Terminplaner: Verfuegbarkeit, Abwesenheit schlaegt Sonderoeffnung, waehleRessource ignoriert abgelaufene Haltungen

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-03 08:17:43 +00:00
1 parent cce6e64dd1
commit 4def5c735d
2 files changed
+48 -10

No files matched your search

+11 -8
View File
@@ -7,10 +7,10 @@ import { heute, monatInfo, plusTage, wochentag, zuUtc } from './zeit.js'
* sind UTC-Zeitpunkte und werden nur als Zeitpunkte verglichen (nie je Kalendertag), damit eine Belegung vom Vortag
* (22:00 bis 06:00) und die Zeitumstellung stimmen.
*
* Rangfolge fuer die Fenster eines Tages: Sonderoeffnung > Abwesenheit > Feiertag > Plan.
* Eine Sonderoeffnung gilt fuer alle Ressourcen und ersetzt Plan, Feiertag und Abwesenheit (leere Liste = geschlossen).
* Sonst schliesst eine Abwesenheit (Betrieb: ressourceId null) die Ressource, dann ein Feiertag (wenn
* feiertageGeschlossen), sonst gilt der Wochenplan.
* Fenster eines Tages: Oeffnungsfenster aus dem Wochenplan der Ressource oder aus der Sonderoeffnung des Datums
* (gilt fuer alle Ressourcen, ersetzt Plan und Feiertagssperre; leere Liste = geschlossen), minus Feiertag (wenn
* feiertageGeschlossen und keine Sonderoeffnung), minus Abwesenheiten: eine Abwesenheit der Ressource oder des
* Betriebs (ressourceId null) nimmt den Tag der betroffenen Ressourcen immer heraus, auch an einem Sonderoeffnungstag.
*/
const MIN = 60000
@@ -184,8 +184,8 @@ function tagZeiten(ctx, tag, nurPruefen) {
const treffer = new Map() // ms -> Eintrag
for (const r of ctx.ressourcen) {
let fenster = sonder
if (fenster === null) fenster = feiertagZu || abwesend(e.abwesenheiten, r.id, tag) ? [] : (r.plan?.[wt] || [])
let fenster = []
if (!abwesend(e.abwesenheiten, r.id, tag)) fenster = sonder ?? (feiertagZu ? [] : (r.plan?.[wt] || []))
const belegtR = ctx.belegt.get(r.id) || []
for (const f of Array.isArray(fenster) ? fenster : []) {
const von = minuten(f?.[0])
@@ -240,14 +240,17 @@ export function freieTage(parameter) {
/**
* Wahl unter mehreren freien Ressourcen ('egal'): die mit den wenigsten Buchungen an dem Tag; bei Gleichstand die
* in der Einstellung zuerst genannte. Abgesagte, abgelehnte und verfallene Buchungen sowie Sperren zaehlen nicht.
* Keine Kandidaten => null.
* Mit now (optional) zaehlt eine Haltung nur, solange heldUntil > now. Keine Kandidaten => null.
*/
export function waehleRessource(ids, buchungenAmTag, einstellung) {
export function waehleRessource(ids, buchungenAmTag, einstellung, now = null) {
if (now !== null) pruefeNow(now, 'waehleRessource')
const jetztMs = now === null ? null : now.getTime()
const kandidaten = [...new Set((Array.isArray(ids) ? ids : []).filter((id) => typeof id === 'string'))]
if (kandidaten.length === 0) return null
const anzahl = new Map(kandidaten.map((id) => [id, 0]))
for (const b of Array.isArray(buchungenAmTag) ? buchungenAmTag : []) {
if (!b || b.quelle === 'sperre' || NICHT_BELEGT.has(b.status) || !anzahl.has(b.ressourceId)) continue
if (jetztMs !== null && b.status === 'gehalten' && !istBelegend(b, jetztMs)) continue
anzahl.set(b.ressourceId, anzahl.get(b.ressourceId) + 1)
}
const rang = new Map((einstellung?.ressourcen || []).map((r, i) => [r?.id, i]))