From 0e5661bb7fb3c163225e40cc077d5dae587cc9d3 Mon Sep 17 00:00:00 2001 From: tristan Date: Wed, 20 May 2026 16:29:38 +0200 Subject: [PATCH] docs(leave) : document forfait mid-year entry leave calculation Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 1 + doc/contract-phase-view.md | 15 +++++++++++++++ frontend/data/documentation-content.ts | 2 ++ 3 files changed, 18 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 3861801..664bce8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -90,6 +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. + - **Entrée FORFAIT en cours d'année** (année d'entrée only) : l'exercice d'entrée crédite `repos_proratisés + CP_reportés` au lieu de `max(0, businessDays−218)`=0. Repos année = `jours_ouvrés_année − 218 − 25`, proratisés par jours ouvrés. CP reportés = solde de la phase non-forfait précédente (jours ouvrés nets + samedis bruts ; un samedi posé ne réduit PAS le report ; fractionnés exclus). Nouvel embauché = repos seuls. Années pleines suivantes + forfait démarrant le 01/01 = calcul 218 inchangé (→34). Services : `EmployeeLeaveSummaryProvider::{resolveLeavePolicy (branche FORFAIT), isForfaitEntryYear, computeProratedForfaitRepoDays, resolveCarriedCpFromPriorPhase}`. Témoin Grégory : ≈13. - 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. diff --git a/doc/contract-phase-view.md b/doc/contract-phase-view.md index 0d5f879..d5c49c0 100644 --- a/doc/contract-phase-view.md +++ b/doc/contract-phase-view.md @@ -59,6 +59,21 @@ Le cumul 218 jours est **par année civile**. Toute consultation FORFAIT cape : Ex. switch 39h → FORFAIT au 01/05/2026, vue FORFAIT année 2026 → période = [01/05/2026, 31/12/2026]. +#### Entrée en FORFAIT en cours d'année civile + +L'**année d'entrée** (période partielle, ex. 01/05 → 31/12) ne calcule pas `max(0, businessDays − 218)` (qui donnerait 0) mais : + + jours_repos_année = jours_ouvrés_année − 218 − 25 + jours_repos_proratisés = jours_repos_année × (jours_ouvrés_période / jours_ouvrés_année) + congés_à_poser = jours_repos_proratisés + CP_reportés_phase_précédente + +- jours ouvrés = Lun-Ven − fériés en semaine (liste brute, incl. Pentecôte) ; prorata par jours ouvrés. +- `CP_reportés` = solde de la phase non-forfait précédente : jours ouvrés **nets** (acquis + en cours − jours ouvrés posés) + samedis **bruts**. Un **samedi déjà posé ne réduit pas** le report (seuls les jours ouvrés posés le réduisent — règle comptable). Jours fractionnés exclus. Nouvel embauché forfait (pas de phase précédente) → 0, donc repos proratisés seuls. +- Périmètre : **uniquement l'année d'entrée**. Les années pleines suivantes et les forfaits démarrant un 1er janvier gardent le calcul 218 (→ 34). +- Détection : `EmployeeLeaveSummaryProvider::isForfaitEntryYear` ; calcul : `computeProratedForfaitRepoDays` + `resolveCarriedCpFromPriorPhase`. + +Exemple Grégory BARRIBAULT (forfait 01/05/2026 après 39h, exercice 2026) : `6 repos + ~7 CP = ≈ 13 jours`. + ### Phase non-forfait (35h / 39h / CUSTOM / INTERIM) L'exercice CP est **annuel** (Juin N-1 → Mai N) et continu à travers les changements d'heures contractuelles dans le même régime non-forfait. La cap **n'applique pas** sur `from` : diff --git a/frontend/data/documentation-content.ts b/frontend/data/documentation-content.ts index f57f686..69b2bc8 100644 --- a/frontend/data/documentation-content.ts +++ b/frontend/data/documentation-content.ts @@ -439,6 +439,8 @@ export const documentationSections: DocSection[] = [ blocks: [ { type: 'paragraph', content: 'Pour les contrats forfait, l\'exercice suit l\'année civile (1er janvier au 31 décembre).' }, { type: 'list', content: 'Calcul : jours ouvrés de l\'année − 218 + bonus weekend/férié\nBonus : 1 jour par jour travaillé un weekend ou jour férié (0.5 si demi-journée)\nPas de samedis\nPas de jours en cours d\'acquisition' }, + { type: 'paragraph', content: 'Lorsqu\'un salarié passe en forfait en cours d\'année (ex. après une phase 39h), ses congés à poser pour cette année-là correspondent à ses jours de repos forfait calculés au prorata de la période, augmentés du reliquat de congés payés acquis sous son contrat précédent. Un nouveau salarié embauché directement en forfait en cours d\'année n\'a que les jours de repos proratisés. Les années complètes suivantes suivent le calcul forfait habituel.' }, + { type: 'note', content: 'Le reliquat CP de la phase précédente inclut les jours ouvrés nets (acquis + en cours − jours ouvrés posés) et les samedis bruts (les samedis déjà posés ne réduisent pas le report). Les jours fractionnés sont exclus.' }, ], }, {