Browse Source

add the RegistrationStatus resource / provider / service

Olivier Massot 2 years ago
parent
commit
69adcb2d38

+ 1 - 0
config/opentalent/products.yaml

@@ -227,6 +227,7 @@ opentalent:
             - AccessTmp
             - EducationStudentWish
             - OnlineRegistrationSettings
+            - RegistrationStatus
           roles:
             - ROLE_ONLINEREGISTRATION_ADMINISTRATION
 

+ 48 - 0
src/ApiResources/OnlineRegistration/RegistrationStatus.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace App\ApiResources\OnlineRegistration;
+
+use ApiPlatform\Metadata\ApiProperty;
+use ApiPlatform\Metadata\ApiResource;
+use ApiPlatform\Metadata\Get;
+use App\ApiResources\ApiResourcesInterface;
+use App\State\Provider\OnlineRegistration\RegistrationStatusProvider;
+use Symfony\Component\Serializer\Annotation\Groups;
+
+#[ApiResource(
+    operations: [
+        new Get(
+            uriTemplate: '/online_registration/registration_status/{accessId}',
+            requirements: ['accessId' => '\\d+'],
+            defaults: ['accessId' => 0],
+            provider: RegistrationStatusProvider::class
+        )
+    ]
+)]
+class RegistrationStatus implements ApiResourcesInterface
+{
+    #[ApiProperty(identifier: true)]
+    private int $accessId;
+
+    private ?string $status = null;
+
+    public function getAccessId(): int
+    {
+        return $this->accessId;
+    }
+
+    public function setAccessId(int $accessId): void
+    {
+        $this->accessId = $accessId;
+    }
+
+    public function getStatus(): ?string
+    {
+        return $this->status;
+    }
+
+    public function setStatus(?string $status): void
+    {
+        $this->status = $status;
+    }
+}

+ 30 - 1
src/Entity/AccessWish/AccessFamilyWish.php

@@ -20,9 +20,19 @@ class AccessFamilyWish
     #[ORM\GeneratedValue]
     private ?int $id = null;
 
+    #[ORM\Column]
+    private bool $registrationCompleted = false;
+
     #[ORM\OneToMany(mappedBy: 'accessFamilyWish', targetEntity: AccessWish::class, cascade: ['remove'])]
     private Collection $accessWishes;
 
+    /**
+     * Date de dernière mise à jour de l'entité
+     * @var DateTime
+     */
+    #[ORM\Column(type: 'datetime', nullable: true)]
+    private \DateTimeInterface $updateDate;
+
     public function __construct()
     {
         $this->accessWishes = new ArrayCollection();
@@ -33,6 +43,16 @@ class AccessFamilyWish
         return $this->id;
     }
 
+    public function isRegistrationCompleted(): bool
+    {
+        return $this->registrationCompleted;
+    }
+
+    public function setRegistrationCompleted(bool $registrationCompleted): void
+    {
+        $this->registrationCompleted = $registrationCompleted;
+    }
+
     /**
      * @return Collection<int, AccessWish>
      */
@@ -63,4 +83,13 @@ class AccessFamilyWish
         return $this;
     }
 
-}
+    public function getUpdateDate(): \DateTimeInterface
+    {
+        return $this->updateDate;
+    }
+
+    public function setUpdateDate(\DateTimeInterface $updateDate): void
+    {
+        $this->updateDate = $updateDate;
+    }
+}

+ 35 - 0
src/Entity/AccessWish/AccessWish.php

@@ -13,6 +13,7 @@ use App\Entity\Organization\Organization;
 use Doctrine\Common\Collections\ArrayCollection;
 use Doctrine\ORM\Mapping as ORM;
 use Doctrine\Common\Collections\Collection;
