From 2b699b333b342343fdc491e4aac543952380c498 Mon Sep 17 00:00:00 2001 From: tristan Date: Tue, 26 May 2026 15:50:33 +0200 Subject: [PATCH] =?UTF-8?q?docs=20:=20plan=20d'impl=C3=A9mentation=20en-co?= =?UTF-8?q?urs=20d'acquisition=20net/brut=20(SIRH-32)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- ...026-05-26-en-cours-acquisition-net-brut.md | 321 ++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 docs/superpowers/plans/2026-05-26-en-cours-acquisition-net-brut.md diff --git a/docs/superpowers/plans/2026-05-26-en-cours-acquisition-net-brut.md b/docs/superpowers/plans/2026-05-26-en-cours-acquisition-net-brut.md new file mode 100644 index 0000000..c4c7629 --- /dev/null +++ b/docs/superpowers/plans/2026-05-26-en-cours-acquisition-net-brut.md @@ -0,0 +1,321 @@ +# En-cours d'acquisition « net / brut » — 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:** Sur l'onglet Congés de la fiche employé, afficher l'en-cours d'acquisition au format `{net} / {brut généré à ce jour}` pour les non-forfait, afin que la RH voie le total acquis même quand des congés ont été pris en anticipé. + +**Architecture :** Exposition d'une valeur **déjà calculée** côté backend (`generatedDays + generatedSaturdays`) via un nouveau champ `accruingDaysTotal` sur `EmployeeLeaveSummary`, puis affichage en fraction côté Nuxt. Aucune nouvelle règle métier ; `accruingDays` (net) reste le numérateur inchangé. + +**Tech Stack :** Backend Symfony / API Platform (State Provider + ApiResource DTO). Frontend Nuxt 4 / Vue 3 / TypeScript. Tests : PHPUnit (backend) ; pas de harnais frontend → vérification manuelle. + +**Référence spec :** `docs/superpowers/specs/2026-05-26-en-cours-acquisition-net-brut-design.md` + +--- + +## File Structure + +- `src/State/EmployeeLeaveSummaryProvider.php` — calcule `accruingDaysTotal` dans `computeYearSummary` et le recopie sur le DTO. +- `src/ApiResource/EmployeeLeaveSummary.php` — nouvelle propriété exposée `accruingDaysTotal`. +- `frontend/services/dto/employee-leave-summary.ts` — champ TS `accruingDaysTotal`. +- `frontend/components/employees/LeaveTab.vue` — affichage `net / brut` (non-forfait). +- `doc/leave-tab.md` + `frontend/data/documentation-content.ts` — documentation. + +Aucun fichier créé ; 6 fichiers modifiés. + +--- + +### Task 1 : Backend — exposer `accruingDaysTotal` + +**Files:** +- Modify: `src/State/EmployeeLeaveSummaryProvider.php` +- Modify: `src/ApiResource/EmployeeLeaveSummary.php` + +- [ ] **Step 1 : Calculer `accruingDaysTotal` dans les deux branches de `computeYearSummary`** + +Dans `src/State/EmployeeLeaveSummaryProvider.php`, branche non-forfait, remplacer : + +```php + $acquiredDays = $carryDays; + $accruingDays = $remainingGenerated + $remainingGeneratedSaturdays; +``` + +par : + +```php + $acquiredDays = $carryDays; + $accruingDays = $remainingGenerated + $remainingGeneratedSaturdays; + // Brut généré à ce jour, AVANT imputation des congés pris en anticipé + // (dénominateur de l'affichage « net / brut » sur l'onglet Congés). + $accruingDaysTotal = $generatedDays + $generatedSaturdays; +``` + +Puis, branche forfait, remplacer : + +```php + $acquiredDays = $leavePolicy['acquiredDays']; + $accruingDays = 0.0; +``` + +par : + +```php + $acquiredDays = $leavePolicy['acquiredDays']; + $accruingDays = 0.0; + $accruingDaysTotal = 0.0; +``` + +- [ ] **Step 2 : Ajouter la clé au tableau `targetSummary`** + +Toujours dans `computeYearSummary`, remplacer : + +```php + 'accruingDays' => $accruingDays, +``` + +par : + +```php + 'accruingDays' => $accruingDays, + 'accruingDaysTotal' => $accruingDaysTotal, +``` + +- [ ] **Step 3 : Déclarer la clé dans le PHPDoc de retour** + +Dans le bloc `@return null|array{ ... }` de `computeYearSummary`, remplacer : + +```php + * accruingDays: float, +``` + +par : + +```php + * accruingDays: float, + * accruingDaysTotal: float, +``` + +- [ ] **Step 4 : Recopier la valeur sur le DTO dans `provide()`** + +Remplacer : + +```php + $summary->accruingDays = $yearSummary['accruingDays']; +``` + +par : + +```php + $summary->accruingDays = $yearSummary['accruingDays']; + $summary->accruingDaysTotal = $yearSummary['accruingDaysTotal']; +``` + +- [ ] **Step 5 : Ajouter la propriété sur l'ApiResource** + +Dans `src/ApiResource/EmployeeLeaveSummary.php`, remplacer : + +```php + public float $accruingDays = 0.0; +``` + +par : + +```php + public float $accruingDays = 0.0; + /** Brut généré sur l'exercice à ce jour (= accruingDays + congés pris en anticipé). Dénominateur de l'affichage « net / brut ». */ + public float $accruingDaysTotal = 0.0; +``` + +- [ ] **Step 6 : Lancer la suite PHPUnit (non-régression)** + +Run: `docker exec -t -u www-data php-sirh-fpm php vendor/bin/phpunit` +Expected: `OK (151 tests, ...)` — vert. (Le champ est une exposition pure ; aucun test existant ne doit casser. Le service n'est pas unit-testable en isolation à cause des dépôts `final`, cf. note spec.) + +- [ ] **Step 7 : Vérification sur données réelles (jetable, non commitée)** + +Créer `src/Command/TmpVerifyAccruingCommand.php` : + +```php +em->getRepository(Employee::class)->findAll() as $e) { + $s = $m->invoke($this->provider, $e, 2026, 0.0, null, null); + if (null === $s || 'CDI_CDD_NON_FORFAIT' !== $s['ruleCode']) { + continue; + } + $output->writeln(sprintf( + '#%d %s : en-cours net=%.2f / brut=%.2f', + $e->getId(), + $e->getLastName(), + $s['accruingDays'], + $s['accruingDaysTotal'], + )); + } + + return Command::SUCCESS; + } +} +``` + +Run: `docker exec -t php-sirh-fpm php /var/www/html/bin/console app:tmp-verify-accruing --env=dev` +Expected: chaque ligne affiche `net=… / brut=…` avec `net ≤ brut`. Pour un salarié sans congé anticipé, `net == brut` ; pour un salarié ayant débordé, `net < brut`. + +Puis supprimer le fichier : + +```bash +rm src/Command/TmpVerifyAccruingCommand.php +``` + +- [ ] **Step 8 : Commit** + +```bash +git add src/State/EmployeeLeaveSummaryProvider.php src/ApiResource/EmployeeLeaveSummary.php +git commit -m "feat : exposer accruingDaysTotal (brut généré) sur le récap congés + +Co-Authored-By: Claude Opus 4.7 (1M context) " +``` + +--- + +### Task 2 : Frontend — afficher « net / brut » + +**Files:** +- Modify: `frontend/services/dto/employee-leave-summary.ts` +- Modify: `frontend/components/employees/LeaveTab.vue` + +- [ ] **Step 1 : Ajouter le champ au DTO TypeScript** + +Dans `frontend/services/dto/employee-leave-summary.ts`, remplacer : + +```ts + accruingDays: number +``` + +par : + +```ts + accruingDays: number + accruingDaysTotal: number +``` + +- [ ] **Step 2 : Afficher la fraction dans la case « En cours d'acquisition »** + +Dans `frontend/components/employees/LeaveTab.vue`, remplacer : + +```vue +

