From f799fe0649fd579b46664cf729464a4f3d00f19c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 18 Oct 2023 11:46:15 +0200 Subject: [PATCH 01/16] [export] add a grouping of accompanying period by opening and closing date --- .../unreleased/Feature-20231018-113825.yaml | 6 ++ .../Export/Aggregator/DateAggregator.php | 1 - .../ClosingDateAggregator.php | 88 +++++++++++++++++++ .../OpeningDateAggregator.php | 88 +++++++++++++++++++ .../Export/Enum/DateGroupingChoiceEnum.php | 19 ++++ .../ClosingDateAggregatorTest.php | 66 ++++++++++++++ .../OpeningDateAggregatorTest.php | 66 ++++++++++++++ .../services/exports_accompanying_course.yaml | 8 ++ .../translations/messages.fr.yml | 13 +++ 9 files changed, 354 insertions(+), 1 deletion(-) create mode 100644 .changes/unreleased/Feature-20231018-113825.yaml create mode 100644 src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ClosingDateAggregator.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/OpeningDateAggregator.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Enum/DateGroupingChoiceEnum.php create mode 100644 src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AccompanyingCourseAggregators/ClosingDateAggregatorTest.php create mode 100644 src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AccompanyingCourseAggregators/OpeningDateAggregatorTest.php diff --git a/.changes/unreleased/Feature-20231018-113825.yaml b/.changes/unreleased/Feature-20231018-113825.yaml new file mode 100644 index 000000000..f8922b356 --- /dev/null +++ b/.changes/unreleased/Feature-20231018-113825.yaml @@ -0,0 +1,6 @@ +kind: Feature +body: '[export] Add a filter "grouping accompanying period by opening date" and "trouping + accompanying period by closing date"' +time: 2023-10-18T11:38:25.80362952+02:00 +custom: + Issue: "172" diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/DateAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/DateAggregator.php index f7315140e..9d9e5ed61 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/DateAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/DateAggregator.php @@ -73,7 +73,6 @@ class DateAggregator implements AggregatorInterface 'choices' => self::CHOICES, 'multiple' => false, 'expanded' => true, - 'empty_data' => self::DEFAULT_CHOICE, ]); } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ClosingDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ClosingDateAggregator.php new file mode 100644 index 000000000..ce96c40c9 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ClosingDateAggregator.php @@ -0,0 +1,88 @@ +add('frequency', ChoiceType::class, [ + 'choices' => array_combine( + array_map(fn (DateGroupingChoiceEnum $c) => 'export.enum.frequency.'.$c->value, DateGroupingChoiceEnum::cases()), + array_map(fn (DateGroupingChoiceEnum $c) => $c->value, DateGroupingChoiceEnum::cases()), + ), + 'label' => 'export.aggregator.course.by_closing_date.frequency', + 'multiple' => false, + 'expanded' => true, + ]); + } + + public function getFormDefaultData(): array + { + return [ + 'frequency' => 'year', + ]; + } + + public function getLabels($key, array $values, mixed $data) + { + return function (null|string $value): string { + if ('_header' === $value) { + return 'export.aggregator.course.by_closing_date.header'; + } + + return (string) $value; + }; + } + + public function getQueryKeys($data) + { + return [self::PREFIX.'_closing_date']; + } + + public function getTitle() + { + return 'export.aggregator.course.by_closing_date.title'; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $p = self::PREFIX; + + $qb->addSelect(sprintf("TO_CHAR(acp.closingDate, '%s') AS {$p}_closing_date", $data['frequency'])); + $qb->addGroupBy("{$p}_closing_date"); + $qb->addOrderBy("{$p}_closing_date", 'DESC'); + } + + public function applyOn() + { + return Declarations::ACP_TYPE; + } +} diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/OpeningDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/OpeningDateAggregator.php new file mode 100644 index 000000000..bf71d04d8 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/OpeningDateAggregator.php @@ -0,0 +1,88 @@ +add('frequency', ChoiceType::class, [ + 'choices' => array_combine( + array_map(fn (DateGroupingChoiceEnum $c) => 'export.enum.frequency.'.$c->value, DateGroupingChoiceEnum::cases()), + array_map(fn (DateGroupingChoiceEnum $c) => $c->value, DateGroupingChoiceEnum::cases()), + ), + 'label' => 'export.aggregator.course.by_opening_date.frequency', + 'multiple' => false, + 'expanded' => true, + ]); + } + + public function getFormDefaultData(): array + { + return [ + 'frequency' => 'year', + ]; + } + + public function getLabels($key, array $values, mixed $data) + { + return function (null|string $value): string { + if ('_header' === $value) { + return 'export.aggregator.course.by_opening_date.header'; + } + + return (string) $value; + }; + } + + public function getQueryKeys($data) + { + return [self::PREFIX.'_opening_date']; + } + + public function getTitle() + { + return 'export.aggregator.course.by_opening_date.title'; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $p = self::PREFIX; + + $qb->addSelect(sprintf("TO_CHAR(acp.openingDate, '%s') AS {$p}_opening_date", $data['frequency'])); + $qb->addGroupBy("{$p}_opening_date"); + $qb->addOrderBy("{$p}_opening_date", 'DESC'); + } + + public function applyOn() + { + return Declarations::ACP_TYPE; + } +} diff --git a/src/Bundle/ChillPersonBundle/Export/Enum/DateGroupingChoiceEnum.php b/src/Bundle/ChillPersonBundle/Export/Enum/DateGroupingChoiceEnum.php new file mode 100644 index 000000000..2b1ffc816 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Enum/DateGroupingChoiceEnum.php @@ -0,0 +1,19 @@ +get(ClosingDateAggregator::class); + self::$entityManager = self::$container->get(EntityManagerInterface::class); + } + + public function getAggregator() + { + return self::$closingDateAggregator; + } + + public function getFormData() + { + yield ['frequency' => 'YYYY']; + yield ['frequency' => 'YYYY-MM']; + yield ['frequency' => 'YYYY-IV']; + } + + public function getQueryBuilders() + { + self::bootKernel(); + self::$entityManager = self::$container->get(EntityManagerInterface::class); + + $data = [ + self::$entityManager->createQueryBuilder() + ->select('count(acp.id)') + ->from(AccompanyingPeriod::class, 'acp'), + ]; + + self::ensureKernelShutdown(); + + return $data; + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AccompanyingCourseAggregators/OpeningDateAggregatorTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AccompanyingCourseAggregators/OpeningDateAggregatorTest.php new file mode 100644 index 000000000..77d26b278 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AccompanyingCourseAggregators/OpeningDateAggregatorTest.php @@ -0,0 +1,66 @@ +get(OpeningDateAggregator::class); + self::$entityManager = self::$container->get(EntityManagerInterface::class); + } + + public function getAggregator() + { + return self::$openingDateAggregator; + } + + public function getFormData() + { + yield ['frequency' => 'YYYY']; + yield ['frequency' => 'YYYY-MM']; + yield ['frequency' => 'YYYY-IV']; + } + + public function getQueryBuilders() + { + self::bootKernel(); + self::$entityManager = self::$container->get(EntityManagerInterface::class); + + $data = [ + self::$entityManager->createQueryBuilder() + ->select('count(acp.id)') + ->from(AccompanyingPeriod::class, 'acp'), + ]; + + self::ensureKernelShutdown(); + + return $data; + } +} diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml index c5a2dba68..4eaaf67b0 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml @@ -251,3 +251,11 @@ services: Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators\ScopeWorkingOnCourseAggregator: tags: - { name: chill.export_aggregator, alias: accompanyingcourse_scope_working_on_course_aggregator } + + Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators\OpeningDateAggregator: + tags: + - { name: chill.export_aggregator, alias: accompanyingcourse_opening_date_aggregator } + + Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators\ClosingDateAggregator: + tags: + - { name: chill.export_aggregator, alias: accompanyingcourse_closing_date_aggregator } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 097b5e79f..0c5a0fe57 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -981,6 +981,11 @@ notification: personId: Identifiant de l'usager export: + enum: + frequency: + YYYY-IW: par semaine + YYYY-MM: par mois + YYYY: par année export: acp_stats: avg_duration: Moyenne de la durée de participation de chaque usager concerné @@ -1037,6 +1042,14 @@ export: Calc date: Date de calcul du service de l'intervenant by_scope: Group course by scope: Grouper les parcours par service + by_opening_date: + title: Grouper les parcours par date d'ouverture + frequency: Intervalle de regroupement + header: Date d'ouverture des parcours (période) + by_closing_date: + title: Grouper les parcours par date de cloture + frequency: Intervalle de regroupement + header: Date de cloture des parcours (période) course_work: by_treating_agent: From a4edb34668bc23512662346f771c945db333ea95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 18 Oct 2023 13:32:26 +0200 Subject: [PATCH 02/16] [export] add a filter and aggregator on accompanying period work: group/filter by handling third party --- .../unreleased/Feature-20231018-133203.yaml | 6 + .../Resources/views/Export/new.html.twig | 52 +++--- .../HandlingThirdPartyAggregator.php | 73 ++++++++ .../HandlingThirdPartyFilter.php | 78 ++++++++ .../HandlingThirdPartyAggregatorTest.php | 60 ++++++ .../HandlingThirdPartyFilterTest.php | 71 +++++++ .../services/exports_social_actions.yaml | 173 ++++++++---------- .../translations/messages.fr.yml | 7 + .../Export/Helper/LabelThirdPartyHelper.php | 2 +- 9 files changed, 397 insertions(+), 125 deletions(-) create mode 100644 .changes/unreleased/Feature-20231018-133203.yaml create mode 100644 src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/HandlingThirdPartyAggregator.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HandlingThirdPartyFilter.php create mode 100644 src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/SocialWorkAggregators/HandlingThirdPartyAggregatorTest.php create mode 100644 src/Bundle/ChillPersonBundle/Tests/Export/Filter/SocialWorkFilters/HandlingThirdPartyFilterTest.php diff --git a/.changes/unreleased/Feature-20231018-133203.yaml b/.changes/unreleased/Feature-20231018-133203.yaml new file mode 100644 index 000000000..f839ebcf3 --- /dev/null +++ b/.changes/unreleased/Feature-20231018-133203.yaml @@ -0,0 +1,6 @@ +kind: Feature +body: '[export] add a filter and aggregator on accompanying period work: group/filter + by handling third party' +time: 2023-10-18T13:32:03.565201495+02:00 +custom: + Issue: "172" diff --git a/src/Bundle/ChillMainBundle/Resources/views/Export/new.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Export/new.html.twig index 8ef4c3ad7..82b3e0c0c 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Export/new.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Export/new.html.twig @@ -1,5 +1,5 @@ {# - * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, + * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, / * * This program is free software: you can redistribute it and/or modify @@ -36,84 +36,84 @@ {% block content %}
- + {{ include('@ChillMain/Export/_breadcrumb.html.twig') }} - +

{{ export.title|trans }}

- +

{{ export.description|trans }}

- + {{ form_start(form) }} - + {% if form.children.export.children.filters is defined %} {% if form.children.export.children.filters is not empty%} - +

{{ 'Filters'| trans }}

- + {{ form_errors(form.children.export.children.filters) }} - +
{% for filter_form in form.children.export.children.filters %}
- + {{ form_widget(filter_form.enabled, { 'label': filter_form.vars.label, 'label_attr': { 'class': 'h6' }, 'attr': { 'data-display-target': filter_form.vars.id } }) }} - +
{{ form_widget(filter_form.form) }} {{ form_errors(filter_form) }}
- +
{% endfor %}
- + {% else %} {# render the children, to mark the widget as 'rendered' #} {{ form_widget(form.children.export.children.filters) }} {% endif %} {% endif %} - + {% if form.children.export.children.aggregators is defined %} {% if form.children.export.children.aggregators is not empty %} - +

{{ 'Aggregators'| trans }}

- +
{% for aggregator_form in form.children.export.children.aggregators %}
- + {{ form_widget(aggregator_form.enabled, { 'label': aggregator_form.vars.label, 'label_attr': { 'class': 'h6' }, 'attr': { 'data-display-target': aggregator_form.vars.id } }) }} - +
{{ form_widget(aggregator_form.form) }} {{ form_errors(aggregator_form) }}
- +
{% endfor %}
- + {% else %} {# render the children, to mark the widget as 'rendered' #} {{ form_widget(form.children.export.children.aggregators) }} {% endif %} {% endif %} - - + + {% if form.children.export.children.export.children|length > 0 %} - + @@ -123,12 +123,12 @@ {{ form_widget(form.children.export.children.export) }} - + {% else %} {# render the children, to mark the widget as 'rendered' #} {{ form_widget(form.children.export.children.export) }} {% endif %} - + {% if form.children.export.children.pick_formatter is defined %}

@@ -140,7 +140,7 @@ {{ form_row(form.children.export.children.pick_formatter.children.alias, { 'label' : 'Formatter' }) }}

{% endif %} - +

{{ form_widget(form.submit, { 'attr' : { 'class' : 'btn btn-create' }, 'label' : 'Go to formatter options' } ) }}

{{ form_end(form) }} diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/HandlingThirdPartyAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/HandlingThirdPartyAggregator.php new file mode 100644 index 000000000..f58246a25 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/HandlingThirdPartyAggregator.php @@ -0,0 +1,73 @@ +labelThirdPartyHelper->getLabel($key, $values, 'export.aggregator.course_work.by_handling_third_party.header'); + } + + public function getQueryKeys($data) + { + return [self::PREFIX.'_h3party']; + } + + public function getTitle() + { + return 'export.aggregator.course_work.by_handling_third_party.title'; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $p = self::PREFIX; + + $qb + ->addSelect("IDENTITY(acpw.handlingThierParty) AS {$p}_h3party") + ->addGroupBy("{$p}_h3party"); + } + + public function applyOn() + { + return Declarations::SOCIAL_WORK_ACTION_TYPE; + } +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HandlingThirdPartyFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HandlingThirdPartyFilter.php new file mode 100644 index 000000000..80bc7b04a --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HandlingThirdPartyFilter.php @@ -0,0 +1,78 @@ +add('handling_3parties', PickThirdpartyDynamicType::class, [ + 'label' => 'export.filter.work.by_handling3party.pick_3parties', + 'multiple' => true, + ]); + } + + public function getFormDefaultData(): array + { + return ['handling_3parties' => []]; + } + + public function describeAction($data, $format = 'string') + { + return [ + 'export.filter.work.by_handling3party.Only 3 parties %3parties%', + [ + '%3parties%' => implode( + ', ', + array_map(fn (ThirdParty $thirdParty) => $this->thirdPartyRender->renderString($thirdParty, []), $data['handling_3parties']) + ), + ], + ]; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $p = self::PREFIX; + + $qb->andWhere("acpw.handlingThierParty IN (:{$p}_3ps)"); + $qb->setParameter("{$p}_3ps", $data['handling_3parties']); + } + + public function applyOn() + { + return Declarations::SOCIAL_WORK_ACTION_TYPE; + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/SocialWorkAggregators/HandlingThirdPartyAggregatorTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/SocialWorkAggregators/HandlingThirdPartyAggregatorTest.php new file mode 100644 index 000000000..3677cedf2 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/SocialWorkAggregators/HandlingThirdPartyAggregatorTest.php @@ -0,0 +1,60 @@ +get(HandlingThirdPartyAggregator::class); + } + + public function getAggregator() + { + return self::$handlingThirdPartyAggregator; + } + + public function getFormData() + { + return [ + [], + ]; + } + + public function getQueryBuilders() + { + self::bootKernel(); + + $em = self::$container + ->get(EntityManagerInterface::class); + + return [ + $em->createQueryBuilder() + ->select('count(acpw.id)') + ->from(AccompanyingPeriodWork::class, 'acpw'), + ]; + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/SocialWorkFilters/HandlingThirdPartyFilterTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/SocialWorkFilters/HandlingThirdPartyFilterTest.php new file mode 100644 index 000000000..e454a10fc --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/SocialWorkFilters/HandlingThirdPartyFilterTest.php @@ -0,0 +1,71 @@ +thirdPartyRender = self::$container->get(ThirdPartyRender::class); + } + + public function getFilter() + { + return new HandlingThirdPartyFilter($this->thirdPartyRender); + } + + public function getFormData() + { + self::bootKernel(); + + $em = self::$container->get(EntityManagerInterface::class); + + $thirdParties = $em->createQuery('SELECT tp FROM '.ThirdParty::class.' tp') + ->setMaxResults(2) + ->getResult(); + + return [ + [ + 'handling_3parties' => $thirdParties, + ], + ]; + } + + public function getQueryBuilders() + { + self::bootKernel(); + + $em = self::$container->get(EntityManagerInterface::class); + + return [ + $em->createQueryBuilder() + ->select('acpw.id') + ->from(AccompanyingPeriodWork::class, 'acpw'), + ]; + } +} diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml index c0e6abc4b..57be6bf40 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml @@ -1,116 +1,93 @@ services: + _defaults: + autowire: true + autoconfigure: true - ## Indicators - Chill\PersonBundle\Export\Export\CountAccompanyingPeriodWork: - autowire: true - autoconfigure: true - tags: - - { name: chill.export, alias: count_social_work_actions } + ## Indicators + Chill\PersonBundle\Export\Export\CountAccompanyingPeriodWork: + tags: + - { name: chill.export, alias: count_social_work_actions } - Chill\PersonBundle\Export\Export\ListAccompanyingPeriodWork: - autowire: true - autoconfigure: true - tags: - - { name: chill.export, alias: list_social_work_actions } + Chill\PersonBundle\Export\Export\ListAccompanyingPeriodWork: + tags: + - { name: chill.export, alias: list_social_work_actions } - ## FILTERS - chill.person.export.filter_social_work_type: - class: Chill\PersonBundle\Export\Filter\SocialWorkFilters\SocialWorkTypeFilter - autowire: true - autoconfigure: true - tags: - - { name: chill.export_filter, alias: social_work_type_filter } + ## FILTERS + chill.person.export.filter_social_work_type: + class: Chill\PersonBundle\Export\Filter\SocialWorkFilters\SocialWorkTypeFilter + tags: + - { name: chill.export_filter, alias: social_work_type_filter } - chill.person.export.filter_scope: - class: Chill\PersonBundle\Export\Filter\SocialWorkFilters\ScopeFilter - autowire: true - autoconfigure: true - tags: - - { name: chill.export_filter, alias: social_work_actions_scope_filter } + chill.person.export.filter_scope: + class: Chill\PersonBundle\Export\Filter\SocialWorkFilters\ScopeFilter + tags: + - { name: chill.export_filter, alias: social_work_actions_scope_filter } - chill.person.export.filter_job: - class: Chill\PersonBundle\Export\Filter\SocialWorkFilters\JobFilter - autowire: true - autoconfigure: true - tags: - - { name: chill.export_filter, alias: social_work_actions_job_filter } + chill.person.export.filter_job: + class: Chill\PersonBundle\Export\Filter\SocialWorkFilters\JobFilter + tags: + - { name: chill.export_filter, alias: social_work_actions_job_filter } - chill.person.export.filter_treatingagent: - class: Chill\PersonBundle\Export\Filter\SocialWorkFilters\ReferrerFilter - autowire: true - autoconfigure: true - tags: - - { name: chill.export_filter, alias: social_work_actions_treatingagent_filter } + chill.person.export.filter_treatingagent: + class: Chill\PersonBundle\Export\Filter\SocialWorkFilters\ReferrerFilter + tags: + - { name: chill.export_filter, alias: social_work_actions_treatingagent_filter } - Chill\PersonBundle\Export\Filter\SocialWorkFilters\CurrentActionFilter: - autowire: true - autoconfigure: true - tags: - - { name: chill.export_filter, alias: social_work_actions_current_filter } + Chill\PersonBundle\Export\Filter\SocialWorkFilters\CurrentActionFilter: + tags: + - { name: chill.export_filter, alias: social_work_actions_current_filter } - Chill\PersonBundle\Export\Filter\SocialWorkFilters\AccompanyingPeriodWorkStartDateBetweenDateFilter: - autowire: true - autoconfigure: true - tags: - - { name: chill.export_filter, alias: social_work_actions_start_btw_dates_filter } + Chill\PersonBundle\Export\Filter\SocialWorkFilters\AccompanyingPeriodWorkStartDateBetweenDateFilter: + tags: + - { name: chill.export_filter, alias: social_work_actions_start_btw_dates_filter } - Chill\PersonBundle\Export\Filter\SocialWorkFilters\AccompanyingPeriodWorkEndDateBetweenDateFilter: - autowire: true - autoconfigure: true - tags: - - { name: chill.export_filter, alias: social_work_actions_end_btw_dates_filter } + Chill\PersonBundle\Export\Filter\SocialWorkFilters\AccompanyingPeriodWorkEndDateBetweenDateFilter: + tags: + - { name: chill.export_filter, alias: social_work_actions_end_btw_dates_filter } - ## AGGREGATORS - chill.person.export.aggregator_action_type: - class: Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\ActionTypeAggregator - autowire: true - autoconfigure: true - tags: - - { name: chill.export_aggregator, alias: social_work_actions_action_type_aggregator } + ## AGGREGATORS + chill.person.export.aggregator_action_type: + class: Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\ActionTypeAggregator + tags: + - { name: chill.export_aggregator, alias: social_work_actions_action_type_aggregator } - chill.person.export.aggregator_treatingagent_scope: - class: Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\ScopeAggregator - autowire: true - autoconfigure: true - tags: - - { name: chill.export_aggregator, alias: social_work_actions_treatingagent_scope_aggregator } + chill.person.export.aggregator_treatingagent_scope: + class: Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\ScopeAggregator + tags: + - { name: chill.export_aggregator, alias: social_work_actions_treatingagent_scope_aggregator } - chill.person.export.aggregator_treatingagent_job: - class: Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\JobAggregator - autowire: true - autoconfigure: true - tags: - - { name: chill.export_aggregator, alias: social_work_actions_treatingagent_job_aggregator } + chill.person.export.aggregator_treatingagent_job: + class: Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\JobAggregator + tags: + - { name: chill.export_aggregator, alias: social_work_actions_treatingagent_job_aggregator } - Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\ReferrerAggregator: - autowire: true - autoconfigure: true - tags: - - { name: chill.export_aggregator, alias: social_work_actions_treatingagent_aggregator } + Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\ReferrerAggregator: + tags: + - { name: chill.export_aggregator, alias: social_work_actions_treatingagent_aggregator } - chill.person.export.aggregator_goal: - class: Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\GoalAggregator - autowire: true - autoconfigure: true - tags: - - { name: chill.export_aggregator, alias: social_work_actions_goal_aggregator } + chill.person.export.aggregator_goal: + class: Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\GoalAggregator + tags: + - { name: chill.export_aggregator, alias: social_work_actions_goal_aggregator } - chill.person.export.aggregator_result: - class: Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\ResultAggregator - autowire: true - autoconfigure: true - tags: - - { name: chill.export_aggregator, alias: social_work_actions_result_aggregator } + chill.person.export.aggregator_result: + class: Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\ResultAggregator + tags: + - { name: chill.export_aggregator, alias: social_work_actions_result_aggregator } - chill.person.export.aggregator_goalresult: - class: Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\GoalResultAggregator - autowire: true - autoconfigure: true - tags: - - { name: chill.export_aggregator, alias: social_work_actions_goal_result_aggregator } + chill.person.export.aggregator_goalresult: + class: Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\GoalResultAggregator + tags: + - { name: chill.export_aggregator, alias: social_work_actions_goal_result_aggregator } - Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\CurrentActionAggregator: - autowire: true - autoconfigure: true - tags: - - { name: chill.export_aggregator, alias: social_work_actions_current_aggregator } + Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\CurrentActionAggregator: + tags: + - { name: chill.export_aggregator, alias: social_work_actions_current_aggregator } + + Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\HandlingThirdPartyAggregator: + tags: + - { name: chill.export_aggregator, alias: accompanyingcourse_handling3party_aggregator } + + Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters\HandlingThirdPartyFilter: + tags: + - { name: chill.export_filter, alias: 'acpw_handling3party_filter'} diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 0c5a0fe57..4ab5d88a6 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -1066,6 +1066,9 @@ export: by_agent_job: Group by treating agent job: Grouper les actions par métier de l'agent traitant Calc date: Date de calcul du métier de l'agent traitant + by_handling_third_party: + title: Grouper les actions par tiers traitant + header: Tiers traitant eval: by_end_date: @@ -1181,6 +1184,10 @@ export: Calc date: Date à laquelle l'agent est en situation de désignation sur l'action calc_date_help: Il s'agit de la date à laquelle l'agent est actif comme agent traitant de l'action, et non la date à la quelle l'agent est désigné comme agent traitant. "Filtered by treating agent: only %agents%": "Filtré par agent traitant: uniquement %agents%" + by_handling3party: + title: Filtrer les actions par tiers traitant + Only 3 parties %3parties%: "Seulement les actions d'accompagnement qui ont pour tiers traitant: %3parties%" + pick_3parties: Tiers traitants des actions list: person_with_acp: diff --git a/src/Bundle/ChillThirdPartyBundle/Export/Helper/LabelThirdPartyHelper.php b/src/Bundle/ChillThirdPartyBundle/Export/Helper/LabelThirdPartyHelper.php index 9b4cbfa75..e92cdae93 100644 --- a/src/Bundle/ChillThirdPartyBundle/Export/Helper/LabelThirdPartyHelper.php +++ b/src/Bundle/ChillThirdPartyBundle/Export/Helper/LabelThirdPartyHelper.php @@ -25,7 +25,7 @@ class LabelThirdPartyHelper return $header; } - if (null === $value || null === $thirdParty = $this->thirdPartyRepository->find($value)) { + if ('' === $value || null === $value || null === $thirdParty = $this->thirdPartyRepository->find($value)) { return ''; } From 11fb9bcd0b170143a82d78fc1fc8390186f609d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 18 Oct 2023 16:03:26 +0200 Subject: [PATCH 03/16] [export] add a filter and aggregator on activities: filter/group by persons taking part to the activity --- .../unreleased/Feature-20231018-160235.yaml | 6 ++ .../Export/Aggregator/PersonsAggregator.php | 78 +++++++++++++++++ .../Export/Filter/PersonsFilter.php | 87 +++++++++++++++++++ .../Aggregator/PersonsAggregatorTest.php | 60 +++++++++++++ .../Tests/Export/Filter/PersonsFilterTest.php | 72 +++++++++++++++ .../config/services/export.yaml | 8 ++ .../translations/messages.fr.yml | 7 ++ .../Export/Helper/LabelPersonHelper.php | 15 ++++ 8 files changed, 333 insertions(+) create mode 100644 .changes/unreleased/Feature-20231018-160235.yaml create mode 100644 src/Bundle/ChillActivityBundle/Export/Aggregator/PersonsAggregator.php create mode 100644 src/Bundle/ChillActivityBundle/Export/Filter/PersonsFilter.php create mode 100644 src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/PersonsAggregatorTest.php create mode 100644 src/Bundle/ChillActivityBundle/Tests/Export/Filter/PersonsFilterTest.php diff --git a/.changes/unreleased/Feature-20231018-160235.yaml b/.changes/unreleased/Feature-20231018-160235.yaml new file mode 100644 index 000000000..87fe1de0c --- /dev/null +++ b/.changes/unreleased/Feature-20231018-160235.yaml @@ -0,0 +1,6 @@ +kind: Feature +body: '[export] add a filter and aggregator on activites: group/filter activities + by people participating to the exchange' +time: 2023-10-18T16:02:35.99265091+02:00 +custom: + Issue: "172" diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/PersonsAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/PersonsAggregator.php new file mode 100644 index 000000000..8459741c5 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/PersonsAggregator.php @@ -0,0 +1,78 @@ +labelPersonHelper->getLabel($key, $values, 'export.aggregator.activity.by_persons.Persons'); + } + + public function getQueryKeys($data) + { + return [self::PREFIX.'_pid']; + } + + public function getTitle() + { + return 'export.aggregator.activity.by_persons.Group activity by persons'; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $p = self::PREFIX; + + $qb + ->leftJoin('activity.persons', "{$p}_p") + ->addSelect("{$p}_p.id AS {$p}_pid") + ->addGroupBy("{$p}_pid"); + } + + public function applyOn() + { + return Declarations::ACTIVITY; + } +} diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/PersonsFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/PersonsFilter.php new file mode 100644 index 000000000..8bdefeb24 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Export/Filter/PersonsFilter.php @@ -0,0 +1,87 @@ +expr()->orX(); + + foreach (array_values($data['accepted_persons']) as $key => $person) { + $orX->add($qb->expr()->isMemberOf(":{$p}_p_{$key}", 'activity.persons')); + $qb->setParameter(":{$p}_p_{$key}", $person); + } + + $qb->andWhere($orX); + } + + public function applyOn() + { + return Declarations::ACTIVITY; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add('accepted_persons', PickPersonDynamicType::class, [ + 'multiple' => true, + 'label' => 'export.filter.activity.by_persons.persons taking part on the activity', + ]); + } + + public function getFormDefaultData(): array + { + return [ + 'accepted_persons' => [], + ]; + } + + public function describeAction($data, $format = 'string') + { + $users = []; + + foreach ($data['accepted_persons'] as $u) { + $users[] = $this->personRender->renderString($u, []); + } + + return ['export.filter.activity.by_persons.Filtered activity by persons: only %persons%', [ + '%persons%' => implode(', ', $users), + ]]; + } + + public function getTitle(): string + { + return 'export.filter.activity.by_persons.Filter activity by persons'; + } +} diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/PersonsAggregatorTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/PersonsAggregatorTest.php new file mode 100644 index 000000000..b067e308d --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/PersonsAggregatorTest.php @@ -0,0 +1,60 @@ +labelPersonHelper = self::$container->get(LabelPersonHelper::class); + } + + public function getAggregator() + { + return new PersonsAggregator($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/Tests/Export/Filter/PersonsFilterTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Filter/PersonsFilterTest.php new file mode 100644 index 000000000..cefc226e7 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Filter/PersonsFilterTest.php @@ -0,0 +1,72 @@ +personRender = self::$container->get(PersonRenderInterface::class); + } + + public function getFilter() + { + return new PersonsFilter($this->personRender); + } + + public function getFormData() + { + self::bootKernel(); + $em = self::$container->get(EntityManagerInterface::class); + + $persons = $em->createQuery('SELECT p FROM '.Person::class.' p ') + ->setMaxResults(2) + ->getResult(); + + self::ensureKernelShutdown(); + + return [ + [ + 'accepted_persons' => $persons, + ], + ]; + } + + 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 09a5227eb..3bb3b3695 100644 --- a/src/Bundle/ChillActivityBundle/config/services/export.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/export.yaml @@ -200,3 +200,11 @@ services: Chill\ActivityBundle\Export\Aggregator\SentReceivedAggregator: tags: - { name: chill.export_aggregator, alias: activity_sentreceived_aggregator } + + Chill\ActivityBundle\Export\Filter\PersonsFilter: + tags: + - { name: chill.export_filter, alias: activity_by_persons_filter } + + Chill\ActivityBundle\Export\Aggregator\PersonsAggregator: + tags: + - { name: chill.export_aggregator, alias: activity_by_persons_aggregator } diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index 123a0d075..9c84e1815 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -377,6 +377,10 @@ export: by_creator_scope: Filter activity by user scope: Filtrer les échanges par service du créateur de l'échange 'Filtered activity by user scope: only %scopes%': "Filtré par service du créateur: uniquement %scopes%" + by_persons: + Filter activity by persons: Filtrer les échanges par usager participant + 'Filtered activity by persons: only %persons%': 'Échanges filtrés par usagers participants: seulement %persons%' + persons taking part on the activity: Usagers participants à l'échange aggregator: activity: @@ -400,6 +404,9 @@ export: by_creator_job: Group activity by creator job: Grouper les échanges par service du créateur de l'échange Calc date: Date de calcul du service du créateur de l'échange + by_persons: + Group activity by persons: Grouper les échanges par usager participant + Persons: Usagers participants generic_doc: filter: diff --git a/src/Bundle/ChillPersonBundle/Export/Helper/LabelPersonHelper.php b/src/Bundle/ChillPersonBundle/Export/Helper/LabelPersonHelper.php index 7e752395c..8f75d033c 100644 --- a/src/Bundle/ChillPersonBundle/Export/Helper/LabelPersonHelper.php +++ b/src/Bundle/ChillPersonBundle/Export/Helper/LabelPersonHelper.php @@ -18,6 +18,21 @@ class LabelPersonHelper { public function __construct(private readonly PersonRepository $personRepository, private readonly PersonRenderInterface $personRender) {} + public function getLabel(string $key, array $values, string $header): callable + { + return function (null|int|string $value) use ($header): string { + if ('_header' === $value) { + return $header; + } + + if ('' === $value || null === $value || null === $person = $this->personRepository->find($value)) { + return ''; + } + + return $this->personRender->renderString($person, []); + }; + } + public function getLabelMulti(string $key, array $values, string $header): callable { return function ($value) use ($header) { From 981dc6a959d5fa4c73440a3ecf626e6239efa953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 18 Oct 2023 16:56:35 +0200 Subject: [PATCH 04/16] [export] add a filter and aggregator on accompanying periods: group by activity type (accompanying course having at least one activity from this type) --- .../unreleased/Feature-20231018-164927.yaml | 6 + .../ByActivityTypeAggregator.php | 122 ++++++++++++++++++ .../ByActivityTypeAggregatorTest.php | 87 +++++++++++++ .../config/services/export.yaml | 4 + .../translations/messages.fr.yml | 6 + .../Form/Type/PickRollingDateType.php | 4 + 6 files changed, 229 insertions(+) create mode 100644 .changes/unreleased/Feature-20231018-164927.yaml create mode 100644 src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityTypeAggregator.php create mode 100644 src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ACPAggregators/ByActivityTypeAggregatorTest.php diff --git a/.changes/unreleased/Feature-20231018-164927.yaml b/.changes/unreleased/Feature-20231018-164927.yaml new file mode 100644 index 000000000..cf0be6fef --- /dev/null +++ b/.changes/unreleased/Feature-20231018-164927.yaml @@ -0,0 +1,6 @@ +kind: Feature +body: '[export] add a grouping on accompanying period export: group by activity type + associated to at least one activity within the accompanying period' +time: 2023-10-18T16:49:27.567166953+02:00 +custom: + Issue: "172" diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityTypeAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityTypeAggregator.php new file mode 100644 index 000000000..cdb66bb77 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityTypeAggregator.php @@ -0,0 +1,122 @@ +add('after_date', PickRollingDateType::class, [ + 'required' => false, + 'label' => 'export.aggregator.acp.by_activity_type.after_date', + ]) + ->add('before_date', PickRollingDateType::class, [ + 'required' => false, + 'label' => 'export.aggregator.acp.by_activity_type.before_date', + ]); + } + + public function getFormDefaultData(): array + { + return [ + 'before_date' => null, + 'after_date' => null, + ]; + } + + public function getLabels($key, array $values, mixed $data) + { + return function (null|int|string $value): string { + if ('_header' === $value) { + return 'export.aggregator.acp.by_activity_type.activity_type'; + } + + if ('' === $value || null === $value || null === $activityType = $this->activityTypeRepository->find($value)) { + return ''; + } + + return $this->translatableStringHelper->localize($activityType->getName()); + }; + } + + public function getQueryKeys($data) + { + return [self::PREFIX.'_actype_id']; + } + + public function getTitle() + { + return 'export.aggregator.acp.by_activity_type.title'; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $p = self::PREFIX; + + // we make a left join, with acp having at least one activity of the given type + $exists = 'EXISTS (SELECT 1 FROM '.Activity::class." {$p}_activity WHERE {$p}_activity.accompanyingPeriod = acp AND {$p}_activity.activityType = {$p}_activity_type"; + + if (null !== $data['after_date']) { + $exists .= " AND {$p}_activity.date > :{$p}_after_date"; + $qb->setParameter("{$p}_after_date", $this->rollingDateConverter->convert($data['after_date'])); + } + + if (null !== $data['before_date']) { + $exists .= " AND {$p}_activity.date < :{$p}_before_date"; + $qb->setParameter("{$p}_before_date", $this->rollingDateConverter->convert($data['before_date'])); + } + + $exists .= ')'; + + $qb->leftJoin( + ActivityType::class, + "{$p}_activity_type", + Join::WITH, + $exists + ); + + $qb + ->addSelect("{$p}_activity_type.id AS {$p}_actype_id") + ->addGroupBy("{$p}_actype_id"); + } + + public function applyOn() + { + return Declarations::ACP_TYPE; + } +} diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ACPAggregators/ByActivityTypeAggregatorTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ACPAggregators/ByActivityTypeAggregatorTest.php new file mode 100644 index 000000000..2d78585f7 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ACPAggregators/ByActivityTypeAggregatorTest.php @@ -0,0 +1,87 @@ +rollingDateConverter = self::$container->get(RollingDateConverterInterface::class); + $this->activityTypeRepository = self::$container->get(ActivityTypeRepositoryInterface::class); + $this->translatableStringHelper = self::$container->get(TranslatableStringHelperInterface::class); + } + + public function getAggregator() + { + return new ByActivityTypeAggregator( + $this->rollingDateConverter, + $this->activityTypeRepository, + $this->translatableStringHelper, + ); + } + + public function getFormData() + { + return [ + [ + 'after_date' => null, + 'before_date' => null, + ], + [ + 'after_date' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), + 'before_date' => null, + ], + [ + 'after_date' => null, + 'before_date' => new RollingDate(RollingDate::T_TODAY), + ], + [ + 'after_date' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), + 'before_date' => new RollingDate(RollingDate::T_TODAY), + ], + ]; + } + + public function getQueryBuilders() + { + self::bootKernel(); + + $em = self::$container->get(EntityManagerInterface::class); + + return [ + $em->createQueryBuilder() + ->select('count(distinct acp.id)') + ->from(AccompanyingPeriod::class, 'acp'), + ]; + } +} diff --git a/src/Bundle/ChillActivityBundle/config/services/export.yaml b/src/Bundle/ChillActivityBundle/config/services/export.yaml index 3bb3b3695..24f10d399 100644 --- a/src/Bundle/ChillActivityBundle/config/services/export.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/export.yaml @@ -208,3 +208,7 @@ services: Chill\ActivityBundle\Export\Aggregator\PersonsAggregator: tags: - { name: chill.export_aggregator, alias: activity_by_persons_aggregator } + + Chill\ActivityBundle\Export\Aggregator\ACPAggregators\ByActivityTypeAggregator: + tags: + - { name: chill.export_aggregator, alias: acp_by_activity_type_aggregator } diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index 9c84e1815..b952ce3a8 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -383,6 +383,12 @@ export: persons taking part on the activity: Usagers participants à l'échange aggregator: + acp: + by_activity_type: + title: Grouper les parcours par type d'échange + after_date: Uniquement échanges après cette date + before_date: Uniquement échanges avant cette date + activity_type: Types d'échange activity: by_sent_received: Sent or received: Envoyé ou reçu diff --git a/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php b/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php index c23e0fa81..8ceb08578 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php @@ -34,6 +34,7 @@ class PickRollingDateType extends AbstractType ), 'multiple' => false, 'expanded' => false, + 'required' => $options['required'], 'label' => 'rolling_date.roll_movement', ]) ->add('fixedDate', ChillDateType::class, [ @@ -57,7 +58,10 @@ class PickRollingDateType extends AbstractType 'constraints' => [ new Callback($this->validate(...)), ], + 'required' => true, ]); + + $resolver->setAllowedTypes('required', 'bool'); } public function validate($data, ExecutionContextInterface $context, $payload): void From 4c9ea740c8c381659d59585b34c6d3e22f871201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 19 Oct 2023 11:44:53 +0200 Subject: [PATCH 05/16] [export] fix date range selection on filtre and grouping "by status of the course at date" on accompanying periods --- .changes/unreleased/Fixed-20231019-114350.yaml | 6 ++++++ .../AccompanyingCourseAggregators/StepAggregator.php | 2 +- .../Filter/AccompanyingCourseFilters/StepFilterOnDate.php | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 .changes/unreleased/Fixed-20231019-114350.yaml diff --git a/.changes/unreleased/Fixed-20231019-114350.yaml b/.changes/unreleased/Fixed-20231019-114350.yaml new file mode 100644 index 000000000..dbb6b4166 --- /dev/null +++ b/.changes/unreleased/Fixed-20231019-114350.yaml @@ -0,0 +1,6 @@ +kind: Fixed +body: '[export] fix date range selection on filter and grouping "by status of the + course at date", on accompanying periods' +time: 2023-10-19T11:43:50.455829748+02:00 +custom: + Issue: "177" diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/StepAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/StepAggregator.php index dd5c26371..a9439a63f 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/StepAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/StepAggregator.php @@ -49,7 +49,7 @@ final readonly class StepAggregator implements AggregatorInterface $qb->expr()->lte(self::A.'.startDate', ':'.self::P), $qb->expr()->orX( $qb->expr()->isNull(self::A.'.endDate'), - $qb->expr()->lt(self::A.'.endDate', ':'.self::P) + $qb->expr()->gt(self::A.'.endDate', ':'.self::P) ) ) ) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/StepFilterOnDate.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/StepFilterOnDate.php index bca812b86..66355e44d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/StepFilterOnDate.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/StepFilterOnDate.php @@ -61,7 +61,7 @@ class StepFilterOnDate implements FilterInterface $qb->expr()->lte(self::A.'.startDate', ':'.self::P), $qb->expr()->orX( $qb->expr()->isNull(self::A.'.endDate'), - $qb->expr()->lt(self::A.'.endDate', ':'.self::P) + $qb->expr()->gt(self::A.'.endDate', ':'.self::P) ) ) ) From 5f805626f76d8fc40dcb807239f995071ca5c612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 19 Oct 2023 14:04:24 +0200 Subject: [PATCH 06/16] [export] sort filters and aggregators by title --- .../unreleased/Feature-20231019-140357.yaml | 5 + .../translations/messages.fr.yml | 4 +- .../ChillMainBundle/Export/ExportManager.php | 49 +++-- .../Export/SortExportElement.php | 37 ++++ .../Form/Type/Export/ExportType.php | 16 +- .../Form/Type/Export/FilterType.php | 9 +- .../Tests/Export/SortExportElementTest.php | 193 ++++++++++++++++++ .../config/services/export.yaml | 2 + .../PersonFilters/AddressRefStatusFilter.php | 2 +- .../translations/messages.fr.yml | 9 +- .../translations/messages.fr.yml | 6 +- 11 files changed, 294 insertions(+), 38 deletions(-) create mode 100644 .changes/unreleased/Feature-20231019-140357.yaml create mode 100644 src/Bundle/ChillMainBundle/Export/SortExportElement.php create mode 100644 src/Bundle/ChillMainBundle/Tests/Export/SortExportElementTest.php diff --git a/.changes/unreleased/Feature-20231019-140357.yaml b/.changes/unreleased/Feature-20231019-140357.yaml new file mode 100644 index 000000000..2ef33a4a5 --- /dev/null +++ b/.changes/unreleased/Feature-20231019-140357.yaml @@ -0,0 +1,5 @@ +kind: Feature +body: '[export] sort filters and aggregators by title' +time: 2023-10-19T14:03:57.435338127+02:00 +custom: + Issue: "" diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index b952ce3a8..a7112b534 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -362,7 +362,7 @@ export: Filter by users scope: Filtrer les échanges par services d'au moins un utilisateur participant 'Filtered activity by users scope: only %scopes%': 'Filtré par service d''au moins un utilisateur participant: seulement %scopes%' course_having_activity_between_date: - Title: Filtre les parcours ayant reçu un échange entre deux dates + Title: Filtrer les parcours ayant reçu un échange entre deux dates Receiving an activity after: Ayant reçu un échange après le Receiving an activity before: Ayant reçu un échange avant le acp_by_activity_type: @@ -372,7 +372,7 @@ export: Implied in an activity before this date: Impliqué dans un échange avant cette date Activity reasons for those activities: Sujets de ces échanges if no reasons: Si aucun sujet n'est coché, tous les sujets seront pris en compte - title: Filtrer les personnes ayant été associés à un échange au cours de la période + title: Filtrer les usagers ayant été associés à un échange au cours de la période date mismatch: La date de fin de la période doit être supérieure à la date du début by_creator_scope: Filter activity by user scope: Filtrer les échanges par service du créateur de l'échange diff --git a/src/Bundle/ChillMainBundle/Export/ExportManager.php b/src/Bundle/ChillMainBundle/Export/ExportManager.php index 8cb69bd63..067cc72e9 100644 --- a/src/Bundle/ChillMainBundle/Export/ExportManager.php +++ b/src/Bundle/ChillMainBundle/Export/ExportManager.php @@ -11,6 +11,7 @@ declare(strict_types=1); namespace Chill\MainBundle\Export; +use Chill\MainBundle\Entity\User; use Chill\MainBundle\Form\Type\Export\ExportType; use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; use Doctrine\ORM\QueryBuilder; @@ -54,20 +55,17 @@ class ExportManager */ private array $formatters = []; - private readonly string|\Stringable|\Symfony\Component\Security\Core\User\UserInterface $user; - public function __construct( private readonly LoggerInterface $logger, private readonly AuthorizationCheckerInterface $authorizationChecker, private readonly AuthorizationHelperInterface $authorizationHelper, - TokenStorageInterface $tokenStorage, + private readonly TokenStorageInterface $tokenStorage, iterable $exports, iterable $aggregators, iterable $filters // iterable $formatters, // iterable $exportElementProvider ) { - $this->user = $tokenStorage->getToken()->getUser(); $this->exports = iterator_to_array($exports); $this->aggregators = iterator_to_array($aggregators); $this->filters = iterator_to_array($filters); @@ -91,20 +89,24 @@ class ExportManager * * @return FilterInterface[] a \Generator that contains filters. The key is the filter's alias */ - public function &getFiltersApplyingOn(DirectExportInterface|ExportInterface $export, array $centers = null): iterable + public function getFiltersApplyingOn(DirectExportInterface|ExportInterface $export, array $centers = null): array { if ($export instanceof DirectExportInterface) { - return; + return []; } + $filters = []; + foreach ($this->filters as $alias => $filter) { if ( \in_array($filter->applyOn(), $export->supportsModifiers(), true) && $this->isGrantedForElement($filter, $export, $centers) ) { - yield $alias => $filter; + $filters[$alias] = $filter; } } + + return $filters; } /** @@ -112,22 +114,26 @@ class ExportManager * * @internal This class check the interface implemented by export, and, if ´ListInterface´ is used, return an empty array * - * @return iterable|null a \Generator that contains aggretagors. The key is the filter's alias + * @return array an array that contains aggregators. The key is the filter's alias */ - public function &getAggregatorsApplyingOn(DirectExportInterface|ExportInterface $export, array $centers = null): ?iterable + public function getAggregatorsApplyingOn(DirectExportInterface|ExportInterface $export, array $centers = null): array { if ($export instanceof ListInterface || $export instanceof DirectExportInterface) { - return; + return []; } + $aggregators = []; + foreach ($this->aggregators as $alias => $aggregator) { if ( \in_array($aggregator->applyOn(), $export->supportsModifiers(), true) && $this->isGrantedForElement($aggregator, $export, $centers) ) { - yield $alias => $aggregator; + $aggregators[$alias] = $aggregator; } } + + return $aggregators; } public function addExportElementsProvider(ExportElementsProviderInterface $provider, string $prefix): void @@ -347,6 +353,17 @@ class ExportManager return $this->filters[$alias]; } + public function getAllFilters(): array + { + $filters = []; + + foreach ($this->filters as $alias => $filter) { + $filters[$alias] = $filter; + } + + return $filters; + } + /** * get all filters. * @@ -452,7 +469,7 @@ class ExportManager if (null === $centers || [] === $centers) { // we want to try if at least one center is reachable return [] !== $this->authorizationHelper->getReachableCenters( - $this->user, + $this->tokenStorage->getToken()->getUser(), $role ); } @@ -484,11 +501,17 @@ class ExportManager { $r = []; + $user = $this->tokenStorage->getToken()->getUser(); + + if (!$user instanceof User) { + return []; + } + foreach ($centers as $center) { $r[] = [ 'center' => $center, 'circles' => $this->authorizationHelper->getReachableScopes( - $this->user, + $user, $element->requiredRole(), $center ), diff --git a/src/Bundle/ChillMainBundle/Export/SortExportElement.php b/src/Bundle/ChillMainBundle/Export/SortExportElement.php new file mode 100644 index 000000000..6228109ed --- /dev/null +++ b/src/Bundle/ChillMainBundle/Export/SortExportElement.php @@ -0,0 +1,37 @@ + $elements + */ + public function sortFilters(array &$elements): void + { + uasort($elements, fn (FilterInterface $a, FilterInterface $b) => $this->translator->trans($a->getTitle()) <=> $this->translator->trans($b->getTitle())); + } + + /** + * @param array $elements + */ + public function sortAggregators(array &$elements): void + { + uasort($elements, fn (AggregatorInterface $a, AggregatorInterface $b) => $this->translator->trans($a->getTitle()) <=> $this->translator->trans($b->getTitle())); + } +} diff --git a/src/Bundle/ChillMainBundle/Form/Type/Export/ExportType.php b/src/Bundle/ChillMainBundle/Form/Type/Export/ExportType.php index 324b5d8d7..e5d0887f3 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/ExportType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/ExportType.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\MainBundle\Form\Type\Export; use Chill\MainBundle\Export\ExportManager; +use Chill\MainBundle\Export\SortExportElement; use Chill\MainBundle\Validator\Constraints\Export\ExportElementConstraint; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\FormType; @@ -28,15 +29,7 @@ class ExportType extends AbstractType final public const PICK_FORMATTER_KEY = 'pick_formatter'; - /** - * @var ExportManager - */ - protected $exportManager; - - public function __construct(ExportManager $exportManager) - { - $this->exportManager = $exportManager; - } + public function __construct(private readonly ExportManager $exportManager, private readonly SortExportElement $sortExportElement) {} public function buildForm(FormBuilderInterface $builder, array $options) { @@ -58,12 +51,12 @@ class ExportType extends AbstractType if ($export instanceof \Chill\MainBundle\Export\ExportInterface) { // add filters $filters = $this->exportManager->getFiltersApplyingOn($export, $options['picked_centers']); + $this->sortExportElement->sortFilters($filters); $filterBuilder = $builder->create(self::FILTER_KEY, FormType::class, ['compound' => true]); foreach ($filters as $alias => $filter) { $filterBuilder->add($alias, FilterType::class, [ - 'filter_alias' => $alias, - 'export_manager' => $this->exportManager, + 'filter' => $filter, 'label' => $filter->getTitle(), 'constraints' => [ new ExportElementConstraint(['element' => $filter]), @@ -76,6 +69,7 @@ class ExportType extends AbstractType // add aggregators $aggregators = $this->exportManager ->getAggregatorsApplyingOn($export, $options['picked_centers']); + $this->sortExportElement->sortAggregators($aggregators); $aggregatorBuilder = $builder->create( self::AGGREGATOR_KEY, FormType::class, diff --git a/src/Bundle/ChillMainBundle/Form/Type/Export/FilterType.php b/src/Bundle/ChillMainBundle/Form/Type/Export/FilterType.php index d4f897430..bcf842e73 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/FilterType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/FilterType.php @@ -11,6 +11,7 @@ declare(strict_types=1); namespace Chill\MainBundle\Form\Type\Export; +use Chill\MainBundle\Export\FilterInterface; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\FormType; @@ -25,8 +26,7 @@ class FilterType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options) { - $exportManager = $options['export_manager']; - $filter = $exportManager->getFilter($options['filter_alias']); + $filter = $options['filter']; $builder ->add(self::ENABLED_FIELD, CheckboxType::class, [ @@ -46,8 +46,9 @@ class FilterType extends AbstractType public function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired('filter_alias') - ->setRequired('export_manager') + $resolver + ->setRequired('filter') + ->setAllowedTypes('filter', [FilterInterface::class]) ->setDefault('compound', true) ->setDefault('error_bubbling', false); } diff --git a/src/Bundle/ChillMainBundle/Tests/Export/SortExportElementTest.php b/src/Bundle/ChillMainBundle/Tests/Export/SortExportElementTest.php new file mode 100644 index 000000000..e7dbaf8fb --- /dev/null +++ b/src/Bundle/ChillMainBundle/Tests/Export/SortExportElementTest.php @@ -0,0 +1,193 @@ +sortExportElement = new SortExportElement($this->makeTranslator()); + } + + public function testSortFilterRealData(): void + { + self::bootKernel(); + + $sorter = self::$container->get(SortExportElement::class); + $translator = self::$container->get(TranslatorInterface::class); + $exportManager = self::$container->get(ExportManager::class); + $filters = $exportManager->getAllFilters(); + + $sorter->sortFilters($filters); + + $previousName = null; + foreach ($filters as $filter) { + if (null === $previousName) { + $previousName = $translator->trans($filter->getTitle()); + continue; + } + + $current = $translator->trans($filter->getTitle()); + if ($current === $previousName) { + continue; + } + + self::assertEquals(-1, $previousName <=> $current, sprintf("comparing '%s' and '%s'", $previousName, $current)); + $previousName = $current; + } + } + + public function testSortAggregator(): void + { + $aggregators = [ + 'foo' => $a = $this->makeAggregator('a'), + 'zop' => $q = $this->makeAggregator('q'), + 'bar' => $c = $this->makeAggregator('c'), + 'baz' => $b = $this->makeAggregator('b'), + ]; + + $this->sortExportElement->sortAggregators($aggregators); + + self::assertEquals(['foo', 'baz', 'bar', 'zop'], array_keys($aggregators)); + self::assertSame($a, $aggregators['foo']); + self::assertSame($b, $aggregators['baz']); + self::assertSame($c, $aggregators['bar']); + self::assertSame($q, $aggregators['zop']); + } + + public function testSortFilter(): void + { + $filters = [ + 'foo' => $a = $this->makeFilter('a'), + 'zop' => $q = $this->makeFilter('q'), + 'bar' => $c = $this->makeFilter('c'), + 'baz' => $b = $this->makeFilter('b'), + ]; + + $this->sortExportElement->sortFilters($filters); + + self::assertEquals(['foo', 'baz', 'bar', 'zop'], array_keys($filters)); + self::assertSame($a, $filters['foo']); + self::assertSame($b, $filters['baz']); + self::assertSame($c, $filters['bar']); + self::assertSame($q, $filters['zop']); + } + + private function makeTranslator(): TranslatorInterface + { + return new class () implements TranslatorInterface { + public function trans(string $id, array $parameters = [], string $domain = null, string $locale = null) + { + return $id; + } + + public function getLocale(): string + { + return 'en'; + } + }; + } + + private function makeAggregator(string $title): AggregatorInterface + { + return new class ($title) implements AggregatorInterface { + public function __construct(private readonly string $title) {} + + public function buildForm(FormBuilderInterface $builder) {} + + public function getFormDefaultData(): array + { + return []; + } + + public function getLabels($key, array $values, mixed $data) + { + return fn ($v) => $v; + } + + public function getQueryKeys($data) + { + return []; + } + + public function getTitle() + { + return $this->title; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) {} + + public function applyOn() + { + return []; + } + }; + } + + private function makeFilter(string $title): FilterInterface + { + return new class ($title) implements FilterInterface { + public function __construct(private readonly string $title) {} + + public function getTitle() + { + return $this->title; + } + + public function buildForm(FormBuilderInterface $builder) {} + + public function getFormDefaultData(): array + { + return []; + } + + public function describeAction($data, $format = 'string') + { + return ['a', []]; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) {} + + public function applyOn() + { + return []; + } + }; + } +} diff --git a/src/Bundle/ChillMainBundle/config/services/export.yaml b/src/Bundle/ChillMainBundle/config/services/export.yaml index 6bae6f9c0..ece7ae902 100644 --- a/src/Bundle/ChillMainBundle/config/services/export.yaml +++ b/src/Bundle/ChillMainBundle/config/services/export.yaml @@ -54,3 +54,5 @@ services: - { name: chill.export_formatter, alias: 'csv_pivoted_list' } Chill\MainBundle\Export\AccompanyingCourseExportHelper: ~ + + Chill\MainBundle\Export\SortExportElement: ~ diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AddressRefStatusFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AddressRefStatusFilter.php index 6430b5e99..8cd675abe 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AddressRefStatusFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AddressRefStatusFilter.php @@ -66,7 +66,7 @@ class AddressRefStatusFilter implements \Chill\MainBundle\Export\FilterInterface { $builder ->add('date_calc', PickRollingDateType::class, [ - 'label' => 'Compute address at date', + 'label' => 'export.filter.person.by_address_ref_status.Address at date', 'required' => true, ]) ->add('ref_statuses', ChoiceType::class, [ diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 4ab5d88a6..66aecff1f 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -480,7 +480,7 @@ acp_geog_agg_unitrefid: Clé de la zone géographique Geographical layer: Couche géographique Select a geographical layer: Choisir une couche géographique Group people by geographical unit based on his address: Grouper les usagers par zone géographique (sur base de l'adresse) -Filter by person's geographical unit (based on address): Filter les usagers par zone géographique (sur base de l'adresse) +Filter by person's geographical unit (based on address): Filtrer les usagers par zone géographique (sur base de l'adresse) Filter by socialaction: Filtrer les parcours par action d'accompagnement Accepted socialactions: Actions d'accompagnement @@ -1100,21 +1100,22 @@ export: Persons filtered by no composition at %date%: Uniquement les usagers sans composition de ménage à la date du %date% Date calc: Date de calcul by_address_ref_status: - Filter by person's address ref status: Filtrer par comparaison avec l'adresse de référence + Filter by person's address ref status: Filtrer les usagers par comparaison avec l'adresse de référence to_review: Diffère de l'adresse de référence reviewed: Diffère de l'adresse de référence mais conservé par l'utilisateur match: Identique à l'adresse de référence Filtered by person\'s address status computed at %datecalc%, only %statuses%: Filtré par comparaison à l'adresse de référence, calculé à %datecalc%, seulement %statuses% Status: Statut + Address at date: Adresse à la date course: having_info_within_interval: - title: Filter les parcours ayant reçu une intervention entre deux dates + title: Filtrer les parcours ayant reçu une intervention entre deux dates start_date: Début de la période end_date: Fin de la période Only course with events between %startDate% and %endDate%: Seulement les parcours ayant reçu une intervention entre le %startDate% et le %endDate% by_user_working: - title: Filter les parcours par intervenant, entre deux dates + title: Filtrer les parcours par intervenant, entre deux dates 'Filtered by user working on course: only %users%, between %start_date% and %end_date%': 'Filtré par intervenants sur le parcours: seulement %users%, entre le %start_date% et le %end_date%' User working after: Intervention après le User working before: Intervention avant le diff --git a/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml b/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml index f62a5beff..2bb17cca4 100644 --- a/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml @@ -128,8 +128,8 @@ export: thirdParties: Tiers intervenant # exports filters/aggregators -Filtered by person\'s who have a residential address located at a thirdparty of type %thirparty_type%: Uniquement les personnes qui ont une addresse de résidence chez un tiers de catégorie %thirdparty_type% +Filtered by person\'s who have a residential address located at a thirdparty of type %thirparty_type%: Uniquement les usagers qui ont une addresse de résidence chez un tiers de catégorie %thirdparty_type% is thirdparty: Le demandeur est un tiers -Filter by person's who have a residential address located at a thirdparty of type: Filtrer les personnes qui ont une addresse de résidence chez un tiers de catégorie "xxx" -"Filtered by person's who have a residential address located at a thirdparty of type %thirdparty_type% and valid on %date_calc%": "Uniquement les personnes qui ont une addresse de résidence chez un tiers de catégorie %thirdparty_type% et valide sur la date %date_calc%" +Filter by person's who have a residential address located at a thirdparty of type: Filtrer les usagers qui ont une addresse de résidence chez un tiers de catégorie "xxx" +"Filtered by person's who have a residential address located at a thirdparty of type %thirdparty_type% and valid on %date_calc%": "Uniquement les usagers qui ont une addresse de résidence chez un tiers de catégorie %thirdparty_type% et valide sur la date %date_calc%" From a6e930958beceaf0f339c3b85eeb0b642c3be833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 19 Oct 2023 17:19:28 +0200 Subject: [PATCH 07/16] [export] create a parameter that will force to skip the filtering by center (ACL) when generating an export --- .../unreleased/Feature-20231019-171900.yaml | 6 + .../LinkedToACP/AvgActivityDuration.php | 28 +- .../LinkedToACP/AvgActivityVisitDuration.php | 19 +- .../Export/LinkedToACP/CountActivity.php | 19 +- .../Export/LinkedToACP/ListActivity.php | 32 +- .../LinkedToACP/SumActivityDuration.php | 18 +- .../LinkedToACP/SumActivityVisitDuration.php | 18 +- .../Export/LinkedToPerson/CountActivity.php | 36 ++- .../Export/LinkedToPerson/ListActivity.php | 36 ++- .../LinkedToPerson/StatActivityDuration.php | 33 +- .../LinkedToACP/AvgActivityDurationTest.php | 10 +- .../AvgActivityVisitDurationTest.php | 10 +- .../Export/LinkedToACP/CountActivityTest.php | 10 +- .../LinkedToACP/SumActivityDurationTest.php | 10 +- .../SumActivityVisitDurationTest.php | 6 +- .../LinkedToPerson/CountActivityTest.php | 10 +- .../LinkedToPerson/ListActivityTest.php | 29 +- .../StatActivityDurationTest.php | 9 +- .../Export/Export/CountCalendars.php | 4 +- .../DependencyInjection/Configuration.php | 4 + .../Test/Export/AbstractExportTest.php | 293 ++++++++++-------- .../Export/Export/CountAccompanyingCourse.php | 20 +- .../Export/CountAccompanyingPeriodWork.php | 26 +- .../Export/Export/CountEvaluation.php | 26 +- .../Export/Export/CountHousehold.php | 32 +- .../Export/Export/CountPerson.php | 26 +- .../CountPersonWithAccompanyingCourse.php | 16 +- .../Export/Export/ListAccompanyingPeriod.php | 24 +- .../Export/ListAccompanyingPeriodWork.php | 26 +- .../Export/Export/ListEvaluation.php | 36 ++- .../Export/Export/ListHouseholdInPeriod.php | 27 +- .../Export/Export/ListPerson.php | 27 +- .../ListPersonHavingAccompanyingPeriod.php | 42 ++- ...istPersonWithAccompanyingPeriodDetails.php | 24 +- .../Export/StatAccompanyingCourseDuration.php | 34 +- .../Export/CountAccompanyingCourseTest.php | 10 +- .../CountAccompanyingPeriodWorkTest.php | 6 +- .../Tests/Export/Export/CountPersonTest.php | 10 +- .../CountPersonWithAccompanyingCourseTest.php | 48 +++ .../Export/ListAccompanyingPeriodTest.php | 40 ++- .../Export/ListAccompanyingPeriodWorkTest.php | 87 +++++- .../Export/Export/ListEvaluationTest.php | 71 ++++- .../Export/ListHouseholdInPeriodTest.php | 72 +++++ ...ListPersonHavingAccompanyingPeriodTest.php | 69 +++++ .../Tests/Export/Export/ListPersonTest.php | 29 +- ...ersonWithAccompanyingPeriodDetailsTest.php | 73 +++++ .../StatAccompanyingCourseDurationTest.php | 11 +- 47 files changed, 1145 insertions(+), 407 deletions(-) create mode 100644 .changes/unreleased/Feature-20231019-171900.yaml create mode 100644 src/Bundle/ChillPersonBundle/Tests/Export/Export/CountPersonWithAccompanyingCourseTest.php create mode 100644 src/Bundle/ChillPersonBundle/Tests/Export/Export/ListHouseholdInPeriodTest.php create mode 100644 src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonHavingAccompanyingPeriodTest.php create mode 100644 src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonWithAccompanyingPeriodDetailsTest.php diff --git a/.changes/unreleased/Feature-20231019-171900.yaml b/.changes/unreleased/Feature-20231019-171900.yaml new file mode 100644 index 000000000..d8ee98cdd --- /dev/null +++ b/.changes/unreleased/Feature-20231019-171900.yaml @@ -0,0 +1,6 @@ +kind: Feature +body: '[export] create a parameter that will force to skip the filtering by center + (ACL) when generating an export' +time: 2023-10-19T17:19:00.51809407+02:00 +custom: + Issue: "179" diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityDuration.php index 9cdbc183d..d8b204e8c 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityDuration.php @@ -11,8 +11,8 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Export\Export\LinkedToACP; -use Chill\ActivityBundle\Entity\Activity; use Chill\ActivityBundle\Export\Declarations; +use Chill\ActivityBundle\Repository\ActivityRepository; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\MainBundle\Export\AccompanyingCourseExportHelper; use Chill\MainBundle\Export\ExportInterface; @@ -21,19 +21,19 @@ use Chill\MainBundle\Export\GroupedExportInterface; use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Chill\PersonBundle\Entity\Person\PersonCenterHistory; use Chill\PersonBundle\Export\Declarations as PersonDeclarations; -use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; class AvgActivityDuration implements ExportInterface, GroupedExportInterface { - protected EntityRepository $repository; + private readonly bool $filterStatsByCenters; public function __construct( - EntityManagerInterface $em, + private readonly ActivityRepository $activityRepository, + ParameterBagInterface $parameterBag, ) { - $this->repository = $em->getRepository(Activity::class); + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; } public function buildForm(FormBuilderInterface $builder) {} @@ -91,23 +91,25 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface { $centers = array_map(static fn ($el) => $el['center'], $acl); - $qb = $this->repository->createQueryBuilder('activity'); + $qb = $this->activityRepository->createQueryBuilder('activity'); $qb ->join('activity.accompanyingPeriod', 'acp') ->select('AVG(activity.durationTime) as export_avg_activity_duration') ->andWhere($qb->expr()->isNotNull('activity.durationTime')); - $qb - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part + 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); + ->setParameter('authorized_centers', $centers); + } AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityVisitDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityVisitDuration.php index 58ac6e829..acfb073f5 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityVisitDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityVisitDuration.php @@ -24,16 +24,21 @@ use Chill\PersonBundle\Export\Declarations as PersonDeclarations; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterface { protected EntityRepository $repository; + private readonly bool $filterStatsByCenters; + public function __construct( EntityManagerInterface $em, + ParameterBagInterface $parameterBag, ) { $this->repository = $em->getRepository(Activity::class); + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; } public function buildForm(FormBuilderInterface $builder) @@ -101,16 +106,18 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac ->select('AVG(activity.travelTime) as export_avg_activity_visit_duration') ->andWhere($qb->expr()->isNotNull('activity.travelTime')); - $qb - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part + 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); + ->setParameter('authorized_centers', $centers); + } AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/CountActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/CountActivity.php index 39c79cf1f..dfd5d966f 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/CountActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/CountActivity.php @@ -24,16 +24,21 @@ use Chill\PersonBundle\Export\Declarations as PersonDeclarations; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; class CountActivity implements ExportInterface, GroupedExportInterface { protected EntityRepository $repository; + private readonly bool $filterStatsByCenters; + public function __construct( EntityManagerInterface $em, + ParameterBagInterface $parameterBag, ) { $this->repository = $em->getRepository(Activity::class); + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; } public function buildForm(FormBuilderInterface $builder) {} @@ -95,16 +100,18 @@ class CountActivity implements ExportInterface, GroupedExportInterface ->createQueryBuilder('activity') ->join('activity.accompanyingPeriod', 'acp'); - $qb - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part + 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); + ->setParameter('authorized_centers', $centers); + } AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/ListActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/ListActivity.php index 45233d97f..270fbd12c 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/ListActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/ListActivity.php @@ -22,11 +22,21 @@ use Chill\MainBundle\Export\Helper\TranslatableStringExportLabelHelper; use Chill\MainBundle\Export\ListInterface; use Chill\PersonBundle\Entity\Person\PersonCenterHistory; use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; class ListActivity implements ListInterface, GroupedExportInterface { - public function __construct(private readonly ListActivityHelper $helper, private readonly EntityManagerInterface $entityManager, private readonly TranslatableStringExportLabelHelper $translatableStringExportLabelHelper) {} + private readonly bool $filterStatsByCenters; + + public function __construct( + private readonly ListActivityHelper $helper, + private readonly EntityManagerInterface $entityManager, + private readonly TranslatableStringExportLabelHelper $translatableStringExportLabelHelper, + ParameterBagInterface $parameterBag, + ) { + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } public function buildForm(FormBuilderInterface $builder) { @@ -107,21 +117,27 @@ class ListActivity implements ListInterface, GroupedExportInterface ->join('activity.accompanyingPeriod', 'acp') ->leftJoin('acp.participations', 'acppart') ->leftJoin('acppart.person', 'person') - ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 + ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL'); + + 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 // some grouping are necessary ->addGroupBy('acp.id') ->addOrderBy('activity.date') - ->addOrderBy('activity.id') - ->setParameter('authorized_centers', $centers); + ->addOrderBy('activity.id'); $this->helper->addSelect($qb); diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityDuration.php index a8d6f10fd..159fcf78d 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityDuration.php @@ -24,16 +24,20 @@ use Chill\PersonBundle\Export\Declarations as PersonDeclarations; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; class SumActivityDuration implements ExportInterface, GroupedExportInterface { protected EntityRepository $repository; + private readonly bool $filterStatsByCenters; public function __construct( EntityManagerInterface $em, + ParameterBagInterface $parameterBag, ) { $this->repository = $em->getRepository(Activity::class); + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; } public function buildForm(FormBuilderInterface $builder) @@ -101,16 +105,18 @@ class SumActivityDuration implements ExportInterface, GroupedExportInterface $qb->select('SUM(activity.durationTime) as export_sum_activity_duration') ->andWhere($qb->expr()->isNotNull('activity.durationTime')); - $qb - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part + 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); + ->setParameter('authorized_centers', $centers); + } AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityVisitDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityVisitDuration.php index dae572ba5..27502e2b0 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityVisitDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityVisitDuration.php @@ -24,16 +24,20 @@ use Chill\PersonBundle\Export\Declarations as PersonDeclarations; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; class SumActivityVisitDuration implements ExportInterface, GroupedExportInterface { protected EntityRepository $repository; + private readonly bool $filterStatsByCenters; public function __construct( EntityManagerInterface $em, + ParameterBagInterface $parameterBag, ) { $this->repository = $em->getRepository(Activity::class); + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; } public function buildForm(FormBuilderInterface $builder) @@ -101,16 +105,18 @@ class SumActivityVisitDuration implements ExportInterface, GroupedExportInterfac $qb->select('SUM(activity.travelTime) as export_sum_activity_visit_duration') ->andWhere($qb->expr()->isNotNull('activity.travelTime')); - $qb - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part + 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); + ->setParameter('authorized_centers', $centers); + } AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/CountActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/CountActivity.php index dbc7e3fde..e0a95b1f5 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/CountActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/CountActivity.php @@ -19,11 +19,19 @@ use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; use Chill\PersonBundle\Export\Declarations as PersonDeclarations; use Doctrine\ORM\Query; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; class CountActivity implements ExportInterface, GroupedExportInterface { - public function __construct(protected ActivityRepository $activityRepository) {} + private readonly bool $filterStatsByCenters; + + public function __construct( + private readonly ActivityRepository $activityRepository, + ParameterBagInterface $parameterBag, + ) { + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } public function buildForm(FormBuilderInterface $builder) {} @@ -82,23 +90,25 @@ class CountActivity implements ExportInterface, GroupedExportInterface $qb = $this->activityRepository ->createQueryBuilder('activity') - ->join('activity.person', 'person') - ->join('person.centerHistory', 'centerHistory'); + ->join('activity.person', 'person'); $qb->select('COUNT(activity.id) as export_count_activity'); - $qb - ->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') + 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); + ->andWhere($qb->expr()->in('centerHistory.center', ':centers')) + ->setParameter('centers', $centers); + } return $qb; } diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/ListActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/ListActivity.php index 50b8ace2a..f7b5f3a8a 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/ListActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/ListActivity.php @@ -23,6 +23,7 @@ use Chill\PersonBundle\Export\Declarations as PersonDeclarations; use Doctrine\DBAL\Exception\InvalidArgumentException; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Validator\Constraints\Callback; @@ -44,8 +45,17 @@ class ListActivity implements ListInterface, GroupedExportInterface 'person_lastname', 'person_id', ]; + private readonly bool $filterStatsByCenters; - public function __construct(protected EntityManagerInterface $entityManager, protected TranslatorInterface $translator, protected TranslatableStringHelperInterface $translatableStringHelper, private readonly ActivityRepository $activityRepository) {} + public function __construct( + protected EntityManagerInterface $entityManager, + protected TranslatorInterface $translator, + protected TranslatableStringHelperInterface $translatableStringHelper, + private readonly ActivityRepository $activityRepository, + ParameterBagInterface $parameterBag, + ) { + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } public function buildForm(FormBuilderInterface $builder) { @@ -188,20 +198,22 @@ class ListActivity implements ListInterface, GroupedExportInterface $qb ->from('ChillActivityBundle:Activity', 'activity') - ->join('activity.person', 'actperson') - ->join('actperson.centerHistory', 'centerHistory'); + ->join('activity.person', 'actperson'); - $qb->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') + if ($this->filterStatsByCenters) { + $qb->join('actperson.centerHistory', 'centerHistory'); + $qb->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); + ->andWhere($qb->expr()->in('centerHistory.center', ':centers')) + ->setParameter('centers', $centers); + } foreach ($this->fields as $f) { if (\in_array($f, $data['fields'], true)) { diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/StatActivityDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/StatActivityDuration.php index 6f254bb08..3cdadac67 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/StatActivityDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/StatActivityDuration.php @@ -20,6 +20,7 @@ use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; use Chill\PersonBundle\Export\Declarations as PersonDeclarations; use Doctrine\ORM\Query; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; /** @@ -30,17 +31,21 @@ use Symfony\Component\Form\FormBuilderInterface; class StatActivityDuration implements ExportInterface, GroupedExportInterface { final public const SUM = 'sum'; + private readonly bool $filterStatsByCenters; /** * @param string $action the stat to perform */ public function __construct( private readonly ActivityRepository $activityRepository, + ParameterBagInterface $parameterBag, /** * The action for this report. */ protected string $action = 'sum' - ) {} + ) { + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } public function buildForm(FormBuilderInterface $builder) {} @@ -119,21 +124,23 @@ class StatActivityDuration implements ExportInterface, GroupedExportInterface } $qb->select($select) - ->join('activity.person', 'person') - ->join('person.centerHistory', 'centerHistory'); + ->join('activity.person', 'person'); - $qb - ->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') + 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); + ->andWhere($qb->expr()->in('centerHistory.center', ':centers')) + ->setParameter('centers', $centers); + } return $qb; } diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/AvgActivityDurationTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/AvgActivityDurationTest.php index 5f9b635ee..c8010c327 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/AvgActivityDurationTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/AvgActivityDurationTest.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Tests\Export\Export\LinkedToACP; use Chill\ActivityBundle\Export\Export\LinkedToACP\AvgActivityDuration; +use Chill\ActivityBundle\Repository\ActivityRepository; use Chill\MainBundle\Test\Export\AbstractExportTest; /** @@ -21,18 +22,17 @@ use Chill\MainBundle\Test\Export\AbstractExportTest; */ final class AvgActivityDurationTest extends AbstractExportTest { - private AvgActivityDuration $export; - protected function setUp(): void { self::bootKernel(); - - $this->export = self::$container->get('chill.activity.export.avg_activity_duration_linked_to_acp'); } public function getExport() { - return $this->export; + $activityRepository = self::$container->get(ActivityRepository::class); + + yield new AvgActivityDuration($activityRepository, $this->getParameters(true)); + yield new AvgActivityDuration($activityRepository, $this->getParameters(false)); } public function getFormData(): array diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/AvgActivityVisitDurationTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/AvgActivityVisitDurationTest.php index b15462912..414e72960 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/AvgActivityVisitDurationTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/AvgActivityVisitDurationTest.php @@ -13,6 +13,7 @@ namespace Chill\ActivityBundle\Tests\Export\Export\LinkedToACP; use Chill\ActivityBundle\Export\Export\LinkedToACP\AvgActivityVisitDuration; use Chill\MainBundle\Test\Export\AbstractExportTest; +use Doctrine\ORM\EntityManagerInterface; /** * @internal @@ -21,18 +22,17 @@ use Chill\MainBundle\Test\Export\AbstractExportTest; */ final class AvgActivityVisitDurationTest extends AbstractExportTest { - private AvgActivityVisitDuration $export; - protected function setUp(): void { self::bootKernel(); - - $this->export = self::$container->get('chill.activity.export.avg_activity_visit_duration_linked_to_acp'); } public function getExport() { - return $this->export; + $em = self::$container->get(EntityManagerInterface::class); + + yield new AvgActivityVisitDuration($em, $this->getParameters(true)); + yield new AvgActivityVisitDuration($em, $this->getParameters(false)); } public function getFormData(): array diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/CountActivityTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/CountActivityTest.php index 46279ebd8..174bcc790 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/CountActivityTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/CountActivityTest.php @@ -13,6 +13,7 @@ namespace Chill\ActivityBundle\Tests\Export\Export\LinkedToACP; use Chill\ActivityBundle\Export\Export\LinkedToACP\CountActivity; use Chill\MainBundle\Test\Export\AbstractExportTest; +use Doctrine\ORM\EntityManagerInterface; /** * @internal @@ -21,18 +22,17 @@ use Chill\MainBundle\Test\Export\AbstractExportTest; */ final class CountActivityTest extends AbstractExportTest { - private CountActivity $export; - protected function setUp(): void { self::bootKernel(); - - $this->export = self::$container->get('chill.activity.export.count_activity_linked_to_acp'); } public function getExport() { - return $this->export; + $em = self::$container->get(EntityManagerInterface::class); + + yield new CountActivity($em, $this->getParameters(true)); + yield new CountActivity($em, $this->getParameters(false)); } public function getFormData(): array diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/SumActivityDurationTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/SumActivityDurationTest.php index c4f91f52e..f538ad3ea 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/SumActivityDurationTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/SumActivityDurationTest.php @@ -13,6 +13,7 @@ namespace Chill\ActivityBundle\Tests\Export\Export\LinkedToACP; use Chill\ActivityBundle\Export\Export\LinkedToACP\SumActivityDuration; use Chill\MainBundle\Test\Export\AbstractExportTest; +use Doctrine\ORM\EntityManagerInterface; /** * @internal @@ -21,18 +22,17 @@ use Chill\MainBundle\Test\Export\AbstractExportTest; */ final class SumActivityDurationTest extends AbstractExportTest { - private SumActivityDuration $export; - protected function setUp(): void { self::bootKernel(); - - $this->export = self::$container->get('chill.activity.export.sum_activity_duration_linked_to_acp'); } public function getExport() { - return $this->export; + $em = self::$container->get(EntityManagerInterface::class); + + yield new SumActivityDuration($em, $this->getParameters(true)); + yield new SumActivityDuration($em, $this->getParameters(false)); } public function getFormData(): array diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/SumActivityVisitDurationTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/SumActivityVisitDurationTest.php index 6bd7e9d19..95d4b597f 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/SumActivityVisitDurationTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToACP/SumActivityVisitDurationTest.php @@ -13,6 +13,7 @@ namespace Chill\ActivityBundle\Tests\Export\Export\LinkedToACP; use Chill\ActivityBundle\Export\Export\LinkedToACP\SumActivityVisitDuration; use Chill\MainBundle\Test\Export\AbstractExportTest; +use Doctrine\ORM\EntityManagerInterface; /** * @internal @@ -32,7 +33,10 @@ final class SumActivityVisitDurationTest extends AbstractExportTest public function getExport() { - return $this->export; + $em = self::$container->get(EntityManagerInterface::class); + + yield new SumActivityVisitDuration($em, $this->getParameters(true)); + yield new SumActivityVisitDuration($em, $this->getParameters(false)); } public function getFormData(): array diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToPerson/CountActivityTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToPerson/CountActivityTest.php index 61ae15604..8759dceb3 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToPerson/CountActivityTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToPerson/CountActivityTest.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Tests\Export\Export\LinkedToPerson; use Chill\ActivityBundle\Export\Export\LinkedToPerson\CountActivity; +use Chill\ActivityBundle\Repository\ActivityRepository; use Chill\MainBundle\Test\Export\AbstractExportTest; /** @@ -21,18 +22,17 @@ use Chill\MainBundle\Test\Export\AbstractExportTest; */ final class CountActivityTest extends AbstractExportTest { - private CountActivity $export; - protected function setUp(): void { self::bootKernel(); - - $this->export = self::$container->get('chill.activity.export.count_activity_linked_to_person'); } public function getExport() { - return $this->export; + $activityRepository = self::$container->get(ActivityRepository::class); + + yield new CountActivity($activityRepository, $this->getParameters(true)); + yield new CountActivity($activityRepository, $this->getParameters(false)); } public function getFormData(): array diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToPerson/ListActivityTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToPerson/ListActivityTest.php index f474b1fe6..a6b6903f2 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToPerson/ListActivityTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToPerson/ListActivityTest.php @@ -12,8 +12,12 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Tests\Export\Export\LinkedToPerson; use Chill\ActivityBundle\Export\Export\LinkedToPerson\ListActivity; +use Chill\ActivityBundle\Repository\ActivityRepository; +use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\MainBundle\Test\Export\AbstractExportTest; +use Doctrine\ORM\EntityManagerInterface; use Prophecy\PhpUnit\ProphecyTrait; +use Symfony\Contracts\Translation\TranslatorInterface; /** * @internal @@ -24,14 +28,12 @@ final class ListActivityTest extends AbstractExportTest { use ProphecyTrait; - private ListActivity $export; + private readonly ListActivity $export; protected function setUp(): void { self::bootKernel(); - $this->export = self::$container->get('chill.activity.export.list_activity_linked_to_person'); - $request = $this->prophesize() ->willExtend(\Symfony\Component\HttpFoundation\Request::class); @@ -43,7 +45,26 @@ final class ListActivityTest extends AbstractExportTest public function getExport() { - return $this->export; + $em = self::$container->get(EntityManagerInterface::class); + $translator = self::$container->get(TranslatorInterface::class); + $translatableStringHelper = self::$container->get(TranslatableStringHelperInterface::class); + $activityRepository = self::$container->get(ActivityRepository::class); + + yield new ListActivity( + $em, + $translator, + $translatableStringHelper, + $activityRepository, + $this->getParameters(true) + ); + + yield new ListActivity( + $em, + $translator, + $translatableStringHelper, + $activityRepository, + $this->getParameters(false) + ); } public function getFormData() diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToPerson/StatActivityDurationTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToPerson/StatActivityDurationTest.php index 11fb84a9a..8f4e98452 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToPerson/StatActivityDurationTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Export/LinkedToPerson/StatActivityDurationTest.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Tests\Export\Export\LinkedToPerson; use Chill\ActivityBundle\Export\Export\LinkedToPerson\StatActivityDuration; +use Chill\ActivityBundle\Repository\ActivityRepository; use Chill\MainBundle\Test\Export\AbstractExportTest; /** @@ -23,18 +24,18 @@ use Chill\MainBundle\Test\Export\AbstractExportTest; */ final class StatActivityDurationTest extends AbstractExportTest { - private StatActivityDuration $export; + private readonly StatActivityDuration $export; protected function setUp(): void { self::bootKernel(); - - $this->export = self::$container->get('chill.activity.export.sum_activity_duration_linked_to_person'); } public function getExport() { - return $this->export; + $activityRepository = self::$container->get(ActivityRepository::class); + yield new StatActivityDuration($activityRepository, $this->getParameters(true), 'sum'); + yield new StatActivityDuration($activityRepository, $this->getParameters(false), 'sum'); } public function getFormData(): array diff --git a/src/Bundle/ChillCalendarBundle/Export/Export/CountCalendars.php b/src/Bundle/ChillCalendarBundle/Export/Export/CountCalendars.php index 2e156d7a0..f643eaa68 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Export/CountCalendars.php +++ b/src/Bundle/ChillCalendarBundle/Export/Export/CountCalendars.php @@ -25,7 +25,9 @@ use Symfony\Component\Validator\Exception\LogicException; class CountCalendars implements ExportInterface, GroupedExportInterface { - public function __construct(private readonly CalendarRepository $calendarRepository) {} + public function __construct( + private readonly CalendarRepository $calendarRepository, + ) {} public function buildForm(FormBuilderInterface $builder) { diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php index 76e160b52..8bd3e35f4 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php @@ -116,8 +116,12 @@ class Configuration implements ConfigurationInterface ->booleanNode('form_show_centers') ->defaultTrue() ->end() + ->booleanNode('filter_stats_by_center') + ->defaultTrue() + ->info("if set to false, the exports won't take into account the center of the people") ->end() ->end() + ->end() // end of 'acl' ->booleanNode('access_global_history') ->defaultTrue() ->end() diff --git a/src/Bundle/ChillMainBundle/Test/Export/AbstractExportTest.php b/src/Bundle/ChillMainBundle/Test/Export/AbstractExportTest.php index 8d845b413..bb4cdc6f7 100644 --- a/src/Bundle/ChillMainBundle/Test/Export/AbstractExportTest.php +++ b/src/Bundle/ChillMainBundle/Test/Export/AbstractExportTest.php @@ -11,11 +11,15 @@ declare(strict_types=1); namespace Chill\MainBundle\Test\Export; +use Chill\MainBundle\Export\DirectExportInterface; +use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Test\PrepareClientTrait; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\NativeQuery; use Doctrine\ORM\QueryBuilder; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; /** * This class provide a set of tests for exports. @@ -94,7 +98,7 @@ abstract class AbstractExportTest extends WebTestCase /** * Create an instance of the report to test. * - * @return \Chill\MainBundle\Export\ExportInterface an instance of the export to test + * @return ExportInterface|DirectExportInterface|iterable|iterable an instance of the export to test */ abstract public function getExport(); @@ -116,19 +120,40 @@ abstract class AbstractExportTest extends WebTestCase */ abstract public function getModifiersCombination(); + protected function getParameters(bool $filterStatsByCenter): ParameterBagInterface + { + return new ParameterBag(['chill_main' => ['acl' => ['filter_stats_by_center' => $filterStatsByCenter]]]); + } + + /** + * wrap the results of @see{self::getExports()}, which may be an iterable or an export into an iterble. + */ + private function getExports(): iterable + { + $exports = $this->getExport(); + + if (is_iterable($exports)) { + return $exports; + } + + return [$exports]; + } + /** * Test the formatters type are string. */ public function testGetAllowedFormattersType() { - $formattersTypes = $this->getExport()->getAllowedFormattersTypes(); + foreach ($this->getExports() as $export) { + $formattersTypes = $export->getAllowedFormattersTypes(); - $this->assertContainsOnly( - 'string', - $formattersTypes, - true, - 'Test that the method `getAllowedFormattersTypes` returns an array of string' - ); + $this->assertContainsOnly( + 'string', + $formattersTypes, + true, + 'Test that the method `getAllowedFormattersTypes` returns an array of string' + ); + } } /** @@ -136,17 +161,17 @@ abstract class AbstractExportTest extends WebTestCase */ public function testGetDescription() { - $export = $this->getExport(); - - $this->assertIsString( - $export->getDescription(), - 'Assert that the `getDescription` method return a string' - ); - $this->assertNotEmpty( - $export->getDescription(), - 'Assert that the `getDescription` method does not return an empty ' - .'string.' - ); + foreach ($this->getExports() as $export) { + $this->assertIsString( + $export->getDescription(), + 'Assert that the `getDescription` method return a string' + ); + $this->assertNotEmpty( + $export->getDescription(), + 'Assert that the `getDescription` method does not return an empty ' + .'string.' + ); + } } /** @@ -156,19 +181,21 @@ abstract class AbstractExportTest extends WebTestCase */ public function testGetQueryKeys(array $data) { - $queryKeys = $this->getExport()->getQueryKeys($data); + foreach ($this->getExports() as $export) { + $queryKeys = $export->getQueryKeys($data); - $this->assertContainsOnly( - 'string', - $queryKeys, - true, - 'test that the query keys returned by `getQueryKeys` are only strings' - ); - $this->assertGreaterThanOrEqual( - 1, - \count($queryKeys), - 'test that there are at least one query key returned' - ); + $this->assertContainsOnly( + 'string', + $queryKeys, + true, + 'test that the query keys returned by `getQueryKeys` are only strings' + ); + $this->assertGreaterThanOrEqual( + 1, + \count($queryKeys), + 'test that there are at least one query key returned' + ); + } } /** @@ -187,61 +214,70 @@ abstract class AbstractExportTest extends WebTestCase */ public function testGetResultsAndLabels($modifiers, $acl, array $data) { - // it is more convenient to group the `getResult` and `getLabels` test - // due to the fact that testing both methods use the same tools. + foreach ($this->getExports() as $export) { + // it is more convenient to group the `getResult` and `getLabels` test + // due to the fact that testing both methods use the same tools. - $queryKeys = $this->getExport()->getQueryKeys($data); - $query = $this->getExport()->initiateQuery($modifiers, $acl, $data); + $queryKeys = $export->getQueryKeys($data); + $query = $export->initiateQuery($modifiers, $acl, $data); - // limit the result for the query for performance reason (only for QueryBuilder, - // not possible in NativeQuery) - if ($query instanceof QueryBuilder) { - $query->setMaxResults(1); - } + // limit the result for the query for performance reason (only for QueryBuilder, + // not possible in NativeQuery) + if ($query instanceof QueryBuilder) { + $query->setMaxResults(1); + } - $results = $this->getExport()->getResult($query, $data); + $results = $export->getResult($query, $data); - $this->assertIsArray( - $results, - 'assert that the returned result is an array' - ); - - if (0 === \count($results)) { - $this->markTestIncomplete('The result is empty. We cannot process tests ' - .'on results'); - } - - // testing the result - $result = $results[0]; - - $this->assertTrue( - is_iterable($result), - 'test that each row in the result is traversable or an array' - ); - - foreach ($result as $key => $value) { - $this->assertContains( - $key, - $queryKeys, - 'test that each key is present in `getQueryKeys`' + $this->assertIsArray( + $results, + 'assert that the returned result is an array' ); - $closure = $this->getExport()->getLabels($key, [$value], $data); + if (0 === \count($results)) { + $this->markTestIncomplete('The result is empty. We cannot process tests ' + .'on results'); + } + + // testing the result + $result = $results[0]; $this->assertTrue( - \is_callable($closure, false), - 'test that the `getLabels` for key is a callable' + is_iterable($result), + 'test that each row in the result is traversable or an array' ); - $this->assertTrue( - // conditions - \is_string((string) \call_user_func($closure, '_header')) - && !empty(\call_user_func($closure, '_header')) - && '_header' !== \call_user_func($closure, '_header'), - // message - sprintf('Test that the callable return by `getLabels` for key %s ' - .'can provide an header', $key) - ); + $i = 0; + foreach ($result as $key => $value) { + $this->assertContains( + $key, + $queryKeys, + 'test that each key is present in `getQueryKeys`' + ); + + $closure = $export->getLabels($key, [$value], $data); + + $this->assertTrue( + \is_callable($closure, false), + 'test that the `getLabels` for key is a callable' + ); + + $this->assertTrue( + // conditions + \is_string((string) \call_user_func($closure, '_header')) + && !empty(\call_user_func($closure, '_header')) + && '_header' !== \call_user_func($closure, '_header'), + // message + sprintf('Test that the callable return by `getLabels` for key %s ' + .'can provide an header', $key) + ); + ++$i; + + if ($i > 15) { + // do not iterate on each result + break; + } + } } } @@ -250,14 +286,14 @@ abstract class AbstractExportTest extends WebTestCase */ public function testGetType() { - $export = $this->getExport(); - - $this->assertIsString( - $export->getType(), - 'Assert that the `getType` method return a string' - ); - $this->assertNotEmpty($export->getType(), 'Assert that the `getType` method' - .' does not return an empty string.'); + foreach ($this->getExports() as $export) { + $this->assertIsString( + $export->getType(), + 'Assert that the `getType` method return a string' + ); + $this->assertNotEmpty($export->getType(), 'Assert that the `getType` method' + .' does not return an empty string.'); + } } /** @@ -272,34 +308,36 @@ abstract class AbstractExportTest extends WebTestCase */ public function testInitiateQuery(mixed $modifiers, mixed $acl, mixed $data) { - $query = $this->getExport()->initiateQuery($modifiers, $acl, $data); + foreach ($this->getExports() as $export) { + $query = $export->initiateQuery($modifiers, $acl, $data); - $this->assertTrue( - $query instanceof QueryBuilder || $query instanceof NativeQuery, - sprintf( - 'Assert that the returned query is an instance of %s or %s', - QueryBuilder::class, - Query::class - ) - ); - - if ($query instanceof QueryBuilder) { - $this->assertGreaterThanOrEqual( - 1, - \count($query->getDQLPart('select')), - "assert there is at least one 'select' part" + $this->assertTrue( + $query instanceof QueryBuilder || $query instanceof NativeQuery, + sprintf( + 'Assert that the returned query is an instance of %s or %s', + QueryBuilder::class, + NativeQuery::class + ) ); - $this->assertGreaterThanOrEqual( - 1, - \count($query->getDQLPart('from')), - "assert there is at least one 'from' part" - ); - } elseif ($query instanceof NativeQuery) { - $this->assertNotEmpty( - $query->getSQL(), - 'check that the SQL query is not empty' - ); + if ($query instanceof QueryBuilder) { + $this->assertGreaterThanOrEqual( + 1, + \count($query->getDQLPart('select')), + "assert there is at least one 'select' part" + ); + + $this->assertGreaterThanOrEqual( + 1, + \count($query->getDQLPart('from')), + "assert there is at least one 'from' part" + ); + } elseif ($query instanceof NativeQuery) { + $this->assertNotEmpty( + $query->getSQL(), + 'check that the SQL query is not empty' + ); + } } } @@ -308,9 +346,11 @@ abstract class AbstractExportTest extends WebTestCase */ public function testRequiredRole() { - $role = $this->getExport()->requiredRole(); + foreach ($this->getExports() as $export) { + $role = $export->requiredRole(); - self::assertIsString($role); + self::assertIsString($role); + } } /** @@ -323,22 +363,23 @@ abstract class AbstractExportTest extends WebTestCase */ public function testSupportsModifier(mixed $modifiers, mixed $acl, mixed $data) { - $export = $this->getExport(); - $query = $export->initiateQuery($modifiers, $acl, $data); + foreach ($this->getExports() as $export) { + $query = $export->initiateQuery($modifiers, $acl, $data); - if ($query instanceof QueryBuilder) { - $this->assertContainsOnly( - 'string', - $export->supportsModifiers(), - true, - 'Test that the `supportsModifiers` method returns only strings' - ); - } elseif ($query instanceof NativeQuery) { - $this->assertTrue( - null === $export->supportsModifiers() - || 0 === \count($export->supportsModifiers()), - 'Test that the `supportsModifier` methods returns null or an empty array' - ); + if ($query instanceof QueryBuilder) { + $this->assertContainsOnly( + 'string', + $export->supportsModifiers(), + true, + 'Test that the `supportsModifiers` method returns only strings' + ); + } elseif ($query instanceof NativeQuery) { + $this->assertTrue( + null === $export->supportsModifiers() + || 0 === \count($export->supportsModifiers()), + 'Test that the `supportsModifier` methods returns null or an empty array' + ); + } } } } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php index a710cccf7..1118b2cc4 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php @@ -23,16 +23,20 @@ use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; class CountAccompanyingCourse implements ExportInterface, GroupedExportInterface { protected EntityRepository $repository; + private readonly bool $filterStatsByCenters; public function __construct( EntityManagerInterface $em, + ParameterBagInterface $parameterBag, ) { $this->repository = $em->getRepository(AccompanyingPeriod::class); + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; } public function buildForm(FormBuilderInterface $builder): void @@ -102,15 +106,19 @@ class CountAccompanyingCourse implements ExportInterface, GroupedExportInterface ->andWhere('acp.step != :count_acp_step') ->leftJoin('acp.participations', 'acppart') ->leftJoin('acppart.person', 'person') - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.PersonCenterHistory::class.' acl_count_person_history WHERE acl_count_person_history.person = person + ->setParameter('count_acp_step', AccompanyingPeriod::STEP_DRAFT); + + 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('count_acp_step', AccompanyingPeriod::STEP_DRAFT) - ->setParameter('authorized_centers', $centers); + ->setParameter('authorized_centers', $centers); + } AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWork.php b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWork.php index e1e771222..e274ac5cd 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWork.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWork.php @@ -22,11 +22,19 @@ use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; class CountAccompanyingPeriodWork implements ExportInterface, GroupedExportInterface { - public function __construct(protected EntityManagerInterface $em) {} + private readonly bool $filterStatsByCenters; + + public function __construct( + protected EntityManagerInterface $em, + ParameterBagInterface $parameterBag, + ) { + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } public function buildForm(FormBuilderInterface $builder): void { @@ -95,15 +103,19 @@ class CountAccompanyingPeriodWork implements ExportInterface, GroupedExportInter ->from(AccompanyingPeriod\AccompanyingPeriodWork::class, 'acpw') ->join('acpw.accompanyingPeriod', 'acp') ->join('acp.participations', 'acppart') - ->join('acppart.person', 'person') - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.PersonCenterHistory::class.' acl_count_person_history WHERE acl_count_person_history.person = person + ->join('acppart.person', '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); + ->setParameter('authorized_centers', $centers); + } $qb->select('COUNT(DISTINCT acpw.id) as export_result'); diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php b/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php index ad32e0a03..0cbe7b3e8 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php @@ -21,11 +21,19 @@ use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; class CountEvaluation implements ExportInterface, GroupedExportInterface { - public function __construct(private readonly EntityManagerInterface $entityManager) {} + private readonly bool $filterStatsByCenters; + + public function __construct( + private readonly EntityManagerInterface $entityManager, + ParameterBagInterface $parameterBag, + ) { + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } public function buildForm(FormBuilderInterface $builder) {} @@ -92,15 +100,19 @@ class CountEvaluation implements ExportInterface, GroupedExportInterface ->join('workeval.accompanyingPeriodWork', 'acpw') ->join('acpw.accompanyingPeriod', 'acp') ->join('acp.participations', 'acppart') - ->join('acppart.person', 'person') - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.PersonCenterHistory::class.' acl_count_person_history WHERE acl_count_person_history.person = person + ->join('acppart.person', '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); + ->setParameter('authorized_centers', $centers); + } AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php b/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php index 9d4d22085..82a5c4aa4 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php @@ -23,13 +23,21 @@ use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Security\Authorization\HouseholdVoter; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; class CountHousehold implements ExportInterface, GroupedExportInterface { private const TR_PREFIX = 'export.export.nb_household_with_course.'; + private readonly bool $filterStatsByCenters; - public function __construct(private readonly EntityManagerInterface $entityManager, private readonly RollingDateConverterInterface $rollingDateConverter) {} + public function __construct( + private readonly EntityManagerInterface $entityManager, + private readonly RollingDateConverterInterface $rollingDateConverter, + ParameterBagInterface $parameterBag, + ) { + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } public function buildForm(FormBuilderInterface $builder) { @@ -112,21 +120,25 @@ class CountHousehold implements ExportInterface, GroupedExportInterface ->join('person.accompanyingPeriodParticipations', 'acppart') ->join('acppart.accompanyingPeriod', 'acp') ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') - ->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) - ' - ) - ) - ->andWhere('hmember.startDate <= :count_household_at_date AND (hmember.endDate IS NULL OR hmember.endDate > :count_household_at_date)') - ->setParameter('authorized_centers', $centers) ->setParameter('count_household_at_date', $this->rollingDateConverter->convert($data['calc_date'])); $qb ->select('COUNT(DISTINCT household.id) AS household_export_result') ->addSelect('COUNT(DISTINCT acp.id) AS acp_export_result'); + 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) + ' + ) + ) + ->andWhere('hmember.startDate <= :count_household_at_date AND (hmember.endDate IS NULL OR hmember.endDate > :count_household_at_date)') + ->setParameter('authorized_centers', $centers); + } + return $qb; } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php index a9635791a..a1e855b0e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php @@ -20,11 +20,19 @@ use Chill\PersonBundle\Repository\PersonRepository; use Chill\PersonBundle\Security\Authorization\PersonVoter; use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; class CountPerson implements ExportInterface, GroupedExportInterface { - public function __construct(protected PersonRepository $personRepository) {} + private readonly bool $filterStatsByCenters; + + public function __construct( + protected PersonRepository $personRepository, + ParameterBagInterface $parameterBag, + ) { + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } public function buildForm(FormBuilderInterface $builder) { @@ -94,13 +102,17 @@ class CountPerson implements ExportInterface, GroupedExportInterface $qb = $this->personRepository->createQueryBuilder('person'); - $qb->select('COUNT(DISTINCT person.id) AS export_result') - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.PersonCenterHistory::class.' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)' + $qb->select('COUNT(DISTINCT person.id) AS export_result'); + + if ($this->filterStatsByCenters) { + $qb + ->andWhere( + $qb->expr()->exists( + 'SELECT 1 FROM '.PersonCenterHistory::class.' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)' + ) ) - ) - ->setParameter('authorized_centers', $centers); + ->setParameter('authorized_centers', $centers); + } return $qb; } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountPersonWithAccompanyingCourse.php b/src/Bundle/ChillPersonBundle/Export/Export/CountPersonWithAccompanyingCourse.php index a582d987f..ef000603a 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountPersonWithAccompanyingCourse.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountPersonWithAccompanyingCourse.php @@ -22,16 +22,20 @@ use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; class CountPersonWithAccompanyingCourse implements ExportInterface, GroupedExportInterface { private readonly EntityRepository $repository; + private readonly bool $filterStatsByCenters; public function __construct( EntityManagerInterface $em, + ParameterBagInterface $parameterBag, ) { $this->repository = $em->getRepository(AccompanyingPeriod::class); + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; } public function buildForm(FormBuilderInterface $builder) @@ -105,11 +109,13 @@ class CountPersonWithAccompanyingCourse implements ExportInterface, GroupedExpor $qb->join('acppart.person', 'person'); } - $qb->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.PersonCenterHistory::class.' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)' - ) - )->setParameter('authorized_centers', $centers); + if ($this->filterStatsByCenters) { + $qb->andWhere( + $qb->expr()->exists( + 'SELECT 1 FROM '.PersonCenterHistory::class.' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)' + ) + )->setParameter('authorized_centers', $centers); + } AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php index cd6eb2e81..881a38db6 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php @@ -26,15 +26,21 @@ use Chill\PersonBundle\Export\Helper\ListAccompanyingPeriodHelper; use Chill\PersonBundle\Security\Authorization\PersonVoter; use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; final readonly class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface { + private bool $filterStatsByCenters; + public function __construct( private EntityManagerInterface $entityManager, private RollingDateConverterInterface $rollingDateConverter, private ListAccompanyingPeriodHelper $listAccompanyingPeriodHelper, - ) {} + ParameterBagInterface $parameterBag, + ) { + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } public function buildForm(FormBuilderInterface $builder) { @@ -102,16 +108,20 @@ final readonly class ListAccompanyingPeriod implements ListInterface, GroupedExp $qb ->from(AccompanyingPeriod::class, 'acp') ->andWhere('acp.step != :list_acp_step') - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part + ->setParameter('list_acp_step', AccompanyingPeriod::STEP_DRAFT); + + 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('list_acp_step', AccompanyingPeriod::STEP_DRAFT) - ->setParameter('authorized_centers', $centers); + ->setParameter('authorized_centers', $centers); + } $this->listAccompanyingPeriodHelper->addSelectClauses($qb, $this->rollingDateConverter->convert($data['calc_date'])); diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWork.php b/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWork.php index 6c9b5d202..81c60bae6 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWork.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWork.php @@ -44,6 +44,7 @@ use Chill\ThirdPartyBundle\Export\Helper\LabelThirdPartyHelper; use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterface @@ -78,6 +79,8 @@ class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterfac 'updatedBy', ]; + private readonly bool $filterStatsByCenters; + public function __construct( private readonly EntityManagerInterface $entityManager, private readonly DateTimeHelper $dateTimeHelper, @@ -90,8 +93,11 @@ class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterfac private readonly SocialActionRender $socialActionRender, private readonly RollingDateConverterInterface $rollingDateConverter, private readonly AggregateStringHelper $aggregateStringHelper, - private readonly SocialActionRepository $socialActionRepository - ) {} + private readonly SocialActionRepository $socialActionRepository, + ParameterBagInterface $parameterBag, + ) { + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } public function buildForm(FormBuilderInterface $builder) { @@ -214,15 +220,19 @@ class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterfac ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') // get participants at the given date ->andWhere('acppart.startDate <= :calc_date AND (acppart.endDate > :calc_date OR acppart.endDate IS NULL)') - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.PersonCenterHistory::class.' acl_count_person_history WHERE acl_count_person_history.person = person + ->setParameter('calc_date', $this->rollingDateConverter->convert($data['calc_date'])); + + 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) - ->setParameter('calc_date', $this->rollingDateConverter->convert($data['calc_date'])); + ->setParameter('authorized_centers', $centers); + } AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListEvaluation.php b/src/Bundle/ChillPersonBundle/Export/Export/ListEvaluation.php index 653075dbc..6b3eba107 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListEvaluation.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListEvaluation.php @@ -37,6 +37,7 @@ use Chill\PersonBundle\Templating\Entity\SocialIssueRender; use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; class ListEvaluation implements ListInterface, GroupedExportInterface @@ -68,7 +69,24 @@ class ListEvaluation implements ListInterface, GroupedExportInterface 'updatedBy', ]; - public function __construct(private readonly EntityManagerInterface $entityManager, private readonly SocialIssueRender $socialIssueRender, private readonly SocialIssueRepository $socialIssueRepository, private readonly SocialActionRender $socialActionRender, private readonly SocialActionRepository $socialActionRepository, private readonly UserHelper $userHelper, private readonly LabelPersonHelper $personHelper, private readonly DateTimeHelper $dateTimeHelper, private readonly TranslatableStringExportLabelHelper $translatableStringExportLabelHelper, private readonly AggregateStringHelper $aggregateStringHelper, private readonly RollingDateConverterInterface $rollingDateConverter) {} + private readonly bool $filterStatsByCenters; + + public function __construct( + private readonly EntityManagerInterface $entityManager, + private readonly SocialIssueRender $socialIssueRender, + private readonly SocialIssueRepository $socialIssueRepository, + private readonly SocialActionRender $socialActionRender, + private readonly SocialActionRepository $socialActionRepository, + private readonly UserHelper $userHelper, + private readonly LabelPersonHelper $personHelper, + private readonly DateTimeHelper $dateTimeHelper, + private readonly TranslatableStringExportLabelHelper $translatableStringExportLabelHelper, + private readonly AggregateStringHelper $aggregateStringHelper, + private readonly RollingDateConverterInterface $rollingDateConverter, + ParameterBagInterface $parameterBag, + ) { + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } public function buildForm(FormBuilderInterface $builder) { @@ -190,15 +208,19 @@ class ListEvaluation implements ListInterface, GroupedExportInterface ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') // get participants at the given date ->andWhere('acppart.startDate <= :calc_date AND (acppart.endDate > :calc_date OR acppart.endDate IS NULL)') - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.PersonCenterHistory::class.' acl_count_person_history WHERE acl_count_person_history.person = person + ->setParameter('calc_date', $this->rollingDateConverter->convert($data['calc_date'])); + + 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) - ->setParameter('calc_date', $this->rollingDateConverter->convert($data['calc_date'])); + ->setParameter('authorized_centers', $centers); + } AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListHouseholdInPeriod.php b/src/Bundle/ChillPersonBundle/Export/Export/ListHouseholdInPeriod.php index 2d332969d..46770fab8 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListHouseholdInPeriod.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListHouseholdInPeriod.php @@ -29,6 +29,7 @@ use Chill\PersonBundle\Security\Authorization\HouseholdVoter; use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; class ListHouseholdInPeriod implements ListInterface, GroupedExportInterface @@ -42,14 +43,18 @@ class ListHouseholdInPeriod implements ListInterface, GroupedExportInterface 'compositionComment', 'compositionType', ]; + private readonly bool $filterStatsByCenters; public function __construct( private readonly ExportAddressHelper $addressHelper, private readonly AggregateStringHelper $aggregateStringHelper, private readonly EntityManagerInterface $entityManager, private readonly RollingDateConverterInterface $rollingDateConverter, - private readonly TranslatableStringExportLabelHelper $translatableStringHelper - ) {} + private readonly TranslatableStringExportLabelHelper $translatableStringHelper, + ParameterBagInterface $parameterBag, + ) { + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } public function buildForm(FormBuilderInterface $builder) { @@ -138,16 +143,20 @@ class ListHouseholdInPeriod implements ListInterface, GroupedExportInterface ->join('person.accompanyingPeriodParticipations', 'acppart') ->join('acppart.accompanyingPeriod', 'acp') ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.PersonCenterHistory::class.' acl_count_person_history WHERE acl_count_person_history.person = person + ->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'])); + + 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) ' + ) ) - ) - ->andWhere('hmember.startDate <= :count_household_at_date AND (hmember.endDate IS NULL OR hmember.endDate > :count_household_at_date)') - ->setParameter('authorized_centers', $centers) - ->setParameter('count_household_at_date', $this->rollingDateConverter->convert($data['calc_date'])); + ->setParameter('authorized_centers', $centers); + } $this->addSelectClauses($qb, $this->rollingDateConverter->convert($data['calc_date'])); diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php index 8beda5ef5..b0e916765 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php @@ -29,6 +29,7 @@ use DateTimeImmutable; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query; use PhpOffice\PhpSpreadsheet\Shared\Date; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Validator\Constraints\Callback; @@ -40,14 +41,18 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface; class ListPerson implements ExportElementValidatedInterface, ListInterface, GroupedExportInterface { private array $slugs = []; + private readonly bool $filterStatsByCenters; public function __construct( private readonly ExportAddressHelper $addressHelper, private readonly CustomFieldProvider $customFieldProvider, private readonly ListPersonHelper $listPersonHelper, private readonly EntityManagerInterface $entityManager, - private readonly TranslatableStringHelper $translatableStringHelper - ) {} + private readonly TranslatableStringHelper $translatableStringHelper, + ParameterBagInterface $parameterBag, + ) { + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } public function buildForm(FormBuilderInterface $builder) { @@ -184,16 +189,18 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou throw new \Doctrine\DBAL\Exception\InvalidArgumentException('any fields have been checked'); } - $qb = $this->entityManager->createQueryBuilder(); + $qb = $this->entityManager->createQueryBuilder() + ->from(Person::class, 'person'); - $qb - ->from(Person::class, 'person') - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.Person\PersonCenterHistory::class.' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)' + if ($this->filterStatsByCenters) { + $qb + ->andWhere( + $qb->expr()->exists( + 'SELECT 1 FROM '.Person\PersonCenterHistory::class.' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)' + ) ) - ) - ->setParameter('authorized_centers', $centers); + ->setParameter('authorized_centers', $centers); + } $fields = $data['fields']; diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonHavingAccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonHavingAccompanyingPeriod.php index 7cc2a4c35..e638838fb 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonHavingAccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonHavingAccompanyingPeriod.php @@ -17,7 +17,9 @@ use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; use Chill\MainBundle\Export\Helper\ExportAddressHelper; use Chill\MainBundle\Export\ListInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person\PersonCenterHistory; @@ -27,6 +29,7 @@ use Chill\PersonBundle\Security\Authorization\PersonVoter; use DateTimeImmutable; use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Validator\Constraints\Callback; @@ -37,9 +40,19 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface; * * Details of the accompanying period are not included */ -class ListPersonHavingAccompanyingPeriod implements ExportElementValidatedInterface, ListInterface, GroupedExportInterface +final readonly class ListPersonHavingAccompanyingPeriod implements ExportElementValidatedInterface, ListInterface, GroupedExportInterface { - public function __construct(private readonly ExportAddressHelper $addressHelper, private readonly ListPersonHelper $listPersonHelper, private readonly EntityManagerInterface $entityManager) {} + private bool $filterStatsByCenters; + + public function __construct( + private ExportAddressHelper $addressHelper, + private ListPersonHelper $listPersonHelper, + private EntityManagerInterface $entityManager, + private RollingDateConverterInterface $rollingDateConverter, + ParameterBagInterface $parameterBag, + ) { + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } public function buildForm(FormBuilderInterface $builder) { @@ -69,10 +82,9 @@ class ListPersonHavingAccompanyingPeriod implements ExportElementValidatedInterf ])], ]); - $builder->add('address_date', ChillDateType::class, [ + $builder->add('address_date_rolling', PickRollingDateType::class, [ 'label' => 'Data valid at this date', 'help' => 'Data regarding center, addresses, and so on will be computed at this date', - 'input' => 'datetime_immutable', ]); } @@ -80,7 +92,7 @@ class ListPersonHavingAccompanyingPeriod implements ExportElementValidatedInterf { $choices = array_combine(ListPersonHelper::FIELDS, ListPersonHelper::FIELDS); - return ['fields' => array_values($choices), 'address_date' => new \DateTimeImmutable()]; + return ['fields' => array_values($choices), 'address_date_rolling' => new RollingDate(RollingDate::T_TODAY)]; } public function getAllowedFormattersTypes() @@ -162,16 +174,20 @@ class ListPersonHavingAccompanyingPeriod implements ExportElementValidatedInterf $qb->from(Person::class, 'person') ->join('person.accompanyingPeriodParticipations', 'acppart') ->join('acppart.accompanyingPeriod', 'acp') - ->andWhere($qb->expr()->neq('acp.step', "'".AccompanyingPeriod::STEP_DRAFT."'")) - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.PersonCenterHistory::class.' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)' - ) - )->setParameter('authorized_centers', $centers); + ->andWhere($qb->expr()->neq('acp.step', "'".AccompanyingPeriod::STEP_DRAFT."'")); + + if ($this->filterStatsByCenters) { + $qb + ->andWhere( + $qb->expr()->exists( + 'SELECT 1 FROM '.PersonCenterHistory::class.' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)' + ) + )->setParameter('authorized_centers', $centers); + } $fields = $data['fields']; - $this->listPersonHelper->addSelect($qb, $fields, $data['address_date']); + $this->listPersonHelper->addSelect($qb, $fields, $this->rollingDateConverter->convert($data['address_date_rolling'])); AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriodDetails.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriodDetails.php index 22be5ceca..d1cf49a5d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriodDetails.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriodDetails.php @@ -28,6 +28,7 @@ use Chill\PersonBundle\Security\Authorization\PersonVoter; use DateTimeImmutable; use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; /** @@ -35,12 +36,17 @@ use Symfony\Component\Form\FormBuilderInterface; */ final readonly class ListPersonWithAccompanyingPeriodDetails implements ListInterface, GroupedExportInterface { + private bool $filterStatsByCenters; + public function __construct( private ListPersonHelper $listPersonHelper, private ListAccompanyingPeriodHelper $listAccompanyingPeriodHelper, private EntityManagerInterface $entityManager, private RollingDateConverterInterface $rollingDateConverter, - ) {} + ParameterBagInterface $parameterBag, + ) { + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } public function buildForm(FormBuilderInterface $builder) { @@ -114,12 +120,16 @@ final readonly class ListPersonWithAccompanyingPeriodDetails implements ListInte $qb->from(Person::class, 'person') ->join('person.accompanyingPeriodParticipations', 'acppart') ->join('acppart.accompanyingPeriod', 'acp') - ->andWhere($qb->expr()->neq('acp.step', "'".AccompanyingPeriod::STEP_DRAFT."'")) - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.PersonCenterHistory::class.' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)' - ) - )->setParameter('authorized_centers', $centers); + ->andWhere($qb->expr()->neq('acp.step', "'".AccompanyingPeriod::STEP_DRAFT."'")); + + if ($this->filterStatsByCenters) { + $qb + ->andWhere( + $qb->expr()->exists( + 'SELECT 1 FROM '.PersonCenterHistory::class.' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)' + ) + )->setParameter('authorized_centers', $centers); + } $this->listPersonHelper->addSelect($qb, ListPersonHelper::FIELDS, $this->rollingDateConverter->convert($data['address_date'])); $this->listAccompanyingPeriodHelper->addSelectClauses($qb, $this->rollingDateConverter->convert($data['address_date'])); diff --git a/src/Bundle/ChillPersonBundle/Export/Export/StatAccompanyingCourseDuration.php b/src/Bundle/ChillPersonBundle/Export/Export/StatAccompanyingCourseDuration.php index 01cc94aa8..58f06ab7e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/StatAccompanyingCourseDuration.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/StatAccompanyingCourseDuration.php @@ -15,7 +15,9 @@ use Chill\MainBundle\Export\AccompanyingCourseExportHelper; use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Person\PersonCenterHistory; use Chill\PersonBundle\Export\Declarations; @@ -24,28 +26,34 @@ use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\FormBuilderInterface; -class StatAccompanyingCourseDuration implements ExportInterface, GroupedExportInterface +final readonly class StatAccompanyingCourseDuration implements ExportInterface, GroupedExportInterface { private readonly EntityRepository $repository; + private bool $filterStatsByCenters; + public function __construct( EntityManagerInterface $em, + private RollingDateConverterInterface $rollingDateConverter, + ParameterBagInterface $parameterBag, ) { $this->repository = $em->getRepository(AccompanyingPeriod::class); + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; } public function buildForm(FormBuilderInterface $builder): void { - $builder->add('closingdate', ChillDateType::class, [ + $builder->add('closingdate_rolling', PickRollingDateType::class, [ 'label' => 'Closingdate to apply', ]); } public function getFormDefaultData(): array { - return ['closingdate' => new \DateTime('now')]; + return ['closingdate_rolling' => new RollingDate(RollingDate::T_TODAY)]; } public function getAllowedFormattersTypes(): array @@ -118,20 +126,24 @@ class StatAccompanyingCourseDuration implements ExportInterface, GroupedExportIn ->addSelect('COUNT(DISTINCT acppart.id) AS count_acppart_export_result') ->addSelect('COUNT(DISTINCT person.id) AS count_pers_export_result') ->addSelect('COUNT(DISTINCT acp.id) AS count_acp_export_result') - ->setParameter('force_closingDate', $data['closingdate']) + ->setParameter('force_closingDate', $this->rollingDateConverter->convert($data['closingdate_rolling'])) ->leftJoin('acp.participations', 'acppart') ->leftJoin('acppart.person', 'person') ->andWhere('acp.step != :count_acp_step') ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') - ->andWhere( - $qb->expr()->exists( - 'SELECT 1 FROM '.PersonCenterHistory::class.' acl_count_person_history WHERE acl_count_person_history.person = person + ->setParameter('count_acp_step', AccompanyingPeriod::STEP_DRAFT); + + 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('count_acp_step', AccompanyingPeriod::STEP_DRAFT) - ->setParameter('authorized_centers', $centers); + ->setParameter('authorized_centers', $centers); + } AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingCourseTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingCourseTest.php index 2b7f8468c..88803e508 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingCourseTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingCourseTest.php @@ -14,6 +14,7 @@ namespace Export\Export; use Chill\MainBundle\Test\Export\AbstractExportTest; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Export\Export\CountAccompanyingCourse; +use Doctrine\ORM\EntityManagerInterface; /** * @internal @@ -22,18 +23,17 @@ use Chill\PersonBundle\Export\Export\CountAccompanyingCourse; */ final class CountAccompanyingCourseTest extends AbstractExportTest { - private CountAccompanyingCourse $export; - protected function setUp(): void { self::bootKernel(); - - $this->export = self::$container->get('chill.person.export.count_accompanyingcourse'); } public function getExport() { - return $this->export; + $em = self::$container->get(EntityManagerInterface::class); + + yield new CountAccompanyingCourse($em, $this->getParameters(true)); + yield new CountAccompanyingCourse($em, $this->getParameters(false)); } public function getFormData(): array diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingPeriodWorkTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingPeriodWorkTest.php index 1ec36a0ab..271f448d6 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingPeriodWorkTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountAccompanyingPeriodWorkTest.php @@ -14,6 +14,7 @@ namespace Export\Export; use Chill\MainBundle\Test\Export\AbstractExportTest; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Export\Export\CountAccompanyingPeriodWork; +use Doctrine\ORM\EntityManagerInterface; /** * @internal @@ -33,7 +34,10 @@ final class CountAccompanyingPeriodWorkTest extends AbstractExportTest public function getExport() { - return $this->export; + $em = self::$container->get(EntityManagerInterface::class); + + yield new CountAccompanyingPeriodWork($em, $this->getParameters(true)); + yield new CountAccompanyingPeriodWork($em, $this->getParameters(false)); } public function getFormData(): array diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountPersonTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountPersonTest.php index 91640e9a4..758b4d11f 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountPersonTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountPersonTest.php @@ -13,6 +13,7 @@ namespace Chill\PersonBundle\Tests\Export\Export; use Chill\MainBundle\Test\Export\AbstractExportTest; use Chill\PersonBundle\Export\Export\CountPerson; +use Chill\PersonBundle\Repository\PersonRepository; /** * Test CountPerson export. @@ -23,18 +24,17 @@ use Chill\PersonBundle\Export\Export\CountPerson; */ final class CountPersonTest extends AbstractExportTest { - private ?object $export = null; - protected function setUp(): void { self::bootKernel(); - - $this->export = self::$container->get(CountPerson::class); } public function getExport() { - return $this->export; + $personRepository = self::$container->get(PersonRepository::class); + + yield new CountPerson($personRepository, $this->getParameters(true)); + yield new CountPerson($personRepository, $this->getParameters(false)); } public function getFormData() diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountPersonWithAccompanyingCourseTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountPersonWithAccompanyingCourseTest.php new file mode 100644 index 000000000..128bf271d --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountPersonWithAccompanyingCourseTest.php @@ -0,0 +1,48 @@ +get(EntityManagerInterface::class); + + yield new CountPersonWithAccompanyingCourse($em, $this->getParameters(true)); + yield new CountPersonWithAccompanyingCourse($em, $this->getParameters(false)); + } + + public function getFormData() + { + return [[]]; + } + + public function getModifiersCombination() + { + return [[Declarations::ACP_TYPE]]; + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListAccompanyingPeriodTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListAccompanyingPeriodTest.php index 0a864050f..a74822584 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListAccompanyingPeriodTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListAccompanyingPeriodTest.php @@ -11,43 +11,51 @@ declare(strict_types=1); namespace Chill\PersonBundle\Tests\Export\Export; -use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Repository\CenterRepositoryInterface; 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\ListAccompanyingPeriod; -use Doctrine\ORM\AbstractQuery; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Chill\PersonBundle\Export\Helper\ListAccompanyingPeriodHelper; +use Doctrine\ORM\EntityManagerInterface; /** * @internal * * @coversNothing */ -class ListAccompanyingPeriodTest extends KernelTestCase +class ListAccompanyingPeriodTest extends AbstractExportTest { - private ListAccompanyingPeriod $listAccompanyingPeriod; + private readonly ListAccompanyingPeriod $listAccompanyingPeriod; - private CenterRepositoryInterface $centerRepository; + private readonly CenterRepositoryInterface $centerRepository; protected function setUp(): void { parent::setUp(); self::bootKernel(); - - $this->listAccompanyingPeriod = self::$container->get(ListAccompanyingPeriod::class); - $this->centerRepository = self::$container->get(CenterRepositoryInterface::class); } - public function testQuery(): void + public function getExport() { - $centers = $this->centerRepository->findAll(); + $em = self::$container->get(EntityManagerInterface::class); + $rollingDateConverter = self::$container->get(RollingDateConverterInterface::class); + $listAccompanyingPeriodHelper = self::$container->get(ListAccompanyingPeriodHelper::class); - $query = $this->listAccompanyingPeriod->initiateQuery([], array_map(fn (Center $c) => ['center' => $c], $centers), $exportOpts = ['calc_date' => new RollingDate(RollingDate::T_TODAY)]); + yield new ListAccompanyingPeriod($em, $rollingDateConverter, $listAccompanyingPeriodHelper, $this->getParameters(true)); + yield new ListAccompanyingPeriod($em, $rollingDateConverter, $listAccompanyingPeriodHelper, $this->getParameters(false)); + } - $query->setMaxResults(1); + public function getFormData() + { + return [ + ['calc_date' => new RollingDate(RollingDate::T_TODAY)], + ]; + } - $actual = $query->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY); - - self::assertIsArray($actual); + 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/ListAccompanyingPeriodWorkTest.php index 08fa5141e..ab8ca7c38 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListAccompanyingPeriodWorkTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListAccompanyingPeriodWorkTest.php @@ -11,40 +11,93 @@ declare(strict_types=1); namespace Chill\PersonBundle\Tests\Export\Export; -use Chill\MainBundle\Entity\Center; -use Chill\MainBundle\Repository\CenterRepositoryInterface; +use Chill\MainBundle\Export\Helper\AggregateStringHelper; +use Chill\MainBundle\Export\Helper\DateTimeHelper; +use Chill\MainBundle\Export\Helper\TranslatableStringExportLabelHelper; +use Chill\MainBundle\Export\Helper\UserHelper; 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 Doctrine\ORM\AbstractQuery; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Chill\PersonBundle\Export\Helper\LabelPersonHelper; +use Chill\PersonBundle\Repository\SocialWork\SocialActionRepository; +use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository; +use Chill\PersonBundle\Templating\Entity\SocialActionRender; +use Chill\PersonBundle\Templating\Entity\SocialIssueRender; +use Chill\ThirdPartyBundle\Export\Helper\LabelThirdPartyHelper; +use Doctrine\ORM\EntityManagerInterface; /** * @internal * * @coversNothing */ -class ListAccompanyingPeriodWorkTest extends KernelTestCase +class ListAccompanyingPeriodWorkTest extends AbstractExportTest { - private ListAccompanyingPeriodWork $listAccompanyingPeriodWork; - - private CenterRepositoryInterface $centerRepository; - protected function setUp(): void { parent::setUp(); self::bootKernel(); - - $this->listAccompanyingPeriodWork = self::$container->get(ListAccompanyingPeriodWork::class); - $this->centerRepository = self::$container->get(CenterRepositoryInterface::class); } - public function testQuery(): void + public function getExport() { - $centers = $this->centerRepository->findAll(); + $entityManager = self::$container->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); - $query = $this->listAccompanyingPeriodWork->initiateQuery([], array_map(fn (Center $c) => ['center' => $c], $centers), ['calc_date' => new RollingDate(RollingDate::T_TODAY)]); - $query->setMaxResults(1); + yield new ListAccompanyingPeriodWork( + $entityManager, + $dateTimeHelper, + $userHelper, + $personHelper, + $thirdPartyHelper, + $translatableStringExportLabelHelper, + $socialIssueRender, + $socialIssueRepository, + $socialActionRender, + $rollingDateConverter, + $aggregateStringHelper, + $socialActionRepository, + $this->getParameters(true), + ); - self::assertIsArray($query->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY)); + yield new ListAccompanyingPeriodWork( + $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/ListEvaluationTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListEvaluationTest.php index 7015fae11..08920881e 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListEvaluationTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListEvaluationTest.php @@ -12,18 +12,30 @@ declare(strict_types=1); namespace Chill\PersonBundle\Tests\Export\Export; use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Export\Helper\AggregateStringHelper; +use Chill\MainBundle\Export\Helper\DateTimeHelper; +use Chill\MainBundle\Export\Helper\TranslatableStringExportLabelHelper; +use Chill\MainBundle\Export\Helper\UserHelper; use Chill\MainBundle\Repository\CenterRepositoryInterface; 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\ListEvaluation; +use Chill\PersonBundle\Export\Helper\LabelPersonHelper; +use Chill\PersonBundle\Repository\SocialWork\SocialActionRepository; +use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository; +use Chill\PersonBundle\Templating\Entity\SocialActionRender; +use Chill\PersonBundle\Templating\Entity\SocialIssueRender; use Doctrine\ORM\AbstractQuery; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Doctrine\ORM\EntityManagerInterface; /** * @internal * * @coversNothing */ -class ListEvaluationTest extends KernelTestCase +class ListEvaluationTest extends AbstractExportTest { private ListEvaluation $listEvaluation; @@ -38,6 +50,61 @@ class ListEvaluationTest extends KernelTestCase $this->centerRepository = self::$container->get(CenterRepositoryInterface::class); } + public function getExport() + { + $entityManager = self::$container->get(EntityManagerInterface::class); + $dateTimeHelper = self::$container->get(DateTimeHelper::class); + $userHelper = self::$container->get(UserHelper::class); + $personHelper = self::$container->get(LabelPersonHelper::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 ListEvaluation( + $entityManager, + $socialIssueRender, + $socialIssueRepository, + $socialActionRender, + $socialActionRepository, + $userHelper, + $personHelper, + $dateTimeHelper, + $translatableStringExportLabelHelper, + $aggregateStringHelper, + $rollingDateConverter, + $this->getParameters(true), + ); + + yield new ListEvaluation( + $entityManager, + $socialIssueRender, + $socialIssueRepository, + $socialActionRender, + $socialActionRepository, + $userHelper, + $personHelper, + $dateTimeHelper, + $translatableStringExportLabelHelper, + $aggregateStringHelper, + $rollingDateConverter, + $this->getParameters(false), + ); + } + + public function getFormData() + { + return [['calc_date' => new RollingDate(RollingDate::T_TODAY)]]; + } + + public function getModifiersCombination() + { + return [[Declarations::ACP_TYPE]]; + } + public function testQuery(): void { $centers = $this->centerRepository->findAll(); diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListHouseholdInPeriodTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListHouseholdInPeriodTest.php new file mode 100644 index 000000000..929fdc829 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListHouseholdInPeriodTest.php @@ -0,0 +1,72 @@ +get(ExportAddressHelper::class); + $aggregateStringHelper = self::$container->get(AggregateStringHelper::class); + $entityManager = self::$container->get(EntityManagerInterface::class); + $rollingDateConverter = self::$container->get(RollingDateConverterInterface::class); + $translatableStringHelper = self::$container->get(TranslatableStringExportLabelHelper::class); + + yield new ListHouseholdInPeriod( + $addressHelper, + $aggregateStringHelper, + $entityManager, + $rollingDateConverter, + $translatableStringHelper, + $this->getParameters(true), + ); + + yield new ListHouseholdInPeriod( + $addressHelper, + $aggregateStringHelper, + $entityManager, + $rollingDateConverter, + $translatableStringHelper, + $this->getParameters(false), + ); + } + + public function getFormData() + { + return [['calc_date' => new RollingDate(RollingDate::T_TODAY)]]; + } + + public function getModifiersCombination() + { + return [[Declarations::PERSON_TYPE]]; + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonHavingAccompanyingPeriodTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonHavingAccompanyingPeriodTest.php new file mode 100644 index 000000000..c050779e2 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonHavingAccompanyingPeriodTest.php @@ -0,0 +1,69 @@ +get(ExportAddressHelper::class); + $listPersonHelper = self::$container->get(ListPersonHelper::class); + $entityManager = self::$container->get(EntityManagerInterface::class); + $rollingDateconverter = self::$container->get(RollingDateConverterInterface::class); + + yield new ListPersonHavingAccompanyingPeriod( + $addressHelper, + $listPersonHelper, + $entityManager, + $rollingDateconverter, + $this->getParameters(true), + ); + + yield new ListPersonHavingAccompanyingPeriod( + $addressHelper, + $listPersonHelper, + $entityManager, + $rollingDateconverter, + $this->getParameters(false), + ); + } + + public function getFormData() + { + return [['address_date_rolling' => new RollingDate(RollingDate::T_TODAY), 'fields' => ListPersonHelper::FIELDS]]; + } + + public function getModifiersCombination() + { + return [[Declarations::PERSON_TYPE, Declarations::ACP_TYPE]]; + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonTest.php index 11937c216..b398d1c91 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonTest.php @@ -11,8 +11,13 @@ declare(strict_types=1); namespace Chill\PersonBundle\Tests\Export\Export; +use Chill\CustomFieldsBundle\Service\CustomFieldProvider; +use Chill\MainBundle\Export\Helper\ExportAddressHelper; +use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Test\Export\AbstractExportTest; use Chill\PersonBundle\Export\Export\ListPerson; +use Chill\PersonBundle\Export\Helper\ListPersonHelper; +use Doctrine\ORM\EntityManagerInterface; use Prophecy\PhpUnit\ProphecyTrait; /** @@ -45,7 +50,29 @@ final class ListPersonTest extends AbstractExportTest public function getExport() { - return $this->export; + $addressHelper = self::$container->get(ExportAddressHelper::class); + $customFieldProvider = self::$container->get(CustomFieldProvider::class); + $listPersonHelper = self::$container->get(ListPersonHelper::class); + $entityManager = self::$container->get(EntityManagerInterface::class); + $translatableStringHelper = self::$container->get(TranslatableStringHelper::class); + + yield new ListPerson( + $addressHelper, + $customFieldProvider, + $listPersonHelper, + $entityManager, + $translatableStringHelper, + $this->getParameters(true), + ); + + yield new ListPerson( + $addressHelper, + $customFieldProvider, + $listPersonHelper, + $entityManager, + $translatableStringHelper, + $this->getParameters(false), + ); } public function getFormData(): iterable diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonWithAccompanyingPeriodDetailsTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonWithAccompanyingPeriodDetailsTest.php new file mode 100644 index 000000000..aba208df9 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonWithAccompanyingPeriodDetailsTest.php @@ -0,0 +1,73 @@ +get(ListPersonHelper::class); + $listAccompanyingPeriodHelper = self::$container->get(ListAccompanyingPeriodHelper::class); + $entityManager = self::$container->get(EntityManagerInterface::class); + $rollingDateConverter = self::$container->get(RollingDateConverterInterface::class); + + yield new ListPersonWithAccompanyingPeriodDetails( + $listPersonHelper, + $listAccompanyingPeriodHelper, + $entityManager, + $rollingDateConverter, + $this->getParameters(true), + ); + + yield new ListPersonWithAccompanyingPeriodDetails( + $listPersonHelper, + $listAccompanyingPeriodHelper, + $entityManager, + $rollingDateConverter, + $this->getParameters(false), + ); + } + + public function getFormData() + { + return [ + ['address_date' => new RollingDate(RollingDate::T_TODAY)], + ]; + } + + public function getModifiersCombination() + { + return [ + [Declarations::PERSON_TYPE, Declarations::ACP_TYPE], + ]; + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/StatAccompanyingCourseDurationTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/StatAccompanyingCourseDurationTest.php index a5ce35a7a..bf06466c6 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Export/StatAccompanyingCourseDurationTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/StatAccompanyingCourseDurationTest.php @@ -11,9 +11,12 @@ declare(strict_types=1); namespace Export\Export; +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\StatAccompanyingCourseDuration; +use Doctrine\ORM\EntityManagerInterface; /** * @internal @@ -33,13 +36,17 @@ final class StatAccompanyingCourseDurationTest extends AbstractExportTest public function getExport() { - return $this->export; + $em = self::$container->get(EntityManagerInterface::class); + $rollingDateconverter = self::$container->get(RollingDateConverterInterface::class); + + yield new StatAccompanyingCourseDuration($em, $rollingDateconverter, $this->getParameters(true)); + yield new StatAccompanyingCourseDuration($em, $rollingDateconverter, $this->getParameters(false)); } public function getFormData(): array { return [ - ['closingdate' => \DateTime::createFromFormat('Y-m-d', '2022-06-30')], + ['closingdate_rolling' => new RollingDate(RollingDate::T_TODAY)], ]; } From 4375ecf49a4b0364f55a08cf895996596bb7ff78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 19 Oct 2023 17:43:32 +0200 Subject: [PATCH 08/16] [export controller] skip the page "select a center" when the configuration value of `filter_stats_by_center` is set to false --- .../Controller/ExportController.php | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Controller/ExportController.php b/src/Bundle/ChillMainBundle/Controller/ExportController.php index abae07f9c..3aaac9a68 100644 --- a/src/Bundle/ChillMainBundle/Controller/ExportController.php +++ b/src/Bundle/ChillMainBundle/Controller/ExportController.php @@ -27,6 +27,7 @@ use Chill\MainBundle\Security\Authorization\SavedExportVoter; use Doctrine\ORM\EntityManagerInterface; use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\FormFactoryInterface; @@ -46,6 +47,8 @@ use Symfony\Contracts\Translation\TranslatorInterface; */ class ExportController extends AbstractController { + private readonly bool $filterStatsByCenters; + public function __construct( private readonly ChillRedis $redis, private readonly ExportManager $exportManager, @@ -56,8 +59,11 @@ class ExportController extends AbstractController private readonly EntityManagerInterface $entityManager, private readonly ExportFormHelper $exportFormHelper, private readonly SavedExportRepositoryInterface $savedExportRepository, - private readonly Security $security - ) {} + private readonly Security $security, + ParameterBagInterface $parameterBag, + ) { + $this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } /** * @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/exports/download/{alias}", name="chill_main_export_download", methods={"GET"}) @@ -484,9 +490,13 @@ class ExportController extends AbstractController $alias = $rawData['alias']; - $formCenters = $this->createCreateFormExport($alias, 'generate_centers', [], $savedExport); - $formCenters->submit($rawData['centers']); - $dataCenters = $formCenters->getData(); + if ($this->filterStatsByCenters) { + $formCenters = $this->createCreateFormExport($alias, 'generate_centers', [], $savedExport); + $formCenters->submit($rawData['centers']); + $dataCenters = $formCenters->getData(); + } else { + $dataCenters = ['centers' => []]; + } $formExport = $this->createCreateFormExport($alias, 'generate_export', $dataCenters, $savedExport); $formExport->submit($rawData['export']); @@ -513,6 +523,14 @@ class ExportController extends AbstractController */ private function selectCentersStep(Request $request, DirectExportInterface|ExportInterface $export, $alias, SavedExport $savedExport = null) { + if (!$this->filterStatsByCenters) { + return $this->redirectToRoute('chill_main_export_new', [ + 'step' => $this->getNextStep('centers', $export), + 'alias' => $alias, + 'from_saved' => $request->get('from_saved', ''), + ]); + } + /** @var \Chill\MainBundle\Export\ExportManager $exportManager */ $exportManager = $this->exportManager; From 7bff5ce39e7a8ddb124d649807738338ec9d8bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 24 Oct 2023 14:17:08 +0200 Subject: [PATCH 09/16] DX: rename UserScopeFilter to CreatorScopeFilter --- .../{UserScopeFilter.php => CreatorScopeFilter.php} | 6 +++--- ...UserScopeFilterTest.php => CreatorScopeFilterTest.php} | 8 ++++---- .../ChillActivityBundle/config/services/export.yaml | 4 +++- 3 files changed, 10 insertions(+), 8 deletions(-) rename src/Bundle/ChillActivityBundle/Export/Filter/{UserScopeFilter.php => CreatorScopeFilter.php} (93%) rename src/Bundle/ChillActivityBundle/Tests/Export/Filter/{UserScopeFilterTest.php => CreatorScopeFilterTest.php} (86%) diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/UserScopeFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/CreatorScopeFilter.php similarity index 93% rename from src/Bundle/ChillActivityBundle/Export/Filter/UserScopeFilter.php rename to src/Bundle/ChillActivityBundle/Export/Filter/CreatorScopeFilter.php index d205e2d30..e5da96554 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/UserScopeFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/CreatorScopeFilter.php @@ -21,9 +21,9 @@ use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\FormBuilderInterface; -class UserScopeFilter implements FilterInterface +class CreatorScopeFilter implements FilterInterface { - private const PREFIX = 'acp_act_filter_user_scope'; // creator ? cfr translation + private const PREFIX = 'acp_act_filter_creator_scope'; public function __construct( private readonly TranslatableStringHelper $translatableStringHelper @@ -39,7 +39,7 @@ class UserScopeFilter implements FilterInterface $p = self::PREFIX; $qb - ->leftJoin('activity.user', "{$p}_user") // createdBy ? cfr translation + ->leftJoin('activity.createdBy', "{$p}_user") ->leftJoin( UserScopeHistory::class, "{$p}_history", diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Filter/UserScopeFilterTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Filter/CreatorScopeFilterTest.php similarity index 86% rename from src/Bundle/ChillActivityBundle/Tests/Export/Filter/UserScopeFilterTest.php rename to src/Bundle/ChillActivityBundle/Tests/Export/Filter/CreatorScopeFilterTest.php index 858931327..bf11b0320 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Filter/UserScopeFilterTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Filter/CreatorScopeFilterTest.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Tests\Export\Filter; use Chill\ActivityBundle\Entity\Activity; -use Chill\ActivityBundle\Export\Filter\UserScopeFilter; +use Chill\ActivityBundle\Export\Filter\CreatorScopeFilter; use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Test\Export\AbstractFilterTest; use Doctrine\ORM\EntityManagerInterface; @@ -22,15 +22,15 @@ use Doctrine\ORM\EntityManagerInterface; * * @coversNothing */ -final class UserScopeFilterTest extends AbstractFilterTest +final class CreatorScopeFilterTest extends AbstractFilterTest { - private UserScopeFilter $filter; + private CreatorScopeFilter $filter; protected function setUp(): void { self::bootKernel(); - $this->filter = self::$container->get(UserScopeFilter::class); + $this->filter = self::$container->get(CreatorScopeFilter::class); } public function getFilter() diff --git a/src/Bundle/ChillActivityBundle/config/services/export.yaml b/src/Bundle/ChillActivityBundle/config/services/export.yaml index 24f10d399..6ce5b1d72 100644 --- a/src/Bundle/ChillActivityBundle/config/services/export.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/export.yaml @@ -109,8 +109,10 @@ services: tags: - { name: chill.export_filter, alias: 'activity_user_filter' } - Chill\ActivityBundle\Export\Filter\UserScopeFilter: + Chill\ActivityBundle\Export\Filter\CreatorScopeFilter: tags: + # WARNING: for backward compatibility reason, the alias is named with userscope. Changing this will + # affect all saved exports (unless we write a migration for that) - { name: chill.export_filter, alias: 'activity_userscope_filter' } Chill\ActivityBundle\Export\Filter\UsersJobFilter: From 36b0844e796f87815a25be16b4749c4734f7fd29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 24 Oct 2023 14:17:28 +0200 Subject: [PATCH 10/16] Fix issue with duration aggregator as month --- .../AccompanyingCourseAggregators/DurationAggregator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/DurationAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/DurationAggregator.php index 5d0b0e87f..f5dc99115 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/DurationAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/DurationAggregator.php @@ -38,7 +38,7 @@ final readonly class DurationAggregator implements AggregatorInterface match ($data['precision']) { 'day' => $qb->addSelect('(COALESCE(acp.closingDate, :now) - acp.openingDate) AS duration_aggregator'), 'week' => $qb->addSelect('(COALESCE(acp.closingDate, :now) - acp.openingDate) / 7 AS duration_aggregator'), - 'month' => $qb->addSelect('(EXTRACT (MONTH FROM AGE(COALESCE(acp.closingDate, :now), acp.openingDate)) * 12 + + 'month' => $qb->addSelect('(EXTRACT (YEAR FROM AGE(COALESCE(acp.closingDate, :now), acp.openingDate)) * 12 + EXTRACT (MONTH FROM AGE(COALESCE(acp.closingDate, :now), acp.openingDate))) AS duration_aggregator'), default => throw new \LogicException('precision not supported: '.$data['precision']), }; From 54ae17a8d25705697f3308b39ca15d0af0ebe3c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 24 Oct 2023 14:17:51 +0200 Subject: [PATCH 11/16] Fix label on some filters --- .../Export/Filter/SentReceivedFilter.php | 5 +++-- .../ChillActivityBundle/translations/messages.fr.yml | 8 ++++++-- src/Bundle/ChillPersonBundle/translations/messages.fr.yml | 8 ++++---- .../ChillThirdPartyBundle/translations/messages.fr.yml | 2 +- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/SentReceivedFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/SentReceivedFilter.php index 640f33592..3011627e8 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/SentReceivedFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/SentReceivedFilter.php @@ -23,8 +23,8 @@ use Symfony\Contracts\Translation\TranslatorInterface; class SentReceivedFilter implements FilterInterface { private const CHOICES = [ - 'is sent' => Activity::SENTRECEIVED_SENT, - 'is received' => Activity::SENTRECEIVED_RECEIVED, + 'export.filter.activity.by_sent_received.is sent' => Activity::SENTRECEIVED_SENT, + 'export.filter.activity.by_sent_received.is received' => Activity::SENTRECEIVED_RECEIVED, ]; private const DEFAULT_CHOICE = Activity::SENTRECEIVED_SENT; @@ -64,6 +64,7 @@ class SentReceivedFilter implements FilterInterface 'multiple' => false, 'expanded' => true, 'empty_data' => self::DEFAULT_CHOICE, + 'label' => 'export.filter.activity.by_sent_received.Sent or received', ]); } diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index a7112b534..7bb62435f 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -275,7 +275,7 @@ Filter activity by linked socialaction: Filtrer les échanges par action liée 'Filtered activity by linked socialaction: only %actions%': "Filtré par action liée: uniquement %actions%" Filter activity by linked socialissue: Filtrer les échanges par problématique liée 'Filtered activity by linked socialissue: only %issues%': "Filtré par problématique liée: uniquement %issues%" -Filter activity by user: Filtrer les échanges par créateur +Filter activity by user: Filtrer les échanges par utilisateur principal Filter activity by users: Filtrer les échanges par utilisateur participant Filter activity by creator: Filtrer les échanges par créateur de l'échange 'Filtered activity by user: only %users%': "Filtré par référent: uniquement %users%" @@ -359,7 +359,7 @@ export: Filter by users job: Filtrer les échanges par métier d'au moins un utilisateur participant 'Filtered activity by users job: only %jobs%': 'Filtré par métier d''au moins un utilisateur participant: seulement %jobs%' by_users_scope: - Filter by users scope: Filtrer les échanges par services d'au moins un utilisateur participant + Filter by users scope: Filtrer les échanges par service d'au moins un utilisateur participant 'Filtered activity by users scope: only %scopes%': 'Filtré par service d''au moins un utilisateur participant: seulement %scopes%' course_having_activity_between_date: Title: Filtrer les parcours ayant reçu un échange entre deux dates @@ -381,6 +381,10 @@ export: Filter activity by persons: Filtrer les échanges par usager participant 'Filtered activity by persons: only %persons%': 'Échanges filtrés par usagers participants: seulement %persons%' persons taking part on the activity: Usagers participants à l'échange + by_sent_received: + Sent or received: Envoyé ou reçu + is sent: envoyé + is received: reçu aggregator: acp: diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 66aecff1f..f2a90c31f 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -505,10 +505,10 @@ Accepted origins: Origines "Filtered by origins: only %origins%": "Filtré par origine du parcours: uniquement %origins%" Group by origin: Grouper les parcours par origine du parcours -Filter by closing motive: Filtrer les parcours par motif de fermeture +Filter by closing motive: Filtrer les parcours par motif de clôture Accepted closingmotives: Motifs de clôture "Filtered by closingmotive: only %closingmotives%": "Filtré par motif de clôture: uniquement %closingmotives%" -Group by closing motive: Grouper les parcours par motif de fermeture +Group by closing motive: Grouper les parcours par motif de clôture Filter by administrative location: Filtrer les parcours par localisation administrative Accepted locations: Localisations administratives @@ -516,7 +516,7 @@ Administrative location: Localisation administrative "Filtered by administratives locations: only %locations%": "Filtré par localisation administrative: uniquement %locations%" Group by administrative location: Grouper les parcours par localisation administrative -Filter by requestor: Filtrer les parcours selon la présence du demandeur au sein des usagers concernés +Filter by requestor: Filtrer les parcours selon la nature du demandeur Accepted choices: '' is person concerned: Le demandeur est un usager concerné is other person: Le demandeur est un usager, mais n'est pas concerné @@ -1226,7 +1226,7 @@ export: referrer: Référent referrerSince: Référent depuis le locationIsPerson: Parcours localisé auprès d'un usager concerné - locationIsTemp: Parcours avec une localisation temporaire + locationIsTemp: Parcours avec une localisation temporaire ou auprès d'un usager locationPersonName: Usager auprès duquel le parcours est localisé locationPersonId: Identifiant de l'usager auprès duquel le parcours est localisé acpaddress_fieldscountry: Pays de l'adresse diff --git a/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml b/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml index 2bb17cca4..b6a568249 100644 --- a/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml @@ -131,5 +131,5 @@ export: Filtered by person\'s who have a residential address located at a thirdparty of type %thirparty_type%: Uniquement les usagers qui ont une addresse de résidence chez un tiers de catégorie %thirdparty_type% is thirdparty: Le demandeur est un tiers -Filter by person's who have a residential address located at a thirdparty of type: Filtrer les usagers qui ont une addresse de résidence chez un tiers de catégorie "xxx" +Filter by person's who have a residential address located at a thirdparty of type: Filtrer les usagers qui ont une addresse de résidence chez un tiers "Filtered by person's who have a residential address located at a thirdparty of type %thirdparty_type% and valid on %date_calc%": "Uniquement les usagers qui ont une addresse de résidence chez un tiers de catégorie %thirdparty_type% et valide sur la date %date_calc%" From e635b73256fb2f9738f7ad17521905908918291a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 24 Oct 2023 14:18:00 +0200 Subject: [PATCH 12/16] DX: mark a class as final --- .../AccompanyingCourseFilters/UserWorkingOnCourseFilter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserWorkingOnCourseFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserWorkingOnCourseFilter.php index e73ef234a..42bb7dea3 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserWorkingOnCourseFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserWorkingOnCourseFilter.php @@ -28,7 +28,7 @@ use Symfony\Component\Form\FormBuilderInterface; * * Makes use of AccompanyingPeriodInfo */ -readonly class UserWorkingOnCourseFilter implements FilterInterface +final readonly class UserWorkingOnCourseFilter implements FilterInterface { public function __construct( private UserRender $userRender, From e21fe70b75cc0edd70f8dfc32b3c7f282714a812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 24 Oct 2023 15:50:47 +0200 Subject: [PATCH 13/16] Release: version 2.10.0 --- .changes/unreleased/Feature-20231018-113825.yaml | 6 ------ .changes/unreleased/Feature-20231018-133203.yaml | 6 ------ .changes/unreleased/Feature-20231018-160235.yaml | 6 ------ .changes/unreleased/Feature-20231018-164927.yaml | 6 ------ .changes/unreleased/Feature-20231019-140357.yaml | 5 ----- .changes/unreleased/Feature-20231019-171900.yaml | 6 ------ .changes/unreleased/Fixed-20231019-114350.yaml | 6 ------ .changes/v2.10.0.md | 10 ++++++++++ 8 files changed, 10 insertions(+), 41 deletions(-) delete mode 100644 .changes/unreleased/Feature-20231018-113825.yaml delete mode 100644 .changes/unreleased/Feature-20231018-133203.yaml delete mode 100644 .changes/unreleased/Feature-20231018-160235.yaml delete mode 100644 .changes/unreleased/Feature-20231018-164927.yaml delete mode 100644 .changes/unreleased/Feature-20231019-140357.yaml delete mode 100644 .changes/unreleased/Feature-20231019-171900.yaml delete mode 100644 .changes/unreleased/Fixed-20231019-114350.yaml create mode 100644 .changes/v2.10.0.md diff --git a/.changes/unreleased/Feature-20231018-113825.yaml b/.changes/unreleased/Feature-20231018-113825.yaml deleted file mode 100644 index f8922b356..000000000 --- a/.changes/unreleased/Feature-20231018-113825.yaml +++ /dev/null @@ -1,6 +0,0 @@ -kind: Feature -body: '[export] Add a filter "grouping accompanying period by opening date" and "trouping - accompanying period by closing date"' -time: 2023-10-18T11:38:25.80362952+02:00 -custom: - Issue: "172" diff --git a/.changes/unreleased/Feature-20231018-133203.yaml b/.changes/unreleased/Feature-20231018-133203.yaml deleted file mode 100644 index f839ebcf3..000000000 --- a/.changes/unreleased/Feature-20231018-133203.yaml +++ /dev/null @@ -1,6 +0,0 @@ -kind: Feature -body: '[export] add a filter and aggregator on accompanying period work: group/filter - by handling third party' -time: 2023-10-18T13:32:03.565201495+02:00 -custom: - Issue: "172" diff --git a/.changes/unreleased/Feature-20231018-160235.yaml b/.changes/unreleased/Feature-20231018-160235.yaml deleted file mode 100644 index 87fe1de0c..000000000 --- a/.changes/unreleased/Feature-20231018-160235.yaml +++ /dev/null @@ -1,6 +0,0 @@ -kind: Feature -body: '[export] add a filter and aggregator on activites: group/filter activities - by people participating to the exchange' -time: 2023-10-18T16:02:35.99265091+02:00 -custom: - Issue: "172" diff --git a/.changes/unreleased/Feature-20231018-164927.yaml b/.changes/unreleased/Feature-20231018-164927.yaml deleted file mode 100644 index cf0be6fef..000000000 --- a/.changes/unreleased/Feature-20231018-164927.yaml +++ /dev/null @@ -1,6 +0,0 @@ -kind: Feature -body: '[export] add a grouping on accompanying period export: group by activity type - associated to at least one activity within the accompanying period' -time: 2023-10-18T16:49:27.567166953+02:00 -custom: - Issue: "172" diff --git a/.changes/unreleased/Feature-20231019-140357.yaml b/.changes/unreleased/Feature-20231019-140357.yaml deleted file mode 100644 index 2ef33a4a5..000000000 --- a/.changes/unreleased/Feature-20231019-140357.yaml +++ /dev/null @@ -1,5 +0,0 @@ -kind: Feature -body: '[export] sort filters and aggregators by title' -time: 2023-10-19T14:03:57.435338127+02:00 -custom: - Issue: "" diff --git a/.changes/unreleased/Feature-20231019-171900.yaml b/.changes/unreleased/Feature-20231019-171900.yaml deleted file mode 100644 index d8ee98cdd..000000000 --- a/.changes/unreleased/Feature-20231019-171900.yaml +++ /dev/null @@ -1,6 +0,0 @@ -kind: Feature -body: '[export] create a parameter that will force to skip the filtering by center - (ACL) when generating an export' -time: 2023-10-19T17:19:00.51809407+02:00 -custom: - Issue: "179" diff --git a/.changes/unreleased/Fixed-20231019-114350.yaml b/.changes/unreleased/Fixed-20231019-114350.yaml deleted file mode 100644 index dbb6b4166..000000000 --- a/.changes/unreleased/Fixed-20231019-114350.yaml +++ /dev/null @@ -1,6 +0,0 @@ -kind: Fixed -body: '[export] fix date range selection on filter and grouping "by status of the - course at date", on accompanying periods' -time: 2023-10-19T11:43:50.455829748+02:00 -custom: - Issue: "177" diff --git a/.changes/v2.10.0.md b/.changes/v2.10.0.md new file mode 100644 index 000000000..56c384739 --- /dev/null +++ b/.changes/v2.10.0.md @@ -0,0 +1,10 @@ +## v2.10.0 - 2023-10-24 +### Feature +* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] Add a filter "grouping accompanying period by opening date" and "trouping accompanying period by closing date" +* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a filter and aggregator on accompanying period work: group/filter by handling third party +* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a filter and aggregator on activites: group/filter activities by people participating to the exchange +* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a grouping on accompanying period export: group by activity type associated to at least one activity within the accompanying period +* [export] sort filters and aggregators by title +* ([#179](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/179)) [export] create a parameter that will force to skip the filtering by center (ACL) when generating an export +### Fixed +* ([#177](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/177)) [export] fix date range selection on filter and grouping "by status of the course at date", on accompanying periods From 4bc1de01d654a588f9728f92b9f3dea5b193306b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 24 Oct 2023 18:56:42 +0200 Subject: [PATCH 14/16] Release: version 2.10.0: fix typos and French translation --- .changes/v2.10.0.md | 24 +++++++++++++++++------- CHANGELOG.md | 21 +++++++++++++++++++++ 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/.changes/v2.10.0.md b/.changes/v2.10.0.md index 56c384739..54f2e8cfe 100644 --- a/.changes/v2.10.0.md +++ b/.changes/v2.10.0.md @@ -1,10 +1,20 @@ ## v2.10.0 - 2023-10-24 ### Feature -* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] Add a filter "grouping accompanying period by opening date" and "trouping accompanying period by closing date" -* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a filter and aggregator on accompanying period work: group/filter by handling third party -* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a filter and aggregator on activites: group/filter activities by people participating to the exchange -* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a grouping on accompanying period export: group by activity type associated to at least one activity within the accompanying period -* [export] sort filters and aggregators by title -* ([#179](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/179)) [export] create a parameter that will force to skip the filtering by center (ACL) when generating an export +* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] Add a filter "grouping accompanying period by opening date" and "grouping accompanying period by closing date" +* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a filter and aggregator on accompanying period work: group/filter by handling third party +* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a filter and aggregator on activites: group/filter activities by people participating to the activities +* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a grouping on accompanying period export: group by activity type associated to at least one activity within the accompanying period +* [export] sort filters and aggregators by title +* ([#179](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/179)) [export] create a parameter that will force to skip the filtering by center (ACL) when generating an export ### Fixed -* ([#177](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/177)) [export] fix date range selection on filter and grouping "by status of the course at date", on accompanying periods +* ([#177](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/177)) [export] fix date range selection on filter and grouping "by status of the course at date", on accompanying periods + +### Résumé francophone des changements + +- Ajout d'un regroupement sur les parcours: par date de cloture et d'ouverture; +- Ajouter d'un filtre et regroupement par tiers traitant sur les actions d'accompagnement; +- ajout d'un filtre et regroupement par usager participant sur les échanges +- ajout d'un regroupement: par type d'activité associé au parcours; +- trie les filtre et regroupements par ordre alphabétique dans els exports +- ajout d'un paramètre qui permet de désactiver le filtre par centre dans les exports +- correction de l'interface de date dans les filtres et regroupements "par statut du parcours à la date" diff --git a/CHANGELOG.md b/CHANGELOG.md index 298a9af0d..e21aa45b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,27 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html), and is generated by [Changie](https://github.com/miniscruff/changie). +## v2.10.0 - 2023-10-24 +### Feature +* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] Add a filter "grouping accompanying period by opening date" and "grouping accompanying period by closing date" +* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a filter and aggregator on accompanying period work: group/filter by handling third party +* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a filter and aggregator on activites: group/filter activities by people participating to the activities +* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a grouping on accompanying period export: group by activity type associated to at least one activity within the accompanying period +* [export] sort filters and aggregators by title +* ([#179](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/179)) [export] create a parameter that will force to skip the filtering by center (ACL) when generating an export +### Fixed +* ([#177](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/177)) [export] fix date range selection on filter and grouping "by status of the course at date", on accompanying periods + +### Résumé francophone des changements + +- Ajout d'un regroupement sur les parcours: par date de cloture et d'ouverture; +- Ajouter d'un filtre et regroupement par tiers traitant sur les actions d'accompagnement; +- ajout d'un filtre et regroupement par usager participant sur les échanges +- ajout d'un regroupement: par type d'activité associé au parcours; +- trie les filtre et regroupements par ordre alphabétique dans els exports +- ajout d'un paramètre qui permet de désactiver le filtre par centre dans les exports +- correction de l'interface de date dans les filtres et regroupements "par statut du parcours à la date" + ## v2.9.2 - 2023-10-17 ### Fixed * Fix possible null values in string's entities From 2c50f484f0bf775d16a7b83c65248d1b03318b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 24 Oct 2023 20:46:23 +0200 Subject: [PATCH 15/16] Fix export controller when generating an export without any data in session --- src/Bundle/ChillMainBundle/Controller/ExportController.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Controller/ExportController.php b/src/Bundle/ChillMainBundle/Controller/ExportController.php index 3aaac9a68..190d5f1bf 100644 --- a/src/Bundle/ChillMainBundle/Controller/ExportController.php +++ b/src/Bundle/ChillMainBundle/Controller/ExportController.php @@ -281,7 +281,7 @@ class ExportController extends AbstractController $options = match ($step) { 'export', 'generate_export' => [ 'export_alias' => $alias, - 'picked_centers' => $exportManager->getPickedCenters($data['centers']), + 'picked_centers' => $exportManager->getPickedCenters($data['centers'] ?? []), ], 'formatter', 'generate_formatter' => [ 'export_alias' => $alias, @@ -339,9 +339,9 @@ class ExportController extends AbstractController $exportManager = $this->exportManager; // check we have data from the previous step (export step) - $data = $this->session->get('centers_step', null); + $data = $this->session->get('centers_step', []); - if (null === $data) { + if (null === $data && true === $this->filterStatsByCenters) { return $this->redirectToRoute('chill_main_export_new', [ 'step' => $this->getNextStep('export', $export, true), 'alias' => $alias, From bc6c3a1089dcbbcaaabb2b8dc607720640108317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 24 Oct 2023 20:52:46 +0200 Subject: [PATCH 16/16] Release: 2.10.1 --- .changes/v2.10.1.md | 3 +++ CHANGELOG.md | 4 ++++ 2 files changed, 7 insertions(+) create mode 100644 .changes/v2.10.1.md diff --git a/.changes/v2.10.1.md b/.changes/v2.10.1.md new file mode 100644 index 000000000..562b90a2c --- /dev/null +++ b/.changes/v2.10.1.md @@ -0,0 +1,3 @@ +## v2.10.1 - 2023-10-24 +### Fixed +* Fix export controller when generating an export without any data in session diff --git a/CHANGELOG.md b/CHANGELOG.md index e21aa45b3..29bb7ba59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html), and is generated by [Changie](https://github.com/miniscruff/changie). +## v2.10.1 - 2023-10-24 +### Fixed +* Fix export controller when generating an export without any data in session + ## v2.10.0 - 2023-10-24 ### Feature * ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] Add a filter "grouping accompanying period by opening date" and "grouping accompanying period by closing date"