[export] fix activity filters/aggregators + tests: 'at' based on activity date

This commit is contained in:
Mathieu Jaumotte 2023-10-03 15:24:41 +02:00
parent 6e48d036d7
commit fa3fc2c781
8 changed files with 31 additions and 96 deletions

View File

@ -14,10 +14,7 @@ namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations; use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Entity\User\UserJobHistory; use Chill\MainBundle\Entity\User\UserJobHistory;
use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Form\Type\PickRollingDateType;
use Chill\MainBundle\Repository\UserJobRepositoryInterface; use Chill\MainBundle\Repository\UserJobRepositoryInterface;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Service\RollingDate\RollingDateConverter;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\Query\Expr; use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
@ -28,7 +25,6 @@ class ActivityUsersJobAggregator implements AggregatorInterface
private const PREFIX = 'act_agg_user_job'; private const PREFIX = 'act_agg_user_job';
public function __construct( public function __construct(
private readonly RollingDateConverter $rollingDateConverter,
private readonly UserJobRepositoryInterface $userJobRepository, private readonly UserJobRepositoryInterface $userJobRepository,
private readonly TranslatableStringHelperInterface $translatableStringHelper private readonly TranslatableStringHelperInterface $translatableStringHelper
) {} ) {}
@ -50,20 +46,17 @@ class ActivityUsersJobAggregator implements AggregatorInterface
Expr\Join::WITH, Expr\Join::WITH,
$qb->expr()->eq("{$p}_history.user", "{$p}_user") $qb->expr()->eq("{$p}_history.user", "{$p}_user")
) )
// job_at based on activity.date
->andWhere( ->andWhere(
$qb->expr()->andX( $qb->expr()->andX(
$qb->expr()->lte("{$p}_history.startDate", ":{$p}_at"), $qb->expr()->lte("{$p}_history.startDate", "activity.date"),
$qb->expr()->orX( $qb->expr()->orX(
$qb->expr()->isNull("{$p}_history.endDate"), $qb->expr()->isNull("{$p}_history.endDate"),
$qb->expr()->gt("{$p}_history.endDate", ":{$p}_at") $qb->expr()->gt("{$p}_history.endDate", "activity.date")
) )
) )
) )
->addSelect("IDENTITY({$p}_history.job) AS {$p}_select") ->addSelect("IDENTITY({$p}_history.job) AS {$p}_select")
->setParameter(
"{$p}_at",
$this->rollingDateConverter->convert($data['job_at'])
)
->addGroupBy("{$p}_select"); ->addGroupBy("{$p}_select");
} }
@ -74,16 +67,11 @@ class ActivityUsersJobAggregator implements AggregatorInterface
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('job_at', PickRollingDateType::class, [
'label' => 'export.aggregator.activity.by_user_job.Calc date',
'required' => true
]);
} }
public function getFormDefaultData(): array public function getFormDefaultData(): array
{ {
return ['job_at' => new RollingDate(RollingDate::T_TODAY)]; return [];
} }
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)

View File

