Files
SIRH/doc/overtime-contingent.md
T
tristan 0a9b26d31e
Auto Tag Develop / tag (push) Successful in 6s
feat(overtime-contingent) : heures supp structurelles (>35h) ajoutées au contingent
Les heures contractuelles au-delà de 35h (ex. 39h → 17,33h décimales = 17h20/mois)
sont payées chaque mois sans transiter par les paiements RTT (référence 39h). Elles
manquaient au contingent. Ajout via StructuralOvertimeContingentCalculator :
(weeklyHours-35)×260 min/mois, généralisé aux contrats non-forfait/non-intérim >35h,
proratisé aux jours sous contrat. Branché sur l'encart fiche et l'export PDF.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 08:57:26 +02:00

2.8 KiB
Raw Blame History

Contingent d'heures supplémentaires payées

Objectif

Suivre, par année civile (JanvDé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 (112). 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 15) + exercice Y+1 (mois 612).

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 JanvDé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 JuinDéc sur le récap mensuel). À corriger séparément.