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¶
reasonobligatoire, doit être l'une des valeurs de l'énumération- Si
reason=AUTRE,reasonDetailest obligatoire -> erreur « Précisez la raison. » - Au moins l'une des valeurs
correctedClockIn/correctedClockOutdoit être fournie -> erreur « Indiquez au moins une heure corrigée. » datene doit pas être une date futurecorrectedClockIndoit être antérieure àcorrectedClockOutlorsque 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.mddocs/standards/api-guidelines.mddocs/standards/react-typescript-guidelines.mddocs/standards/offline-sync-guidelines.md
Exigences de test¶
Tests unitaires¶
- Validation :
reason=AUTREnécessitereasonDetail, 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
/regularizationsavec des données valides -> 201 PENDING - POST
/regularizationsavecreason=AUTREet aucun détail -> 400 - POST
/regularizationssans 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
anyen 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 testest vert - [ ]
./gradlew spotlessApplyréussit