Aller au contenu

Dossier QR-011 : Demande de régularisation (employé/responsable)

Module : qr-attendance Segment : QR-T4-001 (partiel : création + soumission) Contexte de la marque : [LES DEUX] Papillon HR Suite + ALTARYS ENTERPRISE HR Suite Priorité : 11 Dépend de : QR-006 (DailyAttendance existe) Peut être développé en parallèle avec : QR-009, QR-014, QR-016 Ordre de fusion : Avant QR-012, QR-013 Complexité estimée : M PRD User Stories : US-QR-004


Objectif

Créer le flux de demande de régularisation permettant aux employés et aux responsables de soumettre des corrections pour des événements de pointage manqués ou incorrects. La demande enregistre un motif (issu d’une liste prédéfinie), les heures corrigées, et passe en état d’attente d’approbation. Il s’agit de la première partie de la fonctionnalité de régularisation — création et soumission uniquement ; l’approbation/le rejet est géré dans QR-012.


Portée du backend

Entités et enregistrements

RegularizationRequest : - id (UUID) - tenantId (UUID) - employeeId (UUID) - requestDate (LocalDate) - reason (énumération : OUBLI_POINTAGE, PROBLEME_TECHNIQUE, MISSION_EXTERIEURE, AUTRE) - reasonDetail (chaîne de caractères, peut être nul) - correctedClockIn (LocalTime, peut être nul) - correctedClockOut (LocalTime, nullable) - status (énumération : PENDING, APPROVED, REJECTED — valeur par défaut PENDING) - requestedBy (UUID) - approvedBy (UUID, nullable) - approvedAt (Timestamp, nullable) - isDirectCreate (booléen, valeur par défaut false) - overrideOf (UUID, peut être nul) - createdAt (Timestamp) - updatedAt (Timestamp)

Migrations Flyway

V001_015__attendance_regularization_request.sql :

CREATE TABLE attendance_regularization_request (
    id UUID PRIMARY KEY,
    tenant_id UUID NOT NULL,
    employee_id UUID NOT NULL,
    request_date DATE NOT NULL,
    reason VARCHAR(30) NOT NULL CHECK (reason IN ('OUBLI_POINTAGE', 'PROBLEME_TECHNIQUE', 'MISSION_EXTERIEURE', 'AUTRE')),
    reason_detail TEXT,
    corrected_clock_in TIME,
    corrected_clock_out TIME,
    status VARCHAR(20) NOT NULL DEFAULT 'PENDING' CHECK (status IN ('PENDING', 'APPROVED', 'REJECTED')),
    requested_by UUID NOT NULL,
    approved_by UUID,
    approved_at TIMESTAMP,
    is_direct_create BOOLEAN NOT NULL DEFAULT false,
    override_of UUID,
    created_at TIMESTAMP NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_regularization_tenant_status ON attendance_regularization_request(tenant_id, status, created_at);

Couche de référentiel

RegularizationRepository

: - findByTenantIdAndStatus(UUID tenantId, String status) — liste par statut - findByTenantIdAndEmployeeId(UUID tenantId, UUID employeeId) — liste par employé - findByTenantIdAndId(UUID tenantId, UUID id) — requête unique

Couche de service

RegularizationService

: - createRequest(CreateRegularizationRequest) — valide les champs, crée avec le statut PENDING, publie un événement de notification au responsable + RH

Method Path Request Body Response Auth
POST /api/v1/qrcontr/regularizations CreateRegularizationRequest ApiResponse<RegularizationResponse> Employee, Manager
GET /api/v1/qrcontr/regularizations ?status=&employeeId=&cursor=&size= ApiResponse<CursorPage<RegularizationResponse>> HR, Manager (team)
GET /api/v1/qrcontr/regularizations/{id} ApiResponse<RegularizationResponse> HR, Manager, Employee (own)
### DTOs

CreateRegularizationRequest : - employeeId (UUID) - date (LocalDate) - reason (énumération) - reasonDetail (chaîne de caractères, conditionnel) - correctedClockIn (LocalTime, facultatif) - correctedClockOut (LocalTime, facultatif)

RegularizationResponse : - Tous les champs de l'entity + employeeName (String), requesterName (String)

Règles de validation

  • reason obligatoire, doit être l'une des valeurs de l'énumération
  • Si reason=AUTRE, reasonDetail est obligatoire -> erreur « Précisez la raison. »
  • Au moins l'une des valeurs correctedClockIn / correctedClockOut doit être fournie -> erreur « Indiquez au moins une heure corrigée. »
  • date ne doit pas être une date future
  • correctedClockIn doit être antérieure à correctedClockOut lorsque les deux sont fournies

Considérations relatives au multi-tenant

Toutes les requêtes sont filtrées par tenant_id. Les événements de notification incluent le contexte du tenant. La validation de l'ID d'employé s'applique au niveau du tenant.


Portée du frontend

Composants

RegularizationBottomSheet (maquette de spécifications de conception 3.6) — Assistant en 3 étapes sur mobile : - Étape 1 : Sélectionner le motif (boutons radio : Oubli de pointage, Problème technique, Mission extérieure, Autre) - Étape 2 : Corriger les horaires (sélecteurs d'heure pour l'arrivée et/ou le départ) - Étape 3 : Résumé de confirmation

RegularizationForm — panneau latéral sur ordinateur (tous les champs visibles)

États de l'interface utilisateur

State Behavior French Copy
Loading N/A (form is local)
Empty Pre-filled date from context, reason options visible
Error Inline field errors, red border, auto-focus first error "Indiquez au moins une heure corrigee." / "Precisez la raison."
Offline Form works, submit queued "Demande sauvegardee — sera envoyee des la reconnexion."
Success Step 3: animated checkmark + summary "Demande envoyee. Votre manager et les RH seront notifies."

Comportement adaptatif

  • 360px : Assistant sous forme de feuille inférieure (3 étapes), animation de glissement vers la gauche entre les étapes (300 ms)
  • 768px : Feuille inférieure (2 étapes : motif + horaires, puis confirmation)
  • 1024px+ : Panneau latéral avec tous les champs visibles

Interactions

  • Glisser la poignée de la feuille inférieure pour la fermer (seuil de vitesse)
  • Sélecteur de date et heure : sélecteurs natifs à défilement (heures:minutes), incréments de 15 minutes suggérés, sélection possible de n'importe quelle minute
  • Le bouton Retour conserve les données saisies (aucune perte de données)
  • Déclenché depuis : historique de l'employé (appuyer sur le jour où le problème s'est produit -> bouton « Demander une régularisation »)

