feat : ajout des suspensions et des jours de présence
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
This commit is contained in:
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace App\Service\Leave;
|
||||
|
||||
use App\Entity\Absence;
|
||||
use App\Entity\ContractSuspension;
|
||||
use App\Entity\Employee;
|
||||
use App\Enum\LeaveRuleCode;
|
||||
use App\Repository\AbsenceRepository;
|
||||
@@ -29,6 +30,7 @@ final readonly class LeaveBalanceComputationService
|
||||
private EmployeeContractPeriodRepository $periodRepository,
|
||||
private EmployeeLeaveBalanceRepository $leaveBalanceRepository,
|
||||
private PublicHolidayServiceInterface $publicHolidayService,
|
||||
private SuspensionDaysCalculator $suspensionDaysCalculator,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -67,7 +69,18 @@ final readonly class LeaveBalanceComputationService
|
||||
$fractionedDays = $this->resolveFractionedDays($employee, $ruleCode, $year);
|
||||
|
||||
if (LeaveRuleCode::FORFAIT_218 === $ruleCode) {
|
||||
$acquiredDays = $carryDays + (float) max(0, $this->countBusinessDays($from, $to) - self::FORFAIT_TARGET_WORKED_DAYS) + $fractionedDays;
|
||||
$totalBusinessDays = $this->countBusinessDays($from, $to);
|
||||
$baseAcquiredDays = (float) max(0, $totalBusinessDays - self::FORFAIT_TARGET_WORKED_DAYS);
|
||||
$suspensions = $this->resolveSuspensionsForEmployeePeriod($employee, $from, $to);
|
||||
$acquiredDays = $carryDays + $baseAcquiredDays + $fractionedDays;
|
||||
if ([] !== $suspensions) {
|
||||
$totalMonths = $this->countFractionalMonths($from, $to);
|
||||
$suspendedMonths = $this->countSuspendedFractionalMonths($from, $to, $suspensions);
|
||||
if ($totalMonths > 0) {
|
||||
$ratio = max(0.0, ($totalMonths - $suspendedMonths) / $totalMonths);
|
||||
$acquiredDays = $carryDays + $baseAcquiredDays * $ratio + $fractionedDays;
|
||||
}
|
||||
}
|
||||
$absences = $this->absenceRepository->findByEmployeeAndOverlappingDateRange($employee, $effectiveFrom, $to);
|
||||
[$takenDays] = $this->computeTakenAbsences($absences, $effectiveFrom, $to, false, false);
|
||||
$previousRemainingDays = max(0.0, $acquiredDays - $takenDays);
|
||||
@@ -76,17 +89,20 @@ final readonly class LeaveBalanceComputationService
|
||||
continue;
|
||||
}
|
||||
|
||||
$suspensions = $this->resolveSuspensionsForEmployeePeriod($employee, $from, $to);
|
||||
$generatedDays = $this->computeAccruedDays(
|
||||
$this->resolveAnnualDays($employee),
|
||||
$this->resolveDaysAccrualPerMonth($employee),
|
||||
$effectiveFrom,
|
||||
$to
|
||||
$to,
|
||||
$suspensions
|
||||
);
|
||||
$generatedSaturdays = $this->computeAccruedDays(
|
||||
$this->resolveAnnualSaturdays($employee),
|
||||
$this->resolveSaturdayAccrualPerMonth($employee),
|
||||
$effectiveFrom,
|
||||
$to
|
||||
$to,
|
||||
$suspensions
|
||||
);
|
||||
|
||||
$absences = $this->absenceRepository->findByEmployeeAndOverlappingDateRange($employee, $effectiveFrom, $to);
|
||||
@@ -262,7 +278,8 @@ final readonly class LeaveBalanceComputationService
|
||||
float $annualCap,
|
||||
float $accrualPerMonth,
|
||||
DateTimeImmutable $periodStart,
|
||||
DateTimeImmutable $periodEnd
|
||||
DateTimeImmutable $periodEnd,
|
||||
array $suspensions = []
|
||||
): float {
|
||||
if ($accrualPerMonth <= 0.0 || $periodEnd < $periodStart) {
|
||||
return 0.0;
|
||||
@@ -280,6 +297,10 @@ final readonly class LeaveBalanceComputationService
|
||||
}
|
||||
|
||||
$coveredDays = ((int) $monthEnd->diff($monthStart)->format('%a')) + 1;
|
||||
if ([] !== $suspensions) {
|
||||
$suspendedDays = $this->suspensionDaysCalculator->countSuspendedDaysInMonth($monthStart, $monthEnd, $suspensions);
|
||||
$coveredDays = max(0, $coveredDays - $suspendedDays);
|
||||
}
|
||||
$daysInMonth = (int) $cursor->format('t');
|
||||
$coveredMonths += $coveredDays / $daysInMonth;
|
||||
|
||||
@@ -404,6 +425,80 @@ final readonly class LeaveBalanceComputationService
|
||||
return [$takenDays, $takenSaturdays];
|
||||
}
|
||||
|
||||
private function countFractionalMonths(DateTimeImmutable $from, DateTimeImmutable $to): float
|
||||
{
|
||||
$from = $this->normalizeDate($from);
|
||||
$to = $this->normalizeDate($to);
|
||||
$months = 0.0;
|
||||
$cursor = $from->modify('first day of this month')->setTime(0, 0);
|
||||
|
||||
while ($cursor <= $to) {
|
||||
$monthStart = $cursor > $from ? $cursor : $from;
|
||||
$monthEnd = $cursor->modify('last day of this month')->setTime(0, 0);
|
||||
if ($monthEnd > $to) {
|
||||
$monthEnd = $to;
|
||||
}
|
||||
$coveredDays = ((int) $monthEnd->diff($monthStart)->format('%a')) + 1;
|
||||
$daysInMonth = (int) $cursor->format('t');
|
||||
$months += $coveredDays / $daysInMonth;
|
||||
|
||||
$cursor = $cursor->modify('first day of next month');
|
||||
}
|
||||
|
||||
return $months;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<ContractSuspension> $suspensions
|
||||
*/
|
||||
private function countSuspendedFractionalMonths(DateTimeImmutable $from, DateTimeImmutable $to, array $suspensions): float
|
||||
{
|
||||
$from = $this->normalizeDate($from);
|
||||
$to = $this->normalizeDate($to);
|
||||
$months = 0.0;
|
||||
$cursor = $from->modify('first day of this month')->setTime(0, 0);
|
||||
|
||||
while ($cursor <= $to) {
|
||||
$monthStart = $cursor > $from ? $cursor : $from;
|
||||
$monthEnd = $cursor->modify('last day of this month')->setTime(0, 0);
|
||||
if ($monthEnd > $to) {
|
||||
$monthEnd = $to;
|
||||
}
|
||||
$daysInMonth = (int) $cursor->format('t');
|
||||
$suspendedDays = $this->suspensionDaysCalculator->countSuspendedDaysInMonth($monthStart, $monthEnd, $suspensions);
|
||||
$months += $suspendedDays / $daysInMonth;
|
||||
|
||||
$cursor = $cursor->modify('first day of next month');
|
||||
}
|
||||
|
||||
return $months;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<ContractSuspension>
|
||||
*/
|
||||
private function resolveSuspensionsForEmployeePeriod(Employee $employee, DateTimeImmutable $from, DateTimeImmutable $to): array
|
||||
{
|
||||
$suspensions = [];
|
||||
foreach ($employee->getContractPeriods() as $period) {
|
||||
$periodStart = $period->getStartDate();
|
||||
$periodEnd = $period->getEndDate();
|
||||
|
||||
if ($periodStart > $to) {
|
||||
continue;
|
||||
}
|
||||
if ($periodEnd instanceof DateTimeImmutable && $periodEnd < $from) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($period->getSuspensions() as $suspension) {
|
||||
$suspensions[] = $suspension;
|
||||
}
|
||||
}
|
||||
|
||||
return $suspensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{bool, bool}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user