Files
SIRH/src/Service/Leave/SuspensionDaysCalculator.php
tristan 4a2c3a8eed
All checks were successful
Auto Tag Develop / tag (push) Successful in 6s
feat : Ajout du système de RTT sur la page employé avec le repport annuel des heures
2026-03-13 10:26:33 +01:00

107 lines
3.0 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Service\Leave;
use App\Entity\ContractSuspension;
use DateTimeImmutable;
final class SuspensionDaysCalculator
{
/**
* Count calendar days suspended within a month window [monthStart, monthEnd].
*
* @param list<ContractSuspension> $suspensions
*/
public function countSuspendedDaysInMonth(
DateTimeImmutable $monthStart,
DateTimeImmutable $monthEnd,
array $suspensions
): int {
$total = 0;
foreach ($suspensions as $suspension) {
$sStart = $suspension->getStartDate();
$sEnd = $suspension->getEndDate() ?? $monthEnd;
$overlapStart = $sStart > $monthStart ? $sStart : $monthStart;
$overlapEnd = $sEnd < $monthEnd ? $sEnd : $monthEnd;
if ($overlapStart > $overlapEnd) {
continue;
}
$total += ((int) $overlapEnd->diff($overlapStart)->format('%a')) + 1;
}
return $total;
}
/**
* Return adjusted suspensions where the first month of each suspension is excluded (grace period).
*
* @param list<ContractSuspension> $suspensions
*
* @return list<ContractSuspension>
*/
public function applyFirstMonthGrace(array $suspensions): array
{
$adjusted = [];
foreach ($suspensions as $suspension) {
$gracedStart = $suspension->getStartDate()->modify('+1 month');
$end = $suspension->getEndDate();
if ($end instanceof DateTimeImmutable && $gracedStart > $end) {
continue;
}
$copy = new ContractSuspension();
$copy->setStartDate($gracedStart);
$copy->setEndDate($end);
$adjusted[] = $copy;
}
return $adjusted;
}
/**
* Count business days (Mon-Fri, excl. public holidays) suspended within a period.
*
* @param list<ContractSuspension> $suspensions
* @param array<string, string> $publicHolidays map of Y-m-d => label
*/
public function countSuspendedBusinessDays(
DateTimeImmutable $periodStart,
DateTimeImmutable $periodEnd,
array $suspensions,
array $publicHolidays
): int {
$total = 0;
foreach ($suspensions as $suspension) {
$sStart = $suspension->getStartDate();
$sEnd = $suspension->getEndDate() ?? $periodEnd;
$overlapStart = $sStart > $periodStart ? $sStart : $periodStart;
$overlapEnd = $sEnd < $periodEnd ? $sEnd : $periodEnd;
if ($overlapStart > $overlapEnd) {
continue;
}
for ($cursor = $overlapStart; $cursor <= $overlapEnd; $cursor = $cursor->modify('+1 day')) {
$weekDay = (int) $cursor->format('N');
$dayKey = $cursor->format('Y-m-d');
if ($weekDay <= 5 && !isset($publicHolidays[$dayKey])) {
++$total;
}
}
}
return $total;
}
}