From 59f05717bf02a1bd8871df4f96160403b885a6ad Mon Sep 17 00:00:00 2001 From: tristan Date: Wed, 11 Mar 2026 17:34:07 +0100 Subject: [PATCH] =?UTF-8?q?fix=20:=20prise=20en=20compte=20des=20cong?= =?UTF-8?q?=C3=A9s=20au=20provisionnel=20sauf=20pour=20les=20en=20cours=20?= =?UTF-8?q?d'acquisition?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/functional-rules.md | 6 ++- src/State/EmployeeLeaveSummaryProvider.php | 48 +++++++++++++++++++--- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/doc/functional-rules.md b/doc/functional-rules.md index a94fabd..a4bb51d 100644 --- a/doc/functional-rules.md +++ b/doc/functional-rules.md @@ -198,14 +198,16 @@ Tous les filtres checkbox sont cochés par défaut à l'ouverture du drawer. - lecture des compteurs: - `acquis` = droits reportés de l'exercice N-1 (après application des règles de soldé) - `en cours d'acquisition` = total droits générés sur l'exercice N (jours + samedis en cours), sans detail séparé en UI + - `en cours d'acquisition` est arrêté au dernier jour du mois précédent - règle de consommation: - les absences s'imputent d'abord sur `acquis`, puis sur `en cours d'acquisition` - la prise sur `en cours d'acquisition` est autorisée (usage anticipé) - `en cours d'acquisition` peut devenir négatif si la prise dépasse le généré (ex: `2.08 - 3 = -0.92`), puis se reconstitue avec les acquisitions suivantes - date d'arret de calcul: - - les compteurs sont calculés en prévisionnel jusqu'à la fin de l'exercice + - `reste à prendre` est calculé en prévisionnel jusqu'à la fin de l'exercice - les absences futures déjà posées sur l'exercice sont déduites du `reste à prendre` - - exemple: au `11/03/2026`, l'exercice `2026` est calculé jusqu'au `31/05/2026` + - `en cours d'acquisition` reste calculé jusqu'au dernier jour du mois précédent + - exemple: au `11/03/2026`, l'exercice `2026` déduit les absences posées jusqu'au `31/05/2026`, mais l'acquisition reste arrêtée au `28/02/2026` - hors périmètre phase 1: `INTERIM` (retour non supporté) - onglet `RTT`: - endpoint de synthèse: `GET /api/employees/{id}/rtt-summary?year=YYYY` diff --git a/src/State/EmployeeLeaveSummaryProvider.php b/src/State/EmployeeLeaveSummaryProvider.php index c114964..2bec81f 100644 --- a/src/State/EmployeeLeaveSummaryProvider.php +++ b/src/State/EmployeeLeaveSummaryProvider.php @@ -168,13 +168,14 @@ final readonly class EmployeeLeaveSummaryProvider implements ProviderInterface $carrySaturdays = 0.0; } - $calculationEnd = $this->resolveCalculationEndDate($to, $employee); - $generatedDays = $leavePolicy['accrualPerMonth'] > 0.0 + $accrualCalculationEnd = $this->resolveAccrualCalculationEndDate($leavePolicy['ruleCode'], $year, $to, $employee); + $takenCalculationEnd = $this->resolveTakenCalculationEndDate($to, $employee); + $generatedDays = $leavePolicy['accrualPerMonth'] > 0.0 ? $this->computeAccruedDaysFromStart( $leavePolicy['acquiredDays'], $leavePolicy['accrualPerMonth'], $effectiveFrom, - $calculationEnd + $accrualCalculationEnd ) : 0.0; $generatedSaturdays = $leavePolicy['saturdayAccrualPerMonth'] > 0.0 @@ -182,14 +183,14 @@ final readonly class EmployeeLeaveSummaryProvider implements ProviderInterface $leavePolicy['acquiredSaturdays'], $leavePolicy['saturdayAccrualPerMonth'], $effectiveFrom, - $calculationEnd + $accrualCalculationEnd ) : 0.0; $absences = $this->absenceRepository->findByEmployeeAndOverlappingDateRange($employee, $from, $to); [$takenDays, $takenSaturdays] = $this->computeTakenAbsences( $absences, $effectiveFrom, - $calculationEnd, + $takenCalculationEnd, $leavePolicy['countOnlyCp'], $leavePolicy['splitSaturdays'] ); @@ -353,7 +354,42 @@ final readonly class EmployeeLeaveSummaryProvider implements ProviderInterface return min($acquiredDays, $monthsElapsed * $accrualPerMonth); } - private function resolveCalculationEndDate( + private function resolveAccrualCalculationEndDate( + string $ruleCode, + int $year, + DateTimeImmutable $periodEnd, + Employee $employee + ): ?DateTimeImmutable { + $today = new DateTimeImmutable('today'); + $currentYear = LeaveRuleCode::FORFAIT_218->value === $ruleCode + ? (int) $today->format('Y') + : $this->resolveCurrentLeaveYear($today); + + if ($year < $currentYear) { + $end = $periodEnd; + } elseif ($year > $currentYear) { + $end = null; + } else { + $lastDayPreviousMonth = $today + ->modify('first day of this month') + ->modify('-1 day') + ; + $end = $lastDayPreviousMonth < $periodEnd ? $lastDayPreviousMonth : $periodEnd; + } + + // Cap at contract end date if the employee has left. + $contractEndRaw = $employee->getCurrentContractEndDate(); + if (null !== $end && null !== $contractEndRaw && '' !== trim($contractEndRaw)) { + $contractEnd = DateTimeImmutable::createFromFormat('Y-m-d', $contractEndRaw); + if ($contractEnd instanceof DateTimeImmutable && $contractEnd < $end) { + $end = $contractEnd; + } + } + + return $end; + } + + private function resolveTakenCalculationEndDate( DateTimeImmutable $periodEnd, Employee $employee ): ?DateTimeImmutable {