Aller au contenu

Rapport QR-018 : Rapport sur les heures supplémentaires +

Module de classification hebdomadaire : qr-attendance Tranche : QR-T4-003 + QR-T5-003 Contexte de la marque : [LES DEUX] Papillon HR Suite + ALTARYS ENTERPRISE HR Suite Priorité : 18 Dépend de : QR-006 (DailyAttendance), QR-004 (configuration des heures supplémentaires) Peut être développé en parallèle avec : QR-017 Ordre de fusion : Après QR-004, QR-006 Complexité estimée : M PRD User Stories : US-QR-012


Objectif

Mettre en place la classification hebdomadaire des heures supplémentaires et le rapport sur les heures supplémentaires. Un job batch planifié s'exécute chaque semaine pour classer les heures supplémentaires dans des tranches réglementaires (TRANCHE_1 : 40-46 h, TRANCHE_2 : 46-48 h, TRANCHE_3 : >48 h) avec des indicateurs supplémentaires pour le travail de nuit (21 h 00-05 h 00) et le travail le dimanche/jours fériés. Le rapport sur les heures supplémentaires présente une ventilation par tranche hebdomadaire et par employé à l'intention des RH et des comptables pour le rapprochement de la paie. Les heures supplémentaires sont enregistrées en minutes (et non en valeur monétaire); la paie applique les taux séparément.


Portée du backend

Entités et enregistrements

WeeklyOvertimeSummary : - id (UUID) - tenantId (UUID) - employeeId (UUID) - weekStartDate (LocalDate) - weekEndDate (LocalDate) - totalWorkedMinutes (int) - band1Minutes (int) - band2Minutes (int) - band3Minutes (int) - nightMinutes (int) - sundayHolidayMinutes (int) - totalOvertimeMinutes (int) - createdAt (Instant) - updatedAt (Instant)

Migrations Flyway

V001_017__attendance_weekly_overtime_summary.sql : sql CREATE TABLE attendance_weekly_overtime_summary ( id UUID PRIMARY KEY, tenant_id UUID NOT NULL, employee_id UUID NOT NULL, week_start_date DATE NOT NULL, week_end_date DATE NOT NULL, total_worked_minutes INTEGER NOT NULL DEFAULT 0, band_1_minutes INTEGER NOT NULL DEFAULT 0, band_2_minutes INTEGER NOT NULL DEFAULT 0, band_3_minutes INTEGER NOT NULL DEFAULT 0, night_minutes INTEGER NOT NULL DEFAULT 0, sunday_holiday_minutes INTEGER NOT NULL DEFAULT 0, total_overtime_minutes INTEGER NOT NULL DEFAULT 0, created_at TIMESTAMP NOT NULL DEFAULT NOW(), updated_at TIMESTAMP NOT NULL DEFAULT NOW(), UNIQUE(tenant_id, employee_id, week_start_date) ); CREATE INDEX idx_weekly_overtime_tenant ON attendance_weekly_overtime_summary(tenant_id, employee_id, week_start_date);### Couche de référentiel

WeeklyOvertimeSummaryRepository

: - findByTenantIdAndEmployeeIdAndWeekStartDate(tenantId, employeeId, weekStart) — pour l'upsert - findByTenantIdAndWeekStartDateBetween(tenantId, from, to) — pour le rapport - findByTenantIdAndEmployeeIdAndWeekStartDateBetween(tenantId, employeeId, from, to) — par employé

Couche de service

OvertimeClassificationService

: - classifyWeek(tenantId, employeeId, weekStart, weekEnd) : - Total hebdomadaire travaillé = somme de DailyAttendance.workedMinutes pour la semaine - Si total > 2400 min (40 h) : heures supplémentaires = total - 2400 - Classer en tranches (à partir de OvertimeConfig) : - BAND_1 : premières 360 min d'heures supplémentaires (40 h-46 h) - BAND_2 : 120 min suivantes (46 h-48 h) - BAND_3 : reste (> 48 h) - NIGHT : heures travaillées entre nightStartTime et nightEndTime (21 h 00-05 h 00 par défaut) — indicateur supplémentaire (ajouté en plus de la classification par tranche) - SUNDAY_HOLIDAY : heures travaillées le dimanche ou un jour férié — indicateur supplémentaire - Upsert WeeklyOvertimeSummary - Publier WeeklyOvertimeComputed - La semaine s'étend du jour de début configuré (lundi 00h00 par défaut) jusqu'à la veille du début de la semaine suivante

OvertimeClassificationScheduledJob

: - @Scheduled hebdomadaire (lundi 00h30) - Parcourt les locataires actifs pour lesquels le module QRCONTR est activé - Classe la semaine précédente pour tous les employés ayant des événements d'horloge au cours de cette semaine

OvertimeReportService

: - generateOvertimeReport(tenantId, month, weekStart, employeeId, departmentId): - Renvoie OvertimeReport — ventilation par tranche horaire par employé et par semaine - Utilise la table WeeklyOvertimeSummary

Recalcul rétroactif

: - Lorsqu'une régularisation (QR-012) affecte une semaine passée, réexécute classifyWeek pour cette semaine - Écoute l'événement RegularizationApplied et vérifie si la présence quotidienne concernée se situe dans une semaine passée

Method Path Request Body Response Auth
GET /api/v1/qrcontr/reports/overtime ?month=2026-03&weekStart=&employeeId=&departmentId= ApiResponse<OvertimeReport> HR, Comptable
GET /api/v1/qrcontr/reports/export ?type=overtime&month=&format=xlsx\|csv File download (Content-Disposition) HR, Comptable
### DTO

« OvertimeReport » : - « month » (YearMonth) - « employees » (List) : - « employeeId » (UUID) - « name » (String) - « weekNumber » (int) - « weekStart » (LocalDate) - band1Minutes (int) - band2Minutes (int) - band3Minutes (int) - nightMinutes (int) - sundayHolidayMinutes (int) - totalOvertimeMinutes (int)

Règles de validation

  • Format month : AAAA-MM (obligatoire pour le rapport)
  • format doit être xlsx ou csv pour l'exportation
  • Configuration des plages lue à partir du fichier OvertimeConfig (QR-004) du tenant

Considérations multi-tenant

Toutes les requêtes filtrent par tenant_id. La tâche planifiée itère les tenants indépendamment. Les seuils des plages sont configurables par le tenant. Les RH et la comptabilité voient tout au sein du tenant.


Portée du frontend

Pages et routes

  • /qrcontr/reports/overtime — Affichage du rapport sur les heures supplémentaires

Composants

OvertimeReportPage : - Sélecteur de mois/semaine, filtre employé/service, tableau des heures supplémentaires

OvertimeTable : - Par employé et par semaine : Tranche 1, Tranche 2, Tranche 3, Nuit, Dimanche/Jour férié, Total - Colonnes triables - Ligne des totaux en bas

Réutilise ExportButtons de QR-017 : - « Exporter vers Excel » + « Exporter vers CSV »

États de l'interface utilisateur

State Behavior French Copy
Loading Skeleton table
Empty No overtime for period "Aucune heure supplementaire pour la periode selectionnee."
Error Inline retry "Impossible de generer le rapport. Reessayez."
Offline Cached summaries only "Rapport complet disponible en ligne uniquement."
Success Overtime table rendered

