diff --git a/application/Espo/Core/Record/Duplicator/EntityDuplicator.php b/application/Espo/Core/Record/Duplicator/EntityDuplicator.php index 2661e273a1..fe4b1d40b9 100644 --- a/application/Espo/Core/Record/Duplicator/EntityDuplicator.php +++ b/application/Espo/Core/Record/Duplicator/EntityDuplicator.php @@ -31,11 +31,12 @@ namespace Espo\Core\Record\Duplicator; use Espo\Core\ORM\Type\FieldType; use Espo\Core\Utils\Metadata; +use Espo\ORM\Defs\RelationDefs; use Espo\ORM\Entity; use Espo\ORM\Defs; use Espo\ORM\Defs\FieldDefs; use Espo\Core\Utils\FieldUtil; - +use Espo\ORM\Type\RelationType; use stdClass; /** @@ -63,6 +64,10 @@ class EntityDuplicator $this->processField($entity, $fieldDefs, $valueMap); } + foreach ($entityDefs->getRelationList() as $relationDefs) { + $this->processLink($entity, $relationDefs, $entityDefs, $valueMap); + } + return $valueMap; } @@ -94,6 +99,37 @@ class EntityDuplicator } } + private function processLink( + Entity $entity, + RelationDefs $relationDefs, + Defs\EntityDefs $entityDefs, + stdClass $valueMap, + ): void { + + $link = $relationDefs->getName(); + + if ( + !in_array($relationDefs->getType(), [ + RelationType::BELONGS_TO, + RelationType::BELONGS_TO_PARENT, + RelationType::HAS_ONE, + ]) + ) { + return; + } + + if ($entityDefs->hasField($link)) { + return; + } + + unset($valueMap->{$link . 'Id'}); + unset($valueMap->{$link . 'Name'}); + + if ($relationDefs->getType() === RelationType::BELONGS_TO_PARENT) { + unset($valueMap->{$link . 'Type'}); + } + } + private function toIgnoreField(string $entityType, FieldDefs $fieldDefs): bool { $type = $fieldDefs->getType(); diff --git a/tests/integration/Espo/Record/EntityDuplicatorTest.php b/tests/integration/Espo/Record/EntityDuplicatorTest.php new file mode 100644 index 0000000000..cf135265e4 --- /dev/null +++ b/tests/integration/Espo/Record/EntityDuplicatorTest.php @@ -0,0 +1,88 @@ +. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +namespace tests\integration\Espo\Record; + +use Espo\Core\Record\CreateParams; +use Espo\Core\Record\Duplicator\EntityDuplicator; +use Espo\Core\Record\ServiceContainer; +use Espo\Entities\Email; +use Espo\Entities\User; +use Espo\Modules\Crm\Entities\Account; +use Espo\Modules\Crm\Entities\Task; +use tests\integration\Core\BaseTestCase; + +class EntityDuplicatorTest extends BaseTestCase +{ + /** + * @noinspection PhpUnhandledExceptionInspection + */ + public function testDuplicate(): void + { + $user = $this->createUser([ + 'userName' => 'test', + 'type' => User::TYPE_ADMIN, + ]); + + $this->auth('test'); + $this->reCreateApplication(); + + $em = $this->getEntityManager(); + + $account = $em->getRDBRepositoryByClass(Account::class)->getNew(); + $account->setName('Account'); + $em->saveEntity($account); + + $email = $em->getRDBRepositoryByClass(Email::class)->getNew(); + $email->setSubject('Test'); + $email->setParent($account); + $em->saveEntity($email); + + $taskService = $this->getContainer() + ->getByClass(ServiceContainer::class) + ->getByClass(Task::class); + + $task = $taskService->create((object) [ + 'name' => 'Task', + 'originalEmailId' => $email->getId(), + 'parentId' => $account->getId(), + 'parentType' => $account->getEntityType(), + 'assignedUserId' => $user->getId(), + ], CreateParams::create()); + + $this->assertEquals($email->getId(), $task->get('emailId')); + + $duplicator = $this->getInjectableFactory()->create(EntityDuplicator::class); + + $values = $duplicator->duplicate($task); + + $this->assertEquals($account->getId(), $values->accountId ?? null); + $this->assertFalse(isset($values->emailId)); + } +}