# Règles Fonctionnelles SIRH Ce document centralise les règles métier actuellement implémentées dans l'application. Document complementaire (rollover conges et checklist de lancement): - `doc/leave-rollover.md` ## 1) Utilisateurs et accès - `ROLE_ADMIN` - accès complet aux écrans d'administration - vue semaine des heures - validation RH des lignes d'heures - `ROLE_SELF` - accès limité à son périmètre personnel - Accès "Sites" (via `user_site_roles` avec rôle `SITE_ACCESS`) - accès au périmètre des sites autorisés - validation site des lignes d'heures ## 2) Contrats - Le profil de temps de travail est porté par `Contract`: - `trackingMode`: `TIME` ou `PRESENCE` - `weeklyHours` (ex: 35, 39, 4, etc.) - La nature RH est portée par période employé: - `CDI`, `CDD`, `INTERIM` - Historique des contrats employé: - table `employee_contract_periods` - un employé peut avoir plusieurs périodes ### Règles de période - `CDI`: - à la création d'une période: `endDate` doit être vide - en clôture d'un contrat en cours: `endDate` peut être renseignée - `CDD` / `INTERIM`: - `endDate` obligatoire - `endDate` ne peut pas être antérieure à `startDate` ## 3) Heures (vue jour) - Saisie par salarié et par date: - matin / après-midi / soir - pour `PRESENCE`: demi-journées matin/après-midi - Calculs affichés: - `Jour`, `Nuit`, `Total` - Heures de nuit: - fenêtres `00:00-06:00` et `21:00-24:00` ## 4) Absences - Les absences sont stockées par jour (découpage lors de l'écriture) - Une absence peut être: - journée complète - demi-journée `AM` ou `PM` - Colonne absence (vue jour): - affiche le libellé - fond coloré selon le type d'absence - Si plusieurs absences de couleurs différentes sur le même jour: - fallback rouge ### Effet absence sur les heures - Absence `AM`: - efface les heures du matin - Absence `PM`: - efface les heures d'après-midi et du soir - Absence journée: - efface toutes les plages horaires ### Absences "comptées comme travaillées" - Si `countAsWorkedHours = true`: - `TIME`: crédit de minutes selon contrat actif du jour - `PRESENCE`: crédit d'unités (0.5 / demi-journée) ## 5) Validations des lignes d'heures - Validation RH (`isValid`) - action admin - Validation site (`isSiteValid`) - action chef de site ### Verrouillage - Ligne validée RH: - verrouillée pour modifications heures/absences - Ligne validée site: - verrouillée pour non-admin - admin peut corriger - Toute vraie modification d'une ligne: - remet `isSiteValid = false` - remet `isValid = false` - Si aucun changement réel à l'enregistrement: - les validations existantes ne sont pas altérées ## 6) Heures supplémentaires (vue semaine) - Base de calcul: - dépend du contrat actif par jour - Tranche 25%: - contrats <= 35h: de 35h à 43h - contrats >= 39h: de 39h à 43h - Tranche 50%: - au-delà de 43h - Nature `INTERIM`: - pas de bonus 25% - pas de bonus 50% - pas de total récup ## 7) Fériés - Les jours fériés sont identifiés et affichés - Règle courante: - absences bloquées sur jour férié - saisie d'heures autorisée ## 8) Impression absences (PDF) Filtres disponibles: - période `from` / `to` - sites - nature de contrat (`CDI`, `CDD`, `INTERIM`) - temps de travail (contrats de type Forfait, 35h, 39h, etc.) Tous les filtres checkbox sont cochés par défaut à l'ouverture du drawer. ## 9) Employés - Création employé: - prénom, nom, site - type de contrat (nature RH) - temps de travail - dates début/fin (selon règles nature) - Modification employé: - uniquement prénom, nom, site - pas de modification de contrat depuis ce drawer - Détail employé: - onglet `Suivi contrat` avec affichage de l'historique des périodes de contrat - chaque ligne expose: nature (`CDI`/`CDD`/`INTERIM`), contrat/temps de travail, date de début, date de fin (ou "En cours") - action `Clôturer`: - bouton actif uniquement s'il existe un contrat en cours non déjà clôturé à la date du jour - ouvre un drawer en lecture seule (type/temps de travail/date de début) - champs saisissables: - `contractEndDate` (prérempli à aujourd'hui) - `contractPaidLeaveSettled` (checkbox "Soldé dans le solde de tout compte") - backend: en mode clôture, le flag `contractPaidLeaveSettled` est persisté sur la période clôturée - action `Ajouter`: - conserve le flux d'ajout d'un nouveau contrat via drawer dédié - disponible uniquement s'il n'y a pas de contrat en cours, ou si le contrat en cours a déjà une date de fin - onglet `Congé`: - endpoint de synthèse: `GET /api/employees/{id}/leave-summary?year=YYYY` - phase 1 métier (`CDI`/`CDD` non forfait + `FORFAIT`): - exercice CP: - `CDI`/`CDD` non forfait: du `1er juin (YYYY-1)` au `31 mai (YYYY)` (paramètre `year` = année de fin d'exercice) - `FORFAIT`: du `1er janvier (YYYY)` au `31 décembre (YYYY)` (paramètre `year` = année civile) - contrats `39h` / `35h` / `25h` (et plus largement CDI/CDD non forfait hors `4h`): - acquis annuel CP: `25` - acquis annuel samedi: `5` - en cours d'acquisition jours: `25/12 = 2,08` jours/mois - en cours d'acquisition samedis: `5/12 = 0,42` samedi/mois (non detaille en UI) - samedis acquis affiches: uniquement `opening_saturdays` (report N-1) - contrat `4h`: - acquis annuel CP: `10` - acquis annuel samedi: `0` - en cours d'acquisition: `0.83` jour/mois - contrat `FORFAIT`: - base annuelle: `jours ouvrés de l'exercice (lundi-vendredi, hors jours fériés métropole) - 218` - prorata: en cas de démarrage/fin de contrat en cours d'année civile, le calcul ne couvre que l'intervalle actif du contrat dans l'année - reste à prendre: `acquis - absences` (toutes absences, demi-journées incluses) - pas de samedi (`0`) - pas de jours en cours d'acquisition (`0`) - fractionné: `0` (saisie RH ultérieure, non calculée automatiquement) - pour `CDI`/`CDD` non forfait: - pris CP: basé sur absences de type code `C` (CONGÉ), en tenant compte des demi-journées - samedi pris: absences `C` posées le samedi (demi-journée incluse) - restants = acquis - pris (borné à 0) - pour `FORFAIT`: - pris: basé sur toutes les absences (demi-journées incluses) - restants = acquis - pris (borné à 0) - report annuel: - le reliquat (`restants`) de l'exercice précédent est reporté dans les acquis de l'exercice courant - pour `CDI`/`CDD` non forfait: report séparé jours + samedis - pour `FORFAIT`: report uniquement sur les jours - si un solde d'ouverture existe en base (`employee_leave_balances`) pour l'exercice courant, ce solde devient la source prioritaire du report - si une clôture de contrat est marquée `contractPaidLeaveSettled=true` sur l'exercice précédent, le report vers l'exercice suivant est remis à `0` - si une clôture `contractPaidLeaveSettled=true` existe dans l'exercice courant, le calcul est réinitialisé à partir du lendemain de cette clôture (pas de continuité intra-exercice) - lecture des compteurs: - `acquis` = droits reportés de l'exercice N-1 (après application des règles de soldé) - `en cours d'acquisition` = total droits générés sur l'exercice N (jours + samedis en cours), sans detail séparé en UI - règle de consommation: - les absences s'imputent d'abord sur `acquis`, puis sur `en cours d'acquisition` - la prise sur `en cours d'acquisition` est autorisée (usage anticipé) - `en cours d'acquisition` peut devenir négatif si la prise dépasse le généré (ex: `2.08 - 3 = -0.92`), puis se reconstitue avec les acquisitions suivantes - date d'arret de calcul: - les compteurs sont calculés jusqu'au dernier jour du mois précédent (le mois en cours est exclu) - exemple: au `04/03/2026`, l'arret de calcul est le `28/02/2026` (ou `29/02` en année bissextile) - hors périmètre phase 1: `INTERIM` (retour non supporté) ## 10) Notifications - Icône cloche en topbar: - badge = nombre de notifications non lues - ouverture panneau = liste des non lues - fermeture panneau = marquage "lu" en masse ### Règle métier de déclenchement - Les notifications de validation site ne sont pas envoyées ligne par ligne. - Une notification est créée uniquement quand un chef de site termine la validation complète: - condition: plus aucune ligne `work_hours` du site à la date concernée avec `isSiteValid = false` - destinataires: utilisateurs `ROLE_ADMIN`