From dc9b49e254447ab0f6e85642646368b664606aa8 Mon Sep 17 00:00:00 2001 From: tristan Date: Wed, 20 May 2026 16:12:34 +0200 Subject: [PATCH] feat(leave) : source carried CP from prior non-forfait phase Co-Authored-By: Claude Opus 4.7 (1M context) --- src/State/EmployeeLeaveSummaryProvider.php | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/State/EmployeeLeaveSummaryProvider.php b/src/State/EmployeeLeaveSummaryProvider.php index f7fd33e..46c633f 100644 --- a/src/State/EmployeeLeaveSummaryProvider.php +++ b/src/State/EmployeeLeaveSummaryProvider.php @@ -564,6 +564,34 @@ final readonly class EmployeeLeaveSummaryProvider implements ProviderInterface return $prior; } + /** + * CP nets encore disponibles (jours + samedis) hérités de la phase non-forfait + * précédant immédiatement une entrée en FORFAIT. 0 si aucune phase précédente + * ou si la précédente est elle-même un FORFAIT (nouvel embauché → cas 2). + * + * Le total disponible = remainingDays (acquis restant) + accruingDays (généré + * restant, samedis générés inclus) + remainingSaturdays (samedis acquis restant). + * Les congés déjà posés sous la phase précédente sont déjà déduits par + * computeYearSummary, donc on récupère bien le NET (ex. Grégory : 12 acquis − 5 pris ≈ 7). + */ + private function resolveCarriedCpFromPriorPhase(Employee $employee, ContractPhase $forfaitPhase): float + { + $prior = $this->resolvePhaseImmediatelyBefore($employee, $forfaitPhase); + if (null === $prior || ContractType::FORFAIT === $prior->contractType) { + return 0.0; + } + + $reference = $prior->endDate ?? new DateTimeImmutable('today'); + $priorYear = $this->exerciseYearResolver->forDate($reference, false); + + $summary = $this->computeYearSummary($employee, $priorYear, 0.0, null, $prior); + if (null === $summary) { + return 0.0; + } + + return $summary['remainingDays'] + $summary['accruingDays'] + $summary['remainingSaturdays']; + } + /** * @param list $suspensions * @param list $longMaladiePeriods