From cdd72856a48f559914e8b39c5539a05db02028a2 Mon Sep 17 00:00:00 2001 From: louispaulb Date: Thu, 4 Jun 2026 20:16:05 -0400 Subject: [PATCH] =?UTF-8?q?Planification:=20application=20de=20mod=C3=A8le?= =?UTF-8?q?=20consciente=20des=20absences=20(permanent=20vs=20vacances)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- apps/ops/src/pages/PlanificationPage.vue | 27 +++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/apps/ops/src/pages/PlanificationPage.vue b/apps/ops/src/pages/PlanificationPage.vue index 0d52db2..3a7bee6 100644 --- a/apps/ops/src/pages/PlanificationPage.vue +++ b/apps/ops/src/pages/PlanificationPage.vue @@ -572,11 +572,32 @@ function saveTemplate () { }) } function deleteTemplate (i) { weekTemplates.value = weekTemplates.value.filter((_, j) => j !== i); localStorage.setItem(LS_TPL, JSON.stringify(weekTemplates.value)) } +function countPatternDays (tm, techId) { let n = 0; for (const d of dayList.value) { const map = tm.byDow[dowOf(d.iso)]; if (map && map[techId]) n++ } return n } +// Application « consciente des absences » : on n'assigne pas un tech absent ce jour-là. +// Absent toute la semaine (≈ congé permanent: maternité/blessure) → flag « à remplacer ». +// Absent quelques jours (≈ vacances) → on saute juste ces jours, le reste du patron tient. function applyTemplate (tm) { pushHistory() - for (const d of dayList.value) { const map = tm.byDow[dowOf(d.iso)]; if (!map) continue - for (const techId in map) { const tpl = tplByName.value[map[techId]]; if (!tpl) continue; const t = techs.value.find(x => x.id === techId); setCellReplace(techId, t ? t.name : techId, d.iso, tpl) } } - $q.notify({ type: 'info', message: 'Modèle « ' + tm.name + ' » appliqué — Publier pour confirmer' }) + const skipped = {}; let applied = 0 + for (const d of dayList.value) { + const map = tm.byDow[dowOf(d.iso)]; if (!map) continue + for (const techId in map) { + if (isAbsent(techId, d.iso)) { skipped[techId] = (skipped[techId] || 0) + 1; continue } + const tpl = tplByName.value[map[techId]]; if (!tpl) continue + const t = techs.value.find(x => x.id === techId); setCellReplace(techId, t ? t.name : techId, d.iso, tpl); applied++ + } + } + const fullOut = []; const partial = [] + for (const techId in skipped) { + const t = techs.value.find(x => x.id === techId); const name = (t ? t.name : techId) + const type = absByTechDay.value[techId + '|' + (dayList.value.find(d => isAbsent(techId, d.iso)) || {}).iso] || '' + const lbl = name + (type ? ' (' + type + ')' : '') + if (skipped[techId] >= countPatternDays(tm, techId)) fullOut.push(lbl); else partial.push(lbl) + } + let msg = 'Modèle « ' + tm.name + ' » appliqué (' + applied + ' assignations)' + if (partial.length) msg += ' · absence partielle ignorée : ' + partial.join(', ') + if (fullOut.length) msg += ' · ABSENT toute la semaine — à remplacer : ' + fullOut.join(', ') + $q.notify({ type: fullOut.length ? 'warning' : 'positive', message: msg, timeout: fullOut.length ? 9000 : 4500, multiLine: true }) } // édition + sélection