Re-associate filters for export "count persons"

This commit is contained in:
Julien Fastré 2023-09-28 14:32:58 +02:00
parent 981be7b363
commit 9c436d5c69
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
10 changed files with 87 additions and 106 deletions

View File

@ -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"

View File

@ -17,6 +17,9 @@ use Chill\ActivityBundle\Repository\ActivityReasonRepository;
use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\Export\FilterType; 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\TranslatableStringHelper;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Export\Declarations;
@ -44,9 +47,10 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt
protected TranslatorInterface $translator; protected TranslatorInterface $translator;
public function __construct( public function __construct(
TranslatableStringHelper $translatableStringHelper, TranslatableStringHelper $translatableStringHelper,
ActivityReasonRepository $activityReasonRepository, ActivityReasonRepository $activityReasonRepository,
TranslatorInterface $translator TranslatorInterface $translator,
private readonly RollingDateConverterInterface $rollingDateConverter,
) { ) {
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
$this->activityReasonRepository = $activityReasonRepository; $this->activityReasonRepository = $activityReasonRepository;
@ -62,131 +66,93 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt
{ {
// create a subquery for activity // create a subquery for activity
$sqb = $qb->getEntityManager()->createQueryBuilder(); $sqb = $qb->getEntityManager()->createQueryBuilder();
$sqb->select('person_person_having_activity.id') $sqb->select('1')
->from(Activity::class, 'activity_person_having_activity') ->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 // add clause between date
$sqb->where('activity_person_having_activity.date BETWEEN ' $sqb->where('activity_person_having_activity.date BETWEEN '
. ':person_having_activity_between_date_from' . ':person_having_activity_between_date_from'
. ' AND ' . ' 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 if (isset($data['reasons']) && [] !== $data['reasons']) {
$sqb->join('activity_person_having_activity.reasons', 'reasons_person_having_activity'); // add clause activity reason
$sqb->join('activity_person_having_activity.reasons', 'reasons_person_having_activity');
$sqb->andWhere( $sqb->andWhere(
$sqb->expr()->in( $sqb->expr()->in(
'reasons_person_having_activity', 'reasons_person_having_activity',
':person_having_activity_reasons' ':person_having_activity_reasons'
) )
); );
$where = $qb->getDQLPart('where'); $qb->setParameter('person_having_activity_reasons', $data['reasons']);
$clause = $qb->expr()->in('person.id', $sqb->getDQL());
if ($where instanceof Expr\Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
} }
$qb->add('where', $where); $qb->andWhere(
$qb->expr()->exists($sqb->getDQL())
);
$qb->setParameter( $qb->setParameter(
'person_having_activity_between_date_from', 'person_having_activity_between_date_from',
$data['date_from'] $this->rollingDateConverter->convert($data['date_from_rolling'])
); );
$qb->setParameter( $qb->setParameter(
'person_having_activity_between_date_to', '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 public function applyOn(): string
{ {
return Declarations::PERSON_IMPLIED_IN; return Declarations::PERSON_TYPE;
} }
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('date_from', DateType::class, [ $builder->add('date_from_rolling', PickRollingDateType::class, [
'label' => 'Implied in an activity after this date', 'label' => 'export.filter.activity.person_between_dates.Implied in an activity after this date',
'attr' => ['class' => 'datepicker'],
'widget' => 'single_text',
'format' => 'dd-MM-yyyy',
]); ]);
$builder->add('date_to', DateType::class, [ $builder->add('date_to_rolling', PickRollingDateType::class, [
'label' => 'Implied in an activity before this date', 'label' => 'export.filter.activity.person_between_dates.Implied in an activity before this date',
'attr' => ['class' => 'datepicker'],
'widget' => 'single_text',
'format' => 'dd-MM-yyyy',
]); ]);
$builder->add('reasons', EntityType::class, [ if ([] !== $reasons = $this->activityReasonRepository->findAll()) {
'class' => ActivityReason::class, $builder->add('reasons', EntityType::class, [
'choice_label' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getName()), 'class' => ActivityReason::class,
'group_by' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getCategory()->getName()), 'choices' => $reasons,
'multiple' => true, 'choice_label' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getName()),
'expanded' => false, 'group_by' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getCategory()->getName()),
'label' => 'Activity reasons for those activities', 'multiple' => true,
]); 'expanded' => false,
'label' => 'export.filter.activity.person_between_dates.Activity reasons for those activities',
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { 'help' => 'export.filter.activity.person_between_dates.if no reasons',
/** @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')
));
}
}
});
} }
public function getFormDefaultData(): array 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') public function describeAction($data, $format = 'string')
{ {
return [ return [
'Filtered by person having an activity between %date_from% and ' [] === $data['reasons'] ?
. '%date_to% with reasons %reasons_name%', '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_from' => $this->rollingDateConverter->convert($data['date_from_rolling']),
'%date_to%' => $data['date_to']->format('d-m-Y'), 'date_to' => $this->rollingDateConverter->convert($data['date_to_rolling']),
'%reasons_name%' => implode( 'reasons' => implode(
', ', ', ',
array_map( array_map(
fn (ActivityReason $r): string => '"' . $this->translatableStringHelper->localize($r->getName()) . '"', fn (ActivityReason $r): string => '"' . $this->translatableStringHelper->localize($r->getName()) . '"',
@ -199,13 +165,15 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt
public function getTitle() 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) public function validateForm($data, ExecutionContextInterface $context)
{ {
if (null === $data['reasons'] || count($data['reasons']) === 0) { if ($this->rollingDateConverter->convert($data['date_from_rolling'])
$context->buildViolation('At least one reason must be chosen') >= $this->rollingDateConverter->convert($data['date_to_rolling'])) {
$context->buildViolation('export.filter.activity.person_between_dates.date mismatch')
->setTranslationDomain('messages')
->addViolation(); ->addViolation();
} }
} }

View File

@ -3,3 +3,9 @@ export:
activity: activity:
course_having_activity_between_date: 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} 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}

View File

@ -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%" "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" 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 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 Receiving an activity before: Ayant reçu un échange avant le
acp_by_activity_type: 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%' '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: aggregator:
activity: activity:

View File

@ -22,6 +22,9 @@ abstract class Declarations
public const HOUSEHOLD_TYPE = 'household'; public const HOUSEHOLD_TYPE = 'household';
/**
* @deprecated consider using the PERSON_TYPE instead
*/
public const PERSON_IMPLIED_IN = 'person_implied_in'; public const PERSON_IMPLIED_IN = 'person_implied_in';
public const PERSON_TYPE = 'person'; public const PERSON_TYPE = 'person';

View File

@ -120,9 +120,7 @@ class CountPerson implements ExportInterface, GroupedExportInterface
public function supportsModifiers() public function supportsModifiers()
{ {
return [ return [
'abcde', Declarations::PERSON_TYPE,
//Declarations::PERSON_TYPE,
//Declarations::PERSON_IMPLIED_IN,
]; ];
} }
} }

View File

@ -266,7 +266,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou
public function supportsModifiers() public function supportsModifiers()
{ {
return [Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN]; return [Declarations::PERSON_TYPE];
} }
public function validateForm($data, ExecutionContextInterface $context) public function validateForm($data, ExecutionContextInterface $context)

View File

@ -205,7 +205,7 @@ class ListPersonHavingAccompanyingPeriod implements ExportElementValidatedInterf
public function supportsModifiers() 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) public function validateForm($data, ExecutionContextInterface $context)

View File

@ -149,6 +149,6 @@ final readonly class ListPersonWithAccompanyingPeriodDetails implements ListInte
public function supportsModifiers() public function supportsModifiers()
{ {
return [Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN, Declarations::ACP_TYPE]; return [Declarations::PERSON_TYPE, Declarations::ACP_TYPE];
} }
} }

View File

@ -463,7 +463,7 @@ class ReportList implements ExportElementValidatedInterface, ListInterface
public function supportsModifiers() public function supportsModifiers()
{ {
return [Declarations::PERSON_IMPLIED_IN, Declarations::PERSON_TYPE, 'report']; return [Declarations::PERSON_TYPE, 'report'];
} }
public function validateForm($data, ExecutionContextInterface $context) public function validateForm($data, ExecutionContextInterface $context)