# 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
<?php

declare(strict_types=1);

namespace App\Command;

use App\Entity\Employee;
use App\State\EmployeeLeaveSummaryProvider;
use Doctrine\ORM\EntityManagerInterface;
use ReflectionMethod;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

#[AsCommand(name: 'app:tmp-verify-accruing')]
final class TmpVerifyAccruingCommand extends Command
{
    public function __construct(
        private readonly EntityManagerInterface $em,
        private readonly EmployeeLeaveSummaryProvider $provider,
    ) {
        parent::__construct();
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $m = new ReflectionMethod(EmployeeLeaveSummaryProvider::class, 'computeYearSummary');
        foreach ($this->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) <noreply@anthropic.com>"
```

---

### 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
            <p class="col-start-4 p-[10px] border-b border-primary-500"><strong class="uppercase font-semibold">En cours d'acquisition :</strong>
                {{ formatCount(summary?.accruingDays) }} Jours
            </p>
```

par :

```vue
            <p class="col-start-4 p-[10px] border-b border-primary-500"><strong class="uppercase font-semibold">En cours d'acquisition :</strong>
                <template v-if="!isForfaitRule">{{ formatCount(summary?.accruingDays) }} / {{ formatCount(summary?.accruingDaysTotal) }} Jours</template>
                <template v-else>{{ formatCount(summary?.accruingDays) }} Jours</template>
            </p>
```

- [ ] **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) <noreply@anthropic.com>"
```

---

### 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) <noreply@anthropic.com>"
```

---

## 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`).