@ -14,10 +14,7 @@ namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations; use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Entity\User\UserScopeHistory; use Chill\MainBundle\Entity\User\UserScopeHistory;
use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Form\Type\PickRollingDateType;
use Chill\MainBundle\Repository\ScopeRepositoryInterface; use Chill\MainBundle\Repository\ScopeRepositoryInterface;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Service\RollingDate\RollingDateConverter;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\Query\Expr; use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
@ -28,7 +25,6 @@ class ActivityUsersScopeAggregator implements AggregatorInterface
private const PREFIX = 'act_agg_user_scope'; private const PREFIX = 'act_agg_user_scope';
public function __construct( public function __construct(
private readonly RollingDateConverter $rollingDateConverter,
private readonly ScopeRepositoryInterface $scopeRepository, private readonly ScopeRepositoryInterface $scopeRepository,
private readonly TranslatableStringHelperInterface $translatableStringHelper private readonly TranslatableStringHelperInterface $translatableStringHelper
) {} ) {}
@ -50,20 +46,17 @@ class ActivityUsersScopeAggregator implements AggregatorInterface
Expr\Join::WITH, Expr\Join::WITH,
$qb->expr()->eq("{$p}_history.user", "{$p}_user") $qb->expr()->eq("{$p}_history.user", "{$p}_user")
) )
// scope_at based on activity.date
->andWhere( ->andWhere(
$qb->expr()->andX( $qb->expr()->andX(
$qb->expr()->lte("{$p}_history.startDate", ":{$p}_at"), $qb->expr()->lte("{$p}_history.startDate", "activity.date"),
$qb->expr()->orX( $qb->expr()->orX(
$qb->expr()->isNull("{$p}_history.endDate"), $qb->expr()->isNull("{$p}_history.endDate"),
$qb->expr()->gt("{$p}_history.endDate", ":{$p}_at") $qb->expr()->gt("{$p}_history.endDate", "activity.date")
) )
) )
) )
->addSelect("IDENTITY({$p}_history.scope) AS {$p}_select") ->addSelect("IDENTITY({$p}_history.scope) AS {$p}_select")
->setParameter(
"{$p}_at",
$this->rollingDateConverter->convert($data['scope_at'])
)
->addGroupBy("{$p}_select"); ->addGroupBy("{$p}_select");
} }
@ -74,15 +67,11 @@ class ActivityUsersScopeAggregator implements AggregatorInterface
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('scope_at', PickRollingDateType::class, [
'label' => 'export.aggregator.activity.by_user_scope.Calc date',
'required' => true,
]);
} }
public function getFormDefaultData(): array public function getFormDefaultData(): array
{ {
return ['scope_at' => new RollingDate(RollingDate::T_TODAY)]; return [];
} }
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)

View File

@ -14,12 +14,9 @@ namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations; use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Entity\User\UserScopeHistory; use Chill\MainBundle\Entity\User\UserScopeHistory;
use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Form\Type\PickRollingDateType;
use Chill\MainBundle\Repository\ScopeRepository; use Chill\MainBundle\Repository\ScopeRepository;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Service\RollingDate\RollingDateConverter;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr; use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@ -28,7 +25,6 @@ class CreatorScopeAggregator implements AggregatorInterface
private const PREFIX = 'acp_agg_creator_scope'; private const PREFIX = 'acp_agg_creator_scope';
public function __construct( public function __construct(
private readonly RollingDateConverter $rollingDateConverter,
private readonly ScopeRepository $scopeRepository, private readonly ScopeRepository $scopeRepository,
private readonly TranslatableStringHelper $translatableStringHelper private readonly TranslatableStringHelper $translatableStringHelper
) {} ) {}
@ -47,23 +43,20 @@ class CreatorScopeAggregator implements AggregatorInterface
->leftJoin( ->leftJoin(
UserScopeHistory::class, UserScopeHistory::class,
"{$p}_history", "{$p}_history",
Expr\Join::WITH, Join::WITH,
$qb->expr()->eq("{$p}_history.user", "{$p}_user") $qb->expr()->eq("{$p}_history.user", "{$p}_user")
) )
// scope_at based on activity.date
->andWhere( ->andWhere(
$qb->expr()->andX( $qb->expr()->andX(
$qb->expr()->lte("{$p}_history.startDate", ":{$p}_at"), $qb->expr()->lte("{$p}_history.startDate", "activity.date"),
$qb->expr()->orX( $qb->expr()->orX(
$qb->expr()->isNull("{$p}_history.endDate"), $qb->expr()->isNull("{$p}_history.endDate"),
$qb->expr()->gt("{$p}_history.endDate", ":{$p}_at") $qb->expr()->gt("{$p}_history.endDate", "activity.date")
) )
) )
) )
->addSelect("IDENTITY({$p}_history.scope) AS {$p}_select") ->addSelect("IDENTITY({$p}_history.scope) AS {$p}_select")
->setParameter(
"{$p}_at",
$this->rollingDateConverter->convert($data['scope_at'])
)
->addGroupBy("{$p}_select"); ->addGroupBy("{$p}_select");
} }
@ -74,15 +67,11 @@ class CreatorScopeAggregator implements AggregatorInterface
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('scope_at', PickRollingDateType::class, [
'label' => 'export.aggregator.activity.by_creator_scope.Calc date',
'required' => true,
]);
} }
public function getFormDefaultData(): array public function getFormDefaultData(): array
{ {
return ['scope_at' => new RollingDate(RollingDate::T_TODAY)]; return [];
} }
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)

