Story QR-017: Monthly Attendance Report + Export¶
Module: qr-attendance Slice: QR-T5-002 + QR-T5-004 Brand context: [BOTH] Papillon HR Suite + ALTARYS ENTERPRISE HR Suite Priority: 17 Depends on: QR-012 (regularization info in reports) Can develop concurrently with: QR-018 Merge order: Before QR-018 (export service shared) Estimated complexity: M PRD User Stories: US-QR-011
Objective¶
Build the monthly attendance report for individual employees and department-level summaries, with Excel (.xlsx) and CSV export capabilities. The monthly employee report shows per-day detail (scheduled vs actual hours, status, overtime, anomalies, regularizations) plus a summary row. The department summary aggregates stats across all employees. Export files use French formatting conventions (DD/MM/YYYY dates, HH:MM times, comma decimal separators, UTF-8 with BOM for CSV).
Backend Scope¶
Entities & Records¶
No new tables. Uses existing DailyAttendance, Clock, RegularizationRequest.
Flyway Migrations¶
None.
Repository Layer¶
No new repositories. Extends existing queries on DailyAttendance.
Service Layer¶
MonthlyAttendanceReportService:
- generateEmployeeReport(tenantId, employeeId, month):
- Returns MonthlyEmployeeReport
- Per row (one per working day): date, dayOfWeek, scheduledStart, scheduledEnd, actualClockIn, actualClockOut, workedMinutes, status, overtimeMinutes, earlyDepartureMinutes, anomalies, regularizationsApplied
- Summary: totalWorkedHours, totalScheduledHours, totalOvertime (by band), totalLateCount+minutes, totalEarlyDepartureCount+minutes, totalAbsences, totalTeletravailDays, totalHolidays
DepartmentSummaryReportService:
- generateDepartmentSummary(tenantId, departmentId, month):
- Returns DepartmentSummaryReport
- Per row (one per employee): name, totalWorkedHours, totalOvertime, totalLateCount, totalEarlyDepartureCount, totalAbsences, totalTeletravail, attendanceRate (%)
ExcelExportService:
- Uses Apache POI to generate .xlsx files
- French date format: DD/MM/YYYY, time: HH:MM, decimal separator: comma
- Company header + report title in first rows
- Styled headers, auto-sized columns
- Enterprise: includes signature line at bottom
CsvExportService:
- UTF-8 with BOM (for Excel compatibility with French characters)
- Same format conventions as Excel (DD/MM/YYYY, HH:MM, comma decimals)
- Semicolon delimiter (French CSV standard)
API Endpoints¶
| Method | Path | Request Body | Response | Auth |
|---|---|---|---|---|
| GET | /api/v1/qrcontr/reports/monthly-attendance |
?employeeId=&month=2026-03 |
ApiResponse<MonthlyEmployeeReport> |
HR, Comptable |
| GET | /api/v1/qrcontr/reports/department-summary |
?departmentId=&month=2026-03 |
ApiResponse<DepartmentSummaryReport> |
HR, Manager (own dept) |
| GET | /api/v1/qrcontr/reports/export |
?type=monthly-attendance&employeeId=&month=&format=xlsx\|csv |
File download (Content-Disposition) | HR, Comptable |
DTOs¶
MonthlyEmployeeReport:
- employeeId (UUID), employeeName (String), month (YearMonth)
- summary (ReportSummary): totalWorkedHours, totalScheduledHours, totalOvertimeByBand (Mapdays (List
DepartmentSummaryReport:
- departmentId (UUID), departmentName (String), month (YearMonth)
- employees (List
Validation Rules¶
monthformat: YYYY-MM (required)employeeIdrequired for monthly-attendance reportdepartmentIdrequired for department-summary reportformatmust bexlsxorcsvfor export endpoint- Manager can only access own department summary
Multi-Tenant Considerations¶
All report queries filter by tenant_id. Manager restricted to own department. HR and Comptable see all within tenant.
Frontend Scope¶
Pages & Routes¶
/qrcontr/reports— Report hub/qrcontr/reports/monthly— Monthly attendance report view/qrcontr/reports/department— Department summary view
Components¶
ReportHubPage (design spec wireframe 3.13):
- Links to monthly attendance report and overtime report (QR-018)
MonthlyReportPage:
- Employee selector, month picker, summary cards, daily table
DepartmentSummaryPage:
- Department selector, month picker, employee summary table
ExportButtons:
- "Exporter Excel" + "Exporter CSV" floating action buttons
- Triggers browser download on click
ReportTable:
- Scrollable table with sticky headers
- Sticky first column (date or employee name) on horizontal scroll
UI States¶
| State | Behavior | French Copy |
|---|---|---|
| Loading | Skeleton summary + table | — |
| Empty | No data for period | "Aucune donnee pour la periode selectionnee." |
| Error | Inline retry | "Impossible de generer le rapport. Reessayez." |
| Offline | Cached summaries only, full report requires server | "Rapport complet disponible en ligne uniquement." |
| Success | Summary cards + detailed table | — |
Responsive Behavior¶
- 360px: Horizontal scroll table (3 columns visible), export FABs at bottom
- 768px: 5 columns visible, export FABs at bottom
- 1024px+: Full table with all columns, export buttons in toolbar
Interactions¶
- Employee/department/month selectors: dropdown/picker components
- Table: horizontal scroll on mobile, sticky first column
- Export: triggers browser download. Loading spinner on button while generating.
- Enterprise: Excel file includes company header and signature line
Acceptance Criteria¶
AC-001: Monthly employee attendance sheet
Given I select an employee and a month
When I generate the report
Then I see for each day: scheduled hours, actual clock-in, actual clock-out, worked hours, status, overtime hours, early departures, anomalies, regularizations applied
And a summary row with: total worked hours, total overtime (by band), total late arrivals (count + minutes), total early departures, total absences, total teletravail days
AC-002: Department summary report
Given I select a department and a month
When I generate a department summary
Then I see aggregated stats across all employees in that department
AC-003: Report export to Excel and CSV
Given I generate any report
When I click export
Then I can download it as Excel (.xlsx) or CSV (.csv) with French date/time/decimal formatting
OHADA & Regulatory Rules¶
- FR-QR-113: CSV encoding UTF-8 with BOM, dates DD/MM/YYYY, times HH:MM, decimals with comma
- Reports support 10-year retention obligation (TV-QR-003)
- Reports feed payroll reconciliation (accountant access)
- Attendance records are legal proof in labor disputes
Standards & Conventions¶
docs/standards/java-spring-guidelines.mddocs/standards/api-guidelines.mddocs/standards/react-typescript-guidelines.md
Testing Requirements¶
Unit Tests¶
MonthlyAttendanceReportService: monthly report calculation (summary totals, day records)DepartmentSummaryReportService: department aggregation (per-employee stats, attendance rate)ExcelExportService: French date format (DD/MM/YYYY), time format (HH:MM), comma decimal separatorCsvExportService: UTF-8 BOM present, semicolon delimiter, French formatting
Integration Tests¶
- GET
/reports/monthly-attendance?employeeId=&month=→ correct report data - GET
/reports/department-summary?departmentId=&month=→ correct summary - GET
/reports/export?type=monthly-attendance&format=xlsx→ file download with correct content type - GET
/reports/export?type=monthly-attendance&format=csv→ file download with BOM - Non-HR/Comptable → 403
- Manager accessing other department → 403
- Tenant isolation verified
What QA Will Validate¶
- Generate monthly report, verify data accuracy against known attendance data
- Generate department summary, verify aggregation
- Download Excel file, open in Excel, verify French formatting
- Download CSV file, open in Excel, verify French characters display correctly (BOM)
- Responsive table behavior at all breakpoints
- Offline: cached summary displayed, full report shows online-only message
Out of Scope¶
- Overtime report (QR-018)
- PDF export (Enterprise V2)
- Year-to-date reports (V2)
- Email/scheduled report delivery (V2)
Definition of Done¶
- [ ] Report generation endpoints return correct data
- [ ] Excel export with Apache POI works correctly
- [ ] CSV export with UTF-8 BOM works correctly
- [ ] French formatting applied (DD/MM/YYYY, HH:MM, comma decimals)
- [ ] Report hub page links to all report types
- [ ] Report view renders at all breakpoints (360px, 768px, 1024px)
- [ ] 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
- [ ] No TypeScript
any, no Java raw types - [ ] API responses follow standard envelope format
- [ ]
./gradlew testis green - [ ]
./gradlew spotlessApplypasses