diff --git a/CLAUDE.md b/CLAUDE.md index b8d4a80..3861801 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -90,7 +90,7 @@ - Exposé via `Employee.contractPhases` (`employee:read`). Endpoints `GET /employees/{id}/leave-summary` et `GET /employees/{id}/rtt-summary` acceptent `?phaseId=N` ; défaut = phase courante. - Sélectionner une phase passée : - Onglet **Congés** : période et règles de la phase (Juin→Mai non-forfait, Jan→Déc FORFAIT). Exercice de transition capé sur `phase.endDate`. **Cap `from` au `phase.startDate` uniquement pour FORFAIT** (sémantique année civile). Pour le non-forfait, l'exercice CP reste annuel et continu à travers les changements d'heures (35h→39h, etc.) — seul `resolveEffectivePeriodStart` clampe sur la date d'entrée en contrat des nouveaux embauchés. - - Onglet **RTT** : visible ssi `phase.contractType !== FORFAIT`. `+ Payer les RTT` actif uniquement sur l'exercice contenant `phase.endDate`. + - Onglet **RTT** : visible ssi `phase.contractType !== FORFAIT`. Tableau hebdo affiché sur l'exercice complet (Juin→Mai) ; `periodFrom` non capé sur `phase.startDate` (les semaines avant embauche ou hors phase apparaissent à 0). `periodTo`/`limitDate` capés sur `phase.endDate` pour les phases clôturées. `+ Payer les RTT` actif uniquement sur l'exercice contenant `phase.endDate`. - Bandeau jaune affiché en mode phase passée. Édition d'absences et des stocks de report (jours fractionnés, Année N-1 payés) désactivée. - Sélection non persistée — chaque ouverture de fiche démarre sur la phase courante. - CP : solder via `EmployeeContractPeriod.paidLeaveSettledClosureDate` (mécanisme existant). RTT : créer un `EmployeeRttPayment` sur le dernier exercice de la phase. diff --git a/doc/contract-phase-view.md b/doc/contract-phase-view.md index 10729c2..0d5f879 100644 --- a/doc/contract-phase-view.md +++ b/doc/contract-phase-view.md @@ -39,7 +39,7 @@ Affiché quand le picker est sur une phase passée. Indique que le mode lecture | Onglet | Effet | |---|---| | Congés | Recharge avec les règles de la phase. Période Juin→Mai pour non-forfait, Jan→Déc pour FORFAIT. Exercices bornés à la phase. | -| RTT | Visible ssi `phase.contractType !== FORFAIT`. Exercices bornés à la phase. | +| RTT | Visible ssi `phase.contractType !== FORFAIT`. Le tableau affiche **toujours toutes les semaines de l'exercice** (Juin→Mai). Pour une phase clôturée, `periodTo` et `limitDate` sont capés à `phase.endDate` (les semaines après la fin de phase contribuent 0 au cumul). `periodFrom` n'est pas capé : les semaines avant l'embauche ou avant le début d'une phase passée apparaissent à 0 (pas de contrat → pas de référence → 0 minute). | | Heures, Frais, Formation, Contrat, Calendrier | Non impactés. | ## Paiements de solde sur phase passée diff --git a/src/State/EmployeeRttSummaryProvider.php b/src/State/EmployeeRttSummaryProvider.php index b670ae7..41bdfeb 100644 --- a/src/State/EmployeeRttSummaryProvider.php +++ b/src/State/EmployeeRttSummaryProvider.php @@ -75,13 +75,16 @@ final readonly class EmployeeRttSummaryProvider implements ProviderInterface $currentExerciseYear = $this->resolveCurrentExerciseYear($today); [$periodFrom, $periodTo] = $this->rttRecoveryService->resolveExerciseBounds($year); - // Cap exercise bounds to the phase boundaries. + // Cap periodTo at the phase endDate for closed phases so the RTT table does + // not extend past the date the phase ended. + // Do NOT cap periodFrom at phase.startDate: keep the full exercise + // displayed so weeks before the employee's hire (or before a past phase + // started) appear at 0, matching the previous behavior. Weeks outside the + // contract range contribute 0 minutes to the cumul naturally (no contract + // ⇒ no reference, no worked hours). if (!$phase->isCurrent && null !== $phase->endDate && $phase->endDate < $periodTo) { $periodTo = $phase->endDate; } - if ($phase->startDate > $periodFrom) { - $periodFrom = $phase->startDate; - } $weeks = $this->rttRecoveryService->buildWeeksForExercise($periodFrom, $periodTo); $weekRanges = array_map(