Story QR-013: HR Direct Regularization¶
Module: qr-attendance Slice: QR-T4-001 (partial: HR direct-create) Brand context: [BOTH] Papillon HR Suite + ALTARYS ENTERPRISE HR Suite Priority: 13 Depends on: QR-012 (approval + recalc logic exists) Can develop concurrently with: QR-015, QR-017 Merge order: After QR-012 Estimated complexity: S PRD User Stories: US-QR-006
Objective¶
Enable HR personnel to create direct regularizations that bypass the employee request and manager approval workflow. A direct regularization is auto-approved on creation (HR is both creator and approver), immediately triggers DailyAttendance recalculation, and notifies the affected employee. This supports operational scenarios where HR corrects attendance records proactively.
Backend Scope¶
Entities & Records¶
No new tables. Extends RegularizationService from QR-012.
Flyway Migrations¶
None.
Repository Layer¶
No new repositories. Uses existing RegularizationRequestRepository.
Service Layer¶
RegularizationService.directCreate(request, hrId):
- Creates RegularizationRequest with:
- status = APPROVED
- isDirectCreate = true
- requestedBy = hrId
- approvedBy = hrId
- approvedAt = now()
- Triggers DailyAttendance recalculation (reuses logic from QR-012)
- Publishes notification to employee: "Votre pointage a ete corrige par les RH."
API Endpoints¶
| Method | Path | Request Body | Response | Auth |
|---|---|---|---|---|
| POST | /api/v1/qrcontr/regularizations/direct |
CreateRegularizationRequest |
ApiResponse<RegularizationResponse> |
HR (P2) |
DTOs¶
Reuses CreateRegularizationRequest and RegularizationResponse from QR-011.
Validation Rules¶
Same validation as QR-011:
- reason is mandatory
- At least one time field must be provided (correctedClockIn or correctedClockOut)
- date must reference an existing DailyAttendance record
- employeeId must be a valid employee in the same tenant
Multi-Tenant Considerations¶
All regularization queries filter by tenant_id. HR can only create direct regularizations for employees within their tenant.
Frontend Scope¶
Pages & Routes¶
No new routes. Form is triggered from existing dashboard views.
Components¶
DirectRegularizationForm:
- Triggered from dashboard swipe-left on employee row (HR only), or from employee day detail
- Reuses RegularizationForm component from QR-011 but with "Regularisation directe" header and no PENDING step
- Confirmation message: "Regularisation enregistree. L'employe sera notifie de la correction."
UI States¶
| State | Behavior | French Copy |
|---|---|---|
| Loading | N/A (form is local) | — |
| Empty | Pre-filled with employee + date from context | — |
| Error | Inline validation | Same as QR-011 |
| Offline | Form works, submit queued | "Regularisation sauvegardee — sera envoyee des la reconnexion." |
| Success | Animated checkmark | "Regularisation enregistree. L'employe sera notifie de la correction." |
Responsive Behavior¶
- 360px: Bottom sheet form (single step — no wizard needed since HR knows what to fill)
- 768px: Bottom sheet
- 1024px+: Side panel
Interactions¶
- Swipe-left on employee row in dashboard → opens DirectRegularizationForm
- Employee + date pre-filled from context
- Submit → animated checkmark → form closes
- Offline: form submits to local queue, syncs when online
Acceptance Criteria¶
AC-001: HR direct-create auto-approved regularization
Given I am HR
When I create a direct regularization
Then it is auto-approved (no pending step) and recorded with HR as both creator and approver
AC-002: Employee notification on HR correction
Given I create a direct regularization
When it is saved
Then the employee is notified that their record was corrected
OHADA & Regulatory Rules¶
- FR-QR-064: Direct regularization logged in audit trail with HR as actor
- Original clock events are preserved — regularization is an additive record, not a destructive edit
Standards & Conventions¶
docs/standards/java-spring-guidelines.mddocs/standards/api-guidelines.mddocs/standards/react-typescript-guidelines.mddocs/standards/offline-sync-guidelines.md
Testing Requirements¶
Unit Tests¶
RegularizationService.directCreate: sets status=APPROVED, isDirectCreate=true, requestedBy=hrId, approvedBy=hrIdRegularizationService.directCreate: triggers DailyAttendance recalculation- Validation: reason required, at least one time field required
Integration Tests¶
- POST
/regularizations/direct→ 201 with status APPROVED - POST
/regularizations/directwith non-HR role → 403 - POST
/regularizations/direct→ DailyAttendance recalculated correctly - Tenant isolation: HR from tenant A cannot regularize employee from tenant B
What QA Will Validate¶
- HR creates direct regularization from dashboard swipe action
- Verify regularization is auto-approved (no pending step)
- Verify employee receives notification
- Verify DailyAttendance is recalculated
- Offline: form works and syncs when reconnected
Out of Scope¶
- Employee/manager request workflow (QR-011)
- Approval workflow (QR-012)
- Bulk regularization (V2)
Definition of Done¶
- [ ] POST
/regularizations/directendpoint implemented - [ ] DailyAttendance recalculated on direct create
- [ ] Frontend form works from dashboard swipe action
- [ ] All 5 UI states implemented (loading, empty, error, offline, success)
- [ ] French micro-copy matches design spec exactly
- [ ] All acceptance criteria pass manually
- [ ] Unit tests written and passing
- [ ] Integration tests written and passing
- [ ] Multi-tenant isolation verified
- [ ] Offline write+sync works
- [ ] Audit trail entries for direct regularization
- [ ] No TypeScript
any, no Java raw types - [ ] API responses follow standard envelope format
- [ ]
./gradlew testis green - [ ]
./gradlew spotlessApplypasses