View File

@ -50,21 +50,21 @@ class UserScopeFilter implements FilterInterface
Join::WITH, Join::WITH,
$qb->expr()->eq("{$p}_history.user", "{$p}_user") $qb->expr()->eq("{$p}_history.user", "{$p}_user")
) )
// scope_at based on activity.date
->andWhere( ->andWhere(
$qb->expr()->andX( $qb->expr()->andX(
$qb->expr()->lte("{$p}_history.startDate", ":{$p}_at"), $qb->expr()->lte("{$p}_history.startDate", "activity.date"),
$qb->expr()->orX( $qb->expr()->orX(
$qb->expr()->isNull("{$p}_history.endDate"), $qb->expr()->isNull("{$p}_history.endDate"),
$qb->expr()->gt("{$p}_history.endDate", ":{$p}_at") $qb->expr()->gt("{$p}_history.endDate", "activity.date")
) )
) )
) )
->andWhere( ->andWhere(
$qb->expr()->in("{$p}_history.scope", ":{$p}_scope") $qb->expr()->in("{$p}_history.scope", ":{$p}_scopes")
) )
->setParameters([ ->setParameters([
"{$p}_scope" => $data["scopes"], "{$p}_scopes" => $data["scopes"],
"{$p}_at" => $this->rollingDateConverter->convert($data["scope_at"])
]); ]);
} }
@ -83,10 +83,6 @@ class UserScopeFilter implements FilterInterface
), ),
'multiple' => true, 'multiple' => true,
'expanded' => true, 'expanded' => true,
])
->add('scope_at', PickRollingDateType::class, [
'label' => 'export.filter.activity.course.by_user_scope.Calc date',
'required' => true,
]); ]);
} }
@ -100,7 +96,7 @@ class UserScopeFilter implements FilterInterface
); );
} }
return ['export.filter.activity.course.by_user_scope.Filtered activity by userscope: only %scopes%', [ return ['export.filter.activity.by_creator_scope.Filtered activity by user scope: only %scopes%', [
'%scopes%' => implode(', ', $scopes), '%scopes%' => implode(', ', $scopes),
]]; ]];
} }
@ -109,12 +105,11 @@ class UserScopeFilter implements FilterInterface
{ {
return [ return [
'scopes' => [], 'scopes' => [],
'scope_at' => new RollingDate(RollingDate::T_TODAY)
]; ];
} }
public function getTitle(): string public function getTitle(): string
{ {
return 'export.filter.activity.course.by_user_scope.Filter activity by userscope'; return 'export.filter.activity.by_creator_scope.Filter activity by user scope';
} }
} }

View File

