Aller au contenu

Story AB-021 : Détail du Solde Employé RH (Backend + Frontend)

Module : absence-management Tranche : VS-AB-010 (extension RH) + VS-AB-014 (lien tableau de bord) de l'architecture Contexte de marque : [LES DEUX] Papillon HR Suite + ALTARYS ENTERPRISE HR Suite Priorité : 21 Dépend de : AB-009 Parallèle avec : AB-020 Ordre de fusion : Ordre quelconque avec AB-020 Complexité estimée : S PRD User Stories : US-ABS-008


Objectif

Fournir aux responsables RH et aux DG une vue détaillée des soldes de congé de n'importe quel employé, incluant le grand livre complet des acquisitions, déductions, ajustements, reports et suivi de la phase maladie. Accessible depuis le tableau de bord RH et le calendrier d'équipe. Il s'agit de l'outil RH principal pour comprendre l'historique des congés et les droits actuels d'un employé.


Périmètre Backend

Entités et Enregistrements

Aucune nouvelle entité. Cette story étend la couche de requêtes sur les modèles existants d'AB-009 (LeaveEmployeeProfile, entrées de grand livre).

DTOs :

public record EmployeeBalanceDetailResponse(
    // Profil employé
    String employeeName,
    LocalDate hireDate,
    int seniorityYears,
    String category,                    // cadre / non-cadre
    int childrenUnder21Count,

    // Décomposition congé annuel
    BigDecimal acquisBase,              // acquisition de base (JC)
    BigDecimal senioriteBonusDays,      // bonus ancienneté
    BigDecimal childrenBonusDays,       // bonus enfants
    BigDecimal totalAcquis,             // total acquis
    BigDecimal taken,                   // total pris
    BigDecimal available,               // disponible net (JC)

    // Congé exceptionnel
    BigDecimal exceptionalUsed,         // jours utilisés
    int exceptionalCap,                 // 10 jours
    int exceptionalPercentage,          // pourcentage barre de progression

    // Congé maladie (12 mois glissants)
    BigDecimal sickDaysUsed,
    String currentPhase,                // FULL_PAY, HALF_PAY, ZERO_PAY
    int daysRemainingBeforeNextPhase
) {}

public record LedgerEntryResponse(
    UUID id,
    LocalDate date,
    String transactionType,             // code enum
    String transactionLabel,            // label français
    BigDecimal amount,                  // signé (+/-)
    String unit,                        // "JC"
    @Nullable BigDecimal runningBalance,
    @Nullable String reason
) {}

public record LedgerEntriesResponse(
    List<LedgerEntryResponse> entries,
    @Nullable String nextCursor,
    int totalCount
) {}

Couche Repository

Aucun nouveau repository. Utilise les repositories existants d'AB-009 avec des méthodes de requête étendues : - Requête de grand livre avec pagination (basée sur curseur), filtre de plage de dates, filtre de type de transaction

Couche Service

BalanceQueryService.java (extension depuis AB-009) : - getEmployeeBalanceDetail(UUID tenantId, UUID employeeId) -> EmployeeBalanceDetailResponse — Décomposition complète du solde avec informations du profil employé, résumés des congés annuel/exceptionnel/maladie - getLedgerEntries(UUID tenantId, UUID employeeId, LedgerFilter filters) -> LedgerEntriesResponse — Grand livre paginé avec filtres : - from / to : plage de dates (optionnel) - type : filtre de type de transaction (optionnel, ex. "ANNUAL") - cursor : pagination basée sur curseur - Tri par défaut : chronologique décroissant (le plus récent en premier)

Points de terminaison API

Méthode Chemin Corps de la requête Réponse Auth
GET /api/v1/absence/employees/{employeeId}/balance ?includeHistory=true EmployeeBalanceDetailResponse (+ aperçu grand livre optionnel) HR_MANAGER, DG
GET /api/v1/absence/employees/{employeeId}/balance/ledger ?from=...&to=...&type=ANNUAL&cursor=... LedgerEntriesResponse (paginé) HR_MANAGER, DG

Règles de validation

  • employeeId doit exister et appartenir au tenant actuel
  • Filtres de date from / to : from doit être antérieur ou égal à to
  • Le filtre type doit être un type de transaction valide
  • Seuls les rôles HR_MANAGER ou DG peuvent accéder à ces endpoints

Considérations Multi-Tenant

  • Toutes les requêtes limitées par tenant_id depuis TenantResolutionFilter
  • L'employé doit appartenir au tenant de l'utilisateur authentifié
  • Les entrées de grand livre sont isolées par tenant par conception (FK vers LeaveEmployeeProfile limité au tenant)

Migrations Flyway

Aucune nouvelle migration. Utilise les tables de grand livre existantes d'AB-009/AB-012.


Périmètre Frontend

Pages et Routes

  • /absences/employes/:id/solde — Page de détail du solde employé RH
  • Accès : HR_MANAGER, DG