En cours d'acquisition : + {{ formatCount(summary?.accruingDays) }} Jours +

+``` + +par : + +```vue +

En cours d'acquisition : + + +

+``` + +- [ ] **Step 3 : Vérification manuelle (dev server)** + +Run: `make dev-nuxt` puis ouvrir la fiche d'un employé **non-forfait**. +Attendu : +- La case « En cours d'acquisition » affiche deux nombres séparés par `/` (ex. `14,50 / 17,50` ou `17,50 / 17,50` si aucun congé anticipé). +- Sur un employé **forfait**, la case affiche un seul nombre (`0`), inchangé. + +(Ne pas lancer `npm run build`.) + +- [ ] **Step 4 : Commit** + +```bash +git add frontend/services/dto/employee-leave-summary.ts frontend/components/employees/LeaveTab.vue +git commit -m "feat : afficher l'en-cours d'acquisition au format net / brut (onglet Congés) + +Co-Authored-By: Claude Opus 4.7 (1M context) " +``` + +--- + +### Task 3 : Documentation + +**Files:** +- Modify: `doc/leave-tab.md` +- Modify: `frontend/data/documentation-content.ts` + +- [ ] **Step 1 : `doc/leave-tab.md`** + +Repérer la section décrivant les compteurs du header (recherche : `grep -n "acquisition\|En cours\|compteur" doc/leave-tab.md`). Ajouter (ou compléter la puce correspondante) avec ce texte : + +```markdown +- **En cours d'acquisition** (non-forfait) : affiché au format `net / brut`. + - `net` (`accruingDays`) : généré de l'exercice restant, déduit des congés posés en anticipé (au-delà du report acquis). + - `brut` (`accruingDaysTotal` = `generatedDays + generatedSaturdays`) : total généré sur l'exercice à ce jour, avant cette déduction. + - La RH voit ainsi le total réellement acquis même si une partie a déjà été consommée en anticipé. Forfait : pas d'en-cours (affiche `0`, sans fraction). +``` + +- [ ] **Step 2 : `frontend/data/documentation-content.ts`** + +Repérer le paragraphe de l'article « Onglet Congés » décrivant les compteurs (recherche : `grep -n "en cours d.acquisition\|En cours\|acquis" frontend/data/documentation-content.ts`). Ajouter un bloc `note` dans le tableau `blocks` de cet article : + +```ts + { type: 'note', content: 'La case « En cours d\'acquisition » affiche deux valeurs : à gauche les jours encore à acquérir (déduction faite des congés déjà posés en anticipé), à droite le total brut acquis sur l\'exercice à ce jour. Exemple : « 14,50 / 17,50 » signifie 17,50 jours acquis dont 3 déjà pris en anticipé.' }, +``` + +> Insérer ce bloc juste après le paragraphe qui présente les compteurs de l'exercice de congés (celui mentionnant l'exercice Juin→Mai / les jours acquis). Respecter l'indentation existante (10 espaces) et l'échappement des apostrophes (`\'`). + +- [ ] **Step 3 : Vérifier la cohérence** + +Run: `grep -rn "accruingDaysTotal\|net / brut\|14,50 / 17,50" doc/leave-tab.md frontend/data/documentation-content.ts` +Expected : la doc fonctionnelle mentionne le format `net / brut` et la doc in-app contient la note d'exemple. + +- [ ] **Step 4 : Commit** + +```bash +git add doc/leave-tab.md frontend/data/documentation-content.ts +git commit -m "docs : en-cours d'acquisition affiché net / brut sur l'onglet Congés + +Co-Authored-By: Claude Opus 4.7 (1M context) " +``` + +--- + +## Self-Review + +**1. Couverture de la spec :** +- Nouveau champ `accruingDaysTotal` = `generatedDays + generatedSaturdays` (non-forfait), `0` (forfait) → Task 1 Steps 1-2. ✓ +- Exposition DTO PHP + recopie provider → Task 1 Steps 3-5. ✓ +- DTO TS → Task 2 Step 1. ✓ +- Affichage `net / brut` non-forfait, inchangé forfait → Task 2 Step 2. ✓ +- Docs `doc/leave-tab.md` + in-app → Task 3. ✓ +- Invariant `accruingDays ≤ accruingDaysTotal` → vérifié en Task 1 Step 7. ✓ +- Hors périmètre (RTT, récap, header) → aucun fichier de ces zones touché. ✓ + +**2. Placeholders :** aucun « TBD/TODO » ; tout le code est fourni. Les Steps 1-2 de Task 3 demandent un `grep` pour localiser l'ancre exacte (le texte à insérer est fourni intégralement) car la position dans `documentation-content.ts` dépend de l'article ; c'est une instruction d'insertion, pas un placeholder de contenu. + +**3. Cohérence des types/noms :** `accruingDaysTotal` (float PHP / number TS) utilisé identiquement dans le provider, le tableau `targetSummary`, le PHPDoc, l'ApiResource, le DTO TS et le template. `accruingDays` (numérateur) reste inchangé. La variable `$accruingDaysTotal` est définie dans les deux branches avant la construction de `targetSummary` (comme `$accruingDays`).