| Numéro du ticket | Titre du ticket | |------------------|-----------------| | | | ## Description de la PR ## Modification du .env ## Check list - [ ] Pas de régression - [ ] TU/TI/TF rédigée - [ ] TU/TI/TF OK - [ ] CHANGELOG modifié Reviewed-on: #27 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
6.9 KiB
Déficit RTT pris en compte pour les contrats CUSTOM (4h, etc.)
Date : 2026-06-09
Branche : feature/SIRH-36-corriger-le-calcule-des-rtt-des-contrat-4h
Contexte & problème
Les salariées avec un contrat 4h (type CUSTOM : weeklyHours ≠ 35/39, non INTERIM/FORFAIT,
mode TIME) voient, dans l'onglet RTT, des semaines travaillées en dessous de leurs heures
contractuelles afficher un déficit dans la colonne « Heure » (ex. Ewa S23 : −2h) sans aucun
effet : « Total » = 0 et « Cumul » = 0.
Cause : RttRecoveryComputationService::computeRecoveryByWeek écrête le total hebdo des CUSTOM
avec totalMinutes = max(0, $weeklyOvertimeTotalMinutes). Le déficit est donc supprimé. C'est
le comportement métier documenté jusqu'ici (« CUSTOM : le déficit n'impacte pas le solde »).
Décision métier (validée avec le client) : le déficit doit être pris en compte et réduire le cumul, comme pour les 35h/39h, avec un affichage propre dans l'onglet RTT.
Décisions validées
- Le cumul peut devenir négatif (identique aux 35h/39h, comportement déjà assumé dans le
code — cf.
RttClosingBalanceService::foldligne 98 « leftover may push the balance negative, as on screen »). Le négatif est reporté à l'exercice suivant. - Déficit visible en colonnes « Heure » + « Total » + « Cumul ». Les colonnes 25%/50% restent à 0 pour un contrat CUSTOM (un 4h n'a pas de bonus, donc pas de tranches).
Principe technique
Retirer l'écrêtage max(0, …) pour les semaines CUSTOM : le déficit (négatif) circule dans
WeekRecoveryDetail::totalMinutes et réduit le cumul. La seule spécificité CUSTOM reste :
récupération 1h = 1h, sans bonus 25/50.
Le point délicat : ne pas drainer les tranches 25/50
Pour un 35h/39h, une semaine déficitaire draine les tranches 25/50 accumulées via la cascade
de EmployeeRttSummaryProvider (lignes 149-174) et de RttClosingBalanceService::fold (lignes
92-99), ce qui affiche des valeurs négatives en « Total 25% / 50% ».
Pour un CUSTOM, la récup n'est jamais bucketisée (elle vit uniquement dans totalMinutes). La
cascade ne doit donc pas s'appliquer aux semaines CUSTOM, sinon le déficit apparaîtrait en
négatif dans « Total 25% » (affichage sale, et incohérent avec les récups positives qui, elles,
n'y figurent pas).
Solution : un drapeau isFlatRecovery (récupération plate 1:1, sans tranches) porté par la
semaine, qui désactive la cascade dans le provider.
Changements
Backend
src/Dto/Rtt/WeekRecoveryDetail.php: ajoutpublic bool $isFlatRecovery = false.src/Dto/Rtt/EmployeeRttWeekSummary.php: ajoutpublic bool $isFlatRecovery = false.src/Service/Rtt/RttRecoveryComputationService.php(computeRecoveryByWeek, branche$isCustomContract) :totalMinutes = $weeklyOvertimeTotalMinutes(signé — plus demax(0, …)).isFlatRecovery: truesur leWeekRecoveryDetailretourné.- Les buckets
base25/bonus25/base50/bonus50restent à 0 (inchangé). - Cas non-CUSTOM et PRESENCE/INTERIM inchangés (
isFlatRecoveryrestefalse).
src/State/EmployeeRttSummaryProvider.phpbuildWeekSummaries: propagerisFlatRecoveryduWeekRecoveryDetailvers l'EmployeeRttWeekSummary— dans le cas mono-mois et dans le cas semaine à cheval sur deux mois (les deux instances héritent du drapeau).- Cascade déficit (ligne 150) : condition devient
if ($week->totalMinutes >= 0 || $week->isFlatRecovery). Pour une semaine CUSTOM déficitaire, on ne draine pas : les buckets restent 0,cumulativeBalanceMinutes(déjà basé surtotalMinutes, ligne 197) intègre le déficit. - Dans la reconstruction de la branche
else(semaine déficitaire normale), conserver explicitementisFlatRecovery: $week->isFlatRecovery(toujoursfalseà ce point, mais explicite pour la clarté).
src/Command/DumpVerificationSnapshotCommand.php: ce command duplique la cascade du provider (lignes ~695-716). Mettre à jour la condition de cascade pour respecterisFlatRecovery, et propager le drapeau dans sa reconstruction des week summaries, afin que les snapshots before/after restent fidèles à l'app.
Aucun changement
src/Service/Rtt/RttClosingBalanceService.php:foldgère déjàtotalMinutesnégatif (branche déficit lignes 92-99) et le remainder CUSTOM (lignes 83-87). Le report N+1 intègre donc automatiquement le déficit. Pas de modification.frontend/components/employees/RttTab.vue: aucun. Les sous-colonnes Base/25%/50% sont déjà écrêtées à 0 sur les semaines déficitaires (totalMinutes >= 0 ? … : 0). Avec buckets = 0 côté back, « Total 25%/50% » = 0, et « Heure »/« Total »/« Cumul » affichent le déficit.- Pas de migration : aucun changement de schéma.
Effets de bord (assumés, cohérents)
- Récap congés (
LeaveRecapRowBuilder::…viacomputeTotalRecoveryForExercise) : la valeur RTT reflètera aussi les déficits et peut devenir négative. Cohérent avec la décision. - Rollover / report : la clôture d'exercice (
computeClosingBalance) intègre désormais les déficits. Les lignesemployee_rtt_balancesdéjà stockées (calculées avec l'ancienne logique, déficit = 0) doivent être rafraîchies après déploiement :php bin/console app:rtt:rollover --force --recompute(ne touche pas les lignesis_locked). Ex. Ewa : clôture 2026 passe de 0 à −2h, donc report d'ouverture 2027 = −2h. - Carry / Report row : pour un CUSTOM, le report reste stocké/affiché dans la tranche
base25(convention pré-existante dufold, remainder parking) — comportement inchangé, hors périmètre.
Tests (TDD)
tests/Service/Rtt/RttClosingBalanceServiceTest.php: nouveau cas — unWeekRecoveryDetailCUSTOM déficitaire (totalMinutesnégatif) diminue bien la clôture (somme = report + Σ semaines − payés, négatif inclus).tests/State/EmployeeRttSummaryProviderTest.php: semaine CUSTOM déficitaire (isFlatRecovery = true,totalMinutes < 0) → buckets 25/50 restent 0,cumulativeBalanceréduit du déficit (pas de drainage des tranches). Vérifier aussi qu'une semaine 35h/39h déficitaire continue de drainer (non-régression).tests/Service/Rtt/RttRecoveryComputationServiceTest.php: si réalisable en intégration — contrat CUSTOM, semaine travaillée sous les heures →totalMinutesnégatif etisFlatRecovery = true.
Documentation (obligatoire, même intervention)
doc/rtt-rollover.mdet/oudoc/rtt-tab.md: mettre à jour la règle CUSTOM (déficit désormais compté).frontend/data/documentation-content.ts: section RTT — déficit des contrats CUSTOM.CLAUDE.md: section « Overtime Rules » — corriger « deficit doesn't impact balance » pour les CUSTOM ; documenterisFlatRecovery.