From 4112e59af4f09d02b4f6a0ef3545aa22e90e823d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 9 Nov 2023 17:11:46 +0100 Subject: [PATCH 01/10] Export: add an ActivityPresenceAggregator --- .../unreleased/Feature-20231109-170655.yaml | 5 ++ .../Aggregator/ActivityPresenceAggregator.php | 72 +++++++++++++++++++ .../ActivityPresenceAggregatorTest.php | 62 ++++++++++++++++ .../config/services/export.yaml | 4 ++ .../translations/messages.fr.yml | 3 + 5 files changed, 146 insertions(+) create mode 100644 .changes/unreleased/Feature-20231109-170655.yaml create mode 100644 src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityPresenceAggregator.php create mode 100644 src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityPresenceAggregatorTest.php diff --git a/.changes/unreleased/Feature-20231109-170655.yaml b/.changes/unreleased/Feature-20231109-170655.yaml new file mode 100644 index 000000000..d4f793607 --- /dev/null +++ b/.changes/unreleased/Feature-20231109-170655.yaml @@ -0,0 +1,5 @@ +kind: Feature +body: 'Export: add an aggregator "group activities by presence"' +time: 2023-11-09T17:06:55.876380883+01:00 +custom: + Issue: "199" diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityPresenceAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityPresenceAggregator.php new file mode 100644 index 000000000..17e16357a --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityPresenceAggregator.php @@ -0,0 +1,72 @@ +activityPresenceRepository->find($value)) { + return ''; + } + + return $this->translatableStringHelper->localize($presence->getName()); + }; + } + + public function getQueryKeys($data) + { + return ['activity_presence_aggregator_attendee']; + } + + public function getTitle(): string + { + return 'export.aggregator.activity.by_activity_presence.Group activity by presence'; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data): void + { + $qb->addSelect('IDENTITY(activity.attendee) AS activity_presence_aggregator_attendee'); + $qb->addGroupBy('activity_presence_aggregator_attendee'); + } + + public function applyOn() + { + return Declarations::ACTIVITY; + } +} diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityPresenceAggregatorTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityPresenceAggregatorTest.php new file mode 100644 index 000000000..ea2bafb0d --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityPresenceAggregatorTest.php @@ -0,0 +1,62 @@ +translatableStringHelper = self::$container->get(TranslatableStringHelperInterface::class); + $this->activityPresenceRepository = self::$container->get(ActivityPresenceRepositoryInterface::class); + } + + public function getAggregator() + { + return new ActivityPresenceAggregator($this->activityPresenceRepository, $this->translatableStringHelper); + } + + public function getFormData() + { + return [ + [], + ]; + } + + public function getQueryBuilders() + { + self::bootKernel(); + + $em = self::$container->get(EntityManagerInterface::class); + + return [ + $em->createQueryBuilder() + ->select('count(activity.id)') + ->from(Activity::class, 'activity'), + ]; + } +} diff --git a/src/Bundle/ChillActivityBundle/config/services/export.yaml b/src/Bundle/ChillActivityBundle/config/services/export.yaml index 29f7c2625..5b213cbee 100644 --- a/src/Bundle/ChillActivityBundle/config/services/export.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/export.yaml @@ -218,3 +218,7 @@ services: Chill\ActivityBundle\Export\Aggregator\ACPAggregators\ByActivityTypeAggregator: tags: - { name: chill.export_aggregator, alias: acp_by_activity_type_aggregator } + + Chill\ActivityBundle\Export\Aggregator\ActivityPresenceAggregator: + tags: + - { name: chill.export_aggregator, alias: activity_presence_agg } diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index 759d222c1..f1ce1c681 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -421,6 +421,9 @@ export: by_persons: Group activity by persons: Grouper les échanges par usager participant Persons: Usagers participants + by_activity_presence: + Group activity by presence: Grouper les échanges par présence de l'usager + header: Présence de(s) usager(s) generic_doc: filter: From 27012d842dcae5153ee4dfea9827325f36169651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 9 Nov 2023 17:35:24 +0100 Subject: [PATCH 02/10] Export: add an ActivityPresenceFilter --- .../unreleased/Feature-20231109-173500.yaml | 5 ++ .../Export/Filter/ActivityPresenceFilter.php | 82 +++++++++++++++++++ .../Filter/ActivityPresenceFilterTest.php | 76 +++++++++++++++++ .../config/services/export.yaml | 5 ++ .../translations/messages.fr.yml | 4 + 5 files changed, 172 insertions(+) create mode 100644 .changes/unreleased/Feature-20231109-173500.yaml create mode 100644 src/Bundle/ChillActivityBundle/Export/Filter/ActivityPresenceFilter.php create mode 100644 src/Bundle/ChillActivityBundle/Tests/Export/Filter/ActivityPresenceFilterTest.php diff --git a/.changes/unreleased/Feature-20231109-173500.yaml b/.changes/unreleased/Feature-20231109-173500.yaml new file mode 100644 index 000000000..e356259b4 --- /dev/null +++ b/.changes/unreleased/Feature-20231109-173500.yaml @@ -0,0 +1,5 @@ +kind: Feature +body: 'Export: add a filter "filter activity by activity presence"' +time: 2023-11-09T17:35:00.158055832+01:00 +custom: + Issue: "199" diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityPresenceFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityPresenceFilter.php new file mode 100644 index 000000000..201b9f810 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityPresenceFilter.php @@ -0,0 +1,82 @@ +add('presences', EntityType::class, [ + 'class' => ActivityPresence::class, + 'choice_label' => fn (ActivityPresence $presence) => $this->translatableStringHelper->localize($presence->getName()) + .($presence->isActive() ? '' : ' ('.$this->translator->trans('inactive').')'), + 'multiple' => true, + 'expanded' => true, + 'label' => 'export.filter.activity.by_presence.presences', + ]); + } + + public function getFormDefaultData(): array + { + return []; + } + + public function describeAction($data, $format = 'string') + { + $presences = array_map( + fn (ActivityPresence $presence) => $this->translatableStringHelper->localize($presence->getName()), + $data['presences'] instanceof Collection ? $data['presences']->toArray() : $data['presences'] + ); + + return [ + 'export.filter.activity.by_presence.Filtered by activity presence: only %presences%', + ['%presences%' => implode(', ', $presences)], + ]; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $qb + ->andWhere('activity.attendee IN (:activity_presence_filter_presences)') + ->setParameter('activity_presence_filter_presences', $data['presences']); + } + + public function applyOn() + { + return Declarations::ACTIVITY; + } +} diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Filter/ActivityPresenceFilterTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Filter/ActivityPresenceFilterTest.php new file mode 100644 index 000000000..6fc3d10d8 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Filter/ActivityPresenceFilterTest.php @@ -0,0 +1,76 @@ +translator = self::$container->get(TranslatorInterface::class); + $this->translatableStringHelper = self::$container->get(TranslatableStringHelperInterface::class); + } + + public function getFilter() + { + return new ActivityPresenceFilter($this->translatableStringHelper, $this->translator); + } + + public function getFormData() + { + self::bootKernel(); + + $presences = self::$container->get(ActivityPresenceRepositoryInterface::class) + ->findAll(); + + return [ + [ + 'presences' => $presences, + ], + [ + 'presences' => new ArrayCollection($presences), + ], + ]; + } + + public function getQueryBuilders() + { + self::bootKernel(); + + $em = self::$container->get(EntityManagerInterface::class); + + yield $em->createQueryBuilder() + ->select('count(activity.id)') + ->from(Activity::class, 'activity'); + + self::ensureKernelShutdown(); + } +} diff --git a/src/Bundle/ChillActivityBundle/config/services/export.yaml b/src/Bundle/ChillActivityBundle/config/services/export.yaml index 5b213cbee..ce219b82d 100644 --- a/src/Bundle/ChillActivityBundle/config/services/export.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/export.yaml @@ -135,6 +135,11 @@ services: tags: - { name: chill.export_filter, alias: 'period_having_activity_betw_dates_filter' } + Chill\ActivityBundle\Export\Filter\ActivityPresenceFilter: + tags: + - { name: chill.export_filter, alias: 'activity_presence_filter' } + + ## Aggregators Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator: tags: diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index f1ce1c681..ed4c1a5f4 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -389,6 +389,10 @@ export: Sent or received: Envoyé ou reçu is sent: envoyé is received: reçu + by_presence: + Filter activity by activity presence: Filtrer les échanges par présence de l'usager + presences: Présences + 'Filtered by activity presence: only %presences%': 'Filtré par présence de l''usager: seulement %presences%' aggregator: acp: From cbc83c0e63eed828d5baed885b3000474f0cb468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 10 Nov 2023 14:41:58 +0100 Subject: [PATCH 03/10] Export: add grouping "group activity by person" (activites saved in person context) --- .../unreleased/Feature-20231110-144056.yaml | 6 ++ .../PersonAggregators/PersonAggregator.php | 65 +++++++++++++++++++ .../PersonAggregatorTest.php | 57 ++++++++++++++++ .../config/services/export.yaml | 4 ++ .../translations/messages.fr.yml | 4 ++ 5 files changed, 136 insertions(+) create mode 100644 .changes/unreleased/Feature-20231110-144056.yaml create mode 100644 src/Bundle/ChillActivityBundle/Export/Aggregator/PersonAggregators/PersonAggregator.php create mode 100644 src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/PersonAggregators/PersonAggregatorTest.php diff --git a/.changes/unreleased/Feature-20231110-144056.yaml b/.changes/unreleased/Feature-20231110-144056.yaml new file mode 100644 index 000000000..f263d14c6 --- /dev/null +++ b/.changes/unreleased/Feature-20231110-144056.yaml @@ -0,0 +1,6 @@ +kind: Feature +body: 'Export: add an aggregator "group activities by person" (only for the activities + saved in a person context)' +time: 2023-11-10T14:40:56.93459414+01:00 +custom: + Issue: "199" diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/PersonAggregators/PersonAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/PersonAggregators/PersonAggregator.php new file mode 100644 index 000000000..c7a3bd6b5 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/PersonAggregators/PersonAggregator.php @@ -0,0 +1,65 @@ +labelPersonHelper->getLabel($key, $values, 'export.aggregator.person.by_person.person'); + } + + public function getQueryKeys($data) + { + return ['activity_by_person_agg']; + } + + public function getTitle() + { + return 'export.aggregator.person.by_person.title'; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $qb + ->addSelect('IDENTITY(activity.person) AS activity_by_person_agg') + ->addGroupBy('activity_by_person_agg'); + } + + public function applyOn() + { + return Declarations::ACTIVITY_PERSON; + } +} diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/PersonAggregators/PersonAggregatorTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/PersonAggregators/PersonAggregatorTest.php new file mode 100644 index 000000000..388f13793 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/PersonAggregators/PersonAggregatorTest.php @@ -0,0 +1,57 @@ +labelPersonHelper = self::$container->get(LabelPersonHelper::class); + } + + public function getAggregator() + { + return new PersonAggregator($this->labelPersonHelper); + } + + public function getFormData() + { + return [[]]; + } + + public function getQueryBuilders() + { + self::bootKernel(); + + $em = self::$container->get(EntityManagerInterface::class); + + return [ + $em->createQueryBuilder() + ->select('count(activity.id)') + ->from(Activity::class, 'activity'), + ]; + } +} diff --git a/src/Bundle/ChillActivityBundle/config/services/export.yaml b/src/Bundle/ChillActivityBundle/config/services/export.yaml index ce219b82d..dcc6bec17 100644 --- a/src/Bundle/ChillActivityBundle/config/services/export.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/export.yaml @@ -227,3 +227,7 @@ services: Chill\ActivityBundle\Export\Aggregator\ActivityPresenceAggregator: tags: - { name: chill.export_aggregator, alias: activity_presence_agg } + + Chill\ActivityBundle\Export\Aggregator\PersonAggregators\PersonAggregator: + tags: + - { name: chill.export_aggregator, alias: activity_person_agg } diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index ed4c1a5f4..52c5366a7 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -395,6 +395,10 @@ export: 'Filtered by activity presence: only %presences%': 'Filtré par présence de l''usager: seulement %presences%' aggregator: + person: + by_person: + title: Grouper les échanges par usager (dossier d'usager dans lequel l'échange est enregistré) + person: Usager acp: by_activity_type: title: Grouper les parcours par type d'échange From 0d741ab88636e6a3bca45fad8c510c41ea29c055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 10 Nov 2023 17:17:51 +0100 Subject: [PATCH 04/10] Export: add grouping "group peoples by postal code" --- .../unreleased/Feature-20231110-171720.yaml | 5 + .../PostalCodeAggregator.php | 99 +++++++++++++++++++ .../PostalCodeAggregatorTest.php | 61 ++++++++++++ .../config/services/exports_person.yaml | 4 +- .../translations/messages.fr.yml | 4 + 5 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 .changes/unreleased/Feature-20231110-171720.yaml create mode 100644 src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/PostalCodeAggregator.php create mode 100644 src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/PersonAggregators/PostalCodeAggregatorTest.php diff --git a/.changes/unreleased/Feature-20231110-171720.yaml b/.changes/unreleased/Feature-20231110-171720.yaml new file mode 100644 index 000000000..69135e62c --- /dev/null +++ b/.changes/unreleased/Feature-20231110-171720.yaml @@ -0,0 +1,5 @@ +kind: Feature +body: 'Export: add a new aggregator "group peoples by postal code"' +time: 2023-11-10T17:17:20.236876015+01:00 +custom: + Issue: "199" diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/PostalCodeAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/PostalCodeAggregator.php new file mode 100644 index 000000000..6f8978ad4 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/PostalCodeAggregator.php @@ -0,0 +1,99 @@ +add('calc_date', PickRollingDateType::class, [ + 'label' => 'export.aggregator.person.by_postal_code.at_date', + ]); + } + + public function getFormDefaultData(): array + { + return ['calc_date' => new RollingDate(RollingDate::T_TODAY)]; + } + + public function getLabels($key, array $values, mixed $data) + { + return function (null|int|string $value): string { + if ('_header' === $value) { + return 'export.aggregator.person.by_postal_code.header'; + } + + if (null === $value) { + return ''; + } + + return $value; + }; + } + + public function getQueryKeys($data) + { + return [self::PREFIX.'_postal_code_code', self::PREFIX.'_postal_code_label']; + } + + public function getTitle() + { + return 'export.aggregator.person.by_postal_code.title'; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $p = self::PREFIX; + + $qb + ->leftJoin( + 'person.householdAddresses', + "{$p}_household_addresses", + Join::WITH, + "{$p}_household_addresses.validFrom <= :{$p}_calc_date AND ({$p}_household_addresses.validTo IS NULL OR {$p}_household_addresses.validTo > :{$p}_calc_date)" + ) + ->setParameter("{$p}_calc_date", $this->rollingDateConverter->convert($data['calc_date'])) + ->leftJoin("{$p}_household_addresses.address", "{$p}_address") + ->leftJoin("{$p}_address.postcode", "{$p}_postal_code") + ->addSelect("{$p}_postal_code.code AS {$p}_postal_code_code") + ->addSelect("{$p}_postal_code.name AS {$p}_postal_code_label") + ->addGroupBy("{$p}_postal_code_code") + ->addGroupBy("{$p}_postal_code_label") + ; + } + + public function applyOn() + { + return Declarations::PERSON_TYPE; + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/PersonAggregators/PostalCodeAggregatorTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/PersonAggregators/PostalCodeAggregatorTest.php new file mode 100644 index 000000000..445f257b8 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/PersonAggregators/PostalCodeAggregatorTest.php @@ -0,0 +1,61 @@ +rollingDateConverter = self::$container->get(RollingDateConverterInterface::class); + } + + public function getAggregator() + { + return new PostalCodeAggregator($this->rollingDateConverter); + } + + public function getFormData() + { + return [ + ['calc_date' => new RollingDate(RollingDate::T_TODAY)], + ]; + } + + public function getQueryBuilders() + { + self::bootKernel(); + + $em = self::$container + ->get(EntityManagerInterface::class); + + return [ + $em->createQueryBuilder() + ->select('count(person.id)') + ->from(Person::class, 'person'), + ]; + } +} diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml index 43f5556cf..d25a3b9e6 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml @@ -173,4 +173,6 @@ services: tags: - { name: chill.export_aggregator, alias: person_center_aggregator } - + Chill\PersonBundle\Export\Aggregator\PersonAggregators\PostalCodeAggregator: + tags: + - { name: chill.export_aggregator, alias: person_postal_code_aggregator } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index f2a90c31f..87c0e3703 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -1010,6 +1010,10 @@ export: title: Grouper les usagers par centre at_date: Date de calcul du centre center: Centre de l'usager + by_postal_code: + title: Grouper les usagers par code postal de l'adresse + at_date: Date de calcul de l'adresse + header: Code postal course: by_referrer: From 2cc5fa06ae238cea79777bb29cc45249d7f12d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 10 Nov 2023 18:01:13 +0100 Subject: [PATCH 05/10] Export: split export about person on accompanying period work: one with the people associated with the work, another one with the people associated with the accompanying period --- .../unreleased/Feature-20231110-175928.yaml | 7 + ...rkAssociatePersonOnAccompanyingPeriod.php} | 8 +- ...panyingPeriodWorkAssociatePersonOnWork.php | 139 +++++++ ...rkAssociatePersonOnAccompanyingPeriod.php} | 8 +- ...panyingPeriodWorkAssociatePersonOnWork.php | 348 ++++++++++++++++++ ...sociatePersonOnAccompanyingPeriodTest.php} | 12 +- ...ingPeriodWorkAssociatePersonOnWorkTest.php | 48 +++ ...ssociatePersonOnAccompanyingPeriodTest.php | 103 ++++++ ...ngPeriodWorkAssociatePersonOnWorkTest.php} | 8 +- .../services/exports_social_actions.yaml | 14 +- .../translations/messages.fr.yml | 20 +- 11 files changed, 691 insertions(+), 24 deletions(-) create mode 100644 .changes/unreleased/Feature-20231110-175928.yaml rename src/Bundle/ChillPersonBundle/Export/Export/{CountAccompanyingPeriodWork.php => CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod.php} (90%) create mode 100644 src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWorkAssociatePersonOnWork.php rename src/Bundle/ChillPersonBundle/Export/Export/{ListAccompanyingPeriodWork.php => ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod.php} (97%) create mode 100644 src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWorkAssociatePersonOnWork.php rename src/Bundle/ChillPersonBundle/Tests/Export/Export/{CountAccompanyingPeriodWorkTest.php => CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriodTest.php} (69%) create mode 100644 src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingPeriodWorkAssociatePersonOnWorkTest.php create mode 100644 src/Bundle/ChillPersonBundle/Tests/Export/Export/ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriodTest.php rename src/Bundle/ChillPersonBundle/Tests/Export/Export/{ListAccompanyingPeriodWorkTest.php => ListAccompanyingPeriodWorkAssociatePersonOnWorkTest.php} (91%) diff --git a/.changes/unreleased/Feature-20231110-175928.yaml b/.changes/unreleased/Feature-20231110-175928.yaml new file mode 100644 index 000000000..a42e1210d --- /dev/null +++ b/.changes/unreleased/Feature-20231110-175928.yaml @@ -0,0 +1,7 @@ +kind: Feature +body: 'Export: split export about person on accompanying period work: one with the + people associated with the work, another one with the people associated with the + accompanying period' +time: 2023-11-10T17:59:28.388361356+01:00 +custom: + Issue: "200" diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWork.php b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod.php similarity index 90% rename from src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWork.php rename to src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod.php index e274ac5cd..a73e4f037 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWork.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod.php @@ -25,7 +25,7 @@ use Doctrine\ORM\QueryBuilder; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; -class CountAccompanyingPeriodWork implements ExportInterface, GroupedExportInterface +class CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod implements ExportInterface, GroupedExportInterface { private readonly bool $filterStatsByCenters; @@ -53,7 +53,7 @@ class CountAccompanyingPeriodWork implements ExportInterface, GroupedExportInter public function getDescription(): string { - return 'Count social work actions by various parameters'; + return 'export.export.count_accompanying_period_work_associate_person.description'; } public function getGroup(): string @@ -68,7 +68,7 @@ class CountAccompanyingPeriodWork implements ExportInterface, GroupedExportInter } $labels = array_combine($values, $values); - $labels['_header'] = $this->getTitle(); + $labels['_header'] = 'export.export.count_accompanying_period_work_associate_person.header'; return static fn ($value) => $labels[$value]; } @@ -85,7 +85,7 @@ class CountAccompanyingPeriodWork implements ExportInterface, GroupedExportInter public function getTitle(): string { - return 'Count social work actions'; + return 'export.export.count_accompanying_period_work_associate_person.title'; } public function getType(): string diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWorkAssociatePersonOnWork.php b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWorkAssociatePersonOnWork.php new file mode 100644 index 000000000..4f43a78b0 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWorkAssociatePersonOnWork.php @@ -0,0 +1,139 @@ +filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } + + public function buildForm(FormBuilderInterface $builder): void + { + // No form necessary? + } + + public function getFormDefaultData(): array + { + return []; + } + + public function getAllowedFormattersTypes(): array + { + return [FormatterInterface::TYPE_TABULAR]; + } + + public function getDescription(): string + { + return 'export.export.count_accompanying_period_work_associate_work.description'; + } + + public function getGroup(): string + { + return 'Exports of social work actions'; + } + + public function getLabels($key, array $values, $data) + { + if ('export_result' !== $key) { + throw new \LogicException("the key {$key} is not used by this export"); + } + + $labels = array_combine($values, $values); + $labels['_header'] = 'export.export.count_accompanying_period_work_associate_work.header'; + + return static fn ($value) => $labels[$value]; + } + + public function getQueryKeys($data): array + { + return ['export_result']; + } + + public function getResult($query, $data) + { + return $query->getQuery()->getResult(Query::HYDRATE_SCALAR); + } + + public function getTitle(): string + { + return 'export.export.count_accompanying_period_work_associate_work.title'; + } + + public function getType(): string + { + return Declarations::SOCIAL_WORK_ACTION_TYPE; + } + + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder + { + $centers = array_map(static fn ($el) => $el['center'], $acl); + + $qb = $this->em->createQueryBuilder(); + + $qb + ->from(AccompanyingPeriod\AccompanyingPeriodWork::class, 'acpw') + ->join('acpw.accompanyingPeriod', 'acp') + ->join('acpw.persons', 'person'); + + if ($this->filterStatsByCenters) { + $qb + ->andWhere( + $qb->expr()->exists( + 'SELECT 1 FROM '.PersonCenterHistory::class.' acl_count_person_history WHERE acl_count_person_history.person = person + AND acl_count_person_history.center IN (:authorized_centers) + ' + ) + ) + ->setParameter('authorized_centers', $centers); + } + + $qb->select('COUNT(DISTINCT acpw.id) as export_result'); + + AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); + + return $qb; + } + + public function requiredRole(): string + { + return AccompanyingPeriodVoter::STATS; + } + + public function supportsModifiers(): array + { + return [ + Declarations::SOCIAL_WORK_ACTION_TYPE, + Declarations::ACP_TYPE, + Declarations::PERSON_TYPE, + ]; + } +} diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWork.php b/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod.php similarity index 97% rename from src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWork.php rename to src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod.php index 81c60bae6..49b21ef69 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWork.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod.php @@ -47,7 +47,7 @@ use Doctrine\ORM\QueryBuilder; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; -class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterface +class ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod implements ListInterface, GroupedExportInterface { private const FIELDS = [ 'id', @@ -121,7 +121,7 @@ class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterfac public function getDescription(): string { - return 'export.list.acpw.List description'; + return 'export.list.acpw_associate_period.List description'; } public function getGroup(): string @@ -190,12 +190,12 @@ class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterfac public function getResult($query, $data) { - return dump($query->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR)); + return $query->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR); } public function getTitle(): string { - return 'export.list.acpw.List of accompanying period works'; + return 'export.list.acpw_associate_period.List of accompanying period works'; } public function getType(): string diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWorkAssociatePersonOnWork.php b/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWorkAssociatePersonOnWork.php new file mode 100644 index 000000000..4e68d5341 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWorkAssociatePersonOnWork.php @@ -0,0 +1,348 @@ +filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder + ->add('calc_date', PickRollingDateType::class, [ + 'label' => 'export.list.acpw.Date of calculation for associated elements', + 'help' => 'export.list.acpw.help_description', + 'required' => true, + ]); + } + + public function getFormDefaultData(): array + { + return ['calc_date' => new RollingDate(RollingDate::T_TODAY)]; + } + + public function getAllowedFormattersTypes() + { + return [FormatterInterface::TYPE_LIST]; + } + + public function getDescription(): string + { + return 'export.list.acpw_associate_work.List description'; + } + + public function getGroup(): string + { + return 'Exports of social work actions'; + } + + public function getLabels($key, array $values, $data) + { + return match ($key) { + 'startDate', 'endDate', 'createdAt', 'updatedAt' => $this->dateTimeHelper->getLabel('export.list.acpw.'.$key), + 'socialAction' => function ($value) use ($key) { + if ('_header' === $value) { + return 'export.list.acpw.'.$key; + } + + if (null === $value) { + return ''; + } + + return $this->socialActionRender->renderString( + $this->socialActionRepository->find($value), + [] + ); + }, + 'socialIssue' => function ($value) use ($key) { + if ('_header' === $value) { + return 'export.list.acpw.'.$key; + } + + if (null === $value) { + return ''; + } + + return $this->socialIssueRender->renderString( + $this->socialIssueRepository->find($value), + [] + ); + }, + 'createdBy', 'updatedBy', 'acp_user' => $this->userHelper->getLabel($key, $values, 'export.list.acpw.'.$key), + 'referrers' => $this->userHelper->getLabel($key, $values, 'export.list.acpw.'.$key), + // 'acpwReferrers' => $this->userHelper->getLabelMulti($key, $values, 'export.list.acpw.' . $key), + 'personsName' => $this->personHelper->getLabelMulti($key, $values, 'export.list.acpw.'.$key), + 'handlingThierParty' => $this->thirdPartyHelper->getLabel($key, $values, 'export.list.acpw.'.$key), + 'thirdParties' => $this->thirdPartyHelper->getLabelMulti($key, $values, 'export.list.acpw.'.$key), + 'personsId', 'goalsId', 'goalResultsId', 'resultsId', 'evaluationsId' => $this->aggregateStringHelper->getLabelMulti($key, $values, 'export.list.acpw.'.$key), + 'goalsTitle', 'goalResultsTitle', 'resultsTitle', 'evaluationsTitle' => $this->translatableStringExportLabelHelper->getLabelMulti($key, $values, 'export.list.acpw.'.$key), + default => static function ($value) use ($key) { + if ('_header' === $value) { + return 'export.list.acpw.'.$key; + } + + if (null === $value) { + return ''; + } + + return $value; + }, + }; + } + + public function getQueryKeys($data) + { + return self::FIELDS; + } + + public function getResult($query, $data) + { + return $query->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR); + } + + public function getTitle(): string + { + return 'export.list.acpw_associate_work.List of accompanying period works'; + } + + public function getType(): string + { + return Declarations::SOCIAL_WORK_ACTION_TYPE; + } + + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) + { + $centers = array_map(static fn ($el) => $el['center'], $acl); + + $qb = $this->entityManager->createQueryBuilder(); + + $qb + ->from(AccompanyingPeriodWork::class, 'acpw') + ->distinct() + ->select('acpw.id AS id') + ->join('acpw.accompanyingPeriod', 'acp') + ->join('acpw.persons', 'person') + ; + + if ($this->filterStatsByCenters) { + $qb + ->andWhere( + $qb->expr()->exists( + 'SELECT 1 FROM '.PersonCenterHistory::class.' acl_count_person_history WHERE acl_count_person_history.person = person + AND acl_count_person_history.center IN (:authorized_centers) + ' + ) + ) + ->setParameter('authorized_centers', $centers); + } + + AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); + + $this->addSelectClauses($qb, $this->rollingDateConverter->convert($data['calc_date'])); + + return $qb; + } + + public function requiredRole(): string + { + return AccompanyingPeriodVoter::STATS; + } + + public function supportsModifiers(): array + { + return [ + Declarations::SOCIAL_WORK_ACTION_TYPE, + Declarations::ACP_TYPE, + Declarations::PERSON_TYPE, + ]; + } + + private function addSelectClauses(QueryBuilder $qb, \DateTimeImmutable $calcDate): void + { + // add regular fields + foreach ([ + 'startDate', + 'endDate', + 'note', + 'createdAt', + 'updatedAt', + ] as $field) { + $qb->addSelect(sprintf('acpw.%s AS %s', $field, $field)); + } + + // those with identity + foreach ([ + 'createdBy', + 'updatedBy', + 'handlingThierParty', + ] as $field) { + $qb->addSelect(sprintf('IDENTITY(acpw.%s) AS %s', $field, $field)); + } + + // join socialaction + $qb + ->join('acpw.socialAction', 'sa') + ->addSelect('sa.id AS socialActionId') + ->addSelect('sa.id AS socialAction') + ->addSelect('IDENTITY(sa.issue) AS socialIssue'); + + // join acp + $qb + ->addSelect('acp.id AS acp_id') + ->addSelect('IDENTITY(acp.user) AS acp_user'); + + // persons + $qb + ->addSelect('(SELECT AGGREGATE(person_acpw_member.id) FROM '.Person::class.' person_acpw_member ' + .'WHERE person_acpw_member MEMBER OF acpw.persons) AS personsId') + ->addSelect('(SELECT AGGREGATE(person1_acpw_member.id) FROM '.Person::class.' person1_acpw_member ' + .'WHERE person1_acpw_member MEMBER OF acpw.persons) AS personsName'); + + // referrers => at date XXXX + $qb + ->addSelect('(SELECT JSON_BUILD_OBJECT(\'uid\', IDENTITY(history.user), \'d\', history.startDate) FROM '.UserHistory::class.' history '. + 'WHERE history.accompanyingPeriod = acp AND history.startDate <= :calcDate AND (history.endDate IS NULL OR history.endDate > :calcDate)) AS referrers'); + + /* + // acpwReferrers at date XXX + $qb + ->addSelect('( + SELECT IDENTITY(acpw_ref_history.accompanyingPeriodWork) AS acpw_ref_history_id, + JSON_BUILD_OBJECT(\'uid\', IDENTITY(acpw_ref_history.user), \'d\', acpw_ref_history.startDate) + FROM ' . AccompanyingPeriodWorkReferrerHistory::class . ' acpw_ref_history ' . + 'WHERE acpw_ref_history.accompanyingPeriodWork = acpw AND acpw_ref_history.startDate <= :calcDate AND (acpw_ref_history.endDate IS NULL or acpw_ref_history.endDate > :calcDate) GROUP BY acpw_ref_history_id) AS acpwReferrers' + ); + */ + + // thirdparties + $qb + ->addSelect('(SELECT AGGREGATE(tp.id) FROM '.ThirdParty::class.' tp ' + .'WHERE tp MEMBER OF acpw.thirdParties) AS thirdParties'); + + // goals + $qb + ->addSelect('(SELECT AGGREGATE(IDENTITY(goal.goal)) FROM '.AccompanyingPeriodWorkGoal::class.' goal ' + .'WHERE goal MEMBER OF acpw.goals) AS goalsId') + ->addSelect('(SELECT AGGREGATE(g.title) FROM '.AccompanyingPeriodWorkGoal::class.' goal1 ' + .'LEFT JOIN '.Goal::class.' g WITH goal1.goal = g.id WHERE goal1 MEMBER OF acpw.goals) AS goalsTitle'); + + // goals results + $qb + ->addSelect('(SELECT AGGREGATE(wr.id) FROM '.Result::class.' wr ' + .'JOIN '.AccompanyingPeriodWorkGoal::class.' wg WITH wr MEMBER OF wg.results ' + .'WHERE wg MEMBER OF acpw.goals) AS goalResultsId') + ->addSelect('(SELECT AGGREGATE(wr1.title) FROM '.Result::class.' wr1 ' + .'JOIN '.AccompanyingPeriodWorkGoal::class.' wg1 WITH wr1 MEMBER OF wg1.results ' + .'WHERE wg1 MEMBER OF acpw.goals) AS goalResultsTitle'); + + // results + $qb + ->addSelect('(SELECT AGGREGATE(result.id) FROM '.Result::class.' result ' + .'WHERE result MEMBER OF acpw.results ) AS resultsId ') + ->addSelect('(SELECT AGGREGATE (result1.title) FROM '.Result::class.' result1 ' + .'WHERE result1 MEMBER OF acpw.results ) AS resultsTitle '); + + // evaluations + $qb + ->addSelect('(SELECT AGGREGATE(IDENTITY(we.evaluation)) FROM '.AccompanyingPeriodWorkEvaluation::class.' we ' + .'WHERE we MEMBER OF acpw.accompanyingPeriodWorkEvaluations ) AS evaluationsId ') + ->addSelect('(SELECT AGGREGATE(ev.title) FROM '.AccompanyingPeriodWorkEvaluation::class.' we1 ' + .'LEFT JOIN '.Evaluation::class.' ev WITH we1.evaluation = ev.id ' + .'WHERE we1 MEMBER OF acpw.accompanyingPeriodWorkEvaluations ) AS evaluationsTitle '); + + $qb->setParameter('calcDate', $calcDate); + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingPeriodWorkTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriodTest.php similarity index 69% rename from src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingPeriodWorkTest.php rename to src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriodTest.php index 271f448d6..5caabf351 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingPeriodWorkTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriodTest.php @@ -13,7 +13,7 @@ namespace Export\Export; use Chill\MainBundle\Test\Export\AbstractExportTest; use Chill\PersonBundle\Export\Declarations; -use Chill\PersonBundle\Export\Export\CountAccompanyingPeriodWork; +use Chill\PersonBundle\Export\Export\CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod; use Doctrine\ORM\EntityManagerInterface; /** @@ -21,23 +21,19 @@ use Doctrine\ORM\EntityManagerInterface; * * @coversNothing */ -final class CountAccompanyingPeriodWorkTest extends AbstractExportTest +final class CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriodTest extends AbstractExportTest { - private CountAccompanyingPeriodWork $export; - protected function setUp(): void { self::bootKernel(); - - $this->export = self::$container->get(CountAccompanyingPeriodWork::class); } public function getExport() { $em = self::$container->get(EntityManagerInterface::class); - yield new CountAccompanyingPeriodWork($em, $this->getParameters(true)); - yield new CountAccompanyingPeriodWork($em, $this->getParameters(false)); + yield new CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod($em, $this->getParameters(true)); + yield new CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod($em, $this->getParameters(false)); } public function getFormData(): array diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingPeriodWorkAssociatePersonOnWorkTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingPeriodWorkAssociatePersonOnWorkTest.php new file mode 100644 index 000000000..6b6e7b7b4 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingPeriodWorkAssociatePersonOnWorkTest.php @@ -0,0 +1,48 @@ +get(EntityManagerInterface::class); + + yield new CountAccompanyingPeriodWorkAssociatePersonOnWork($em, $this->getParameters(true)); + yield new CountAccompanyingPeriodWorkAssociatePersonOnwork($em, $this->getParameters(false)); + } + + public function getFormData(): array + { + return [[]]; + } + + public function getModifiersCombination() + { + return [[Declarations::SOCIAL_WORK_ACTION_TYPE]]; + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriodTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriodTest.php new file mode 100644 index 000000000..aacd1bf55 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriodTest.php @@ -0,0 +1,103 @@ +get(EntityManagerInterface::class); + $dateTimeHelper = self::$container->get(DateTimeHelper::class); + $userHelper = self::$container->get(UserHelper::class); + $personHelper = self::$container->get(LabelPersonHelper::class); + $thirdPartyHelper = self::$container->get(LabelThirdPartyHelper::class); + $translatableStringExportLabelHelper = self::$container->get(TranslatableStringExportLabelHelper::class); + $socialIssueRender = self::$container->get(SocialIssueRender::class); + $socialIssueRepository = self::$container->get(SocialIssueRepository::class); + $socialActionRender = self::$container->get(SocialActionRender::class); + $rollingDateConverter = self::$container->get(RollingDateConverterInterface::class); + $aggregateStringHelper = self::$container->get(AggregateStringHelper::class); + $socialActionRepository = self::$container->get(SocialActionRepository::class); + + yield new ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod( + $entityManager, + $dateTimeHelper, + $userHelper, + $personHelper, + $thirdPartyHelper, + $translatableStringExportLabelHelper, + $socialIssueRender, + $socialIssueRepository, + $socialActionRender, + $rollingDateConverter, + $aggregateStringHelper, + $socialActionRepository, + $this->getParameters(true), + ); + + yield new ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod( + $entityManager, + $dateTimeHelper, + $userHelper, + $personHelper, + $thirdPartyHelper, + $translatableStringExportLabelHelper, + $socialIssueRender, + $socialIssueRepository, + $socialActionRender, + $rollingDateConverter, + $aggregateStringHelper, + $socialActionRepository, + $this->getParameters(false), + ); + } + + public function getFormData() + { + return [ + ['calc_date' => new RollingDate(RollingDate::T_TODAY)], + ]; + } + + public function getModifiersCombination() + { + return [[Declarations::ACP_TYPE]]; + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListAccompanyingPeriodWorkTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListAccompanyingPeriodWorkAssociatePersonOnWorkTest.php similarity index 91% rename from src/Bundle/ChillPersonBundle/Tests/Export/Export/ListAccompanyingPeriodWorkTest.php rename to src/Bundle/ChillPersonBundle/Tests/Export/Export/ListAccompanyingPeriodWorkAssociatePersonOnWorkTest.php index ab8ca7c38..2f65ac85b 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListAccompanyingPeriodWorkTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListAccompanyingPeriodWorkAssociatePersonOnWorkTest.php @@ -19,7 +19,7 @@ use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Test\Export\AbstractExportTest; use Chill\PersonBundle\Export\Declarations; -use Chill\PersonBundle\Export\Export\ListAccompanyingPeriodWork; +use Chill\PersonBundle\Export\Export\ListAccompanyingPeriodWorkAssociatePersonOnWork; use Chill\PersonBundle\Export\Helper\LabelPersonHelper; use Chill\PersonBundle\Repository\SocialWork\SocialActionRepository; use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository; @@ -33,7 +33,7 @@ use Doctrine\ORM\EntityManagerInterface; * * @coversNothing */ -class ListAccompanyingPeriodWorkTest extends AbstractExportTest +class ListAccompanyingPeriodWorkAssociatePersonOnWorkTest extends AbstractExportTest { protected function setUp(): void { @@ -56,7 +56,7 @@ class ListAccompanyingPeriodWorkTest extends AbstractExportTest $aggregateStringHelper = self::$container->get(AggregateStringHelper::class); $socialActionRepository = self::$container->get(SocialActionRepository::class); - yield new ListAccompanyingPeriodWork( + yield new ListAccompanyingPeriodWorkAssociatePersonOnWork( $entityManager, $dateTimeHelper, $userHelper, @@ -72,7 +72,7 @@ class ListAccompanyingPeriodWorkTest extends AbstractExportTest $this->getParameters(true), ); - yield new ListAccompanyingPeriodWork( + yield new ListAccompanyingPeriodWorkAssociatePersonOnWork( $entityManager, $dateTimeHelper, $userHelper, diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml index 57be6bf40..f813455d8 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml @@ -4,14 +4,24 @@ services: autoconfigure: true ## Indicators - Chill\PersonBundle\Export\Export\CountAccompanyingPeriodWork: + Chill\PersonBundle\Export\Export\CountAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod: tags: + # the name is not matching the class name: it is kept for backward compatibility - { name: chill.export, alias: count_social_work_actions } - Chill\PersonBundle\Export\Export\ListAccompanyingPeriodWork: + Chill\PersonBundle\Export\Export\CountAccompanyingPeriodWorkAssociatePersonOnWork: tags: + - { name: chill.export, alias: count_social_work_actions_associate_person_work } + + Chill\PersonBundle\Export\Export\ListAccompanyingPeriodWorkAssociatePersonOnAccompanyingPeriod: + tags: + # the name is not matching the class name: it is kept for backward compatibility - { name: chill.export, alias: list_social_work_actions } + Chill\PersonBundle\Export\Export\ListAccompanyingPeriodWorkAssociatePersonOnWork: + tags: + - { name: chill.export, alias: list_social_work_actions_associate_person_work } + ## FILTERS chill.person.export.filter_social_work_type: class: Chill\PersonBundle\Export\Filter\SocialWorkFilters\SocialWorkTypeFilter diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 87c0e3703..ceebe7d1b 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -379,8 +379,6 @@ Create an average of accompanying courses duration of each person participation Closingdate to apply: Date de fin à prendre en compte lorsque le parcours n'est pas clotûré Exports of social work actions: Exports des actions d'accompagnement -Count social work actions: Nombre d'actions -Count social work actions by various parameters: Compte le nombre d'actions d'accompagnement en fonction de différents filtres. Exports of evaluations: Exports des évaluations @@ -1000,6 +998,16 @@ export: Count household with accompanying course by various parameters.: Compte le nombre de ménages impliqués dans un parcours selon différents filtres. Date of calculation of household members: Date à laquelle les membres du ménages sont comptabilisés + count_accompanying_period_work_associate_person: + title: Nombre d'actions, filtres et regroupements sur les usagers du parcours + description: Compte le nombre d'actions d'accompagnement avec des filtres et regroupements possibles sur les usagers, les parcours et les actions. Les filtres et regroupements agissent sur les usagers concernés par le parcours de l'action. + header: Nombre d'actions + + count_accompanying_period_work_associate_work: + title: Nombre d'actions, filtres et regroupements sur les usagers de l'action + description: Compte le nombre d'actions d'accompagnement avec des filtres et regroupements possibles sur les usagers, les parcours et les actions. Les filtres et regroupements agissent sur les usagers concernés par l'action. + header: Nombre d'actions + aggregator: person: by_household_composition: @@ -1272,6 +1280,14 @@ export: updatedBy: Modifié par timeSpent: Temps de rédaction (minutes) + acpw_associate_work: + List of accompanying period works: Liste des actions, filtres sur les usagers de l'action + List description: Compte le nombre d'actions d'accompagnement avec des filtres possibles sur les usagers, les parcours et les actions. Les filtres et regroupements agissent sur les usagers concernés par l'action. + + acpw_associate_period: + List of accompanying period works: Liste des actions, filtres sur les usagers du parcours + List description: Génère une liste des actions d'accompagnement, avec des filtres possibles sur les usagers, les parcours et les actions. Les filtres des usagers agissent sur les usagers concernés par le parcours de l'action. + acpw: List of accompanying period works: Liste des actions List description: Génère une liste des actions d'accompagnement, filtrée sur différents paramètres. From 847c8238e8de5b6d3e2f3991aaf5ba9851ac4bcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 13 Nov 2023 12:09:18 +0100 Subject: [PATCH 06/10] Export: fix typo in filter "filter accompanying period work on end date --- .changes/unreleased/Fixed-20231113-120855.yaml | 5 +++++ .../AccompanyingPeriodWorkEndDateBetweenDateFilter.php | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changes/unreleased/Fixed-20231113-120855.yaml diff --git a/.changes/unreleased/Fixed-20231113-120855.yaml b/.changes/unreleased/Fixed-20231113-120855.yaml new file mode 100644 index 000000000..6a2003d3d --- /dev/null +++ b/.changes/unreleased/Fixed-20231113-120855.yaml @@ -0,0 +1,5 @@ +kind: Fixed +body: 'Export: fix typo in filter "filter accompanying period work on end date"' +time: 2023-11-13T12:08:55.509927824+01:00 +custom: + Issue: "" diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/AccompanyingPeriodWorkEndDateBetweenDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/AccompanyingPeriodWorkEndDateBetweenDateFilter.php index 373572e54..32bbbaf6e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/AccompanyingPeriodWorkEndDateBetweenDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/AccompanyingPeriodWorkEndDateBetweenDateFilter.php @@ -54,7 +54,7 @@ final readonly class AccompanyingPeriodWorkEndDateBetweenDateFilter implements F public function describeAction($data, $format = 'string'): array { return [ - 'export.filter.work.end_between_dates.Only where end date is between %endDate% and %endDate%', + 'export.filter.work.end_between_dates.Only where start date is between %startDate% and %endDate%', [ '%startDate%' => null !== $data['start_date'] ? $this->rollingDateConverter->convert($data['start_date'])->format('d-m-Y') : '', '%endDate%' => null !== $data['end_date'] ? $this->rollingDateConverter->convert($data['end_date'])->format('d-m-Y') : '', From d01b6db5dc98367e69511e0597faf44bdc9207c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 13 Nov 2023 12:09:43 +0100 Subject: [PATCH 07/10] DX: remove unused property --- .../HouseholdAggregators/ChildrenNumberAggregator.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/ChildrenNumberAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/ChildrenNumberAggregator.php index b73b2e600..cea3de7dd 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/ChildrenNumberAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/ChildrenNumberAggregator.php @@ -19,11 +19,10 @@ use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Contracts\Translation\TranslatorInterface; class ChildrenNumberAggregator implements AggregatorInterface { - public function __construct(private readonly TranslatorInterface $translator, private readonly RollingDateConverterInterface $rollingDateConverter) {} + public function __construct(private readonly RollingDateConverterInterface $rollingDateConverter) {} public function addRole(): ?string { From 1663c6f7c7a42977cb872ef201bdf3ecb48cd4ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 13 Nov 2023 12:56:59 +0100 Subject: [PATCH 08/10] DX: rename CountHousehold => CountHouseholdInPeriod.php + add test --- ...usehold.php => CountHouseholdInPeriod.php} | 4 +- .../Export/CountHouseholdInPeriodTest.php | 58 +++++++++++++++++++ .../config/services/exports_household.yaml | 16 ++--- 3 files changed, 64 insertions(+), 14 deletions(-) rename src/Bundle/ChillPersonBundle/Export/Export/{CountHousehold.php => CountHouseholdInPeriod.php} (95%) create mode 100644 src/Bundle/ChillPersonBundle/Tests/Export/Export/CountHouseholdInPeriodTest.php diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php b/src/Bundle/ChillPersonBundle/Export/Export/CountHouseholdInPeriod.php similarity index 95% rename from src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php rename to src/Bundle/ChillPersonBundle/Export/Export/CountHouseholdInPeriod.php index 82a5c4aa4..8b56be371 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountHouseholdInPeriod.php @@ -26,7 +26,7 @@ use Doctrine\ORM\Query; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; -class CountHousehold implements ExportInterface, GroupedExportInterface +class CountHouseholdInPeriod implements ExportInterface, GroupedExportInterface { private const TR_PREFIX = 'export.export.nb_household_with_course.'; private readonly bool $filterStatsByCenters; @@ -120,6 +120,7 @@ class CountHousehold implements ExportInterface, GroupedExportInterface ->join('person.accompanyingPeriodParticipations', 'acppart') ->join('acppart.accompanyingPeriod', 'acp') ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') + ->andWhere('hmember.startDate <= :count_household_at_date AND (hmember.endDate IS NULL OR hmember.endDate > :count_household_at_date)') ->setParameter('count_household_at_date', $this->rollingDateConverter->convert($data['calc_date'])); $qb @@ -135,7 +136,6 @@ class CountHousehold implements ExportInterface, GroupedExportInterface ' ) ) - ->andWhere('hmember.startDate <= :count_household_at_date AND (hmember.endDate IS NULL OR hmember.endDate > :count_household_at_date)') ->setParameter('authorized_centers', $centers); } diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountHouseholdInPeriodTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountHouseholdInPeriodTest.php new file mode 100644 index 000000000..b29c9a1f9 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountHouseholdInPeriodTest.php @@ -0,0 +1,58 @@ +get(EntityManagerInterface::class); + $rollingDate = self::$container->get(RollingDateConverterInterface::class); + + yield new CountHouseholdInPeriod($em, $rollingDate, $this->getParameters(true)); + yield new CountHouseholdInPeriod($em, $rollingDate, $this->getParameters(false)); + } + + public function getFormData() + { + return [ + ['calc_date' => new RollingDate(RollingDate::T_TODAY)], + ]; + } + + public function getModifiersCombination() + { + return [ + [ + Declarations::HOUSEHOLD_TYPE, + Declarations::ACP_TYPE, + Declarations::PERSON_TYPE, + ]]; + } +} diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_household.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_household.yaml index 1a12c1bc8..15386c2cd 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_household.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_household.yaml @@ -1,38 +1,30 @@ services: + _defaults: + autoconfigure: true + autowire: true ## Indicators - chill.person.export.count_household: - class: Chill\PersonBundle\Export\Export\CountHousehold - autowire: true - autoconfigure: true + Chill\PersonBundle\Export\Export\CountHouseholdInPeriod: tags: - { name: chill.export, alias: count_household } Chill\PersonBundle\Export\Export\ListHouseholdInPeriod: - autowire: true - autoconfigure: true tags: - { name: chill.export, alias: list_household_in_period } ## Filters chill.person.export.filter_household_composition: class: Chill\PersonBundle\Export\Filter\HouseholdFilters\CompositionFilter - autowire: true - autoconfigure: true tags: - { name: chill.export_filter, alias: household_composition_filter } ## Aggregators chill.person.export.aggregator_household_composition: class: Chill\PersonBundle\Export\Aggregator\HouseholdAggregators\CompositionAggregator - autowire: true - autoconfigure: true tags: - { name: chill.export_aggregator, alias: household_composition_aggregator } chill.person.export.aggregator_household_childrennumber: class: Chill\PersonBundle\Export\Aggregator\HouseholdAggregators\ChildrenNumberAggregator - autowire: true - autoconfigure: true tags: - { name: chill.export_aggregator, alias: household_childrennumber_aggregator } From 2e60ba31375c563dfd2db43d55490142c1c4b653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 13 Nov 2023 15:27:07 +0100 Subject: [PATCH 09/10] Export: fix infinite loop in HouseholdVoter --- .changes/unreleased/Fixed-20231113-152621.yaml | 5 +++++ .../Security/Authorization/HouseholdVoter.php | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changes/unreleased/Fixed-20231113-152621.yaml diff --git a/.changes/unreleased/Fixed-20231113-152621.yaml b/.changes/unreleased/Fixed-20231113-152621.yaml new file mode 100644 index 000000000..e897fec30 --- /dev/null +++ b/.changes/unreleased/Fixed-20231113-152621.yaml @@ -0,0 +1,5 @@ +kind: Fixed +body: 'Export: Fix failure in export linked to household' +time: 2023-11-13T15:26:21.891117274+01:00 +custom: + Issue: "189" diff --git a/src/Bundle/ChillPersonBundle/Security/Authorization/HouseholdVoter.php b/src/Bundle/ChillPersonBundle/Security/Authorization/HouseholdVoter.php index 798ed853a..415154457 100644 --- a/src/Bundle/ChillPersonBundle/Security/Authorization/HouseholdVoter.php +++ b/src/Bundle/ChillPersonBundle/Security/Authorization/HouseholdVoter.php @@ -78,7 +78,7 @@ class HouseholdVoter extends Voter implements ProvideRoleHierarchyInterface, Chi return match ($attribute) { self::SEE => $this->checkAssociatedMembersRole($subject, PersonVoter::SEE), self::EDIT => $this->checkAssociatedMembersRole($subject, PersonVoter::UPDATE), - self::STATS => $this->voteOnAttribute($attribute, $subject, $token), + self::STATS => $this->helper->voteOnAttribute($attribute, $subject, $token), default => throw new \UnexpectedValueException('attribute not supported'), }; } From 86e659edd44b735cf090df7e01919c08b04ef1b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 13 Nov 2023 15:28:29 +0100 Subject: [PATCH 10/10] DX: replace some string by constants --- .../ChillMainBundle/Controller/ExportController.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Controller/ExportController.php b/src/Bundle/ChillMainBundle/Controller/ExportController.php index 190d5f1bf..d318fcc58 100644 --- a/src/Bundle/ChillMainBundle/Controller/ExportController.php +++ b/src/Bundle/ChillMainBundle/Controller/ExportController.php @@ -304,7 +304,7 @@ class ExportController extends AbstractController FormType::class, $defaultFormData, [ - 'method' => $isGenerate ? 'GET' : 'POST', + 'method' => $isGenerate ? Request::METHOD_GET : Request::METHOD_POST, 'csrf_protection' => !$isGenerate, ] ); @@ -352,7 +352,7 @@ class ExportController extends AbstractController $form = $this->createCreateFormExport($alias, 'export', $data, $savedExport); - if ('POST' === $request->getMethod()) { + if (Request::METHOD_POST === $request->getMethod()) { $form->handleRequest($request); if ($form->isValid()) { @@ -406,7 +406,7 @@ class ExportController extends AbstractController $form = $this->createCreateFormExport($alias, 'formatter', $data, $savedExport); - if ('POST' === $request->getMethod()) { + if (Request::METHOD_POST === $request->getMethod()) { $form->handleRequest($request); if ($form->isValid()) { @@ -536,7 +536,7 @@ class ExportController extends AbstractController $form = $this->createCreateFormExport($alias, 'centers', [], $savedExport); - if ('POST' === $request->getMethod()) { + if (Request::METHOD_POST === $request->getMethod()) { $form->handleRequest($request); if ($form->isValid()) {