From b17b2a8cfba5aa70abcbe6e34618e70bbe1e315c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 4 Dec 2023 16:30:09 +0100 Subject: [PATCH] Export: add export "number of household associated with an activity" --- .../unreleased/Feature-20231204-162923.yaml | 5 + .../LinkedToACP/CountHouseholdOnActivity.php | 147 ++++++++++++++++++ .../CountHouseholdOnActivity.php | 138 ++++++++++++++++ .../CountHouseholdOnActivityTest.php | 60 +++++++ .../CountHouseholdOnActivityTest.php | 59 +++++++ .../config/services/export.yaml | 8 + .../translations/messages.fr.yml | 8 + 7 files changed, 425 insertions(+) create mode 100644 .changes/unreleased/Feature-20231204-162923.yaml create mode 100644 src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/CountHouseholdOnActivity.php create mode 100644 src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/CountHouseholdOnActivity.php create mode 100644 src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/CountHouseholdOnActivityTest.php create mode 100644 src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToPerson/CountHouseholdOnActivityTest.php diff --git a/.changes/unreleased/Feature-20231204-162923.yaml b/.changes/unreleased/Feature-20231204-162923.yaml new file mode 100644 index 000000000..745ad159a --- /dev/null +++ b/.changes/unreleased/Feature-20231204-162923.yaml @@ -0,0 +1,5 @@ +kind: Feature +body: Add export "number of household associate with an exchange" +time: 2023-12-04T16:29:23.341485328+01:00 +custom: + Issue: "191" diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/CountHouseholdOnActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/CountHouseholdOnActivity.php new file mode 100644 index 000000000..41c05494c --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/CountHouseholdOnActivity.php @@ -0,0 +1,147 @@ +repository = $em->getRepository(Activity::class); + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } + + public function buildForm(FormBuilderInterface $builder) {} + + public function getFormDefaultData(): array + { + return []; + } + + public function getAllowedFormattersTypes(): array + { + return [FormatterInterface::TYPE_TABULAR]; + } + + public function getDescription(): string + { + return 'export.export.count_household_on_activity.description'; + } + + public function getGroup(): string + { + return 'Exports of activities linked to an accompanying period'; + } + + public function getLabels($key, array $values, $data) + { + if ('export_count_activity' !== $key) { + throw new \LogicException("the key {$key} is not used by this export"); + } + + return static fn ($value) => '_header' === $value ? 'export.export.count_household_on_activity.header' : $value; + } + + public function getQueryKeys($data): array + { + return ['export_count_activity']; + } + + public function getResult($query, $data) + { + return $query->getQuery()->getResult(Query::HYDRATE_SCALAR); + } + + public function getTitle(): string + { + return 'export.export.count_household_on_activity.title'; + } + + public function getType(): string + { + return Declarations::ACTIVITY; + } + + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) + { + $centers = array_map(static fn ($el) => $el['center'], $acl); + + $qb = $this->repository + ->createQueryBuilder('activity') + ->join('activity.persons', 'person') + ->join('activity.accompanyingPeriod', 'acp') + ->join( + HouseholdMember::class, + 'householdmember', + Query\Expr\Join::WITH, + 'person.id = IDENTITY(householdmember.person) AND householdmember.startDate <= activity.date AND (householdmember.endDate IS NULL OR householdmember.endDate > activity.date)' + ) + ->join('householdmember.household', 'household'); + + if ($this->filterStatsByCenters) { + $qb + ->andWhere( + $qb->expr()->exists( + 'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part + JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person) + WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) + ' + ) + ) + ->setParameter('authorized_centers', $centers); + } + + AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); + + $qb->select('COUNT(DISTINCT household.id) as export_count_activity'); + + return $qb; + } + + public function requiredRole(): string + { + return ActivityStatsVoter::STATS; + } + + public function supportsModifiers(): array + { + return [ + Declarations::ACTIVITY, + Declarations::ACTIVITY_ACP, + PersonDeclarations::ACP_TYPE, + PersonDeclarations::PERSON_TYPE, + PersonDeclarations::HOUSEHOLD_TYPE, + ]; + } +} diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/CountHouseholdOnActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/CountHouseholdOnActivity.php new file mode 100644 index 000000000..31111a083 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/CountHouseholdOnActivity.php @@ -0,0 +1,138 @@ +filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } + + public function buildForm(FormBuilderInterface $builder) {} + + public function getFormDefaultData(): array + { + return []; + } + + public function getAllowedFormattersTypes() + { + return [FormatterInterface::TYPE_TABULAR]; + } + + public function getDescription() + { + return 'export.export.count_household_on_activity_person.description'; + } + + public function getGroup(): string + { + return 'Exports of activities linked to a person'; + } + + public function getLabels($key, array $values, $data) + { + if ('export_count_activity' !== $key) { + throw new \LogicException("the key {$key} is not used by this export"); + } + + return static fn ($value) => '_header' === $value ? 'export.export.count_household_on_activity_person.header' : $value; + } + + public function getQueryKeys($data) + { + return ['export_count_activity']; + } + + public function getResult($query, $data) + { + return $query->getQuery()->getResult(Query::HYDRATE_SCALAR); + } + + public function getTitle() + { + return 'export.export.count_household_on_activity_person.title'; + } + + public function getType(): string + { + return Declarations::ACTIVITY; + } + + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) + { + $centers = array_map(static fn ($el) => $el['center'], $acl); + + $qb = $this->activityRepository + ->createQueryBuilder('activity') + ->join('activity.person', 'person') + ->join( + HouseholdMember::class, + 'householdmember', + Query\Expr\Join::WITH, + 'person = householdmember.person AND householdmember.startDate <= activity.date AND (householdmember.endDate IS NULL OR householdmember.endDate > activity.date)' + ) + ->join('householdmember.household', 'household'); + + $qb->select('COUNT(DISTINCT household.id) as export_count_activity'); + + if ($this->filterStatsByCenters) { + $qb + ->join('person.centerHistory', 'centerHistory') + ->where( + $qb->expr()->andX( + $qb->expr()->lte('centerHistory.startDate', 'activity.date'), + $qb->expr()->orX( + $qb->expr()->isNull('centerHistory.endDate'), + $qb->expr()->gt('centerHistory.endDate', 'activity.date') + ) + ) + ) + ->andWhere($qb->expr()->in('centerHistory.center', ':centers')) + ->setParameter('centers', $centers); + } + + return $qb; + } + + public function requiredRole(): string + { + return ActivityStatsVoter::STATS; + } + + public function supportsModifiers() + { + return [ + Declarations::ACTIVITY, + Declarations::ACTIVITY_PERSON, + PersonDeclarations::PERSON_TYPE, + PersonDeclarations::HOUSEHOLD_TYPE, + ]; + } +} diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/CountHouseholdOnActivityTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/CountHouseholdOnActivityTest.php new file mode 100644 index 000000000..132813176 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/CountHouseholdOnActivityTest.php @@ -0,0 +1,60 @@ +entityManager = self::$container->get(EntityManagerInterface::class); + } + + public function getExport() + { + yield new CountHouseholdOnActivity($this->entityManager, $this->getParameters(true)); + yield new CountHouseholdOnActivity($this->entityManager, $this->getParameters(false)); + } + + public function getFormData() + { + return [ + [], + ]; + } + + public function getModifiersCombination() + { + return [ + [ + Declarations::ACTIVITY, + Declarations::ACTIVITY_ACP, + PersonDeclarations::ACP_TYPE, + PersonDeclarations::PERSON_TYPE, + PersonDeclarations::HOUSEHOLD_TYPE, + ], + ]; + } +} diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToPerson/CountHouseholdOnActivityTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToPerson/CountHouseholdOnActivityTest.php new file mode 100644 index 000000000..65fdc6c4c --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToPerson/CountHouseholdOnActivityTest.php @@ -0,0 +1,59 @@ +activityRepository = self::$container->get(ActivityRepository::class); + } + + public function getExport() + { + yield new CountHouseholdOnActivity($this->activityRepository, $this->getParameters(true)); + yield new CountHouseholdOnActivity($this->activityRepository, $this->getParameters(false)); + } + + public function getFormData() + { + return [ + [], + ]; + } + + public function getModifiersCombination() + { + return [ + [ + Declarations::ACTIVITY, + Declarations::ACTIVITY_PERSON, + PersonDeclarations::PERSON_TYPE, + PersonDeclarations::HOUSEHOLD_TYPE, + ], + ]; + } +} diff --git a/src/Bundle/ChillActivityBundle/config/services/export.yaml b/src/Bundle/ChillActivityBundle/config/services/export.yaml index 52294be40..ef691ba0d 100644 --- a/src/Bundle/ChillActivityBundle/config/services/export.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/export.yaml @@ -20,6 +20,14 @@ services: tags: - { name: chill.export, alias: 'count_person_on_activity' } + Chill\ActivityBundle\Export\Export\LinkedToACP\CountHouseholdOnActivity: + tags: + - { name: chill.export, alias: 'count_household_on_activity_acp' } + + Chill\ActivityBundle\Export\Export\LinkedToPerson\CountHouseholdOnActivity: + tags: + - { name: chill.export, alias: 'count_household_on_activity_person' } + chill.activity.export.count_activity_linked_to_acp: class: Chill\ActivityBundle\Export\Export\LinkedToACP\CountActivity tags: diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index 036f75ce3..be7359cb0 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -337,6 +337,14 @@ export: title: Nombre d'usagers concernés par les échanges description: Compte le nombre d'usagers concernés par les échanges. Si un usager est présent dans plusieurs échanges, il n'est comptabilisé qu'une seule fois. header: Nombre d'usagers concernés par des échanges + count_household_on_activity: + title: Nombre de ménages concernés par les échanges + description: Compte le nombre de ménages concernés par les échanges. Si un ménage est présent dans plusieurs échanges, il n'est comptabilisé qu'une seule fois. Les usagers sans ménages ne sont pas comptabilisés. + header: Nombre de ménage concernés par des échanges + count_household_on_activity_person: + title: Nombre de ménages concernés par les échanges + description: Compte le nombre de ménages concernés par les échanges. Si un ménage est présent dans plusieurs échanges, il n'est comptabilisé qu'une seule fois. Les usagers sans ménages ne sont pas comptabilisés. Lorsqu'un usager change de ménage, chaque ménage est comptabilisé une fois. + header: Nombre de ménage concernés par des échanges list: activity: users name: Nom des utilisateurs