From 31fc7fffe9c7c7db344acf1658120549360e853d Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Tue, 3 Oct 2023 14:19:45 +0200 Subject: [PATCH] [export] fix calendar filters/aggregators + tests: 'at' based on calendar date --- .../Export/Aggregator/JobAggregator.php | 36 +++++++---------- .../Export/Aggregator/ScopeAggregator.php | 39 ++++++++----------- .../Export/Filter/JobFilter.php | 37 +++++++----------- .../Export/Filter/ScopeFilter.php | 29 +++++++------- .../Export/Aggregator/JobAggregatorTest.php | 5 +-- .../Export/Aggregator/ScopeAggregatorTest.php | 5 +-- .../Tests/Export/Filter/JobFilterTest.php | 2 - .../Tests/Export/Filter/ScopeFilterTest.php | 2 - .../translations/messages.fr.yml | 24 ++++++------ 9 files changed, 74 insertions(+), 105 deletions(-) diff --git a/src/Bundle/ChillCalendarBundle/Export/Aggregator/JobAggregator.php b/src/Bundle/ChillCalendarBundle/Export/Aggregator/JobAggregator.php index 6a7d4cf5d..acef258fa 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Aggregator/JobAggregator.php +++ b/src/Bundle/ChillCalendarBundle/Export/Aggregator/JobAggregator.php @@ -14,13 +14,10 @@ namespace Chill\CalendarBundle\Export\Aggregator; use Chill\CalendarBundle\Export\Declarations; use Chill\MainBundle\Entity\User\UserJobHistory; use Chill\MainBundle\Export\AggregatorInterface; -use Chill\MainBundle\Form\Type\PickRollingDateType; use Chill\MainBundle\Repository\UserJobRepository; -use Chill\MainBundle\Service\RollingDate\RollingDate; -use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Closure; -use Doctrine\ORM\Query\Expr; +use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -29,7 +26,6 @@ final readonly class JobAggregator implements AggregatorInterface private const PREFIX = 'cal_agg_job'; public function __construct( - private RollingDateConverterInterface $rollingDateConverter, private UserJobRepository $jobRepository, private TranslatableStringHelper $translatableStringHelper ) {} @@ -44,22 +40,24 @@ final readonly class JobAggregator implements AggregatorInterface $p = self::PREFIX; $qb - ->leftJoin( - 'cal.mainUser', - "{$p}_user" - ) + ->leftJoin('cal.mainUser', "{$p}_user") ->leftJoin( UserJobHistory::class, "{$p}_history", - Expr\Join::WITH, + Join::WITH, $qb->expr()->eq("{$p}_history.user", "{$p}_user") ) - ->andWhere("{$p}_history.startDate <= :{$p}_at AND ({$p}_history.endDate IS NULL OR {$p}_history.endDate > :{$p}_at)") - ->addSelect("IDENTITY({$p}_history.job) AS {$p}_select") - ->setParameter( - "{$p}_at", - $this->rollingDateConverter->convert($data['job_at']) + // job_at based on cal.startDate + ->andWhere( + $qb->expr()->andX( + $qb->expr()->lte("{$p}_history.startDate", "cal.startDate"), + $qb->expr()->orX( + $qb->expr()->isNull("{$p}_history.endDate"), + $qb->expr()->gt("{$p}_history.endDate", "cal.startDate") + ) + ) ) + ->addSelect("IDENTITY({$p}_history.job) AS {$p}_select") ->addGroupBy("{$p}_select"); } @@ -70,15 +68,11 @@ final readonly class JobAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('job_at', PickRollingDateType::class, [ - 'label' => 'export.calendar.agent_job.Calc date', - 'required' => true, - ]); } public function getFormDefaultData(): array { - return ['job_at' => new RollingDate(RollingDate::T_TODAY)]; + return []; } public function getLabels($key, array $values, $data): Closure @@ -109,6 +103,6 @@ final readonly class JobAggregator implements AggregatorInterface public function getTitle(): string { - return 'Group calendars by agent job'; + return 'export.aggregator.calendar.agent_job.Group calendars by agent job'; } } diff --git a/src/Bundle/ChillCalendarBundle/Export/Aggregator/ScopeAggregator.php b/src/Bundle/ChillCalendarBundle/Export/Aggregator/ScopeAggregator.php index f7c71951e..ec1c91dc9 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Aggregator/ScopeAggregator.php +++ b/src/Bundle/ChillCalendarBundle/Export/Aggregator/ScopeAggregator.php @@ -14,24 +14,18 @@ namespace Chill\CalendarBundle\Export\Aggregator; use Chill\CalendarBundle\Export\Declarations; use Chill\MainBundle\Entity\User\UserScopeHistory; use Chill\MainBundle\Export\AggregatorInterface; -use Chill\MainBundle\Form\Type\PickRollingDateType; use Chill\MainBundle\Repository\ScopeRepository; -use Chill\MainBundle\Service\RollingDate\RollingDate; -use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Closure; -use Doctrine\ORM\Query\Expr; +use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Exp; use Symfony\Component\Form\FormBuilderInterface; -use function in_array; final readonly class ScopeAggregator implements AggregatorInterface { private const PREFIX = "cal_agg_scope"; public function __construct( - private RollingDateConverterInterface $rollingDateConverter, private ScopeRepository $scopeRepository, private TranslatableStringHelper $translatableStringHelper ) {} @@ -46,22 +40,24 @@ final readonly class ScopeAggregator implements AggregatorInterface $p = self::PREFIX; $qb - ->leftJoin( - "cal.mainUser", - "{$p}_user" - ) + ->leftJoin("cal.mainUser", "{$p}_user") ->leftJoin( UserScopeHistory::class, "{$p}_history", - Expr\Join::WITH, + Join::WITH, $qb->expr()->eq("{$p}_history.user", "{$p}_user") ) - ->andWhere("{$p}_history.startDate <= :{$p}_at AND ({$p}_history.endDate IS NULL OR {$p}_history.endDate > :{$p}_at)") - ->addSelect("IDENTITY({$p}_history.scope) AS {$p}_select") - ->setParameter( - "{$p}_at", - $this->rollingDateConverter->convert($data['scope_at']) + // scope_at based on cal.startDate + ->andWhere( + $qb->expr()->andX( + $qb->expr()->lte("{$p}_history.startDate", "cal.startDate"), + $qb->expr()->orX( + $qb->expr()->isNull("{$p}_history.endDate"), + $qb->expr()->gt("{$p}_history.endDate", "cal.startDate") + ) + ) ) + ->addSelect("IDENTITY({$p}_history.scope) AS {$p}_select") ->addGroupBy("{$p}_select"); } @@ -72,14 +68,11 @@ final readonly class ScopeAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('scope_at', PickRollingDateType::class, [ - 'label' => 'export.calendar.agent_scope.Calc date', - 'required' => true, - ]); } + public function getFormDefaultData(): array { - return ['scope_at' => new RollingDate(RollingDate::T_TODAY)]; + return []; } public function getLabels($key, array $values, $data): Closure @@ -110,6 +103,6 @@ final readonly class ScopeAggregator implements AggregatorInterface public function getTitle(): string { - return 'Group calendars by agent scope'; + return 'export.aggregator.calendar.agent_scope.Group calendars by agent scope'; } } diff --git a/src/Bundle/ChillCalendarBundle/Export/Filter/JobFilter.php b/src/Bundle/ChillCalendarBundle/Export/Filter/JobFilter.php index 11a26eea6..1b666019b 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Filter/JobFilter.php +++ b/src/Bundle/ChillCalendarBundle/Export/Filter/JobFilter.php @@ -15,11 +15,8 @@ use Chill\CalendarBundle\Export\Declarations; use Chill\MainBundle\Entity\User\UserJobHistory; use Chill\MainBundle\Entity\UserJob; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\PickRollingDateType; -use Chill\MainBundle\Service\RollingDate\RollingDate; -use Chill\MainBundle\Service\RollingDate\RollingDateConverter; use Chill\MainBundle\Templating\TranslatableStringHelper; -use Doctrine\ORM\Query\Expr; +use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\FormBuilderInterface; @@ -30,7 +27,6 @@ class JobFilter implements FilterInterface private const PREFIX = 'cal_filter_job'; public function __construct( - private readonly RollingDateConverter $rollingDateConverter, protected TranslatorInterface $translator, private readonly TranslatableStringHelper $translatableStringHelper ) {} @@ -45,25 +41,27 @@ class JobFilter implements FilterInterface $p = self::PREFIX; $qb - ->leftJoin( - "cal.mainUser", - "{$p}_user" - ) + ->leftJoin("cal.mainUser", "{$p}_user") ->leftJoin( UserJobHistory::class, "{$p}_history", - Expr\Join::WITH, + Join::WITH, $qb->expr()->eq("{$p}_history.user", "{$p}_user") ) - ->andWhere($qb->expr()->in("{$p}_history.job", ":{$p}_job")) + // job_at based on cal.startDate ->andWhere( - "{$p}_history.startDate <= :{$p}_at AND ({$p}_history.endDate IS NULL OR {$p}_history.endDate > :{$p}_at)" + $qb->expr()->andX( + $qb->expr()->lte("{$p}_history.startDate", "cal.startDate"), + $qb->expr()->orX( + $qb->expr()->isNull("{$p}_history.endDate"), + $qb->expr()->gt("{$p}_history.endDate", "cal.startDate") + ) + ) ) + ->andWhere($qb->expr()->in("{$p}_history.job", ":{$p}_job")) ->setParameters([ "{$p}_job" => $data["job"], - "{$p}_at" => $this->rollingDateConverter->convert($data["job_at"]) - ]) - ; + ]); } @@ -82,10 +80,6 @@ class JobFilter implements FilterInterface ), 'multiple' => true, 'expanded' => true, - ]) - ->add('job_at', PickRollingDateType::class, [ - 'label' => 'export.calendar.agent_job.Calc date', - 'required' => true, ]); } @@ -99,7 +93,7 @@ class JobFilter implements FilterInterface ); } - return ['Filtered by agent job: only %jobs%', [ + return ['export.filter.calendar.agent_job.Filtered by agent job: only %jobs%', [ '%jobs%' => implode(', ', $userJobs), ]]; } @@ -108,12 +102,11 @@ class JobFilter implements FilterInterface { return [ 'job' => [], - 'job_at' => new RollingDate(RollingDate::T_TODAY), ]; } public function getTitle(): string { - return 'Filter calendars by agent job'; + return 'export.filter.calendar.agent_job.Filter calendars by agent job'; } } diff --git a/src/Bundle/ChillCalendarBundle/Export/Filter/ScopeFilter.php b/src/Bundle/ChillCalendarBundle/Export/Filter/ScopeFilter.php index 5a310c38b..61ec8d50d 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Filter/ScopeFilter.php +++ b/src/Bundle/ChillCalendarBundle/Export/Filter/ScopeFilter.php @@ -15,11 +15,8 @@ use Chill\CalendarBundle\Export\Declarations; use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\User\UserScopeHistory; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\PickRollingDateType; -use Chill\MainBundle\Service\RollingDate\RollingDate; -use Chill\MainBundle\Service\RollingDate\RollingDateConverter; use Chill\MainBundle\Templating\TranslatableStringHelper; -use Doctrine\ORM\Query\Expr; +use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\FormBuilderInterface; @@ -30,7 +27,6 @@ class ScopeFilter implements FilterInterface private const PREFIX = 'cal_filter_scope'; public function __construct( - private readonly RollingDateConverter $rollingDateConverter, protected TranslatorInterface $translator, private readonly TranslatableStringHelper $translatableStringHelper ) {} @@ -49,16 +45,22 @@ class ScopeFilter implements FilterInterface ->leftJoin( UserScopeHistory::class, "{$p}_history", - Expr\Join::WITH, + Join::WITH, $qb->expr()->eq("{$p}_history.user", "{$p}_user") ) - ->andWhere($qb->expr()->in("{$p}_history.scope", ":{$p}_scope")) + // scope_at based on cal.startDate ->andWhere( - "{$p}_history.startDate <= :{$p}_at AND ({$p}_history.endDate IS NULL OR {$p}_history.endDate > :{$p}_at)" + $qb->expr()->andX( + $qb->expr()->lte("{$p}_history.startDate", "cal.startDate"), + $qb->expr()->orX( + $qb->expr()->isNull("{$p}_history.endDate"), + $qb->expr()->gt("{$p}_history.endDate", "cal.startDate") + ) + ) ) + ->andWhere($qb->expr()->in("{$p}_history.scope", ":{$p}_scope")) ->setParameters([ "{$p}_scope" => $data["scope"], - "{$p}_at" => $this->rollingDateConverter->convert($data['scope_at']) ]); } @@ -77,10 +79,6 @@ class ScopeFilter implements FilterInterface ), 'multiple' => true, 'expanded' => true, - ]) - ->add('scope_at', PickRollingDateType::class, [ - 'label' => 'export.calendar.agent_scope.Calc date', - 'required' => true, ]); } @@ -94,7 +92,7 @@ class ScopeFilter implements FilterInterface ); } - return ['Filtered by agent scope: only %scopes%', [ + return ['export.filter.calendar.agent_scope.Filtered by agent scope: only %scopes%', [ '%scopes%' => implode(', ', $scopes), ]]; } @@ -103,12 +101,11 @@ class ScopeFilter implements FilterInterface { return [ 'scope' => [], - 'scope_at' => new RollingDate(RollingDate::T_TODAY) ]; } public function getTitle(): string { - return 'Filter calendars by agent scope'; + return 'export.filter.calendar.agent_scope.Filter calendars by agent scope'; } } diff --git a/src/Bundle/ChillCalendarBundle/Tests/Export/Aggregator/JobAggregatorTest.php b/src/Bundle/ChillCalendarBundle/Tests/Export/Aggregator/JobAggregatorTest.php index 838f8b988..094567fa7 100644 --- a/src/Bundle/ChillCalendarBundle/Tests/Export/Aggregator/JobAggregatorTest.php +++ b/src/Bundle/ChillCalendarBundle/Tests/Export/Aggregator/JobAggregatorTest.php @@ -20,7 +20,6 @@ namespace Chill\CalendarBundle\Tests\Export\Aggregator; use Chill\CalendarBundle\Entity\Calendar; use Chill\CalendarBundle\Export\Aggregator\JobAggregator; -use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Test\Export\AbstractAggregatorTest; use Doctrine\ORM\EntityManagerInterface; @@ -47,9 +46,7 @@ final class JobAggregatorTest extends AbstractAggregatorTest public function getFormData(): array { return [ - [ - 'job_at' => new RollingDate(RollingDate::T_FIXED_DATE, \DateTimeImmutable::createFromFormat('Y-m-d', '2020-01-01')), - ] + [] ]; } diff --git a/src/Bundle/ChillCalendarBundle/Tests/Export/Aggregator/ScopeAggregatorTest.php b/src/Bundle/ChillCalendarBundle/Tests/Export/Aggregator/ScopeAggregatorTest.php index 43900d53a..c9a2b9e5c 100644 --- a/src/Bundle/ChillCalendarBundle/Tests/Export/Aggregator/ScopeAggregatorTest.php +++ b/src/Bundle/ChillCalendarBundle/Tests/Export/Aggregator/ScopeAggregatorTest.php @@ -20,7 +20,6 @@ namespace Chill\CalendarBundle\Tests\Export\Aggregator; use Chill\CalendarBundle\Entity\Calendar; use Chill\CalendarBundle\Export\Aggregator\ScopeAggregator; -use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Test\Export\AbstractAggregatorTest; use Doctrine\ORM\EntityManagerInterface; @@ -47,9 +46,7 @@ final class ScopeAggregatorTest extends AbstractAggregatorTest public function getFormData(): array { return [ - [ - 'scope_at' => new RollingDate(RollingDate::T_FIXED_DATE, \DateTimeImmutable::createFromFormat('Y-m-d', '2020-01-01')), - ], + [], ]; } diff --git a/src/Bundle/ChillCalendarBundle/Tests/Export/Filter/JobFilterTest.php b/src/Bundle/ChillCalendarBundle/Tests/Export/Filter/JobFilterTest.php index c1305036c..a395062db 100644 --- a/src/Bundle/ChillCalendarBundle/Tests/Export/Filter/JobFilterTest.php +++ b/src/Bundle/ChillCalendarBundle/Tests/Export/Filter/JobFilterTest.php @@ -21,7 +21,6 @@ namespace Chill\CalendarBundle\Tests\Export\Filter; use Chill\CalendarBundle\Entity\Calendar; use Chill\CalendarBundle\Export\Filter\JobFilter; use Chill\MainBundle\Entity\UserJob; -use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Test\Export\AbstractFilterTest; use Doctrine\ORM\EntityManagerInterface; @@ -68,7 +67,6 @@ final class JobFilterTest extends AbstractFilterTest foreach ($array as $a) { $data[] = [ 'job' => $a, - 'job_at' => new RollingDate(RollingDate::T_FIXED_DATE, \DateTimeImmutable::createFromFormat('Y-m-d', '2020-01-01')), ]; } diff --git a/src/Bundle/ChillCalendarBundle/Tests/Export/Filter/ScopeFilterTest.php b/src/Bundle/ChillCalendarBundle/Tests/Export/Filter/ScopeFilterTest.php index 5d54a091e..eef7d1362 100644 --- a/src/Bundle/ChillCalendarBundle/Tests/Export/Filter/ScopeFilterTest.php +++ b/src/Bundle/ChillCalendarBundle/Tests/Export/Filter/ScopeFilterTest.php @@ -21,7 +21,6 @@ namespace Chill\CalendarBundle\Tests\Export\Filter; use Chill\CalendarBundle\Entity\Calendar; use Chill\CalendarBundle\Export\Filter\ScopeFilter; use Chill\MainBundle\Entity\Scope; -use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Test\Export\AbstractFilterTest; use Doctrine\ORM\EntityManagerInterface; @@ -68,7 +67,6 @@ final class ScopeFilterTest extends AbstractFilterTest foreach ($array as $a) { $data[] = [ 'scope' => $a, - 'scope_at' => new RollingDate(RollingDate::T_FIXED_DATE, \DateTimeImmutable::createFromFormat('Y-m-d', '2020-01-01')), ]; } diff --git a/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml b/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml index 0da92fd72..d157683e0 100644 --- a/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml @@ -99,29 +99,31 @@ Get the sum of appointment durations according to various filters: Calcule la so 'Filtered by agent: only %agents%': "Filtré par agents: uniquement %agents%" Filter calendars by agent: Filtrer les rendez-vous par agents -Filter calendars by agent job: Filtrer les rendez-vous par métiers des agents -'Filtered by agent job: only %jobs%': 'Filtré par métiers des agents: uniquement les %jobs%' -Filter calendars by agent scope: Filtrer les rendez-vous par services des agents -'Filtered by agent scope: only %scopes%': 'Filtré par services des agents: uniquement les services %scopes%' Filter calendars between certain dates: Filtrer les rendez-vous par date du rendez-vous 'Filtered by calendars between %dateFrom% and %dateTo%': 'Filtré par rendez-vous entre %dateFrom% et %dateTo%' 'Filtered by calendar range: only %calendarRange%': 'Filtré par rendez-vous par plage de disponibilité: uniquement les %calendarRange%' Filter by calendar range: Filtrer par rendez-vous dans une plage de disponibilité ou non Group calendars by agent: Grouper les rendez-vous par agent -Group calendars by agent job: Grouper les rendez-vous par métier de l'agent -Group calendars by agent scope: Grouper les rendez-vous par service de l'agent Group calendars by location type: Grouper les rendez-vous par type de localisation Group calendars by location: Grouper les rendez-vous par lieu de rendez-vous Group calendars by cancel reason: Grouper les rendez-vous par motif d'annulation Group calendars by month and year: Grouper les rendez-vous par mois et année Group calendars by urgency: Grouper les rendez-vous par urgent ou non -export.calendar: - agent_job: - Calc date: Date de calcul du métier de l'agent - agent_scope: - Calc date: Date de calcul du service de l'agent +export: + aggregator.calendar: + agent_job: + Group calendars by agent job: Grouper les rendez-vous par métier de l'agent + agent_scope: + Group calendars by agent scope: Grouper les rendez-vous par service de l'agent + filter.calendar: + agent_job: + Filter calendars by agent job: Filtrer les rendez-vous par métiers des agents (utilisateurs principaux) + 'Filtered by agent job: only %jobs%': 'Filtré par métiers des agents (utilisateurs principaux): uniquement les %jobs%' + agent_scope: + Filter calendars by agent scope: Filtrer les rendez-vous par services des agents (utilisateurs principaux) + 'Filtered by agent scope: only %scopes%': 'Filtré par services des agents (utilisateurs principaux): uniquement les services %scopes%' Scope: Service Job: Métier