@ -16,9 +16,6 @@ use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Entity\User\UserJobHistory; use Chill\MainBundle\Entity\User\UserJobHistory;
use Chill\MainBundle\Entity\UserJob; use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Export\FilterInterface; 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\TranslatableStringHelperInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
@ -29,7 +26,6 @@ class UsersJobFilter implements FilterInterface
private const PREFIX = 'act_filter_user_job'; private const PREFIX = 'act_filter_user_job';
public function __construct( public function __construct(
private readonly RollingDateConverter $rollingDateConverter,
private readonly TranslatableStringHelperInterface $translatableStringHelper private readonly TranslatableStringHelperInterface $translatableStringHelper
) {} ) {}
@ -49,14 +45,14 @@ class UsersJobFilter implements FilterInterface
. "JOIN {$p}_act.users {$p}_user " . "JOIN {$p}_act.users {$p}_user "
. "JOIN " . UserJobHistory::class . " {$p}_history WITH {$p}_history.user = {$p}_user " . "JOIN " . UserJobHistory::class . " {$p}_history WITH {$p}_history.user = {$p}_user "
. "WHERE {$p}_act = activity " . "WHERE {$p}_act = activity "
. "AND {$p}_history.startDate <= :{$p}_at " // job_at based on activity.date
. "AND ({$p}_history.endDate IS NULL OR {$p}_history.endDate > :{$p}_at) " . "AND {$p}_history.startDate <= activity.date "
. "AND ({$p}_history.endDate IS NULL OR {$p}_history.endDate > activity.date) "
. "AND {$p}_history.job IN ( :{$p}_jobs )" . "AND {$p}_history.job IN ( :{$p}_jobs )"
) )
) )
->setParameters([ ->setParameters([
"{$p}_jobs" => $data["jobs"], "{$p}_jobs" => $data["jobs"],
"{$p}_at" => $this->rollingDateConverter->convert($data["job_at"])
]); ]);
} }
@ -73,10 +69,6 @@ class UsersJobFilter implements FilterInterface
'choice_label' => fn (UserJob $j) => $this->translatableStringHelper->localize($j->getLabel()), 'choice_label' => fn (UserJob $j) => $this->translatableStringHelper->localize($j->getLabel()),
'multiple' => true, 'multiple' => true,
'expanded' => true, 'expanded' => true,
])
->add('job_at', PickRollingDateType::class, [
'label' => 'export.filter.activity.by_users_job.Calc date',
'required' => true
]); ]);
} }
@ -97,7 +89,6 @@ class UsersJobFilter implements FilterInterface
{ {
return [ return [
'jobs' => [], 'jobs' => [],
'job_at' => new RollingDate(RollingDate::T_TODAY)
]; ];
} }

View File

@ -16,10 +16,7 @@ use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User\UserScopeHistory; use Chill\MainBundle\Entity\User\UserScopeHistory;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\PickRollingDateType;
use Chill\MainBundle\Repository\ScopeRepositoryInterface; use Chill\MainBundle\Repository\ScopeRepositoryInterface;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Service\RollingDate\RollingDateConverter;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
@ -30,7 +27,6 @@ class UsersScopeFilter implements FilterInterface
private const PREFIX = 'act_filter_user_scope'; private const PREFIX = 'act_filter_user_scope';
public function __construct( public function __construct(
private readonly RollingDateConverter $rollingDateConverter,
private readonly ScopeRepositoryInterface $scopeRepository, private readonly ScopeRepositoryInterface $scopeRepository,
private readonly TranslatableStringHelperInterface $translatableStringHelper private readonly TranslatableStringHelperInterface $translatableStringHelper
) {} ) {}
@ -51,14 +47,14 @@ class UsersScopeFilter implements FilterInterface
. "JOIN {$p}_act.users {$p}_user " . "JOIN {$p}_act.users {$p}_user "
. "JOIN " . UserScopeHistory::class . " {$p}_history WITH {$p}_history.user = {$p}_user " . "JOIN " . UserScopeHistory::class . " {$p}_history WITH {$p}_history.user = {$p}_user "
. "WHERE {$p}_act = activity " . "WHERE {$p}_act = activity "
. "AND {$p}_history.startDate <= :{$p}_at " // scope_at based on activity.date
. "AND ({$p}_history.endDate IS NULL OR {$p}_history.endDate > :{$p}_at) " . "AND {$p}_history.startDate <= activity.date "
. "AND ({$p}_history.endDate IS NULL OR {$p}_history.endDate > activity.date) "
. "AND {$p}_history.scope IN ( :{$p}_scopes )" . "AND {$p}_history.scope IN ( :{$p}_scopes )"
) )
) )
->setParameters([ ->setParameters([
"{$p}_scopes" => $data["scopes"], "{$p}_scopes" => $data["scopes"],
"{$p}_at" => $this->rollingDateConverter->convert($data["scope_at"])
]); ]);
} }
@ -76,10 +72,6 @@ class UsersScopeFilter implements FilterInterface
'choice_label' => fn (Scope $s) => $this->translatableStringHelper->localize($s->getName()), 'choice_label' => fn (Scope $s) => $this->translatableStringHelper->localize($s->getName()),
'multiple' => true, 'multiple' => true,
'expanded' => true, 'expanded' => true,
])
->add('scope_at', PickRollingDateType::class, [
'label' => 'export.filter.activity.by_users_scope.Calc date',
'required' => true,
]); ]);
} }
@ -100,7 +92,6 @@ class UsersScopeFilter implements FilterInterface
{ {
return [ return [
'scopes' => [], 'scopes' => [],
'scope_at' => new RollingDate(RollingDate::T_TODAY)
]; ];
} }