Composants

  • EmployeeBalanceDetailPage.tsx — Page principale orchestrant toutes les sections
  • EmployeeProfileCard.tsx — Identité employé : nom, date d'embauche, ancienneté, catégorie, nombre d'enfants
  • AnnualLeaveSection.tsx — Affichage héroïque du solde (JC) + décomposition (acquis base, ancienneté, enfants, pris, disponible)
  • ExceptionalLeaveSection.tsx — Barre de progression "Utilisées : {n} / 10 jours" avec pourcentage
  • SickLeaveSection.tsx — Jours utilisés, badge de phase actuelle (variante selon la phase), jours restants
  • LedgerSection.tsx — Liste chronologique du grand livre avec lien "Voir tout"
  • LedgerEntryRow.tsx — Entrée de grand livre unique : date, label, montant signé avec unité +/- et JC
  • LedgerFullPage.tsx — Vue de grand livre complet paginé (route : /absences/employes/:id/solde/grand-livre)

États UI (TOUS REQUIS)

État Comportement Copie Française
Chargement Squelette : carte de profil + 3 sections de solde + liste de grand livre
Vide (nouvel employé) Le solde affiche 0, section grand livre vide "Aucune transaction enregistree"
Erreur Toast + bouton réessayer "Impossible de charger le solde de l'employe."
Hors ligne Données en cache affichées + bandeau hors ligne "Hors connexion -- derniere synchro : {time}"
Succès N/A (page en lecture seule)

Comportement Responsive

  • 360px (mobile) : Colonne unique, sections empilées :
  • Carte de profil employé avec icône avatar, nom, date d'embauche, badge ancienneté, catégorie, nombre d'enfants
  • Section "Congé annuel" : grand nombre héroïque du solde (JC), lignes de décomposition dessous
  • Section "Permissions exceptionnelles" : barre de progression avec label
  • Section "Congé maladie (12 mois glissants)" : badge de phase + informations sur les jours
  • Section "Grand livre" : 5 dernières entrées de grand livre, lien "Voir tout" en bas
  • Bouton "Ajuster le solde" (secondary, full-width) en bas
  • 768px (tablette) : Même mise en page empilée, cartes plus larges.
  • 1024px+ (desktop) : Mise en page 2 colonnes :
  • Colonne gauche : carte de profil employé + sections de solde
  • Colonne droite : entrées de grand livre dans un DataTable avec colonnes triables/filtrables (date, type, montant)
  • Bouton "Ajuster le solde" dans la zone d'en-tête de page

Interactions

  • Navigation vers l'ajustement : Appuyer sur le bouton "Ajuster le solde" pour naviguer vers /absences/employes/:id/ajustement (AB-020), en pré-remplissant le contexte employé
  • Grand livre "Voir tout" : Navigue vers la vue de grand livre complet paginée avec filtre de plage de dates et filtre de type de transaction
  • Cache hors ligne : La page se charge depuis le cache IndexedDB hors ligne. Le bandeau affiche l'heure de la dernière synchronisation. Les données peuvent être périmées.
  • Couleurs des badges de phase :
  • FULL_PAY : Badge variant=success (vert)
  • HALF_PAY : Badge variant=warning (orange)
  • ZERO_PAY : Badge variant=error (rouge)

Labels français des types de transactions du grand livre :

Type de Transaction Label Français
MONTHLY_ACCRUAL "Acquisition mensuelle"
SENIORITY_BONUS "Bonus anciennete"
CHILDREN_BONUS "Bonus enfants"
LEAVE_DEBIT "Deduction conge"
CANCEL_CREDIT "Credit annulation"
EARLY_RETURN_CREDIT "Credit retour anticipe"
OVERLAP_CREDIT "Credit chevauchement"
CARRY_OVER "Report"
EXPIRY "Expiration"
MANUAL_ADJUSTMENT "Ajustement manuel"
SETTLEMENT "Solde de tout compte"

Critères d'Acceptation

