From 6c37d798bf93738465b057e3c8d2a13da1983e78 Mon Sep 17 00:00:00 2001 From: Christophe Siraut Date: Wed, 27 Nov 2024 17:05:50 +0100 Subject: [PATCH 01/67] ChillPersonBundle: add administrativeStatus property to Person --- .../AdministrativeStatusController.php | 26 ++++++ .../ORM/LoadAdministrativeStatus.php | 43 ++++++++++ .../ChillPersonExtension.php | 25 ++++++ .../DependencyInjection/Configuration.php | 1 + .../Entity/AdministrativeStatus.php | 80 +++++++++++++++++++ .../ChillPersonBundle/Entity/Person.php | 19 +++++ .../Form/AdministrativeStatusType.php | 44 ++++++++++ .../ChillPersonBundle/Form/PersonType.php | 6 ++ .../Type/PickAdministrativeStatusType.php | 50 ++++++++++++ .../Menu/AdminPersonMenuBuilder.php | 6 ++ .../views/AdministrativeStatus/edit.html.twig | 11 +++ .../AdministrativeStatus/index.html.twig | 42 ++++++++++ .../views/AdministrativeStatus/new.html.twig | 11 +++ .../Resources/views/Person/edit.html.twig | 3 + .../Resources/views/Person/view.html.twig | 16 +++- .../migrations/Version20241127160628.php | 43 ++++++++++ .../translations/messages.fr.yml | 7 ++ 17 files changed, 431 insertions(+), 2 deletions(-) create mode 100644 src/Bundle/ChillPersonBundle/Controller/AdministrativeStatusController.php create mode 100644 src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAdministrativeStatus.php create mode 100644 src/Bundle/ChillPersonBundle/Entity/AdministrativeStatus.php create mode 100644 src/Bundle/ChillPersonBundle/Form/AdministrativeStatusType.php create mode 100644 src/Bundle/ChillPersonBundle/Form/Type/PickAdministrativeStatusType.php create mode 100644 src/Bundle/ChillPersonBundle/Resources/views/AdministrativeStatus/edit.html.twig create mode 100644 src/Bundle/ChillPersonBundle/Resources/views/AdministrativeStatus/index.html.twig create mode 100644 src/Bundle/ChillPersonBundle/Resources/views/AdministrativeStatus/new.html.twig create mode 100644 src/Bundle/ChillPersonBundle/migrations/Version20241127160628.php diff --git a/src/Bundle/ChillPersonBundle/Controller/AdministrativeStatusController.php b/src/Bundle/ChillPersonBundle/Controller/AdministrativeStatusController.php new file mode 100644 index 000000000..0b854ce43 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Controller/AdministrativeStatusController.php @@ -0,0 +1,26 @@ +addOrderBy('e.order', 'ASC'); + + return parent::orderQuery($action, $query, $request, $paginator); + } +} diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAdministrativeStatus.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAdministrativeStatus.php new file mode 100644 index 000000000..b9de3990a --- /dev/null +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAdministrativeStatus.php @@ -0,0 +1,43 @@ + ['fr' => 'situation administrative régulière']], + ['name' => ['fr' => 'sans papier']], + ['name' => ['fr' => 'séjour provisoire']], + ]; + + foreach ($status as $val) { + $administrativeStatus = (new AdministrativeStatus()) + ->setName($val['name']) + ->setActive(true); + $manager->persist($administrativeStatus); + } + + $manager->flush(); + } +} diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php index 9320a1246..8fddd477d 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php @@ -15,12 +15,15 @@ use Chill\MainBundle\DependencyInjection\MissingBundleException; use Chill\MainBundle\Security\Authorization\ChillExportVoter; use Chill\PersonBundle\Controller\AccompanyingPeriodCommentApiController; use Chill\PersonBundle\Controller\AccompanyingPeriodResourceApiController; +use Chill\PersonBundle\Controller\AdministrativeStatusController; use Chill\PersonBundle\Controller\EmploymentStatusController; use Chill\PersonBundle\Controller\HouseholdCompositionTypeApiController; use Chill\PersonBundle\Controller\RelationApiController; use Chill\PersonBundle\Doctrine\DQL\AddressPart; use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Entity\AdministrativeStatus; use Chill\PersonBundle\Entity\EmploymentStatus; +use Chill\PersonBundle\Form\AdministrativeStatusType; use Chill\PersonBundle\Form\EmploymentStatusType; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodCommentVoter; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodResourceVoter; @@ -195,6 +198,28 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac ], ], ], + [ + 'class' => AdministrativeStatus::class, + 'name' => 'administrative_status', + 'base_path' => '/admin/administrative', + 'base_role' => 'ROLE_ADMIN', + 'form_class' => AdministrativeStatusType::class, + 'controller' => AdministrativeStatusController::class, + 'actions' => [ + 'index' => [ + 'role' => 'ROLE_ADMIN', + 'template' => '@ChillPerson/AdministrativeStatus/index.html.twig', + ], + 'new' => [ + 'role' => 'ROLE_ADMIN', + 'template' => '@ChillPerson/AdministrativeStatus/new.html.twig', + ], + 'edit' => [ + 'role' => 'ROLE_ADMIN', + 'template' => '@ChillPerson/AdministrativeStatus/edit.html.twig', + ], + ], + ], [ 'class' => EmploymentStatus::class, 'name' => 'employment_status', diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php index 5f75f0d69..c0cdee8fa 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php @@ -86,6 +86,7 @@ class Configuration implements ConfigurationInterface ->append($this->addFieldNode('acceptEmail')) ->append($this->addFieldNode('deathdate')) ->append($this->addFieldNode('employment_status', 'hidden')) + ->append($this->addFieldNode('administrative_status', 'hidden')) ->arrayNode('alt_names') ->defaultValue([]) ->arrayPrototype() diff --git a/src/Bundle/ChillPersonBundle/Entity/AdministrativeStatus.php b/src/Bundle/ChillPersonBundle/Entity/AdministrativeStatus.php new file mode 100644 index 000000000..35260ae56 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Entity/AdministrativeStatus.php @@ -0,0 +1,80 @@ + AdministrativeStatus::class])] +#[ORM\Entity] +#[ORM\Table(name: 'chill_person_administrative_status')] +class AdministrativeStatus +{ + #[Serializer\Groups(['read', 'docgen:read'])] + #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER)] + private ?int $id = null; + + #[Serializer\Groups(['read', 'docgen:read'])] + #[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON)] + #[Serializer\Context(['is-translatable' => true], groups: ['docgen:read'])] + private array $name = []; + + #[Serializer\Groups(['read'])] + #[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN)] + private bool $active = true; + + #[ORM\Column(type: \Doctrine\DBAL\Types\Types::FLOAT, name: 'ordering', nullable: true, options: ['default' => '0.0'])] + private float $order = 0; + + public function getId(): ?int + { + return $this->id; + } + + public function getActive(): ?bool + { + return $this->active; + } + + public function getName(): ?array + { + return $this->name; + } + + public function getOrder(): ?float + { + return $this->order; + } + + public function setActive(bool $active): self + { + $this->active = $active; + + return $this; + } + + public function setName(array $name): self + { + $this->name = $name; + + return $this; + } + + public function setOrder(float $order): self + { + $this->order = $order; + + return $this; + } +} diff --git a/src/Bundle/ChillPersonBundle/Entity/Person.php b/src/Bundle/ChillPersonBundle/Entity/Person.php index 04607a0e0..5d57f11af 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Person.php +++ b/src/Bundle/ChillPersonBundle/Entity/Person.php @@ -304,6 +304,13 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI #[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT)] private string $memo = ''; + /** + * The person's administrative status. + */ + #[ORM\ManyToOne(targetEntity: AdministrativeStatus::class)] + #[ORM\JoinColumn(nullable: true)] + private ?AdministrativeStatus $administrativeStatus = null; + /** * The person's mobile phone number. */ @@ -777,6 +784,11 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI return $this->addresses; } + public function getAdministrativeStatus(): ?AdministrativeStatus + { + return $this->administrativeStatus; + } + /** * Return the age of a person, calculated at the date 'now'. * @@ -1420,6 +1432,13 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI return $this; } + public function setAdministrativeStatus(?AdministrativeStatus $administrativeStatus): self + { + $this->administrativeStatus = $administrativeStatus; + + return $this; + } + public function setAcceptSMS(bool $acceptSMS): self { $this->acceptSMS = $acceptSMS; diff --git a/src/Bundle/ChillPersonBundle/Form/AdministrativeStatusType.php b/src/Bundle/ChillPersonBundle/Form/AdministrativeStatusType.php new file mode 100644 index 000000000..81f299538 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Form/AdministrativeStatusType.php @@ -0,0 +1,44 @@ +add('name', TranslatableStringFormType::class, [ + 'required' => true, + ]) + ->add('active', ChoiceType::class, [ + 'choices' => [ + 'Active' => true, + 'Inactive' => false, + ], + ]) + ->add('order', NumberType::class); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => AdministrativeStatus::class, + ]); + } +} diff --git a/src/Bundle/ChillPersonBundle/Form/PersonType.php b/src/Bundle/ChillPersonBundle/Form/PersonType.php index c03221f04..21d56dde7 100644 --- a/src/Bundle/ChillPersonBundle/Form/PersonType.php +++ b/src/Bundle/ChillPersonBundle/Form/PersonType.php @@ -26,6 +26,7 @@ use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\PersonPhone; use Chill\PersonBundle\Form\Type\PersonAltNameType; use Chill\PersonBundle\Form\Type\PersonPhoneType; +use Chill\PersonBundle\Form\Type\PickAdministrativeStatusType; use Chill\PersonBundle\Form\Type\PickEmploymentStatusType; use Chill\PersonBundle\Form\Type\PickGenderType; use Chill\PersonBundle\Form\Type\Select2MaritalStatusType; @@ -108,6 +109,11 @@ class PersonType extends AbstractType ->add('employmentStatus', PickEmploymentStatusType::class, ['required' => false]); } + if ('visible' === $this->config['administrative_status']) { + $builder + ->add('administrativeStatus', PickAdministrativeStatusType::class, ['required' => false]); + } + if ('visible' === $this->config['place_of_birth']) { $builder->add('placeOfBirth', TextType::class, [ 'required' => false, diff --git a/src/Bundle/ChillPersonBundle/Form/Type/PickAdministrativeStatusType.php b/src/Bundle/ChillPersonBundle/Form/Type/PickAdministrativeStatusType.php new file mode 100644 index 000000000..126c260f5 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Form/Type/PickAdministrativeStatusType.php @@ -0,0 +1,50 @@ +setDefault('label', 'Administrative Status') + ->setDefault( + 'choice_label', + fn (AdministrativeStatus $administrativeStatus): string => $this->translatableStringHelper->localize($administrativeStatus->getName()) + ) + ->setDefault( + 'query_builder', + static fn (EntityRepository $er): QueryBuilder => $er->createQueryBuilder('c') + ->where('c.active = true') + ->orderBy('c.order'), + ) + ->setDefault('placeholder', $this->translatableStringHelper->localize(['Select an option…'])) + ->setDefault('class', AdministrativeStatus::class); + } + + public function getParent() + { + return EntityType::class; + } +} diff --git a/src/Bundle/ChillPersonBundle/Menu/AdminPersonMenuBuilder.php b/src/Bundle/ChillPersonBundle/Menu/AdminPersonMenuBuilder.php index bfcb5e436..a361b107d 100644 --- a/src/Bundle/ChillPersonBundle/Menu/AdminPersonMenuBuilder.php +++ b/src/Bundle/ChillPersonBundle/Menu/AdminPersonMenuBuilder.php @@ -65,6 +65,12 @@ class AdminPersonMenuBuilder implements LocalMenuBuilderInterface ])->setExtras(['order' => 2035]); } + if ('visible' == $this->fields_visibility['administrative_status']) { + $menu->addChild('Administrative status', [ + 'route' => 'chill_crud_administrative_status_index', + ])->setExtras(['order' => 2036]); + } + $menu->addChild('person_admin.person_resource_kind', [ 'route' => 'chill_crud_person_resource-kind_index', ])->setExtras(['order' => 2040]); diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AdministrativeStatus/edit.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AdministrativeStatus/edit.html.twig new file mode 100644 index 000000000..4d55c480c --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/views/AdministrativeStatus/edit.html.twig @@ -0,0 +1,11 @@ +{% extends '@ChillMain/CRUD/Admin/index.html.twig' %} + +{% block title %} + {% include('@ChillMain/CRUD/_edit_title.html.twig') %} +{% endblock %} + +{% block admin_content %} + {% embed '@ChillMain/CRUD/_edit_content.html.twig' %} + {% block content_form_actions_save_and_show %}{% endblock %} + {% endembed %} +{% endblock admin_content %} diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AdministrativeStatus/index.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AdministrativeStatus/index.html.twig new file mode 100644 index 000000000..82f96c490 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/views/AdministrativeStatus/index.html.twig @@ -0,0 +1,42 @@ +{% extends '@ChillMain/CRUD/Admin/index.html.twig' %} + +{% block admin_content %} + {% embed '@ChillMain/CRUD/_index.html.twig' %} + {% block table_entities_thead_tr %} + id + {{ 'name'|trans }} + {{ 'active'|trans }} + {{ 'ordering'|trans }} + + {% endblock %} + {% block table_entities_tbody %} + {% for entity in entities %} + + {{ entity.id }} + {{ entity.name|localize_translatable_string }} + + {%- if entity.active -%} + + {%- else -%} + + {%- endif -%} + + {{ entity.order }} + + + + + {% endfor %} + {% endblock %} + + {% block actions_before %} +
  • + {{'Back to the admin'|trans}} +
  • + {% endblock %} + {% endembed %} +{% endblock %} diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AdministrativeStatus/new.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AdministrativeStatus/new.html.twig new file mode 100644 index 000000000..7c204dddd --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/views/AdministrativeStatus/new.html.twig @@ -0,0 +1,11 @@ +{% extends '@ChillMain/CRUD/Admin/index.html.twig' %} + +{% block title %} + {% include('@ChillMain/CRUD/_new_title.html.twig') %} +{% endblock %} + +{% block admin_content %} + {% embed '@ChillMain/CRUD/_new_content.html.twig' %} + {% block content_form_actions_save_and_show %}{% endblock %} + {% endembed %} +{% endblock admin_content %} diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Person/edit.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Person/edit.html.twig index cd856fb61..cb2d867c4 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/Person/edit.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/Person/edit.html.twig @@ -107,6 +107,9 @@ {%- if form.spokenLanguages is defined -%} {{ form_row(form.spokenLanguages, {'label' : 'Spoken languages'}) }} {%- endif -%} + {%- if form.administrativeStatus is defined -%} + {{ form_row(form.administrativeStatus, {'label' : 'Administrative status'}) }} + {%- endif -%} {%- if form.employmentStatus is defined -%} {{ form_row(form.employmentStatus, {'label' : 'Employment status'}) }} {%- endif -%} diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Person/view.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Person/view.html.twig index 144018627..74585c5f1 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/Person/view.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/Person/view.html.twig @@ -170,8 +170,20 @@ This view should receive those arguments: {%- endif -%} + {% if chill_person.fields.administrative_status == 'visible' %} +
    +
    {{ 'Administrative status'|trans }} :
    +
    + {% if person.administrativeStatus is not empty %} + {{ person.administrativeStatus.name|localize_translatable_string }} + {% else %} + {{ 'No data given'|trans }} + {% endif %} +
    +
    + {% endif %} + {% if chill_person.fields.employment_status == 'visible' %}
    - {% if chill_person.fields.employment_status == 'visible' %}
    {{ 'Employment status'|trans }} :
    {% if person.employmentStatus is not empty %} @@ -180,8 +192,8 @@ This view should receive those arguments: {{ 'No data given'|trans }} {% endif %}
    - {% endif %}
    + {% endif %} {%- if chill_person.fields.number_of_children == 'visible' -%}
    {{'Number of children'|trans}} :
    diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20241127160628.php b/src/Bundle/ChillPersonBundle/migrations/Version20241127160628.php new file mode 100644 index 000000000..5e657f6ce --- /dev/null +++ b/src/Bundle/ChillPersonBundle/migrations/Version20241127160628.php @@ -0,0 +1,43 @@ +addSql('CREATE SEQUENCE chill_person_administrative_status_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE TABLE chill_person_administrative_status (id INT NOT NULL, name JSON NOT NULL, active BOOLEAN NOT NULL, ordering DOUBLE PRECISION DEFAULT \'0.0\', PRIMARY KEY(id))'); + $this->addSql('ALTER TABLE chill_person_person ADD administrativeStatus_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_person_person ADD CONSTRAINT FK_BF210A146E64B00C FOREIGN KEY (administrativeStatus_id) REFERENCES chill_person_administrative_status (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_BF210A146E64B00C ON chill_person_person (administrativeStatus_id)'); + } + + public function down(Schema $schema): void + { + $this->addSql('DROP SEQUENCE chill_person_administrative_status_id_seq CASCADE'); + $this->addSql('ALTER TABLE chill_person_person DROP CONSTRAINT FK_BF210A146E64B00C'); + $this->addSql('DROP TABLE chill_person_administrative_status'); + $this->addSql('ALTER TABLE chill_person_person DROP administrativeStatus_id'); + } +} diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 6b3c5cd0e..269196f41 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -100,6 +100,7 @@ numberOfChildren: Nombre d'enfants contactInfo: Commentaire des contacts spokenLanguages: Langues parlées Employment status: Situation professionelle +Administrative status: Situation administrative # dédoublonnage @@ -648,6 +649,12 @@ Group people by country of birth: Grouper les usagers par pays de naissance Similar persons: Usagers similaires crud: + administrative_status: + index: + title: Situations administratives + add_new: Ajouter une nouvelle + title_new: Ajouter une situation administrative + title_edit: Modifier cette situation administrative closing_motive: index: title: Liste des motifs de clotûre From 98cf16704070bb6cd23652f60ff302ea1dccf83a Mon Sep 17 00:00:00 2001 From: Christophe Siraut Date: Wed, 18 Dec 2024 18:45:27 +0100 Subject: [PATCH 02/67] ChillPersonBundle: add aggregators for administrative status and employment status --- .../AdministrativeStatusAggregator.php | 76 +++++++++++++++++++ .../EmploymentStatusAggregator.php | 76 +++++++++++++++++++ .../AdministrativeStatusRepository.php | 51 +++++++++++++ ...dministrativeStatusRepositoryInterface.php | 27 +++++++ .../Repository/EmploymentStatusRepository.php | 51 +++++++++++++ .../EmploymentStatusRepositoryInterface.php | 27 +++++++ .../config/services/exports_person.yaml | 14 ++++ .../translations/messages.fr.yml | 2 + 8 files changed, 324 insertions(+) create mode 100644 src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/AdministrativeStatusAggregator.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/EmploymentStatusAggregator.php create mode 100644 src/Bundle/ChillPersonBundle/Repository/AdministrativeStatusRepository.php create mode 100644 src/Bundle/ChillPersonBundle/Repository/AdministrativeStatusRepositoryInterface.php create mode 100644 src/Bundle/ChillPersonBundle/Repository/EmploymentStatusRepository.php create mode 100644 src/Bundle/ChillPersonBundle/Repository/EmploymentStatusRepositoryInterface.php diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/AdministrativeStatusAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/AdministrativeStatusAggregator.php new file mode 100644 index 000000000..8bdc74f7f --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/AdministrativeStatusAggregator.php @@ -0,0 +1,76 @@ +leftJoin('person.administrativeStatus', 'admin_status'); + $qb->addSelect('admin_status.id as administrative_status_aggregator'); + + $qb->addGroupBy('administrative_status_aggregator'); + } + + public function applyOn() + { + return Declarations::PERSON_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) {} + + public function getFormDefaultData(): array + { + return []; + } + + public function getLabels($key, array $values, $data) + { + return function ($value): string { + if ('_header' === $value) { + return 'Administrative status'; + } + + if (null === $value || '' === $value) { + return ''; + } + + $g = $this->administrativeStatusRepository->find($value); + + return $this->translatableStringHelper->localize($g->getName()); + }; + } + + public function getQueryKeys($data) + { + return ['administrative_status_aggregator']; + } + + public function getTitle() + { + return 'Group people by administrative status'; + } +} diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/EmploymentStatusAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/EmploymentStatusAggregator.php new file mode 100644 index 000000000..359e48cf3 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/EmploymentStatusAggregator.php @@ -0,0 +1,76 @@ +leftJoin('person.employmentStatus', 'es'); + $qb->addSelect('es.id as employment_status_aggregator'); + + $qb->addGroupBy('employment_status_aggregator'); + } + + public function applyOn() + { + return Declarations::PERSON_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) {} + + public function getFormDefaultData(): array + { + return []; + } + + public function getLabels($key, array $values, $data) + { + return function ($value): string { + if ('_header' === $value) { + return 'Employment status'; + } + + if (null === $value || '' === $value) { + return ''; + } + + $g = $this->employmentStatusRepository->find($value); + + return $this->translatableStringHelper->localize($g->getName()); + }; + } + + public function getQueryKeys($data) + { + return ['employment_status_aggregator']; + } + + public function getTitle() + { + return 'Group people by employment status'; + } +} diff --git a/src/Bundle/ChillPersonBundle/Repository/AdministrativeStatusRepository.php b/src/Bundle/ChillPersonBundle/Repository/AdministrativeStatusRepository.php new file mode 100644 index 000000000..40254c395 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Repository/AdministrativeStatusRepository.php @@ -0,0 +1,51 @@ +repository = $entityManager->getRepository(AdministrativeStatus::class); + } + + public function find($id): ?AdministrativeStatus + { + return $this->repository->find($id); + } + + public function findAll(): array + { + return $this->repository->findAll(); + } + + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function findOneBy(array $criteria): ?AdministrativeStatus + { + return $this->findOneBy($criteria); + } + + public function getClassName(): string + { + return AdministrativeStatus::class; + } +} diff --git a/src/Bundle/ChillPersonBundle/Repository/AdministrativeStatusRepositoryInterface.php b/src/Bundle/ChillPersonBundle/Repository/AdministrativeStatusRepositoryInterface.php new file mode 100644 index 000000000..da40a117b --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Repository/AdministrativeStatusRepositoryInterface.php @@ -0,0 +1,27 @@ +repository = $entityManager->getRepository(EmploymentStatus::class); + } + + public function find($id): ?EmploymentStatus + { + return $this->repository->find($id); + } + + public function findAll(): array + { + return $this->repository->findAll(); + } + + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function findOneBy(array $criteria): ?EmploymentStatus + { + return $this->findOneBy($criteria); + } + + public function getClassName(): string + { + return EmploymentStatus::class; + } +} diff --git a/src/Bundle/ChillPersonBundle/Repository/EmploymentStatusRepositoryInterface.php b/src/Bundle/ChillPersonBundle/Repository/EmploymentStatusRepositoryInterface.php new file mode 100644 index 000000000..5d696cc9c --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Repository/EmploymentStatusRepositoryInterface.php @@ -0,0 +1,27 @@ + Date: Thu, 19 Dec 2024 10:31:14 +0100 Subject: [PATCH 03/67] ChillMainBundle: optionnaly mask aggegators in ExportType --- .../Form/Type/Export/ExportType.php | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Bundle/ChillMainBundle/Form/Type/Export/ExportType.php b/src/Bundle/ChillMainBundle/Form/Type/Export/ExportType.php index e5d0887f3..fe4c43830 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/ExportType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/ExportType.php @@ -18,6 +18,7 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; class ExportType extends AbstractType { @@ -29,7 +30,15 @@ class ExportType extends AbstractType final public const PICK_FORMATTER_KEY = 'pick_formatter'; - public function __construct(private readonly ExportManager $exportManager, private readonly SortExportElement $sortExportElement) {} + private array $personFieldsConfig; + + public function __construct( + private readonly ExportManager $exportManager, + private readonly SortExportElement $sortExportElement, + protected ParameterBagInterface $parameterBag, + ) { + $this->personFieldsConfig = $parameterBag->get('chill_person.person_fields'); + } public function buildForm(FormBuilderInterface $builder, array $options) { @@ -77,6 +86,17 @@ class ExportType extends AbstractType ); foreach ($aggregators as $alias => $aggregator) { + /* + * eventually mask aggregator + */ + if (str_starts_with((string) $alias, 'person_') and str_ends_with((string) $alias, '_aggregator')) { + $field = preg_replace(['/person_/', '/_aggregator/'], '', (string) $alias); + if (array_key_exists($field, $this->personFieldsConfig) and 'visible' !== $this->personFieldsConfig[$field]) { + continue; + } + } + + $aggregatorBuilder->add($alias, AggregatorType::class, [ 'aggregator_alias' => $alias, 'export_manager' => $this->exportManager, From fbdc0d32f070fc853b8906cc0574a7184bb6670b Mon Sep 17 00:00:00 2001 From: Christophe Siraut Date: Fri, 20 Dec 2024 11:28:36 +0100 Subject: [PATCH 04/67] ChillPersonBundle: Add numberOfDependents and numberOfDependentsWithDisabilities --- .../Controller/HouseholdMemberController.php | 9 +++- .../DependencyInjection/Configuration.php | 1 + .../Entity/Household/HouseholdComposition.php | 36 +++++++++++++ .../Form/HouseholdCompositionType.php | 25 ++++++++- .../components/Dates.vue | 51 +++++++++++++++++++ .../vuejs/HouseholdMembersEditor/js/i18n.js | 3 ++ .../HouseholdMembersEditor/store/index.js | 11 ++++ .../views/Household/summary.html.twig | 6 +++ .../HouseholdComposition/index.html.twig | 4 ++ .../Resources/views/Person/view.html.twig | 22 ++++++++ .../Normalizer/MembersEditorNormalizer.php | 4 ++ .../migrations/Version20241127160628.php | 3 -- .../migrations/Version20241220102357.php | 35 +++++++++++++ .../translations/messages+intl-icu.fr.yaml | 14 +++++ .../translations/messages.fr.yml | 2 + 15 files changed, 220 insertions(+), 6 deletions(-) create mode 100644 src/Bundle/ChillPersonBundle/migrations/Version20241220102357.php diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php index 07ab6da70..b9badff8a 100644 --- a/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php +++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php @@ -33,9 +33,12 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Security; use Symfony\Component\Serializer\Exception; use Symfony\Contracts\Translation\TranslatorInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; class HouseholdMemberController extends ApiController { + private array $fields_visibility; + public function __construct( private readonly UrlGeneratorInterface $generator, private readonly TranslatorInterface $translator, @@ -45,7 +48,10 @@ class HouseholdMemberController extends ApiController private readonly Security $security, private readonly PositionRepository $positionRepository, private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry, - ) {} + protected ParameterBagInterface $parameterBag, + ) { + $this->fields_visibility = $parameterBag->get('chill_person.person_fields'); + } #[Route(path: '/{_locale}/person/household/member/{id}/edit', name: 'chill_person_household_member_edit')] public function editMembership(Request $request, HouseholdMember $member): Response @@ -144,6 +150,7 @@ class HouseholdMemberController extends ApiController 'allowHouseholdCreate' => $allowHouseholdCreate ?? true, 'allowHouseholdSearch' => $allowHouseholdSearch ?? true, 'allowLeaveWithoutHousehold' => $allowLeaveWithoutHousehold ?? $request->query->has('allow_leave_without_household'), + 'displayDependents' => ('visible' == $this->fields_visibility['number_of_dependents']) ? true : false, ]; // context diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php index c0cdee8fa..d33ddfdc6 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php @@ -83,6 +83,7 @@ class Configuration implements ConfigurationInterface ->append($this->addFieldNode('accompanying_period')) ->append($this->addFieldNode('memo')) ->append($this->addFieldNode('number_of_children')) + ->append($this->addFieldNode('number_of_dependents', 'hidden')) ->append($this->addFieldNode('acceptEmail')) ->append($this->addFieldNode('deathdate')) ->append($this->addFieldNode('employment_status', 'hidden')) diff --git a/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdComposition.php b/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdComposition.php index 4aea2129c..ac84bb3fd 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdComposition.php +++ b/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdComposition.php @@ -58,6 +58,18 @@ class HouseholdComposition implements TrackCreationInterface, TrackUpdateInterfa #[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER, nullable: true, options: ['default' => null])] private ?int $numberOfChildren = null; + #[Assert\NotNull] + #[Assert\GreaterThanOrEqual(0, groups: ['Default', 'household_composition'])] + #[Serializer\Groups(['docgen:read'])] + #[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER, nullable: true, options: ['default' => null])] + private ?int $numberOfDependents = null; + + #[Assert\NotNull] + #[Assert\GreaterThanOrEqual(0, groups: ['Default', 'household_composition'])] + #[Serializer\Groups(['docgen:read'])] + #[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER, nullable: true, options: ['default' => null])] + private ?int $numberOfDependentsWithDisabilities = null; + #[Assert\NotNull(groups: ['Default', 'household_composition'])] #[Serializer\Groups(['docgen:read'])] #[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATE_IMMUTABLE, nullable: false)] @@ -98,6 +110,16 @@ class HouseholdComposition implements TrackCreationInterface, TrackUpdateInterfa return $this->numberOfChildren; } + public function getNumberOfDependents(): ?int + { + return $this->numberOfDependents; + } + + public function getNumberOfDependentsWithDisabilities(): ?int + { + return $this->numberOfDependentsWithDisabilities; + } + public function getStartDate(): ?\DateTimeImmutable { return $this->startDate; @@ -142,6 +164,20 @@ class HouseholdComposition implements TrackCreationInterface, TrackUpdateInterfa return $this; } + public function setNumberOfDependents(?int $numberOfDependents): HouseholdComposition + { + $this->numberOfDependents = $numberOfDependents; + + return $this; + } + + public function setNumberOfDependentsWithDisabilities(?int $numberOfDependentsWithDisabilities): HouseholdComposition + { + $this->numberOfDependentsWithDisabilities = $numberOfDependentsWithDisabilities; + + return $this; + } + public function setStartDate(?\DateTimeImmutable $startDate): HouseholdComposition { $this->startDate = $startDate; diff --git a/src/Bundle/ChillPersonBundle/Form/HouseholdCompositionType.php b/src/Bundle/ChillPersonBundle/Form/HouseholdCompositionType.php index 2df66039f..437a209e7 100644 --- a/src/Bundle/ChillPersonBundle/Form/HouseholdCompositionType.php +++ b/src/Bundle/ChillPersonBundle/Form/HouseholdCompositionType.php @@ -19,10 +19,19 @@ use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\IntegerType; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; class HouseholdCompositionType extends AbstractType { - public function __construct(private readonly HouseholdCompositionTypeRepository $householdCompositionTypeRepository, private readonly TranslatableStringHelperInterface $translatableStringHelper) {} + private array $fields_visibility; + + public function __construct( + private readonly HouseholdCompositionTypeRepository $householdCompositionTypeRepository, + private readonly TranslatableStringHelperInterface $translatableStringHelper, + protected ParameterBagInterface $parameterBag, + ) { + $this->fields_visibility = $parameterBag->get('chill_person.person_fields'); + } public function buildForm(FormBuilderInterface $builder, array $options) { @@ -42,7 +51,19 @@ class HouseholdCompositionType extends AbstractType ->add('numberOfChildren', IntegerType::class, [ 'required' => true, 'label' => 'household_composition.numberOfChildren', - ]) + ]); + if ('visible' == $this->fields_visibility['number_of_dependents']) { + $builder + ->add('numberOfDependents', IntegerType::class, [ + 'required' => true, + 'label' => 'household_composition.numberOfDependents', + ]) + ->add('numberOfDependentsWithDisabilities', IntegerType::class, [ + 'required' => true, + 'label' => 'household_composition.numberOfDependentsWithDisabilities', + ]); + } + $builder ->add('comment', CommentType::class, [ 'required' => false, ]); diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Dates.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Dates.vue index 854db2058..b5392d110 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Dates.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Dates.vue @@ -47,6 +47,36 @@ /> +
    + +
    + +
    +
    +
    + +
    + +
    +
    @@ -62,6 +92,11 @@ export default { computed: { ...mapState(["householdCompositionTypes"]), ...mapGetters(["isHouseholdNew"]), + displayDependents: { + get() { + return window.household_members_editor_data.displayDependents; + }, + }, householdCompositionType: { get() { if (this.$store.state.householdCompositionType !== null) { @@ -81,6 +116,22 @@ export default { this.$store.commit("setNumberOfChildren", value); }, }, + numberOfDependents: { + get() { + return this.$store.state.numberOfDependents; + }, + set(value) { + this.$store.commit("setNumberOfDependents", value); + }, + }, + numberOfDependentsWithDisabilities: { + get() { + return this.$store.state.numberOfDependentsWithDisabilities; + }, + set(value) { + this.$store.commit("setNumberOfDependentsWithDisabilities", value); + }, + }, startDate: { get() { return this.$store.state.startDate; diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/js/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/js/i18n.js index 4afecc448..425088f81 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/js/i18n.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/js/i18n.js @@ -91,6 +91,9 @@ const appMessages = { composition: "Composition familiale", household_composition: "Composition du ménage", number_of_children: "Nombre d'enfants mineurs au sein du ménage", + number_of_dependents: "Nombre de personnes majeures à charge", + number_of_dependents_with_disabilities: + "Nombre de personnes à charge reconnues handicapées", }, confirmation: { save: "Enregistrer", diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/store/index.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/store/index.js index d0ce9162f..7327d9003 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/store/index.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/store/index.js @@ -73,6 +73,8 @@ const store = createStore({ window.household_members_editor_expand_suggestions === 1, householdCompositionType: null, numberOfChildren: 0, + numberOfDependents: 0, + numberOfDependentsWithDisabilities: 0, addressesSuggestion: [], showAddressSuggestion: true, householdCompositionTypes: [], @@ -322,6 +324,9 @@ const store = createStore({ start_date: { datetime: datetimeToISO(ISOToDate(state.startDate)), }, + number_of_dependents: state.numberOfDependents, + number_of_dependents_with_disabilities: + state.numberOfDependentsWithDisabilities, }; } @@ -455,6 +460,12 @@ const store = createStore({ setNumberOfChildren(state, number) { state.numberOfChildren = Number.parseInt(number); }, + setNumberOfDependents(state, number) { + state.numberOfDependents = Number.parseInt(number); + }, + setNumberOfDependentsWithDisabilities(state, number) { + state.numberOfDependentsWithDisabilities = Number.parseInt(number); + }, addAddressesSuggestion(state, addresses) { let existingIds = state.addressesSuggestion.map((a) => a.address_id); diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Household/summary.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Household/summary.html.twig index 4f4a0841d..a142ffd5f 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/Household/summary.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/Household/summary.html.twig @@ -63,6 +63,12 @@

    {{ 'household_composition.numberOfChildren children in household'|trans({'numberOfChildren': currentComposition.numberOfChildren}) }} + {% if chill_person.fields.number_of_dependents == 'visible' %} +
    + {{ 'household_composition.numberOfDependents adult dependents'|trans({'numberOfDependents': currentComposition.numberOfDependents}) }} +
    + {{ 'household_composition.numberOfDependentsWithDisabilities dependents with disabilities'|trans({'numberOfDependentsWithDisabilities': currentComposition.numberOfDependentsWithDisabilities}) }} + {% endif %}

    {{ 'household_composition.Since'|trans({'startDate': currentComposition.startDate}) }} diff --git a/src/Bundle/ChillPersonBundle/Resources/views/HouseholdComposition/index.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/HouseholdComposition/index.html.twig index 7d3adc04a..2b0b8946b 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/HouseholdComposition/index.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/HouseholdComposition/index.html.twig @@ -21,6 +21,10 @@

    {{ c.householdCompositionType.label|localize_translatable_string }}

    {{ 'household_composition.numberOfChildren'|trans }}: {{ c.numberOfChildren }}

    + {% if chill_person.fields.number_of_dependents == 'visible' %} +

    {{ 'household_composition.numberOfDependents'|trans }}: {{ c.numberOfDependents }}

    +

    {{ 'household_composition.numberOfDependentsWithDisabilities'|trans }}: {{ c.numberOfDependentsWithDisabilities }}

    + {% endif %}
    {{ 'household_composition.Since'|trans({'startDate': c.startDate}) }}
    diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Person/view.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Person/view.html.twig index 74585c5f1..c8f4da3ec 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/Person/view.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/Person/view.html.twig @@ -206,6 +206,28 @@ This view should receive those arguments:
    {%- endif -%} + {%- if chill_person.fields.number_of_dependents == 'isible' -%} +
    +
    {{'Number of dependents'|trans}} :
    +
    + {% if person.numberOfDependents is not null %} + {{ person.numberOfDependents }} + {% else %} + {{ 'No data given'|trans }} + {% endif %} +
    +
    +
    +
    {{'Number of dependents with disabilities'|trans}} :
    +
    + {% if person.numberOfDependents is not null %} + {{ person.numberOfDependentsWithDisabilities }} + {% else %} + {{ 'No data given'|trans }} + {% endif %} +
    +
    + {%- endif -%} {%- if chill_person.fields.marital_status == 'visible' -%}
    {{'Marital status'|trans}} :
    diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php index 0e358483e..956bdf03c 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php @@ -147,6 +147,8 @@ class MembersEditorNormalizer implements DenormalizerAwareInterface, Denormalize if (null !== $data['composition']) { $compositionType = $this->denormalizer->denormalize($data['composition']['household_composition_type'], HouseholdCompositionType::class, $format, $context); $numberOfChildren = $data['composition']['number_of_children']; + $numberOfDependents = $data['composition']['number_of_dependents']; + $numberOfDependentsWithDisabilities = $data['composition']['number_of_dependents_with_disabilities']; $startDate = $this->denormalizer->denormalize($data['composition']['start_date'], \DateTimeImmutable::class, $format, $context); if (null === $compositionType) { @@ -156,6 +158,8 @@ class MembersEditorNormalizer implements DenormalizerAwareInterface, Denormalize $householdComposition = (new HouseholdComposition()) ->setHouseholdCompositionType($compositionType) ->setNumberOfChildren($numberOfChildren) + ->setNumberOfDependents($numberOfDependents) + ->setNumberOfDependentsWithDisabilities($numberOfDependentsWithDisabilities) ->setStartDate($startDate); $household->addComposition($householdComposition); diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20241127160628.php b/src/Bundle/ChillPersonBundle/migrations/Version20241127160628.php index 5e657f6ce..cd6a67b6d 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20241127160628.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20241127160628.php @@ -14,9 +14,6 @@ namespace Chill\Migrations\Person; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; -/** - * Auto-generated Migration: Please modify to your needs! - */ final class Version20241127160628 extends AbstractMigration { public function getDescription(): string diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20241220102357.php b/src/Bundle/ChillPersonBundle/migrations/Version20241220102357.php new file mode 100644 index 000000000..123efdb1a --- /dev/null +++ b/src/Bundle/ChillPersonBundle/migrations/Version20241220102357.php @@ -0,0 +1,35 @@ +addSql('ALTER TABLE chill_person_household_composition ADD numberOfDependents INT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_person_household_composition ADD numberOfDependentsWithDisabilities INT DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE chill_person_household_composition DROP numberOfDependents'); + $this->addSql('ALTER TABLE chill_person_household_composition DROP numberOfDependentsWithDisabilities'); + } +} diff --git a/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml b/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml index 76a8606af..830e21d2d 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml +++ b/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml @@ -116,6 +116,20 @@ household_composition: few {# enfants dans le ménage} other {# enfants dans le ménage} } + numberOfDependents adult dependents: >- + {numberOfDependents, plural, + =0 {Aucune personne majeure à charge} + one {1 personne majeure à charge} + few {# personnes majeures à charge} + other {# personnes majeures à charge} + } + numberOfDependentsWithDisabilities dependents with disabilities: >- + {numberOfDependentsWithDisabilities, plural, + =0 {Aucune personne à charge reconnue handicapée} + one {1 personne à charge reconnue handicapée} + few {# personnes à charge reconnue handicapée} + other {# personnes à charge reconnue handicapée} + } periods: title: Parcours d'accompagnement (n°{id}) diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 1759cedc3..c33b6be4a 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -963,6 +963,8 @@ household_composition: Add a composition: Ajouter une composition familiale Update composition: Modifier la composition familiale Create: Créér une nouvelle composition familiale + numberOfDependents: Nombre de personnes majeures à charges + numberOfDependentsWithDisabilities: Nombre de personnes à charge reconnues handicapées # docgen Linked evaluations: Évaluations associées From bc7f0907ab151886457cd395ef08667fdb29d2f0 Mon Sep 17 00:00:00 2001 From: Christophe Siraut Date: Mon, 3 Feb 2025 14:05:08 +0100 Subject: [PATCH 05/67] doc: add languages population command --- docs/source/installation/installation-production.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/installation/installation-production.rst b/docs/source/installation/installation-production.rst index 30e8c91ce..c12581265 100644 --- a/docs/source/installation/installation-production.rst +++ b/docs/source/installation/installation-production.rst @@ -109,6 +109,8 @@ To continue the installation process, you will have to run migrations: symfony console messenger:setup-transports # prepare some views symfony console chill:db:sync-views + # load languages data + symfony console chill:main:languages:populate # generate jwt token, required for some api features (webdav access, ...) symfony console lexik:jwt:generate-keypair From 02c524dd79484571a3a3ceb47c0d73b61a361f54 Mon Sep 17 00:00:00 2001 From: Christophe Siraut Date: Fri, 7 Feb 2025 10:53:53 +0100 Subject: [PATCH 06/67] doc: chill:main:address-ref-from-best-addresse requires a language code --- docs/source/installation/load-addresses.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/source/installation/load-addresses.rst b/docs/source/installation/load-addresses.rst index 85c29d618..641325dee 100644 --- a/docs/source/installation/load-addresses.rst +++ b/docs/source/installation/load-addresses.rst @@ -41,16 +41,18 @@ Postal code are loaded from this database. There is no need to load postal codes The data are prepared for Chill (`See this repository `_). One can select postal code by his first number (:code:`1xxx` for postal codes from 1000 to 1999), or a limited list for development purpose. +The command expects a language code as first argument. + .. code-block:: bash # load postal code from 1000 to 3999: - bin/console chill:main:address-ref-from-best-addresse 1xxx 2xxx 3xxx + bin/console chill:main:address-ref-from-best-addresse fr 1xxx 2xxx 3xxx # load only an extract (for dev purposes) - bin/console chill:main:address-ref-from-best-addresse extract + bin/console chill:main:address-ref-from-best-addresse fr extract # load full addresses (discouraged) - bin/console chill:main:address-ref-from-best-addresse full + bin/console chill:main:address-ref-from-best-addresse fr full .. note:: From 03717a1a878a1336b1d68989b0b9abade58d6c2a Mon Sep 17 00:00:00 2001 From: Christophe Siraut Date: Fri, 20 Dec 2024 11:28:36 +0100 Subject: [PATCH 07/67] ChillPersonBundle: move numberOfDependents configuration to a new household node; extend AdministrativeStatusRepository and EmploymentStatusRepository from ServiceEntityRepository --- .../Controller/HouseholdMemberController.php | 6 +-- .../ChillPersonExtension.php | 21 +++++++++++ .../DependencyInjection/Configuration.php | 6 +++ .../Entity/AdministrativeStatus.php | 3 +- .../Entity/EmploymentStatus.php | 3 +- .../Form/HouseholdCompositionType.php | 6 +-- .../AdministrativeStatusRepository.php | 37 +++---------------- ...dministrativeStatusRepositoryInterface.php | 27 -------------- .../Repository/EmploymentStatusRepository.php | 37 +++---------------- .../EmploymentStatusRepositoryInterface.php | 27 -------------- .../views/Household/summary.html.twig | 2 +- .../HouseholdComposition/index.html.twig | 2 +- 12 files changed, 49 insertions(+), 128 deletions(-) delete mode 100644 src/Bundle/ChillPersonBundle/Repository/AdministrativeStatusRepositoryInterface.php delete mode 100644 src/Bundle/ChillPersonBundle/Repository/EmploymentStatusRepositoryInterface.php diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php index b9badff8a..fd35ef31b 100644 --- a/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php +++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php @@ -37,7 +37,7 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; class HouseholdMemberController extends ApiController { - private array $fields_visibility; + private array $household_fields_visibility; public function __construct( private readonly UrlGeneratorInterface $generator, @@ -50,7 +50,7 @@ class HouseholdMemberController extends ApiController private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry, protected ParameterBagInterface $parameterBag, ) { - $this->fields_visibility = $parameterBag->get('chill_person.person_fields'); + $this->household_fields_visibility = $parameterBag->get('chill_person.household_fields'); } #[Route(path: '/{_locale}/person/household/member/{id}/edit', name: 'chill_person_household_member_edit')] @@ -150,7 +150,7 @@ class HouseholdMemberController extends ApiController 'allowHouseholdCreate' => $allowHouseholdCreate ?? true, 'allowHouseholdSearch' => $allowHouseholdSearch ?? true, 'allowLeaveWithoutHousehold' => $allowLeaveWithoutHousehold ?? $request->query->has('allow_leave_without_household'), - 'displayDependents' => ('visible' == $this->fields_visibility['number_of_dependents']) ? true : false, + 'displayDependents' => ('visible' == $this->household_fields_visibility['number_of_dependents']) ? true : false, ]; // context diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php index 8fddd477d..40393f79e 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php @@ -60,6 +60,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac $this->handlePersonFieldsParameters($container, $config['person_fields']); $this->handleAccompanyingPeriodsFieldsParameters($container, $config['accompanying_periods_fields']); + $this->handleHouseholdFieldsParameters($container, $config['household_fields']); $container->setParameter( 'chill_person.allow_multiple_simultaneous_accompanying_periods', @@ -135,6 +136,9 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'chill_accompanying_periods' => [ 'fields' => $config['accompanying_periods_fields'], ], + 'chill_household' => [ + 'fields' => $config['household_fields'], + ], ], 'form_themes' => ['@ChillPerson/Export/ListPersonFormFields.html.twig'], ]; @@ -1142,6 +1146,23 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac } } + private function handleHouseholdFieldsParameters(ContainerBuilder $container, $config) + { + $container->setParameter('chill_person.household_fields', $config); + + foreach ($config as $key => $value) { + switch ($key) { + case 'enabled': + break; + + default: + $container->setParameter('chill_person.household_fields.'.$key, $value); + + break; + } + } + } + private function handlePersonFieldsParameters(ContainerBuilder $container, $config) { if (\array_key_exists('enabled', $config)) { diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php index d33ddfdc6..12c8b4c5b 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php @@ -110,6 +110,12 @@ class Configuration implements ConfigurationInterface ->end() ->end() // children for 'person_fields', parent = array 'person_fields' ->end() // person_fields, parent = children of root + ->arrayNode('household_fields') + ->canBeDisabled() + ->children() + ->append($this->addFieldNode('number_of_dependents', 'hidden')) + ->end() + ->end() ->arrayNode('accompanying_periods_fields') ->canBeDisabled() ->children() diff --git a/src/Bundle/ChillPersonBundle/Entity/AdministrativeStatus.php b/src/Bundle/ChillPersonBundle/Entity/AdministrativeStatus.php index 35260ae56..23d451f48 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AdministrativeStatus.php +++ b/src/Bundle/ChillPersonBundle/Entity/AdministrativeStatus.php @@ -11,11 +11,12 @@ declare(strict_types=1); namespace Chill\PersonBundle\Entity; +use Chill\PersonBundle\Repository\AdministrativeStatusRepository; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation as Serializer; #[Serializer\DiscriminatorMap(typeProperty: 'type', mapping: ['chill_person_administrative_status' => AdministrativeStatus::class])] -#[ORM\Entity] +#[ORM\Entity(repositoryClass: AdministrativeStatusRepository::class)] #[ORM\Table(name: 'chill_person_administrative_status')] class AdministrativeStatus { diff --git a/src/Bundle/ChillPersonBundle/Entity/EmploymentStatus.php b/src/Bundle/ChillPersonBundle/Entity/EmploymentStatus.php index 08b1f45ac..83b3c65f5 100644 --- a/src/Bundle/ChillPersonBundle/Entity/EmploymentStatus.php +++ b/src/Bundle/ChillPersonBundle/Entity/EmploymentStatus.php @@ -11,11 +11,12 @@ declare(strict_types=1); namespace Chill\PersonBundle\Entity; +use Chill\PersonBundle\Repository\EmploymentStatusRepository; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation as Serializer; #[Serializer\DiscriminatorMap(typeProperty: 'type', mapping: ['chill_person_employment_status' => EmploymentStatus::class])] -#[ORM\Entity] +#[ORM\Entity(repositoryClass: EmploymentStatusRepository::class)] #[ORM\Table(name: 'chill_person_employment_status')] class EmploymentStatus { diff --git a/src/Bundle/ChillPersonBundle/Form/HouseholdCompositionType.php b/src/Bundle/ChillPersonBundle/Form/HouseholdCompositionType.php index 437a209e7..b0b7fbef5 100644 --- a/src/Bundle/ChillPersonBundle/Form/HouseholdCompositionType.php +++ b/src/Bundle/ChillPersonBundle/Form/HouseholdCompositionType.php @@ -23,14 +23,14 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; class HouseholdCompositionType extends AbstractType { - private array $fields_visibility; + private array $household_fields_visibility; public function __construct( private readonly HouseholdCompositionTypeRepository $householdCompositionTypeRepository, private readonly TranslatableStringHelperInterface $translatableStringHelper, protected ParameterBagInterface $parameterBag, ) { - $this->fields_visibility = $parameterBag->get('chill_person.person_fields'); + $this->household_fields_visibility = $parameterBag->get('chill_person.household_fields'); } public function buildForm(FormBuilderInterface $builder, array $options) @@ -52,7 +52,7 @@ class HouseholdCompositionType extends AbstractType 'required' => true, 'label' => 'household_composition.numberOfChildren', ]); - if ('visible' == $this->fields_visibility['number_of_dependents']) { + if ('visible' == $this->household_fields_visibility['number_of_dependents']) { $builder ->add('numberOfDependents', IntegerType::class, [ 'required' => true, diff --git a/src/Bundle/ChillPersonBundle/Repository/AdministrativeStatusRepository.php b/src/Bundle/ChillPersonBundle/Repository/AdministrativeStatusRepository.php index 40254c395..637db23c5 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AdministrativeStatusRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/AdministrativeStatusRepository.php @@ -12,40 +12,13 @@ declare(strict_types=1); namespace Chill\PersonBundle\Repository; use Chill\PersonBundle\Entity\AdministrativeStatus; -use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\EntityRepository; +use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\Persistence\ManagerRegistry; -class AdministrativeStatusRepository implements AdministrativeStatusRepositoryInterface +class AdministrativeStatusRepository extends ServiceEntityRepository { - private readonly EntityRepository $repository; - - public function __construct(EntityManagerInterface $entityManager) + public function __construct(ManagerRegistry $registry) { - $this->repository = $entityManager->getRepository(AdministrativeStatus::class); - } - - public function find($id): ?AdministrativeStatus - { - return $this->repository->find($id); - } - - public function findAll(): array - { - return $this->repository->findAll(); - } - - public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array - { - return $this->repository->findBy($criteria, $orderBy, $limit, $offset); - } - - public function findOneBy(array $criteria): ?AdministrativeStatus - { - return $this->findOneBy($criteria); - } - - public function getClassName(): string - { - return AdministrativeStatus::class; + parent::__construct($registry, AdministrativeStatus::class); } } diff --git a/src/Bundle/ChillPersonBundle/Repository/AdministrativeStatusRepositoryInterface.php b/src/Bundle/ChillPersonBundle/Repository/AdministrativeStatusRepositoryInterface.php deleted file mode 100644 index da40a117b..000000000 --- a/src/Bundle/ChillPersonBundle/Repository/AdministrativeStatusRepositoryInterface.php +++ /dev/null @@ -1,27 +0,0 @@ -repository = $entityManager->getRepository(EmploymentStatus::class); - } - - public function find($id): ?EmploymentStatus - { - return $this->repository->find($id); - } - - public function findAll(): array - { - return $this->repository->findAll(); - } - - public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array - { - return $this->repository->findBy($criteria, $orderBy, $limit, $offset); - } - - public function findOneBy(array $criteria): ?EmploymentStatus - { - return $this->findOneBy($criteria); - } - - public function getClassName(): string - { - return EmploymentStatus::class; + parent::__construct($registry, EmploymentStatus::class); } } diff --git a/src/Bundle/ChillPersonBundle/Repository/EmploymentStatusRepositoryInterface.php b/src/Bundle/ChillPersonBundle/Repository/EmploymentStatusRepositoryInterface.php deleted file mode 100644 index 5d696cc9c..000000000 --- a/src/Bundle/ChillPersonBundle/Repository/EmploymentStatusRepositoryInterface.php +++ /dev/null @@ -1,27 +0,0 @@ -

    {{ 'household_composition.numberOfChildren children in household'|trans({'numberOfChildren': currentComposition.numberOfChildren}) }} - {% if chill_person.fields.number_of_dependents == 'visible' %} + {% if chill_household.fields.number_of_dependents == 'visible' %}
    {{ 'household_composition.numberOfDependents adult dependents'|trans({'numberOfDependents': currentComposition.numberOfDependents}) }}
    diff --git a/src/Bundle/ChillPersonBundle/Resources/views/HouseholdComposition/index.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/HouseholdComposition/index.html.twig index 2b0b8946b..f3c931707 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/HouseholdComposition/index.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/HouseholdComposition/index.html.twig @@ -21,7 +21,7 @@

    {{ c.householdCompositionType.label|localize_translatable_string }}

    {{ 'household_composition.numberOfChildren'|trans }}: {{ c.numberOfChildren }}

    - {% if chill_person.fields.number_of_dependents == 'visible' %} + {% if chill_household.fields.number_of_dependents == 'visible' %}

    {{ 'household_composition.numberOfDependents'|trans }}: {{ c.numberOfDependents }}

    {{ 'household_composition.numberOfDependentsWithDisabilities'|trans }}: {{ c.numberOfDependentsWithDisabilities }}

    {% endif %} From 8db8f5fdf57f8d3133010f59c0f548082df0bb84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 14 Feb 2025 12:11:28 +0100 Subject: [PATCH 08/67] Refactor username mapping in activity context filter. Replaced array_map with a foreach loop for clarity and maintainability when extracting usernames from work referrers. This ensures better readability and aligns with coding standards. --- .changes/unreleased/Fixed-20250214-121010.yaml | 6 ++++++ .../ListActivitiesByAccompanyingPeriodContext.php | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 .changes/unreleased/Fixed-20250214-121010.yaml diff --git a/.changes/unreleased/Fixed-20250214-121010.yaml b/.changes/unreleased/Fixed-20250214-121010.yaml new file mode 100644 index 000000000..d7000c11c --- /dev/null +++ b/.changes/unreleased/Fixed-20250214-121010.yaml @@ -0,0 +1,6 @@ +kind: Fixed +body: fix generation of document with accompanying period context, and list of activities and works +time: 2025-02-14T12:10:10.920355454+01:00 +custom: + Issue: "" + SchemaChange: No schema change diff --git a/src/Bundle/ChillActivityBundle/Service/DocGenerator/ListActivitiesByAccompanyingPeriodContext.php b/src/Bundle/ChillActivityBundle/Service/DocGenerator/ListActivitiesByAccompanyingPeriodContext.php index 56b9de408..9b473309e 100644 --- a/src/Bundle/ChillActivityBundle/Service/DocGenerator/ListActivitiesByAccompanyingPeriodContext.php +++ b/src/Bundle/ChillActivityBundle/Service/DocGenerator/ListActivitiesByAccompanyingPeriodContext.php @@ -143,7 +143,10 @@ class ListActivitiesByAccompanyingPeriodContext implements array_filter( $works, function ($work) use ($user) { - $workUsernames = array_map(static fn (User $user) => $user['username'], $work['referrers'] ?? []); + $workUsernames = []; + foreach ($work['referrers'] as $referrer) { + $workUsernames[] = $referrer['username']; + } return \in_array($user->getUserIdentifier(), $workUsernames, true); } From 0a34f9086f98e5a1d9b3b5d31ba4ea8b10799fea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 14 Feb 2025 15:08:42 +0100 Subject: [PATCH 09/67] Add event subscriber for document restoration on cancel Implement an event subscriber to restore documents to their last kept version when a workflow transition ends in a non-positive final state. Includes corresponding unit tests and an unreleased feature change log entry. --- .../unreleased/Feature-20250214-150328.yaml | 6 + ...eDocumentToEditableEventSubscriberTest.php | 156 ++++++++++++++++++ ...storeDocumentToEditableEventSubscriber.php | 71 ++++++++ 3 files changed, 233 insertions(+) create mode 100644 .changes/unreleased/Feature-20250214-150328.yaml create mode 100644 src/Bundle/ChillMainBundle/Tests/Workflow/EventSubscriber/OnCancelRestoreDocumentToEditableEventSubscriberTest.php create mode 100644 src/Bundle/ChillMainBundle/Workflow/EventSubscriber/OnCancelRestoreDocumentToEditableEventSubscriber.php diff --git a/.changes/unreleased/Feature-20250214-150328.yaml b/.changes/unreleased/Feature-20250214-150328.yaml new file mode 100644 index 000000000..9ca416984 --- /dev/null +++ b/.changes/unreleased/Feature-20250214-150328.yaml @@ -0,0 +1,6 @@ +kind: Feature +body: Restore document to previous kept version when a workflow is canceled +time: 2025-02-14T15:03:28.707250207+01:00 +custom: + Issue: "360" + SchemaChange: No schema change diff --git a/src/Bundle/ChillMainBundle/Tests/Workflow/EventSubscriber/OnCancelRestoreDocumentToEditableEventSubscriberTest.php b/src/Bundle/ChillMainBundle/Tests/Workflow/EventSubscriber/OnCancelRestoreDocumentToEditableEventSubscriberTest.php new file mode 100644 index 000000000..ebb90eda2 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Tests/Workflow/EventSubscriber/OnCancelRestoreDocumentToEditableEventSubscriberTest.php @@ -0,0 +1,156 @@ +setMetadataStore( + new InMemoryMetadataStore( + placesMetadata: [ + 'final' => ['isFinal' => true], + 'cancel' => ['isFinal' => true, 'isFinalPositive' => false], + ] + ) + ); + + $registry = new Registry(); + $workflow = new Workflow($builder->build(), new EntityWorkflowMarkingStore(), $eventDispatcher = new EventDispatcher(), 'dummy'); + + $manager = $this->createMock(EntityWorkflowManager::class); + $manager->method('getAssociatedStoredObject')->willReturn($storedObject); + + $eventSubscriber = new OnCancelRestoreDocumentToEditableEventSubscriber( + $registry, + $manager, + $storedObjectRestore + ); + $eventDispatcher->addSubscriber($eventSubscriber); + + $registry->addWorkflow($workflow, new class () implements WorkflowSupportStrategyInterface { + public function supports(WorkflowInterface $workflow, object $subject): bool + { + return true; + } + }); + + return $registry; + } + + public function testOnCancelRestoreDocumentToEditableExpectsRestoring(): void + { + $storedObject = new StoredObject(); + $version = $storedObject->registerVersion(); + new StoredObjectPointInTime($version, StoredObjectPointInTimeReasonEnum::KEEP_BEFORE_CONVERSION); + $storedObject->registerVersion(); + + $restore = $this->createMock(StoredObjectRestoreInterface::class); + $restore->expects($this->once())->method('restore')->with($version); + + $registry = $this->buildRegistry($restore, $storedObject); + $entityWorkflow = (new EntityWorkflow())->setWorkflowName('dummy'); + + $workflow = $registry->get($entityWorkflow, $entityWorkflow->getWorkflowName()); + $context = new WorkflowTransitionContextDTO($entityWorkflow); + + $workflow->apply($entityWorkflow, 'to_cancel', [ + 'context' => $context, + 'transition' => 'to_cancel', + 'transitionAt' => new \DateTimeImmutable('now'), + ]); + } + + public function testOnCancelRestoreDocumentDoNotExpectRestoring(): void + { + $storedObject = new StoredObject(); + $version = $storedObject->registerVersion(); + new StoredObjectPointInTime($version, StoredObjectPointInTimeReasonEnum::KEEP_BEFORE_CONVERSION); + $storedObject->registerVersion(); + + $restore = $this->createMock(StoredObjectRestoreInterface::class); + $restore->expects($this->never())->method('restore')->withAnyParameters(); + + $registry = $this->buildRegistry($restore, $storedObject); + $entityWorkflow = (new EntityWorkflow())->setWorkflowName('dummy'); + + $workflow = $registry->get($entityWorkflow, $entityWorkflow->getWorkflowName()); + $context = new WorkflowTransitionContextDTO($entityWorkflow); + + $workflow->apply($entityWorkflow, 'to_intermediate', [ + 'context' => $context, + 'transition' => 'to_intermediate', + 'transitionAt' => new \DateTimeImmutable('now'), + ]); + + $workflow->apply($entityWorkflow, 'intermediate_to_final', [ + 'context' => $context, + 'transition' => 'intermediate_to_final', + 'transitionAt' => new \DateTimeImmutable('now'), + ]); + } + + public function testOnCancelRestoreDocumentToEditableToCancelStoredObjectWithoutKepts(): void + { + $storedObject = new StoredObject(); + $storedObject->registerVersion(); + + $restore = $this->createMock(StoredObjectRestoreInterface::class); + $restore->expects($this->never())->method('restore')->withAnyParameters(); + + $registry = $this->buildRegistry($restore, $storedObject); + $entityWorkflow = (new EntityWorkflow())->setWorkflowName('dummy'); + + $workflow = $registry->get($entityWorkflow, $entityWorkflow->getWorkflowName()); + $context = new WorkflowTransitionContextDTO($entityWorkflow); + + $workflow->apply($entityWorkflow, 'to_cancel', [ + 'context' => $context, + 'transition' => 'to_cancel', + 'transitionAt' => new \DateTimeImmutable('now'), + ]); + } +} diff --git a/src/Bundle/ChillMainBundle/Workflow/EventSubscriber/OnCancelRestoreDocumentToEditableEventSubscriber.php b/src/Bundle/ChillMainBundle/Workflow/EventSubscriber/OnCancelRestoreDocumentToEditableEventSubscriber.php new file mode 100644 index 000000000..da5b3da5a --- /dev/null +++ b/src/Bundle/ChillMainBundle/Workflow/EventSubscriber/OnCancelRestoreDocumentToEditableEventSubscriber.php @@ -0,0 +1,71 @@ + ['onCancelRestoreDocumentToEditable', 0]]; + } + + public function onCancelRestoreDocumentToEditable(TransitionEvent $event): void + { + $entityWorkflow = $event->getSubject(); + + if (!$entityWorkflow instanceof EntityWorkflow) { + return; + } + + $workflow = $this->registry->get($entityWorkflow, $entityWorkflow->getWorkflowName()); + + foreach ($event->getTransition()->getTos() as $place) { + $metadata = $workflow->getMetadataStore()->getPlaceMetadata($place); + + if (($metadata['isFinal'] ?? false) && !($metadata['isFinalPositive'] ?? true)) { + $this->restoreDocument($entityWorkflow); + + return; + } + } + } + + private function restoreDocument(EntityWorkflow $entityWorkflow): void + { + $storedObject = $this->manager->getAssociatedStoredObject($entityWorkflow); + + if (null === $storedObject) { + return; + } + + $version = $storedObject->getLastKeptBeforeConversionVersion(); + + if (null === $version) { + return; + } + + $this->storedObjectRestore->restore($storedObject->getLastKeptBeforeConversionVersion()); + } +} From 10eaebf610195a445020bc900d7e4695935ce71a Mon Sep 17 00:00:00 2001 From: LenaertsJ Date: Mon, 17 Feb 2025 12:21:10 +0000 Subject: [PATCH 10/67] =?UTF-8?q?Resolve=20"Proposer=20en=20plus=20du=20r?= =?UTF-8?q?=C3=A9f=C3=A9rent=20de=20parcours=20les=20agents=20traitants=20?= =?UTF-8?q?saisis=20dans=20toutes=20les=20cations=20d'accompagnement=20du?= =?UTF-8?q?=20parcours"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../unreleased/Feature-20250130-120207.yaml | 6 ++++ .../Resources/public/vuejs/Activity/store.js | 30 ++++++++++++++++--- .../AccompanyingCourseApiController.php | 18 +++++++++-- .../ChillPersonBundle/chill.api.specs.yaml | 23 ++++++++++++++ 4 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 .changes/unreleased/Feature-20250130-120207.yaml diff --git a/.changes/unreleased/Feature-20250130-120207.yaml b/.changes/unreleased/Feature-20250130-120207.yaml new file mode 100644 index 000000000..c707205ad --- /dev/null +++ b/.changes/unreleased/Feature-20250130-120207.yaml @@ -0,0 +1,6 @@ +kind: Feature +body: Suggest all referrers within actions of the accompanying period when creating an activity +time: 2025-01-30T12:02:07.053587034+01:00 +custom: + Issue: "349" + SchemaChange: No schema change diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/store.js b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/store.js index 26edac646..c910d7318 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/store.js +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/store.js @@ -26,6 +26,7 @@ const store = createStore({ state: { me: null, activity: window.activity, + accompanyingPeriodWorks: [], socialIssuesOther: [], socialActionsList: [], availableLocations: [], @@ -41,7 +42,7 @@ const store = createStore({ const allEntities = [ ...store.getters.suggestedPersons, ...store.getters.suggestedRequestor, - ...store.getters.suggestedUser, + ...store.getters.suggestedUsers, ...store.getters.suggestedResources, ]; const uniqueIds = [ @@ -80,8 +81,7 @@ const store = createStore({ state.activity.activityType.thirdPartiesVisible !== 0), ); }, - suggestedUser(state) { - // console.log('current user', state.me) + suggestedUsers(state) { const existingUserIds = state.activity.users.map((p) => p.id); let suggestedUsers = state.activity.activityType.usersVisible === 0 @@ -90,11 +90,18 @@ const store = createStore({ (u) => u !== null && !existingUserIds.includes(u.id), ); + state.accompanyingPeriodWorks.forEach((work) => { + work.referrers.forEach((r) => { + if (!existingUserIds.includes(r.id)) { + suggestedUsers.push(r); + } + }); + }); // Add the current user from the state if (state.me && !existingUserIds.includes(state.me.id)) { suggestedUsers.push(state.me); } - console.log("suggested users", suggestedUsers); + // console.log("suggested users", suggestedUsers); return suggestedUsers; }, @@ -223,6 +230,9 @@ const store = createStore({ addAvailableLocationGroup(state, group) { state.availableLocations.push(group); }, + setAccompanyingPeriodWorks(state, works) { + state.accompanyingPeriodWorks = works; + }, }, actions: { addIssueSelected({ commit }, issue) { @@ -341,6 +351,17 @@ const store = createStore({ } commit("updateLocation", value); }, + async fetchAccompanyingPeriodWorks({ state, commit }) { + const accompanyingPeriodId = state.activity.accompanyingPeriod.id; + const url = `/api/1.0/person/accompanying-course/${accompanyingPeriodId}/works.json`; + try { + const works = await makeFetch("GET", url); + // console.log("works", works); + commit("setAccompanyingPeriodWorks", works); + } catch (error) { + console.error("Failed to fetch accompanying period works:", error); + } + }, getWhoAmI({ commit }) { const url = `/api/1.0/main/whoami.json`; makeFetch("GET", url).then((user) => { @@ -353,5 +374,6 @@ const store = createStore({ store.dispatch("getWhoAmI"); prepareLocations(store); +store.dispatch("fetchAccompanyingPeriodWorks"); export default store; diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php index 262a4a03d..ac7c7dec4 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php @@ -25,7 +25,7 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\SocialWork\SocialIssue; use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent; -use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepository; +use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository; use Chill\PersonBundle\Repository\AccompanyingPeriodRepository; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Chill\ThirdPartyBundle\Entity\ThirdParty; @@ -46,7 +46,7 @@ use Symfony\Component\Workflow\Registry; final class AccompanyingCourseApiController extends ApiController { - public function __construct(private readonly AccompanyingPeriodRepository $accompanyingPeriodRepository, private readonly AccompanyingPeriodACLAwareRepository $accompanyingPeriodACLAwareRepository, private readonly EventDispatcherInterface $eventDispatcher, private readonly ReferralsSuggestionInterface $referralAvailable, private readonly Registry $registry, private readonly ValidatorInterface $validator, private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry) {} + public function __construct(private readonly AccompanyingPeriodRepository $accompanyingPeriodRepository, private readonly EventDispatcherInterface $eventDispatcher, private readonly ReferralsSuggestionInterface $referralAvailable, private readonly Registry $registry, private readonly ValidatorInterface $validator, private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry, private readonly AccompanyingPeriodWorkRepository $accompanyingPeriodWorkRepository) {} public function commentApi($id, Request $request, string $_format): Response { @@ -305,6 +305,20 @@ final class AccompanyingCourseApiController extends ApiController return $this->json($accompanyingCourse->getIntensity(), Response::HTTP_OK, [], ['groups' => ['read']]); } + /** + * @ParamConverter("accompanyingPeriod", options={"id": "id"}) + */ + #[Route(path: '/api/1.0/person/accompanying-course/{id}/works.json', name: 'chill_api_person_accompanying_period_works')] + public function worksByAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): JsonResponse + { + $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $accompanyingPeriod); + + $works = $this->accompanyingPeriodWorkRepository->findBy(['accompanyingPeriod' => $accompanyingPeriod]); + dump($works); + + return $this->json($works, Response::HTTP_OK, [], ['groups' => ['read']]); + } + public function workApi($id, Request $request, string $_format): Response { return $this->addRemoveSomething( diff --git a/src/Bundle/ChillPersonBundle/chill.api.specs.yaml b/src/Bundle/ChillPersonBundle/chill.api.specs.yaml index 45cccf958..637ab399d 100644 --- a/src/Bundle/ChillPersonBundle/chill.api.specs.yaml +++ b/src/Bundle/ChillPersonBundle/chill.api.specs.yaml @@ -1013,6 +1013,29 @@ paths: 200: description: "OK" + /1.0/person/accompanying-course/{id}/works.json: + get: + tags: + - accompanying-course + summary: List of accompanying period works for an accompanying period + description: Gets a list of accompanying period works for an accompanying period + parameters: + - name: id + in: path + required: true + description: The accompanying period id + schema: + type: integer + format: integer + minimum: 1 + responses: + 401: + description: "Unauthorized" + 404: + description: "Not found" + 200: + description: "OK" + /1.0/person/accompanying-course/{id}/work.json: post: tags: From d2fcb6945bbef5c17385ec0318e4ad7ce609e9da Mon Sep 17 00:00:00 2001 From: LenaertsJ Date: Wed, 19 Feb 2025 10:57:59 +0000 Subject: [PATCH 11/67] Setup alias for use in standalone chill-bundles project and replace relative paths --- .changes/unreleased/DX-20250131-131801.yaml | 6 + .gitignore | 1 + .gitlab-ci.yml | 2 +- assets/translator.ts | 9 + composer.json | 1 + config/bundles.php | 1 + config/packages/ux_translator.yaml | 3 + .../installation/installation-production.rst | 50 +- package.json | 15 +- .../Activity/components/ConcernedGroups.vue | 35 +- .../vuejs/Activity/components/Location.vue | 30 +- .../components/Location/NewLocation.vue | 46 +- .../Activity/components/SocialIssuesAcc.vue | 73 +- .../translations/messages.fr.yml | 26 + .../translations/messages.fr.yml | 5 - .../public/module/ckeditor5/editor_config.ts | 55 +- .../public/module/ckeditor5/index.ts | 14 +- .../public/module/notification/toggle_read.js | 3 +- .../Component/PickGenericDocItem.vue | 3 +- .../public/vuejs/_components/BadgeEntity.vue | 76 +- .../_components/Entity/AddressRenderBox.vue | 8 +- .../EntityWorkflowVueSubscriber.vue | 125 +- .../EntityWorkflow/ListWorkflow.vue | 140 +- .../EntityWorkflow/ListWorkflowModal.vue | 148 +- .../public/vuejs/_components/Modal.vue | 52 +- .../Notification/NotificationReadToggle.vue | 151 +- .../public/vuejs/_components/OpenWopiLink.vue | 307 +- .../ChillMainBundle/chill.webpack.config.js | 44 - .../translations/messages.fr.yml | 98 + .../AccompanyingCourse/components/Comment.vue | 13 +- .../components/Resources/WriteComment.vue | 11 +- .../vuejs/AccompanyingCourseWorkEdit/App.vue | 34 +- .../components/FormEvaluation.vue | 28 +- .../components/MemberDetails.vue | 21 +- .../components/PersonComment.vue | 15 +- .../components/Positioning.vue | 2 +- src/vuex.d.ts | 6 + symfony.lock | 15 + ts-config-base.json | 28 + tsconfig.json | 38 +- webpack.config.js | 23 +- yarn.lock | 8612 ----------------- 42 files changed, 924 insertions(+), 9449 deletions(-) create mode 100644 .changes/unreleased/DX-20250131-131801.yaml create mode 100644 assets/translator.ts create mode 100644 config/packages/ux_translator.yaml create mode 100644 src/vuex.d.ts create mode 100644 ts-config-base.json delete mode 100644 yarn.lock diff --git a/.changes/unreleased/DX-20250131-131801.yaml b/.changes/unreleased/DX-20250131-131801.yaml new file mode 100644 index 000000000..387f48054 --- /dev/null +++ b/.changes/unreleased/DX-20250131-131801.yaml @@ -0,0 +1,6 @@ +kind: DX +body: Create an unique source of trust for translations +time: 2025-01-31T13:18:01.239211506+01:00 +custom: + Issue: "333" + SchemaChange: No schema change diff --git a/.gitignore b/.gitignore index 210b03aa6..ec5200ebd 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ docker/rabbitmq/data # in this development bundle, we want to ignore directories related to a real app assets/* +!assets/translator.ts migrations/* templates/* translations/* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a632f8f18..02c01640c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -113,7 +113,7 @@ lint: - export PATH="./node_modules/.bin:$PATH" script: - yarn install --ignore-optional - - npx eslint-baseline "**/*.{js,vue}" + - npx eslint-baseline "src/**/*.{js,ts,vue}" cache: paths: - node_modules/ diff --git a/assets/translator.ts b/assets/translator.ts new file mode 100644 index 000000000..4834e30a6 --- /dev/null +++ b/assets/translator.ts @@ -0,0 +1,9 @@ +// @ts-ignore Cannot find module (when used within an app) +import { trans, getLocale, setLocale, setLocaleFallbacks } from "@symfony/ux-translator"; + +setLocaleFallbacks({"en": "fr", "nl": "fr", "fr": "en"}); +setLocale('fr'); + +export { trans }; +// @ts-ignore Cannot find module (when used within an app) +export * from '../var/translations'; diff --git a/composer.json b/composer.json index d4134c916..8d36d4d07 100644 --- a/composer.json +++ b/composer.json @@ -75,6 +75,7 @@ "symfony/templating": "^5.4", "symfony/translation": "^5.4", "symfony/twig-bundle": "^5.4", + "symfony/ux-translator": "^2.22", "symfony/validator": "^5.4", "symfony/webpack-encore-bundle": "^1.11", "symfony/workflow": "^5.4", diff --git a/config/bundles.php b/config/bundles.php index 815c3e62d..ec11bc0b6 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -36,4 +36,5 @@ return [ Chill\BudgetBundle\ChillBudgetBundle::class => ['all' => true], Chill\WopiBundle\ChillWopiBundle::class => ['all' => true], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], + Symfony\UX\Translator\UxTranslatorBundle::class => ['all' => true], ]; diff --git a/config/packages/ux_translator.yaml b/config/packages/ux_translator.yaml new file mode 100644 index 000000000..1c1c70608 --- /dev/null +++ b/config/packages/ux_translator.yaml @@ -0,0 +1,3 @@ +ux_translator: + # The directory where the JavaScript translations are dumped + dump_directory: '%kernel.project_dir%/var/translations' diff --git a/docs/source/installation/installation-production.rst b/docs/source/installation/installation-production.rst index c12581265..08ede3d40 100644 --- a/docs/source/installation/installation-production.rst +++ b/docs/source/installation/installation-production.rst @@ -29,8 +29,7 @@ We strongly encourage you to initialize a git repository at this step, to track # add the flex endpoints required for custom recipes cat <<< "$(jq '.extra.symfony += {"endpoint": ["flex://defaults", "https://gitlab.com/api/v4/projects/57371968/repository/files/index.json/raw?ref=main"]}' composer.json)" > composer.json # install chill and some dependencies - # TODO fix the suffix "alpha1" and replace by ^3.0.0 when version 3.0.0 will be released - symfony composer require chill-project/chill-bundles v3.0.0-RC3 champs-libres/wopi-lib dev-master@dev champs-libres/wopi-bundle dev-master@dev + symfony composer require chill-project/chill-bundles ^3.7.1 champs-libres/wopi-lib dev-master@dev champs-libres/wopi-bundle dev-master@dev symfony/amqp-messenger We encourage you to accept the inclusion of the "Docker configuration from recipes": this is the documented way to run the database. You must also accept to configure recipes from the contrib repository, unless you want to configure the bundles manually). @@ -48,7 +47,7 @@ You must also accept to configure recipes from the contrib repository, unless yo If you encounter this error during assets compilation (:code:`yarn run encore production`) (repeated multiple times): - .. code-block:: txt + .. code-block:: [tsl] ERROR in /tmp/chill/v1/public/bundles/chillcalendar/types.ts(2,65) TS2307: Cannot find module '../../../ChillMainBundle/Resources/public/types' or its corresponding type declarations. @@ -74,14 +73,22 @@ or in the :code:`.env.local` file, which should not be committed to the git repo You do not need to set variables for the smtp server, redis server and relatorio server, as they are generated automatically by the symfony server, from the docker compose services. -The only required variable is the :code:`ADMIN_PASSWORD`. You can generate a hashed and salted admin password using the command -:code:`symfony console security:hash-password 'Symfony\Component\Security\Core\User\User'`. Then, +The required variables are: + +- the :code:`ADMIN_PASSWORD`; +- the :code:`OVHCLOUD_DSN` variable; + +:code:`ADMIN_PASSWORD` +^^^^^^^^^^^^^^^^^^^^^^ + +You can generate a hashed and salted admin password using the command +:code:`symfony console security:hash-password 'Symfony\Component\Security\Core\User\User'`.Then, you can either: - add this password to the :code:`.env.local` file, you must escape the character :code:`$`: if the generated password is :code:`$2y$13$iyvJLuT4YEa6iWXyQV4/N.hNHpNG8kXlYDkkt5MkYy4FXcSwYAwmm`, your :code:`.env.local` file will be: - .. code-block:: env + .. code-block:: bash ADMIN_PASSWORD=\$2y\$13\$iyvJLuT4YEa6iWXyQV4/N.hNHpNG8kXlYDkkt5MkYy4FXcSwYAwmm # note: if you copy-paste the line above, the password will be "admin". @@ -89,12 +96,24 @@ you can either: - add the generated password to the secrets manager (**note**: you must add the generated hashed password to the secrets env, not the password in clear text). -- set up the jwt authentication bundle +:code:`OVHCLOUD_DSN` and sending SMS messages +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is a temporary dependency, for ensuring compatibility for previous behaviour. + +You can set it to :code:`null://null` if you do not plan to use sending SMS. + +.. code-block:: bash + + OVHCLOUD_DSN=null://null + +If you plan to do it, you can configure the notifier component `as described in the symfony documentation `_. + Some environment variables are available for the JWT authentication bundle in the :code:`.env` file. -Prepare migrations and other tools ----------------------------------- +Prepare database, messenger queue, and other configuration +---------------------------------------------------------- To continue the installation process, you will have to run migrations: @@ -114,14 +133,17 @@ To continue the installation process, you will have to run migrations: # generate jwt token, required for some api features (webdav access, ...) symfony console lexik:jwt:generate-keypair -.. warning:: +.. note:: - If you encounter an error while running :code:`symfony console messenger:setup-transports`, you can set up the messenger - transport to redis, by adding this in the :code:`.env.local` or :code:`.env` file: + If you encounter this error: + + .. code-block:: + + No transport supports the given Messenger DSN. + + Please check that you installed the package `symfony/amqp-messenger`. - .. code-block:: env - MESSENGER_TRANSPORT_DSN=redis://${REDIS_HOST}:${REDIS_PORT}/messages Start your web server locally ----------------------------- diff --git a/package.json b/package.json index 397676b1b..a24c4ee8f 100644 --- a/package.json +++ b/package.json @@ -6,15 +6,11 @@ "@apidevtools/swagger-cli": "^4.0.4", "@babel/core": "^7.20.5", "@babel/preset-env": "^7.20.2", - "@ckeditor/ckeditor5-build-classic": "^41.4.2", - "@ckeditor/ckeditor5-dev-translations": "^40.2.0", - "@ckeditor/ckeditor5-dev-utils": "^40.2.0", - "@ckeditor/ckeditor5-dev-webpack-plugin": "^31.1.13", - "@ckeditor/ckeditor5-markdown-gfm": "^41.4.2", - "@ckeditor/ckeditor5-theme-lark": "^41.4.2", - "@ckeditor/ckeditor5-vue": "^5.1.0", + "@ckeditor/ckeditor5-vue": "^7.3.0", "@eslint/js": "^9.14.0", + "@hotwired/stimulus": "^3.0.0", "@luminateone/eslint-baseline": "^1.0.9", + "@symfony/stimulus-bridge": "^3.2.0", "@symfony/webpack-encore": "^4.1.0", "@tsconfig/node20": "^20.1.4", "@types/dompurify": "^3.0.5", @@ -23,12 +19,14 @@ "bindings": "^1.5.0", "bootstrap": "5.2.3", "chokidar": "^3.5.1", + "ckeditor5": "^44.1.0", "dompurify": "^3.1.0", "eslint": "^9.14.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-vue": "^9.30.0", "fork-awesome": "^1.1.7", + "intl-messageformat": "^10.5.11", "jquery": "^3.6.0", "node-sass": "^8.0.0", "popper.js": "^1.16.1", @@ -54,6 +52,7 @@ "@fullcalendar/timegrid": "^6.1.4", "@fullcalendar/vue3": "^6.1.4", "@popperjs/core": "^2.9.2", + "@tsconfig/node20": "^20.1.4", "@types/dompurify": "^3.0.5", "@types/leaflet": "^1.9.3", "bootstrap-icons": "^1.11.3", @@ -72,7 +71,7 @@ "vuex": "^4.0.0" }, "browserslist": [ - "Firefox ESR" + "defaults and fully supports es6-module and not dead" ], "scripts": { "dev-server": "encore dev-server", diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/ConcernedGroups.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/ConcernedGroups.vue index 8437a1524..b99de220d 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/ConcernedGroups.vue +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/ConcernedGroups.vue @@ -30,13 +30,14 @@
    • + > +
    @@ -47,6 +48,14 @@ import { mapState, mapGetters } from "vuex"; import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue"; import PersonsBloc from "./ConcernedGroups/PersonsBloc.vue"; import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue"; +import { + ACTIVITY_BLOC_PERSONS, + ACTIVITY_BLOC_PERSONS_ASSOCIATED, + ACTIVITY_BLOC_THIRDPARTY, + ACTIVITY_BLOC_USERS, + ACTIVITY_ADD_PERSONS, + trans, +} from "translator"; export default { name: "ConcernedGroups", @@ -55,18 +64,24 @@ export default { PersonsBloc, PersonText, }, + setup() { + return { + trans, + ACTIVITY_ADD_PERSONS, + }; + }, data() { return { personsBlocs: [ { key: "persons", - title: "activity.bloc_persons", + title: trans(ACTIVITY_BLOC_PERSONS), persons: [], included: false, }, { key: "personsAssociated", - title: "activity.bloc_persons_associated", + title: trans(ACTIVITY_BLOC_PERSONS_ASSOCIATED), persons: [], included: window.activity ? window.activity.activityType.personsVisible !== 0 @@ -82,7 +97,7 @@ export default { }, { key: "thirdparty", - title: "activity.bloc_thirdparty", + title: trans(ACTIVITY_BLOC_THIRDPARTY), persons: [], included: window.activity ? window.activity.activityType.thirdPartiesVisible !== 0 @@ -90,7 +105,7 @@ export default { }, { key: "users", - title: "activity.bloc_users", + title: trans(ACTIVITY_BLOC_USERS), persons: [], included: window.activity ? window.activity.activityType.usersVisible !== 0 diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location.vue index efa1ca9e5..79df05da5 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location.vue +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location.vue @@ -2,7 +2,7 @@
    - +
    @@ -33,6 +33,14 @@ import { mapState, mapGetters } from "vuex"; import VueMultiselect from "vue-multiselect"; import NewLocation from "./Location/NewLocation.vue"; +import { + trans, + ACTIVITY_LOCATION, + ACTIVITY_CHOOSE_LOCATION, + MULTISELECT_SELECT_LABEL, + MULTISELECT_DESELECT_LABEL, + MULTISELECT_SELECTED_LABEL, +} from "translator"; export default { name: "Location", @@ -40,6 +48,16 @@ export default { NewLocation, VueMultiselect, }, + setup() { + return { + trans, + ACTIVITY_LOCATION, + ACTIVITY_CHOOSE_LOCATION, + MULTISELECT_SELECT_LABEL, + MULTISELECT_DESELECT_LABEL, + MULTISELECT_SELECTED_LABEL, + }; + }, data() { return { locationClassList: `col-form-label col-sm-4 ${document.querySelector("input#chill_activitybundle_activity_location").getAttribute("required") ? "required" : ""}`, diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location/NewLocation.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location/NewLocation.vue index da3e471ef..bea758ff8 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location/NewLocation.vue +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location/NewLocation.vue @@ -3,7 +3,7 @@ @@ -11,12 +11,12 @@ @@ -126,6 +126,17 @@ import AddAddress from "ChillMainAssets/vuejs/Address/components/AddAddress.vue" import { mapState } from "vuex"; import { getLocationTypes } from "../../api"; import { makeFetch } from "ChillMainAssets/lib/api/apiMethods"; +import { + SAVE, + ACTIVITY_LOCATION_FIELDS_EMAIL, + ACTIVITY_LOCATION_FIELDS_PHONENUMBER1, + ACTIVITY_LOCATION_FIELDS_PHONENUMBER2, + ACTIVITY_LOCATION_FIELDS_NAME, + ACTIVITY_LOCATION_FIELDS_TYPE, + ACTIVITY_CHOOSE_LOCATION_TYPE, + ACTIVITY_CREATE_NEW_LOCATION, + trans, +} from "translator"; export default { name: "NewLocation", @@ -133,6 +144,19 @@ export default { Modal, AddAddress, }, + setup() { + return { + trans, + SAVE, + ACTIVITY_LOCATION_FIELDS_EMAIL, + ACTIVITY_LOCATION_FIELDS_PHONENUMBER1, + ACTIVITY_LOCATION_FIELDS_PHONENUMBER2, + ACTIVITY_LOCATION_FIELDS_NAME, + ACTIVITY_LOCATION_FIELDS_TYPE, + ACTIVITY_CHOOSE_LOCATION_TYPE, + ACTIVITY_CREATE_NEW_LOCATION, + }; + }, props: ["availableLocations"], data() { return { diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc.vue index a055fa725..10ed84d79 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc.vue +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc.vue @@ -3,7 +3,7 @@
    @@ -12,8 +12,9 @@ :key="issue.id" :issue="issue" :selection="socialIssuesSelected" - @update-selected="updateIssuesSelected" - /> + @updateSelected="updateIssuesSelected" + > +
    + > +
    @@ -42,36 +44,38 @@
    - +
    - {{ $t("activity.select_first_a_social_issue") }} + {{ trans(ACTIVITY_SELECT_FIRST_A_SOCIAL_ISSUE) }} - - {{ $t("activity.social_action_list_empty") }} + {{ trans(ACTIVITY_SOCIAL_ACTION_LIST_EMPTY) }}
    @@ -92,6 +96,14 @@ import VueMultiselect from "vue-multiselect"; import CheckSocialIssue from "./SocialIssuesAcc/CheckSocialIssue.vue"; import CheckSocialAction from "./SocialIssuesAcc/CheckSocialAction.vue"; import { getSocialIssues, getSocialActionByIssue } from "../api.js"; +import { + ACTIVITY_SOCIAL_ACTION_LIST_EMPTY, + ACTIVITY_SELECT_FIRST_A_SOCIAL_ISSUE, + ACTIVITY_SOCIAL_ACTIONS, + ACTIVITY_SOCIAL_ISSUES, + ACTIVITY_CHOOSE_OTHER_SOCIAL_ISSUE, + trans, +} from "translator"; export default { name: "SocialIssuesAcc", @@ -100,6 +112,16 @@ export default { CheckSocialAction, VueMultiselect, }, + setup() { + return { + trans, + ACTIVITY_SOCIAL_ACTION_LIST_EMPTY, + ACTIVITY_SELECT_FIRST_A_SOCIAL_ISSUE, + ACTIVITY_SOCIAL_ACTIONS, + ACTIVITY_SOCIAL_ISSUES, + ACTIVITY_CHOOSE_OTHER_SOCIAL_ISSUE, + }; + }, data() { return { issueIsLoading: false, @@ -133,7 +155,7 @@ export default { this.actionAreLoaded = false; getSocialIssues().then( (response) => - new Promise((resolve, reject) => { + new Promise((resolve) => { this.$store.commit("updateIssuesOther", response.results); /* Add in list the issues already associated (if not yet listed) @@ -208,7 +230,7 @@ export default { this.actionIsLoading = true; getSocialActionByIssue(item.id).then( (actions) => - new Promise((resolve, reject) => { + new Promise((resolve) => { actions.results.forEach((action) => { this.$store.commit("addActionInList", action); }, this); @@ -235,7 +257,6 @@ export default { }; - diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/ListWorkflow.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/ListWorkflow.vue index 608508dd8..ebcc5128c 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/ListWorkflow.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/ListWorkflow.vue @@ -1,7 +1,7 @@ - diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue index 022f274a3..59dcd80f4 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue @@ -1,23 +1,24 @@ - diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc/CheckSocialAction.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc/CheckSocialAction.vue index 0d5a6bbf4..8172b2b6f 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc/CheckSocialAction.vue +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc/CheckSocialAction.vue @@ -10,7 +10,9 @@ :value="action" />
    @@ -43,5 +45,9 @@ span.badge { font-size: 95%; margin-bottom: 5px; margin-right: 1em; + max-width: 100%; /* Adjust as needed */ + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/store.js b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/store.js index c910d7318..f29e2e6d4 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/store.js +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/store.js @@ -124,9 +124,19 @@ const store = createStore({ ); }, socialActionsListSorted(state) { - return [...state.socialActionsList].sort( - (a, b) => a.ordering - b.ordering, - ); + return [...state.socialActionsList] + .sort((a, b) => a.ordering - b.ordering) + .reduce((acc, action) => { + const issueText = action.issue?.text || "Uncategorized"; + // Find if the group for the issue already exists + let group = acc.find((item) => item.issue === issueText); + if (!group) { + group = { issue: issueText, actions: [] }; + acc.push(group); + } + group.actions.push(action); + return acc; + }, []); }, }, mutations: { From 03b24968173a65cb7957448dc9fdaf00380ce526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 4 Mar 2025 23:02:19 +0100 Subject: [PATCH 26/67] Fix dependency injection issues in AbstractCRUDController Replaced incorrect service definitions in AbstractCRUDController to ensure proper dependency injection. Specifically, fixed retrieval of the ManagerRegistry and Validator services to resolve CalendarRange save errors (Issue #362). No schema changes were introduced. --- .changes/unreleased/Fixed-20250304-160058.yaml | 6 ++++++ .../CRUD/Controller/AbstractCRUDController.php | 5 ++--- 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 .changes/unreleased/Fixed-20250304-160058.yaml diff --git a/.changes/unreleased/Fixed-20250304-160058.yaml b/.changes/unreleased/Fixed-20250304-160058.yaml new file mode 100644 index 000000000..d2e9cf3ed --- /dev/null +++ b/.changes/unreleased/Fixed-20250304-160058.yaml @@ -0,0 +1,6 @@ +kind: Fixed +body: Fix Dependency Injection, which prevented to save the CalendarRange +time: 2025-03-04T16:00:58.269626007+01:00 +custom: + Issue: "362" + SchemaChange: No schema change diff --git a/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php b/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php index ea5e55a69..1cbf69630 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php +++ b/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php @@ -63,7 +63,6 @@ abstract class AbstractCRUDController extends AbstractController parent::getSubscribedServices(), [ 'chill_main.paginator_factory' => PaginatorFactory::class, - ManagerRegistry::class => ManagerRegistry::class, 'translator' => TranslatorInterface::class, AuthorizationHelper::class => AuthorizationHelper::class, EventDispatcherInterface::class => EventDispatcherInterface::class, @@ -213,7 +212,7 @@ abstract class AbstractCRUDController extends AbstractController protected function getManagerRegistry(): ManagerRegistry { - return $this->container->get(ManagerRegistry::class); + return $this->container->get('doctrine'); } /** @@ -226,7 +225,7 @@ abstract class AbstractCRUDController extends AbstractController protected function getValidator(): ValidatorInterface { - return $this->get('validator'); + return $this->container->get('validator'); } /** From 08af5307269984d6a0ef63c0f7094a53a5213e9e Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 5 Mar 2025 10:26:22 +0100 Subject: [PATCH 27/67] Replace deprecated Statement::create() method use constructor directly --- .../AddressReferenceBEFromBestAddress.php | 4 ++-- .../Import/AddressReferenceFromBAN.php | 4 ++-- .../Import/AddressReferenceFromBano.php | 22 +++++++++---------- .../Service/Import/AddressReferenceLU.php | 6 +++-- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceBEFromBestAddress.php b/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceBEFromBestAddress.php index ea6575e43..fcf49079f 100644 --- a/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceBEFromBestAddress.php +++ b/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceBEFromBestAddress.php @@ -68,8 +68,8 @@ class AddressReferenceBEFromBestAddress $csv->setDelimiter(','); $csv->setHeaderOffset(0); - $stmt = Statement::create() - ->process($csv); + $stmt = new Statement(); + $stmt = $stmt->process($csv); foreach ($stmt as $record) { $this->baseImporter->importAddress( diff --git a/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceFromBAN.php b/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceFromBAN.php index b45760592..d79997b0a 100644 --- a/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceFromBAN.php +++ b/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceFromBAN.php @@ -55,8 +55,8 @@ class AddressReferenceFromBAN $csv = Reader::createFromStream($csvDecompressed); $csv->setDelimiter(';')->setHeaderOffset(0); - $stmt = Statement::create() - ->process($csv, [ + $stmt = new Statement(); + $stmt = $stmt->process($csv, [ 'id', 'id_fantoir', 'numero', diff --git a/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceFromBano.php b/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceFromBano.php index 5ee3f6964..be20bbc11 100644 --- a/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceFromBano.php +++ b/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceFromBano.php @@ -43,17 +43,17 @@ class AddressReferenceFromBano $csv = Reader::createFromStream($file); $csv->setDelimiter(','); - $stmt = Statement::create() - ->process($csv, [ - 'refId', - 'streetNumber', - 'street', - 'postcode', - 'city', - '_o', - 'lat', - 'lon', - ]); + $stmt = new Statement(); + $stmt = $stmt->process($csv, [ + 'refId', + 'streetNumber', + 'street', + 'postcode', + 'city', + '_o', + 'lat', + 'lon', + ]); foreach ($stmt as $record) { $this->baseImporter->importAddress( diff --git a/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceLU.php b/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceLU.php index 86c1b61b8..e1294732b 100644 --- a/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceLU.php +++ b/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceLU.php @@ -54,7 +54,8 @@ class AddressReferenceLU private function process_address(Reader $csv, ?string $sendAddressReportToEmail = null): void { - $stmt = Statement::create()->process($csv); + $stmt = new Statement(); + $stmt = $stmt->process($csv); foreach ($stmt as $record) { $this->addressBaseImporter->importAddress( $record['id_geoportail'], @@ -74,7 +75,8 @@ class AddressReferenceLU private function process_postal_code(Reader $csv): void { - $stmt = Statement::create()->process($csv); + $stmt = new Statement(); + $stmt = $stmt->process($csv); $arr_postal_codes = []; foreach ($stmt as $record) { if (false === \array_key_exists($record['code_postal'], $arr_postal_codes)) { From 84b7cc81452a670d89172af32a9b733d19fd1056 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 5 Mar 2025 10:46:36 +0100 Subject: [PATCH 28/67] Php cs fixes --- .../Import/AddressReferenceFromBAN.php | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceFromBAN.php b/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceFromBAN.php index d79997b0a..1c03b7bfb 100644 --- a/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceFromBAN.php +++ b/src/Bundle/ChillMainBundle/Service/Import/AddressReferenceFromBAN.php @@ -57,30 +57,30 @@ class AddressReferenceFromBAN $csv->setDelimiter(';')->setHeaderOffset(0); $stmt = new Statement(); $stmt = $stmt->process($csv, [ - 'id', - 'id_fantoir', - 'numero', - 'rep', - 'nom_voie', - 'code_postal', - 'code_insee', - 'nom_commune', - 'code_insee_ancienne_commune', - 'nom_ancienne_commune', - 'x', - 'y', - 'lon', - 'lat', - 'type_position', - 'alias', - 'nom_ld', - 'libelle_acheminement', - 'nom_afnor', - 'source_position', - 'source_nom_voie', - 'certification_commune', - 'cad_parcelles', - ]); + 'id', + 'id_fantoir', + 'numero', + 'rep', + 'nom_voie', + 'code_postal', + 'code_insee', + 'nom_commune', + 'code_insee_ancienne_commune', + 'nom_ancienne_commune', + 'x', + 'y', + 'lon', + 'lat', + 'type_position', + 'alias', + 'nom_ld', + 'libelle_acheminement', + 'nom_afnor', + 'source_position', + 'source_nom_voie', + 'certification_commune', + 'cad_parcelles', + ]); foreach ($stmt as $record) { $this->baseImporter->importAddress( From 7a9168fcdb92febf358965bb00b22b95326836ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 14 Mar 2025 15:02:09 +0100 Subject: [PATCH 29/67] Refactor variable declarations in pick-entity module. Consolidated variable declarations into a single statement using const. This improves code readability and aligns with modern JavaScript best practices. --- .../Resources/public/module/pick-entity/index.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/module/pick-entity/index.js b/src/Bundle/ChillMainBundle/Resources/public/module/pick-entity/index.js index 6f6aad7ff..1b3ee4594 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/module/pick-entity/index.js +++ b/src/Bundle/ChillMainBundle/Resources/public/module/pick-entity/index.js @@ -12,10 +12,6 @@ function loadDynamicPicker(element) { let apps = element.querySelectorAll('[data-module="pick-dynamic"]'); apps.forEach(function (el) { - let suggested; - let as_id; - let submit_on_adding_new_entity; - let label; const isMultiple = parseInt(el.dataset.multiple) === 1, uniqId = el.dataset.uniqid, input = element.querySelector( @@ -26,12 +22,12 @@ function loadDynamicPicker(element) { ? JSON.parse(input.value) : input.value === "[]" || input.value === "" ? null - : [JSON.parse(input.value)]; - suggested = JSON.parse(el.dataset.suggested); - as_id = parseInt(el.dataset.asId) === 1; - submit_on_adding_new_entity = - parseInt(el.dataset.submitOnAddingNewEntity) === 1; - label = el.dataset.label; + : [JSON.parse(input.value)], + suggested = JSON.parse(el.dataset.suggested), + as_id = parseInt(el.dataset.asId) === 1, + submit_on_adding_new_entity = + parseInt(el.dataset.submitOnAddingNewEntity) === 1, + label = el.dataset.label; if (!isMultiple) { if (input.value === "[]") { From f202625ea834e3f0fee691bedf3bfd4ac414b695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 14 Mar 2025 15:02:26 +0100 Subject: [PATCH 30/67] Fix LIKE clause logic in UserGroupRepository query Adjusted the parameter order and ensured consistent use of LOWER and UNACCENT functions in the LIKE clause. This resolves potential mismatches and improves query reliability for pattern matching. --- .changes/unreleased/Fixed-20250314-150408.yaml | 6 ++++++ .../ChillMainBundle/Repository/UserGroupRepository.php | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 .changes/unreleased/Fixed-20250314-150408.yaml diff --git a/.changes/unreleased/Fixed-20250314-150408.yaml b/.changes/unreleased/Fixed-20250314-150408.yaml new file mode 100644 index 000000000..0c278aa12 --- /dev/null +++ b/.changes/unreleased/Fixed-20250314-150408.yaml @@ -0,0 +1,6 @@ +kind: Fixed +body: fix search query for user groups +time: 2025-03-14T15:04:08.622666838+01:00 +custom: + Issue: "368" + SchemaChange: No schema change diff --git a/src/Bundle/ChillMainBundle/Repository/UserGroupRepository.php b/src/Bundle/ChillMainBundle/Repository/UserGroupRepository.php index e1c54442d..71266f8e5 100644 --- a/src/Bundle/ChillMainBundle/Repository/UserGroupRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/UserGroupRepository.php @@ -75,8 +75,8 @@ final class UserGroupRepository implements UserGroupRepositoryInterface, LocaleA ->setWhereClauses(' ug.active AND ( SIMILARITY(LOWER(UNACCENT(?)), ug.label->>?) > 0.15 - OR ug.label->>? LIKE \'%\' || LOWER(UNACCENT(?)) || \'%\') - ', [$pattern, $lang, $pattern, $lang]); + OR LOWER(UNACCENT(ug.label->>?)) LIKE \'%\' || LOWER(UNACCENT(?)) || \'%\') + ', [$pattern, $lang, $lang, $pattern]); return $query; } From 7ddf84ea5a76c63afa50f323fe37d6b3ea1d3517 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Fri, 14 Mar 2025 15:07:23 +0100 Subject: [PATCH 31/67] Fix ts errors upon prod compilation --- assets/translator.ts | 2 +- package.json | 1 + .../public/vuejs/DocumentSignature/App.vue | 29 ++++++++++--------- .../HistoryButton/HistoryButtonModal.vue | 7 +++-- .../public/vuejs/WorkflowAttachment/App.vue | 5 +++- .../Component/PickGenericDoc.vue | 8 +++-- 6 files changed, 32 insertions(+), 20 deletions(-) diff --git a/assets/translator.ts b/assets/translator.ts index 4834e30a6..ad2de8c0b 100644 --- a/assets/translator.ts +++ b/assets/translator.ts @@ -1,5 +1,5 @@ // @ts-ignore Cannot find module (when used within an app) -import { trans, getLocale, setLocale, setLocaleFallbacks } from "@symfony/ux-translator"; +import { trans, setLocale, setLocaleFallbacks } from "@symfony/ux-translator"; setLocaleFallbacks({"en": "fr", "nl": "fr", "fr": "en"}); setLocale('fr'); diff --git a/package.json b/package.json index a24c4ee8f..e2b8d8ba3 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "@hotwired/stimulus": "^3.0.0", "@luminateone/eslint-baseline": "^1.0.9", "@symfony/stimulus-bridge": "^3.2.0", + "@symfony/ux-translator": "file:vendor/symfony/ux-translator/assets", "@symfony/webpack-encore": "^4.1.0", "@tsconfig/node20": "^20.1.4", "@types/dompurify": "^3.0.5", diff --git a/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/DocumentSignature/App.vue b/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/DocumentSignature/App.vue index b47a6bce0..283156696 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/DocumentSignature/App.vue +++ b/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/DocumentSignature/App.vue @@ -92,8 +92,7 @@ >