View File

@ -53,7 +53,7 @@ final class UserScopeFilterTest extends AbstractFilterTest
foreach ($array as $a) { foreach ($array as $a) {
$data[] = [ $data[] = [
'accepted_userscope' => $a, 'scopes' => $a,
]; ];
} }

View File

@ -363,23 +363,18 @@ export:
by_users_job: by_users_job:
Filter by users job: Filtrer les échanges par métier d'au moins un utilisateur participant 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%' 'Filtered activity by users job: only %jobs%': 'Filtré par métier d''au moins un utilisateur participant: seulement %jobs%'
Calc date: Date de calcul du métier de l'utilisateur
by_users_scope: 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 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%' 'Filtered activity by users scope: only %scopes%': 'Filtré par service d''au moins un utilisateur participant: seulement %scopes%'
Calc date: Date de calcul du service de l'utilisateur
course_having_activity_between_date: course_having_activity_between_date:
Title: Filtre les parcours ayant reçu un échange entre deux dates Title: Filtre 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 after: Ayant reçu un échange après le
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%'
course: by_creator_scope:
by_user_scope: Filter activity by user scope: Filtrer les échanges par service du créateur de l'échange
Filter activity by userscope: Filtrer les échanges par service du créateur 'Filtered activity by user scope: only %scopes%': "Filtré par service du créateur: uniquement %scopes%"
'Filtered activity by userscope: only %scopes%': "Filtré par service du créateur: uniquement %scopes%"
Calc date: Date de calcul du service du créateur
aggregator: aggregator:
activity: activity:
@ -394,16 +389,13 @@ export:
by_user_job: by_user_job:
Users 's job: Métier des utilisateurs participants à l'échange Users 's job: Métier des utilisateurs participants à l'échange
Aggregate by users job: Grouper les échanges par métier des utilisateurs participants Aggregate by users job: Grouper les échanges par métier des utilisateurs participants
Calc date: Date de calcul du métier des participants
by_user_scope: by_user_scope:
Users 's scope: Service principal des utilisateurs participants à l'échange Users 's scope: Service principal des utilisateurs participants à l'échange
Aggregate by users scope: Grouper les échanges par service principal de l'utilisateur Aggregate by users scope: Grouper les échanges par service principal de l'utilisateur
Calc date: Date de calcul du service principal de l'utilisateur
by_creator_scope: by_creator_scope:
Group activity by creator scope: Grouper les échanges par service du créateur de l'échange Group activity by creator scope: Grouper les échanges par service du créateur de l'échange
Calc date: Date de calcul du service du créateur de l'échange Calc date: Date de calcul du service du créateur de l'échange
generic_doc: generic_doc:
filter: filter:
keys: keys: