abdaf809f8
Auto Tag Develop / tag (push) Has been cancelled
| Numéro du ticket | Titre du ticket | |------------------|-----------------| | | | ## Description de la PR ## Modification du .env ## Check list - [x] Pas de régression - [x] TU/TI/TF rédigée - [x] TU/TI/TF OK - [x] CHANGELOG modifié Reviewed-on: #19 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
111 lines
3.5 KiB
PHP
111 lines
3.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Service\Contracts;
|
|
|
|
use App\Dto\Contracts\ContractPhase;
|
|
use App\Entity\Employee;
|
|
use App\Entity\EmployeeContractPeriod;
|
|
use DateTimeImmutable;
|
|
use LogicException;
|
|
|
|
final readonly class EmployeeContractPhaseResolver
|
|
{
|
|
private ?DateTimeImmutable $dataStartDate;
|
|
|
|
public function __construct(string $dataStartDate = '')
|
|
{
|
|
$trimmed = trim($dataStartDate);
|
|
if ('' === $trimmed) {
|
|
$this->dataStartDate = null;
|
|
|
|
return;
|
|
}
|
|
|
|
$parsed = DateTimeImmutable::createFromFormat('!Y-m-d', $trimmed);
|
|
$this->dataStartDate = $parsed instanceof DateTimeImmutable ? $parsed : null;
|
|
}
|
|
|
|
/**
|
|
* @return list<ContractPhase>
|
|
*/
|
|
public function resolvePhases(Employee $employee): array
|
|
{
|
|
$periods = $employee->getContractPeriods()->toArray();
|
|
usort(
|
|
$periods,
|
|
static fn (EmployeeContractPeriod $a, EmployeeContractPeriod $b): int => $a->getStartDate() <=> $b->getStartDate()
|
|
);
|
|
|
|
$today = new DateTimeImmutable('today');
|
|
$phases = [];
|
|
$group = [];
|
|
$signature = null;
|
|
|
|
foreach ($periods as $period) {
|
|
$currentSignature = $this->signature($period);
|
|
if (null !== $signature && $currentSignature !== $signature) {
|
|
$phases[] = $this->buildPhase($group, $today);
|
|
$group = [];
|
|
}
|
|
$group[] = $period;
|
|
$signature = $currentSignature;
|
|
}
|
|
|
|
if ([] !== $group) {
|
|
$phases[] = $this->buildPhase($group, $today);
|
|
}
|
|
|
|
// Hide phases entirely before the application's data start date: no usable
|
|
// work-hour or absence data exists before that date, so exposing them would
|
|
// confuse HR (e.g. legacy contract periods predating the software launch).
|
|
if (null !== $this->dataStartDate) {
|
|
$dataStart = $this->dataStartDate;
|
|
$phases = array_values(array_filter(
|
|
$phases,
|
|
static fn (ContractPhase $phase): bool => null === $phase->endDate || $phase->endDate >= $dataStart,
|
|
));
|
|
}
|
|
|
|
// Most recent first.
|
|
return array_reverse($phases);
|
|
}
|
|
|
|
private function signature(EmployeeContractPeriod $period): string
|
|
{
|
|
$contract = $period->getContract();
|
|
$type = $contract?->getType()->value ?? '';
|
|
$hours = $contract?->getWeeklyHours() ?? -1;
|
|
$driver = $period->getIsDriver() ? '1' : '0';
|
|
|
|
return sprintf('%s|%d|%s', $type, $hours, $driver);
|
|
}
|
|
|
|
/**
|
|
* @param non-empty-list<EmployeeContractPeriod> $group
|
|
*/
|
|
private function buildPhase(array $group, DateTimeImmutable $today): ContractPhase
|
|
{
|
|
$first = $group[0];
|
|
$last = end($group);
|
|
|
|
$endDate = $last->getEndDate();
|
|
$isCurrent = null === $endDate || $endDate >= $today;
|
|
|
|
$contract = $first->getContract();
|
|
|
|
return new ContractPhase(
|
|
id: (int) $first->getId(),
|
|
contractType: $contract?->getType() ?? throw new LogicException('Phase requires a contract type'),
|
|
weeklyHours: $contract?->getWeeklyHours(),
|
|
isDriver: $first->getIsDriver(),
|
|
startDate: $first->getStartDate(),
|
|
endDate: $endDate,
|
|
periodIds: array_map(static fn (EmployeeContractPeriod $p): int => (int) $p->getId(), $group),
|
|
isCurrent: $isCurrent,
|
|
contractNature: $first->getContractNatureEnum(),
|
|
);
|
|
}
|
|
}
|