+use \DateTime;
 
 /**
  * Classe ... qui ...
@@ -60,6 +61,20 @@ class AccessWish
     #[ORM\InverseJoinColumn(name: 'tag_id', referencedColumnName: 'id')]
     private Collection $tags;
 
+    /**
+     * Date de création dde l'entité
+     * @var DateTime
+     */
+    #[ORM\Column(type: 'datetime', nullable: true)]
+    private \DateTimeInterface $createDate;
+
+    /**
+     * Date de dernière mise à jour de l'entité
+     * @var DateTime
+     */
+    #[ORM\Column(type: 'datetime', nullable: true)]
+    private \DateTimeInterface $updateDate;
+
     public function __construct()
     {
         $this->educationStudentWishes = new ArrayCollection();
@@ -246,4 +261,24 @@ class AccessWish
 
         return $this;
     }
+
+    public function getCreateDate(): DateTime
+    {
+        return $this->createDate;
+    }
+
+    public function setCreateDate(DateTime $createDate): void
+    {
+        $this->createDate = $createDate;
+    }
+
+    public function getUpdateDate(): DateTime
+    {
+        return $this->updateDate;
+    }
+
+    public function setUpdateDate(DateTime $updateDate): void
+    {
+        $this->updateDate = $updateDate;
+    }
 }

+ 40 - 1
src/Entity/AccessWish/EducationStudentWish.php

@@ -8,7 +8,10 @@ use App\Entity\Education\EducationCurriculum;
 use App\Entity\Education\EducationStudent;
 use App\Entity\Education\EducationTiming;
 //use DH\Auditor\Provider\Doctrine\Auditing\Annotation\Auditable;
+use App\Enum\OnlineRegistration\RegistrationStatusEnum;
+use App\Enum\OnlineRegistration\WishRegistrationEnum;
 use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Validator\Constraints as Assert;
 
 /**
  * Classe ... qui ...
@@ -22,6 +25,22 @@ class EducationStudentWish
     #[ORM\GeneratedValue]
     private ?int $id = null;
 
+    /**
+     * TODO: Documenter
+     * @var string|null
+     */
+    #[ORM\Column(length: 50)]
+    #[Assert\Choice(callback: [WishRegistrationEnum::class, 'toArray'])]
+    private ?string $wishRegistration = null;
+
+    /**
+     * Statut de l'enregistrement en ligne
+     * @var string|null
+     */
+    #[ORM\Column(length: 50)]
+    #[Assert\Choice(callback: [RegistrationStatusEnum::class, 'toArray'])]
+    private ?string $registrationStatus = null;
+
     #[ORM\ManyToOne]
     #[ORM\JoinColumn(referencedColumnName: 'id' ,nullable: true, onDelete: 'SET NULL')]
     private Education $educationWish;
@@ -49,6 +68,26 @@ class EducationStudentWish
         return $this->id;
     }
 
+    public function getWishRegistration(): ?string
+    {
+        return $this->wishRegistration;
+    }
+
+    public function setWishRegistration(?string $wishRegistration): void
+    {
+        $this->wishRegistration = $wishRegistration;
+    }
+
+    public function getRegistrationStatus(): ?string
+    {
+        return $this->registrationStatus;
+    }
+
+    public function setRegistrationStatus(?string $registrationStatus): void
+    {
+        $this->registrationStatus = $registrationStatus;
+    }
+
     public function getEducationWish(): ?Education
     {
         return $this->educationWish;
@@ -120,4 +159,4 @@ class EducationStudentWish
 
         return $this;
     }
-}
+}

+ 21 - 0
src/Enum/OnlineRegistration/RegistrationStatusEnum.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace App\Enum\OnlineRegistration;
+
+use MyCLabs\Enum\Enum;
+
+/**
+ * Statut de l'enregistrement en ligne
+ *
+ * @method static NEGOTIABLE()
+ * @method static ACCEPTED()
+ * @method static PENDING()
+ * @method static DENIED()
+ */
+class RegistrationStatusEnum extends Enum
+{
+    private const NEGOTIABLE = 'NEGOTIABLE';
+    private const ACCEPTED = 'ACCEPTED';
+    private const PENDING = 'PENDING';
+    private const DENIED = 'DENIED';
+}

