diff --git a/src/Bundle/ChillActivityBundle/Service/DocGenerator/ActivityContext.php b/src/Bundle/ChillActivityBundle/Service/DocGenerator/ActivityContext.php index 624859eda..a20ca365b 100644 --- a/src/Bundle/ChillActivityBundle/Service/DocGenerator/ActivityContext.php +++ b/src/Bundle/ChillActivityBundle/Service/DocGenerator/ActivityContext.php @@ -24,6 +24,9 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Repository\PersonRepository; use Chill\PersonBundle\Templating\Entity\PersonRenderInterface; +use Chill\ThirdPartyBundle\Entity\ThirdParty; +use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender; +use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; @@ -55,6 +58,10 @@ class ActivityContext implements private TranslatorInterface $translator; + private ThirdPartyRender $thirdPartyRender; + + private ThirdPartyRepository $thirdPartyRepository; + public function __construct( DocumentCategoryRepository $documentCategoryRepository, NormalizerInterface $normalizer, @@ -63,7 +70,9 @@ class ActivityContext implements PersonRenderInterface $personRender, PersonRepository $personRepository, TranslatorInterface $translator, - BaseContextData $baseContextData + BaseContextData $baseContextData, + ThirdPartyRender $thirdPartyRender, + ThirdPartyRepository $thirdPartyRepository ) { $this->documentCategoryRepository = $documentCategoryRepository; $this->normalizer = $normalizer; @@ -73,6 +82,8 @@ class ActivityContext implements $this->personRepository = $personRepository; $this->translator = $translator; $this->baseContextData = $baseContextData; + $this->thirdPartyRender = $thirdPartyRender; + $this->thirdPartyRepository = $thirdPartyRepository; } public function adminFormReverseTransform(array $data): array @@ -89,6 +100,8 @@ class ActivityContext implements 'person1Label' => $data['person1Label'] ?? $this->translator->trans('docgen.person 1'), 'person2' => $data['person2'] ?? false, 'person2Label' => $data['person2Label'] ?? $this->translator->trans('docgen.person 2'), + 'thirdParty' => $data['thirdParty'] ?? false, + 'thirdPartyLabel' => $data['thirdPartyLabel'] ?? $this->translator->trans('thirdParty'), ]; } @@ -118,6 +131,14 @@ class ActivityContext implements ->add('person2Label', TextType::class, [ 'label' => 'person 2 label', 'required' => true, + ]) + ->add('thirdParty', CheckboxType::class, [ + 'required' => false, + 'label' => 'docgen.Ask for thirdParty', + ]) + ->add('thirdPartyLabel', TextType::class, [ + 'label' => 'docgen.thirdParty label', + 'required' => true, ]); } @@ -143,6 +164,20 @@ class ActivityContext implements ]); } } + + $thirdParties = $entity->getThirdParties(); + if ($options['thirdParty'] ?? false) { + $builder->add('thirdParty', EntityType::class, [ + 'class' => ThirdParty::class, + 'choices' => $thirdParties, + 'choice_label' => fn (ThirdParty $p) => $this->thirdPartyRender->renderString($p, []), + 'multiple' => false, + 'required' => false, + 'expanded' => true, + 'label' => $options['thirdPartyLabel'], + 'placeholder' => $this->translator->trans('Any third party selected'), + ]); + } } public function contextGenerationDataDenormalize(DocGeneratorTemplate $template, $entity, array $data): array @@ -157,6 +192,12 @@ class ActivityContext implements } } + if (null !== ($id = ($data['thirdParty'] ?? null))) { + $denormalized['thirdParty'] = $this->thirdPartyRepository->find($id); + } else { + $denormalized['thirdParty'] = null; + } + return $denormalized; } @@ -165,9 +206,11 @@ class ActivityContext implements $normalized = []; foreach (['mainPerson', 'person1', 'person2'] as $k) { - $normalized[$k] = null === $data[$k] ? null : $data[$k]->getId(); + $normalized[$k] = ($data[$k] ?? null)?->getId(); } + $normalized['thirdParty'] = ($data['thirdParty'] ?? null)?->getId(); + return $normalized; } @@ -196,6 +239,13 @@ class ActivityContext implements } } + if ($options['thirdParty']) { + $data['thirdParty'] = $this->normalizer->normalize($contextGenerationData['thirdParty'], 'docgen', [ + 'docgen:expects' => ThirdParty::class, + 'groups' => 'docgen:read' + ]); + } + return $data; } @@ -235,7 +285,7 @@ class ActivityContext implements { $options = $template->getOptions(); - return $options['mainPerson'] || $options['person1'] || $options['person2']; + return $options['mainPerson'] || $options['person1'] || $options['person2'] || $options ['thirdParty']; } public function storeGenerated(DocGeneratorTemplate $template, StoredObject $storedObject, object $entity, array $contextGenerationData): void diff --git a/src/Bundle/ChillPersonBundle/Service/DocGenerator/AccompanyingPeriodContext.php b/src/Bundle/ChillPersonBundle/Service/DocGenerator/AccompanyingPeriodContext.php index a42765c12..4f6235930 100644 --- a/src/Bundle/ChillPersonBundle/Service/DocGenerator/AccompanyingPeriodContext.php +++ b/src/Bundle/ChillPersonBundle/Service/DocGenerator/AccompanyingPeriodContext.php @@ -22,10 +22,14 @@ use Chill\DocStoreBundle\Entity\StoredObject; use Chill\DocStoreBundle\Repository\DocumentCategoryRepository; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource; use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Repository\PersonRepository; use Chill\PersonBundle\Templating\Entity\PersonRenderInterface; +use Chill\ThirdPartyBundle\Entity\ThirdParty; +use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender; +use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository; use DateTime; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\EntityManagerInterface; @@ -40,6 +44,7 @@ use Symfony\Contracts\Translation\TranslatorInterface; use function array_key_exists; /** + * @see AccompanyingPeriodContextTest * @template-implements DocGeneratorContextWithPublicFormInterface */ class AccompanyingPeriodContext implements @@ -62,6 +67,10 @@ class AccompanyingPeriodContext implements private TranslatorInterface $translator; + private ThirdPartyRender $thirdPartyRender; + + private ThirdPartyRepository $thirdPartyRepository; + public function __construct( DocumentCategoryRepository $documentCategoryRepository, NormalizerInterface $normalizer, @@ -70,7 +79,9 @@ class AccompanyingPeriodContext implements PersonRenderInterface $personRender, PersonRepository $personRepository, TranslatorInterface $translator, - BaseContextData $baseContextData + BaseContextData $baseContextData, + ThirdPartyRender $thirdPartyRender, + ThirdPartyRepository $thirdPartyRepository ) { $this->documentCategoryRepository = $documentCategoryRepository; $this->normalizer = $normalizer; @@ -80,6 +91,8 @@ class AccompanyingPeriodContext implements $this->personRepository = $personRepository; $this->translator = $translator; $this->baseContextData = $baseContextData; + $this->thirdPartyRender = $thirdPartyRender; + $this->thirdPartyRepository = $thirdPartyRepository; } public function adminFormReverseTransform(array $data): array @@ -103,11 +116,12 @@ class AccompanyingPeriodContext implements 'person1Label' => $data['person1Label'] ?? $this->translator->trans('docgen.person 1'), 'person2' => $data['person2'] ?? false, 'person2Label' => $data['person2Label'] ?? $this->translator->trans('docgen.person 2'), + 'thirdParty' => $data['thirdParty'] ?? false, + 'thirdPartyLabel' => $data['thirdPartyLabel'] ?? $this->translator->trans('Third party'), ]; if (array_key_exists('category', $data)) { - $r['category'] = array_key_exists('category', $data) ? - $this->documentCategoryRepository->find($data['category']) : null; + $r['category'] = $this->documentCategoryRepository->find($data['category']); } return $r; @@ -140,6 +154,14 @@ class AccompanyingPeriodContext implements 'label' => 'person 2 label', 'required' => true, ]) + ->add('thirdParty', CheckboxType::class, [ + 'required' => false, + 'label' => 'docgen.Ask for thirdParty', + ]) + ->add('thirdPartyLabel', TextType::class, [ + 'label' => 'docgen.thirdParty label', + 'required' => true, + ]) ->add('category', EntityType::class, [ 'placeholder' => 'Choose a document category', 'class' => DocumentCategory::class, @@ -190,6 +212,28 @@ class AccompanyingPeriodContext implements ]); } } + + $thirdParties = [...array_values(array_filter([$entity->getRequestorThirdParty()])), ...array_values(array_filter( + array_map( + fn (Resource $r): ?ThirdParty => $r->getThirdParty(), + $entity->getResources()->filter( + static fn (Resource $r): bool => null !== $r->getThirdParty() + )->toArray() + ) + ))]; + + if ($options['thirdParty'] ?? false) { + $builder->add('thirdParty', EntityType::class, [ + 'class' => ThirdParty::class, + 'choices' => $thirdParties, + 'choice_label' => fn (ThirdParty $p) => $this->thirdPartyRender->renderString($p, []), + 'multiple' => false, + 'required' => false, + 'expanded' => true, + 'label' => $options['thirdPartyLabel'], + 'placeholder' => $this->translator->trans('Any third party selected'), + ]); + } } public function getData(DocGeneratorTemplate $template, $entity, array $contextGenerationData = []): array @@ -215,6 +259,13 @@ class AccompanyingPeriodContext implements } } + if ($options['thirdParty']) { + $data['thirdParty'] = $this->normalizer->normalize($contextGenerationData['thirdParty'], 'docgen', [ + 'docgen:expects' => ThirdParty::class, + 'groups' => 'docgen:read' + ]); + } + return $data; } @@ -254,7 +305,7 @@ class AccompanyingPeriodContext implements { $options = $template->getOptions(); - return $options['mainPerson'] || $options['person1'] || $options['person2']; + return $options['mainPerson'] || $options['person1'] || $options['person2'] || $options ['thirdParty']; } public function contextGenerationDataNormalize(DocGeneratorTemplate $template, $entity, array $data): array @@ -264,6 +315,8 @@ class AccompanyingPeriodContext implements $normalized[$k] = null !== ($data[$k] ?? null) ? $data[$k]->getId() : null; } + $normalized['thirdParty'] = ($data['thirdParty'] ?? null)?->getId(); + return $normalized; } @@ -279,6 +332,12 @@ class AccompanyingPeriodContext implements } } + if (null !== ($id = ($data['thirdParty'] ?? null))) { + $denormalized['thirdParty'] = $this->thirdPartyRepository->find($id); + } else { + $denormalized['thirdParty'] = null; + } + return $denormalized; } diff --git a/src/Bundle/ChillPersonBundle/Service/DocGenerator/AccompanyingPeriodWorkEvaluationContext.php b/src/Bundle/ChillPersonBundle/Service/DocGenerator/AccompanyingPeriodWorkEvaluationContext.php index 34b339822..f58788120 100644 --- a/src/Bundle/ChillPersonBundle/Service/DocGenerator/AccompanyingPeriodWorkEvaluationContext.php +++ b/src/Bundle/ChillPersonBundle/Service/DocGenerator/AccompanyingPeriodWorkEvaluationContext.php @@ -18,13 +18,18 @@ use Chill\DocStoreBundle\Entity\StoredObject; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument; +use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource; use Chill\PersonBundle\Entity\SocialWork\Evaluation; use Chill\PersonBundle\Repository\SocialWork\EvaluationRepository; +use Chill\ThirdPartyBundle\Entity\ThirdParty; +use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender; +use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Contracts\Translation\TranslatorInterface; /** * @implements DocGeneratorContextWithPublicFormInterface @@ -43,18 +48,26 @@ class AccompanyingPeriodWorkEvaluationContext implements private TranslatableStringHelperInterface $translatableStringHelper; + private ThirdPartyRender $thirdPartyRender; + + private TranslatorInterface $translator; + public function __construct( AccompanyingPeriodWorkContext $accompanyingPeriodWorkContext, EntityManagerInterface $em, EvaluationRepository $evaluationRepository, NormalizerInterface $normalizer, - TranslatableStringHelperInterface $translatableStringHelper + TranslatableStringHelperInterface $translatableStringHelper, + ThirdPartyRender $thirdPartyRender, + TranslatorInterface $translator ) { $this->accompanyingPeriodWorkContext = $accompanyingPeriodWorkContext; $this->em = $em; $this->evaluationRepository = $evaluationRepository; $this->normalizer = $normalizer; $this->translatableStringHelper = $translatableStringHelper; + $this->thirdPartyRender = $thirdPartyRender; + $this->translator = $translator; } public function adminFormReverseTransform(array $data): array @@ -102,6 +115,31 @@ class AccompanyingPeriodWorkEvaluationContext implements public function buildPublicForm(FormBuilderInterface $builder, DocGeneratorTemplate $template, $entity): void { $this->accompanyingPeriodWorkContext->buildPublicForm($builder, $template, $entity->getAccompanyingPeriodWork()); + + $thirdParties = [...array_values(array_filter($entity->getAccompanyingPeriodWork()->getThirdParties()->toArray())), ...array_values(array_filter([$entity->getAccompanyingPeriodWork()->getHandlingThierParty()])), ...array_values( + array_filter( + array_map( + fn (Resource $r): ?ThirdParty => $r->getThirdParty(), + $entity->getAccompanyingPeriodWork()->getAccompanyingPeriod()->getResources()->filter( + static fn (Resource $r): bool => null !== $r->getThirdParty() + )->toArray() + ) + ) + )]; + + $options = $template->getOptions(); + if ($options['thirdParty'] ?? false) { + $builder->add('thirdParty', EntityType::class, [ + 'class' => ThirdParty::class, + 'choices' => $thirdParties, + 'choice_label' => fn (ThirdParty $p) => $this->thirdPartyRender->renderString($p, []), + 'multiple' => false, + 'required' => false, + 'expanded' => true, + 'label' => $options['thirdPartyLabel'], + 'placeholder' => $this->translator->trans('Any third party selected'), + ]); + } } public function getData(DocGeneratorTemplate $template, $entity, array $contextGenerationData = []): array @@ -116,7 +154,6 @@ class AccompanyingPeriodWorkEvaluationContext implements AbstractNormalizer::GROUPS => ['docgen:read'], ] ); - return $data; } diff --git a/src/Bundle/ChillPersonBundle/Service/DocGenerator/PersonContext.php b/src/Bundle/ChillPersonBundle/Service/DocGenerator/PersonContext.php index 1fdfd23d9..9d7f1cdd5 100644 --- a/src/Bundle/ChillPersonBundle/Service/DocGenerator/PersonContext.php +++ b/src/Bundle/ChillPersonBundle/Service/DocGenerator/PersonContext.php @@ -26,14 +26,22 @@ use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; +use Chill\PersonBundle\Entity\Person\PersonResource; use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Entity\Person\ResidentialAddress; use Chill\PersonBundle\Repository\PersonRepository; +use Chill\PersonBundle\Repository\ResidentialAddressRepository; +use Chill\ThirdPartyBundle\Entity\ThirdParty; +use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender; +use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository; use DateTime; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; use LogicException; +use Service\DocGenerator\PersonContextTest; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Security\Core\Security; @@ -43,6 +51,9 @@ use Symfony\Contracts\Translation\TranslatorInterface; use function array_key_exists; use function count; +/** + * @see PersonContextTest + */ final class PersonContext implements PersonContextInterface { private AuthorizationHelperInterface $authorizationHelper; @@ -67,6 +78,12 @@ final class PersonContext implements PersonContextInterface private TranslatorInterface $translator; + private ThirdPartyRender $thirdPartyRender; + + private ThirdPartyRepository $thirdPartyRepository; + + private ResidentialAddressRepository $residentialAddressRepository; + public function __construct( AuthorizationHelperInterface $authorizationHelper, BaseContextData $baseContextData, @@ -78,7 +95,10 @@ final class PersonContext implements PersonContextInterface ScopeRepositoryInterface $scopeRepository, Security $security, TranslatorInterface $translator, - TranslatableStringHelperInterface $translatableStringHelper + TranslatableStringHelperInterface $translatableStringHelper, + ThirdPartyRender $thirdPartyRender, + ThirdPartyRepository $thirdPartyRepository, + ResidentialAddressRepository $residentialAddressRepository ) { $this->authorizationHelper = $authorizationHelper; $this->centerResolverManager = $centerResolverManager; @@ -91,6 +111,9 @@ final class PersonContext implements PersonContextInterface $this->showScopes = $parameterBag->get('chill_main')['acl']['form_show_scopes']; $this->translator = $translator; $this->translatableStringHelper = $translatableStringHelper; + $this->thirdPartyRender = $thirdPartyRender; + $this->thirdPartyRepository = $thirdPartyRepository; + $this->residentialAddressRepository = $residentialAddressRepository; } public function adminFormReverseTransform(array $data): array @@ -110,11 +133,12 @@ final class PersonContext implements PersonContextInterface $r = [ 'mainPerson' => $data['mainPerson'] ?? false, 'mainPersonLabel' => $data['mainPersonLabel'] ?? $this->translator->trans('docgen.Main person'), + 'thirdParty' => $data['thirdParty'] ?? false, + 'thirdPartyLabel' => $data['thirdPartyLabel'] ?? $this->translator->trans('Third party'), ]; if (array_key_exists('category', $data)) { - $r['category'] = array_key_exists('category', $data) ? - $this->documentCategoryRepository->find($data['category']) : null; + $r['category'] = $this->documentCategoryRepository->find($data['category']); } return $r; @@ -131,6 +155,14 @@ final class PersonContext implements PersonContextInterface ->setParameter('docClass', PersonDocument::class), 'choice_label' => fn ($entity = null) => $entity ? $this->translatableStringHelper->localize($entity->getName()) : '', 'required' => true, + ]) + ->add('thirdParty', CheckboxType::class, [ + 'required' => false, + 'label' => 'docgen.Ask for thirdParty', + ]) + ->add('thirdPartyLabel', TextType::class, [ + 'label' => 'docgen.thirdParty label', + 'required' => true, ]); } @@ -139,12 +171,47 @@ final class PersonContext implements PersonContextInterface */ public function buildPublicForm(FormBuilderInterface $builder, DocGeneratorTemplate $template, $entity): void { + $options = $template->getOptions(); + $builder->add('title', TextType::class, [ 'required' => true, 'label' => 'docgen.Document title', 'data' => $this->translatableStringHelper->localize($template->getName()), ]); + $thirdParties = [...array_values( + array_filter( + array_map( + fn (ResidentialAddress $r): ?ThirdParty => $r->getHostThirdParty(), + $this + ->residentialAddressRepository + ->findCurrentResidentialAddressByPerson($entity) + ) + ) + ), ...array_values( + array_filter( + array_map( + fn (PersonResource $r): ?ThirdParty => $r->getThirdParty(), + $entity->getResources()->filter( + static fn (PersonResource $r): bool => null !== $r->getThirdParty() + )->toArray() + ) + ) + )]; + + if ($options['thirdParty'] ?? false) { + $builder->add('thirdParty', EntityType::class, [ + 'class' => ThirdParty::class, + 'choices' => $thirdParties, + 'choice_label' => fn (ThirdParty $p) => $this->thirdPartyRender->renderString($p, []), + 'multiple' => false, + 'required' => false, + 'expanded' => true, + 'label' => $options['thirdPartyLabel'], + 'placeholder' => $this->translator->trans('Any third party selected'), + ]); + } + if ($this->isScopeNecessary($entity)) { $builder->add('scope', ScopePickerType::class, [ 'center' => $this->centerResolverManager->resolveCenters($entity), @@ -156,10 +223,6 @@ final class PersonContext implements PersonContextInterface public function getData(DocGeneratorTemplate $template, $entity, array $contextGenerationData = []): array { - if (!$entity instanceof Person) { - throw new UnexpectedTypeException($entity, Person::class); - } - $data = []; $data = array_merge($data, $this->baseContextData->getData($contextGenerationData['creator'] ?? null)); $data['person'] = $this->normalizer->normalize($entity, 'docgen', [ @@ -170,6 +233,13 @@ final class PersonContext implements PersonContextInterface 'docgen:person:with-budget' => true, ]); + if ($template->getOptions()['thirdParty']) { + $data['thirdParty'] = $this->normalizer->normalize($contextGenerationData['thirdParty'], 'docgen', [ + 'docgen:expects' => ThirdParty::class, + 'groups' => 'docgen:read' + ]); + } + return $data; } @@ -223,6 +293,7 @@ final class PersonContext implements PersonContextInterface return [ 'title' => $data['title'] ?? '', 'scope_id' => $scope instanceof Scope ? $scope->getId() : null, + 'thirdParty' => ($data['thirdParty'] ?? null)?->getId(), ]; } @@ -242,6 +313,7 @@ final class PersonContext implements PersonContextInterface return [ 'title' => $data['title'] ?? '', 'scope' => $scope, + 'thirdParty' => null !== ($id = ($data['thirdParty'] ?? null)) ? $this->thirdPartyRepository->find($id) : null, ]; } diff --git a/src/Bundle/ChillPersonBundle/Service/DocGenerator/PersonContextInterface.php b/src/Bundle/ChillPersonBundle/Service/DocGenerator/PersonContextInterface.php index 6de8c1c50..53e241292 100644 --- a/src/Bundle/ChillPersonBundle/Service/DocGenerator/PersonContextInterface.php +++ b/src/Bundle/ChillPersonBundle/Service/DocGenerator/PersonContextInterface.php @@ -19,7 +19,8 @@ use Chill\PersonBundle\Entity\Person; use Symfony\Component\Form\FormBuilderInterface; /** - * @template-extends DocGeneratorContextWithPublicFormInterface + * @template-extends DocGeneratorContextWithPublicFormInterface + * @template-extends DocGeneratorContextWithAdminFormInterface */ interface PersonContextInterface extends DocGeneratorContextWithAdminFormInterface, DocGeneratorContextWithPublicFormInterface { diff --git a/src/Bundle/ChillPersonBundle/Tests/Service/DocGenerator/AccompanyingPeriodContextTest.php b/src/Bundle/ChillPersonBundle/Tests/Service/DocGenerator/AccompanyingPeriodContextTest.php new file mode 100644 index 000000000..f9f888999 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Service/DocGenerator/AccompanyingPeriodContextTest.php @@ -0,0 +1,291 @@ +baseContextData = self::$container->get(BaseContextData::class); + $this->documentCategoryRepository = self::$container->get(DocumentCategoryRepository::class); + $this->em = self::$container->get(EntityManagerInterface::class); + $this->normalizer = self::$container->get(NormalizerInterface::class); + $this->personRender = self::$container->get(PersonRenderInterface::class); + $this->personRepository = self::$container->get(PersonRepository::class); + $this->translatableStringHelper = self::$container->get(TranslatableStringHelperInterface::class); + $this->translator = self::$container->get(TranslatorInterface::class); + $this->thirdPartyRender = self::$container->get(ThirdPartyRender::class); + $this->thirdPartyRepository = self::$container->get(ThirdPartyRepository::class); + } + + private function buildContext(): AccompanyingPeriodContext + { + return new AccompanyingPeriodContext( + $this->documentCategoryRepository, + $this->normalizer, + $this->translatableStringHelper, + $this->em, + $this->personRender, + $this->personRepository, + $this->translator, + $this->baseContextData, + $this->thirdPartyRender, + $this->thirdPartyRepository, + ); + } + + /** + * This test run the methods executed when a document is generated: + * + * - normalized data from the form in a way that they are stored in message queue; + * - denormalize the data from the message queue, + * - and get the data, as they will be transmitted to the GeneratorDriver + * + * @param array $options the options, as they are stored in the DocGeneratorTemplate (the admin form data) + * @param AccompanyingPeriod $entity The entity from which the data will be extracted + * @param array $data The data, from the public form + * @param array $expectedNormalized, how the normalized data are expected (allow to check that this data will be compliant with the storage in messenger queue) + * @param callable $assertionsOnData some test that will be executed on the normalized data + * @dataProvider provideNormalizedData + */ + public function testContextGenerationDataNormalizeDenormalizeGetData( + array $options, + AccompanyingPeriod $entity, + array $data, + array $expectedNormalized, + callable $assertionsOnData + ): void { + $context = $this->buildContext(); + $template = new DocGeneratorTemplate(); + $template->setName(["fr" =>"test"])->setContext(AccompanyingPeriodContext::class) + ->setDescription("description")->setActive(true) + ->setOptions($options); + + $normalized = $context->contextGenerationDataNormalize($template, $entity, $data); + + self::assertEquals($expectedNormalized, $normalized); + + $denormalized = $context->contextGenerationDataDenormalize($template, $entity, $normalized); + + $data = $context->getData($template, $entity, $denormalized); + + call_user_func($assertionsOnData, $data); + } + + public function provideNormalizedData(): iterable + { + self::bootKernel(); + $em = self::$container->get(EntityManagerInterface::class); + + $thirdParty = $em->createQuery("SELECT t FROM " . ThirdParty::class . " t") + ->setMaxResults(1) + ->getSingleResult(); + + if (null === $thirdParty) { + throw new \RuntimeException("No thirdparty in database"); + } + + $period = $em->createQuery("SELECT a FROM " . AccompanyingPeriod::class . " a WHERE a.step = 'CONFIRMED'") + ->setMaxResults(1) + ->getSingleResult(); + + if (null === $period) { + throw new \RuntimeException("No confirmed period in database"); + } + + $person = $em->createQuery("SELECT p FROM " . Person::class . " p") + ->setMaxResults(1) + ->getSingleResult(); + + if (null === $person) { + throw new \RuntimeException("No confirmed period in database"); + } + + yield [ + // test with only thirdParty + [ + 'mainPerson' => false, + 'mainPersonLabel' => 'person', + 'person1' => false, + 'person1Label' => 'person2', + 'person2' => false, + 'person2Label' => 'person2', + 'thirdParty' => true, + 'thirdPartyLabel' => '3party' + ], + $period, + [ + 'thirdParty' => $thirdParty + ], + [ + 'thirdParty' => $thirdParty->getId(), + 'mainPerson' => null, + 'person1' => null, + 'person2' => null, + ], + function (array $data) use ($thirdParty, $period) { + self::assertArrayHasKey('thirdParty', $data); + self::assertEquals($thirdParty->getId(), $data['thirdParty']['id']); + + self::assertArrayHasKey('course', $data); + self::assertEquals($period->getId(), $data['course']['id']); + }, + ]; + + yield [ + // test with only mainPerson + [ + 'mainPerson' => true, + 'mainPersonLabel' => 'person', + 'person1' => false, + 'person1Label' => 'person2', + 'person2' => false, + 'person2Label' => 'person2', + 'thirdParty' => false, + 'thirdPartyLabel' => '3party' + ], + $period, + [ + 'mainPerson' => $person, + ], + [ + 'thirdParty' => null, + 'mainPerson' => $person->getId(), + 'person1' => null, + 'person2' => null, + ], + function (array $data) use ($person, $period) { + self::assertArrayHasKey('mainPerson', $data); + self::assertEquals($person->getId(), $data['mainPerson']['id']); + + self::assertArrayHasKey('course', $data); + self::assertEquals($period->getId(), $data['course']['id']); + }, + ]; + + yield [ + // test with every options activated + [ + 'mainPerson' => true, + 'mainPersonLabel' => 'person', + 'person1' => true, + 'person1Label' => 'person2', + 'person2' => true, + 'person2Label' => 'person2', + 'thirdParty' => true, + 'thirdPartyLabel' => '3party' + ], + $period, + [ + 'mainPerson' => $person, + 'person1' => $person, + 'person2' => $person, + 'thirdParty' => $thirdParty, + ], + [ + 'thirdParty' => $thirdParty->getId(), + 'mainPerson' => $person->getId(), + 'person1' => $person->getId(), + 'person2' => $person->getId(), + ], + function (array $data) use ($person, $thirdParty, $period) { + self::assertArrayHasKey('mainPerson', $data); + self::assertEquals($person->getId(), $data['mainPerson']['id']); + + self::assertArrayHasKey('person1', $data); + self::assertEquals($person->getId(), $data['person1']['id']); + + self::assertArrayHasKey('person2', $data); + self::assertEquals($person->getId(), $data['person2']['id']); + + self::assertArrayHasKey('thirdParty', $data); + self::assertEquals($thirdParty->getId(), $data['thirdParty']['id']); + + self::assertArrayHasKey('course', $data); + self::assertEquals($period->getId(), $data['course']['id']); + }, + ]; + + yield [ + // test with any option activated + [ + 'mainPerson' => false, + 'mainPersonLabel' => 'person', + 'person1' => false, + 'person1Label' => 'person2', + 'person2' => false, + 'person2Label' => 'person2', + 'thirdParty' => false, + 'thirdPartyLabel' => '3party' + ], + $period, + [ + 'mainPerson' => null, + 'person1' => null, + 'person2' => null, + 'thirdParty' => null, + ], + [ + 'thirdParty' => null, + 'mainPerson' => null, + 'person1' => null, + 'person2' => null, + ], + function (array $data) use ($period) { + self::assertArrayHasKey('course', $data); + self::assertEquals($period->getId(), $data['course']['id']); + }, + ]; + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Service/DocGenerator/PersonContextTest.php b/src/Bundle/ChillPersonBundle/Tests/Service/DocGenerator/PersonContextTest.php index d0138dc30..71fce8c92 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Service/DocGenerator/PersonContextTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Service/DocGenerator/PersonContextTest.php @@ -18,20 +18,30 @@ use Chill\DocStoreBundle\Entity\PersonDocument; use Chill\DocStoreBundle\Entity\StoredObject; use Chill\DocStoreBundle\Repository\DocumentCategoryRepository; use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter; +use Chill\MainBundle\Entity\Address; use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Entity\PostalCode; use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Form\Type\ScopePickerType; +use Chill\MainBundle\Repository\ScopeRepositoryInterface; use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; +use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Repository\ResidentialAddressRepository; +use Chill\PersonBundle\Service\DocGenerator\AccompanyingPeriodContext; use Chill\PersonBundle\Service\DocGenerator\PersonContext; +use Chill\ThirdPartyBundle\Entity\ThirdParty; +use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository; +use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender; use Doctrine\ORM\EntityManagerInterface; use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\Exception\Prediction\FailedPredictionException; use Prophecy\PhpUnit\ProphecyTrait; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\Extension\Core\Type\TextType; @@ -46,10 +56,142 @@ use function count; * @internal * @coversNothing */ -final class PersonContextTest extends TestCase +final class PersonContextTest extends KernelTestCase { use ProphecyTrait; + /** + * This test run the methods executed when a document is generated: + * + * - normalized data from the form in a way that they are stored in message queue; + * - denormalize the data from the message queue, + * - and get the data, as they will be transmitted to the GeneratorDriver + * + * @param array $options the options, as they are stored in the DocGeneratorTemplate (the admin form data) + * @param Person $entity The entity from which the data will be extracted + * @param array $data The data, from the public form + * @param array $expectedNormalized, how the normalized data are expected (allow to check that this data will be compliant with the storage in messenger queue) + * @param callable $assertionsOnData some test that will be executed on the normalized data + * @dataProvider provideNormalizedData + */ + public function testContextGenerationDataNormalizeDenormalizeGetData( + array $options, + Person $entity, + array $data, + array $expectedNormalized, + callable $assertionsOnData + ): void { + // we boot kernel only for this test + self::bootKernel(); + + // we create a PersonContext with the minimal dependency injection needed (relying on + // prophecy for other dependencies) + $context = $this->buildPersonContext( + null, + self::$container->get(BaseContextData::class), + self::$container->get(CenterResolverManagerInterface::class), + self::$container->get(DocumentCategoryRepository::class), + self::$container->get(EntityManagerInterface::class), + self::$container->get(NormalizerInterface::class), + (new ParameterBag(['chill_main' => ['acl' => ['form_show_scopes' => false]]])), + null, + self::$container->get(Security::class), + null, + null, + null, + self::$container->get(ThirdPartyRepository::class) + ); + $template = new DocGeneratorTemplate(); + $template->setName(["fr" =>"test"])->setContext(AccompanyingPeriodContext::class) + ->setDescription("description")->setActive(true) + ->setOptions($options); + + $normalized = $context->contextGenerationDataNormalize($template, $entity, $data); + + self::assertEquals($expectedNormalized, $normalized); + + $denormalized = $context->contextGenerationDataDenormalize($template, $entity, $normalized); + + $data = $context->getData($template, $entity, $denormalized); + + call_user_func($assertionsOnData, $data); + } + + public function provideNormalizedData(): iterable + { + self::bootKernel(); + $em = self::$container->get(EntityManagerInterface::class); + + $thirdParty = $em->createQuery("SELECT t FROM " . ThirdParty::class . " t") + ->setMaxResults(1) + ->getSingleResult(); + + if (null === $thirdParty) { + throw new \RuntimeException("No thirdparty in database"); + } + + $person = $em->createQuery("SELECT p FROM " . Person::class . " p") + ->setMaxResults(1) + ->getSingleResult(); + + if (null === $person) { + throw new \RuntimeException("No confirmed period in database"); + } + + $category = self::$container->get(DocumentCategoryRepository::class) + ->findAll()[0]; + + if (null === $category) { + throw new \RuntimeException("no document category in database"); + } + + yield [ + [ + 'thirdParty' => true, + 'thirdPartyLabel' => '3party', + 'category' => $category, + ], + $person, + [ + 'title' => 'test', + 'thirdParty' => $thirdParty, + ], + [ + 'thirdParty' => $thirdParty->getId(), + 'title' => 'test', + 'scope_id' => null, + ], + function ($data) use ($person, $thirdParty) { + self::assertArrayHasKey('person', $data); + self::assertEquals($person->getId(), $data['person']['id']); + + self::assertArrayHasKey('thirdParty', $data); + self::assertEquals($thirdParty->getId(), $data['thirdParty']['id']); + } + ]; + + yield [ + [ + 'thirdParty' => false, + 'thirdPartyLabel' => '3party', + 'category' => $category, + ], + $person, + [ + 'title' => 'test', + ], + [ + 'title' => 'test', + 'scope_id' => null, + 'thirdParty' => null, + ], + function ($data) use ($person, $thirdParty) { + self::assertArrayHasKey('person', $data); + self::assertEquals($person->getId(), $data['person']['id']); + } + ]; + } + /** * Test that the build person context works in the case when 'form_show_scope' is false. */ @@ -208,9 +350,13 @@ final class PersonContextTest extends TestCase ?EntityManagerInterface $em = null, ?NormalizerInterface $normalizer = null, ?ParameterBagInterface $parameterBag = null, + ?ScopeRepositoryInterface $scopeRepository = null, ?Security $security = null, ?TranslatorInterface $translator = null, - ?TranslatableStringHelperInterface $translatableStringHelper = null + ?TranslatableStringHelperInterface $translatableStringHelper = null, + ?ThirdPartyRender $thirdPartyRender = null, + ?ThirdPartyRepository $thirdPartyRepository = null, + ?ResidentialAddressRepository $residentialAddressRepository = null ): PersonContext { if (null === $authorizationHelper) { $authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class)->reveal(); @@ -250,6 +396,11 @@ final class PersonContextTest extends TestCase $parameterBag = new ParameterBag(['chill_main' => ['acl' => ['form_show_scopes' => true]]]); } + if (null === $scopeRepository) { + $scopeRepository = $this->prophesize(ScopeRepositoryInterface::class); + $scopeRepository = $scopeRepository->reveal(); + } + if (null === $security) { $security = $this->prophesize(Security::class); $security->getUser()->willReturn(new User()); @@ -267,6 +418,28 @@ final class PersonContextTest extends TestCase $translatableStringHelper = $translatableStringHelper->reveal(); } + if (null === $thirdPartyRender) { + $thirdPartyRender = $this->prophesize(ThirdPartyRender::class); + $thirdPartyRender = $thirdPartyRender->reveal(); + } + + if (null === $thirdPartyRepository) { + $thirdPartyRepository = $this->prophesize(ThirdPartyRepository::class); + $thirdPartyRepository = $thirdPartyRepository->reveal(); + } + + if (null === $residentialAddressRepository) { + $residentialAddressRepository = $this->prophesize(ResidentialAddressRepository::class); + $residentialAddressRepository->findCurrentResidentialAddressByPerson(Argument::type(Person::class), Argument::any()) + ->willReturn([ + (new Person\ResidentialAddress()) + ->setAddress((new Address()) + ->setStreet('test street') + ->setPostcode(new PostalCode())) + ]); + $residentialAddressRepository = $residentialAddressRepository->reveal(); + } + return new PersonContext( $authorizationHelper, $baseContextData, @@ -275,9 +448,13 @@ final class PersonContextTest extends TestCase $em, $normalizer, $parameterBag, + $scopeRepository, $security, $translator, - $translatableStringHelper + $translatableStringHelper, + $thirdPartyRender, + $thirdPartyRepository, + $residentialAddressRepository ); } } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 341136f65..5cc9ee1f1 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -927,10 +927,10 @@ docgen: Accompanying period work: "Action d'accompagnement" Accompanying period work context: "Evaluation des actions d'accompagnement" Main person: Usager principal - person 1: Premièr usager + person 1: Premier usager person 2: Second usager Ask for main person: Demander à l'utilisateur de préciser l'usager principal - Ask for person 1: Demander à l'utilisateur de préciser le premièr usager + Ask for person 1: Demander à l'utilisateur de préciser le premier usager Ask for person 2: Demander à l'utilisateur de préciser le second usager A basic context for accompanying period: Contexte pour les parcours A context for accompanying period work: Contexte pour les actions d'accompagnement diff --git a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php index 76e15ef17..f9893b9d9 100644 --- a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php +++ b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php @@ -21,7 +21,7 @@ use DomainException; use function array_key_exists; -final class ThirdPartyRepository implements ObjectRepository +class ThirdPartyRepository implements ObjectRepository { private EntityRepository $repository; diff --git a/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml b/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml index 94a10177b..f62a5beff 100644 --- a/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml @@ -75,6 +75,7 @@ No email given: Aucune adresse courriel renseignée The party is visible in those centers: Le tiers est visible dans ces centres The party is not visible in any center: Le tiers n'est associé à aucun centre No third parties: Aucun tiers +Any third party selected: Aucun tiers sélectionné Thirdparty handling: Tiers traitant Thirdparty workers: Tiers intervenants @@ -112,6 +113,8 @@ crud: docgen: A context for person with a third party (for sending mail): Un contexte d'une personne avec un tiers (pour envoyer un courrier à ce tiers, par exemple) Person with third party: Personne avec choix d'un tiers + Ask for thirdParty: Demander à l'utilisateur de préciser un tiers + thirdParty label: Libellé du tiers # exports export: