diff --git a/.changes/unreleased/Fixed-20230928-143246.yaml b/.changes/unreleased/Fixed-20230928-143246.yaml new file mode 100644 index 000000000..f0f756a22 --- /dev/null +++ b/.changes/unreleased/Fixed-20230928-143246.yaml @@ -0,0 +1,5 @@ +kind: Fixed +body: Fix the filters and aggregators on exports "count peoples" +time: 2023-09-28T14:32:46.696092741+02:00 +custom: + Issue: "163" diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/PersonHavingActivityBetweenDateFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/PersonHavingActivityBetweenDateFilter.php index 490b5fd0c..bd010e1ff 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/PersonHavingActivityBetweenDateFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/PersonHavingActivityBetweenDateFilter.php @@ -17,6 +17,9 @@ use Chill\ActivityBundle\Repository\ActivityReasonRepository; use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\Export\FilterType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Export\Declarations; @@ -44,9 +47,10 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt protected TranslatorInterface $translator; public function __construct( - TranslatableStringHelper $translatableStringHelper, - ActivityReasonRepository $activityReasonRepository, - TranslatorInterface $translator + TranslatableStringHelper $translatableStringHelper, + ActivityReasonRepository $activityReasonRepository, + TranslatorInterface $translator, + private readonly RollingDateConverterInterface $rollingDateConverter, ) { $this->translatableStringHelper = $translatableStringHelper; $this->activityReasonRepository = $activityReasonRepository; @@ -62,131 +66,93 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt { // create a subquery for activity $sqb = $qb->getEntityManager()->createQueryBuilder(); - $sqb->select('person_person_having_activity.id') + $sqb->select('1') ->from(Activity::class, 'activity_person_having_activity') - ->join('activity_person_having_activity.person', 'person_person_having_activity'); + ->leftJoin('activity_person_having_activity.person', 'person_person_having_activity'); // add clause between date $sqb->where('activity_person_having_activity.date BETWEEN ' . ':person_having_activity_between_date_from' . ' AND ' - . ':person_having_activity_between_date_to'); + . ':person_having_activity_between_date_to' + . ' AND ' + . '(person_person_having_activity.id = person.id OR person MEMBER OF activity_person_having_activity.persons)'); - // add clause activity reason - $sqb->join('activity_person_having_activity.reasons', 'reasons_person_having_activity'); + if (isset($data['reasons']) && [] !== $data['reasons']) { + // add clause activity reason + $sqb->join('activity_person_having_activity.reasons', 'reasons_person_having_activity'); - $sqb->andWhere( - $sqb->expr()->in( - 'reasons_person_having_activity', - ':person_having_activity_reasons' - ) - ); + $sqb->andWhere( + $sqb->expr()->in( + 'reasons_person_having_activity', + ':person_having_activity_reasons' + ) + ); - $where = $qb->getDQLPart('where'); - $clause = $qb->expr()->in('person.id', $sqb->getDQL()); - - if ($where instanceof Expr\Andx) { - $where->add($clause); - } else { - $where = $qb->expr()->andX($clause); + $qb->setParameter('person_having_activity_reasons', $data['reasons']); } - $qb->add('where', $where); + $qb->andWhere( + $qb->expr()->exists($sqb->getDQL()) + ); + $qb->setParameter( 'person_having_activity_between_date_from', - $data['date_from'] + $this->rollingDateConverter->convert($data['date_from_rolling']) ); $qb->setParameter( 'person_having_activity_between_date_to', - $data['date_to'] + $this->rollingDateConverter->convert($data['date_to_rolling']) ); - $qb->setParameter('person_having_activity_reasons', $data['reasons']); } public function applyOn(): string { - return Declarations::PERSON_IMPLIED_IN; + return Declarations::PERSON_TYPE; } public function buildForm(FormBuilderInterface $builder) { - $builder->add('date_from', DateType::class, [ - 'label' => 'Implied in an activity after this date', - 'attr' => ['class' => 'datepicker'], - 'widget' => 'single_text', - 'format' => 'dd-MM-yyyy', + $builder->add('date_from_rolling', PickRollingDateType::class, [ + 'label' => 'export.filter.activity.person_between_dates.Implied in an activity after this date', ]); - $builder->add('date_to', DateType::class, [ - 'label' => 'Implied in an activity before this date', - 'attr' => ['class' => 'datepicker'], - 'widget' => 'single_text', - 'format' => 'dd-MM-yyyy', + $builder->add('date_to_rolling', PickRollingDateType::class, [ + 'label' => 'export.filter.activity.person_between_dates.Implied in an activity before this date', ]); - $builder->add('reasons', EntityType::class, [ - 'class' => ActivityReason::class, - 'choice_label' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getName()), - 'group_by' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getCategory()->getName()), - 'multiple' => true, - 'expanded' => false, - 'label' => 'Activity reasons for those activities', - ]); - - $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { - /** @var FormInterface $filterForm */ - $filterForm = $event->getForm()->getParent(); - $enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData(); - - if (true === $enabled) { - // if the filter is enabled, add some validation - $form = $event->getForm(); - $date_from = $form->get('date_from')->getData(); - $date_to = $form->get('date_to')->getData(); - - // check that fields are not empty - if (null === $date_from) { - $form->get('date_from')->addError(new FormError( - $this->translator->trans('This field ' - . 'should not be empty') - )); - } - - if (null === $date_to) { - $form->get('date_to')->addError(new FormError( - $this->translator->trans('This field ' - . 'should not be empty') - )); - } - - // check that date_from is before date_to - if ( - (null !== $date_from && null !== $date_to) - && $date_from >= $date_to - ) { - $form->get('date_to')->addError(new FormError( - $this->translator->trans('This date ' - . 'should be after the date given in "Implied in an ' - . 'activity after this date" field') - )); - } - } - }); + if ([] !== $reasons = $this->activityReasonRepository->findAll()) { + $builder->add('reasons', EntityType::class, [ + 'class' => ActivityReason::class, + 'choices' => $reasons, + 'choice_label' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getName()), + 'group_by' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getCategory()->getName()), + 'multiple' => true, + 'expanded' => false, + 'label' => 'export.filter.activity.person_between_dates.Activity reasons for those activities', + 'help' => 'export.filter.activity.person_between_dates.if no reasons', + ]); + } } public function getFormDefaultData(): array { - return ['date_from' => new DateTime(), 'date_to' => new DateTime(), 'reasons' => $this->activityReasonRepository->findAll()]; + return [ + 'date_from_rolling' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), + 'date_to_rolling' => new RollingDate(RollingDate::T_TODAY), + 'reasons' => [], + ]; } public function describeAction($data, $format = 'string') { return [ - 'Filtered by person having an activity between %date_from% and ' - . '%date_to% with reasons %reasons_name%', + [] === $data['reasons'] ? + 'export.filter.person_between_dates.describe_action_with_no_subject' + : 'export.filter.person_between_dates.describe_action_with_subject', [ - '%date_from%' => $data['date_from']->format('d-m-Y'), - '%date_to%' => $data['date_to']->format('d-m-Y'), - '%reasons_name%' => implode( + 'date_from' => $this->rollingDateConverter->convert($data['date_from_rolling']), + 'date_to' => $this->rollingDateConverter->convert($data['date_to_rolling']), + 'reasons' => implode( ', ', array_map( fn (ActivityReason $r): string => '"' . $this->translatableStringHelper->localize($r->getName()) . '"', @@ -199,13 +165,15 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt public function getTitle() { - return 'Filter by person having an activity in a period'; + return 'export.filter.activity.person_between_dates.title'; } public function validateForm($data, ExecutionContextInterface $context) { - if (null === $data['reasons'] || count($data['reasons']) === 0) { - $context->buildViolation('At least one reason must be chosen') + if ($this->rollingDateConverter->convert($data['date_from_rolling']) + >= $this->rollingDateConverter->convert($data['date_to_rolling'])) { + $context->buildViolation('export.filter.activity.person_between_dates.date mismatch') + ->setTranslationDomain('messages') ->addViolation(); } } diff --git a/src/Bundle/ChillActivityBundle/translations/messages+intl-icu.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages+intl-icu.fr.yml index ab3b963ab..7c02e29c6 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages+intl-icu.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages+intl-icu.fr.yml @@ -3,3 +3,9 @@ export: activity: course_having_activity_between_date: Only course having an activity between from and to: Seulement les parcours ayant reçu au moins un échange entre le {from, date, short} et le {to, date, short} + person_between_dates: + describe_action_with_no_subject: >- + Filtré par personne ayant eu un échange entre le {date_from, date} et le {date_to, date} + describe_action_with_subject: >- + Filtré par personne ayant eu un échange entre le {date_from, date} et le {date_to, date}, et un de ces sujets choisis: {reasons} + diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index ef2494f57..b2ec70623 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -255,11 +255,6 @@ Activities before this date: Échanges avant cette date "Filtered by date of activity: only between %date_from% and %date_to%": "Filtré par date de l'échange: uniquement entre %date_from% et %date_to%" This date should be after the date given in "Implied in an activity after this date" field: Cette date devrait être postérieure à la date donnée dans le champ "échanges après cette date" -Filtered by person having an activity in a period: Uniquement les usagers ayant eu un échange dans la période donnée -Implied in an activity after this date: Impliqué dans un échange après cette date -Implied in an activity before this date: Impliqué dans un échange avant cette date -Filtered by person having an activity between %date_from% and %date_to% with reasons %reasons_name%: Filtré par usager associées à un échange entre %date_from% et %date_to% avec les sujets %reasons_name% -Activity reasons for those activities: Sujets de ces échanges Filter by activity type: Filtrer les échanges par type @@ -379,7 +374,13 @@ export: Receiving an activity before: Ayant reçu un échange avant le acp_by_activity_type: 'acp_containing_at_least_one_%activitytypes%': 'Parcours filtrés: uniquement ceux qui contiennent au moins un échange d''un des types suivants: %activitytypes%' - + person_between_dates: + Implied in an activity after this date: Impliqué dans un échange après cette date + 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 + date mismatch: La date de fin de la période doit être supérieure à la date du début aggregator: activity: diff --git a/src/Bundle/ChillPersonBundle/Export/Declarations.php b/src/Bundle/ChillPersonBundle/Export/Declarations.php index 507f02041..47e58aead 100644 --- a/src/Bundle/ChillPersonBundle/Export/Declarations.php +++ b/src/Bundle/ChillPersonBundle/Export/Declarations.php @@ -22,6 +22,9 @@ abstract class Declarations public const HOUSEHOLD_TYPE = 'household'; + /** + * @deprecated consider using the PERSON_TYPE instead + */ public const PERSON_IMPLIED_IN = 'person_implied_in'; public const PERSON_TYPE = 'person'; diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php index c1800395c..beb4daa89 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php @@ -120,9 +120,7 @@ class CountPerson implements ExportInterface, GroupedExportInterface public function supportsModifiers() { return [ - 'abcde', - //Declarations::PERSON_TYPE, - //Declarations::PERSON_IMPLIED_IN, + Declarations::PERSON_TYPE, ]; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php index 467bc02ea..51bc731e8 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php @@ -266,7 +266,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou public function supportsModifiers() { - return [Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN]; + return [Declarations::PERSON_TYPE]; } public function validateForm($data, ExecutionContextInterface $context) diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonHavingAccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonHavingAccompanyingPeriod.php index 408d0b3af..f63907391 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonHavingAccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonHavingAccompanyingPeriod.php @@ -205,7 +205,7 @@ class ListPersonHavingAccompanyingPeriod implements ExportElementValidatedInterf public function supportsModifiers() { - return [Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN, Declarations::ACP_TYPE]; + return [Declarations::PERSON_TYPE, Declarations::ACP_TYPE]; } public function validateForm($data, ExecutionContextInterface $context) diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriodDetails.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriodDetails.php index 66d4d1530..572e75993 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriodDetails.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriodDetails.php @@ -149,6 +149,6 @@ final readonly class ListPersonWithAccompanyingPeriodDetails implements ListInte public function supportsModifiers() { - return [Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN, Declarations::ACP_TYPE]; + return [Declarations::PERSON_TYPE, Declarations::ACP_TYPE]; } } diff --git a/src/Bundle/ChillReportBundle/Export/Export/ReportList.php b/src/Bundle/ChillReportBundle/Export/Export/ReportList.php index 9d99b7e62..549548691 100644 --- a/src/Bundle/ChillReportBundle/Export/Export/ReportList.php +++ b/src/Bundle/ChillReportBundle/Export/Export/ReportList.php @@ -463,7 +463,7 @@ class ReportList implements ExportElementValidatedInterface, ListInterface public function supportsModifiers() { - return [Declarations::PERSON_IMPLIED_IN, Declarations::PERSON_TYPE, 'report']; + return [Declarations::PERSON_TYPE, 'report']; } public function validateForm($data, ExecutionContextInterface $context)