Story AB-016: Maternity Declaration (Backend + Frontend)¶
Module: absence-management Slice: VS-AB-009 from architecture Brand context: [BOTH] Papillon HR Suite + ALTARYS ENTERPRISE HR Suite Priority: 16 Depends on: AB-012 Can develop concurrently with: AB-014, AB-015 Merge order: After AB-012 Estimated complexity: M PRD User Stories: US-ABS-004
Objective¶
Enable HR managers and DGs to create maternity declarations that auto-generate a 14-week leave block: 6 semaines prénatales + 8 semaines postnatales (Art. 25.8 Code du Travail, 98 jours calendaires total). The leave is AUTO_APPROVED — no manager approval step. Overlapping annual leaves are detected and credited back automatically via BalanceMutationService.
Backend Scope¶
Entities & Records¶
MaternityDeclaration (from AB-002):
public class MaternityDeclaration {
private UUID id;
private UUID tenantId;
private UUID employeeId;
private LocalDate expectedDeliveryDate;
private LocalDate actualDeliveryDate; // nullable — set via PATCH
private LocalDate startDate; // computed: expectedDeliveryDate - 42 days
private LocalDate endDate; // computed: expectedDeliveryDate + 56 days (or actualDeliveryDate + 56 days after update)
private UUID leaveRequestId; // FK to auto-created LeaveRequest
private UUID supportingDocumentId; // attestation medicale — required
private Instant createdAt;
private Instant updatedAt;
}
LeaveRequest (status=AUTO_APPROVED, type=MATERNITY) — uses existing entity from AB-002.
Request records:
public record CreateMaternityDeclarationRequest(
@NotNull UUID employeeId,
@NotNull LocalDate expectedDeliveryDate,
@NotNull UUID supportingDocumentId // attestation medicale — hard block
) {}
public record UpdateMaternityDeclarationRequest(
@NotNull LocalDate actualDeliveryDate
) {}
Repository Layer¶
MaternityDeclarationRepository.java:
- save(MaternityDeclaration declaration) — insert or update
- findById(UUID id) — single declaration lookup
- findByTenantIdAndEmployeeId(UUID tenantId, UUID employeeId) — all declarations for an employee
- existsOverlapping(UUID tenantId, UUID employeeId, LocalDate startDate, LocalDate endDate) — checks for overlapping maternity declarations
Service Layer¶
MaternityService.java:
createDeclaration(UUID employeeId, LocalDate expectedDeliveryDate, UUID supportingDocumentId):- Calculate period:
startDate = expectedDeliveryDate - 42 days,endDate = expectedDeliveryDate + 56 days - Validate no overlapping maternity declarations exist for the employee
- Create LeaveRequest with
status=AUTO_APPROVED,type=MATERNITY - Detect overlapping APPROVED annual leaves within the maternity period
- For each overlap: credit back overlapping annual leave days via
OVERLAP_CREDITledger entry using BalanceMutationService - Notify employee + manager (publish notification event)
- Publish
LeaveApprovedwith{ leaveType=MATERNITY, isPaid=true, payRate=100 } -
Persist MaternityDeclaration and return response
-
updateActualDeliveryDate(UUID declarationId, LocalDate actualDate): - Load existing declaration
- Set
actualDeliveryDate - Recalculate post-delivery period:
newEndDate = actualDate + 56 days - Pre-delivery period stays as originally taken (FR-ABS-093)
- Update the associated LeaveRequest end date
- Re-evaluate overlap credits if end date extended
- Publish updated
LeaveApproved
API Endpoints¶
| Method | Path | Request Body | Response | Auth |
|---|---|---|---|---|
| POST | /api/v1/absence/maternity-declarations |
CreateMaternityDeclarationRequest |
ApiResponse<MaternityDeclarationResponse> (201) |
HR_MANAGER, DG |
| PATCH | /api/v1/absence/maternity-declarations/:id |
UpdateMaternityDeclarationRequest |
ApiResponse<MaternityDeclarationResponse> |
HR_MANAGER, DG |
Validation Rules¶
- Employee must be ACTIVE (validated via employee service lookup)
expectedDeliveryDatemust be in the future — 422"La date presumee d'accouchement doit etre dans le futur."supportingDocumentId(attestation medicale) is required — 422"L'attestation medicale est obligatoire."- Cannot create overlapping maternity declarations for same employee — 409
"Une declaration de maternite existe deja pour cette periode." actualDeliveryDateon PATCH must be a valid date (past or today) — 422"La date d'accouchement doit etre dans le passe ou aujourd'hui."- Gender check is NOT enforced by the system (inclusive design)
Multi-Tenant Considerations¶
- All queries include
tenantIdfromScopedValue<TenantContext> - MaternityDeclaration table has
tenant_idcolumn - Overlap detection is scoped to tenant + employee
- Works across all 4 DB profiles (designed for BYO-DB first)
Frontend Scope¶
OFFLINE SYNC REMINDER (Papillon — CRITICAL): Maternity declaration is an online-only action — it requires HR/DG access and document upload. Form is blocked when offline with clear messaging.
Pages & Routes¶
| Route | Page | Description |
|---|---|---|
/absences/maternite/nouvelle |
MaternityDeclarationPage | HR/DG-only maternity declaration form |
Components¶
InfoBanner— Info banner (bg=info-light) explaining maternity rightsFormField+Select(searchable) — Employee searchFormField+DatePicker— Expected delivery date (DPA)MaternityPeriodSummary— Auto-calculated summary Card (bg=primary-subtle) showing start, end, durationOverlapNotice— Amber info text for overlapping annual leave credit-backFileUpload— Attestation medicale upload zone (required)Button— Submit button (primary, lg, fullWidth)HelperText— Notification helper below submit
UI States (ALL REQUIRED)¶
| State | Behavior | French Copy |
|---|---|---|
| Loading | Skeleton for employee select | — |
| Empty | N/A (form always available) | — |
| Error (validation) | Inline field errors | Various validation messages |
| Error (API) | Toast | "Impossible d'enregistrer la declaration." |
| Offline | Form blocked (online-only action) | "Cette action necessite une connexion internet" |
| Success | Confetti animation + Toast + navigate back | "Declaration enregistree — conge cree automatiquement" |
Responsive Behavior¶
Mobile (360px — Papillon primary): - Full-screen form layout, single column - Info banner at top (bg=info-light): "La maternite est un droit legal. Ce formulaire cree automatiquement un conge de 14 semaines." - FormField + Select (searchable) for employee: placeholder "Rechercher une employee..." - FormField + DatePicker for DPA: label "Date presumee d'accouchement" - Auto-calculated summary Card (bg=primary-subtle): "Debut : {date} (DPA - 42 jours) / Fin : {date} (DPA + 56 jours) / Duree : 14 semaines (98 jours)" - If overlap detected: amber info text: "{n} jours de conge annuel approuve seront recredites automatiquement." - FileUpload zone: label "Attestation medicale" (required) - Submit button: "Enregistrer la declaration" (primary, lg, fullWidth) - Helper: "L'employee et son manager seront notifies automatiquement." - All touch targets >= 48px
Desktop (1024px+ — Enterprise primary): - Modal or side panel, same form flow, max-width 600px - More compact spacing, same component order
Interactions¶
- Employee search: type-ahead search with debounce (300ms), shows employee name + matricule
- DPA selection: when date selected, MaternityPeriodSummary auto-calculates and renders
- Overlap detection: client checks if overlap warning is needed (API provides overlap count on DPA change)
- FileUpload: tap to open file picker (mobile), drag-drop also supported (desktop)
- Submit: validates all required fields client-side, then POST to API
- Success: confetti animation (200ms), toast, navigate to
/absences
French Micro-Copy¶
maternity.info: "La maternite est un droit legal. Ce formulaire cree automatiquement un conge de 14 semaines."maternity.employee: "Employee"maternity.search: "Rechercher une employee..."maternity.dpa: "Date presumee d'accouchement"maternity.summary: "Resume du conge"maternity.start: "Debut : {date} (DPA - 42 jours)"maternity.end: "Fin : {date} (DPA + 56 jours)"maternity.duration: "Duree : 14 semaines (98 jours)"maternity.overlap: "{n} jours de conge annuel approuve seront recredites automatiquement."maternity.attestation: "Attestation medicale"maternity.submit: "Enregistrer la declaration"maternity.notify: "L'employee et son manager seront notifies automatiquement."maternity.error.future_date: "La date presumee d'accouchement doit etre dans le futur."maternity.error.attestation_required: "L'attestation medicale est obligatoire."maternity.error.overlap: "Une declaration de maternite existe deja pour cette periode."maternity.error.save: "Impossible d'enregistrer la declaration."maternity.offline: "Cette action necessite une connexion internet"maternity.success: "Declaration enregistree — conge cree automatiquement"
Acceptance Criteria¶
AC-051: Maternity auto-creates 14-week leave block
Given I enter an expected delivery date
When I save the maternity declaration
Then the system creates a 14-week leave block (6 weeks before expected delivery + 8 weeks after)
AC-052: Maternity leave is auto-approved
Given maternity leave is created
When I view it
Then it shows status AUTO_APPROVED — no manager approval step
AC-053: Overlapping annual leave days are credited back
Given the employee has other approved leaves overlapping with the maternity period
When maternity is created
Then overlapping annual leave days are credited back to the employee's balance
OHADA & Regulatory Rules¶
- FR-ABS-090: Maternity = 14 weeks (6 before + 8 after delivery)
- FR-ABS-091: HR enters expected delivery date; system auto-calculates the leave period
- FR-ABS-092: Auto-calculation and auto-creation with overlap resolution
- FR-ABS-093: Actual delivery date update recalculates post-delivery period only — pre-delivery period stays as originally taken
- FR-ABS-094: Employer pays 100%, claims CNPS reimbursement (TV-ABS-01)
- FR-ABS-095: Employee protected from dismissal during entire maternity period
Standards & Conventions¶
docs/standards/java-spring-guidelines.md— §REST controller patterns, §Application Events, §Service layer patternsdocs/standards/database-guidelines.md— §Multi-tenant repository pattern, §Tenant isolation in every querydocs/standards/api-guidelines.md— §POST/PATCH endpoint patterns, §ApiResponse envelope, §201 Created, §422 validation errorsdocs/standards/react-typescript-guidelines.md— §Component patterns, §CSS Modules, §i18n, §Form patternsdocs/standards/design-system.md— §Select (searchable), §DatePicker, §FileUpload, §Button, §Card, §InfoBannerdocs/standards/offline-sync-guidelines.md— §Online-only actions, §Offline blocking patterndocs/standards/multi-datasource-patterns.md— §Tenant-scoped repository queries
Testing Requirements¶
Unit Tests¶
MaternityService.createDeclaration(): valid input → creates LeaveRequest with AUTO_APPROVED + MaternityDeclarationMaternityService.createDeclaration(): calculates start = DPA - 42 days, end = DPA + 56 daysMaternityService.createDeclaration(): overlapping approved annual leave (5 days) → 5 OVERLAP_CREDIT ledger entriesMaternityService.createDeclaration(): no overlapping annual leave → no credit-back entriesMaternityService.createDeclaration(): overlapping maternity declaration exists → 409MaternityService.createDeclaration(): expectedDeliveryDate in the past → 422MaternityService.createDeclaration(): missing supportingDocumentId → 422MaternityService.updateActualDeliveryDate(): recalculates end = actualDate + 56 days, start unchangedMaternityService.updateActualDeliveryDate(): extended end date triggers re-evaluation of overlap credits
Integration Tests¶
- POST valid maternity declaration → 201, LeaveRequest created with AUTO_APPROVED
- POST with past expectedDeliveryDate → 422
- POST without supportingDocumentId → 422
- POST with existing overlapping declaration → 409
- PATCH with actualDeliveryDate → 200, end date recalculated
- Multi-tenant: tenant A declaration does not affect tenant B
What QA Will Validate¶
- Form renders at 360px with info banner, employee search, date picker, file upload
- DPA selection triggers auto-calculation of period summary
- Overlap notice appears when applicable
- Submit with valid data → confetti + toast + navigation
- Submit without attestation → inline error
- Offline → form blocked with "Cette action necessite une connexion internet"
- Desktop: modal/panel layout, max-width 600px
Out of Scope¶
- CNPS reimbursement tracking (accounting process)
- Dismissal protection enforcement (Employee Management module)
- Paternity leave flow (uses standard request flow with 2-day auto-fill via AB-010)
- Maternity extension for medical complications (V2)
- Breastfeeding hour reduction tracking (V2)
Definition of Done¶
- [ ] All backend endpoints implemented and returning correct responses
- [ ] All frontend pages render correctly at 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 — declarations scoped to tenant, overlap check per tenant+employee
- [ ] Offline behavior verified — form blocked with message (Papillon) / N/A (Enterprise)
- [ ] No TypeScript
any - [ ] No Java raw types — all generics explicit
- [ ] API responses follow standard envelope format
- [ ] Audit trail entries for every data mutation — LeaveApproved published with leaveType=MATERNITY