From 7cadcfa3629fde67b51c2140c0303b2ee1bd2cb0 Mon Sep 17 00:00:00 2001 From: tristan Date: Mon, 4 May 2026 09:51:19 +0200 Subject: [PATCH] =?UTF-8?q?feat=20:=20s=C3=A9lecteur=20d'ann=C3=A9e=20sur?= =?UTF-8?q?=20l'onglet=20Cong=C3=A9s=20de=20la=20fiche=20employ=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Permet de consulter les exercices passés (calendrier + compteurs) sur l'onglet Congés. La plage proposée est bornée par max(début historique contrat, RTT_START_DATE) pour ne pas remonter avant la mise en service du logiciel. Édition des stocks N-1 et fractionnés verrouillée sur exercices clos. Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 7 ++ config/services.yaml | 4 + doc/leave-tab.md | 60 ++++++++++++ frontend/components/employees/LeaveTab.vue | 43 +++++++++ frontend/composables/useEmployeeLeave.ts | 92 +++++++++++++++++-- frontend/data/documentation-content.ts | 11 +++ frontend/pages/employees/[id].vue | 8 ++ .../services/dto/employee-leave-summary.ts | 1 + src/ApiResource/EmployeeLeaveSummary.php | 3 + src/State/EmployeeLeaveSummaryProvider.php | 14 ++- 10 files changed, 231 insertions(+), 12 deletions(-) create mode 100644 doc/leave-tab.md diff --git a/CLAUDE.md b/CLAUDE.md index 635947a..d274cfc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -69,6 +69,13 @@ - FORFAIT weekend/holiday bonus: each weekend or public holiday day worked gives bonus leave (full day if morning+afternoon, 0.5 if only one). Added to acquired days, no cap. PRESENCE mode only. - **FORFAIT — jours de présence et N-1** : les congés posés et imputés sur le stock N-1 ne décrémentent **pas** les jours de présence affichés (`presenceDaysByMonth` et `presenceDaysToToday`). Implémenté dans `EmployeeLeaveSummaryProvider::computePresenceDaysByMonth` via un budget N-1 (= `previousYearTakenDays`) consommé chronologiquement avant comptage des absences. Pour les non-forfait, ce budget vaut toujours 0 → comportement inchangé. +## Onglet Congés (fiche employé) +- Calendrier annuel des congés (`frontend/components/employees/LeaveTab.vue`) — période = Janvier→Décembre pour FORFAIT, Juin(N-1)→Mai(N) pour les autres contrats. Règle pilotée par le **contrat courant** (cf. `EmployeeLeaveSummaryProvider::resolveYear`), même quand on consulte une année passée. +- **Sélecteur d'année** en pied de calendrier (zone scrollable, à gauche). Plage : de l'exercice courant jusqu'à `max(floor_contrat, floor_data_start_date)` — `floor_contrat` = premier exercice avec contrat ouvert (`employee.contractHistory[].startDate`) ; `floor_data_start_date` = exercice contenant `RTT_START_DATE` (env, ex. `2026-02-23` → exercice 2026). Le double plancher empêche de remonter avant la mise en service du logiciel. Format : `2026` pour FORFAIT, `Juin 2025 → Mai 2026` sinon. +- Changement d'année → recharge complète de l'onglet via `useEmployeeLeave.setSelectedLeaveYear(year)` (reload de `getEmployeeLeaveSummary?year=YYYY` + `listAbsences` + `listPublicHolidays`). Backend : filtre `?year=YYYY` validé 2000-2100, et `EmployeeLeaveSummary` expose `dataStartDate` (env `RTT_START_DATE`, injecté via `services.yaml`). +- Sur un exercice passé (`selectedYear !== currentYear`), les boutons crayon **Jours fractionnés** et **Année N-1 payés** sont **désactivés** : pas d'édition rétroactive des stocks de report. +- Doc : `doc/leave-tab.md`. + ## Récap. congés (écran) - Accès via sidebar `Récap. congés`, conditionné au flag `User.hasLeaveRecapAccess` (défaut `false`) — activé au create/edit user. Le flag s'applique à tous les profils, y compris admin. - Scope : `ROLE_ADMIN` → tous les employés, `ROLE_USER` (chef de site) → employés de ses sites, `ROLE_SELF` → sa ligne diff --git a/config/services.yaml b/config/services.yaml index 92dac45..81d3957 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -35,6 +35,10 @@ services: arguments: $rttStartDate: '%env(RTT_START_DATE)%' + App\State\EmployeeLeaveSummaryProvider: + arguments: + $dataStartDate: '%env(RTT_START_DATE)%' + App\Repository\Contract\AbsenceReadRepositoryInterface: '@App\Repository\AbsenceRepository' App\Repository\Contract\EmployeeContractPeriodReadRepositoryInterface: '@App\Repository\EmployeeContractPeriodRepository' App\Repository\Contract\EmployeeScopedRepositoryInterface: '@App\Repository\EmployeeRepository' diff --git a/doc/leave-tab.md b/doc/leave-tab.md new file mode 100644 index 0000000..34091b0 --- /dev/null +++ b/doc/leave-tab.md @@ -0,0 +1,60 @@ +# Onglet "Congés" — fiche employé + +## Vue d'ensemble + +L'onglet **Congés** de la fiche employé (`frontend/components/employees/LeaveTab.vue`) affiche : +- un bandeau de compteurs (acquis, pris, reste, en cours d'acquisition, N-1 ou samedis selon le contrat) ; +- un calendrier annuel coloré des congés posés (12 mois en grille 4×3) ; +- pour chaque mois, le nombre de jours de présence (`presenceDaysByMonth`) ; +- un sélecteur d'année en pied de calendrier. + +## Période affichée + +La période dépend du **type de contrat actuel** de l'employé : + +| Type de contrat | Période affichée | +|-------------------|--------------------------------| +| FORFAIT | Janvier → Décembre (année civile) | +| Autres | Juin (Y-1) → Mai (Y) (exercice CP) | + +Cette règle suit `EmployeeLeaveSummaryProvider::resolveYear()` côté backend : la sélection FORFAIT vs non-FORFAIT se fait toujours sur le contrat **courant**, pas sur celui qui était en vigueur à l'année consultée. + +## Sélecteur d'année + +Position : **en bas du calendrier**, à gauche, à l'intérieur de la zone scrollable. Il scrolle donc avec les mois et apparaît sous la grille. + +Plage proposée : +- du plus récent (= année courante) au plus ancien ; +- **double plancher** : l'année minimum est `max(floor_historique_contrat, floor_data_start_date)` + - **floor_historique_contrat** : dérivé de `employee.contractHistory[].startDate` — premier exercice où l'employé avait un contrat ouvert + - **floor_data_start_date** : dérivé de l'env `RTT_START_DATE` (date de mise en service du logiciel, ex. `2026-02-23` → exercice 2026 / année forfait 2026). Aucune donnée historique n'existe avant cette date, donc on ne propose pas d'années antérieures même si le contrat de l'employé est plus ancien. +- la valeur est exposée par l'API `GET /employees/{id}/leave-summary` via le champ `dataStartDate` (peuplé depuis l'env serveur). +- en cas d'historique manquant **et** d'env absente, la plage se réduit à l'année courante. + +Format des libellés : +- FORFAIT : `2026`, `2025`, `2024`… +- Autres : `Juin 2025 → Mai 2026`, `Juin 2024 → Mai 2025`… + +Comportement : +- changer d'année recharge l'intégralité de l'onglet (`getEmployeeLeaveSummary?year=YYYY` + `listAbsences` + `listPublicHolidays`) ; +- les compteurs du bandeau reflètent l'année sélectionnée. + +## Verrouillage des éditions sur années passées + +Quand `selectedYear !== currentYear` (consultation d'une année antérieure) : +- le bouton crayon **Jours fractionnés** (non-FORFAIT) est désactivé ; +- le bouton crayon **Année N-1 payés** (FORFAIT) est désactivé. + +Justification : modifier rétroactivement les stocks de report ou les jours fractionnés d'un exercice clos décalerait silencieusement les soldes de toutes les années postérieures. La consultation reste possible, l'édition non. + +## Implémentation + +- Composable : `frontend/composables/useEmployeeLeave.ts` + - État : `selectedLeaveYear`, computed `currentLeaveYear`, `availableLeaveYears` + - API : `setSelectedLeaveYear(year)`, `loadLeaveData()`, `resetLoaded()` + - `resetLoaded()` (appelé au changement d'employé) remet `selectedLeaveYear = null` pour que la valeur par défaut soit recalculée à partir du nouveau contrat. +- Composant : `frontend/components/employees/LeaveTab.vue` + - Props : `selectedYear`, `availableYears`, `currentYear` + - Event : `update-selected-year` +- Page : `frontend/pages/employees/[id].vue` (câble le composable au composant) +- Backend : `EmployeeLeaveSummaryProvider` reçoit `RTT_START_DATE` via `services.yaml` (argument `$dataStartDate`) et l'expose dans la réponse `EmployeeLeaveSummary.dataStartDate`. Le filtrage `?year=YYYY` était déjà accepté (validation 2000–2100). diff --git a/frontend/components/employees/LeaveTab.vue b/frontend/components/employees/LeaveTab.vue index b61e5d5..0899172 100644 --- a/frontend/components/employees/LeaveTab.vue +++ b/frontend/components/employees/LeaveTab.vue @@ -39,6 +39,8 @@