diff --git a/.changes/unreleased/Fixed-20230928-120910.yaml b/.changes/unreleased/Fixed-20230928-120910.yaml deleted file mode 100644 index 72c9dd9b4..000000000 --- a/.changes/unreleased/Fixed-20230928-120910.yaml +++ /dev/null @@ -1,5 +0,0 @@ -kind: Fixed -body: 'View a third party: avoid errors when a contact has a civility' -time: 2023-09-28T12:09:10.199359071+02:00 -custom: - Issue: "164" diff --git a/.changes/v2.8.0.md b/.changes/v2.8.0.md new file mode 100644 index 000000000..4e0f03c11 --- /dev/null +++ b/.changes/v2.8.0.md @@ -0,0 +1,19 @@ +## v2.8.0 - 2023-10-05 + +### Feature + +* ([#162](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/162)) Reassigning list: when reassigning courses to a new user, the job associated with the course become the one of the new user (if any) +* Reassining list: the length of the list is increased to 100 courses + +### Fixed + +* ([#143](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/143)) Fix filter "accompanying course by social action" to avoid duplication in list +* ([#164](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/164)) View a third party: avoid errors when a contact has a civility +* ([#163](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/163)) Fix the filters and aggregators on exports "count peoples" +* ([#143](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/143)) From the database, avoid the creation of location history for same period and at same dates + +### Traduction francophone des principaux changements + +- Fonctionnalité: Réassigner les parcours en lot: lorsque des parcours sont réassignés "en lot", les parcours sont maintenant associés au métier du nouveau référent; +- Correction: certaines causes qui créaient des doublons dans les listes ont été corrigées; +- Correction des associations entre l'export "nombre de personnes" et les filtres et regroupements associés diff --git a/CHANGELOG.md b/CHANGELOG.md index d2a1e74b8..12c36b4c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,26 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html), and is generated by [Changie](https://github.com/miniscruff/changie). +## v2.8.0 - 2023-10-05 + +### Feature + +* ([#162](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/162)) Reassigning list: when reassigning courses to a new user, the job associated with the course become the one of the new user (if any) +* Reassining list: the length of the list is increased to 100 courses + +### Fixed + +* ([#143](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/143)) Fix filter "accompanying course by social action" to avoid duplication in list +* ([#164](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/164)) View a third party: avoid errors when a contact has a civility +* ([#163](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/163)) Fix the filters and aggregators on exports "count peoples" +* ([#143](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/143)) From the database, avoid the creation of location history for same period and at same dates + +### Traduction francophone des principaux changements + +- Fonctionnalité: Réassigner les parcours en lot: lorsque des parcours sont réassignés "en lot", les parcours sont maintenant associés au métier du nouveau référent; +- Correction: certaines causes qui créaient des doublons dans les listes ont été corrigées; +- Correction des associations entre l'export "nombre de personnes" et les filtres et regroupements associés + ## v2.7.0 - 2023-09-27 ### Feature * ([#155](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/155)) The regulation list load accompanying periods by exact postal code (address associated with postal code), and not by the content of the postal code (postal code with same code's string) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 20b03f783..fe34130d2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,7 +40,7 @@ About once a year, the core team discusses the opportunity to invite new members ### Core Membership Revocation -A Symfony Core membership can be revoked for any of the following reasons: +A Chill Core membership can be revoked for any of the following reasons: - Refusal to follow the rules and policies stated in this document; - Lack of activity for the past six months; diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/PersonHavingActivityBetweenDateFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/PersonHavingActivityBetweenDateFilter.php index 9bd77c9a2..9cf6fa281 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/PersonHavingActivityBetweenDateFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/PersonHavingActivityBetweenDateFilter.php @@ -16,31 +16,22 @@ use Chill\ActivityBundle\Entity\ActivityReason; 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; -use DateTime; -use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Form\FormError; -use Symfony\Component\Form\FormEvent; -use Symfony\Component\Form\FormEvents; -use Symfony\Component\Form\FormInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface; -use Symfony\Contracts\Translation\TranslatorInterface; -use function count; - -class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInterface, FilterInterface +final readonly class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInterface, FilterInterface { public function __construct( - protected TranslatableStringHelper $translatableStringHelper, - protected ActivityReasonRepository $activityReasonRepository, - protected TranslatorInterface $translator + private TranslatableStringHelper $translatableStringHelper, + private ActivityReasonRepository $activityReasonRepository, + private RollingDateConverterInterface $rollingDateConverter, ) {} public function addRole(): ?string @@ -52,131 +43,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()) . '"', @@ -189,13 +142,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 8deebbb8c..123a0d075 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 @@ -372,6 +367,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 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%" diff --git a/src/Bundle/ChillPersonBundle/Controller/ReassignAccompanyingPeriodController.php b/src/Bundle/ChillPersonBundle/Controller/ReassignAccompanyingPeriodController.php index 000730131..11d42f74b 100644 --- a/src/Bundle/ChillPersonBundle/Controller/ReassignAccompanyingPeriodController.php +++ b/src/Bundle/ChillPersonBundle/Controller/ReassignAccompanyingPeriodController.php @@ -33,9 +33,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\Routing\Annotation\Route; -use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\Security; -use Symfony\Component\Templating\EngineInterface; use Symfony\Component\Validator\Constraints\NotIdenticalTo; use Symfony\Component\Validator\Constraints\NotNull; use function is_int; @@ -62,7 +60,7 @@ class ReassignAccompanyingPeriodController extends AbstractController $total = $this->accompanyingPeriodACLAwareRepository->countByUserAndPostalCodesOpenedAccompanyingPeriod($userFrom, $postalCodes); $paginator = $this->paginatorFactory->create($total); - $paginator->setItemsPerPage(50); + $paginator->setItemsPerPage(100); $periods = $this->accompanyingPeriodACLAwareRepository ->findByUserAndPostalCodesOpenedAccompanyingPeriod( $userFrom, @@ -85,6 +83,7 @@ class ReassignAccompanyingPeriodController extends AbstractController if ($assignForm->isSubmitted() && $assignForm->isValid()) { $assignPeriodIds = json_decode((string) $assignForm->get('periods')->getData(), true, 512, JSON_THROW_ON_ERROR); + /** @var User $userTo */ $userTo = $assignForm->get('userTo')->getData(); $userFrom = $assignForm->get('userFrom')->getData(); @@ -93,6 +92,10 @@ class ReassignAccompanyingPeriodController extends AbstractController if ($period->getUser() === $userFrom) { $period->setUser($userTo, true); + + if (null !== $userTo->getUserJob() && $period->getJob() !== $userTo->getUserJob()) { + $period->setJob($userTo->getUserJob()); + } } } diff --git a/src/Bundle/ChillPersonBundle/Export/Declarations.php b/src/Bundle/ChillPersonBundle/Export/Declarations.php index a512700ee..a79c05a67 100644 --- a/src/Bundle/ChillPersonBundle/Export/Declarations.php +++ b/src/Bundle/ChillPersonBundle/Export/Declarations.php @@ -22,7 +22,10 @@ abstract class Declarations final public const HOUSEHOLD_TYPE = 'household'; - final public const PERSON_IMPLIED_IN = 'person_implied_in'; + /** + * @deprecated consider using the PERSON_TYPE instead + */ + public const PERSON_IMPLIED_IN = 'person_implied_in'; final public const PERSON_TYPE = 'person'; diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php index 392aa5485..3537f63ee 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php @@ -114,9 +114,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 adb58757f..9201b0c50 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php @@ -250,7 +250,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 c94637028..4c0b6e61d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonHavingAccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonHavingAccompanyingPeriod.php @@ -194,7 +194,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 958d52111..a5a788c12 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriodDetails.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriodDetails.php @@ -152,6 +152,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/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialActionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialActionFilter.php index bc4738155..71a7ff9f4 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialActionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialActionFilter.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\SocialWork\SocialAction; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Form\Type\PickSocialActionType; @@ -21,9 +21,9 @@ use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; use function in_array; -class SocialActionFilter implements FilterInterface +final readonly class SocialActionFilter implements FilterInterface { - public function __construct(private readonly TranslatableStringHelper $translatableStringHelper, private readonly SocialActionRender $actionRender) {} + public function __construct(private SocialActionRender $actionRender) {} public function addRole(): ?string { @@ -32,21 +32,17 @@ class SocialActionFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { - if (!in_array('acpw', $qb->getAllAliases(), true)) { - $qb->join('acp.works', 'acpw'); - } + $qb->andWhere( + $qb->expr()->exists( + sprintf( + "SELECT 1 FROM %s acp_by_social_action_filter WHERE acp_by_social_action_filter.socialAction " + . "IN (:acp_by_social_action_filter_actions) AND acp_by_social_action_filter.accompanyingPeriod = acp", + AccompanyingPeriod\AccompanyingPeriodWork::class + ) + ) + ); - if (!in_array('acpwsocialaction', $qb->getAllAliases(), true)) { - $qb->join('acpw.socialAction', 'acpwsocialaction'); - } - - $clause = $qb->expr()->in('acpwsocialaction.id', ':socialactions'); - - $qb->andWhere($clause) - ->setParameter( - 'socialactions', - SocialAction::getDescendantsWithThisForActions($data['accepted_socialactions'])->toArray() - ); + $qb->setParameter('acp_by_social_action_filter_actions', SocialAction::getDescendantsWithThisForActions($data['accepted_socialactions'])); } public function applyOn(): string diff --git a/src/Bundle/ChillPersonBundle/Form/ClosingMotiveType.php b/src/Bundle/ChillPersonBundle/Form/ClosingMotiveType.php index aa2f06afe..b89fd63a6 100644 --- a/src/Bundle/ChillPersonBundle/Form/ClosingMotiveType.php +++ b/src/Bundle/ChillPersonBundle/Form/ClosingMotiveType.php @@ -26,9 +26,7 @@ use Symfony\Contracts\Translation\TranslatorInterface; */ class ClosingMotiveType extends AbstractType { - public function __construct(private readonly TranslatorInterface $translator) - { - } + public function __construct(private readonly TranslatorInterface $translator) {} public function buildForm(FormBuilderInterface $builder, array $options) { diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20231002094521.php b/src/Bundle/ChillPersonBundle/migrations/Version20231002094521.php new file mode 100644 index 000000000..c960ab8f8 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/migrations/Version20231002094521.php @@ -0,0 +1,60 @@ +addSql( + <<<'SQL' + WITH doublons_ordered AS ( + SELECT h2.id AS h2id, h2.createdAt AS h2createdAt, h2.startDate AS h2start, h2.endDate AS h2end, h1.*, + rank() OVER (partition by h1.period_id ORDER BY h1.id, h2.id) AS ranking + FROM chill_person_accompanying_period_location_history h1 + JOIN chill_person_accompanying_period_location_history h2 ON h1.period_id = h2.period_id AND h1.id <> h2.id + WHERE daterange(h1.startdate, h1.enddate) && daterange(h2.startdate, h2.enddate) ORDER BY h1.period_id, h1.id + ), + keep_only_first AS ( + SELECT id FROM doublons_ordered WHERE ranking > 1 + ) + DELETE FROM chill_person_accompanying_period_location_history WHERE id IN (SELECT id FROM doublons_ordered); + SQL + ); + + $this->addSql( + <<<'SQL' + ALTER TABLE chill_person_accompanying_period_location_history + ADD CONSTRAINT acc_period_location_history_not_overlaps + EXCLUDE USING GIST (period_id with =, tsrange(startdate, enddate) with &&) + DEFERRABLE INITIALLY DEFERRED + SQL + ); + } + + public function down(Schema $schema): void + { + $this->addSql( + <<<'SQL' + ALTER TABLE chill_person_accompanying_period_location_history DROP CONSTRAINT acc_period_location_history_not_overlaps + SQL + ); + } +} diff --git a/src/Bundle/ChillReportBundle/Export/Export/ReportList.php b/src/Bundle/ChillReportBundle/Export/Export/ReportList.php index 1239c9167..93685bdec 100644 --- a/src/Bundle/ChillReportBundle/Export/Export/ReportList.php +++ b/src/Bundle/ChillReportBundle/Export/Export/ReportList.php @@ -426,7 +426,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)