gigafibre-fsm/docs/shifts-module-spec.md
louispaulb f4138cdd75 Roster AI (planification) + prise de rendez-vous client
Solveur OR-Tools (services/roster-solver) : couverture, compétences,
équité, coût chargé, cadence/efficacité, capacité-par-job ; contraintes
dures/souples façon Timefold.

Hub (lib/roster.js) : génération via solveur, publication par réécriture
de semaine (anti-doublons), demande (effectif ou nb de jobs), cadence/coût/
compétences par tech, pause, congés (Tech Availability + approbation),
booking (slots roster-aware / fit 3-dispos / confirm) + portail public /book.
Réessai sur serialization failures frappe_pg ; appels ERP séquentiels.

Ops : page Planification (grille compacte « J8 », multi-shift, drag-select
+ undo/redo, modèles de semaine, éditeur cadence&coût, congés, SMS opt-in),
page Rendez-vous (répartiteur), jobColor tech en pause → tickets rouges.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 16:42:44 -04:00

6.7 KiB
Raw Permalink Blame History

Module Shifts — spécification (intégré au Dispatch, sans paie)

Statut : spec v2 (2026-06-03) — architecture résolue. Parcours : on a d'abord exploré Frappe HR sur PostgreSQL (déployé+validé à hr.gigafibre.ca, cf. reference_frappe_hr_postgres.md) — mais (1) son UI Desk n'est pas assez conviviale (l'usager la compare à Odoo Planning) et (2) elle est déconnectée des vrais techs/jobs qui vivent dans l'ERPNext de FACTURATION (Dispatch Technician / Dispatch Job). → On revient donc à la conclusion d'origine : build-our-own, intégré au domaine dispatch.

Décisions arrêtées :

  • Moteur (« Roster AI ») = OR-Tools CP-SAT (Python), BÂTI + validé → services/roster-solver/. Contraintes dures/souples « façon Timefold ».
  • Données du roster = dans l'ERPNext de facturation (custom doctypes, à côté de Dispatch Technician/Job) → intégration triviale des features dispatch.
  • UI = page « Planification » dans Ops (Vue/Quasar, style Odoo : grille Gantt, drag-drop, bouton « Générer »), à côté du Dispatch.
  • L'instance Frappe HR (hr.gigafibre.ca) n'est PAS le foyer du roster (techs ailleurs). Gardée seulement si on veut de la vraie RH (soldes de congés) plus tard.

Features demandées par l'usager (2026-06-03) : modèles de shifts → dispo vs requis par jour ; mettre un tech en pause → ses tickets dispatch passent en ROUGE ; demande de vacances ; demande de modification de shift.

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_id sur 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 la ShiftAssignment. Multi-niveaux possible (chaîne d'approbateurs).
  • ShiftSwapRequest : demandeur propose → le pair acceptegestionnaire approuve → échange des deux ShiftAssignment. Tout refus annule.
  • AttendanceRequest : employé demande correction → approver approuve → maj AttendanceDay.
  • 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, AttendanceDay est calculé depuis les punchs vs le ShiftType (retard si IN > début+grâce ; sortie hâtive si OUT < fingrâ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 des ShiftAssignment proposé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.