Story QR-015: Teletravail Approval + Day-of Status Handling¶
Module: qr-attendance Slice: QR-T4-002 (partial: approve + day-of status) Brand context: [BOTH] Papillon HR Suite + ALTARYS ENTERPRISE HR Suite Priority: 15 Depends on: QR-014 (requests exist) Can develop concurrently with: QR-013 Merge order: After QR-014 Estimated complexity: M PRD User Stories: US-QR-007 (AC-004, AC-005)
Objective¶
Implement the manager/HR approval workflow for teletravail requests and the day-of status handling logic. When a teletravail request is approved, the employee's DailyAttendance status is set to TELETRAVAIL with scheduled hours credited automatically (no QR scan expected). If a request is still PENDING when the day arrives, the employee is conservatively marked ABSENT_PENDING. Retroactive approval corrects the status with full audit trail.
Backend Scope¶
Entities & Records¶
No new tables. Extends RemoteWorkService and DailyAttendanceService from prior stories.
Flyway Migrations¶
None.
Repository Layer¶
No new repositories. Uses existing RemoteWorkRepository and DailyAttendanceRepository.
Service Layer¶
RemoteWorkService.approve(id, approverId):
- Sets status=APPROVED, approvedBy, approvedAt
- Calls DailyAttendanceService to set day status=TELETRAVAIL
- Credits scheduled hours automatically (no overtime)
- No QR scan expected for the day
- Publishes notification to employee: "Votre demande de teletravail a ete approuvee."
RemoteWorkService.reject(id, rejecterId, reason):
- Sets status=REJECTED, rejectionReason
- Publishes notification to employee with rejection reason: "Votre demande de teletravail a ete refusee. Motif : {reason}"
Day-of status handling (batch integration with NoShowDetectionService from QR-009):
- If APPROVED teletravail for date → DailyAttendance.status = TELETRAVAIL, scheduledMinutes credited
- If PENDING on day of → DailyAttendance.status = ABSENT_PENDING ("Absent en attente de validation")
- If approver approves retroactively after day → status changes from ABSENT_PENDING to TELETRAVAIL, hours credited
- Publishes notification to approver when request is overdue (request_date = today and status still PENDING)
API Endpoints¶
| Method | Path | Request Body | Response | Auth |
|---|---|---|---|---|
| POST | /api/v1/qrcontr/remote-work/{id}/approve |
— | ApiResponse<RemoteWorkResponse> |
Manager (N+1), HR |
| POST | /api/v1/qrcontr/remote-work/{id}/reject |
{reason: string} |
ApiResponse<RemoteWorkResponse> |
Manager (N+1), HR |
DTOs¶
Reuses RemoteWorkResponse from QR-014.
RejectRemoteWorkRequest:
- reason (String, required)
Validation Rules¶
- Approve/reject: only PENDING requests
- Reject: reason is mandatory
- Only Manager (N+1 of employee) or HR can approve/reject
- Retroactive approval: allowed — status correction is audited
Multi-Tenant Considerations¶
All queries filter by tenant_id. Manager can only approve/reject requests from their direct reports. HR can approve/reject any request within tenant.
Frontend Scope¶
Pages & Routes¶
No new routes. Extends Approval page from QR-012.
Components¶
TeletravailApprovalCard:
- Displayed in approval list under "Teletravail" tab
- Shows: employee name, date, reason (if provided), limit warning (if applicable)
- Approve/Reject buttons
- Overdue indicator: amber badge "! Demande pour aujourd'hui" on cards where request_date = today
Extends ApprovalPage (from QR-012):
- Adds teletravail tab/filter alongside regularization requests
TeletravailCalendar (from QR-014):
- Approved requests now show green dots (updated from amber pending)
UI States¶
| State | Behavior | French Copy |
|---|---|---|
| Loading | Skeleton cards | — |
| Empty | No pending teletravail requests | "Aucune demande de teletravail en attente." |
| Error | Inline retry | "Impossible de charger les demandes. Reessayez." |
| Offline | Cached requests, approve/reject queued | "Actions sauvegardees — seront synchronisees." |
| Success (approve) | Green flash → card slides out | "Teletravail approuve pour {date}." |
| Success (reject) | Red flash → card slides out | "Demande refusee." |
Responsive Behavior¶
Same as QR-012 approval page: - 360px: Full-width approval cards, swipe gestures - 768px: Cards with more detail - 1024px+: Split view with list and detail panel
Interactions¶
- Same swipe approve/reject as regularization (QR-012)
- Reject requires reason in popup dialog
- Undo: 5-second toast window after approve/reject
- Overdue indicator: amber badge on cards where request_date = today
Acceptance Criteria¶
AC-001: Approved teletravail credits hours
Given my teletravail request is approved
When the day arrives
Then my status on the dashboard is "Teletravail", no QR scan is expected, and scheduled hours are credited automatically
AC-002: Pending teletravail on day-of marks absent pending
Given my request is still PENDING when the day arrives
When the system evaluates my status
Then I am marked as "Absent en attente de validation" (conservative approach)
OHADA & Regulatory Rules¶
- Conservative approach (ABSENT_PENDING) protects employer's attendance record integrity
- Retroactive approval corrects status with full audit trail
- All status changes are logged for regulatory compliance
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¶
RemoteWorkService.approve: sets status=APPROVED, DailyAttendance.status=TELETRAVAIL, scheduledMinutes creditedRemoteWorkService.reject: sets status=REJECTED, notification sent with reason- Day-of handling: PENDING on day → ABSENT_PENDING
- Retroactive approve: ABSENT_PENDING → TELETRAVAIL, hours credited
- Overdue notification: triggered when request_date = today and status = PENDING
Integration Tests¶
- POST
/remote-work/{id}/approve→ 200 APPROVED, DailyAttendance updated - POST
/remote-work/{id}/reject→ 200 REJECTED with reason - POST
/remote-work/{id}/approvewith non-manager → 403 - POST
/remote-work/{id}/rejectwithout reason → 400 - Retroactive approval: DailyAttendance status changes correctly
- Tenant isolation verified
What QA Will Validate¶
- Full approval flow: request → approve → dashboard shows TELETRAVAIL
- Rejection flow: request → reject → employee notified with reason
- Verify dashboard status for approved teletravail (no QR scan expected)
- Verify ABSENT_PENDING for pending requests on day-of
- Retroactive approval corrects status
- Swipe approve/reject gestures on mobile
- Undo toast window (5 seconds)
- Offline: approve/reject queued and synced
Out of Scope¶
- Request creation (QR-014)
- Dashboard integration of teletravail counts (already in QR-009)
- Bulk approval (V2)
Definition of Done¶
- [ ] Approve/reject endpoints implemented and returning correct responses
- [ ] DailyAttendance status updated correctly on approval
- [ ] Scheduled hours credited on approval (no overtime)
- [ ] ABSENT_PENDING set for pending requests on day-of
- [ ] Retroactive approval corrects status with audit trail
- [ ] Approval cards displayed in approval page under teletravail tab
- [ ] 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: approve/reject queued and synced
- [ ] Audit trail entries for all approval/rejection actions
- [ ] No TypeScript
any, no Java raw types - [ ] API responses follow standard envelope format
- [ ]
./gradlew testis green - [ ]
./gradlew spotlessApplypasses