Comportement adaptatif

  • 360px : tableau à défilement horizontal, 3 colonnes visibles, première colonne fixe (nom de l'employé)
  • 768px : 5 colonnes visibles
  • 1024px+ : tableau complet avec toutes les colonnes

Interactions

  • Sélecteur de mois/semaine : menu déroulant pour le mois, bascule entre les semaines au sein du mois
  • Filtre employé/service : sélecteurs déroulants
  • Exportation : réutilise le flux d'exportation de QR-017 (téléchargement via le navigateur)
  • Tableau : défilement horizontal sur mobile, première colonne fixe

Critères d'acceptation

```gherkin AC-001: Overtime report by band per employee per week Given I generate the overtime report When I view it Then I see per employee per week: Band 1 hours, Band 2 hours, Band 3 hours, Night hours, Sunday/holiday hours, Total overtime hours

AC-002: Overtime report export for payroll Given I export the report When Payroll receives it Then the data is structured for direct import (Excel/CSV with correct formatting) ```---

OHADA et dispositions réglementaires

  • Code du travail de la CI, art. 21.2-21.3 : heures supplémentaires réglementées par décret, sur la base de 40 heures par semaine
  • Valeurs par défaut de la CI (TV-QR-002) : BAND_1 40-46 h, BAND_2 46-48 h, BAND_3 >48 h
  • NUIT : 21h00-05h00 (classification supplémentaire, s'ajoute à la tranche)
  • DIMANCHE_JOUR FÉRIÉ : classification supplémentaire (s'ajoute à la tranche)
  • Les tranches sont configurables par tenant — les valeurs par défaut incorrectes peuvent être corrigées sans modification du code
  • Les heures supplémentaires sont stockées en minutes de type INTEGER (pas en valeur monétaire — la paie applique les taux)

Normes et conventions

  • docs/standards/java-spring-guidelines.md — Modèles @Scheduled
  • docs/standards/api-guidelines.md
  • docs/standards/react-typescript-guidelines.md
  • docs/standards/database-guidelines.md — Nommage des migrations Flyway

Exigences de test

Tests unitaires

  • OvertimeClassificationService : pas d'heures supplémentaires pour une semaine <= 40 h (2 400 min)
  • OvertimeClassificationService : 43 h par semaine → 3 h BAND_1, 0 h BAND_2, 0 h BAND_3
  • OvertimeClassificationService : 47 h par semaine → 6 h BAND_1, 1 h BAND_2, 0 h BAND_3
  • OvertimeClassificationService : semaine de 50 h → 6 h BAND_1, 2 h BAND_2, 2 h BAND_3
  • OvertimeClassificationService : détection des heures de nuit (entre 21 h et 5 h)
  • OvertimeClassificationService : détection des dimanches et jours fériés
  • OvertimeClassificationService : recalcul rétroactif lors de la régularisation
  • OvertimeReportService : agrégation par employé et par semaine

Tests d'intégration

  • Exécution hebdomadaire de la tâche : s'exécute pour tous les tenants, classe correctement
  • GET /reports/overtime?month=2026-03 → répartition correcte par tranche
  • GET /reports/export?type=overtime&format=xlsx → téléchargement du fichier
  • GET /reports/export?type=overtime&format=csv → téléchargement du fichier avec BOM
  • Non-RH/Comptable → 403
  • Isolation des locataires : les données du locataire A n'apparaissent pas dans le rapport du locataire B

Ce que l'assurance qualité va valider

  • Vérifier que les tranches d'heures supplémentaires correspondent à la configuration (base de 40 h, valeurs par défaut CI)
  • Générer un rapport pour le mois avec les heures supplémentaires connues, vérifier la répartition par tranche
  • Exporter vers Excel et CSV, vérifier la mise en forme et l'exactitude des données
  • Vérifier le recalcul rétroactif après régularisation
  • Tableau réactif à tous les points de rupture

Hors périmètre

  • Calcul monétaire des heures supplémentaires (module Paie)
  • Taux d'heures supplémentaires multi-pays (V2)
  • Dérogations aux conventions collectives (V2)
  • Alertes d'heures supplémentaires en temps réel (V2)

Définition de « terminé »

  • [ ] Le traitement par lots hebdomadaire de classification s'exécute correctement
  • [ ] Les tranches d'heures supplémentaires sont classées selon la configuration du tenant
  • [ ] Le recalcul rétroactif lors de la régularisation fonctionne
  • [ ] L'événement WeeklyOvertimeComputed est publié après la classification
  • [ ] L'endpoint du rapport sur les heures supplémentaires renvoie une répartition correcte des tranches
  • [ ] L'exportation réutilise les services Excel/CSV de QR-017
  • [ ] La migration Flyway a été appliquée avec succès
  • [ ] L'affichage du rapport s'affiche correctement à tous les points de rupture (360px, 768px, 1024px)
  • [ ] Les 5 états de l'interface utilisateur sont implémentés (chargement, vide, erreur, hors ligne, succès)
  • [ ] Les micro-textes en français correspondent exactement aux spécifications de conception
  • [ ] Tous les critères d'acceptation sont satisfaits manuellement
  • [ ] Les tests unitaires sont écrits et réussis
  • [ ] Les tests d'intégration sont écrits et réussis
  • [ ] L'isolation multi-tenant est vérifiée
  • [ ] Pas de any en TypeScript, pas de types bruts en Java
  • [ ] Les réponses API respectent le format d'enveloppe standard
  • [ ] ./gradlew test est vert
  • [ ] ./gradlew spotlessApply réussit