# Rollover RTT - Regles et Mise en Production Document de reference pour expliquer le fonctionnement metier du report RTT N-1 et preparer le lancement en production. ## 1) Objectif Permettre le report des heures supplementaires (RTT) d'un exercice a l'autre et fiabiliser les soldes. Principe: - le solde d'ouverture est stocke par exercice - au changement d'exercice, on ouvre la nouvelle periode avec un "solde d'ouverture" (report N-1) - au go-live, les soldes d'ouverture sont importes manuellement (CSV ou insertion SQL) ## 2) Exercice metier - exercice RTT: du `1er juin` au `31 mai` - `year` = annee de fin d'exercice (ex: `2026` = 01/06/2025 -> 31/05/2026) - employes eligibles: tous sauf `INTERIM` et suivi `PRESENCE` ## 3) Logique de compteurs - `report N-1`: - correspond au solde d'ouverture (`opening_minutes`) - source prioritaire: table `employee_rtt_balances` - fallback: calcul dynamique de la somme des minutes de recuperation de l'exercice precedent - `acquis N`: - somme des minutes de recuperation hebdomadaires de l'exercice en cours - calcul: `HS totales + bonus 25% + bonus 50%` par semaine - `disponible`: - `report N-1 + acquis N` - affichage du compteur global: en **jours** (1 jour = 7h = 420 minutes) ## 4) Attribution mensuelle des semaines - une semaine ISO qui chevauche deux mois est affichee dans **les deux mois**, avec les valeurs reparties proportionnellement aux minutes travaillees de chaque portion - le calcul des heures supplementaires reste hebdomadaire (seuils 35h/39h/43h appliques sur la semaine entiere), seul l'affichage est scinde - exemple: S14 lundi-mardi en mars, mercredi-dimanche en avril → la S14 apparait en mars (part lun-mar) et en avril (part mer-dim) ## 5) Table cible Table `employee_rtt_balances` (une ligne par employe et exercice): - `employee_id` - `year` - `opening_minutes` - `is_locked` - `created_at`, `updated_at` Contrainte unique: - `(employee_id, year)` Etat implementation: - la table est creee - le calcul de synthese RTT lit en priorite `opening_minutes` de cette table quand une ligne existe pour `(employee, year)` - si aucune ligne n'existe, le calcul dynamique sur l'exercice N-1 est effectue ### Definition des colonnes - `employee_id`: - identifiant employe (FK vers `employees`) - une ligne de solde par employe / exercice - `year`: - annee d'exercice (annee de fin) - `2026` = 01/06/2025 -> 31/05/2026 - `opening_minutes`: - report N-1 en minutes (solde d'ouverture) - correspond a la somme des minutes de recuperation de l'exercice precedent - `is_locked`: - `false` sur exercice ouvert (recalcul possible) - `true` apres validation RH (exercice fige) - `created_at`, `updated_at`: - trace technique creation / mise a jour ## 6) Rollover automatique Commande quotidienne (cron) idempotente. - commande Symfony: `php bin/console app:rtt:rollover` - comportement date metier: - le `01/06`: calcule et persiste le report pour chaque employe eligible - les autres jours: sortie sans action - option manuelle: `--force` pour executer hors date metier (reprise/correction) Date d'effet: - au `1er juin` (meme date que le rollover conges non forfait) Traitement par employe: 1. verifier l'eligibilite (ni INTERIM, ni suivi PRESENCE) 2. verifier qu'aucune ligne n'existe deja pour `(employee, targetYear)` (idempotence) 3. calculer la somme des minutes de recuperation de l'exercice N-1 4. creer la ligne du nouvel exercice avec ce total en `opening_minutes` ## 7) Donnees a fournir au go-live La RH doit fournir les soldes RTT a reporter. Colonnes minimales: - `employee_id` (id interne) - `year` - `opening_minutes` (total en minutes) Format recommande: - CSV UTF-8 - separateur `;` Exemple: ```csv employee_id;year;opening_minutes 42;2026;1260 17;2026;840 ``` Equivalent en insertion SQL directe: ```sql INSERT INTO employee_rtt_balances (employee_id, year, opening_minutes, is_locked, created_at, updated_at) VALUES (42, 2026, 1260, false, NOW(), NOW()), (17, 2026, 840, false, NOW(), NOW()); ``` Conversion rapide: `1260 minutes = 21h00 = 3.00 jours` (1 jour = 420 min = 7h) ## 8) Checklist mise en prod 1. Executer la migration (`employee_rtt_balances`) 2. Importer les soldes d'ouverture N-1 (CSV ou SQL) 3. Verifier 3 cas metier: - CDI 39h avec heures supp sur l'exercice precedent - CDI 35h sans heures supp (report = 0) - INTERIM (doit etre ignore, pas de ligne creee) 4. Activer le cron de rollover 5. Geler (`is_locked`) les exercices historicises valides Exemple cron (tous les jours a 02:15, juste apres le rollover conges): Dev ```cron 15 2 * * * cd /var/www/html && php bin/console app:rtt:rollover --no-interaction 2>&1 ``` Prod ```cron 10 2 * * * cd /var/www/sirh && php bin/console app:rtt:rollover --no-interaction 2>&1 ``` Explication de la ligne cron: - `15 2 * * *`: tous les jours a 02:15 - `php bin/console app:rtt:rollover --no-interaction`: execute le rollover sans confirmation - hors `01/06`, la commande sort en no-op (normal) - `>> var/log/rtt-rollover.log 2>&1`: log sortie standard et erreurs Execution manuelle forcee: ```bash php bin/console app:rtt:rollover --force --no-interaction ``` Exemple de verification rapide: ```bash tail -n 50 /var/www/html/var/log/rtt-rollover.log ``` ## 9) Points de vigilance - Ne jamais modifier `opening_minutes` apres validation RH sans procedure explicite - Garder une trace de toute correction manuelle (auteur, date, motif) - Le calcul dynamique N-1 (fallback) parcourt toutes les heures de l'exercice precedent: preferer l'import explicite pour les exercices historiques - La commande de rollover est idempotente: si une ligne existe deja, l'employe est ignore (pas d'ecrasement)