# Rollover Conges - Regles et Mise en Production Document de reference pour expliquer le fonctionnement metier du report N-1 et preparer le lancement en production. ## 1) Objectif Eviter les recalculs "depuis le debut du contrat" et fiabiliser les soldes. Principe: - le solde est stocké par exercice - au changement d'exercice, on ouvre la nouvelle période avec un "solde d'ouverture" (report N-1) - un indicateur de cloture (`contractPaidLeaveSettled`) permet de couper la continuité entre 2 contrats ## 2) Exercices metier - `CDI` / `CDD` non forfait: - exercice: `1er juin` au `31 mai` - `year` = annee de fin d'exercice (ex: `2026` = 01/06/2025 -> 31/05/2026) - `FORFAIT`: - exercice: `1er janvier` au `31 decembre` - `year` = annee civile - `INTERIM`: - hors perimetre conges ## 3) Logique de compteurs - `acquis`: - correspond au report N-1 (solde d'ouverture) - `en cours d'acquisition`: - correspond aux droits generes sur l'exercice en cours - `pris`: - non forfait: absences type `C` (conge) - forfait: toutes absences - `restant`: - `acquis + en_cours - pris` (borne a 0 dans l'affichage) ## 4) Effet du "solde de tout compte" Le champ de cloture `contractPaidLeaveSettled` est saisi lors de la fermeture d'une periode contrat. - `false`: - continuite des droits entre contrats - `true`: - pas de reprise des droits precedents - reset de continuite au lendemain de la date de cloture ## 5) Table cible Table `employee_leave_balances` (une ligne par employe et exercice): - `employee_id` - `rule_code` (`CDI_CDD_NON_FORFAIT` ou `FORFAIT_218`) - `year` - `opening_days` - `opening_saturdays` - `accrued_days` - `accrued_saturdays` (optionnel selon implementation) - `taken_days` - `taken_saturdays` - `closing_days` - `closing_saturdays` - `is_locked` - `created_at`, `updated_at` Contrainte unique recommandee: - `(employee_id, rule_code, year)` Etat implementation: - la table est creee - le calcul de synthese conges lit en priorite `opening_days/opening_saturdays` de cette table quand une ligne existe pour `(employee, rule_code, year)` - si aucune ligne n'existe, le calcul reste base sur le report dynamique N-1 - la commande `app:leave:rollover` calcule aussi le report dynamique N-1 si la ligne N-1 n'est pas encore persistée (pas de reset a 0 par defaut) ### Definition des colonnes - `employee_id`: - identifiant employe (FK vers `employees`) - une ligne de solde par employe / regle / exercice - `rule_code`: - code de regle appliquee (`CDI_CDD_NON_FORFAIT`, `FORFAIT_218`) - permet de savoir quelles regles de calcul sont utilisees - `year`: - annee d'exercice - non forfait: annee de fin d'exercice (`2026` = 01/06/2025 -> 31/05/2026) - forfait: annee civile (`2026` = 01/01/2026 -> 31/12/2026) - `opening_days`: - report N-1 en jours (solde d'ouverture) - `opening_saturdays`: - report N-1 "samedis" (0 pour forfait) - `accrued_days`: - droits generes sur l'exercice courant (N) - `accrued_saturdays`: - droits samedis generes sur N (0 pour forfait) - `taken_days`: - jours poses sur l'exercice - `taken_saturdays`: - samedis poses sur l'exercice (0 pour forfait) - `closing_days`: - solde de cloture jours (`opening_days + accrued_days - taken_days`) - `closing_saturdays`: - solde de cloture samedis (`opening_saturdays + accrued_saturdays - taken_saturdays`) - `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:leave:rollover` - comportement date metier: - le `01/01`: traite uniquement `FORFAIT_218` - le `01/06`: traite uniquement `CDI_CDD_NON_FORFAIT` - les autres jours: sortie sans action - option manuelle: `--force` pour executer hors date metier (reprise/correction) Date d'effet: - forfait: au `1er janvier` - non forfait: au `1er juin` Traitement par employe: 1. lire l'exercice precedent 2. determiner le report: - si cloture `paidLeaveSettled=true` sur la periode precedente => report `0` - sinon report = `closing` exercice precedent 3. creer la ligne du nouvel exercice avec ce report en `opening_*` 4. initialiser `accrued/taken/closing` pour le nouvel exercice ## 7) Donnees a fournir au go-live La RH doit fournir un import d'ouverture: Colonnes minimales: - `employee_identifier` (id interne ou matricule) - `rule_code` - `year` - `opening_days` - `opening_saturdays` (0 pour forfait) - `source_date` (date de reference du relevé RH) - `comment` (optionnel) Format recommande: - CSV UTF-8 - separateur `;` - decimales en point (`7.5`) Exemple: ```csv employee_id;rule_code;year;opening_days;opening_saturdays;source_date;comment 42;CDI_CDD_NON_FORFAIT;2026;12.5;2;2026-05-31;Reprise fichier RH 17;FORFAIT_218;2026;8;0;2025-12-31;Reprise fichier RH ``` ## 8) Checklist mise en prod 1. Valider le mapping employe RH -> employe applicatif 2. Importer les soldes d'ouverture N-1 3. Verifier 5 cas metier: - CDI simple sans changement de contrat - CDD -> CDI avec `paidLeaveSettled=false` - CDD -> CDI avec `paidLeaveSettled=true` - Forfait sur annee complete - Forfait avec debut en cours d'annee 4. Activer le cron de rollover 5. Geler (`is_locked`) les exercices historicises valides Exemple cron (tous les jours a 02:10): Dev ```cron 10 2 * * * cd /var/www/html && php bin/console app:leave:rollover --no-interaction 2>&1 ``` Prod ```cron 10 2 * * * cd /var/www/sirh && php bin/console app:leave:rollover --no-interaction 2>&1 ``` Explication de la ligne cron: - `10 2 * * *`: planification - `10` = minute - `2` = heure - `*` = tous les jours du mois - `*` = tous les mois - `*` = tous les jours de la semaine - `cd /var/www/html`: se place dans le dossier de l application Symfony - `php bin/console app:leave:rollover --no-interaction`: execute le rollover sans demander de confirmation - hors `01/01` et `01/06`, la commande sort en no-op (normal) - `>> var/log/leave-rollover.log`: ajoute la sortie standard dans le fichier de log (sans ecraser l historique) - `2>&1`: redirige aussi les erreurs dans le meme fichier de log Execution manuelle forcee: ```bash php bin/console app:leave:rollover --force --no-interaction ``` Exemple de verification rapide: ```bash tail -n 50 /var/www/html/var/log/leave-rollover.log ``` ## 9) Points de vigilance - Ne jamais recalculer les soldes historiques apres validation RH sans procedure explicite - Garder une trace de toute correction manuelle (auteur, date, motif) - Aligner strictement les regles UI et API sur les memes compteurs (pas de formule differente front/back) ## 10) Regle de consommation des droits Regle metier: - un employe peut poser des conges en cours d'acquisition - la consommation se fait par ordre: 1. `acquis` (report N-1) 2. `en cours d'acquisition` (droits N) Effet attendu: - si `acquis = 0` et `en cours = 7.5`, puis prise de `7`, alors: - `acquis` reste `0` - `en cours` devient `0.5` - si `acquis = 0` et `en cours = 2.5`, puis prise de `3`, alors: - `acquis` reste `0` - `en cours` devient `-0.5` (dette) - le mois suivant, une acquisition de `2.5` ramené `en cours` a `2.0` Formule de lecture recommandée: - `restant_acquis = max(0, acquis - pris)` - `reste_a_imputer_sur_en_cours = max(0, pris - acquis)` - `restant_en_cours = en_cours - reste_a_imputer_sur_en_cours` (valeur negative autorisee)