Spec v1 du module de gestion de shifts + approbations dans le dispatch (décision build-our-own vs Frappe HR déjà actée: PG + multitenant + géofence-job). Modèle de données, workflows d'approbation (ShiftRequest/Swap/AttendanceRequest), géofence vs adresse du job dispatch, auto-attendance, auto-roster Timefold, mapping validé vs Frappe HR, intégrations (Authentik/dispatch/ERPNext API), phasage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5.7 KiB
Module Shifts — spécification (intégré au Dispatch, sans paie)
Statut : spec v1 (2026-06-02). Décision d'architecture déjà prise (cf.
memory/project_punch_shift_tool.md) : build-our-own dans le domaine dispatch, PAS Frappe HR. Raisons : ERPNext sur PostgreSQL (hrms = MariaDB- first), multitenant shared-DB par org (hrms = site/company-per-tenant), et géofence sur adresse de job dynamique (hrms = Shift Locations fixes).
1. Périmètre
Gestion de shifts + approbations. Pas de paie. On pousse les heures approuvées vers ERPNext par API (la paie/compta reste côté ERPNext/legacy).
Validé contre la page Frappe HR « Shifts & Attendance » — toutes les fonctions shift/approbation sont couvertes (voir mapping §7).
2. Contraintes transverses
- Multitenant :
org_idsur chaque doctype (shared-DB), pour usage interne Targo/Gigafibre et revente future à des tiers. - SSO : Authentik OIDC (comme toutes les apps — cf.
reference_authentik). - Stockage : Postgres (hub ou base dédiée). Pas de dépendance ERPNext pour le fonctionnement; sync sortante par API.
3. Modèle de données (doctypes / tables)
| Entité | Champs clés |
|---|---|
| ShiftType | org_id, nom, heure_début, heure_fin, durée_pause, seuil_demi_journée (h), seuil_absent (h), grâce_retard (min), grâce_sortie_hâtive (min), marge_pointage_avant/après (min), couleur |
| ShiftAssignment | org_id, employee_id, shift_type_id, date_début, date_fin, statut (Active/Inactive), source (manual/schedule/swap) |
| ShiftSchedule | org_id, nom, patron récurrent (RRULE hebdo), shift_type, équipe/employés, fenêtre de génération |
| ShiftRequest | org_id, employee_id, shift_type_id, date(s), motif, approver_id, statut (Draft→Submitted→Approved/Rejected), historique |
| ShiftSwapRequest | org_id, requester_id, counterparty_id, assignment_a, assignment_b, statut (Proposé→Accepté_par_pair→Approuvé_gestionnaire/Rejeté) |
| Punch (EmployeeCheckin) | org_id, employee_id, type (IN/OUT), timestamp, lat, lon, job_id (réf dispatch), device, source (mobile/web), within_geofence (bool) |
| AttendanceDay | org_id, employee_id, date, shift_assignment_id, statut (Présent/Retard/Demi/Absent), heures_calculées, première_IN, dernière_OUT |
| AttendanceRequest (régularisation) | org_id, employee_id, date, type, valeur_demandée, motif, approver_id, statut |
4. Workflows d'approbation
- ShiftRequest : employé soumet →
approver(gestionnaire/département) approuve/rejette → si approuvé, crée/maj laShiftAssignment. Multi-niveaux possible (chaîne d'approbateurs). - ShiftSwapRequest : demandeur propose → le pair accepte → gestionnaire approuve
→ échange des deux
ShiftAssignment. Tout refus annule. - AttendanceRequest : employé demande correction →
approverapprouve → majAttendanceDay. - Approbateurs : configurables par employé / équipe / org. Notifs in-app + (option) SMS via le hub (Twilio).
5. Différenciateur — géofence vs adresse du job dispatch
À chaque punch terrain, on calcule la distance entre (lat,lon) du punch et
l'adresse géocodée du job dispatch assigné (RQA address DB), pas un lieu fixe.
within_geofence = distance ≤ rayon_org (configurable, ex. 150 m). Le punch hors
rayon est accepté mais flaggé (preuve de présence pour le dispatch).
6. Auto-attendance & auto-rostering
- Auto-attendance : à la clôture du shift,
AttendanceDayest calculé depuis les punchs vs leShiftType(retard si IN > début+grâce ; sortie hâtive si OUT < fin−grâce ; demi-journée/absent selon seuils d'heures). - Auto-rostering : Timefold Solver (Apache-2.0, successeur d'OptaPlanner) —
même moteur que le dispatch par tags/compétences (
feedback_dispatch_tags). Contraintes : couverture des shifts, compétences requises, disponibilités, équité, coûts. Génère desShiftAssignmentproposées (révisables).
7. Mapping Frappe HR → ce build (validé)
| Frappe HR | Ici |
|---|---|
| Shift Type (seuils, grâce) | ShiftType |
| Shift Assignment (+ outil lot) | ShiftAssignment (+ assignation en lot) |
| Repeating schedules / rotating | ShiftSchedule + Timefold |
| Shift Request + approbation multi-niveaux | ShiftRequest (workflow) |
| Roster drag-and-drop + échange | Vue roster + ShiftSwapRequest |
| Check-in/out mobile + géoloc | Punch (app field-tech) |
| Auto-attendance, retard/sortie hâtive | AttendanceDay |
| Attendance regularization | AttendanceRequest |
| Rapports/calendrier | Vues calendrier + exports |
| Paie | ❌ hors périmètre — push heures → ERPNext API |
8. Écrans
- Ops (desktop) : calendrier roster (drag-and-drop), définition ShiftType, assignation en lot, file d'approbations (ShiftRequest/Swap/AttendanceRequest), tableau de présence, déclencheur Timefold.
- App field-tech (déjà existante) : mon shift du jour, punch IN/OUT (géoloc vs job), demander un shift / un échange, demander une régularisation.
9. Intégrations
- Authentik OIDC : auth + rôles (employé / gestionnaire / admin org).
- Dispatch :
Punch.job_id↔ jobs ; le solver partage les contraintes de skills/tags. - ERPNext : push des heures approuvées (par employé/période) via l'API REST
(le hub a déjà
erpFetch+ token). Aucune dépendance hrms.
10. Phasage
- MVP : ShiftType, ShiftAssignment (+ lot), ShiftRequest + approbation, Punch géoloc-vs-job, AttendanceDay auto, calendrier roster. Mono-org (Targo).
- v2 : ShiftSchedule récurrent + Timefold auto-roster, ShiftSwap,
AttendanceRequest, multitenant
org_id+ revente, push ERPNext.