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>
40 lines
2.1 KiB
JavaScript
40 lines
2.1 KiB
JavaScript
/**
|
||
* API d'assignation UNIFIÉE — chemin d'écriture UNIQUE (via targo-hub).
|
||
* -----------------------------------------------------------------------------
|
||
* CONVERGENCE Dispatch ⇄ Planification : l'assignation job→tech
|
||
* (`assigned_tech` / `scheduled_date` / `route_order` / `start_time` / `status`
|
||
* + l'ÉQUIPE) ne doit JAMAIS être écrite en direct dans ERPNext (PUT
|
||
* api/dispatch.js). Tout passe ici → le hub (lib/roster.js) qui valide, pose le
|
||
* first-fit `start_time`, garde la durée, le booking_status, et — après 1b —
|
||
* préserve les assistants. Un seul écrivain ⇒ plus de conflit « dernier qui
|
||
* écrit gagne » entre les deux UIs.
|
||
*
|
||
* NE PAS importer api/dispatch.js#updateJob pour ces champs. Utiliser ceci.
|
||
*/
|
||
import { HUB_URL as HUB } from 'src/config/hub'
|
||
|
||
async function jpost (path, body) {
|
||
const r = await fetch(HUB + path, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(body || {}),
|
||
})
|
||
if (!r.ok) throw new Error('Assignment API ' + r.status + ' ' + path)
|
||
return r.json()
|
||
}
|
||
|
||
// Assigner un job à un tech sur une date (le hub pose first-fit start_time + garde durée + booking_status).
|
||
export const assign = (job, tech, date) => jpost('/roster/assign-job', { job, tech, date })
|
||
|
||
// Réordonner / re-prioriser les jobs d'un tech×jour — updates = [{ job, route_order, priority? }]
|
||
export const reorder = (updates) => jpost('/roster/reorder-jobs', { updates })
|
||
|
||
// Retirer un job du tech (retour au pool non assigné).
|
||
export const unassign = (job) => jpost('/roster/unassign-job', { job })
|
||
|
||
// Équipe (lead + assistants). assistants = [{ tech_id, tech_name, duration_h, note, pinned }].
|
||
// Le LEAD reste `assigned_tech` (inchangé) ; on ne fait qu'éditer la table-enfant `assistants`.
|
||
// Route hub /roster/job/team ajoutée en 1b (qui persiste la table-enfant + recalcule l'occupation
|
||
// des assistants pinnés). Avant 1b, cet appel échoue proprement (404) — aucune vue ne l'appelle encore.
|
||
export const setTeam = (job, assistants) => jpost('/roster/job/team', { job, assistants })
|