Critères d'acceptation

AC-001: Regularization request with reason and corrected times
Given I forgot to clock in/out
When I submit a regularization request
Then I must select a reason from the predefined list and specify the corrected time(s)

AC-002: Request enters pending status with notifications
Given I submit a request
When it is saved
Then it enters PENDING status and my manager and HR are notified

AC-003: Offline regularization request
Given I am offline
When I submit a request
Then it is queued for sync

OHADA et règles réglementaires

  • FR-QR-064 : Chaque action de régularisation doit être enregistrée avec l'acteur, l'horodatage et les valeurs avant/après
  • Les événements d'horloge d'origine ne doivent JAMAIS être modifiés ni supprimés — les régularisations constituent des enregistrements supplémentaires

Normes et conventions

  • docs/standards/java-spring-guidelines.md
  • docs/standards/api-guidelines.md
  • docs/standards/react-typescript-guidelines.md
  • docs/standards/offline-sync-guidelines.md

Exigences de test

Tests unitaires

  • Validation : reason=AUTRE nécessite reasonDetail, au moins une heure corrigée requise, date future rejetée, clockIn avant clockOut lorsque les deux sont fournis
  • Statut PENDING défini lors de la création
  • Événement de notification publié lors de la création

Tests d'intégration

  • POST /regularizations avec des données valides -> 201 PENDING
  • POST /regularizations avec reason=AUTRE et aucun détail -> 400
  • POST /regularizations sans heures corrigées -> 400
  • GET /regularizations?status=PENDING -> liste filtrée
  • GET /regularizations/{id} -> requête unique avec le nom de l'employé
  • Isolation des locataires : les requêtes du locataire A ne sont pas visibles pour le locataire B

Ce que le contrôle qualité va valider

  • Parcours complet de l'assistant sur mobile (3 étapes : motif, horaires, confirmation)
  • Vérification de la file d'attente hors ligne (soumission hors ligne, synchronisation en ligne)
  • Vérification des notifications envoyées au responsable et aux RH
  • Vérification des messages d'erreur en cas d'échec de la validation
  • Vérification que le bouton Retour conserve les données saisies

Hors périmètre

  • Workflow d'approbation/rejet (QR-012)
  • Création directe par les RH (QR-013)
  • Recalcul de la présence quotidienne lors de l'approbation (QR-012)
  • Remplacement de l'approbation du responsable par les RH (QR-012)
  • [ ] L'assistant de la feuille inférieure fonctionne sur mobile (360px)
  • [ ] Le formulaire du panneau latéral fonctionne sur ordinateur de bureau (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 et les tests d'intégration sont réussis
  • [ ] Isolation multi-tenant vérifiée
  • [ ] L'écriture et la synchronisation hors ligne fonctionnent (file d'attente IndexedDB)
  • [ ] Pas de any en TypeScript, pas de types bruts en Java
  • [ ] Les réponses API respectent le format d'enveloppe standard
  • [ ] Entrées de piste d'audit pour la création de régularisations
  • [ ] ./gradlew test est vert
  • [ ] ./gradlew spotlessApply réussit