AC-067 : Le RH peut voir le profil employé et la décomposition du solde
Étant donné que je suis authentifié en tant que HR_MANAGER ou DG
Quand je navigue vers /absences/employes/{id}/solde pour un employé de mon tenant
Alors je vois : le profil employé (nom, date d'embauche, ancienneté, catégorie, enfants de moins de 21 ans)
Et la décomposition du congé annuel (acquis base, bonus ancienneté, bonus enfants, pris, disponible)
Et le congé exceptionnel (utilisé / plafond de 10 avec barre de progression)
Et le congé maladie (jours utilisés, phase actuelle avec badge coloré, jours restants avant la prochaine phase)

AC-068 : L'historique complet du grand livre est visible
Étant donné que je consulte le détail du solde d'un employé
Quand j'étends la section grand livre ou navigue vers la vue complète du grand livre
Alors je vois la liste chronologique de toutes les transactions du grand livre (acquisitions, déductions, ajustements, reports)
Et chaque entrée affiche : date, label français, montant signé en JC et motif optionnel
Et les entrées sont paginées avec navigation basée sur curseur

AC-069 : Navigation vers l'ajustement depuis le détail
Étant donné que je consulte le détail du solde d'un employé
Quand j'appuie sur "Ajuster le solde"
Alors je navigue vers /absences/employes/{id}/ajustement (AB-020)
Et le contexte employé (id, nom, solde actuel) est pré-rempli

Règles OHADA et Réglementaires

  • FR-ABS-120 : Types de transactions du grand livre — tous les types doivent être affichés avec les labels français corrects
  • FR-ABS-121 : Champs de l'entrée de grand livre — date, transaction_type, amount, reason doivent être visibles par les RH
  • FR-ABS-122 : Le grand livre est en mode ajout uniquement et immuable — l'UI ne doit pas proposer d'édition/suppression sur les entrées de grand livre
  • FR-ABS-123 : Les corrections sont de nouvelles entrées — si un MANUAL_ADJUSTMENT corrige une erreur antérieure, il apparaît comme une entrée distincte dans le grand livre

Standards et Conventions

  • docs/standards/java-spring-guidelines.md — Couche service, pagination basée sur curseur
  • docs/standards/database-guidelines.md — Requêtes en lecture, isolation tenant, BigDecimal pour les soldes
  • docs/standards/api-guidelines.md — GET avec paramètres de requête, enveloppe ApiResponse standard, format de pagination par curseur
  • docs/standards/react-typescript-guidelines.md — Composition de page, chargement squelette, affichage du cache hors ligne
  • docs/standards/design-system.md — Badge (variant=success/warning/error), ProgressBar, Card, DataTable, composants Button
  • docs/standards/offline-sync-guidelines.md — Pattern de cache en lecture seule (afficher les données en cache hors ligne avec bandeau de vétusté)
  • docs/standards/multi-datasource-patterns.md — Accès aux données limité au tenant via JdbcClient

Exigences de Test

Tests Unitaires

  • BalanceQueryService : getEmployeeBalanceDetail retourne la décomposition correcte
  • BalanceQueryService : getLedgerEntries avec filtre de plage de dates
  • BalanceQueryService : getLedgerEntries avec filtre de type de transaction
  • BalanceQueryService : la pagination basée sur curseur retourne la bonne page
  • BalanceQueryService : calcul de la phase maladie (FULL_PAY, HALF_PAY, ZERO_PAY)

Tests d'Intégration

  • GET /api/v1/absence/employees/{id}/balance — validation complète de la structure de la réponse
  • GET /api/v1/absence/employees/{id}/balance/ledger — pagination et filtrage
  • Endpoint GET — 403 pour le rôle EMPLOYE (non autorisé pour la vue détail RH)
  • Isolation tenant : le solde d'un employé du tenant A n'est pas visible par le RH du tenant B

Ce que QA Validera

  • La page de détail du solde s'affiche correctement sur mobile (360px), tablette (768px), desktop (1024px+)
  • Mise en page 2 colonnes desktop avec DataTable à droite
  • Les badges de phase affichent les bonnes couleurs (vert/orange/rouge)
  • La barre de progression pour le congé exceptionnel affiche le bon pourcentage
  • Les entrées de grand livre affichent les labels français pour tous les types de transactions
  • "Voir tout" navigue vers le grand livre complet paginé
  • "Ajuster le solde" navigue vers le formulaire d'ajustement AB-020
  • Hors ligne : données en cache affichées avec bandeau de vétusté
  • État vide : nouvel employé sans transactions affiche "Aucune transaction enregistree"

Hors Périmètre

  • Modification des données du profil employé — responsabilité du module RH Core
  • Export du grand livre en CSV/PDF — Enterprise V2
  • Vue du solde en libre-service pour l'employé — AB-009 (route différente, périmètre d'auth différent)
  • Édition/suppression des entrées de grand livre — non autorisé conformément à FR-ABS-122 (grand livre immuable)
  • Instantanés historiques du solde — V2 (reconstruction du solde à un instant donné)

Définition de Done

  • [ ] Tous les endpoints backend implémentés et retournant les réponses correctes
  • [ ] Toutes les pages frontend s'affichent correctement à 360px, 768px, 1024px
  • [ ] Les 5 états UI implémentés (chargement, vide, erreur, hors ligne, succès)
  • [ ] La micro-copie française correspond exactement à la spécification design
  • [ ] Tous les critères d'acceptation passent manuellement
  • [ ] Tests unitaires écrits et passants
  • [ ] Tests d'intégration écrits et passants
  • [ ] Isolation multi-tenant vérifiée (aucune fuite de données inter-tenant)
  • [ ] Synchronisation hors ligne (Papillon) — cache en lecture seule avec bandeau de vétusté
  • [ ] Pas de any TypeScript — tous les types explicites
  • [ ] Pas de types bruts Java — tous les génériques explicites
  • [ ] Les réponses API suivent le format d'enveloppe standard
  • [ ] Entrées de piste d'audit créées pour chaque mutation de données — N/A (endpoints en lecture seule)