fix(planif): afficher les congés en attente dans le résumé de Publier

Le résumé de « Publier l'horaire » (pubSummary) était construit UNIQUEMENT à
partir des quarts non publiés (unpublished) et ignorait pendingAbs. Un congé
mis en attente (ex. Josée-Anne, congé indéterminé) allumait bien le badge
« non publié » ET était bien envoyé au Publier (flushPendingAbsences), mais
n'apparaissait PAS dans le dialogue de confirmation — on n'y voyait que le
changement de quart (Nathan Morrisseau). Le répartiteur ne pouvait donc pas
réviser le congé avant de confirmer.

pubSummary intègre désormais pendingAbs, groupé par date, avec compteurs
absAdded/absRemoved ; l'en-tête affiche « N quart(s) · M congé(s) » et chaque
jour liste les congés (event_busy orange = ajout · event_available teal =
retrait) à côté des quarts.

Vérifié (aperçu, client-only, rien écrit) : congé indéfini Josée-Anne 13-17/07
→ résumé « 1 quart(s) · 5 congé(s) », lignes Congé par jour à côté du quart de
Nathan Morrisseau.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
louispaulb 2026-07-16 12:29:31 -04:00
parent 6761c9e05a
commit 9d568986fc

View File

@ -1338,12 +1338,13 @@
<q-space /><q-btn flat round dense icon="close" v-close-popup />
</q-card-section>
<q-card-section class="q-pt-sm">
<div class="text-body2 q-mb-sm"><b class="text-positive">{{ pubSummary.added }}</b> ajout(s) · <b class="text-negative">{{ pubSummary.removed }}</b> retrait(s) · <b>{{ notifySms ? pubSummary.added + ' SMS aux techs' : 'sans SMS' }}</b></div>
<div class="text-body2 q-mb-sm"><b class="text-positive">{{ pubSummary.added }}</b> quart(s) · <b v-if="pubSummary.absAdded" class="text-orange-8">{{ pubSummary.absAdded }}</b><span v-if="pubSummary.absAdded"> congé(s)</span><span v-if="pubSummary.absRemoved"> · <b class="text-teal-7">{{ pubSummary.absRemoved }}</b> congé(s) retiré(s)</span> · <b>{{ notifySms ? pubSummary.added + ' SMS aux techs' : 'sans SMS' }}</b></div>
<q-list dense bordered style="border-radius:8px;max-height:44vh;overflow:auto">
<template v-for="d in pubSummary.days" :key="d.date">
<q-item-label header class="q-py-xs text-weight-medium">{{ fmtDueLabel(d.date) }}</q-item-label>
<q-item v-for="(a, i) in d.add" :key="'a' + i" dense><q-item-section avatar style="min-width:24px"><q-icon name="add" color="positive" size="16px" /></q-item-section><q-item-section>{{ a.name }}<span class="text-grey-6"> · {{ a.shift }}</span></q-item-section></q-item>
<q-item v-for="(r, i) in d.rem" :key="'r' + i" dense><q-item-section avatar style="min-width:24px"><q-icon name="remove" color="negative" size="16px" /></q-item-section><q-item-section>{{ r.name }}<span class="text-grey-6"> · {{ r.shift }}</span></q-item-section></q-item>
<q-item v-for="(ab, i) in d.abs" :key="'ab' + i" dense><q-item-section avatar style="min-width:24px"><q-icon :name="ab.op === 'set' ? 'event_busy' : 'event_available'" :color="ab.op === 'set' ? 'orange-8' : 'teal-7'" size="16px" /></q-item-section><q-item-section>{{ ab.name }}<span class="text-grey-6"> · {{ ab.op === 'set' ? (ab.type || 'Congé') : 'congé retiré' }}</span></q-item-section></q-item>
</template>
</q-list>
</q-card-section>
@ -4003,11 +4004,20 @@ const pubConfirm = ref(false)
const pubSummary = computed(() => {
const nameOf = id => { const t = (techs.value || []).find(x => x.id === id); return (t && t.name) || id }
const byDate = {}
const bucket = date => (byDate[date] = byDate[date] || { date, add: [], rem: [], abs: [] })
for (const a of unpublished.value) {
const d = (byDate[a.date] = byDate[a.date] || { date: a.date, add: [], rem: [] })
d.add.push({ tech: a.tech, date: a.date, shift: a.shift_name || a.shift, name: nameOf(a.tech), status: a.status })
bucket(a.date).add.push({ tech: a.tech, date: a.date, shift: a.shift_name || a.shift, name: nameOf(a.tech), status: a.status })
}
return { added: unpublished.value.length, removed: 0, days: Object.values(byDate).sort((x, y) => String(x.date).localeCompare(String(y.date))) }
// CONGÉS / ABSENCES en attente (pendingAbs) : ils comptent dans « non publié » et sont bien envoyés au Publier
// (flushPendingAbsences) donc ils DOIVENT figurer dans le résumé (sinon un congé indéfini reste invisible, ex. Josée-Anne).
let absAdded = 0; let absRemoved = 0
for (const [k, v] of Object.entries(pendingAbs.value || {})) {
const [tid, iso] = k.split('|')
const set = v && v.op === 'set'
bucket(iso).abs.push({ tech: tid, date: iso, name: nameOf(tid), type: set ? (v.type || 'Congé') : null, op: set ? 'set' : 'remove' })
if (set) absAdded++; else absRemoved++
}
return { added: unpublished.value.length, removed: 0, absAdded, absRemoved, days: Object.values(byDate).sort((x, y) => String(x.date).localeCompare(String(y.date))) }
})
const holSet = computed(() => new Set(holidays.value))