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¶
employeeIddoit exister et appartenir au tenant actuel- Filtres de date
from/to:fromdoit être antérieur ou égal àto - Le filtre
typedoit ê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 sectionsEmployeeProfileCard.tsx— Identité employé : nom, date d'embauche, ancienneté, catégorie, nombre d'enfantsAnnualLeaveSection.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 pourcentageSickLeaveSection.tsx— Jours utilisés, badge de phase actuelle (variante selon la phase), jours restantsLedgerSection.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 JCLedgerFullPage.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 curseurdocs/standards/database-guidelines.md— Requêtes en lecture, isolation tenant, BigDecimal pour les soldesdocs/standards/api-guidelines.md— GET avec paramètres de requête, enveloppe ApiResponse standard, format de pagination par curseurdocs/standards/react-typescript-guidelines.md— Composition de page, chargement squelette, affichage du cache hors lignedocs/standards/design-system.md— Badge (variant=success/warning/error), ProgressBar, Card, DataTable, composants Buttondocs/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
anyTypeScript — 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)