diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityType.php b/src/Bundle/ChillActivityBundle/Form/ActivityType.php index 8af7a204c..22bd45658 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityType.php @@ -35,6 +35,7 @@ use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\CallbackTransformer; use Chill\PersonBundle\Form\DataTransformer\PersonToIdTransformer; use Chill\PersonBundle\Templating\Entity\SocialIssueRender; +use Chill\PersonBundle\Templating\Entity\SocialActionRender; class ActivityType extends AbstractType { @@ -46,6 +47,10 @@ class ActivityType extends AbstractType protected TranslatableStringHelper $translatableStringHelper; + protected SocialIssueRender $socialIssueRender; + + protected SocialActionRender $socialActionRender; + protected array $timeChoices; public function __construct ( @@ -54,7 +59,8 @@ class ActivityType extends AbstractType ObjectManager $om, TranslatableStringHelper $translatableStringHelper, array $timeChoices, - SocialIssueRender $socialIssueRender + SocialIssueRender $socialIssueRender, + SocialActionRender $socialActionRender ) { if (!$tokenStorage->getToken()->getUser() instanceof User) { throw new \RuntimeException("you should have a valid user"); @@ -66,6 +72,7 @@ class ActivityType extends AbstractType $this->translatableStringHelper = $translatableStringHelper; $this->timeChoices = $timeChoices; $this->socialIssueRender = $socialIssueRender; + $this->socialActionRender = $socialActionRender; } public function buildForm(FormBuilderInterface $builder, array $options): void @@ -124,7 +131,7 @@ class ActivityType extends AbstractType 'required' => $activityType->isRequired('socialActions'), 'class' => SocialAction::class, 'choice_label' => function (SocialAction $socialAction) { - return $this->translatableStringHelper->localize($socialAction->getTitle()); + return $this->socialActionRender->renderString($socialAction, []); }, 'multiple' => true, 'choices' => $accompanyingPeriod->getRecursiveSocialActions(), diff --git a/src/Bundle/ChillActivityBundle/config/services/form.yaml b/src/Bundle/ChillActivityBundle/config/services/form.yaml index 3da20cce5..fd034b2da 100644 --- a/src/Bundle/ChillActivityBundle/config/services/form.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/form.yaml @@ -32,6 +32,7 @@ services: - "@chill.main.helper.translatable_string" - "%chill_activity.form.time_duration%" - '@Chill\PersonBundle\Templating\Entity\SocialIssueRender' + - '@Chill\PersonBundle\Templating\Entity\SocialActionRender' tags: - { name: form.type, alias: chill_activitybundle_activity } diff --git a/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php b/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php index 71476fb78..a1d28483d 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php +++ b/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php @@ -8,6 +8,11 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Validator\Validator\ValidatorInterface; use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\MainBundle\Pagination\PaginatorInterface; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\CRUD\Resolver\Resolver; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Serializer\SerializerInterface; +use Symfony\Component\Translation\TranslatorInterface; class AbstractCRUDController extends AbstractController { @@ -248,4 +253,24 @@ class AbstractCRUDController extends AbstractController { return $this->get('validator'); } + + /** + * @return array + */ + public static function getSubscribedServices(): array + { + return \array_merge( + parent::getSubscribedServices(), + [ + 'chill_main.paginator_factory' => PaginatorFactory::class, + + 'translator' => TranslatorInterface::class, + AuthorizationHelper::class => AuthorizationHelper::class, + EventDispatcherInterface::class => EventDispatcherInterface::class, + Resolver::class => Resolver::class, + SerializerInterface::class => SerializerInterface::class, + 'validator' => ValidatorInterface::class, + ] + ); + } } diff --git a/src/Bundle/ChillMainBundle/Resources/public/js/date.js b/src/Bundle/ChillMainBundle/Resources/public/js/date.js index e49a05972..ec66da770 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/js/date.js +++ b/src/Bundle/ChillMainBundle/Resources/public/js/date.js @@ -48,8 +48,8 @@ const ISOToDatetime = (str) => { let [cal, times] = str.split('T'), [year, month, date] = cal.split('-'), - [time, timezone] = cal.split(times.charAt(9)), - [hours, minutes, seconds] = cal.split(':') + [time, timezone] = times.split(times.charAt(8)), + [hours, minutes, seconds] = time.split(':') ; return new Date(year, month-1, date, hours, minutes, seconds); diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkApiController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkApiController.php new file mode 100644 index 000000000..6263736b0 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkApiController.php @@ -0,0 +1,23 @@ +getMethod()) { + case Request::METHOD_PUT: + return [ 'groups' => [ 'accompanying_period_work:edit' ] ]; + } + } + + return parent::getContextForSerialization($action, $request, $_format, $entity); + } + +} diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php index 1a5ab3925..077fa15d7 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php @@ -2,32 +2,44 @@ namespace Chill\PersonBundle\Controller; +use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Serializer\SerializerInterface; use Symfony\Component\Translation\TranslatorInterface; +use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository; class AccompanyingCourseWorkController extends AbstractController { private TranslatorInterface $trans; private SerializerInterface $serializer; + private AccompanyingPeriodWorkRepository $workRepository; + private PaginatorFactory $paginator; - public function __construct(TranslatorInterface $trans, SerializerInterface $serializer) - { + public function __construct( + TranslatorInterface $trans, + SerializerInterface $serializer, + AccompanyingPeriodWorkRepository $workRepository, + PaginatorFactory $paginator + ) { $this->trans = $trans; $this->serializer = $serializer; + $this->workRepository = $workRepository; + $this->paginator = $paginator; } /** * @Route( * "{_locale}/person/accompanying-period/{id}/work/new", - * methods={"GET", "POST"} + * name="chill_person_accompanying_period_work_new", + * methods={"GET"} * ) */ - public function createWork(AccompanyingPeriod $period) + public function createWork(AccompanyingPeriod $period): Response { // TODO ACL @@ -49,4 +61,49 @@ class AccompanyingCourseWorkController extends AbstractController 'json' => $json ]); } + + /** + * @Route( + * "{_locale}/person/accompanying-period/work/{id}/edit", + * name="chill_person_accompanying_period_work_edit", + * methods={"GET"} + * ) + */ + public function editWork(AccompanyingPeriodWork $work): Response + { + // TODO ACL + $json = $this->serializer->normalize($work, 'json', [ "groups" => [ "read" ] ]); + return $this->render('@ChillPerson/AccompanyingCourseWork/edit.html.twig', [ + 'accompanyingCourse' => $work->getAccompanyingPeriod(), + 'work' => $work, + 'json' => $json + ]); + } + + /** + * @Route( + * "{_locale}/person/accompanying-period/{id}/work", + * name="chill_person_accompanying_period_work_list", + * methods={"GET"} + * ) + */ + public function listWorkByAccompanyingPeriod(AccompanyingPeriod $period): Response + { + // TODO ACL + $totalItems = $this->workRepository->countByAccompanyingPeriod($period); + $paginator = $this->paginator->create($totalItems); + + $works = $this->workRepository->findByAccompanyingPeriod( + $period, + ['startDate' => 'DESC', 'endDate' => 'DESC'], + $paginator->getItemsPerPage(), + $paginator->getCurrentPageFirstItemNumber() + ); + + return $this->render('@ChillPerson/AccompanyingCourseWork/list_by_accompanying_period.html.twig', [ + 'accompanyingCourse' => $period, + 'works' => $works, + 'paginator' => $paginator + ]); + } } diff --git a/src/Bundle/ChillPersonBundle/Controller/SocialIssueApiController.php b/src/Bundle/ChillPersonBundle/Controller/SocialIssueApiController.php new file mode 100644 index 000000000..40d7068ce --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Controller/SocialIssueApiController.php @@ -0,0 +1,21 @@ +where( + $query->expr()->orX( + $query->expr()->gt('e.desactivationDate', ':now'), + $query->expr()->isNull('e.desactivationDate') + ) + ); + $query->setParameter('now', new \DateTimeImmutable()); + } +} diff --git a/src/Bundle/ChillPersonBundle/Controller/SocialWorkGoalApiController.php b/src/Bundle/ChillPersonBundle/Controller/SocialWorkGoalApiController.php new file mode 100644 index 000000000..2e678a0d0 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Controller/SocialWorkGoalApiController.php @@ -0,0 +1,40 @@ +goalRepository = $goalRepository; + $this->paginator = $paginator; + } + + public function listBySocialAction(Request $request, SocialAction $action): Response + { + $totalItems = $this->goalRepository->countBySocialActionWithDescendants($action); + $paginator = $this->getPaginatorFactory()->create($totalItems); + + $entities = $this->goalRepository->findBySocialActionWithDescendants($action, ["id" => "ASC"], + $paginator->getItemsPerPage(), $paginator->getCurrentPageFirstItemNumber()); + + $model = new Collection($entities, $paginator); + + return $this->json($model, Response::HTTP_OK, [], [ "groups" => [ "read" ]]); + } + +} diff --git a/src/Bundle/ChillPersonBundle/Controller/SocialWorkResultApiController.php b/src/Bundle/ChillPersonBundle/Controller/SocialWorkResultApiController.php new file mode 100644 index 000000000..24902a163 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Controller/SocialWorkResultApiController.php @@ -0,0 +1,47 @@ +resultRepository = $resultRepository; + } + + public function listBySocialAction(Request $request, SocialAction $action): Response + { + $totalItems = $this->resultRepository->countBySocialActionWithDescendants($action); + $paginator = $this->getPaginatorFactory()->create($totalItems); + + $entities = $this->resultRepository->findBySocialActionWithDescendants($action, ["id" => "ASC"], + $paginator->getItemsPerPage(), $paginator->getCurrentPageFirstItemNumber()); + + $model = new Collection($entities, $paginator); + + return $this->json($model, Response::HTTP_OK, [], [ "groups" => [ "read" ]]); + } + + public function listByGoal(Request $request, Goal $goal): Response + { + $totalItems = $this->resultRepository->countByGoal($goal); + $paginator = $this->getPaginatorFactory()->create($totalItems); + + $entities = $this->resultRepository->findByGoal($goal, ["id" => "ASC"], + $paginator->getItemsPerPage(), $paginator->getCurrentPageFirstItemNumber()); + + $model = new Collection($entities, $paginator); + + return $this->json($model, Response::HTTP_OK, [], [ "groups" => [ "read" ]]); + } +} diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php index 79dae3255..733579acb 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php @@ -488,6 +488,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac [ 'class' => \Chill\PersonBundle\Entity\SocialWork\SocialIssue::class, 'name' => 'social_work_social_issue', + 'controller' => \Chill\PersonBundle\Controller\SocialIssueApiController::class, 'base_path' => '/api/1.0/person/social-work/social-issue', 'base_role' => 'ROLE_USER', 'actions' => [ @@ -553,7 +554,6 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'methods' => [ Request::METHOD_GET => true, Request::METHOD_HEAD => true, - Request::METHOD_POST=> true, ] ], 'address' => [ @@ -567,25 +567,6 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac ], ] ], - [ - 'class' => \Chill\PersonBundle\Entity\Household\Household::class, - 'name' => 'household', - 'base_path' => '/api/1.0/person/household', - // TODO: acl - 'base_role' => 'ROLE_USER', - 'actions' => [ - '_entity' => [ - 'methods' => [ - Request::METHOD_GET => true, - Request::METHOD_HEAD => true, - ], - 'roles' => [ - Request::METHOD_GET => 'ROLE_USER', - Request::METHOD_HEAD => 'ROLE_USER', - ] - ], - ] - ], [ 'class' => \Chill\PersonBundle\Entity\SocialWork\SocialAction::class, 'name' => 'social_action', @@ -629,6 +610,127 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac ] ] ], + [ + 'class' => \Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork::class, + 'name' => 'accompanying_period_work', + 'base_path' => '/api/1.0/person/accompanying-course/work', + 'controller' => \Chill\PersonBundle\Controller\AccompanyingCourseWorkApiController::class, + // TODO: acl + 'base_role' => 'ROLE_USER', + 'actions' => [ + '_entity' => [ + 'methods' => [ + Request::METHOD_GET => true, + Request::METHOD_HEAD => true, + Request::METHOD_PATCH => true, + Request::METHOD_PUT => true, + ], + 'roles' => [ + Request::METHOD_GET => 'ROLE_USER', + Request::METHOD_HEAD => 'ROLE_USER', + Request::METHOD_PATCH => 'ROLE_USER', + Request::METHOD_PUT => 'ROLE_USER', + ] + ], + ] + ], + [ + 'class' => \Chill\PersonBundle\Entity\SocialWork\Result::class, + 'controller' => \Chill\PersonBundle\Controller\SocialWorkResultApiController::class, + 'name' => 'social_work_result', + 'base_path' => '/api/1.0/person/social-work/result', + 'base_role' => 'ROLE_USER', + 'actions' => [ + '_entity' => [ + 'methods' => [ + Request::METHOD_GET => true, + Request::METHOD_HEAD => true, + ], + 'roles' => [ + Request::METHOD_GET => 'ROLE_USER', + Request::METHOD_HEAD => 'ROLE_USER', + ] + ], + '_index' => [ + 'methods' => [ + Request::METHOD_GET => true, + Request::METHOD_HEAD => true, + ], + 'roles' => [ + Request::METHOD_GET => 'ROLE_USER', + Request::METHOD_HEAD => 'ROLE_USER', + ] + ], + 'by-social-action' => [ + 'single-collection' => 'collection', + 'path' => '/by-social-action/{id}.{_format}', + 'controller_action' => 'listBySocialAction', + 'methods' => [ + Request::METHOD_GET => true, + Request::METHOD_HEAD => true, + ], + 'roles' => [ + Request::METHOD_GET => 'ROLE_USER', + Request::METHOD_HEAD => 'ROLE_USER', + ] + ], + 'by-goal' => [ + 'single-collection' => 'collection', + 'path' => '/by-goal/{id}.{_format}', + 'controller_action' => 'listByGoal', + 'methods' => [ + Request::METHOD_GET => true, + Request::METHOD_HEAD => true, + ], + 'roles' => [ + Request::METHOD_GET => 'ROLE_USER', + Request::METHOD_HEAD => 'ROLE_USER', + ] + ], + ] + ], + [ + 'class' => \Chill\PersonBundle\Entity\SocialWork\Goal::class, + 'controller' => \Chill\PersonBundle\Controller\SocialWorkGoalApiController::class, + 'name' => 'social_work_goal', + 'base_path' => '/api/1.0/person/social-work/goal', + 'base_role' => 'ROLE_USER', + 'actions' => [ + '_entity' => [ + 'methods' => [ + Request::METHOD_GET => true, + Request::METHOD_HEAD => true, + ], + 'roles' => [ + Request::METHOD_GET => 'ROLE_USER', + Request::METHOD_HEAD => 'ROLE_USER', + ] + ], + '_index' => [ + 'methods' => [ + Request::METHOD_GET => true, + Request::METHOD_HEAD => true, + ], + 'roles' => [ + Request::METHOD_GET => 'ROLE_USER', + Request::METHOD_HEAD => 'ROLE_USER', + ] + ], + 'by-social-action' => [ + 'single-collection' => 'collection', + 'path' => '/by-social-action/{id}.{_format}', + 'controller_action' => 'listBySocialAction', + 'methods' => [ + Request::METHOD_GET => true, + Request::METHOD_HEAD => true, + ], + 'roles' => [ + Request::METHOD_GET => 'ROLE_USER', + Request::METHOD_HEAD => 'ROLE_USER', + ] + ], + ] + ], ] ]); } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php index 11570945e..e80f37364 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php @@ -4,6 +4,7 @@ namespace Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\SocialWork\Result; use Chill\PersonBundle\Entity\SocialWork\SocialAction; +use Chill\PersonBundle\Entity\Person; use Chill\MainBundle\Entity\User; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\ThirdPartyBundle\Entity\ThirdParty; @@ -38,7 +39,7 @@ use Symfony\Component\Validator\Constraints as Assert; /** * @ORM\Column(type="text") - * @Serializer\Groups({"read"}) + * @Serializer\Groups({"read", "accompanying_period_work:edit"}) */ private string $note = ""; @@ -50,7 +51,8 @@ use Symfony\Component\Validator\Constraints as Assert; /** * @ORM\ManyToOne(targetEntity=SocialAction::class) - * @Serializer\Groups({"accompanying_period_work:create", "read"}) + * @Serializer\Groups({"read"}) + * @Serializer\Groups({"accompanying_period_work:create"}) */ private ?SocialAction $socialAction = null; @@ -83,13 +85,16 @@ use Symfony\Component\Validator\Constraints as Assert; /** * @ORM\Column(type="date_immutable") * @Serializer\Groups({"accompanying_period_work:create"}) + * @Serializer\Groups({"accompanying_period_work:edit"}) * @Serializer\Groups({"read"}) */ private \DateTimeImmutable $startDate; /** * @ORM\Column(type="date_immutable", nullable=true, options={"default":null}) - * @Serializer\Groups({"accompanying_period_work:create", "read"}) + * @Serializer\Groups({"accompanying_period_work:create"}) + * @Serializer\Groups({"accompanying_period_work:edit"}) + * @Serializer\Groups({"read"}) * @Assert\GreaterThan(propertyPath="startDate", * message="accompanying_course_work.The endDate should be greater than the start date" * ) @@ -99,6 +104,7 @@ use Symfony\Component\Validator\Constraints as Assert; /** * @ORM\ManyToOne(targetEntity=ThirdParty::class) * @Serializer\Groups({"read"}) + * @Serializer\Groups({"accompanying_period_work:edit"}) * * In schema : traitant */ @@ -115,13 +121,22 @@ use Symfony\Component\Validator\Constraints as Assert; private string $createdAutomaticallyReason = ""; /** - * @ORM\OneToMany(targetEntity=AccompanyingPeriodWorkGoal::class, mappedBy="accompanyingPeriodWork") + * @ORM\OneToMany( + * targetEntity=AccompanyingPeriodWorkGoal::class, + * mappedBy="accompanyingPeriodWork", + * cascade={"persist"}, + * orphanRemoval=true + * ) + * @Serializer\Groups({"read"}) + * @Serializer\Groups({"accompanying_period_work:edit"}) */ private Collection $goals; /** * @ORM\ManyToMany(targetEntity=Result::class, inversedBy="accompanyingPeriodWorks") * @ORM\JoinTable(name="chill_person_accompanying_period_work_result") + * @Serializer\Groups({"read"}) + * @Serializer\Groups({"accompanying_period_work:edit"}) */ private Collection $results; @@ -130,14 +145,27 @@ use Symfony\Component\Validator\Constraints as Assert; * @ORM\JoinTable(name="chill_person_accompanying_period_work_third_party") * * In schema : intervenants + * @Serializer\Groups({"read"}) + * @Serializer\Groups({"accompanying_period_work:edit"}) */ private Collection $thirdParties; + /** + * + * @ORM\ManyToMany(targetEntity=Person::class) + * @ORM\JoinTable(name="chill_person_accompanying_period_work_person") + * @Serializer\Groups({"read"}) + * @Serializer\Groups({"accompanying_period_work:edit"}) + * @Serializer\Groups({"accompanying_period_work:create"}) + */ + private Collection $persons; + public function __construct() { $this->goals = new ArrayCollection(); $this->results = new ArrayCollection(); $this->thirdParties = new ArrayCollection(); + $this->persons = new ArrayCollection(); } public function getId(): ?int @@ -255,7 +283,7 @@ use Symfony\Component\Validator\Constraints as Assert; return $this->endDate; } - public function setEndDate(\DateTimeInterface $endDate): self + public function setEndDate(?\DateTimeInterface $endDate = null): self { $this->endDate = $endDate; @@ -310,7 +338,7 @@ use Symfony\Component\Validator\Constraints as Assert; { if (!$this->goals->contains($goal)) { $this->goals[] = $goal; - $goal->setAccompanyingPeriodWork2($this); + $goal->setAccompanyingPeriodWork($this); } return $this; @@ -318,10 +346,10 @@ use Symfony\Component\Validator\Constraints as Assert; public function removeGoal(AccompanyingPeriodWorkGoal $goal): self { - if ($this->goals->removeElement($goal)) { + if ($this->goals->removeElement($goal)) { // set the owning side to null (unless already changed) - if ($goal->getAccompanyingPeriodWork2() === $this) { - $goal->setAccompanyingPeriodWork2(null); + if ($goal->getAccompanyingPeriodWork() === $this) { + $goal->setAccompanyingPeriodWork(null); } } @@ -375,4 +403,25 @@ use Symfony\Component\Validator\Constraints as Assert; return $this; } + + public function getPersons(): Collection + { + return $this->persons; + } + + public function addPerson(Person $person): self + { + if (!$this->persons->contains($person)) { + $this->persons[] = $person; + } + + return $this; + } + + public function removePerson(Person $person): self + { + $this->persons->removeElement($person); + + return $this; + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkGoal.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkGoal.php index 955f9e3a1..d8cfb4875 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkGoal.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkGoal.php @@ -7,10 +7,17 @@ use Chill\PersonBundle\Entity\SocialWork\Result; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Serializer\Annotation as Serializer; /** * @ORM\Entity * @ORM\Table(name="chill_person_accompanying_period_work_goal") + * @Serializer\DiscriminatorMap( + * typeProperty="type", + * mapping={ + * "accompanying_period_work_goal":AccompanyingPeriodWorkGoal::class + * } + * ) */ class AccompanyingPeriodWorkGoal { @@ -18,11 +25,14 @@ class AccompanyingPeriodWorkGoal * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") + * @Serializer\Groups({"read"}) */ private $id; /** * @ORM\Column(type="text") + * @Serializer\Groups({"accompanying_period_work:edit"}) + * @Serializer\Groups({"read"}) */ private $note; @@ -33,12 +43,16 @@ class AccompanyingPeriodWorkGoal /** * @ORM\ManyToOne(targetEntity=Goal::class) + * @Serializer\Groups({"accompanying_period_work:edit"}) + * @Serializer\Groups({"read"}) */ private $goal; /** * @ORM\ManyToMany(targetEntity=Result::class, inversedBy="accompanyingPeriodWorkGoals") * @ORM\JoinTable(name="chill_person_accompanying_period_work_goal_result") + * @Serializer\Groups({"accompanying_period_work:edit"}) + * @Serializer\Groups({"read"}) */ private $results; @@ -71,6 +85,13 @@ class AccompanyingPeriodWorkGoal public function setAccompanyingPeriodWork(?AccompanyingPeriodWork $accompanyingPeriodWork): self { + if ($this->accompanyingPeriodWork instanceof AccompanyingPeriodWork + && $accompanyingPeriodWork !== $this->accompanyingPeriodWork + && $accompanyingPeriodWork !== null + ) { + throw new \LogicException("Change accompanying period work is not allowed"); + } + $this->accompanyingPeriodWork = $accompanyingPeriodWork; return $this; diff --git a/src/Bundle/ChillPersonBundle/Entity/SocialWork/Goal.php b/src/Bundle/ChillPersonBundle/Entity/SocialWork/Goal.php index 996fcf3eb..7ad301875 100644 --- a/src/Bundle/ChillPersonBundle/Entity/SocialWork/Goal.php +++ b/src/Bundle/ChillPersonBundle/Entity/SocialWork/Goal.php @@ -5,10 +5,17 @@ namespace Chill\PersonBundle\Entity\SocialWork; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Serializer\Annotation as Serializer; /** * @ORM\Entity * @ORM\Table(name="chill_person_social_work_goal") + * @Serializer\DiscriminatorMap( + * typeProperty="type", + * mapping={ + * "social_work_goal":Goal::class + * } + * ) */ class Goal { @@ -16,11 +23,13 @@ class Goal * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") + * @Serializer\Groups({"read"}) */ private $id; /** * @ORM\Column(type="json") + * @Serializer\Groups({"read"}) */ private $title = []; @@ -46,6 +55,11 @@ class Goal $this->results = new ArrayCollection(); } + public function getId(): ?int + { + return $this->id; + } + public function getTitle(): array { return $this->title; diff --git a/src/Bundle/ChillPersonBundle/Entity/SocialWork/Result.php b/src/Bundle/ChillPersonBundle/Entity/SocialWork/Result.php index 37e5c2b18..42a4c0929 100644 --- a/src/Bundle/ChillPersonBundle/Entity/SocialWork/Result.php +++ b/src/Bundle/ChillPersonBundle/Entity/SocialWork/Result.php @@ -7,10 +7,17 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkGoal; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Serializer\Annotation as Serializer; /** * @ORM\Entity * @ORM\Table(name="chill_person_social_work_result") + * @Serializer\DiscriminatorMap( + * typeProperty="type", + * mapping={ + * "social_work_result":Result::class + * } + * ) */ class Result { @@ -18,11 +25,13 @@ class Result * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") + * @Serializer\Groups({"read"}) */ private $id; /** * @ORM\Column(type="json") + * @Serializer\Groups({"read"}) */ private $title = []; diff --git a/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php b/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php index 49543c42d..b946f3f89 100644 --- a/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php +++ b/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php @@ -60,6 +60,13 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface 'accompanying_period_id' => $period->getId() ]]) ->setExtras(['order' => 30]); + + $menu->addChild($this->translator->trans('Accompanying Course Actions'), [ + 'route' => 'chill_person_accompanying_period_work_list', + 'routeParameters' => [ + 'id' => $period->getId() + ]]) + ->setExtras(['order' => 40]); } diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php index 5d455b617..872feebbe 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php @@ -3,16 +3,12 @@ namespace Chill\PersonBundle\Repository\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; +use Chill\PersonBundle\Entity\AccompanyingPeriod; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; +use Doctrine\Persistence\ObjectRepository; -/** - * @method AccompanyingPeriodWork|null find($id, $lockMode = null, $lockVersion = null) - * @method AccompanyingPeriodWork|null findOneBy(array $criteria, array $orderBy = null) - * @method AccompanyingPeriodWork[] findAll() - * @method AccompanyingPeriodWork[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) - */ -final class AccompanyingPeriodWorkRepository +final class AccompanyingPeriodWorkRepository implements ObjectRepository { private EntityRepository $repository; @@ -20,4 +16,88 @@ final class AccompanyingPeriodWorkRepository { $this->repository = $entityManager->getRepository(AccompanyingPeriodWork::class); } + + public function find($id): ?AccompanyingPeriodWork + { + return $this->repository->find($id); + } + + public function findAll(): array + { + return $this->repository->findAll(); + } + + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function findOneBy(array $criteria): ?AccompanyingPeriodWork + { + return $this->findOneBy($criteria); + } + + public function getClassName() + { + return AccompanyingPeriodWork::class; + } + + /** + * + * @return AccompanyingPeriodWork[] + */ + public function findByAccompanyingPeriod(AccompanyingPeriod $period, $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findByAccompanyingPeriod($period, $orderBy, $limit, $offset); + } + + public function countByAccompanyingPeriod(AccompanyingPeriod $period): int + { + return $this->repository->countByAccompanyingPeriod($period); + } + + public function toDelete() + { + $qb = $this->buildQueryBySocialActionWithDescendants($action); + $qb->select('g'); + + foreach ($orderBy as $sort => $order) { + $qb->addOrderBy('g.'.$sort, $order); + } + + return $qb + ->setMaxResults($limit) + ->setFirstResult($offset) + ->getQuery() + ->getResult() + ; + } + + public function countBySocialActionWithDescendants(SocialAction $action): int + { + $qb = $this->buildQueryBySocialActionWithDescendants($action); + $qb->select('COUNT(g)'); + + return $qb + ->getQuery() + ->getSingleScalarResult() + ; + } + + protected function buildQueryBySocialActionWithDescendants(SocialAction $action): QueryBuilder + { + $actions = $action->getDescendantsWithThis(); + + $qb = $this->repository->createQueryBuilder('g'); + + $orx = $qb->expr()->orX(); + $i = 0; + foreach ($actions as $action) { + $orx->add(":action_{$i} MEMBER OF g.socialActions"); + $qb->setParameter("action_{$i}", $action); + } + $qb->where($orx); + + return $qb; + } } diff --git a/src/Bundle/ChillPersonBundle/Repository/SocialWork/GoalRepository.php b/src/Bundle/ChillPersonBundle/Repository/SocialWork/GoalRepository.php index bd7c6a738..e6aac493f 100644 --- a/src/Bundle/ChillPersonBundle/Repository/SocialWork/GoalRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/SocialWork/GoalRepository.php @@ -3,10 +3,13 @@ namespace Chill\PersonBundle\Repository\SocialWork; use Chill\PersonBundle\Entity\SocialWork\Goal; +use Chill\PersonBundle\Entity\SocialWork\SocialAction; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\QueryBuilder; +use Doctrine\Persistence\ObjectRepository; -final class GoalRepository +final class GoalRepository implements ObjectRepository { private EntityRepository $repository; @@ -14,4 +17,78 @@ final class GoalRepository { $this->repository = $entityManager->getRepository(Goal::class); } + + public function find($id) + { + return $this->repository->find($id); + } + + public function findAll() + { + return $this->repository->findAll(); + } + + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null) + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function findOneBy(array $criteria) + { + return $this->findOneBy($criteria); + } + + public function getClassName() + { + return Goal::class; + } + + /** + * + * @return Goal[] + */ + public function findBySocialActionWithDescendants(SocialAction $action, $orderBy = null, $limit = null, $offset = null): array + { + $qb = $this->buildQueryBySocialActionWithDescendants($action); + $qb->select('g'); + + foreach ($orderBy as $sort => $order) { + $qb->addOrderBy('g.'.$sort, $order); + } + + return $qb + ->setMaxResults($limit) + ->setFirstResult($offset) + ->getQuery() + ->getResult() + ; + } + + public function countBySocialActionWithDescendants(SocialAction $action): int + { + $qb = $this->buildQueryBySocialActionWithDescendants($action); + $qb->select('COUNT(g)'); + + return $qb + ->getQuery() + ->getSingleScalarResult() + ; + } + + protected function buildQueryBySocialActionWithDescendants(SocialAction $action): QueryBuilder + { + $actions = $action->getDescendantsWithThis(); + + $qb = $this->repository->createQueryBuilder('g'); + + $orx = $qb->expr()->orX(); + $i = 0; + foreach ($actions as $action) { + $orx->add(":action_{$i} MEMBER OF g.socialActions"); + $qb->setParameter("action_{$i}", $action); + } + $qb->where($orx); + + return $qb; + } } diff --git a/src/Bundle/ChillPersonBundle/Repository/SocialWork/ResultRepository.php b/src/Bundle/ChillPersonBundle/Repository/SocialWork/ResultRepository.php index 1c4d8d013..6dc6a887c 100644 --- a/src/Bundle/ChillPersonBundle/Repository/SocialWork/ResultRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/SocialWork/ResultRepository.php @@ -3,10 +3,14 @@ namespace Chill\PersonBundle\Repository\SocialWork; use Chill\PersonBundle\Entity\SocialWork\Result; +use Chill\PersonBundle\Entity\SocialWork\SocialAction; +use Chill\PersonBundle\Entity\SocialWork\Goal; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\QueryBuilder; +use Doctrine\Persistence\ObjectRepository; -final class ResultRepository +final class ResultRepository implements ObjectRepository { private EntityRepository $repository; @@ -14,4 +18,120 @@ final class ResultRepository { $this->repository = $entityManager->getRepository(Result::class); } + + public function find($id) + { + return $this->repository->find($id); + } + + public function findAll() + { + return $this->repository->findAll(); + } + + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null) + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function findOneBy(array $criteria) + { + return $this->findOneBy($criteria); + } + + public function getClassName() + { + return Result::class; + } + + /** + * + * @return Result[] + */ + public function findBySocialActionWithDescendants(SocialAction $action, $orderBy = null, $limit = null, $offset = null): array + { + $qb = $this->buildQueryBySocialActionWithDescendants($action); + $qb->select('r'); + + foreach ($orderBy as $sort => $order) { + $qb->addOrderBy('r.'.$sort, $order); + } + + return $qb + ->setMaxResults($limit) + ->setFirstResult($offset) + ->getQuery() + ->getResult() + ; + } + + public function countBySocialActionWithDescendants(SocialAction $action): int + { + $qb = $this->buildQueryBySocialActionWithDescendants($action); + $qb->select('COUNT(r)'); + + return $qb + ->getQuery() + ->getSingleScalarResult() + ; + } + + protected function buildQueryBySocialActionWithDescendants(SocialAction $action): QueryBuilder + { + $actions = $action->getDescendantsWithThis(); + + $qb = $this->repository->createQueryBuilder('r'); + + $orx = $qb->expr()->orX(); + $i = 0; + foreach ($actions as $action) { + $orx->add(":action_{$i} MEMBER OF r.socialActions"); + $qb->setParameter("action_{$i}", $action); + } + $qb->where($orx); + + return $qb; + } + protected function buildQueryByGoal(Goal $goal): QueryBuilder + { + $qb = $this->repository->createQueryBuilder('r'); + + $qb->where(":goal MEMBER OF r.goals") + ->setParameter('goal', $goal) + ; + + return $qb; + } + + /** + * @return Result[] + */ + public function findByGoal(Goal $goal, $orderBy = null, $limit = null, $offset = null): array + { + $qb = $this->buildQueryByGoal($goal); + + foreach ($orderBy as $sort => $order) { + $qb->addOrderBy('r.'.$sort, $order); + } + + return $qb + ->select('r') + ->setMaxResults($limit) + ->setFirstResult($offset) + ->getQuery() + ->getResult() + ; + } + + public function countByGoal(Goal $goal): int + { + $qb = $this->buildQueryByGoal($goal); + $qb->select('COUNT(r)'); + + return $qb + ->getQuery() + ->getSingleScalarResult() + ; + } } + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/modules/accompanying_course_work_list/index.js b/src/Bundle/ChillPersonBundle/Resources/public/modules/accompanying_course_work_list/index.js new file mode 100644 index 000000000..cbc8531c0 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/modules/accompanying_course_work_list/index.js @@ -0,0 +1 @@ +require('./index.scss'); diff --git a/src/Bundle/ChillPersonBundle/Resources/public/modules/accompanying_course_work_list/index.scss b/src/Bundle/ChillPersonBundle/Resources/public/modules/accompanying_course_work_list/index.scss new file mode 100644 index 000000000..433f291b5 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/modules/accompanying_course_work_list/index.scss @@ -0,0 +1,96 @@ + +#accompanying_course_work_list { + + .item { + margin-bottom: 1.5rem; + padding: 1rem; + border: 1px solid gray; + + .title_label { + display: block; + margin: 0; + + font-variant-caps: small-caps; + + + * { + margin-top: 0; + } + } + + .objective_results { + display: grid; + grid-template-areas: + "obj res" + ; + grid-template-columns: 50%; + column-gap: 1rem; + + padding: 0.3rem; + + .obj { + grid-area: obj; + } + + .res { + grid-area: res; + + ul.result_list { + list-style-type: none; + padding: 0; + } + } + } + + .objective_results:nth-child(2n+2) { + background-color: var(--chill-llight-gray); + } + } + + .updatedBy { + margin-top: 1rem; + text-align: right; + font-size: 0.8rem; + font-style: italic; + } +} + +ul.timeline { + display: flex; + align-items: center; + justify-content: center; + padding: 0; + list-style-type: none; + + > li { + min-width: 210px; + + div.date { + margin-bottom: 20px; + display: flex; + flex-direction: column; + align-items: center; + } + div.label { + display: flex; + flex-direction: column; + align-items: center; + + padding: 0 40px; + border-top: 2px solid var(--chill-green); + + &:before { + content: ''; + display: inline-block; + position: relative; + width: 25px; + height: 25px; + + background-color: white; + border-radius: 25px; + border: 1px solid #ddd; + + top: -15px; + } + } + } +} diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/index.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/index.js index 2a7f19d61..bd47d4a73 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/index.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/index.js @@ -24,7 +24,6 @@ if (root === 'app') { .use(i18n) .component('app', App) .mount('#accompanying-course'); - }); } @@ -43,8 +42,7 @@ if (root === 'banner') { .use(store) .use(i18n) .component('banner', Banner) - .mount('#accompanying-course'); - + .mount('#banner-accompanying-course'); }); } diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkCreate/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkCreate/App.vue index 3c1f4b07a..96edce825 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkCreate/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkCreate/App.vue @@ -13,8 +13,7 @@
spinner
{{ work.socialAction.text }}
+Motifs, objectifs et dispositifs disponibles pour ajout :
+ ++ Aucun tiers traitant +
+ +{{ handlingThirdParty.text }}
+Aucun tiers intervenant
+ +{{ t.text }}
+Veuillez corriger les erreurs suivantes:
++ Aucun résultat associé +
+{{ 'accompanying_course_work.action'|trans }}
+{{ 'accompanying_course_work.goal'|trans }}
+{{ 'accompanying_course_work.results without objective'|trans }}
+{{ 'accompanying_course_work.results'|trans }}
+{{ 'accompanying_course_work.goal'|trans }}
+{{ 'accompanying_course_work.results'|trans }}
+{{ 'accompanying_course_work.no_results'|trans }}
+ {% else %} +{{ 'accompanying_course_work.results'|trans }}
+{{ 'accompanying_course_work.No work'|trans }}
+ {% endfor %} +