Ajout des notification + page employé (#6)
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
| Numéro du ticket | Titre du ticket | |------------------|-----------------| | | | ## Description de la PR ## Modification du .env ## Check list - [ ] Pas de régression - [ ] TU/TI/TF rédigée - [ ] TU/TI/TF OK - [ ] CHANGELOG modifié Reviewed-on: #6 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #6.
This commit is contained in:
36
src/Service/Contracts/EmployeeContractChangeRequest.php
Normal file
36
src/Service/Contracts/EmployeeContractChangeRequest.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Contracts;
|
||||
|
||||
use App\Enum\ContractNature;
|
||||
use DateTimeImmutable;
|
||||
|
||||
final readonly class EmployeeContractChangeRequest
|
||||
{
|
||||
public function __construct(
|
||||
public ?ContractNature $contractNature,
|
||||
public ?DateTimeImmutable $contractStartDate,
|
||||
public ?DateTimeImmutable $contractEndDate,
|
||||
public ?bool $contractPaidLeaveSettled,
|
||||
public ?string $contractComment,
|
||||
) {}
|
||||
|
||||
public function hasPeriodChangeRequest(): bool
|
||||
{
|
||||
return null !== $this->contractNature
|
||||
|| null !== $this->contractStartDate
|
||||
|| null !== $this->contractEndDate
|
||||
|| null !== $this->contractPaidLeaveSettled
|
||||
|| null !== $this->contractComment;
|
||||
}
|
||||
|
||||
public function isCloseOnlyRequest(bool $contractChanged): bool
|
||||
{
|
||||
return !$contractChanged
|
||||
&& null === $this->contractStartDate
|
||||
&& null === $this->contractNature
|
||||
&& null !== $this->contractEndDate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Contracts;
|
||||
|
||||
use App\Entity\Employee;
|
||||
use App\Enum\ContractNature;
|
||||
use DateTimeImmutable;
|
||||
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
||||
|
||||
final class EmployeeContractChangeRequestFactory
|
||||
{
|
||||
public function fromEmployee(Employee $employee): EmployeeContractChangeRequest
|
||||
{
|
||||
return new EmployeeContractChangeRequest(
|
||||
contractNature: $this->resolveContractNature($employee->getContractNature()),
|
||||
contractStartDate: $this->parseOptionalYmd($employee->getContractStartDate(), 'contractStartDate'),
|
||||
contractEndDate: $this->parseOptionalYmd($employee->getContractEndDate(), 'contractEndDate'),
|
||||
contractPaidLeaveSettled: $employee->getContractPaidLeaveSettled(),
|
||||
contractComment: $employee->getContractComment(),
|
||||
);
|
||||
}
|
||||
|
||||
private function resolveContractNature(?string $raw): ?ContractNature
|
||||
{
|
||||
if (null === $raw || '' === trim($raw)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ContractNature::tryFrom(trim($raw))
|
||||
?? throw new UnprocessableEntityHttpException('contractNature must be one of CDI, CDD, INTERIM.');
|
||||
}
|
||||
|
||||
private function parseOptionalYmd(?string $raw, string $field): ?DateTimeImmutable
|
||||
{
|
||||
if (null === $raw || '' === trim($raw)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$value = trim($raw);
|
||||
$date = DateTimeImmutable::createFromFormat('Y-m-d', $value);
|
||||
if (!$date || $date->format('Y-m-d') !== $value) {
|
||||
throw new UnprocessableEntityHttpException(sprintf('%s must use Y-m-d format.', $field));
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
}
|
||||
30
src/Service/Contracts/EmployeeContractPeriodBuilder.php
Normal file
30
src/Service/Contracts/EmployeeContractPeriodBuilder.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Contracts;
|
||||
|
||||
use App\Entity\Contract;
|
||||
use App\Entity\Employee;
|
||||
use App\Entity\EmployeeContractPeriod;
|
||||
use App\Enum\ContractNature;
|
||||
use DateTimeImmutable;
|
||||
|
||||
final class EmployeeContractPeriodBuilder
|
||||
{
|
||||
public function build(
|
||||
Employee $employee,
|
||||
Contract $contract,
|
||||
DateTimeImmutable $startDate,
|
||||
?DateTimeImmutable $endDate,
|
||||
ContractNature $nature,
|
||||
): EmployeeContractPeriod {
|
||||
return new EmployeeContractPeriod()
|
||||
->setEmployee($employee)
|
||||
->setContract($contract)
|
||||
->setStartDate($startDate)
|
||||
->setEndDate($endDate)
|
||||
->setContractNature($nature)
|
||||
;
|
||||
}
|
||||
}
|
||||
98
src/Service/Contracts/EmployeeContractPeriodManager.php
Normal file
98
src/Service/Contracts/EmployeeContractPeriodManager.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Contracts;
|
||||
|
||||
use App\Entity\Contract;
|
||||
use App\Entity\Employee;
|
||||
use App\Entity\EmployeeContractPeriod;
|
||||
use App\Enum\ContractNature;
|
||||
use App\Repository\EmployeeContractPeriodRepository;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
||||
|
||||
final readonly class EmployeeContractPeriodManager implements EmployeeContractPeriodManagerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
private EmployeeContractPeriodRepository $periodRepository,
|
||||
private EmployeeContractPeriodBuilder $periodBuilder,
|
||||
private EmployeeContractPeriodValidator $periodValidator,
|
||||
) {}
|
||||
|
||||
public function ensureContractPeriodExists(
|
||||
Employee $employee,
|
||||
Contract $contract,
|
||||
DateTimeImmutable $startDate,
|
||||
?DateTimeImmutable $endDate,
|
||||
ContractNature $nature,
|
||||
): void {
|
||||
$this->periodValidator->assertPeriodDates($startDate, $endDate, $nature);
|
||||
|
||||
$covered = $this->periodRepository->findOneCoveringDate($employee, $startDate);
|
||||
if (null !== $covered) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->persistNewPeriod($employee, $contract, $startDate, $endDate, $nature);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
public function closeCurrentPeriod(
|
||||
?EmployeeContractPeriod $todayPeriod,
|
||||
DateTimeImmutable $requestedEndDate,
|
||||
bool $paidLeaveSettled,
|
||||
?string $comment = null
|
||||
): void {
|
||||
if (null === $todayPeriod) {
|
||||
throw new UnprocessableEntityHttpException('No active contract period to close.');
|
||||
}
|
||||
|
||||
$this->periodValidator->assertCloseEndDateCanBeApplied(
|
||||
$todayPeriod->getStartDate(),
|
||||
$todayPeriod->getEndDate(),
|
||||
$requestedEndDate,
|
||||
$todayPeriod->getContractNatureEnum()
|
||||
);
|
||||
|
||||
$todayPeriod->setEndDate($requestedEndDate);
|
||||
$todayPeriod->setPaidLeaveSettled($paidLeaveSettled);
|
||||
$todayPeriod->setComment($comment);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
public function createNextPeriod(
|
||||
Employee $employee,
|
||||
Contract $contract,
|
||||
DateTimeImmutable $startDate,
|
||||
?DateTimeImmutable $endDate,
|
||||
ContractNature $nature,
|
||||
?EmployeeContractPeriod $todayPeriod
|
||||
): void {
|
||||
$this->periodValidator->assertPeriodDates($startDate, $endDate, $nature);
|
||||
|
||||
if (null !== $todayPeriod) {
|
||||
$this->periodValidator->assertNextStartDateCompatible($startDate, $todayPeriod);
|
||||
|
||||
if (null === $todayPeriod->getEndDate()) {
|
||||
$todayPeriod->setEndDate($startDate->modify('-1 day'));
|
||||
}
|
||||
}
|
||||
|
||||
$this->persistNewPeriod($employee, $contract, $startDate, $endDate, $nature);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
private function persistNewPeriod(
|
||||
Employee $employee,
|
||||
Contract $contract,
|
||||
DateTimeImmutable $startDate,
|
||||
?DateTimeImmutable $endDate,
|
||||
ContractNature $nature,
|
||||
): void {
|
||||
$period = $this->periodBuilder->build($employee, $contract, $startDate, $endDate, $nature);
|
||||
$this->entityManager->persist($period);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Contracts;
|
||||
|
||||
use App\Entity\Contract;
|
||||
use App\Entity\Employee;
|
||||
use App\Entity\EmployeeContractPeriod;
|
||||
use App\Enum\ContractNature;
|
||||
use DateTimeImmutable;
|
||||
|
||||
interface EmployeeContractPeriodManagerInterface
|
||||
{
|
||||
public function ensureContractPeriodExists(
|
||||
Employee $employee,
|
||||
Contract $contract,
|
||||
DateTimeImmutable $startDate,
|
||||
?DateTimeImmutable $endDate,
|
||||
ContractNature $nature,
|
||||
): void;
|
||||
|
||||
public function closeCurrentPeriod(
|
||||
?EmployeeContractPeriod $todayPeriod,
|
||||
DateTimeImmutable $requestedEndDate,
|
||||
bool $paidLeaveSettled,
|
||||
?string $comment = null
|
||||
): void;
|
||||
|
||||
public function createNextPeriod(
|
||||
Employee $employee,
|
||||
Contract $contract,
|
||||
DateTimeImmutable $startDate,
|
||||
?DateTimeImmutable $endDate,
|
||||
ContractNature $nature,
|
||||
?EmployeeContractPeriod $todayPeriod
|
||||
): void;
|
||||
}
|
||||
63
src/Service/Contracts/EmployeeContractPeriodValidator.php
Normal file
63
src/Service/Contracts/EmployeeContractPeriodValidator.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Contracts;
|
||||
|
||||
use App\Entity\EmployeeContractPeriod;
|
||||
use App\Enum\ContractNature;
|
||||
use DateTimeImmutable;
|
||||
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
||||
|
||||
final class EmployeeContractPeriodValidator
|
||||
{
|
||||
public function assertPeriodDates(
|
||||
DateTimeImmutable $startDate,
|
||||
?DateTimeImmutable $endDate,
|
||||
ContractNature $nature,
|
||||
bool $allowCdiEndDate = false
|
||||
): void {
|
||||
if (null !== $endDate && $endDate < $startDate) {
|
||||
throw new UnprocessableEntityHttpException('contractEndDate cannot be before contractStartDate.');
|
||||
}
|
||||
|
||||
if ($nature->requiresEndDate() && null === $endDate) {
|
||||
throw new UnprocessableEntityHttpException('contractEndDate is required for CDD and INTERIM.');
|
||||
}
|
||||
|
||||
if (!$allowCdiEndDate && ContractNature::CDI === $nature && null !== $endDate) {
|
||||
throw new UnprocessableEntityHttpException('contractEndDate must be empty for CDI.');
|
||||
}
|
||||
}
|
||||
|
||||
public function assertCloseEndDateCanBeApplied(
|
||||
DateTimeImmutable $startDate,
|
||||
?DateTimeImmutable $currentEndDate,
|
||||
DateTimeImmutable $requestedEndDate,
|
||||
ContractNature $nature
|
||||
): void {
|
||||
$this->assertPeriodDates($startDate, $requestedEndDate, $nature, true);
|
||||
|
||||
if (null !== $currentEndDate && $requestedEndDate > $currentEndDate) {
|
||||
throw new UnprocessableEntityHttpException('contractEndDate cannot be increased on current contract.');
|
||||
}
|
||||
}
|
||||
|
||||
public function assertNextStartDateCompatible(
|
||||
DateTimeImmutable $startDate,
|
||||
EmployeeContractPeriod $currentPeriod
|
||||
): void {
|
||||
$currentEndDate = $currentPeriod->getEndDate();
|
||||
if (null === $currentEndDate) {
|
||||
if ($startDate <= $currentPeriod->getStartDate()) {
|
||||
throw new UnprocessableEntityHttpException('contractStartDate must be after current contract start date.');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($startDate <= $currentEndDate) {
|
||||
throw new UnprocessableEntityHttpException('contractStartDate must be after current contract end date.');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user