# Contingent d'heures supplémentaires payées

## Objectif
Suivre, par année civile (Janv–Déc), les heures supplémentaires payées de chaque employé
non-forfait (chauffeurs inclus) face au plafond légal annuel.

## Règles
- **Heures payées** = `base25 + base50` (en minutes), hors majoration (bonus), **+ heures
  structurelles** (voir ci-dessous).
- **Plafond** : 350 h pour les chauffeurs (contrat courant `isDriver`), 220 h sinon.
- **Périmètre** : non-forfait uniquement (FORFAIT exclus, ni RTT ni heures supp payées).

## Heures supplémentaires structurelles
Les heures contractuelles **au-delà de 35h** (durée légale) sont des heures supplémentaires
payées **chaque mois**, qui ne transitent pas par les paiements RTT (la référence d'un 39h est
39h, pas 35h) mais comptent dans le contingent légal.

- Montant mensuel plein = `(weeklyHours − 35) × 52/12` h = `(weeklyHours − 35) × 260` min.
  Pour un 39h : `4 × 260 = 1040` min = **17,33 h/mois**.
- **Généralisé** à tout contrat non-forfait/non-intérim dont `weeklyHours > 35` (ex. custom
  40h → 21,67 h/mois). Contrats ≤ 35h, FORFAIT, INTERIM → 0.
- **Proratisé** au nombre de jours réellement sous contrat dans le mois (entrée/sortie en cours
  de mois). Itère les périodes de contrat (`employee.contractPeriods`), pas de requête jour/jour.
- Cœur partagé : `App\Service\WorkHours\StructuralOvertimeContingentCalculator`
  (`monthlyStructuralMinutes` / `totalStructuralMinutes`). Ajouté au total des paiements RTT
  côté provider (encart fiche) **et** export builder (PDF).

## Mapping exercice → année civile
Les paiements RTT (`EmployeeRttPayment`) sont stockés par **exercice** (`year` = Juin N-1 →
Mai N) + `month` (1–12). L'année civile d'un paiement :

    annéeCivile = month >= 6 ? exerciseYear - 1 : exerciseYear

Donc l'année civile **Y** agrège : exercice `Y` (mois 1–5) + exercice `Y+1` (mois 6–12).

## Implémentation
- Cœur partagé : `App\Service\WorkHours\OvertimePaidContingentCalculator` (pur).
- Repo : `EmployeeRttPaymentRepository::findByEmployeesAndYears`.
- Fiche employé : `GET /employees/{id}/overtime-contingent?year=YYYY` → encart header
  (`Total H.payés {année} : X h / plafond h`, rouge si dépassement, année civile courante).
- Export PDF : `GET /overtime-contingent/print?year=&siteIds=` (`ROLE_USER`, périmètre
  `findScoped`), groupé par site (`displayOrder`), tri `displayOrder → nom → prénom`,
  colonnes Janv–Déc + colonne `Total payé / payable`. Builder
  `OvertimeContingentExportBuilder`, template `overtime-contingent/print.html.twig`.

## Hors périmètre / connu
- Bug latent récap salaire : `SalaryRecapPrintProvider` requête `findByYearAndMonth` avec
  l'année civile alors que le stockage est par exercice (mauvais rattachement des paiements
  des mois Juin–Déc sur le récap mensuel). À corriger séparément.
