Files
SIRH/docs/superpowers/plans/2026-05-26-exercice-suivant-conges-rtt.md
T
tristan cf2e12c8ba
Auto Tag Develop / tag (push) Successful in 9s
[#SIRH-32] Ajouter l'exercice 2026/2027 dans les congés/RTT (#20)
| 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>
2026-05-26 14:09:02 +00:00

268 lines
13 KiB
Markdown

# Exercice suivant dans les sélecteurs Congés et RTT — Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Faire apparaître toujours l'exercice **suivant** (exercice courant + 1) dans les sélecteurs d'exercice des onglets Congés et RTT de la fiche employé, pour une phase de contrat ouverte.
**Architecture :** Changement **frontend uniquement**. Le backend calcule déjà l'exercice suivant pour une phase ouverte (`clampYearToPhase` ne plafonne pas vers le haut quand `phase.endDate` est nul). On déplace la borne haute (`maxYear`) des deux `computed` `availableLeaveYears` / `availableRttYears` de « exercice courant » à « exercice courant + 1 » lorsque la phase est ouverte ; la borne reste l'exercice de fin de phase pour une phase clôturée. La borne basse, la sélection par défaut (exercice courant) et le verrouillage des éditions (`isHistoricalYear`) sont inchangés.
**Tech Stack :** Nuxt 4 / Vue 3 / TypeScript (composables). Backend Symfony inchangé (les tests PHPUnit doivent rester verts). Pas de harnais de test frontend dans le projet → vérification manuelle via `make dev-nuxt`.
**Référence spec :** `docs/superpowers/specs/2026-05-26-exercice-suivant-conges-rtt-design.md`
---
## File Structure
- `frontend/composables/useEmployeeLeave.ts` — borne haute du sélecteur Congés (`availableLeaveYears`).
- `frontend/composables/useEmployeeRtt.ts` — borne haute du sélecteur RTT (`availableRttYears`).
- `doc/leave-tab.md` — doc fonctionnelle, section « Sélecteur d'année ».
- `doc/rtt-tab.md` — doc fonctionnelle, section « Sélecteur d'année ».
- `CLAUDE.md` — bullets « Sélecteur d'année » des sections Congés et RTT.
- `frontend/data/documentation-content.ts` — documentation in-app (2 paragraphes).
Aucun fichier créé ; 6 fichiers modifiés.
---
### Task 1 : Borne haute = exercice suivant sur les deux composables
**Files:**
- Modify: `frontend/composables/useEmployeeLeave.ts` (computed `availableLeaveYears`)
- Modify: `frontend/composables/useEmployeeRtt.ts` (computed `availableRttYears`)
- [ ] **Step 1 : Modifier `availableLeaveYears` dans `useEmployeeLeave.ts`**
Remplacer ce bloc (déclaration de `phaseEndYear`) :
```ts
// Plage = exercices intersectant la phase.
const phaseStartYear = computeLeaveYearForDate(new Date(`${phase.startDate}T00:00:00`))
const phaseEndYear = phase.endDate
? computeLeaveYearForDate(new Date(`${phase.endDate}T00:00:00`))
: currentLeaveYear.value
```
par :
```ts
// Plage = exercices intersectant la phase.
const phaseStartYear = computeLeaveYearForDate(new Date(`${phase.startDate}T00:00:00`))
// Borne haute : fin de phase si clôturée ; sinon l'exercice SUIVANT (courant + 1),
// pour pouvoir consulter en avance les congés posés sur l'exercice à venir.
const maxYear = phase.endDate
? computeLeaveYearForDate(new Date(`${phase.endDate}T00:00:00`))
: currentLeaveYear.value + 1
```
Puis, plus bas, supprimer la ligne devenue redondante en remplaçant :
```ts
const minYear = dataFloor !== null ? Math.max(phaseStartYear, dataFloor) : phaseStartYear
const maxYear = phaseEndYear
```
par :
```ts
const minYear = dataFloor !== null ? Math.max(phaseStartYear, dataFloor) : phaseStartYear
```
(La variable `maxYear` est désormais déclarée plus haut ; la boucle `for (let y = maxYear; ...)` qui suit est inchangée.)
- [ ] **Step 2 : Modifier `availableRttYears` dans `useEmployeeRtt.ts`**
Remplacer ce bloc :
```ts
// Plage = exercices intersectant la phase.
const phaseStartYear = computeRttYearForDate(new Date(`${phase.startDate}T00:00:00`))
const phaseEndYear = phase.endDate
? computeRttYearForDate(new Date(`${phase.endDate}T00:00:00`))
: currentRttYear.value
```
par :
```ts
// Plage = exercices intersectant la phase.
const phaseStartYear = computeRttYearForDate(new Date(`${phase.startDate}T00:00:00`))
// Borne haute : fin de phase si clôturée ; sinon l'exercice SUIVANT (courant + 1),
// pour rester cohérent avec le sélecteur de l'onglet Congés.
const maxYear = phase.endDate
? computeRttYearForDate(new Date(`${phase.endDate}T00:00:00`))
: currentRttYear.value + 1
```
Puis remplacer :
```ts
const minYear = dataFloor !== null ? Math.max(phaseStartYear, dataFloor) : phaseStartYear
const maxYear = phaseEndYear
```
par :
```ts
const minYear = dataFloor !== null ? Math.max(phaseStartYear, dataFloor) : phaseStartYear
```
- [ ] **Step 3 : Vérifier qu'il ne reste aucune référence à `phaseEndYear`**
Run: `grep -rn "phaseEndYear" frontend/composables/`
Expected: aucune sortie (la variable a été supprimée des deux fichiers).
- [ ] **Step 4 : Vérification manuelle dans le dev server**
Run: `make dev-nuxt` puis, dans le navigateur, ouvrir la fiche d'un employé **non-forfait avec phase courante ouverte**.
Attendu :
- Onglet **Congés** → le menu déroulant en pied de calendrier propose l'exercice **suivant** en première position (ex. aujourd'hui exercice `Juin 2025 → Mai 2026` → l'option `Juin 2026 → Mai 2027` est présente), et l'onglet s'ouvre **par défaut** sur l'exercice courant.
- Onglet **RTT** → idem, l'exercice suivant est proposé.
- Sélectionner l'exercice suivant : les boutons **Jours fractionnés** / **Année N-1 payés** (Congés) et **+ Payer les RTT** (RTT) sont **désactivés** (car `isHistoricalYear` = vrai), et aucun bandeau « Vous consultez l'historique » n'apparaît (ce bandeau dépend de la phase, pas de l'année).
- Ouvrir la fiche d'un employé ayant une **phase clôturée** (sélecteur « Vue contrat ») : le sélecteur d'exercice de cette phase **ne propose pas** d'exercice au-delà de la fin de phase (comportement inchangé).
- [ ] **Step 5 : Commit**
```bash
git add frontend/composables/useEmployeeLeave.ts frontend/composables/useEmployeeRtt.ts
git commit -m "feat : proposer l'exercice suivant dans les sélecteurs Congés et RTT
Sur une phase de contrat ouverte, la borne haute des sélecteurs d'exercice
(availableLeaveYears / availableRttYears) passe de l'exercice courant à
l'exercice suivant (courant + 1), pour consulter en avance les congés/RTT
posés sur l'exercice à venir. Phase clôturée : borne inchangée (fin de phase).
Sélection par défaut et verrouillage des éditions inchangés.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"
```
(Le hook pre-commit lance PHPUnit ; les 151 tests doivent rester verts — aucun changement backend.)
---
### Task 2 : Mettre à jour la documentation
**Files:**
- Modify: `doc/leave-tab.md` (section « Sélecteur d'année »)
- Modify: `doc/rtt-tab.md` (section « Sélecteur d'année »)
- Modify: `CLAUDE.md` (bullets sélecteur Congés et RTT)
- Modify: `frontend/data/documentation-content.ts` (2 paragraphes)
- [ ] **Step 1 : `doc/leave-tab.md`**
Dans la section « ## Sélecteur d'année » (vers la ligne 26 « Plage proposée : »), remplacer la première puce :
```markdown
- du plus récent (= exercice courant) au plus ancien ;
```
> Remarque : si cette puce n'existe pas telle quelle dans ce fichier, ajouter à la place, juste après la ligne `Plage proposée :`, la puce ci-dessous.
par :
```markdown
- du plus récent au plus ancien. La borne haute est l'exercice **suivant** (exercice courant + 1) lorsque la phase de contrat est ouverte, afin de consulter en avance les congés posés sur l'exercice à venir ; pour une phase clôturée, la borne haute reste l'exercice de fin de phase ;
```
- [ ] **Step 2 : `doc/rtt-tab.md`**
Dans la section « ## Sélecteur d'année », remplacer la puce (ligne 24) :
```markdown
- du plus récent (= exercice courant) au plus ancien ;
```
par :
```markdown
- du plus récent au plus ancien. La borne haute est l'exercice **suivant** (exercice courant + 1) sur une phase ouverte (cohérent avec l'onglet Congés) ; pour une phase clôturée, elle reste l'exercice de fin de phase ;
```
- [ ] **Step 3 : `CLAUDE.md` — section Onglet Congés (ligne 76)**
Remplacer le segment :
```
Plage : de l'exercice courant jusqu'à `max(floor_contrat, floor_data_start_date)`
```
par :
```
Plage : de l'exercice **suivant** (exercice courant + 1 sur une phase ouverte ; exercice de fin de phase si clôturée) jusqu'à `max(floor_contrat, floor_data_start_date)`
```
- [ ] **Step 4 : `CLAUDE.md` — section Onglet RTT (ligne 83)**
Remplacer la phrase :
```
Même mécanique que l'onglet Congés (double plancher) : `max(floor_contrat, floor_rttStartDate)`.
```
par :
```
Même mécanique que l'onglet Congés : borne haute = exercice suivant (courant + 1) sur phase ouverte, double plancher `max(floor_contrat, floor_rttStartDate)`.
```
- [ ] **Step 5 : `frontend/data/documentation-content.ts` — paragraphe Congés (ligne 483)**
Remplacer le contenu du paragraphe :
```ts
{ type: 'paragraph', content: 'Un sélecteur d\'année est disponible en bas du calendrier (zone scrollable, à gauche). Il permet de consulter les exercices passés. La plage proposée part de l\'exercice courant et remonte jusqu\'au plus récent entre (a) le premier exercice où l\'employé avait un contrat ouvert et (b) l\'exercice de mise en service du logiciel — il est inutile de remonter plus loin, aucune donnée n\'a été saisie avant.' },
```
par :
```ts
{ type: 'paragraph', content: 'Un sélecteur d\'année est disponible en bas du calendrier (zone scrollable, à gauche). Il permet de consulter l\'exercice suivant ainsi que les exercices passés. La plage proposée part de l\'exercice suivant (l\'exercice à venir, pour consulter en avance les congés déjà posés) et remonte jusqu\'au plus récent entre (a) le premier exercice où l\'employé avait un contrat ouvert et (b) l\'exercice de mise en service du logiciel — il est inutile de remonter plus loin, aucune donnée n\'a été saisie avant.' },
```
- [ ] **Step 6 : `frontend/data/documentation-content.ts` — paragraphe RTT (ligne 539)**
Remplacer le contenu du paragraphe :
```ts
{ type: 'paragraph', content: 'Un sélecteur d\'exercice est disponible en bas du tableau RTT (zone scrollable, à gauche). Il permet de consulter les exercices passés (Juin → Mai). La plage proposée part de l\'exercice courant et remonte jusqu\'au plus récent entre (a) le premier exercice où l\'employé avait un contrat ouvert et (b) l\'exercice de mise en service du logiciel.' },
```
par :
```ts
{ type: 'paragraph', content: 'Un sélecteur d\'exercice est disponible en bas du tableau RTT (zone scrollable, à gauche). Il permet de consulter l\'exercice suivant ainsi que les exercices passés (Juin → Mai). La plage proposée part de l\'exercice suivant et remonte jusqu\'au plus récent entre (a) le premier exercice où l\'employé avait un contrat ouvert et (b) l\'exercice de mise en service du logiciel.' },
```
- [ ] **Step 7 : Vérifier la cohérence des chaînes éditées**
Run: `grep -n "exercice suivant" frontend/data/documentation-content.ts doc/leave-tab.md doc/rtt-tab.md CLAUDE.md`
Expected: les 6 emplacements modifiés ci-dessus apparaissent (2 dans documentation-content.ts, 1 dans chaque doc, 2 dans CLAUDE.md).
- [ ] **Step 8 : Commit**
```bash
git add doc/leave-tab.md doc/rtt-tab.md CLAUDE.md frontend/data/documentation-content.ts
git commit -m "docs : sélecteurs Congés/RTT proposent l'exercice suivant
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"
```
---
## Self-Review
**1. Couverture de la spec :**
- « Borne haute = exercice courant + 1 sur phase ouverte, fin de phase si clôturée » → Task 1, Steps 1-2. ✓
- « Forfait (année civile) et non-forfait » → le `+1` porte sur le numéro d'exercice produit par `computeLeaveYearForDate`/`computeRttYearForDate`, donc valable pour les deux règles. ✓
- « Sélection par défaut inchangée » → aucun changement à `initSelected*Year` ; vérifié en Step 4. ✓
- « Verrouillage des éditions / pas de bandeau passé » → aucun changement à `isHistoricalYear` ; vérifié en Step 4. ✓
- « Périmètre Congés + RTT » → Task 1 touche les deux composables. ✓
- « Docs : leave-tab.md, rtt-tab.md, CLAUDE.md, documentation-content.ts » → Task 2. ✓
- « Tests backend restent verts » → hook pre-commit, Task 1 Step 5. ✓
**2. Placeholders :** aucun « TBD/TODO » ; tout le code et toutes les chaînes sont fournis. La Step 1 de Task 2 prévoit le cas où l'ancre exacte diffère (instruction de repli explicite).
**3. Cohérence des types/noms :** la variable `maxYear` est désormais déclarée en amont dans les deux composables ; la ligne `const maxYear = phaseEndYear` est supprimée ; `phaseEndYear` n'existe plus (vérifié Step 3). La boucle `for (let y = maxYear; y >= minYear; ...)` reste valide.