feat : ajout des suspensions et des jours de présence
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled

This commit is contained in:
2026-03-12 16:46:06 +01:00
parent e6819bc68a
commit 38f09914cb
25 changed files with 2969 additions and 21 deletions

View File

@@ -0,0 +1,122 @@
<?php
declare(strict_types=1);
namespace App\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\Entity\ContractSuspension;
use App\Entity\EmployeeContractPeriod;
use DateTimeImmutable;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
final readonly class ContractSuspensionWriteProcessor implements ProcessorInterface
{
public function __construct(
#[Autowire(service: 'api_platform.doctrine.orm.state.persist_processor')]
private ProcessorInterface $persistProcessor,
private EntityManagerInterface $entityManager,
) {}
public function process(
mixed $data,
Operation $operation,
array $uriVariables = [],
array $context = []
): mixed {
if (!$data instanceof ContractSuspension) {
return $this->persistProcessor->process($data, $operation, $uriVariables, $context);
}
$period = $data->getContractPeriod();
if (!$period instanceof EmployeeContractPeriod && null !== $data->getContractPeriodId()) {
$period = $this->entityManager->find(EmployeeContractPeriod::class, $data->getContractPeriodId());
if ($period instanceof EmployeeContractPeriod) {
$data->setContractPeriod($period);
}
}
if (!$period instanceof EmployeeContractPeriod) {
throw new UnprocessableEntityHttpException('contractPeriodId is required.');
}
$this->validate($data, $period);
return $this->persistProcessor->process($data, $operation, $uriVariables, $context);
}
private function validate(ContractSuspension $suspension, EmployeeContractPeriod $period): void
{
// Compare as Y-m-d strings to avoid timezone issues between Doctrine and API Platform DateTimeImmutable
$startDate = $suspension->getStartDate()->format('Y-m-d');
$endDate = $suspension->getEndDate()?->format('Y-m-d');
$periodStart = $period->getStartDate()->format('Y-m-d');
$periodEnd = $period->getEndDate()?->format('Y-m-d');
if (null !== $periodEnd && $periodEnd < new DateTimeImmutable('today')->format('Y-m-d')) {
throw new UnprocessableEntityHttpException('Impossible de suspendre une période de contrat clôturée.');
}
if (null !== $endDate && $endDate < $startDate) {
throw new UnprocessableEntityHttpException('La date de fin doit être postérieure à la date de début.');
}
if ($startDate < $periodStart) {
throw new UnprocessableEntityHttpException('La suspension ne peut pas commencer avant le début du contrat.');
}
if (null !== $periodEnd) {
if ($startDate > $periodEnd) {
throw new UnprocessableEntityHttpException('La suspension ne peut pas commencer après la fin du contrat.');
}
if (null !== $endDate && $endDate > $periodEnd) {
throw new UnprocessableEntityHttpException('La suspension ne peut pas se terminer après la fin du contrat.');
}
}
$this->validateNoOverlap($suspension, $period);
}
private function validateNoOverlap(ContractSuspension $suspension, EmployeeContractPeriod $period): void
{
$start = $suspension->getStartDate()->format('Y-m-d');
$end = $suspension->getEndDate()?->format('Y-m-d');
foreach ($period->getSuspensions() as $existing) {
if ($existing->getId() === $suspension->getId() && null !== $suspension->getId()) {
continue;
}
$existingStart = $existing->getStartDate()->format('Y-m-d');
$existingEnd = $existing->getEndDate()?->format('Y-m-d');
if (null === $end && null === $existingEnd) {
throw new UnprocessableEntityHttpException('Les suspensions ne peuvent pas se chevaucher.');
}
if (null === $end) {
if ($start <= $existingEnd) {
throw new UnprocessableEntityHttpException('Les suspensions ne peuvent pas se chevaucher.');
}
continue;
}
if (null === $existingEnd) {
if ($existingStart <= $end) {
throw new UnprocessableEntityHttpException('Les suspensions ne peuvent pas se chevaucher.');
}
continue;
}
if ($start <= $existingEnd && $end >= $existingStart) {
throw new UnprocessableEntityHttpException('Les suspensions ne peuvent pas se chevaucher.');
}
}
}
}