Roster publish: diff au lieu de wipe+recreate → publication quasi instantanée

Avant: /roster/publish-week supprimait TOUTES les assignations de la semaine puis les recréait toutes
(~2N écritures ERPNext séquentielles → plusieurs secondes/dizaines de s). Maintenant: diff par clé
tech|date|shift — supprime seulement les retirées, crée seulement les nouvelles, ignore les inchangées.
Republier sans changement: 87 assignations → 0 écriture, 37 ms (vs ~174 écritures avant). Une modif
de quelques cellules = quelques écritures seulement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
louispaulb 2026-06-04 21:20:03 -04:00
parent 16325ed967
commit b9d4d46d1c

View File

@ -677,10 +677,18 @@ async function handle (req, res, method, path, url) {
if (path === '/roster/publish-week' && method === 'POST') {
const b = await parseBody(req)
const existing = await fetchAssignments(b.start, b.days || 7)
let deleted = 0
for (const a of existing) { const r = await retryWrite(() => erp.remove('Shift Assignment', a.name)); if (r.ok) deleted++ }
let created = 0; let errors = 0
for (const a of (b.assignments || [])) {
const desired = b.assignments || []
// DIFF par clé tech|date|shift : on ne touche QUE ce qui a changé (≫ rapide vs wipe+recreate complet).
const keyOf = (a) => a.tech + '|' + a.date + '|' + a.shift
const existByKey = {}; for (const a of existing) existByKey[keyOf(a)] = a
const desiredKeys = new Set(desired.map(keyOf))
let deleted = 0; let created = 0; let errors = 0; let unchanged = 0
for (const a of existing) { // supprimer ceux qui ne sont plus voulus
if (desiredKeys.has(keyOf(a))) continue
const r = await retryWrite(() => erp.remove('Shift Assignment', a.name)); if (r.ok) deleted++
}
for (const a of desired) { // créer seulement les nouveaux ; ignorer les inchangés
if (existByKey[keyOf(a)]) { unchanged++; continue }
const r = await retryWrite(() => erp.create('Shift Assignment', {
technician: a.tech, technician_name: a.tech_name || '', assignment_date: a.date,
shift_template: a.shift, zone: a.zone || '', hours: Number(a.hours) || 0,
@ -704,7 +712,7 @@ async function handle (req, res, method, path, url) {
}
} catch (e) { /* notif non bloquante */ }
}
return json(res, 200, { ok: errors === 0, created, deleted, errors, notified })
return json(res, 200, { ok: errors === 0, created, deleted, errors, notified, unchanged })
}
// Modifier / supprimer un type de shift (Shift Template)
const mTpl = path.match(/^\/roster\/template\/(.+)$/)