- {{ 'Participants'|trans }}
+ {{ 'accompanying_period.Participants_without_count'|trans({count: acp.currentParticipations|length}) }}
diff --git a/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriodWork/AccompanyingPeriodWorkMergeService.php b/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriodWork/AccompanyingPeriodWorkMergeService.php
new file mode 100644
index 000000000..ba0f93ce3
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriodWork/AccompanyingPeriodWorkMergeService.php
@@ -0,0 +1,112 @@
+em->wrapInTransaction(function (EntityManagerInterface $entityManager) use ($toKeep, $toDelete) {
+ $this->alterStartDate($toKeep, $toDelete);
+ $this->alterEndDate($toKeep, $toDelete);
+ $this->concatenateComments($toKeep, $toDelete);
+ $this->transferWorkflowsSQL($toKeep, $toDelete);
+ $this->updateReferencesSQL($toKeep, $toDelete);
+ $entityManager->remove($toDelete);
+ });
+
+ return $toKeep;
+ }
+
+ private function transferWorkflowsSQL(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): void
+ {
+ $this->em->getConnection()->executeQuery(
+ "UPDATE chill_main_workflow_entity w
+ SET relatedentityid = :toKeepId
+ WHERE w.relatedentityid = :toDeleteId
+ AND w.relatedentityclass = 'Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork'",
+ ['toKeepId' => $toKeep->getId(), 'toDeleteId' => $toDelete->getId()]
+ );
+ }
+
+ private function alterStartDate(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): void
+ {
+ $startDate = min($toKeep->getStartDate(), $toDelete->getStartDate());
+ $toKeep->setStartDate($startDate);
+ }
+
+ private function alterEndDate(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): void
+ {
+ if (null === $toKeep->getEndDate() || null === $toDelete->getEndDate()) {
+ $toKeep->setEndDate(null);
+
+ return;
+ }
+
+ $endDate = max($toKeep->getEndDate(), $toDelete->getEndDate());
+ $toKeep->setEndDate($endDate);
+ }
+
+ private function concatenateComments(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): void
+ {
+ $toKeep->setNote($toKeep->getNote()."\n\n-----------------\n\n".$toDelete->getNote());
+ $toKeep->getPrivateComment()->concatenateComments($toDelete->getPrivateComment());
+ }
+
+ private function updateReferencesSQL(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete): void
+ {
+ foreach ($toDelete->getAccompanyingPeriodWorkEvaluations() as $evaluation) {
+ $toKeep->addAccompanyingPeriodWorkEvaluation($evaluation);
+ }
+
+ foreach ($toDelete->getReferrers() as $referrer) {
+ // we only keep the current referrer
+ $toKeep->addReferrer($referrer);
+ }
+
+ foreach ($toDelete->getPersons() as $person) {
+ $toKeep->addPerson($person);
+ }
+
+ if (null === $toKeep->getHandlingThierParty()) {
+ $toKeep->setHandlingThierParty($toDelete->getHandlingThierParty());
+ }
+
+ foreach ($toDelete->getThirdParties() as $thirdParty) {
+ $toKeep->addThirdParty($thirdParty);
+ }
+
+ foreach ($toDelete->getGoals() as $goal) {
+ $toKeep->addGoal($goal);
+ }
+
+ foreach ($toDelete->getResults() as $result) {
+ $toKeep->addResult($result);
+ }
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/Tests/Service/AccompanyingPeriodWork/AccompanyingPeriodWorkMergeServiceTest.php b/src/Bundle/ChillPersonBundle/Tests/Service/AccompanyingPeriodWork/AccompanyingPeriodWorkMergeServiceTest.php
new file mode 100644
index 000000000..e69c8beee
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Tests/Service/AccompanyingPeriodWork/AccompanyingPeriodWorkMergeServiceTest.php
@@ -0,0 +1,205 @@
+prophesize(EntityManagerInterface::class);
+ $entityManager->wrapInTransaction(Argument::type('callable'))->will(function ($args) use ($entityManager) {
+ call_user_func_array($args[0], [$entityManager->reveal()]);
+ })->shouldBeCalled();
+ $entityManager->remove($toRemove)->shouldBeCalled();
+
+ $connection = $this->prophesize(Connection::class);
+ $connection->executeQuery(Argument::type('string'), Argument::type('array'))->shouldBeCalled();
+
+ $entityManager->getConnection()->willReturn($connection->reveal());
+
+ return new AccompanyingPeriodWorkMergeService($entityManager->reveal());
+ }
+
+ /**
+ * @dataProvider provideStartDateMoveData
+ */
+ public function testStartDateMove(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete, ?\DateTime $expected): void
+ {
+ $service = $this->buildMergeService($toDelete);
+ $return = $service->merge($toKeep, $toDelete);
+
+ self::assertEquals($expected, $return->getStartDate());
+ }
+
+ public static function provideStartDateMoveData(): array
+ {
+ return [
+ 'Earliest date kept when toKeep is earlier' => [
+ (new AccompanyingPeriodWork())->setStartDate(new \DateTime('2023-01-01')),
+ (new AccompanyingPeriodWork())->setStartDate(new \DateTime('2023-06-01')),
+ new \DateTime('2023-01-01'),
+ ],
+ 'Earliest date kept when toDelete is earlier' => [
+ (new AccompanyingPeriodWork())->setStartDate(new \DateTime('2023-06-01')),
+ (new AccompanyingPeriodWork())->setStartDate(new \DateTime('2023-01-01')),
+ new \DateTime('2023-01-01'),
+ ],
+ 'Same start dates remain unchanged' => [
+ (new AccompanyingPeriodWork())->setStartDate(new \DateTime('2023-01-01')),
+ (new AccompanyingPeriodWork())->setStartDate(new \DateTime('2023-01-01')),
+ new \DateTime('2023-01-01'),
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideEndDateMoveData
+ */
+ public function testEndDateMove(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete, ?\DateTimeImmutable $expected): void
+ {
+ $service = $this->buildMergeService($toDelete);
+ $return = $service->merge($toKeep, $toDelete);
+
+ self::assertEquals($expected, $return->getEndDate());
+ }
+
+ public static function provideEndDateMoveData(): array
+ {
+ return [
+ 'Oldest date kept when toKeep is older' => [
+ (new AccompanyingPeriodWork())->setEndDate(new \DateTimeImmutable('2022-01-01'))->setStartDate(new \DateTime('2021-01-01')),
+ (new AccompanyingPeriodWork())->setEndDate(new \DateTimeImmutable('2023-06-01'))->setStartDate(new \DateTime('2021-01-01')),
+ new \DateTimeImmutable('2023-06-01'),
+ ],
+ 'Oldest date kept when toDelete is older' => [
+ (new AccompanyingPeriodWork())->setEndDate(new \DateTimeImmutable('2023-06-01'))->setStartDate(new \DateTime('2021-01-01')),
+ (new AccompanyingPeriodWork())->setEndDate(new \DateTimeImmutable('2022-01-01'))->setStartDate(new \DateTime('2021-01-01')),
+ new \DateTimeImmutable('2023-06-01'),
+ ],
+ 'Same end dates remain unchanged' => [
+ (new AccompanyingPeriodWork())->setEndDate(new \DateTimeImmutable('2023-01-01'))->setStartDate(new \DateTime('2021-01-01')),
+ (new AccompanyingPeriodWork())->setEndDate(new \DateTimeImmutable('2023-01-01'))->setStartDate(new \DateTime('2021-01-01')),
+ new \DateTimeImmutable('2023-01-01'),
+ ],
+ 'End date is null if toKeep is null' => [
+ (new AccompanyingPeriodWork())->setEndDate(null)->setStartDate(new \DateTime('2021-01-01')),
+ (new AccompanyingPeriodWork())->setEndDate(new \DateTimeImmutable('2023-01-01'))->setStartDate(new \DateTime('2021-01-01')),
+ null,
+ ],
+ 'End date is null if toDelete is null' => [
+ (new AccompanyingPeriodWork())->setEndDate(new \DateTimeImmutable('2023-01-01'))->setStartDate(new \DateTime('2021-01-01')),
+ (new AccompanyingPeriodWork())->setEndDate(null)->setStartDate(new \DateTime('2021-01-01')),
+ null,
+ ],
+ 'End date is null if both are null' => [
+ (new AccompanyingPeriodWork())->setEndDate(null)->setStartDate(new \DateTime('2021-01-01')),
+ (new AccompanyingPeriodWork())->setEndDate(null)->setStartDate(new \DateTime('2021-01-01')),
+ null,
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideMoveHandlingThirdPartyData
+ */
+ public function testMoveHandlingThirdParty(AccompanyingPeriodWork $toKeep, AccompanyingPeriodWork $toDelete, ?ThirdParty $expected): void
+ {
+ $service = $this->buildMergeService($toDelete);
+ $return = $service->merge($toKeep, $toDelete);
+
+ self::assertSame($expected, $return->getHandlingThierParty());
+ }
+
+ public static function provideMoveHandlingThirdPartyData(): iterable
+ {
+ yield 'Third party not change when existing in kept' => [
+ (new AccompanyingPeriodWork())->setStartDate(new \DateTimeImmutable('2022-01-01'))->setHandlingThierParty($tpA = new ThirdParty()),
+ (new AccompanyingPeriodWork())->setStartDate(new \DateTimeImmutable('2022-01-01'))->setHandlingThierParty(new ThirdParty()),
+ $tpA,
+ ];
+
+ yield 'Third party will change when not existing in kept' => [
+ (new AccompanyingPeriodWork())->setStartDate(new \DateTimeImmutable('2022-01-01')),
+ (new AccompanyingPeriodWork())->setStartDate(new \DateTimeImmutable('2022-01-01'))->setHandlingThierParty($tpB = new ThirdParty()),
+ $tpB,
+ ];
+
+ yield 'Third party do not change when not existing in removed' => [
+ (new AccompanyingPeriodWork())->setStartDate(new \DateTimeImmutable('2022-01-01'))->setHandlingThierParty($tpC = new ThirdParty()),
+ (new AccompanyingPeriodWork())->setStartDate(new \DateTimeImmutable('2022-01-01')),
+ $tpC,
+ ];
+ }
+
+ public function testMerge(): void
+ {
+ $accompanyingPeriodWork = new AccompanyingPeriodWork();
+ $accompanyingPeriodWork->setStartDate(new \DateTime('2022-01-01'));
+ $accompanyingPeriodWork->addReferrer($userA = new User());
+ $accompanyingPeriodWork->addReferrer($userC = new User());
+ $accompanyingPeriodWork->addAccompanyingPeriodWorkEvaluation($evaluationA = new AccompanyingPeriodWorkEvaluation());
+ $accompanyingPeriodWork->setNote('blabla');
+ $accompanyingPeriodWork->addThirdParty($thirdPartyA = new ThirdParty());
+
+ $toDelete = new AccompanyingPeriodWork();
+ $toDelete->setStartDate(new \DateTime('2022-01-01'));
+ $toDelete->addReferrer($userB = new User());
+ $toDelete->addReferrer($userC);
+ $toDelete->addAccompanyingPeriodWorkEvaluation($evaluationB = new AccompanyingPeriodWorkEvaluation());
+ $toDelete->setNote('boum');
+ $toDelete->addThirdParty($thirdPartyB = new ThirdParty());
+ $toDelete->addGoal($goalA = new AccompanyingPeriodWorkGoal());
+ $toDelete->addResult($resultA = new Result());
+
+ $service = $this->buildMergeService($toDelete);
+ $service->merge($accompanyingPeriodWork, $toDelete);
+
+ self::assertTrue($accompanyingPeriodWork->getReferrers()->contains($userA));
+ self::assertTrue($accompanyingPeriodWork->getReferrers()->contains($userB));
+ self::assertTrue($accompanyingPeriodWork->getReferrers()->contains($userC));
+
+ self::assertTrue($accompanyingPeriodWork->getAccompanyingPeriodWorkEvaluations()->contains($evaluationA));
+ self::assertTrue($accompanyingPeriodWork->getAccompanyingPeriodWorkEvaluations()->contains($evaluationB));
+ foreach ($accompanyingPeriodWork->getAccompanyingPeriodWorkEvaluations() as $evaluation) {
+ self::assertSame($accompanyingPeriodWork, $evaluation->getAccompanyingPeriodWork());
+ }
+
+ self::assertStringContainsString('blabla', $accompanyingPeriodWork->getNote());
+ self::assertStringContainsString('boum', $toDelete->getNote());
+
+ self::assertTrue($accompanyingPeriodWork->getThirdParties()->contains($thirdPartyA));
+ self::assertTrue($accompanyingPeriodWork->getThirdParties()->contains($thirdPartyB));
+
+ self::assertTrue($accompanyingPeriodWork->getGoals()->contains($goalA));
+ self::assertTrue($accompanyingPeriodWork->getResults()->contains($resultA));
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/chill.webpack.config.js b/src/Bundle/ChillPersonBundle/chill.webpack.config.js
index e4c6ed3af..effbec70f 100644
--- a/src/Bundle/ChillPersonBundle/chill.webpack.config.js
+++ b/src/Bundle/ChillPersonBundle/chill.webpack.config.js
@@ -6,7 +6,6 @@ module.exports = function (encore, entries) {
encore.addAliases({
ChillPersonAssets: __dirname + "/Resources/public",
});
-
encore.addEntry(
"vue_household_members_editor",
__dirname + "/Resources/public/vuejs/HouseholdMembersEditor/index.js",
@@ -31,7 +30,6 @@ module.exports = function (encore, entries) {
"vue_export_action_goal_result",
__dirname + "/Resources/public/vuejs/ExportFormActionGoalResult/index.js",
);
-
encore.addEntry(
"mod_set_referrer",
__dirname + "/Resources/public/mod/AccompanyingPeriod/setReferrer.js",
@@ -66,4 +64,8 @@ module.exports = function (encore, entries) {
"page_create_person",
__dirname + "/Resources/public/page/person/create-person.js",
);
+ encore.addEntry(
+ "mod_duplicate_selector",
+ __dirname + "/Resources/public/mod/DuplicateSelector/AccompanyingPeriodWorkSelector.ts",
+ );
};
diff --git a/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml b/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml
index 830e21d2d..6e42a362b 100644
--- a/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml
+++ b/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml
@@ -13,6 +13,14 @@ Requestor: >-
neutral {Demandeur·euse}
}
+accompanying_period:
+ Participants_without_count: >-
+ {count, plural,
+ =0 {Participant}
+ =1 {Participant}
+ other {Participants}
+ }
+
person:
from_the: depuis le
And himself: >-
diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml
index 94e6083ca..4739bac0f 100644
--- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml
+++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml
@@ -208,7 +208,7 @@ Pediod closing form is not valid: Le formulaire n'est pas valide
Accompanying user: Accompagnant
No accompanying user: Aucun accompagnant
No data given: Pas d'information
-Participants: Usagers impliquées
+Participants: Usagers impliqués
Create an accompanying course: Créer un parcours
Accompanying courses of users: Parcours des utilisateurs
This accompanying course is still a draft: Ce parcours est encore à l'état brouillon.
@@ -1502,6 +1502,18 @@ entity_display_title:
Work (n°%w%): "Action d'accompagnement (n°%w%)"
Accompanying Course (n°%w%): "Parcours d'accompagnement (n°%w%)"
+acpw_duplicate:
+ title: Fusionner les actions d'accompagnement
+ description: Cette fusion conservera la date de début la plus ancienne, la date de fin la plus récente, toutes les évaluations, documents et workflows. Les agents traitants seront additionnés ainsi que les tiers intervenants. Les commentaires seront mis l'un à la suite de l'autre.
+ Select accompanying period work: Selectionner un action d'accompagnement
+ Assign duplicate: Désigner un action d'accompagnement doublon
+ Accompanying period work to delete: Action d'accompagnement à supprimer
+ Accompanying period work to delete explanation: Cet action d'accompagnement sera supprimé.
+ Accompanying period work to keep: Action d'accompagnement à conserver
+ to keep: Action d'accompagnement à conserver
+ to delete: Action d'accompagnement à supprimer
+ Successfully merged: Action d'accompagnement fusionnée avec succès.
+
my_parcours_filters:
referrer_parcours_and_acpw: Agent traitant ou réferent
referrer_acpw: Agent traitant d'une action
diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/public/types.ts b/src/Bundle/ChillThirdPartyBundle/Resources/public/types.ts
new file mode 100644
index 000000000..20ae3309b
--- /dev/null
+++ b/src/Bundle/ChillThirdPartyBundle/Resources/public/types.ts
@@ -0,0 +1,47 @@
+import {
+ Address,
+ Center,
+ Civility,
+ DateTime,
+ User,
+} from "ChillMainAssets/types";
+
+export interface Thirdparty {
+ acronym: string | null;
+ active: boolean;
+ address: Address | null;
+ canonicalized: string | null;
+ categories: ThirdpartyCategory[];
+ centers: Center[];
+ children: Thirdparty[];
+ civility: Civility | null;
+ comment: string | null;
+ contactDataAnonymous: boolean;
+ createdAt: DateTime;
+ createdBy: User | null;
+ email: string | null;
+ firstname: string | null;
+ id: number | null;
+ kind: string;
+ name: string;
+ nameCompany: string | null;
+ parent: Thirdparty | null;
+ profession: string;
+ telephone: string | null;
+ thirdPartyTypes: ThirdpartyType[] | null;
+ updatedAt: DateTime | null;
+ updatedBy: User | null;
+}
+
+interface ThirdpartyType {
+ key: string;
+ value: string;
+}
+
+export interface ThirdpartyCategory {
+ id: number;
+ active: boolean;
+ name: {
+ fr: string;
+ };
+}
diff --git a/src/Bundle/ChillWopiBundle/src/Resources/public/module/pending/index.ts b/src/Bundle/ChillWopiBundle/src/Resources/public/module/pending/index.ts
index 98dbac4d4..faeb00540 100644
--- a/src/Bundle/ChillWopiBundle/src/Resources/public/module/pending/index.ts
+++ b/src/Bundle/ChillWopiBundle/src/Resources/public/module/pending/index.ts
@@ -1,8 +1,6 @@
import { is_object_ready } from "../../../../../../ChillDocStoreBundle/Resources/public/vuejs/StoredObjectButton/helpers";
import {
StoredObject,
- StoredObjectStatus,
- StoredObjectStatusChange,
} from "../../../../../../ChillDocStoreBundle/Resources/public/types";
async function reload_if_needed(
diff --git a/symfony.lock b/symfony.lock
index ee44b19d8..6409f0c1d 100644
--- a/symfony.lock
+++ b/symfony.lock
@@ -14,6 +14,15 @@
"config/routes/annotations.yaml"
]
},
+ "doctrine/deprecations": {
+ "version": "1.1",
+ "recipe": {
+ "repo": "github.com/symfony/recipes",
+ "branch": "main",
+ "version": "1.0",
+ "ref": "87424683adc81d7dc305eefec1fced883084aab9"
+ }
+ },
"doctrine/doctrine-bundle": {
"version": "2.13",
"recipe": {