louispaulb
2e6eb6dd01
feat(dispatch): review shows tech's existing jobs + sector, and ordered skills inline
...
- Each tech group day now exposes the jobs ALREADY assigned (OPS
occupancy + legacy F field tickets) behind a "đ N dĂ©jĂ assignĂ©(s) ·
cities" toggle â locked greyed rows (time, skill, subject, duration).
Header shows đ sector(s) where the tech already works, so the
dispatcher can adjust accordingly.
- Header shows the tech's skills IN PRIORITY ORDER (â
first + "+N"),
clickable â same drag-reorder skill editor (visible answer to
"ordonner les compétences depuis le résultat").
- cityOfOcc: heterogeneous legacy subjects ("Type | Ville | Client" vs
"Ville | Client") â picks the first city-looking pipe segment (no
digits, â€4 words, no job stop-words), else address tail, else
" - Ville" suffix. Avoids garbage like "Bris de fibre" as a sector.
Verified: Simon Clot-Gagnon â đ Sherrington, 2 locked repair rows;
Anthony Dion â â
installation · réparation · +4.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 18:22:57 -04:00
louispaulb
28f544a777
ui(dispatch): lighter solver settings â a cost per criterion, no slider
...
Replaced the distanceâspecialty slider (heavy) with 4 compact number
inputs: SpĂ©cialitĂ© (rank_weight), Heures sup (overtime_coef â now
tunable, was hardcoded), km/h (speed), Calcul s (max_seconds). Persisted
in solverOpts (localStorage), passed to the solver. Tooltips replace the
verbose inline hints.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 17:50:23 -04:00
louispaulb
d9215a20fa
fix(dispatch): optimize by default; per-day occupation (not 16h); balance >100% capped 120%; medium=amber
...
- default strategy = optimize â the FIRST GĂ©nĂ©rer runs the VRP (real
techs, no more greedy placeholders on first attempt).
- occupation bar is now PER-DAY (worst day), so a 2-day window shows /8h
not /16h; overload shows in red.
- solver: each vehicle may go up to +20% overtime (â120% cap, hard) but
time past the nominal shift is soft-penalized â overflow spreads to
techs still under 100% before anyone does overtime. Verified: 20 jobs /
2 techs â 9h+9h (balanced, â€9.6h), overflow dropped; under capacity it
still concentrates (no forced equalization).
- priority medium flag = amber (yellow/orange) per request.
Verified live: default optimize on, 16 real techs / 0 placeholders,
per-day /8h occupation, none over, medium flag amber.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 17:39:45 -04:00
louispaulb
7fa8c6dc74
refactor(priority): unify on 3 levels (ERPNext standard), high = red, jobs + conversations
...
- shared priorityMeta/PRIORITY_LEVELS â 3 levels: Haute (RED) · Moyenne
(neutral grey) · Basse. Default/medium = grey outlined_flag. Aliases
urgentâhigh, normalâmedium for old conversation data.
- conversations: priority endpoint accepts 'medium' (keeps old values for
back-compat); the flag menu now shows the 3 levels.
- jobs: dropped the parallel job-flags override store â the job flag now
writes the REAL ERPNext priority (low/medium/high) via patchJob/
updateJob, same source as the pool sheet (no more two mechanisms).
setEntryPriority reuses patchJob. Solver: high never dropped + served
early, low dropped first.
Verified: job flag + conversation flag both grey-by-default, menu Haute/
Moyenne/Basse, high=red.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 16:01:25 -04:00
louispaulb
4e5ad011ee
fix(dispatch): reuse the Communications priority flag (grey outline â list), not a red emoji
...
The urgent flag was a red emoji shown red before being set â wrong.
Now reuses the exact Communications component: priorityMeta() + a
priority list (Urgent/Haute/Normale/Basse/Aucune) â grey outlined_flag
by default, colored only when set.
- SPA: per-job flag = q-btn(icon=priorityMeta(...).icon) + q-menu list,
same as ConversationPanel. setEntryPriority(name,lvl) (renamed to avoid
clashing with the existing pool setJobPriority(j,p)). medium (ERPNext
default) shows as grey/none.
- hub: job-flags store now holds a dispatch PRIORITY (urgent|high|normal|
low) overriding j.priority in buildUnassigned â needed because the
ERPNext job-priority field is whitelisted to low/medium/high (can't do
urgent), just like conversations keep their own priority.
Lesson applied: grep for an existing symbol before declaring (2nd
collision this session â techsForJob, setJobPriority).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 15:50:45 -04:00
louispaulb
86bd8080d2
fix(dispatch): optimizer respects existing load; drop pseudo-tech placeholders; edit skills from review
...
- Overload fix: each vehicle's window is reduced by the tech's already-
assigned load that day (shift_start += existing) â no more 20.8/16h
(verified: William 20.8â5.3/8h). Capacity is now real.
- No more "Tournée N / non casé" pseudo-techs: the optimizer uses ONLY
the selected techs; everything it can't place goes to ONE plain
"â ïž Non assignĂ©s" bucket (weekend + capacity/skill overflow). Assign
them via the proximity+load â menu, or add techs.
- Not forced to fill every tech: unneeded techs are simply left empty
(day off) â the VRP no longer fake-distributes.
- Edit/reorder skills from the optimizer: âïž on each tech header opens
the same skill editor (drag-reorder chips + â
+ rank list).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 15:35:25 -04:00
louispaulb
7d1a5b067f
feat(dispatch): persistent URGENT flag per job (SLA/commercial)
...
Like the omnichannel inbox urgent flag, but for jobs â a đ© that
persists and drives the optimizer.
- hub: durable job-flags store (data/job-flags.json) mirroring
job-levels â getJobFlags/setJobFlag + POST /roster/job-flag {name,
urgent}; buildUnassigned sets j.urgent; invalidatePool on write.
- SPA: đ© chip on each review entry (replaces the session ⥠). Optimistic
local toggle + persists via roster.setJobFlag; reflects j.urgent from
the pool. Flagged jobs â priority_boost (never dropped) + urgent_weight
(served early). Bumped urgent early-weight 6â10.
Verified: flag round-trips (setâurgent, revertâcleared) through the pool;
chips render (đ© /AM/PM).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 15:16:13 -04:00
louispaulb
2566976191
feat(dispatch): review job-move menu ranks techs by proximity + occupancy
...
Each job's move menu in the optimize review now reuses techsForJob()
(capable â with-shift â nearest â least-loaded) instead of alphabetical,
showing per tech: distance (homeâjob km) and load (h/cap). Lets you drop
a "non casĂ©" job onto the best nearby, least-busy capable tech â the
manual version of "move a job to free a tech's capacity". Works on
placeholder/unassigned entries too (same row).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 15:05:05 -04:00
louispaulb
f5a7547c1f
feat(dispatch): urgency â early-in-day + AM/PM windows per job
...
Time-aware dispatch in the VRP optimizer:
- solver: per-job urgent_weight â SetCumulVarSoftUpperBound(idx, 0, w),
a soft cost on arrival time that pulls urgent jobs to the START of the
route (conditions the tech's day start). Verified: a far urgent job is
served first instead of last. AM/PM handled via existing tw_start/end.
- SPA: per-entry AM / PM / ⥠chips (session map suggestDlg.jobTime,
survives re-solves) + a "RĂ©-optimiser" button. optimizeSuggestion maps
AMâ[480,720], PMâ[720,960] (hard window) and urgency (job priority OR
manual ⥠) â urgent_weight. Verified: chips render, toggle persists
across re-optimize, OSRM still engaged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 14:42:36 -04:00
louispaulb
3513f7e15f
feat(dispatch): solver settings (distanceâspecialty, speed, time) + urgent priority
...
- Config UI (Optimiser mode): live settings â a distanceâspecialty
slider (rank_weight 0-10), fallback speed km/h, and solve-time budget.
Persisted to localStorage, passed to the solver per run â tune the
curve without redeploying.
- Urgent jobs prioritized: each job's priority maps to priority_boost
(drop penalty) â urgent/high never dropped, low priority dropped first
when capacity is tight.
SPA-only (solver already accepts rank_weight/speed_kmh/max_seconds/
priority_boost). Verified: settings panel renders, optimize runs
end-to-end (16 techs, OSRM).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 14:03:11 -04:00
louispaulb
bc157588d1
tune(dispatch): VRP prioritizes distance over specialty (rank_weight 6â2)
...
Skill capability stays a hard filter, so a multi-skill tech (e.g. an
installer who also has the repair skill) can take those jobs. But the
specialist bias (skill-order rank) was too strong (6 virtual min/rank),
so a far repair-specialist beat a nearby installer-who-repairs. Lower
rank_weight to 2 â distance dominates; specialty only breaks near-ties.
Verified: repair job near a rank-3 multi-skill installer (4 min) vs a
far rank-0 specialist (14 min) â old weight picked the far specialist
(bug), new weight picks the nearby installer.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 13:53:46 -04:00
louispaulb
5803fb3d0e
feat(dispatch): optimizer assumes 8h shift for every selected tech
...
The VRP « Optimiser » now treats each SELECTED tech as having a 8-16
shift (created at Publish via makeShifts) â not just those already
shifted. Weekday placeholders are folded back into their day so the
solver assigns them across all selected techs; weekend placeholders
stay (no auto weekend shift). Result: full multi-tech consolidation
instead of everything falling to placeholders â verified 34 jobs â 16
techs, tight routes (0.5â14.7 km each). Techs without a real shift show
« Créer quart » (their assumed 8h, created at Publish).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 13:34:37 -04:00
louispaulb
a6508845a7
feat(dispatch): VRP route optimizer (OR-Tools) â "Optimiser" mode
...
Real vehicle-routing optimization behind the Suggérer UI, reusing our
existing OR-Tools solver service (no new stack). Fixes the greedy's
structural limits (sector-splitting, no global optimization).
- roster-solver: new route_solver.py (OR-Tools Routing / VRPTW).
Minimizes real travel; skills = hard filter (VehicleVar â allowedâȘ{-1};
SetAllowedVehiclesForIndex has a broken Span typemap in ortools 9.15);
on-site service time within each tech's shift window; optional per-job
time windows; unfittable jobs left unassigned (drop penalty) instead of
infeasible; specialist bias via skill order (per-vehicle arc cost).
New POST /route endpoint. Dockerfile now COPYs route_solver.py.
Unit-tested: skills respected, sectors consolidated, edge cases safe.
- hub: POST /roster/optimize-routes â proxies to solver /route.
- ops SPA: "⥠Optimiser" strategy. Greedy buckets jobs into days +
placeholders, then the solver re-optimizes each day (assignment +
routes) among shifted techs; result maps into the same review dialog
(occupation bars, route map, swap/merge reused). Graceful fallback to
greedy if the solver is unreachable (never drops jobs). shiftWindowMin
derives each vehicle's shift from templates.
Phase 2 (later): OSRM/Mapbox road-time matrix for exact travel times.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 11:24:08 -04:00
louispaulb
4591ef6169
feat(dispatch): skill PRIORITY ordering per tech (specialists first)
...
Skill order (not just level) now drives auto-dispatch: index 0 in a
tech's skills = their primary function. A job goes to the specialists
of that skill first, sparing less-specialized techs for other work
(e.g. Louis-Paul does repairs but his primary is sales â repair jobs
prefer the repair/install specialists).
- buildSuggestion: skillRank = t.skills.indexOf(reqSkill) (0 = primary);
score += skillRank * W.rank, tuned per strategy (enough/smart weight
specialty highest). Skill capability stays a hard filter.
- TagEditor (shared component): chips are now drag-reorderable
(vuedraggable, touch-friendly) via `sortable` prop; the 1st chip is
marked â
primary. Reorder emits the reordered array â persists as the
ordered skills CSV (order round-trips; stored in custom `skills`
field, not Frappe _user_tags, so no alphabetical re-sort).
- Skill editor: enable sortable chips + explicit priority numbers
(1,2,3âŠ) on the per-skill list, #1 highlighted, plus a hint.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 10:50:51 -04:00
louispaulb
f6e5128859
feat(dispatch): skill-driven auto-dispatch â route grouping, placeholder queues, shift check
...
Overhaul of the Planification « Suggérer » (auto-dispatch) flow:
- fix: read latitude/longitude (hub pool field), not lat/lon â the
distance scoring was inert (NaN) so jobs scattered; they now cluster
by real route (haversine) with a same-city fallback
- skill = HARD filter: incapable techs are no longer candidates
(Josée-Anne no longer gets réparation/installation). Assign/move menus
list capable techs first and block the rest, unless no capable
alternative exists (avoids trapping an unassignable queue)
- placeholder queues for any no-shift day (not just weekend), grouped by
skill then geography into ~8h tournées; the owner is swappable to a
real tech, and two queues can be merged
- per-tech occupation bar in the review (existing load + suggested /
capacity, red on overload); "Créer quart 8-16" button when the
assigned tech has no shift that day (local, saved on Publier)
- fix: "N jobs sans coordonnĂ©es" badge vs locate mismatch â honest
message + open the manual map picker for address-less jobs; also sync
pool jobs (latitude/longitude) on manual save so the badge refreshes
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 10:37:40 -04:00
louispaulb
72e84d6b8d
refactor(dispatch): la JOB impose sa compĂ©tence â retrait du niveau global par compĂ©tence
...
Logique métier : c'est le job précis qui impose la compétence/niveau, pas une
caractéristique globale. Retrait du bouton + éditeur « Niveau requis par compétence »
(level_by_skill/level_by_type globaux) et du repli global dans le moteur â le niveau
vient UNIQUEMENT du job (required_level persistant). La gestion compétences+niveaux se
fait PAR TECHNICIEN dans le SuggĂ©rer via l'icĂŽne âïž = TagEditor (chips + â
), le MĂME
composant que le tableau timeline (Dispatch). Sous-compétences (ex. émondage) = simples
compétences/tags créables et assignables au tech.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 09:38:54 -04:00
louispaulb
aa6cc3e732
feat(dispatch): niveau requis persistant + lasso freeform + routes réelles Mapbox
...
- Niveau requis PAR JOB persistant : store hub durable (job-levels.json) + endpoint
POST /roster/job-level + buildUnassigned enrichit required_level ; pastille « niv »
écrit via l'API (survit reload/session). NB : l'API Custom Field ERPNext v16 échoue
(IndexError) sur ce doctype custom â store hub (migratable en champ ERPNext plus tard).
- Lasso FREEFORM : tracĂ© libre (souris + tactile) â polygone SVG + point-in-polygon sur
les pins/amas projetés (remplace le rectangle) + expansion des amas (getClusterLeaves).
- D v2 : carte des tournĂ©es = routes ROUTIĂRES rĂ©elles (Mapbox Directions par tech,
domicileâarrĂȘts) + distance/temps RĂELS dans la lĂ©gende (cache par signature ;
fallback segments droits + estimation haversine).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 09:18:33 -04:00
louispaulb
453bef006c
fix(ops): sécurité + robustesse dispatch/comms
...
- SĂ©curitĂ© : sanitize DOMPurify sur tout HTML entrant courriel/osTicket (v-html) â
ferme le vecteur XSS (ConversationPanel + IssueDetail). Nouveau src/utils/sanitize.js,
dompurify ajouté en dépendance directe.
- Fix : piÚge TDZ (watches de la carte des tournées placés avant les const suggestDlg/
suggestMapDay/suggestGroups) qui cassait le montage de PlanificationPage â dĂ©placĂ©s
aprÚs les définitions.
- Finition : Ă©tiquette de fenĂȘtre du dispatch auto « Aujourd'hui + Demain » (au lieu de l'ISO).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 08:56:35 -04:00
louispaulb
512c4a5f1b
feat(ops): dispatch auto complet + perf BoĂźte/rapports + fix session
...
Planificateur « Suggérer » : 4 stratégies (smart / meilleurs d'abord / équilibré /
juste ce qu'il faut), compétences+niveaux par tech (édition inline), niveau requis
par compĂ©tence + par job, carte des tournĂ©es (1 couleur/tech, domicileâarrĂȘts,
sĂ©lecteur de jour), fenĂȘtre de dispatch auj.+demain (dates sĂ©lectionnĂ©es), rĂšgle
week-end + placeholder « en attente du quart », clustering + lasso + filtre-date
sur la carte, accÚs rapide « à assigner » (badge).
BoĂźte : liste /conversations allĂ©gĂ©e (45 Mo â ~1 Mo, 17Ă) + messages chargĂ©s Ă
l'ouverture. Rapports : cache SWR sur revenue-explorer (22Ă). Session : keep-alive
+ timeout fetch global + authFetch durci â fin des rechargements manuels.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 08:49:35 -04:00
louispaulb
6628eaaa5b
feat(ops+hub): sender picker, per-user notifs, editable rating emails, planif & tickets UX
...
- Comms: sélecteur d'expéditeur « De: » (défaut groupe Support TARGO) via resolveSendFrom + alias vérifiés
- Notifs: prefs de feeds PAR utilisateur (/conversations/notif-prefs) + cloche Ă bascules ; boot tooltip-ux (clic prioritaire + anti-empilement)
- Courriel: invitation à évaluer = modÚle Unlayer éditable (transactional-rating-invite-*) ; test-send via Gmail + expansion {{rating}} ; logo TARGO auto-hébergé sur le magasin d'actifs du hub
- Planif: bloc « sans dĂ©placement » (damier, dĂ©but de quart, alerte si pas de quart), quart Ă©ditable dans l'Ă©diteur de jour, icĂŽnes de compĂ©tence en vue jour (TV pour tĂ©lĂ©), clic cellule â Ă©diteur, clic gauche lane â liste / clic droit â menu quart, lien â ticket par job
- Tickets: défaut « Non fermés » + correction du filtre « Mes tickets » (owner)
- Inbox: poll Gmail 1 min + rafraĂźchir Ă la demande (poll-now)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 22:41:51 -04:00
louispaulb
0f65c02d83
feat(fsm): platform build â comms UI, FâERPNext sync/billing, roster, campaigns, network, reports
...
Accumulated work on the dispatch/legacy-writeback branch:
- Communications UI: CommunicationsPage, ConversationFullPage, DepartmentBoard,
PipelineBoard, ReaderStack, Orchestrator/NewTicket/ServiceStatus/Outbox dialogs;
hub gmail.js, ticket-collab.js, outbox.js, coupon-triage.js, client-diag.js.
- Billing/sync mirror (FâERPNext): legacy-payments.js, legacy-sync.js,
sync-orchestrator.js, supplier-invoices.js, municipality.js + incremental
migration scripts; LegacySyncPage, SupplierInvoices + negative-billing /
terminated-active reports.
- Roster/campaigns/network/voice: roster + roster-assistant, campaigns, giftbit,
olt-snmp, traccar, twilio, vision, tech-absence-sms, ai/agent/config/helpers,
legacy-dispatch-sync; ops PlanificationPage, RapportsPage, Settings, Tickets,
ClientDetail updates.
- docs/ PLATFORM_GUIDE + UI_AND_OPTIMIZATION; .gitignore __pycache__.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 06:12:12 -04:00
louispaulb
98458861c3
feat(dispatch): capacité AM/PM, durées additives, capture terrain (/field), sync techs
...
Hub (lib/roster.js, vision.js, legacy-dispatch-sync.js, server.js) + Ops + pont legacy.
- Capacité par jour AM/PM (Soir = réserve garde/urgence, jamais offerte) calculée
client-side sur les techs visibles -> suit le filtre de compétence.
- ModÚle de durée ADDITIF (caractéristiques, tableur inline) + auto-détection
DĂTERMINISTE par mots-clĂ©s (sans IA permanente) ; est_min branchĂ© sur capacitĂ© + pool.
- Capture terrain passive : endpoints publics /field (job/tech/checkpoint/ts/photo/
device/vision), tokens HMAC signés sans PII ; dérive actual_start/end. UI hébergée
public/field-app.html (liste/carte Mapbox/Street View/photo/scan MLKit->Gemini).
- Chrono job (start/finish), repositionnement carte (set-location), vue satellite,
Street View clic-droit, année devant les dates dues groupées.
- Sync techniciens : rapport de réconciliation 3 systÚmes (staff legacy / Dispatch
Technician / groupe Authentik), application MANUELLE, zéro écriture Authentik (+11 fiches).
- vision.js : extractEquipment() réutilisable (marque/modÚle/série/MAC/codes-barres).
- Pont legacy (ops_reassign.php) : désassignation reflétée, fermeture ticket, retour
au pool ; notification courriel Ă l'assignation.
Déployé sur le hub ; ce commit aligne le repo sur l'état en production.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 19:47:21 -04:00
louispaulb
ebad7066d6
feat(dispatch/assign): vue date DUE, confirm Quasar, carteâliste
...
- Panneau « Jobs Ă assigner » : tri/groupes par DATE DUE (â crĂ©ation) avec Ă©tiquettes
relatives (« Aujourd'hui », « MM-DD Ⱐen retard », future) + date due affichée sur chaque ligne
(overdue en orange). ASC/DESC place aujourd'hui dans l'ordre chronologique.
- Fermeture (unitaire + lot) : confirm via $q.dialog (au lieu de window.confirm) â propre + fiable.
- Carte â liste : clic sur un pin sĂ©lectionne + scrolle la ligne dans la liste + dĂ©plie son fil + flash visuel.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 22:46:33 -04:00
louispaulb
3d65b994e5
feat(dispatch): fermer ticket (unitaire + lot), tri ASC/DESC, batch PHP
...
- PHP ops_reassign.php : action `close` (single) + `batch_close` (N tickets en 1 connexion â efficace)
; close = status=closed + date_closed + closed_by=acteur Authentik + réouverture enfants waiting_for + log.
- Hub : closeTicketLegacy + batchCloseLegacy + routes POST close-ticket / batch-close (marque Dispatch Job Completed).
- Ops : bouton « Fermer ce ticket » (fil du panneau) ; « Fermer (N) » sur la sélection (fermeture en lot) ;
tri ASC/DESC du panneau (toggle, surtout pour la date).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 22:40:26 -04:00
louispaulb
4abce6fd66
feat(dispatch): pont d'écriture legacy + adresses/coords/carte/UX Planification
...
Pont d'Ă©criture Ops â legacy osTicket via endpoint PHP token-gated (hĂ©rite des
droits write de l'app facturation.targo.ca â AUCUN grant DB). FidĂšle Ă ticket_view.php :
réassignation (assign_to + participant[assistants] + followed_by + ticket_msg + lock
respecté) + fermeture (status=closed + date_closed + closed_by + réouverture des enfants).
Auteur du log = utilisateur Authentik rĂ©el (email â staff legacy par email/nom).
Hub (legacy-dispatch-sync.js):
- adresse de SERVICE importée (champ address) + reimportAddresses + fillMissingCoords
- garde TERRITOIRE (rejette les homonymes hors-zone Gaspésie/Outaouais/Estrie) + centroïde CP/ville
- purgeStaleOrphans (anciens imports TT- périmés), # ticket legacy dans titre + description
- legacyWrite (POST form + X-Ops-Token lu d'un fichier), pushAssignments (reassign), closeTicketLegacy
roster.js: occupancy + unassigned-jobs exposent address/latitude/longitude.
Ops (PlanificationPage.vue):
- carte des jobs Ă assigner (pins couleur=compĂ©tence + lettre repĂšre listeâcarte), chips
filtre par type, panneau ouvert par défaut
- clics cellule: bande quart/garde + blocs jobs â tournĂ©e ; fond â menu horaire (fini le clic droit)
- éditeur de tournée: itinéraire routier réel + adresse + fil ticket (expand), refresh occupation à l'assignation
- bouton « Publier au legacy » (aperçu + â dĂ©sassigner) + « Fermer le ticket »
- fix dates (lundi calculĂ© en local â plus de dĂ©calage UTC) + nav ±1 jour
services/legacy-bridge/ops_reassign.php: endpoint (placeholders; secrets injectés au déploiement, hors repo).
scripts/migration: backfill_dispatch_address.sql + diagnostics.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 22:32:00 -04:00
louispaulb
4a3dc01938
Planification grille : retrait de l'axe de temps + la bande n'intercepte plus le clic/drag de la cellule
...
- Axe de temps (hdr-ruler 0..24) retirĂ© des en-tĂȘtes de jour (inutile dans la grille ; encombrant).
- La bande d'occupation `.tl` ne stoppe plus la propagation (plus de @mousedown.stop/@click.stop) â le
clic/drag sur la cellule remonte Ă `<td>` â onCellClick (menu d'horaire) + onDown/onEnter (sĂ©lection) refonctionnent.
- L'Ă©diteur de journĂ©e s'ouvre dĂ©sormais en cliquant un BLOC de job (.tl-blk, @click.stop) â pas toute la
bande. Donc : clic sur un bloc coloré = éditer la tournée ; clic ailleurs dans la cellule = modifier l'horaire.
Le tooltip d'occupation (survol) reste actif. Curseur/hover sur les blocs cliquables.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 18:02:39 -04:00
louispaulb
29054c49c2
Planification éditeur journée : déplacements en pointillés + clic pin = détails + clic ligne = recentre carte
...
- Barre timeline : l'espace entre 2 jobs (le dĂ©placement) est rendu en POINTILLĂS (au lieu du gris vide),
tooltip « đ dĂ©placement ». dayTravelSegs() = gaps entre packedDay[i].end et [i+1].start.
- Carte : clic sur un pin â POPUP avec dĂ©tails du job (n°, sujet, heure, client) ; curseur main au survol.
- Liste : clic sur une ligne â recentre la carte (easeTo zoom 14) sur ce job, en plus d'ouvrir le dĂ©tail.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 17:50:52 -04:00
louispaulb
34b10e0a1e
Planification : carte de journĂ©e INTERACTIVE (Mapbox GL) â itinĂ©raire routier rĂ©el + zoom/dĂ©placement
...
Remplace la mini-image statique (segments Ă vol d'oiseau) par une carte Mapbox GL :
- Itinéraire ROUTIER réel via l'API Directions (geometries=geojson) tracé sur la carte (halo + ligne).
- Pins numérotés dans l'ordre de tournée (cercle coloré par compétence + numéro).
- Navigable : zoom molette + boutons NavigationControl (+/-), déplacement (pan), ajustée au territoire (fitBounds).
- Lifecycle : init à l'ouverture du dialogue (aprÚs anim + resize), refresh débouncé au réordonnancement
(re-trace l'itinéraire), destruction à la fermeture (pas de fuite). mapbox-gl chargé en CDN (comme le Dispatch).
- Avertissement « N sans coords » conservé. Validé : Directions OK (géométrie 392 pts).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 17:44:22 -04:00
louispaulb
5d4f66108d
Planification : minimap du territoire (pins+tracé) dans l'éditeur de journée + retrait du sélecteur priorité
...
- Minimap Mapbox Static ajoutée sous la timeline : pins numérotés dans l'ordre de tournée + tracé reliant
les arrĂȘts, ajustĂ©e auto au territoire des jobs â on VĂRIFIE d'un coup d'Ćil que chaque arrĂȘt tombe Ă la
bonne adresse (un pin mal placĂ© = coord Ă corriger via ConformitĂ© adresses). Clic â carte interactive (Dispatch).
Indique « N sans coords (absent de la carte) » le cas échéant. Helper encodePolyline (precision 5) pour le tracé.
- SĂ©lecteur de prioritĂ© retirĂ© de chaque ligne (dĂ©faut « Moyenne » conservĂ© en donnĂ©e, gĂ©rĂ© au Dispatch) â gain de place.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 16:54:53 -04:00
louispaulb
e14026ae23
Pont legacy : coords GPS fiables (deliveryâSLâRQAâMapbox) + routage routier rĂ©el (Mapbox Matrix)
...
Pont (legacy-dispatch-sync.js) :
- Import des coordonnées par job via cascade : table legacy `delivery` (point de service exact,
JOIN ticket.delivery_id) > Service Location ERPNext > géocodage RQA > géocodage Mapbox.
Validation bornes Québec (coord()). Couverture 153/172 (89%).
- Géocodage RQA corrigé : retrait du générique de voie (Rue/Rang/Chemin absent de
odonyme_recompose_normal) + code postal non accolé au terme (sinon ilike ne matche jamais).
- Repli Mapbox geocoding pour rues trop récentes pour le RQA (MAPBOX_TOKEN).
- Backfill + UPGRADE : coords delivery écrasent des coords SL moins précises (jamais l'inverse).
- ComptabilitĂ© honnĂȘte : vĂ©rifie r.ok sur create/update (erp ne throw pas) â errors + error_samples.
- Verrou de sérialisation sync() : tick + runs manuels ne se chevauchent plus (frappe_pg).
- Subject tronquĂ© Ă 140 (champ Data) â corrige CharacterLengthExceededError sur jobs sans SL.
- Observabilité : coord_src tally + error_samples dans le résumé.
Ops Planification (éditeur de journée) :
- travelBetween() consulte une matrice Mapbox Matrix chargĂ©e Ă l'ouverture (loadDayRoute) â
temps de trajet ROUTIERS RĂELS ; rĂ©ordonnancement instantanĂ© sans nouvelle requĂȘte.
Repli haversine si Mapbox indispo. Indicateur đ rĂ©el vs đ vol d'oiseau.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 14:43:34 -04:00
louispaulb
22fbb81d3e
feat(planif): éditeur journée = planificateur de tournée (heures recalculées, pas d'overlap, RDV verrouillables, détails)
...
- FIX overlap/ordre : packedDay recalcule les heures depuis la SĂQUENCE (ordre liste) + durĂ©es + transport ;
le timeline et les heures affichĂ©es en dĂ©coulent â rĂ©ordonner/allonger repousse les suivants, plus d'overlap
- RDV Ă heure FIXE : verrou par job (đ , dĂ©faut = booking_status 'ConfirmĂ©') â garde son heure ; flexibles = enchaĂźnĂ©s
- clic sur un job â dĂ©tails (legacy_detail : dates + description) pour juger urgence/durĂ©e ; + tooltip au survol
- save persiste start_time recalculé (+ route_order/priority/duration_h) via reorder-jobs
- hub occupancy renvoie booking_status/legacy_detail/legacy_id ; reorder-jobs accepte start_time
- fix collision fmtH â fmtHM (HH:MM padded)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 13:56:26 -04:00
louispaulb
faea3b0c1a
feat(planif): Ă©diteur journĂ©e â rĂ©ordonnancement fiable (flĂšches+drop) + durĂ©e Ă©ditable (min) + temps de transport
...
- FIX rĂ©ordonnancement : flĂšches ââ (fiable) + drag-drop basĂ© sur le DROP (au lieu du splice live jittery)
- durĂ©e Ă©ditable par job en MINUTES (pas de 5, best practice prĂ©cision) â persistĂ©e via reorder-jobs (duration_h)
- temps de transport estimé entre 2 jobs (haversine sur coords Service Location, 40km/h + 5min) affiché entre les lignes
â en attendant la gĂ©oloc live (Capacitor background-geolocation, notĂ© pour plus tard)
- hub : occupancyByTechDay renvoie lat/lon par job ; reorder-jobs accepte duration_h ; total h en pied
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 13:41:28 -04:00
louispaulb
d96e7be672
feat(planif): Ă©diteur de JOURNĂE contextuel au clic sur le progressbar (drag-drop rĂ©ordonner + retirer)
...
- clic sur le progressbar â q-dialog ciblĂ© sur le techĂjour (garde le contexte de la grille derriĂšre) :
timeline visuelle (blocs colorés par compétence) + liste éditable des jobs
- rĂ©ordonnancement par DRAG-DROP (dragstart/dragover/dragend â route_order) + sĂ©lecteur de prioritĂ© + Enregistrer
- retrait d'un job (â â hub POST /roster/unassign-job : assigned_tech null, status open â retour au pool)
- bouton « Dispatch » comme échappatoire vers le tableau complet (gotoDispatch)
- réutilise occupancy/cellBands/cellBlocks/blockStyle + reorderJobs ; best-practice détail-drawer (pas de navigation pleine page)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 13:29:55 -04:00
louispaulb
482cc948b3
refactor(planif): clic progressbar â timeline Ă©ditable Dispatch (tech+jour) au lieu du popup maison
...
- réutilisation max + cohérence : le clic sur le progressbar ouvre le tableau Dispatch focalisé sur
le tech + le jour cliqué (gotoDispatch(t, d.iso)) = LE timeline éditable (drag-drop réordonner, supprimer/désaffecter)
- retire le popup cellJobsMenu (rĂ©ordonner/prioritĂ©) â rĂšgle aussi le chevauchement avec l'infobulle mouseover
- (endpoint /roster/reorder-jobs conservé, réutilisable ; le réordonnancement se fait désormais cÎté Dispatch)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 13:19:59 -04:00
louispaulb
5eb1e587da
feat(planif): tri du panneau flottant « Jobs à assigner » (groupe/compétence/date/ville/priorité)
...
- assignSort + assignGroups regroupe/trie selon le mode (défaut = groupe parent-enfant) ;
ajout du tri par COMPĂTENCE (demandĂ©) + date/ville/prioritĂ© (jobCity = dernier segment adresse ou « Ville | » du sujet)
- barre de tri dans le panneau (hors zone de drag) + en-tĂȘte de groupe par label ; indentation enfant seulement en mode groupe
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 12:48:44 -04:00
louispaulb
510f8c10e0
feat(planif): blocs cellule colorés par compétence + menu réordonner/re-prioriser au clic sur le progressbar
...
- Blocs d'occupation = 1 job, colorĂ© par la COULEUR DE SA COMPĂTENCE (palette skills Ă©ditable),
au lieu du dĂ©gradĂ© vertârouge par taux. Hub occupancyByTechDay attache skill+job Ă chaque bloc
(skillForJob||deptToSkill) ; blockStyle â getTagColor(blk.skill).
- Clic sur le progressbar (.tl, @click.stop+@mousedown.stop) â menu : liste des jobs du techĂjour avec
rĂ©ordonnancement (flĂšches â route_order) + re-priorisation (select) + Enregistrer.
Hub POST /roster/reorder-jobs (route_order/priority, séquentiel) ; tri occupancy par route_order.
- Clic HORS du progressbar dans la cellule â menu shift inchangĂ© (crĂ©er/modifier).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 12:44:22 -04:00
louispaulb
2631ed9199
feat(dispatch): couleur ticket = couleur skill + fil complet du ticket + tri pool (date/ville/priorité)
...
- Couleurs liées aux skills (éditable/cohérent) : hub deptToSkill() déduit une compétence du type legacy
â /roster/unassigned-jobs renvoie required_skill ; PlanificationPage colore la carte par getTagColor(required_skill)
(mĂȘme couleur que le chip skill) ; bordure 5px
- Fil complet du ticket : hub /dispatch/legacy-sync/ticket-thread (ticket_msg + auteur staff, HTML nettoyé) ;
api legacyTicketThread ; RightPanel bouton « đŹ Voir le fil / commentaires » (chargĂ© au clic, messages+auteurs+dates)
- Order-by du pool dispatch : useBottomPanel.bottomSort (date|city|priority) + dropdown â
dans BottomPanel
(ville = 2e segment adresse / token sujet avant |)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 12:37:45 -04:00
louispaulb
b492e30971
feat(dispatch): réconciliation + heartbeat + détails ticket dans Ops + couleurs panneau roster
...
#1 « ne rien échapper » :
- /dispatch/legacy-sync/reconcile : compare legacy(3301,open) â Dispatch Jobs â missing/orphan (70â70, 0/0)
- /dispatch/legacy-sync/status : heartbeat (last_sync + stale) pour Uptime-Kuma
Détails ticket dans Ops (bug signalé) :
- pont extrait le 1er message du fil legacy (stripHtml) â champ legacy_detail (backfill 70)
- store legacyDetail ; RightPanel : section « Détails du ticket » ; tooltip dans le panneau roster
Couleurs panneau roster (bug signalé) :
- /roster/unassigned-jobs renvoie job_type/legacy_dept/priority/legacy_* ; PlanificationPage colore
chaque carte par type (legacyDeptColor partagĂ©) â bordure gauche
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 11:50:21 -04:00
louispaulb
90f7237312
roster(planif): chip compteur « N hors quart » dans la barre (signal hebdo des jobs assignés sans quart publié)
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 09:15:16 -04:00
louispaulb
f7343f6e0e
roster(planif/dispatch): On-Hold bloqué, alerte hors-quart, deep-link Dispatch, aviser client ( #58 )
...
- On Hold : onCellDrop REFUSE d'assigner un job en attente d'un prĂ©requis (notify), reste au panneau (â đ visuel)
- Hors quart publiĂ© : marqueur â dans la cellule libre (offShiftJobs/rawCellJobs lit occByTechDay brut) +
badge « hors quart » dans la timeline ressource â surface les jobs assignĂ©s un jour sans quart
- Deep-link : Planif gotoDispatch(tech) â /dispatch?tech=&date= ; DispatchPage lit route.query
(goToDay(date+T12:00:00) anti-décalage tz + selectTechOnBoard)
- #58 : bouton « DĂ©saffecter + aviser le client » dans le dialogue d'unassign Dispatch â
roster.notifyReschedule (désassigne serveur + SMS lien /book au mobile du Customer)
- Doc docs/features/roster.md mise à jour (Fait récemment / TODO)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 09:13:17 -04:00
louispaulb
e33dd8e83a
roster(planif): assignation drag-drop + timeline ressource + occupation + nettoyage
...
Panneau « jobs à assigner » v2 : multi-sélection (cases), groupes parent-enfant
surlignés, heuristique terrain/à distance (activation/netadmin pré-décochés),
prĂ©-total d'heures, aperçu d'occupation PROJETĂE au survol (barre fantĂŽme + badge).
Fix barre d'occupation figée aprÚs drop : /roster/assign-job pose désormais un
start_time (premier-trou-libre dans le shift) + garantit duration_h, sinon le job
compte dans les heures mais n'affiche aucun bloc. Nouvel endpoint
/roster/backfill-start-times (idempotent) pour rattraper l'historique.
Infobulle de cellule : nb de jobs + liste triée par priorité (occupancyByTechDay
renvoie jobs[]). Timeline contextuelle par ressource (dialogue, 0 appel réseau).
Lisibilité du drag : fantÎme compact semi-transparent décalé sous le curseur
(ne masque plus l'aperçu) + source estompée.
Scoring de prioritĂ© : hook proximitĂ© (neutre â secteur gĂ©rĂ© manuellement),
réservé à 20% du score quand la géoloc arrivera.
Refactor hub : helper partagé firstFitStart (assign-job + backfill).
Nettoyage : retrait code mort (onDeleteRosterTag, projUsedH), carte des sections
en tĂȘte de PlanificationPage. Doc : docs/features/roster.md + index.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 15:50:17 -04:00
louispaulb
d128adf152
Garde: 2 horaires par rĂšgle â semaine (soir 17h-minuit) vs fin de semaine (8h-minuit)
...
Une rĂšgle a maintenant un shift SEMAINE + un shift FIN DE SEMAINE (optionnel). La rotation reste
UNE sĂ©quence (mĂȘme tech sur la semaine) ; la gĂ©nĂ©ration choisit l'horaire selon le jour : weekend
(sam/dim) â shiftWeekend, sinon shift semaine. Wipe couvre les 2 shifts. ModĂšles semĂ©s:
« Garde soir 17h-00h » (17:00-23:59) + « Garde fin de sem. 8h-00h » (08:00-23:59), on_call.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 22:33:07 -04:00
louispaulb
42eac0101b
Garde: fix « 0 assignations » â rĂ©trocompat des rĂšgles sans steps/anchor
...
Les rÚgles créées avant le refactor (techs[]+periodWeeks, sans steps/anchor) donnaient 0 assignation
(rotationTech voyait 0 Ă©tape) + anchor manquant â toujours step 0. Fix: ruleSteps() convertit techs[]+
periodWeeks en étapes {tech,weeks} (collapse des doublons consécutifs) et ruleAnchor() retombe sur une
rĂ©fĂ©rence stable (epoch). rotationTech/gardeSeqLabel/editGardeRule passent par ces helpers â les vieilles
rÚgles génÚrent + s'affichent correctement, sans devoir tout recréer.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 22:29:57 -04:00
louispaulb
9e47e28e2b
Garde: moteur fiable â sĂ©quence d'Ă©tapes {tech, weeks} + semaine d'ancrage (parcours dĂ©terministe)
...
Refonte du principe de rotation suite aux bugs (3 sem. au lieu de 2, édition non reflétée) :
- Séquence = étapes {tech, nb de semaines} ; « 2 semaines consécutives » = weeks:2 (fini les
doublons+periodWeeks qui se multipliaient). Tours inégaux = weeks différents par étape.
- ANCRAGE explicite (semaine de départ, donnée de référence stockée) : on PARCOURT la séquence
semaine par semaine depuis l'ancrage â dĂ©terministe, reflĂšte les Ă©ditions, pas de dĂ©rive.
- VĂ©rifiĂ©: AĂ2,B,C ancrĂ© 8 juin â A,A,B,C,A,A,B,C (A toujours 2 consĂ©cutives) ; rĂ©ordonner reflĂšte.
- Aperçu et gĂ©nĂ©ration utilisent le mĂȘme parcours. Migration auto des anciennes rĂšgles (techs+periodâsteps).
Rappel: aprÚs édition, re-cliquer « Générer la garde » (l'horizon est réécrit, wipe ciblé du shift).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 22:15:50 -04:00
louispaulb
9ec829fc6f
Planification: marquer une absence d'1 jour depuis la grille (touche A + menu)
...
Clic sur une case â touche « A » (bascule) ou menu « Marquer absent ce jour / Retirer l'absence » â
crĂ©e/supprime une Tech Availability d'1 jour APPROUVĂE (hachurĂ©e tout de suite). Multi-sĂ©lection
supportée (A marque toutes, re-A retire). Endpoint POST /roster/absence/set {tech,date,type,remove}
(remove ne touche que les absences d'un jour, pas les vacances multi-jours). Type défaut Congé.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 22:02:39 -04:00
louispaulb
a60a9bee91
Garde: génération sur un HORIZON multi-semaines (évÚnement récurrent) au lieu d'une seule semaine
...
Avant: « Appliquer Ă la semaine » n'Ă©crivait qu'une semaine â 1 seul tech (rotation hebdo). Maintenant
« Générer la garde » matérialise la rotation sur N semaines (4/8/12/26) d'un coup, écrit direct (publié),
navigable semaine par semaine â comme un Ă©vĂšnement rĂ©current. Endpoint /roster/garde/apply : wipe ciblĂ©
des shifts de garde dans l'horizon + recréation (idempotent, reflÚte l'édition de la séquence). Saut
d'absent conservé. (source='manuel' car le Select n'autorise que solveur/manuel.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 21:58:15 -04:00
louispaulb
8bd3047d96
Garde: presets Soirs de semaine/Fin de semaine (combinables) + rotation par semaine (défaut) + aperçu
...
- Plages combinables: « Soirs de semaine » (L-V) + « Fin de semaine » (S-D) en toggles (+ chips fins).
- Rotation par dĂ©faut = PAR SEMAINE (garde = bloc hebdo) â corrige la sĂ©quence brisĂ©e (par jour, un
week-end pouvait avoir 2 personnes). Index de semaine continu dans le temps â ordre respectĂ© en
naviguant. Séquence [A,A,B] = A 2 semaines consécutives, puis B. (Sélecteur jour/semaine conservé.)
- APERĂU live : qui est de garde sur les 8 prochaines semaines, reflĂšte la file en cours d'Ă©dition â
on voit l'ordre respecté + l'effet des modifs avant d'appliquer.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 21:47:04 -04:00
louispaulb
ca82cfed9f
Garde: la rotation avance par jour de garde (la séquence continue sur les jours affichés)
...
Avant: rotation par semaine â dans une vue d'1 semaine, un seul membre apparaissait. Maintenant la
rotation avance par OCCURRENCE de garde (occurrenceIndex = nb de jours matching weekdays depuis l'époque)
â chaque jour de garde prend le membre suivant de la sĂ©quence (A,A,B,CâŠ), visible sur toute la vue.
Sélecteur « Rotation : par jour de garde / par semaine » (+ N consécutifs). Défaut = par jour ;
les rÚgles existantes (sans unit) basculent en par-jour. Saut d'absent + doublons conservés.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 21:17:25 -04:00
louispaulb
b00217e53e
Garde: sĂ©quence de rotation Ă©ditable â doublons permis + remplacer un tech par position
...
Le multi-select est remplacé par un constructeur de SUITE ordonnée : « Ajouter un tech à la suite »
(push, doublons autorisĂ©s â tours inĂ©gaux ex. A,A,B,C) ; chaque position a un select pour REMPLACER
le tech, + â/â pour rĂ©ordonner, + â pour retirer. Couvre rotations inĂ©gales et substitutions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 21:01:42 -04:00
louispaulb
ae60e60f9a
Garde: dept libre + liste techs complÚte + réordonner la rotation + éditer + 2 sem. consécutives
...
Fix listes vides: département = champ libre optionnel (existants OU texte), liste des techs = TOUS
(plus de dĂ©sactivation sur dept). RĂ©ordonnancement de la rotation (â/â), Ă©dition d'une rĂšgle (crayon
â recharge dans le formulaire â Mettre Ă jour). Champ « Sem. consĂ©cutives / tech » (mettre 2 = un tech
fait 2 semaines de suite). Annuler l'édition.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:53:26 -04:00
louispaulb
fedaf53a3b
Planification: drapeau « longue durée » sur absence (maternité/invalidité = à remplacer)
...
Tech Availability gagne long_term (Check). Case à cocher « Longue durée » dans le dialogue Congés.
absencesByTechDay encode « (longue durĂ©e) » â applyTemplate force « Ă remplacer » (pas juste sauter
comme des vacances), mĂȘme si l'absence ne couvre pas toute la semaine. ComplĂšte l'intelligence
permanent vs vacances (avant: déduit de « absent toute la semaine »).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:31:39 -04:00
louispaulb
d6c4e05488
Planification: rotation de garde par département (récurrence + rotation)
...
Dialogue « Garde » : rÚgles par département (tech_group) = {shift de garde, jours, période (toutes
les X sem.), techs en rotation ordonnés}. Indépendantes entre départements (non synchronisées).
« Appliquer à la semaine » génÚre les gardes : pour chaque jour ciblé, le tech de garde = rotation
(index de semaine / période % liste) ; un tech absent est SAUTà au profit du suivant. RÚgles persistées
(localStorage roster-garde-rules-v1). Les gardes s'affichent en pointillé ambre (on_call), hors heures
travaillées/booking déjà en place.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:27:24 -04:00
louispaulb
15276c89ff
Planification: modĂšle par dĂ©faut (â
) appliqué en 1 clic
...
Marquer un modĂšle de semaine comme dĂ©faut (â
dans le menu ModĂšles, un seul Ă la fois) â
bouton â
<nom> dans la barre pour l'appliquer en 1 clic (avec l'intelligence d'absences déjà en place).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:23:40 -04:00
louispaulb
1459ae6506
Planification: application de modĂšle consciente des absences (permanent vs vacances)
...
applyTemplate respecte maintenant les absences : on n'assigne pas un tech absent ce jour-lĂ .
- Absent toute la semaine (â congĂ© permanent: maternitĂ©/blessure) â signalĂ© « Ă remplacer » (warning).
- Absent quelques jours (â vacances) â ces jours sautĂ©s, le reste du patron tient.
Le toast résume: N assignations, absences partielles ignorées, et qui est à remplacer (avec le type).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:16:05 -04:00
louispaulb
5e15ed5b8b
Planification: menu de case court (2 raccourcis + slider en haut) â Appliquer toujours atteignable
...
- Menu rĂ©duit: 2 raccourcis (Normal 8â17, Soir 16â20) + slider d'ajustement remontĂ©s EN HAUT
(prĂšs du clic) ; Appliquer dans la rangĂ©e du slider â reste visible mĂȘme si la case est en bas
(max-height 85vh + flip auto Quasar). Retrait de la longue liste des modĂšles.
- quickShift(min,max) + applyWindow() factorisés. Shifts en place + Copier/Coller/Vider en icÎnes
compactes sous le slider. Nettoyage cellCode/cellColor/codeByShift/colorByShift/addFromMenu inutilisés.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:55:32 -04:00
louispaulb
ac957b251b
Planification: Suppr/Backspace pour vider les cases sélectionnées (ou la case active)
...
onKey: garde anti-champ (n'intercepte pas dans input/textarea/select/contenteditable) + empĂȘche
le 'retour arriÚre' du navigateur (preventDefault). Suppr/⫠vide la sélection (ou la case cliquée),
avec pushHistory (annulable). Hint de légende mis à jour.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:46:04 -04:00
louispaulb
bb337db14f
Planification: hachuré = ABSENT (congé/pause), garde = pointillé ambre (sur appel hors heures)
...
- Hachuré gris = ABSENT (Tech Availability approuvée + En pause). Nouvel endpoint /roster/absences
(En pause global + congĂ©s approuvĂ©s par jour) â la cellule d'un tech absent est hachurĂ©e (tooltip = type).
Remplace l'ancien 'P' pause.
- GARDE = nouveau visuel: bande à CONTOUR POINTILLà AMBRE + fond ambre léger (sur appel, hors heures
d'ouverture) â distinct du travail planifiĂ© et de l'absent.
- LĂ©gende: dispo (matinâsoir) · occupation · absent (hachurĂ©) · garde (pointillĂ©). Retrait 'P pause'.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:43:47 -04:00
louispaulb
2260a302b3
Planification: contour 1px foncé autour de la bande de disponibilité (vs fond du timeline)
...
La bande pĂąle se confondait avec le fond gris du timeline â contour 1px bleu-violet foncĂ©
(rgba 55,65,120,.5) box-sizing border-box pour ne pas déborder. Garde = contour brun.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:36:07 -04:00
louispaulb
5376cbb14e
Planification: fix slider d'ajustement (menu) â sĂ©lection de texte + resize continu
...
- user-select:none sur le menu (rendu en portail â n'hĂ©ritait pas du no-select de la grille)
â le glissement ne sĂ©lectionne plus le texte.
- Retrait des bulles de label de la q-range (8h/18:30h) qui changeaient de largeur â le menu ne
se redimensionne plus. La valeur reste affichĂ©e en direct sous le slider (8hâ18:30h).
- Largeur du menu fixée (260px) + @mousedown.stop sur le slider.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:29:57 -04:00
louispaulb
23a2e527cd
Planification: barre de temps pĂąle + barre de statut opaque vertâorange (occupation)
...
- Barre de TEMPS (dispo) = pĂąle (bleu trĂšs pĂąle matin â violet pĂąle soir) : repĂšre discret du quand.
- Barre de STATUT (occupĂ©) = OPAQUE vert (peu) â orange (plein) â rouge (surbookĂ©), positionnĂ©e
aux vraies heures des jobs â ressort nettement sur le fond pĂąle ; les trous pĂąles = offrables.
- LĂ©gende: dispo (matinâsoir) pĂąle + occupation (vertâorange) + garde.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:22:05 -04:00
louispaulb
0b8ebf3b8f
Planification: cellule = barre de dispo seule sur une Ă©chelle de temps (rĂšgle horaire en-tĂȘte)
...
- En-tĂȘte de chaque jour: rĂšgle horaire (graduations alignĂ©es sur l'axe adaptatif, ex 8/12/16/20).
- Cellule rĂ©duite Ă LA barre de dispo (dĂ©gradĂ© matinâsoir, occupĂ© assombri, garde hachurĂ©) â
plus de texte d'intervalle : on lit la position contre la rÚgle, détails au survol.
- Barre un peu plus haute (11px). Retrait cellLabel/cell-int/cell-chips.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:18:38 -04:00
louispaulb
1aefd0fdec
Planification: barre de dispo dĂ©gradĂ©e par l'heure (bleu matin â violet soir), fini les lettres
...
- Cellules: plus de chip-lettre (J/S/M/D). La bande de la timeline est colorée par l'HEURE :
dĂ©gradĂ© bleu pĂąle le matin â violet le soir (hsl 210â270). On lit 'quand' d'un coup d'Ćil.
- Occupé = assombrit la bande (clair = libre/offrable, foncé = pris) ; rouge si surbooké.
(Remplace le feu vert/orange/rouge â plus sobre.) Garde reste hachurĂ©e.
- LĂ©gende: Ă©chantillon dĂ©gradĂ© « matin â soir » + « garde » (hachurĂ©) au lieu de la liste de lettres.
- Intervalle (8â16) gardĂ© en texte. occColor retirĂ©.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:12:27 -04:00
louispaulb
b05ee54f92
Planification: ne montrer que les presets nommés + coller multi-cases fiable + fix Cmd+C/V
...
- Nettoyage des modĂšles auto en double fait cĂŽtĂ© donnĂ©es (8hâ16hâJour, 7hâ15hâMatinal,
9hâ17hâDĂ©calĂ©, 8hâ17hâJour, 8hâ22hâSoir) â restent 5 presets propres.
- Barre d'assignation + lĂ©gende = presetTemplates (modĂšles NOMMĂS seulement) â restent propres
mĂȘme si des modĂšles auto rĂ©apparaissent.
- Fix copier-coller : le clic ouvrait le menu ET vidait la sĂ©lection â Cmd+C voyait 0 cellule.
Maintenant on mémorise activeCell (derniÚre case cliquée) ; Cmd+C/V ferment le menu et marchent
sans multi-sélection. Coller = vers la sélection si multi, sinon la case active.
- Indicateur « N copié(s) » visible. Coller multi-cases via la barre (déjà ) + Cmd+V sur sélection.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:04:37 -04:00
louispaulb
ed8ef3bbc6
Planification: fix menu (régression cellHours) + copier/coller + slider d'ajustement dans le menu
...
BUG: le menu de case plantait sur les cases occupées (cellHours retiré mais encore appelé l.259)
â c'est ce qui cassait le copier-coller au clic. CorrigĂ© ({{ a.hours }}h).
- Copier/Coller déplacés dans le MENU de la case (clic simple, plus besoin de Cmd+clic) :
« Copier cette case » / « Coller ». (Boutons barre + Ctrl/Cmd+C/V conservés.)
- « Ajuster l'horaire (glisser) » : q-range dans le menu â Ă©largir/rĂ©duire le crĂ©neau de dispo,
+ toggle Garde. Applique = trouve/crĂ©e un modĂšle auto-nommĂ© (8hâ18h) et remplace la case.
â la dispo Ă©largie est aussitĂŽt offerte au booking (modĂšle standard).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 17:24:07 -04:00
louispaulb
0cf14ec978
Planification: copier-coller de cases + créneaux custom (slider q-range) + auto-nommage
...
- Copier-coller pour bĂątir l'horaire vite : sĂ©lectionne une case â Copier (ses shifts) â
sĂ©lectionne des cibles â Coller (duplique). Boutons dans la barre + raccourcis Ctrl+C / Ctrl+V.
Copier une case vide puis Coller = vider les cases.
- CrĂ©neaux CUSTOM : nouveau modĂšle créé via slider q-range (2 poignĂ©es, pas 0.5 h) â plus besoin
de prĂ©voir tous les types. Nom AUTO si vide (« 8hâ17h » d'aprĂšs les heures).
- Presets standards semĂ©s : 7hâ15h, 9hâ17h, 8hâ17h (+ Jour 8h-16h existant) â triĂ©s par usage.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 16:02:15 -04:00
louispaulb
ea4d91400d
Planification: cellule sans icĂŽnes â juste intervalle + timeline
...
Retrait des icĂŽnes en cellule (â/đ /đ /đĄïž ). Le libellĂ© = uniquement l'intervalle dĂ©butâfin
(ex 8â16) ; le timeline (bande pleine vs garde hachurĂ©e) porte le reste visuellement.
Tag garde dans l'infobulle: '(garde)' au lieu de l'emoji.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 15:55:02 -04:00
louispaulb
054deb7b97
Roster: la garde ne compte PAS comme heures travaillées (mise en dispo)
...
Garde (on_call) exclue partout des heures travaillées + du coût:
- hub statsByDay: heures = somme des shifts NON-garde ; nouveau compteur on_call/jour (techs en dispo).
- Ops: hoursOf (heures/tech + alerte heures supp) et costByDate/weekCost excluent la garde.
- nouvelle ligne de pied 'đĄïž Garde' = nb de techs en disponibilitĂ©/jour (si applicable).
Cohérent avec l'occupation (déjà hors-garde) : la garde = réserve d'urgence, ni offerte ni facturée.
Vérifié 8 juin: 112 h travaillées (garde 6 h exclue), garde=1.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 15:52:01 -04:00
louispaulb
63c19b8b92
Planification: axe timeline adaptatif + intervalle texte + modÚles triés par usage
...
#1 axe trop large (0-24) â axe ADAPTATIF calĂ© sur l'amplitude rĂ©elle des shifts rĂ©guliers de la
semaine (garde n'Ă©largit pas) â barres plus larges, position lisible. Intervalle dĂ©butâfin REMIS
en texte dans la cellule (â 8â16 đĄïž ) = rĂ©fĂ©rence sans survol. Infobulle = capacitĂ© offrable
(corrige aussi un bug: shiftHâbookableH).
#2 modĂšles d'assignation TRIĂS PAR USAGE (les plus utilisĂ©s en premier) + infobulle nom.
(Rappel: créer des modÚles custom = éditeur « Types de shift ».)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 15:48:47 -04:00
louispaulb
ebb440b5d8
Roster: quart de Garde (on_call) = réserve d'urgence, jamais offert au booking
...
ModĂšle: champ on_call (Check) sur Shift Template. Un quart garde:
- N'est JAMAIS offert au booking client (techGaps retourne null) â vĂ©rifiĂ©: tech Jour+Garde
n'offre que la fenĂȘtre Jour, aucun crĂ©neau dans la plage de garde.
- Est EXCLU du dénominateur d'occupation (heures offrables), affiché à part.
- Timeline: bande HACHURĂE (vs neutre pour l'offrable) + đĄïž dans le label + tag (garde) en infobulle.
- Ăditeur de modĂšles: bascule 'đĄïž Garde' pour crĂ©er/marquer un quart de garde.
hub: fetchTemplates expose on_call; create/update template le gĂšrent. Champ ajoutĂ© Ă
setup_dispatch_custom_fields.py (persistance). Démo: Garde 18h-minuit marquée on_call.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 15:37:34 -04:00
louispaulb
f0d6e9fffe
Planification: micro-timeline 24h, multi-shift, neutre/coloré, label h utilisées + icÎne période
...
Refonte selon retour: axe 24h (00â24). Chaque shift = bande NEUTRE positionnĂ©e (multi-shift OK:
Jour + Garde affichĂ©s en 2 bandes, gĂšre le passage minuit). Jobs pris = traits COLORĂS (charge:
vert/orange/rouge). Label compact = icĂŽne pĂ©riode (â/đ /đ ) + heures utilisĂ©es/total (ex 4/8).
Intervalles exacts par shift dans l'infobulle. Tick Ă midi (50%).
Démo 8 juin: TECH-4738 = Jour 8-16 + Garde 18h-minuit (multi-shift), Matinal 7-15 / Décalé 9-17.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 15:27:32 -04:00
louispaulb
2f868133d5
Planification: mini-timeline positionnĂ©e (fenĂȘtre rĂ©elle du shift + blocs pris)
...
Avant: 'J8' ne distinguait pas 7-15 de 9-17 â mĂȘmes crĂ©neaux apparents, dispo rĂ©elle diffĂ©rente.
Maintenant chaque cellule affiche: chip (lettre) + intervalle '7â15', et une mini-timeline sur un
axe de journĂ©e (06:00â21:00) oĂč la fenĂȘtre du shift est positionnĂ©e (donc 7-15 Ă gauche, 9-17 Ă
droite = visuellement distinctes) avec les blocs de jobs pris (couleur selon charge) â les TROUS
restants = créneaux offrables. Infobulle = intervalle + h occupées/h (%).
- hub occupancyByTechDay renvoie {h, blocks:[{s,e}]} (heures de début réelles des jobs).
- ops: cellWindow/axisPos/shiftStyle/blockStyle, rendu .tl/.tl-shift/.tl-blk + tick midi.
- dĂ©mo 8 juin: modĂšles Matinal 7-15 + DĂ©calĂ© 9-17, techs alignĂ©s (7â13.8, 9â18.6 surbookĂ©).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 15:21:04 -04:00
louispaulb
fd5c83d367
Planification: taux d'occupation par cellule (jobs assignés / heures du shift)
...
Chaque cellule techĂjour avec un shift affiche, sous le chip (J8), une mini-barre + % colorĂ©s
(vert <70, orange 70-99, rouge >=100 surbooké) + infobulle = intervalle du shift + h occupées/h.
Occupation = Σ duration_h des Dispatch Jobs planifiés assignés ce jour ÷ Σ heures du shift.
- hub: occupancyByTechDay(start,days) + GET /roster/occupancy â map 'TECH|date': heures.
- ops api: getOccupancy ; PlanificationPage: occCells (computed), cellOcc/occColor/cellInterval,
rendu barre + q-tooltip, chargé dans loadStats. Données démo semaine 8 juin (45/85/120%).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 15:13:27 -04:00
louispaulb
535c2f13bd
Ops cohérence: composants partagés TechSelect (autosuggest) + SkillSelect (chips)
...
Corrige les manques signalĂ©s: champ technicien (congĂ©s) â autosuggest typeahead; compĂ©tences
(demande de shift + Ă©diteur Ă©quipe) â chips au lieu de texte libre. Composants rĂ©utilisables
pour une UX cohérente partout (et le copilote/réassignation à venir).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 11:57:58 -04:00
louispaulb
1a4c45662a
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