+ 19 - 0
src/Enum/OnlineRegistration/WishRegistrationEnum.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace App\Enum\OnlineRegistration;
+
+use MyCLabs\Enum\Enum;
+
+/**
+ * TODO: documenter
+ *
+ * @method static NO_INFORMATION()
+ * @method static REREGISTER()
+ * @method static STOP_REGISTRATION()
+ */
+class WishRegistrationEnum extends Enum
+{
+    const NO_INFORMATION = 'NO_INFORMATION';
+    const REREGISTER = 'REREGISTER';
+    const STOP_REGISTRATION = 'STOP_REGISTRATION';
+}

+ 146 - 0
src/Service/OnlineRegistration/RegistrationStatusService.php

@@ -0,0 +1,146 @@
+<?php
+
+namespace App\Service\OnlineRegistration;
+
+use App\Entity\AccessWish\AccessWish;
+use App\Entity\Access\Access;
+use App\Service\Utils\DatesUtils;
+use App\Enum\OnlineRegistration\RegistrationStatusEnum;
+use App\Enum\OnlineRegistration\WishRegistrationEnum;
+
+/**
+ * Fournit le statut de l'enregistrement en ligne d'un Access
+ */
+class RegistrationStatusService
+{
+    /**
+     * Temps de validité du statut (en jours)
+     * (correspond au temps d'affichage de l'avertissement dans l'application)
+     */
+    const DISPLAYING_TIME = 30;
+
+    /**
+     * Détermine er retourne le statut de l'enregistrement en ligne d'un Access.
+     *
+     * @param Access $access
+     * @return string|null
+     */
+    public function getStatus(Access $access): string | null {
+
+        $currentAccessWish = $this->getCurrentAccessWish($access);
+        if ($currentAccessWish === null) {
+            return null;
+        }
+
+        if (!$currentAccessWish->getAccessFamilyWish()->isRegistrationCompleted()) {
+            return null;
+        }
+
+        $numberByStatus = $this->getCountEducationsByRegistrationStatus($currentAccessWish);
+        if ($numberByStatus === null) {
+            return null;
+        }
+
+        $hasNegotiable = $numberByStatus[RegistrationStatusEnum::NEGOTIABLE()->getValue()] > 0;
+        $hasAccepted = $numberByStatus[RegistrationStatusEnum::ACCEPTED()->getValue()] > 0;
+        $hasPending = $numberByStatus[RegistrationStatusEnum::PENDING()->getValue()] > 0;
+        $hasDenied = $numberByStatus[RegistrationStatusEnum::DENIED()->getValue()] > 0;
+
+        // Après acceptation ou refus, le bandeau est affiché pour une durée de 30 jours.
+        if(
+            !$hasNegotiable && ($hasAccepted || $hasDenied) &&
+            $this->getDaysSinceLastUpdate($currentAccessWish) > self::DISPLAYING_TIME
+        ) {
+            return null;
+        }
+
+        if (!$hasAccepted && !$hasPending && $hasNegotiable) {
+            // La demande est dans la liste des inscriptions en ligne et n'a pas été traitée par l'administration
+            return RegistrationStatusEnum::NEGOTIABLE()->getValue();
+        }
+        else if ($hasPending && !$hasAccepted) {
+            // La demande est dans la liste des inscriptions en ligne car l'administration a mis "En attente" à au moins l'un des enseignements.
+            return RegistrationStatusEnum::PENDING()->getValue();
+        }
+        else if ($hasAccepted)
+        {
+            // La demande a été traitée par l'administration. L'élève a été accepté pour au moins l'une de ses activités.
+            // Et il a été placé dans la liste des "Inscriptions rentrée prochaine".
+            return RegistrationStatusEnum::ACCEPTED()->getValue();
+        }
+        else if ($hasDenied && !$hasNegotiable) {
+            // La demande a été traitée par l'administration. L'élève n'a pas été accepté dans l'établissement.
+            // Il est dans la liste des "Inscriptions en ligne" avec le statut "Refusé" sur tous ses enseignements.
+            return RegistrationStatusEnum::DENIED();
+        }
+
+        return null;
+    }
+
+    /**
+     * Retourne le premier AccessWish correspondant à l'année en cours, ou null si aucun n'est trouvé
+     *
+     * @param Access $access
+     * @return AccessWish | null
+     */
+    private function getCurrentAccessWish(Access $access): AccessWish | null {
+        $currentYear =  DatesUtils::new()->format('Y');
+
+        foreach ($access->getAccessWishes() as $accessWish)
+        {
+            /** @var AccessWish $accessWish */
+            if ($accessWish->getCreateDate()->format('Y') === $currentYear) {
+                return $accessWish;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * @param AccessWish $currentAccessWish
+     * @return int
+     * @throws \Exception
+     */
+    private function getDaysSinceLastUpdate(AccessWish $currentAccessWish): int {
+        return (int)DatesUtils::new()
+            ->diff($currentAccessWish->getAccessFamilyWish()->getUpdateDate())
+            ->format("%a");
+    }
+
+    /**
+     * Retourne le décompte des souhaits de l'utilisateur par RegistrationStatus, ou null si aucun souhaits.
+     *
+     * @param AccessWish $currentAccessWish
+     * @return array<string, int> | null
+     */
+    private function getCountEducationsByRegistrationStatus(AccessWish $currentAccessWish): array | null {
+
+        $wishes = $currentAccessWish->getEducationStudentWishes();
+        $reregistrationWishes = $currentAccessWish->getEducationStudentReregistrationsWishes();
+
+        if ($reregistrationWishes->count() === 0 && $wishes->count() === 0) {
+            return null;
+        }
+
+        $registrationStatuses = [
+            RegistrationStatusEnum::NEGOTIABLE()->getValue() => 0,
+            RegistrationStatusEnum::ACCEPTED()->getValue() => 0,
+            RegistrationStatusEnum::PENDING()->getValue() => 0,
+            RegistrationStatusEnum::DENIED()->getValue() => 0
+        ];
+
+        foreach ($reregistrationWishes as $reregistrationWish) {
+            if ($reregistrationWish->getWishRegistration() !== WishRegistrationEnum::REREGISTER()->getValue()) {
+                continue;
+            }
+            $registrationStatuses[$reregistrationWish->getRegistrationStatus()]++;
+        }
+
+        foreach ($wishes as $educationStudentWish){
+            $registrationStatuses[$educationStudentWish->getRegistrationStatus()]++;
+        }
+
+        return $registrationStatuses;
+    }
+}

+ 49 - 0
src/State/Provider/OnlineRegistration/RegistrationStatusProvider.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace App\State\Provider\OnlineRegistration;
+
+use ApiPlatform\Metadata\GetCollection;
+use ApiPlatform\Metadata\Operation;
+use ApiPlatform\State\ProviderInterface;
+use App\ApiResources\OnlineRegistration\RegistrationStatus;
+use App\Entity\Access\Access;
+use App\Repository\Access\AccessRepository;
+use App\Service\OnlineRegistration\RegistrationStatusService;
+use Symfony\Bundle\SecurityBundle\Security;
+use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
+use RuntimeException;
+
+class RegistrationStatusProvider implements ProviderInterface
+{
+    public function __construct(
+        private Security $security,
+        private RegistrationStatusService $registrationStatusService,
+        private AccessRepository $accessRepository
+    ) {}
+
+    /**
+     * @param Operation $operation
+     * @param mixed[] $uriVariables
+     * @param mixed[] $context
+     * @return RegistrationStatus|null
+     */
+    public function provide(Operation $operation, array $uriVariables = [], array $context = []): ?RegistrationStatus {
+        if($operation instanceof GetCollection) {
+            throw new RuntimeException('not supported', 500);
+        }
+
+        // TODO: voir à refactoriser le "getUser" dans un data provider de base (d'autres ont besoin de l'access et de l'orga en cours)
+        $currentAccess = $this->security->getUser();
+
+        $access = $this->accessRepository->find($uriVariables['accessId']) ?? $currentAccess;
+
+        $registrationStatusValue = $this->registrationStatusService->getStatus($access);
+
+        $registrationStatus = new RegistrationStatus();
+        $registrationStatus->setAccessId($access->getId());
+        $registrationStatus->setStatus($registrationStatusValue);
+
+        return $registrationStatus;
+    }
+
+}