From 53b3f98bba35d4dfef192ebb8d6becd0e13aaa78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 24 Jan 2022 10:59:00 +0000 Subject: [PATCH] Household/composition add + fixes household composition editor --- .../Doctrine/Model/TrackCreationTrait.php | 56 ++++++ .../Doctrine/Model/TrackUpdateTrait.php | 56 ++++++ .../HouseholdCompositionController.php | 149 +++++++++++++++ .../HouseholdCompositionTypeApiController.php | 36 ++++ .../ORM/LoadHouseholdCompositionType.php | 48 +++++ .../ChillPersonExtension.php | 16 ++ .../Entity/Household/Household.php | 104 ++++++++++- .../Entity/Household/HouseholdComposition.php | 171 ++++++++++++++++++ .../Household/HouseholdCompositionType.php | 76 ++++++++ .../ChillPersonBundle/Entity/Person.php | 2 +- .../Form/HouseholdCompositionType.php | 60 ++++++ .../Household/MembersEditor.php | 13 +- .../Menu/HouseholdMenuBuilder.php | 22 ++- .../Household/HouseholdACLAwareRepository.php | 2 +- .../HouseholdCompositionRepository.php | 75 ++++++++ .../HouseholdCompositionTypeRepository.php | 69 +++++++ .../vuejs/HouseholdMembersEditor/App.vue | 9 +- .../components/Concerned.vue | 31 ++-- .../components/Dates.vue | 50 ++++- .../components/PersonComment.vue | 42 +++++ .../components/Positioning.vue | 14 +- .../vuejs/HouseholdMembersEditor/js/i18n.js | 8 +- .../HouseholdMembersEditor/store/index.js | 34 +++- .../_warning_address.html.twig | 38 ++-- .../views/Household/members_editor.html.twig | 10 +- .../views/Household/summary.html.twig | 52 +++++- .../HouseholdComposition/index.html.twig | 96 ++++++++++ .../Security/Authorization/HouseholdVoter.php | 63 ++++++- .../Normalizer/MembersEditorNormalizer.php | 20 ++ .../HouseholdMemberControllerTest.php | 3 + .../Tests/Entity/Household/HouseholdTest.php | 47 +++++ .../config/services/security.yaml | 4 + .../migrations/Version20220121121310.php | 51 ++++++ .../translations/messages+intl-icu.fr.yaml | 14 ++ .../translations/messages.fr.yml | 11 ++ 35 files changed, 1489 insertions(+), 63 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Doctrine/Model/TrackCreationTrait.php create mode 100644 src/Bundle/ChillMainBundle/Doctrine/Model/TrackUpdateTrait.php create mode 100644 src/Bundle/ChillPersonBundle/Controller/HouseholdCompositionController.php create mode 100644 src/Bundle/ChillPersonBundle/Controller/HouseholdCompositionTypeApiController.php create mode 100644 src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHouseholdCompositionType.php create mode 100644 src/Bundle/ChillPersonBundle/Entity/Household/HouseholdComposition.php create mode 100644 src/Bundle/ChillPersonBundle/Entity/Household/HouseholdCompositionType.php create mode 100644 src/Bundle/ChillPersonBundle/Form/HouseholdCompositionType.php create mode 100644 src/Bundle/ChillPersonBundle/Repository/Household/HouseholdCompositionRepository.php create mode 100644 src/Bundle/ChillPersonBundle/Repository/Household/HouseholdCompositionTypeRepository.php create mode 100644 src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/PersonComment.vue create mode 100644 src/Bundle/ChillPersonBundle/Resources/views/HouseholdComposition/index.html.twig create mode 100644 src/Bundle/ChillPersonBundle/Tests/Entity/Household/HouseholdTest.php create mode 100644 src/Bundle/ChillPersonBundle/migrations/Version20220121121310.php diff --git a/src/Bundle/ChillMainBundle/Doctrine/Model/TrackCreationTrait.php b/src/Bundle/ChillMainBundle/Doctrine/Model/TrackCreationTrait.php new file mode 100644 index 000000000..a991399c8 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Doctrine/Model/TrackCreationTrait.php @@ -0,0 +1,56 @@ +createdAt; + } + + public function getCreatedBy(): ?User + { + return $this->createdBy; + } + + public function setCreatedAt(DateTimeInterface $datetime): self + { + $this->createdAt = $datetime instanceof DateTime ? DateTimeImmutable::createFromMutable($datetime) : $datetime; + + return $this; + } + + public function setCreatedBy(User $user): self + { + $this->createdBy = $user; + + return $this; + } +} diff --git a/src/Bundle/ChillMainBundle/Doctrine/Model/TrackUpdateTrait.php b/src/Bundle/ChillMainBundle/Doctrine/Model/TrackUpdateTrait.php new file mode 100644 index 000000000..3c706459c --- /dev/null +++ b/src/Bundle/ChillMainBundle/Doctrine/Model/TrackUpdateTrait.php @@ -0,0 +1,56 @@ +updatedAt; + } + + public function getUpdatedBy(): ?User + { + return $this->updatedBy; + } + + public function setUpdatedAt(DateTimeInterface $datetime): self + { + $this->updatedAt = $datetime instanceof DateTime ? DateTimeImmutable::createFromMutable($datetime) : $datetime; + + return $this; + } + + public function setUpdatedBy(User $user): self + { + $this->updatedBy = $user; + + return $this; + } +} diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdCompositionController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdCompositionController.php new file mode 100644 index 000000000..c74113a05 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdCompositionController.php @@ -0,0 +1,149 @@ +security = $security; + $this->householdCompositionRepository = $householdCompositionRepository; + $this->paginatorFactory = $paginatorFactory; + $this->formFactory = $formFactory; + $this->entityManager = $entityManager; + $this->translator = $translator; + $this->engine = $engine; + $this->urlGenerator = $urlGenerator; + } + + /** + * @Route("/{_locale}/person/household/{id}/composition/index", name="chill_person_household_composition_index") + */ + public function index(Household $household, Request $request): Response + { + if (!$this->security->isGranted(HouseholdVoter::SEE, $household)) { + throw new AccessDeniedException('not allowed to edit an household'); + } + + $count = $this->householdCompositionRepository->countByHousehold($household); + $paginator = $this->paginatorFactory->create($count); + $compositions = $this->householdCompositionRepository->findByHousehold( + $household, + ['startDate' => 'DESC', 'id' => 'DESC'], + $paginator->getItemsPerPage(), + $paginator->getCurrentPageFirstItemNumber() + ); + + if ($this->security->isGranted(HouseholdVoter::EDIT, $household)) { + $isEdit = $request->query->has('edit'); + + if ($isEdit) { + $householdCompositions = $household->getCompositions()->filter(static function (HouseholdComposition $composition) use ($request) { + return $composition->getId() === $request->query->getInt('edit'); + }); + + if ($householdCompositions->count() !== 1) { + throw new BadRequestHttpException('could not find the composition with this id associated to the household'); + } + $householdComposition = $householdCompositions->first(); + } else { + $householdComposition = (new HouseholdComposition()) + ->setStartDate(new DateTimeImmutable()); + } + $form = $this->formFactory->create(HouseholdCompositionType::class, $householdComposition); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + if (!$isEdit) { + $this->entityManager->persist($householdComposition); + $household->addComposition($householdComposition); + } + + $this->entityManager->flush(); + + $request->getSession()->getFlashBag()->add( + 'success', + $this->translator->trans('household_composition.Composition added') + ); + + return new RedirectResponse( + $this->urlGenerator->generate('chill_person_household_composition_index', [ + 'id' => $household->getId(), + ]) + ); + } + + if ($form->isSubmitted() && !$form->isValid()) { + $request->getSession()->getFlashBag()->add( + 'warning', + $this->translator->trans('This form contains errors') + ); + } + } + + return new Response($this->engine->render( + '@ChillPerson/HouseholdComposition/index.html.twig', + [ + 'household' => $household, + 'compositions' => $compositions, + 'form' => isset($form) ? $form->createView() : null, + 'isPosted' => isset($form) ? $form->isSubmitted() : false, + 'editId' => $request->query->getInt('edit', -1), + ] + )); + } +} diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdCompositionTypeApiController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdCompositionTypeApiController.php new file mode 100644 index 000000000..418d04531 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdCompositionTypeApiController.php @@ -0,0 +1,36 @@ +andWhere($query->expr()->eq('e.active', "'TRUE'")); + + break; + + default: + throw new UnexpectedValueException('unexepcted action: ' . $action); + } + } +} diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHouseholdCompositionType.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHouseholdCompositionType.php new file mode 100644 index 000000000..b1d306ef8 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHouseholdCompositionType.php @@ -0,0 +1,48 @@ + 'Couple avec enfant(s)'], + ['fr' => 'Couple sans enfant'], + ['fr' => 'Mère seule'], + ['fr' => 'Père seul'], + ['fr' => 'Mère isolée'], + ['fr' => 'Père isolé'], + ['fr' => 'Homme seul'], + ['fr' => 'Femme seule'], + ]; + + public static function getGroups(): array + { + return ['composition-type']; + } + + public function load(ObjectManager $manager) + { + foreach (self::TYPES as $type) { + $manager->persist( + (new HouseholdCompositionType()) + ->setLabel($type) + ); + } + + $manager->flush(); + } +} diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php index 5982fcebe..01df460e3 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php @@ -13,6 +13,7 @@ namespace Chill\PersonBundle\DependencyInjection; use Chill\MainBundle\DependencyInjection\MissingBundleException; use Chill\MainBundle\Security\Authorization\ChillExportVoter; +use Chill\PersonBundle\Controller\HouseholdCompositionTypeApiController; use Chill\PersonBundle\Doctrine\DQL\AddressPart; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodResourceVoter; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; @@ -760,6 +761,21 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac ], ], ], + [ + 'class' => \Chill\PersonBundle\Entity\Household\HouseholdCompositionType::class, + 'name' => 'household_composition', + 'base_path' => '/api/1.0/person/houehold/composition/type', + 'base_role' => 'ROLE_USER', + 'controller' => HouseholdCompositionTypeApiController::class, + 'actions' => [ + '_index' => [ + 'methods' => [ + Request::METHOD_GET => true, + Request::METHOD_HEAD => true, + ], + ], + ], + ], ], ]); } diff --git a/src/Bundle/ChillPersonBundle/Entity/Household/Household.php b/src/Bundle/ChillPersonBundle/Entity/Household/Household.php index 865526250..ef718bc2e 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Household/Household.php +++ b/src/Bundle/ChillPersonBundle/Entity/Household/Household.php @@ -11,6 +11,7 @@ declare(strict_types=1); namespace Chill\PersonBundle\Entity\Household; +use ArrayIterator; use Chill\MainBundle\Entity\Address; use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; use Chill\PersonBundle\Validator\Constraints\Household\MaxHolder; @@ -23,8 +24,8 @@ use Doctrine\Common\Collections\Criteria; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation as Serializer; use Symfony\Component\Validator\Constraints as Assert; -use Symfony\Component\Validator\Context\ExecutionContextInterface; +use Symfony\Component\Validator\Context\ExecutionContextInterface; use function count; /** @@ -56,6 +57,18 @@ class Household */ private CommentEmbeddable $commentMembers; + /** + * @ORM\OneToMany( + * targetEntity=HouseholdComposition::class, + * mappedBy="household", + * orphanRemoval=true, + * cascade={"persist"} + * ) + * @ORM\OrderBy({"startDate": "DESC"}) + * @Assert\Valid(traverse=true, groups={"household_composition"}) + */ + private Collection $compositions; + /** * @ORM\Id * @ORM\GeneratedValue @@ -90,6 +103,7 @@ class Household $this->addresses = new ArrayCollection(); $this->members = new ArrayCollection(); $this->commentMembers = new CommentEmbeddable(); + $this->compositions = new ArrayCollection(); } /** @@ -108,6 +122,18 @@ class Household return $this; } + public function addComposition(HouseholdComposition $composition): self + { + if (!$this->compositions->contains($composition)) { + $composition->setHousehold($this); + $this->compositions[] = $composition; + } + + $this->householdCompositionConsistency(); + + return $this; + } + public function addMember(HouseholdMember $member): self { if (!$this->members->contains($member)) { @@ -136,6 +162,14 @@ class Household return $this->commentMembers; } + /** + * @return ArrayCollection|Collection|HouseholdComposition[] + */ + public function getCompositions(): Collection + { + return $this->compositions; + } + /** * @Serializer\Groups({"read", "docgen:read"}) * @Serializer\SerializedName("current_address") @@ -157,6 +191,31 @@ class Household return null; } + public function getCurrentComposition(?DateTimeImmutable $at = null): ?HouseholdComposition + { + $at ??= new DateTimeImmutable('today'); + $criteria = new Criteria(); + $expr = Criteria::expr(); + + $criteria->where( + $expr->andX( + $expr->orX( + $expr->isNull('endDate'), + $expr->gt('endDate', $at) + ), + $expr->lte('startDate', $at) + ) + ); + + $compositions = $this->compositions->matching($criteria); + + if ($compositions->count() > 0) { + return $compositions->first(); + } + + return null; + } + /** * @Serializer\Groups({"docgen:read"}) */ @@ -369,11 +428,54 @@ class Household return $this->waitingForBirthDate; } + /** + * @internal + */ + public function householdCompositionConsistency(): void + { + $compositionOrdered = $this->compositions->toArray(); + + usort( + $compositionOrdered, + static function (HouseholdComposition $a, HouseholdComposition $b) { + return $a->getStartDate() <=> $b->getStartDate(); + } + ); + + $iterator = new ArrayIterator($compositionOrdered); + $iterator->rewind(); + + /** @var ?HouseholdComposition $previous */ + $previous = null; + + do { + /** @var ?HouseholdComposition $current */ + $current = $iterator->current(); + + if (null !== $previous) { + if (null === $previous->getEndDate() || $previous->getEndDate() > $current->getStartDate()) { + $previous->setEndDate($current->getStartDate()); + } + } + $previous = $current; + $iterator->next(); + } while ($iterator->valid()); + } + public function removeAddress(Address $address) { $this->addresses->removeElement($address); } + public function removeComposition(HouseholdComposition $composition): self + { + if ($this->compositions->removeElement($composition)) { + $composition->setHousehold(null); + } + + return $this; + } + public function removeMember(HouseholdMember $member): self { if ($this->members->removeElement($member)) { diff --git a/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdComposition.php b/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdComposition.php new file mode 100644 index 000000000..a381fafd8 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdComposition.php @@ -0,0 +1,171 @@ +comment = new CommentEmbeddable(); + } + + public function getComment(): CommentEmbeddable + { + return $this->comment; + } + + public function getEndDate(): ?DateTimeImmutable + { + return $this->endDate; + } + + public function getHousehold(): ?Household + { + return $this->household; + } + + public function getHouseholdCompositionType(): ?HouseholdCompositionType + { + return $this->householdCompositionType; + } + + public function getId(): ?int + { + return $this->id; + } + + public function getNumberOfChildren(): ?int + { + return $this->numberOfChildren; + } + + public function getStartDate(): ?DateTimeImmutable + { + return $this->startDate; + } + + public function setComment(CommentEmbeddable $comment): HouseholdComposition + { + $this->comment = $comment; + + return $this; + } + + public function setEndDate(?DateTimeImmutable $endDate): HouseholdComposition + { + $this->endDate = $endDate; + + if (null !== $this->household) { + $this->household->householdCompositionConsistency(); + } + + return $this; + } + + public function setHousehold(?Household $household): HouseholdComposition + { + $this->household = $household; + + return $this; + } + + public function setHouseholdCompositionType(?HouseholdCompositionType $householdCompositionType): HouseholdComposition + { + $this->householdCompositionType = $householdCompositionType; + + return $this; + } + + public function setNumberOfChildren(?int $numberOfChildren): HouseholdComposition + { + $this->numberOfChildren = $numberOfChildren; + + return $this; + } + + public function setStartDate(?DateTimeImmutable $startDate): HouseholdComposition + { + $this->startDate = $startDate; + + if (null !== $this->household) { + $this->household->householdCompositionConsistency(); + } + + return $this; + } +} diff --git a/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdCompositionType.php b/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdCompositionType.php new file mode 100644 index 000000000..03d1a401a --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdCompositionType.php @@ -0,0 +1,76 @@ +id; + } + + public function getLabel(): array + { + return $this->label; + } + + public function isActive(): bool + { + return $this->active; + } + + public function setActive(bool $active): HouseholdCompositionType + { + $this->active = $active; + + return $this; + } + + public function setLabel(array $label): HouseholdCompositionType + { + $this->label = $label; + + return $this; + } +} diff --git a/src/Bundle/ChillPersonBundle/Entity/Person.php b/src/Bundle/ChillPersonBundle/Entity/Person.php index 91e430a2f..e2847c73c 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Person.php +++ b/src/Bundle/ChillPersonBundle/Entity/Person.php @@ -1142,7 +1142,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI ->where( $expr->eq('shareHousehold', true) ) - ->orderBy(['startDate' => Criteria::DESC]); + ->orderBy(['startDate' => Criteria::DESC, 'id' => Criteria::DESC]); return $this->getHouseholdParticipations() ->matching($criteria); diff --git a/src/Bundle/ChillPersonBundle/Form/HouseholdCompositionType.php b/src/Bundle/ChillPersonBundle/Form/HouseholdCompositionType.php new file mode 100644 index 000000000..0348b0c39 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Form/HouseholdCompositionType.php @@ -0,0 +1,60 @@ +householdCompositionTypeRepository = $householdCompositionTypeRepository; + $this->translatableStringHelper = $translatableStringHelper; + } + + public function buildForm(FormBuilderInterface $builder, array $options) + { + $types = $this->householdCompositionTypeRepository->findAllActive(); + + $builder + ->add('householdCompositionType', EntityType::class, [ + 'class' => \Chill\PersonBundle\Entity\Household\HouseholdCompositionType::class, + 'choices' => $types, + 'choice_label' => function (\Chill\PersonBundle\Entity\Household\HouseholdCompositionType $type) { + return $this->translatableStringHelper->localize($type->getLabel()); + }, + 'label' => 'household_composition.Household composition', + ]) + ->add('startDate', ChillDateType::class, [ + 'required' => true, + 'input' => 'datetime_immutable', + ]) + ->add('numberOfChildren', IntegerType::class, [ + 'required' => true, + 'label' => 'household_composition.numberOfChildren', + ]) + ->add('comment', CommentType::class, [ + 'required' => false, + ]); + } +} diff --git a/src/Bundle/ChillPersonBundle/Household/MembersEditor.php b/src/Bundle/ChillPersonBundle/Household/MembersEditor.php index 4d855a980..adc97a4ac 100644 --- a/src/Bundle/ChillPersonBundle/Household/MembersEditor.php +++ b/src/Bundle/ChillPersonBundle/Household/MembersEditor.php @@ -29,6 +29,8 @@ class MembersEditor { public const VALIDATION_GROUP_AFFECTED = 'household_memberships'; + public const VALIDATION_GROUP_COMPOSITION = 'household_composition'; + public const VALIDATION_GROUP_CREATED = 'household_memberships_created'; private ?Household $household = null; @@ -77,6 +79,15 @@ class MembersEditor $this->oldMembershipsHashes[] = spl_object_hash($participation); } } + + foreach ($person->getHouseholdParticipationsNotShareHousehold() as $participation) { + if ($participation->getHousehold() === $this->household + && $participation->getEndDate() === null || $participation->getEndDate() > $membership->getStartDate() + && $participation->getStartDate() <= $membership->getStartDate() + ) { + $participation->setEndDate($membership->getStartDate()); + } + } } $this->membershipsAffected[] = $membership; @@ -129,7 +140,7 @@ class MembersEditor { if ($this->hasHousehold()) { $list = $this->validator - ->validate($this->getHousehold(), null, [self::VALIDATION_GROUP_AFFECTED]); + ->validate($this->getHousehold(), null, [self::VALIDATION_GROUP_AFFECTED, self::VALIDATION_GROUP_COMPOSITION]); } else { $list = new ConstraintViolationList(); } diff --git a/src/Bundle/ChillPersonBundle/Menu/HouseholdMenuBuilder.php b/src/Bundle/ChillPersonBundle/Menu/HouseholdMenuBuilder.php index a144bf65b..a4d3f8d03 100644 --- a/src/Bundle/ChillPersonBundle/Menu/HouseholdMenuBuilder.php +++ b/src/Bundle/ChillPersonBundle/Menu/HouseholdMenuBuilder.php @@ -29,6 +29,7 @@ class HouseholdMenuBuilder implements LocalMenuBuilderInterface public function buildMenu($menuId, MenuItem $menu, array $parameters): void { + /** @var \Chill\PersonBundle\Entity\Household\Household $household */ $household = $parameters['household']; $menu->addChild($this->translator->trans('household.Household summary'), [ @@ -38,6 +39,20 @@ class HouseholdMenuBuilder implements LocalMenuBuilderInterface ], ]) ->setExtras(['order' => 10]); + $menu->addChild($this->translator->trans('household.Relationship'), [ + 'route' => 'chill_person_household_relationship', + 'routeParameters' => [ + 'household_id' => $household->getId(), + ], ]) + ->setExtras(['order' => 15]); + + $menu->addChild($this->translator->trans('household_composition.Compositions'), [ + 'route' => 'chill_person_household_composition_index', + 'routeParameters' => [ + 'id' => $household->getId(), + ], ]) + ->setExtras(['order' => 17]); + $menu->addChild($this->translator->trans('household.Accompanying period'), [ 'route' => 'chill_person_household_accompanying_period', 'routeParameters' => [ @@ -51,13 +66,6 @@ class HouseholdMenuBuilder implements LocalMenuBuilderInterface 'household_id' => $household->getId(), ], ]) ->setExtras(['order' => 30]); - - $menu->addChild($this->translator->trans('household.Relationship'), [ - 'route' => 'chill_person_household_relationship', - 'routeParameters' => [ - 'household_id' => $household->getId(), - ], ]) - ->setExtras(['order' => 15]); } public static function getMenuIds(): array diff --git a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepository.php b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepository.php index 0649dae1c..dc5e8f5d3 100644 --- a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepository.php @@ -39,7 +39,7 @@ final class HouseholdACLAwareRepository implements HouseholdACLAwareRepositoryIn { $centers = $this->authorizationHelper->getReachableCenters( $this->security->getUser(), - HouseholdVoter::SHOW + HouseholdVoter::SEE ); if ([] === $centers) { diff --git a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdCompositionRepository.php b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdCompositionRepository.php new file mode 100644 index 000000000..23f79c7f5 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdCompositionRepository.php @@ -0,0 +1,75 @@ +repository = $entityManager->getRepository(HouseholdComposition::class); + } + + public function countByHousehold(Household $household): int + { + return $this->repository->count(['household' => $household]); + } + + public function find($id): ?HouseholdComposition + { + return $this->repository->find($id); + } + + /** + * @return array|HouseholdComposition[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + /** + * @param int $limit + * @param int $offset + * + * @return array|object[]|HouseholdComposition[] + */ + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + /** + * @return array|HouseholdComposition[]|object[] + */ + public function findByHousehold(Household $household, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array + { + return $this->findBy(['household' => $household], $orderBy, $limit, $offset); + } + + public function findOneBy(array $criteria): ?HouseholdComposition + { + return $this->repository->findOneBy($criteria); + } + + public function getClassName(): string + { + return HouseholdComposition::class; + } +} diff --git a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdCompositionTypeRepository.php b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdCompositionTypeRepository.php new file mode 100644 index 000000000..45931b4da --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdCompositionTypeRepository.php @@ -0,0 +1,69 @@ +repository = $entityManager->getRepository(HouseholdCompositionType::class); + } + + public function find($id): ?HouseholdCompositionType + { + return $this->repository->find($id); + } + + /** + * @return array|HouseholdCompositionType[]|object[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + /** + * @return array|HouseholdCompositionType[] + */ + public function findAllActive(): array + { + return $this->findBy(['active' => true]); + } + + /** + * @param $limit + * @param $offset + * + * @return array|HouseholdCompositionType[]|object[] + */ + 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): ?HouseholdCompositionType + { + return $this->repository->findOneBy($criteria); + } + + public function getClassName(): string + { + return HouseholdCompositionType::class; + } +} diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/App.vue index 22b4f54a6..52047c630 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/App.vue @@ -32,7 +32,7 @@
  • -
  • @@ -104,6 +104,13 @@ export default { return false; }, + lastStepIsSaveAllowed() { + let r = !this.$store.getters.isHouseholdNew || + (this.$store.state.numberOfChildren !== null && this.$store.state.householdCompositionType !== null); + console.log('is saved allowed ?', r); + + return r; + }, }, methods: { goToNext() { diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Concerned.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Concerned.vue index 3be8822be..74271954f 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Concerned.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Concerned.vue @@ -7,18 +7,14 @@
    -

    - {{ $t('household_members_editor.concerned.persons_will_be_moved') }} : - - - - -

    +

    {{ $t('household_members_editor.concerned.persons_will_be_moved') }} :

    + + +

    {{ $t('household_members_editor.concerned.persons_with_household') }}

      @@ -108,9 +104,14 @@ export default { this.$refs.addPersons.resetSearch(); // to cast child method modal.showModal = false; }, - removePerson(person) { - console.log('remove person in concerned', person); - this.$store.dispatch('removePerson', person); + removeConcerned(concerned) { + console.log('removedconcerned', concerned); + + if (!concerned.allowRemove) { + return; + } + + this.$store.dispatch('removePerson', concerned.person); }, makeHouseholdLink(id) { return `/fr/person/household/${id}/summary` 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 c40cc9cbc..94c1a146a 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Dates.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Dates.vue @@ -4,17 +4,38 @@

      {{ $t('household_members_editor.dates.dates_title') }}

      -

      -

      + - -

      +
      + +
      +
      + +
      +

      {{ $t('household_members_editor.composition.composition') }}

      +
      + +
      + +
      +
      +
      + +
      + +
      +
      +
      + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Positioning.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Positioning.vue index 8e033234c..487fb230e 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Positioning.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Positioning.vue @@ -3,15 +3,15 @@

      {{ $t('household_members_editor.positioning.persons_to_positionnate')}}

      -
      +
      -
      +
      - +

      {{ conc.person.text }}

      +
      +
      +
      {{ $t('household_members_editor.positioning.comment') }}
      + +
      +
      @@ -46,12 +52,14 @@ import MemberDetails from './MemberDetails.vue'; import {mapGetters, mapState} from "vuex"; import CurrentHousehold from "./CurrentHousehold"; import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue'; +import PersonComment from './PersonComment'; export default { name: "Positioning", components: { CurrentHousehold, PersonRenderBox, + PersonComment, }, computed: { ...mapState([ 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 e09fddf0f..66246058f 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/js/i18n.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/js/i18n.js @@ -52,6 +52,7 @@ const appMessages = { positioning: { persons_to_positionnate: 'Usagers à positionner', holder: "Titulaire", + comment: "Commentaire", }, app: { next: 'Suivant', @@ -77,7 +78,12 @@ const appMessages = { dates: { start_date: "Début de validité", end_date: "Fin de validité", - dates_title: "Période de validité", + dates_title: "Depuis le", + }, + composition: { + composition: "Composition familiale", + household_composition: "Composition du ménage", + number_of_children: "Nombre d'enfants mineurs au sein du ménage", }, 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 cd43ee29c..cc5ab497c 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/store/index.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/store/index.js @@ -1,5 +1,6 @@ import { createStore } from 'vuex'; import { householdMove, fetchHouseholdSuggestionByAccompanyingPeriod, fetchAddressSuggestionByPerson} from './../api.js'; +import { fetchResults } from 'ChillMainAssets/lib/api/apiMethods.js' import { fetchHouseholdByAddressReference } from 'ChillPersonAssets/lib/household.js'; import { datetimeToISO } from 'ChillMainAssets/chill/js/date.js'; @@ -54,8 +55,11 @@ const store = createStore({ */ householdSuggestionByAccompanyingPeriod: [], // TODO rename into householdsSuggestion showHouseholdSuggestion: window.household_members_editor_expand_suggestions === 1, + householdCompositionType: null, + numberOfChildren: 0, addressesSuggestion: [], showAddressSuggestion: true, + householdCompositionTypes: [], warnings: [], errors: [] }, @@ -250,7 +254,8 @@ const store = createStore({ payload_conc, payload = { concerned: [], - destination: null + destination: null, + composition: null, } ; @@ -261,7 +266,6 @@ const store = createStore({ }; if (getters.isHouseholdNew && state.household.current_address !== null) { - console.log(state.household); payload.destination.forceAddress = { id: state.household.current_address.address_id }; } } @@ -290,6 +294,19 @@ const store = createStore({ payload.concerned.push(payload_conc); } + if (getters.isHouseholdNew) { + payload.composition = { + household_composition_type: { + type: state.householdCompositionType.type, + id: state.householdCompositionType.id, + }, + number_of_children: state.numberOfChildren, + start_date: { + datetime: datetimeToISO(state.startDate), + }, + }; + } + return payload; }, }, @@ -409,6 +426,15 @@ const store = createStore({ setErrors(state, errors) { state.errors = errors; }, + setHouseholdCompositionTypes(state, types) { + state.householdCompositionTypes = types; + }, + setHouseholdCompositionType(state, id) { + state.householdCompositionType = state.householdCompositionTypes.find(t => t.id = id); + }, + setNumberOfChildren(state, number) { + state.numberOfChildren = Number.parseInt(number); + }, addAddressesSuggestion(state, addresses) { let existingIds = state.addressesSuggestion .map(a => a.address_id); @@ -570,4 +596,8 @@ if (concerned.length > 0) { }); } +fetchResults(`/api/1.0/person/houehold/composition/type.json`).then(types => { + store.commit('setHouseholdCompositionTypes', types); +}) + export { store }; diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/_warning_address.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/_warning_address.html.twig index 2febc7967..1f9c09845 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/_warning_address.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/_warning_address.html.twig @@ -1,23 +1,25 @@ {%- set countPersonLocation = accompanyingCourse.availablePersonLocation|length -%} {%- set hasPersonLocation = countPersonLocation > 0 -%}
      -
      -
      - +
      +
      + +

      + {{ 'This course is located at a temporarily address. You should locate this course to an user'|trans }}

      + {% if not hasPersonLocation %} +

      + {{ 'Associate at least one member with an household, and set an address to this household'|trans }}

      + {% endif %}
      -

      - {{ 'This course is located at a temporarily address. You should locate this course to an user'|trans }}

      - {% if not hasPersonLocation %} -

      - {{ 'Associate at least one member with an household, and set an address to this household'|trans }}

      - {% endif %} -
      +
      diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Household/members_editor.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Household/members_editor.html.twig index ee578203a..8b0134f6b 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/Household/members_editor.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/Household/members_editor.html.twig @@ -4,12 +4,14 @@ {% block title 'household.Edit household members'|trans %} {% block content %} -
      +
      +
      -

      {{ block('title') }}

      -
      +

      {{ block('title') }}

      +
      -
      +
      +
      {% endblock %} {% block js %} diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Household/summary.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Household/summary.html.twig index bbb8ff52f..a00c8df36 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/Household/summary.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/Household/summary.html.twig @@ -51,7 +51,42 @@
      {% if form is null %} - + {% set currentComposition = household.currentComposition %} + {% if currentComposition is not null %} +
      +
      + {{ currentComposition.householdCompositionType.label|localize_translatable_string }} +
      +

      + {{ 'household_composition.numberOfChildren children in household'|trans({'numberOfChildren': currentComposition.numberOfChildren}) }} +

      +

      + {{ 'household_composition.Since'|trans({'startDate': currentComposition.startDate}) }} +

      + +
      + {% else %} +
      +

      + {{ 'household_composition.Currently no composition'|trans }} +

      + +
      + {% endif %} {% if household.waitingForBirth or not household.commentMembers.isEmpty() %}
      {% if household.waitingForBirth %} @@ -176,13 +211,26 @@ {{ 'household.Hide memberships'|trans }} + + {% macro buttonsOldMembers(member) %} + {% set household = member.person.getCurrentHousehold %} + {% if household is not null %} +
    • + +
    • + {% endif %} + {% endmacro %} +
      {% for m in old_members %} - {% include '@ChillPerson/Household/_render_member.html.twig' with { 'member': m } %} + {% include '@ChillPerson/Household/_render_member.html.twig' with { + 'member': m, + 'customButtons': { 'before': _self.buttonsOldMembers(m) } + } %} {% endfor %}
      diff --git a/src/Bundle/ChillPersonBundle/Resources/views/HouseholdComposition/index.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/HouseholdComposition/index.html.twig new file mode 100644 index 000000000..594863a64 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/views/HouseholdComposition/index.html.twig @@ -0,0 +1,96 @@ +{% extends '@ChillPerson/Household/layout.html.twig' %} + +{% block title 'household_composition.Compositions'|trans %} + +{% block block_post_menu %} +
      +{% endblock %} + +{% block content %} +
      +

      {{ block('title') }}

      + + {% if compositions|length == 0 %} +

      {{ 'household_composition.No composition yet'|trans }}

      + {% else %} +
      + {% for c in compositions %} + {% if c.id != editId %} +
      +
      +
      +

      {{ c.householdCompositionType.label|localize_translatable_string }}

      +

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

      +
      +
      {{ 'household_composition.Since'|trans({'startDate': c.startDate}) }}
      +
      +
      +
      + {% if c.endDate is null %} + {{ 'household_composition.Still active'|trans }} + {% else %} + {{ 'household_composition.Until'|trans({'endDate': c.endDate })}} + {% endif %} +
      +
      + {% if c.comment.comment is not empty %} +
      + {{ c.comment|chill_entity_render_box }} +
      + {% endif %} + {% if is_granted('CHILL_PERSON_HOUSEHOLD_EDIT', c.household) %} +
      +
        +
      • + +
      • +
      • + +
      • +
      +
      + {% endif %} +
      + {% else %} + {{ form_start(form) }} + + {{ form_widget(form) }} + + + {{ form_end(form) }} + {% endif %} + {% endfor %} +
      + {% endif %} + +
      + {{ form_start(form) }} + + {{ form_widget(form) }} + +
        +
      • + +
      • +
      + {{ form_end(form) }} +
      + + {% if editId == -1 %} +
        +
      • + +
      • +
      + {% endif %} +
      +{% endblock %} diff --git a/src/Bundle/ChillPersonBundle/Security/Authorization/HouseholdVoter.php b/src/Bundle/ChillPersonBundle/Security/Authorization/HouseholdVoter.php index b702e798e..cdc62c2cf 100644 --- a/src/Bundle/ChillPersonBundle/Security/Authorization/HouseholdVoter.php +++ b/src/Bundle/ChillPersonBundle/Security/Authorization/HouseholdVoter.php @@ -11,7 +11,66 @@ declare(strict_types=1); namespace Chill\PersonBundle\Security\Authorization; -class HouseholdVoter +use Chill\PersonBundle\Entity\Household\Household; +use Chill\PersonBundle\Entity\Household\HouseholdMember; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; +use Symfony\Component\Security\Core\Security; +use UnexpectedValueException; +use function in_array; + +class HouseholdVoter extends Voter { - public const SHOW = PersonVoter::SEE; + public const EDIT = 'CHILL_PERSON_HOUSEHOLD_EDIT'; + + public const SEE = 'CHILL_PERSON_HOUSEHOLD_SEE'; + + /** + * @deprecated use @see{self::SEE} instead + */ + public const SHOW = self::SEE; + + private const ALL = [ + self::EDIT, self::SEE, + ]; + + private Security $security; + + public function __construct(Security $security) + { + $this->security = $security; + } + + protected function supports($attribute, $subject) + { + return $subject instanceof Household + && in_array($attribute, self::ALL, true); + } + + protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool + { + switch ($attribute) { + case self::SEE: + return $this->checkAssociatedMembersRole($subject, PersonVoter::SEE); + + case self::EDIT: + return $this->checkAssociatedMembersRole($subject, PersonVoter::UPDATE); + + default: + throw new UnexpectedValueException('attribute not supported'); + } + } + + private function checkAssociatedMembersRole(Household $household, string $attribute): bool + { + foreach ($household->getCurrentMembers()->map(static function (HouseholdMember $member) { + return $member->getPerson(); + }) as $person) { + if ($this->security->isGranted($attribute, $person)) { + return true; + } + } + + return false; + } } diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php index e2fb0f7dc..757a0bfcb 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php @@ -12,6 +12,8 @@ declare(strict_types=1); namespace Chill\PersonBundle\Serializer\Normalizer; use Chill\PersonBundle\Entity\Household\Household; +use Chill\PersonBundle\Entity\Household\HouseholdComposition; +use Chill\PersonBundle\Entity\Household\HouseholdCompositionType; use Chill\PersonBundle\Entity\Household\Position; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Household\MembersEditor; @@ -22,6 +24,7 @@ use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use UnexpectedValueException; use function array_key_exists; class MembersEditorNormalizer implements DenormalizerAwareInterface, DenormalizerInterface @@ -148,6 +151,23 @@ 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']; + $startDate = $this->denormalizer->denormalize($data['composition']['start_date'], DateTimeImmutable::class, $format, $context); + + if (null === $compositionType) { + throw new UnexpectedValueException('composition type cannot be null'); + } + + $householdComposition = (new HouseholdComposition()) + ->setHouseholdCompositionType($compositionType) + ->setNumberOfChildren($numberOfChildren) + ->setStartDate($startDate); + + $household->addComposition($householdComposition); + } + return $editor; } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdMemberControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdMemberControllerTest.php index f2427bfe8..4706a14d8 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdMemberControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdMemberControllerTest.php @@ -169,6 +169,7 @@ final class HouseholdMemberControllerTest extends WebTestCase ], ], 'destination' => null, + 'composition' => null, ] ) ); @@ -223,6 +224,7 @@ final class HouseholdMemberControllerTest extends WebTestCase 'type' => 'household', 'id' => $householdId, ], + 'composition' => null, ] ) ); @@ -272,6 +274,7 @@ final class HouseholdMemberControllerTest extends WebTestCase 'destination' => [ 'type' => 'household', ], + 'composition' => null, ] ) ); diff --git a/src/Bundle/ChillPersonBundle/Tests/Entity/Household/HouseholdTest.php b/src/Bundle/ChillPersonBundle/Tests/Entity/Household/HouseholdTest.php new file mode 100644 index 000000000..f63c12a2c --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Entity/Household/HouseholdTest.php @@ -0,0 +1,47 @@ +addComposition(($first = new HouseholdComposition()) + ->setStartDate(new DateTimeImmutable('2021-12-01'))); + + $this->assertNull($first->getEndDate()); + + $household->addComposition(($second = new HouseholdComposition()) + ->setStartDate(new DateTimeImmutable('2021-12-31'))); + + $this->assertEquals(new DateTimeImmutable('2021-12-31'), $first->getEndDate()); + $this->assertEquals(new DateTimeImmutable('2021-12-31'), $second->getStartDate()); + + $household->addComposition(($inside = new HouseholdComposition()) + ->setStartDate(new DateTimeImmutable('2021-12-15'))); + + $this->assertEquals(new DateTimeImmutable('2021-12-15'), $first->getEndDate()); + $this->assertEquals(new DateTimeImmutable('2021-12-31'), $second->getStartDate()); + $this->assertEquals(new DateTimeImmutable('2021-12-31'), $inside->getEndDate()); + } +} diff --git a/src/Bundle/ChillPersonBundle/config/services/security.yaml b/src/Bundle/ChillPersonBundle/config/services/security.yaml index f54d4cdfb..0094e180b 100644 --- a/src/Bundle/ChillPersonBundle/config/services/security.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/security.yaml @@ -25,3 +25,7 @@ services: autoconfigure: true tags: - { name: security.voter } + + Chill\PersonBundle\Security\Authorization\HouseholdVoter: + autowire: true + autoconfigure: true diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20220121121310.php b/src/Bundle/ChillPersonBundle/migrations/Version20220121121310.php new file mode 100644 index 000000000..01fe951e1 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/migrations/Version20220121121310.php @@ -0,0 +1,51 @@ +addSql('DROP SEQUENCE chill_person_household_composition_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_person_household_composition_type_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_person_household_composition'); + $this->addSql('DROP TABLE chill_person_household_composition_type'); + } + + public function getDescription(): string + { + return 'Create table for household composition'; + } + + public function up(Schema $schema): void + { + $this->addSql('CREATE SEQUENCE chill_person_household_composition_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE SEQUENCE chill_person_household_composition_type_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE TABLE chill_person_household_composition (id INT NOT NULL, household_id INT NOT NULL, endDate DATE DEFAULT NULL, numberOfChildren INT DEFAULT NULL, startDate DATE NOT NULL, createdAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, updatedAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, comment_comment TEXT DEFAULT NULL, comment_date TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, comment_userId INT DEFAULT NULL, householdCompositionType_id INT NOT NULL, createdBy_id INT DEFAULT NULL, updatedBy_id INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_E62BEE83E79FF843 ON chill_person_household_composition (household_id)'); + $this->addSql('CREATE INDEX IDX_E62BEE83CDEA4FCF ON chill_person_household_composition (householdCompositionType_id)'); + $this->addSql('CREATE INDEX IDX_E62BEE833174800F ON chill_person_household_composition (createdBy_id)'); + $this->addSql('CREATE INDEX IDX_E62BEE8365FF1AEC ON chill_person_household_composition (updatedBy_id)'); + $this->addSql('COMMENT ON COLUMN chill_person_household_composition.endDate IS \'(DC2Type:date_immutable)\''); + $this->addSql('COMMENT ON COLUMN chill_person_household_composition.startDate IS \'(DC2Type:date_immutable)\''); + $this->addSql('CREATE TABLE chill_person_household_composition_type (id INT NOT NULL, active BOOLEAN NOT NULL, label JSON NOT NULL, PRIMARY KEY(id))'); + $this->addSql('ALTER TABLE chill_person_household_composition ADD CONSTRAINT FK_E62BEE83E79FF843 FOREIGN KEY (household_id) REFERENCES chill_person_household (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_person_household_composition ADD CONSTRAINT FK_E62BEE83CDEA4FCF FOREIGN KEY (householdCompositionType_id) REFERENCES chill_person_household_composition_type (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_person_household_composition ADD CONSTRAINT FK_E62BEE833174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_person_household_composition ADD CONSTRAINT FK_E62BEE8365FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('COMMENT ON COLUMN chill_person_household_composition.createdAt IS \'(DC2Type:date_immutable)\''); + $this->addSql('COMMENT ON COLUMN chill_person_household_composition.updatedAt IS \'(DC2Type:date_immutable)\''); + } +} diff --git a/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml b/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml index fcf70c350..ecafb367e 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml +++ b/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml @@ -98,3 +98,17 @@ household: from: Depuis to: Jusqu'au person history: Ménages + +household_composition: + Since: >- + Depuis le {startDate, date, long} + Still active: Toujours actif + Until: >- + Jusqu'au {endDate, date, long} + numberOfChildren children in household: >- + {numberOfChildren, plural, + =0 {Aucun enfant dans le ménage} + one {1 enfant dans le ménage} + few {# enfants dans le ménage} + other {# enfants dans le ménage} + } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 5d0e2b16a..20de73705 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -498,3 +498,14 @@ period_notification: You are getting a notification for a period which does not exists any more: Cette notification ne correspond pas à une période d'accompagnement valide. You are getting a notification for a period you are not allowed to see: La notification fait référence à une période d'accompagnement à laquelle vous n'avez pas accès. This is the minimal period details: Période d'accompagnement n° + +household_composition: + No composition yet: Aucune composition familiale renseignée + Compositions: Composition familiale + endDate: Date de fin + numberOfChildren: Nombre d'enfants mineurs au sein du ménage + Household composition: Composition du ménage + Composition added: Information sur la composition familiale ajoutée + Currently no composition: Aucune composition famiale renseignée. + Add a composition: Ajouter une composition familiale + Update composition: Modifier la composition familiale