fix : calcule des congés en cours d'acquisition au prorata (date début contrat)

This commit is contained in:
2026-03-12 10:36:49 +01:00
parent b0de877b27
commit e34e928264
5 changed files with 222 additions and 28 deletions

View File

@@ -117,14 +117,14 @@ final readonly class LeaveBalanceComputationService
{
if (LeaveRuleCode::FORFAIT_218 === $ruleCode) {
return [
new DateTimeImmutable(sprintf('%d-01-01', $year)),
new DateTimeImmutable(sprintf('%d-12-31', $year)),
new DateTimeImmutable(sprintf('%d-01-01 00:00:00', $year)),
new DateTimeImmutable(sprintf('%d-12-31 00:00:00', $year)),
];
}
return [
new DateTimeImmutable(sprintf('%d-06-01', $year - 1)),
new DateTimeImmutable(sprintf('%d-05-31', $year)),
new DateTimeImmutable(sprintf('%d-06-01 00:00:00', $year - 1)),
new DateTimeImmutable(sprintf('%d-05-31 00:00:00', $year)),
];
}
@@ -145,7 +145,7 @@ final readonly class LeaveBalanceComputationService
$oldestStartDate = null;
foreach ($history as $item) {
$start = DateTimeImmutable::createFromFormat('Y-m-d', $item->startDate);
$start = $this->parseYmdDate($item->startDate);
if (!$start) {
continue;
}
@@ -197,14 +197,14 @@ final readonly class LeaveBalanceComputationService
): ?DateTimeImmutable {
$earliest = null;
foreach ($employee->getContractHistory() as $period) {
$start = DateTimeImmutable::createFromFormat('Y-m-d', $period->startDate);
$start = $this->parseYmdDate($period->startDate);
if (!$start) {
continue;
}
$end = null;
if (null !== $period->endDate && '' !== trim($period->endDate)) {
$end = DateTimeImmutable::createFromFormat('Y-m-d', $period->endDate);
$end = $this->parseYmdDate($period->endDate);
}
if ($start > $to) {
@@ -268,11 +268,37 @@ final readonly class LeaveBalanceComputationService
return 0.0;
}
$monthsElapsed = ((int) $periodEnd->format('Y') - (int) $periodStart->format('Y')) * 12
+ ((int) $periodEnd->format('n') - (int) $periodStart->format('n'))
+ 1;
$periodStart = $this->normalizeDate($periodStart);
$periodEnd = $this->normalizeDate($periodEnd);
$coveredMonths = 0.0;
$cursor = $periodStart->modify('first day of this month')->setTime(0, 0);
while ($cursor <= $periodEnd) {
$monthStart = $cursor > $periodStart ? $cursor : $periodStart;
$monthEnd = $cursor->modify('last day of this month')->setTime(0, 0);
if ($monthEnd > $periodEnd) {
$monthEnd = $periodEnd;
}
return min($annualCap, $monthsElapsed * $accrualPerMonth);
$coveredDays = ((int) $monthEnd->diff($monthStart)->format('%a')) + 1;
$daysInMonth = (int) $cursor->format('t');
$coveredMonths += $coveredDays / $daysInMonth;
$cursor = $cursor->modify('first day of next month');
}
return min($annualCap, $coveredMonths * $accrualPerMonth);
}
private function parseYmdDate(string $value): ?DateTimeImmutable
{
$date = DateTimeImmutable::createFromFormat('!Y-m-d', trim($value));
return $date instanceof DateTimeImmutable ? $date : null;
}
private function normalizeDate(DateTimeImmutable $date): DateTimeImmutable
{
return $date->setTime(0, 0);
}
private function countBusinessDays(DateTimeImmutable $from, DateTimeImmutable $to): int