[#SIRH-32] Ajouter l'exercice 2026/2027 dans les congés/RTT (#20)
Auto Tag Develop / tag (push) Successful in 9s

| 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
- [ ] CHANGELOG modifié

Reviewed-on: #20
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #20.
This commit is contained in:
2026-05-26 14:09:02 +00:00
committed by Autin
parent 25083f00c8
commit cf2e12c8ba
18 changed files with 939 additions and 59 deletions
@@ -51,9 +51,20 @@ final readonly class LeaveBalanceComputationService
for ($year = $firstYear; $year <= $targetYear; ++$year) {
[$from, $to] = $this->resolvePeriodBounds($ruleCode, $year);
// Bootstrap anchor: a manually-entered opening balance (production data
// bootstrap) is the source of truth for the carry of that year — exactly
// like EmployeeLeaveSummaryProvider::computeYearSummary for the live view.
// Without it, the closing would be recomputed from the contract start with no
// historical absences, inflating the carry by one full year of accrual for
// every exercise predating the software (cas Aurore : 88 au lieu de 31).
$openingBalance = $this->leaveBalanceRepository->findOneByEmployeeRuleAndYear($employee, $ruleCode, $year);
$carryDays = 0.0;
$carrySaturdays = 0.0;
if ($year > $firstYear) {
if (null !== $openingBalance) {
$carryDays = $openingBalance->getOpeningDays();
$carrySaturdays = LeaveRuleCode::CDI_CDD_NON_FORFAIT === $ruleCode ? $openingBalance->getOpeningSaturdays() : 0.0;
} elseif ($year > $firstYear) {
[$previousFrom, $previousTo] = $this->resolvePeriodBounds($ruleCode, $year - 1);
$hasSettlementOnPreviousYear = $this->periodRepository->hasPaidLeaveSettledClosureBetween($employee, $previousFrom, $previousTo);
if (!$hasSettlementOnPreviousYear) {
@@ -63,7 +74,10 @@ final readonly class LeaveBalanceComputationService
}
$effectiveFrom = $this->resolveEffectivePeriodStart($employee, $from, $to);
if ($effectiveFrom > $from) {
// A shifted start (new hire / settled closure) zeroes the dynamic carry, but
// an explicit bootstrap opening balance must be preserved (it already reflects
// the real situation at the bootstrap date).
if ($effectiveFrom > $from && null === $openingBalance) {
$carryDays = 0.0;
$carrySaturdays = 0.0;
}
@@ -74,11 +88,14 @@ final readonly class LeaveBalanceComputationService
// Business days for forfait must use the RAW holiday list (excluded holidays
// like "Lundi de Pentecôte" / journée de solidarité still count as non-working
// days for the 218-day legal target).
$totalBusinessDays = $this->countBusinessDaysInRange($from, $to, $this->buildRawPublicHolidayMap($from, $to));
$baseAcquiredDays = (float) max(0, $totalBusinessDays - self::FORFAIT_TARGET_WORKED_DAYS);
$acquiredDays = $carryDays + $baseAcquiredDays + $fractionedDays;
$absences = $this->absenceRepository->findByEmployeeAndOverlappingDateRange($employee, $effectiveFrom, $to);
[$takenDays] = $this->computeTakenAbsences($absences, $effectiveFrom, $to, false, false);
$totalBusinessDays = $this->countBusinessDaysInRange($from, $to, $this->buildRawPublicHolidayMap($from, $to));
$baseAcquiredDays = (float) max(0, $totalBusinessDays - self::FORFAIT_TARGET_WORKED_DAYS);
$acquiredDays = $carryDays + $baseAcquiredDays + $fractionedDays;
$absences = $this->absenceRepository->findByEmployeeAndOverlappingDateRange($employee, $effectiveFrom, $to);
[$takenDays] = $this->computeTakenAbsences($absences, $effectiveFrom, $to, false, false);
if (null !== $openingBalance) {
$takenDays += $openingBalance->getTakenDays();
}
$previousRemainingDays = max(0.0, $acquiredDays - $takenDays);
$previousRemainingSaturdays = 0.0;
@@ -120,6 +137,10 @@ final readonly class LeaveBalanceComputationService
$absences = $this->absenceRepository->findByEmployeeAndOverlappingDateRange($employee, $effectiveFrom, $to);
[$takenDays, $takenSaturdays] = $this->computeTakenAbsences($absences, $effectiveFrom, $to, true, true);
if (null !== $openingBalance) {
$takenDays += $openingBalance->getTakenDays();
$takenSaturdays += $openingBalance->getTakenSaturdays();
}
$acquiredWithFractioned = $carryDays + $fractionedDays;
$takenFromAcquired = min(max(0.0, $acquiredWithFractioned), $takenDays);