Öffnungszeiten: Freischalten erst mit eingetragenen Zeiten
Der 5-Minuten-Job setzt Öffnungszeiten live nach dem Schließen des Tickets nur noch auf active, wenn der Kunde Zeiten eingetragen hat (Haken freischaltbar: Hauptplan gespeichert, mindestens ein Tag nicht "zu"; Lesefehler ergeben false, das Dokument bleibt in setup). Neuer Register-Haken nachFreischaltung: runActivation ruft ihn je freigeschaltetem Dokument vor der K16 auf, Fehler werden nur geloggt; für die Zeiten merkt er den Ersatz-Hash (wochenplanHash). Selbstheilung (Spec 3.2): im Lauf des Jobs (nicht in der Projektliste mit customerId) holt holeZeitenNach für Zeiten in setup fehlendes Ticket und K24 nach, je Dokument abgesichert und ohne Kundendaten im Log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
47ae572fff
commit
11dc4b2c9f
5 files changed
+476
-11
No files matched your search
@@ -7,8 +7,8 @@ import { zeitenFuerKunde } from './zeiten/schalter.js'
|
||||
// termine/schalter.js und zeiten/schalter.js, die nur config lesen): Standard-Haken laden ihre Dienste per dynamischem import()
|
||||
// innerhalb der Funktion (sonst entstuenden Importzyklen).
|
||||
|
||||
/** Namen der Haken, die ein Registereintrag hat (optional): Bestell-, Freischalt- und Unterlagenpruefungen. */
|
||||
const HAKEN_NAMEN = ['verfuegbar', 'bestellpruefung', 'unterlagenBereit', 'belehrung', 'freischaltbar']
|
||||
/** Namen der Haken, die ein Registereintrag hat (optional): Bestell-, Freischalt- und Unterlagenpruefungen, dazu nachFreischaltung. */
|
||||
const HAKEN_NAMEN = ['verfuegbar', 'bestellpruefung', 'unterlagenBereit', 'belehrung', 'freischaltbar', 'nachFreischaltung']
|
||||
|
||||
/**
|
||||
* Bestellpruefung des Terminplaners im Checkout: die offenen Punkte des Entwurfs (Einstellung und Fragebogen aus
|
||||
@@ -38,6 +38,35 @@ async function termineFreischaltbar(doc) {
|
||||
return (await ladeEinstellung(doc.$id)) !== null
|
||||
}
|
||||
|
||||
/**
|
||||
* Freischaltpruefung der Oeffnungszeiten (Spec 4.4): die Einrichtung ist erst freizugeben, wenn der Kunde Zeiten eingetragen hat, also
|
||||
* ein Hauptplan gespeichert ist und mindestens ein Wochentag nicht "zu" ist (modusUndFenster: auch ein unlesbarer Eintrag zaehlt als zu).
|
||||
* Fail-closed: jeder Fehler (Lesefehler, kaputte Daten) ergibt false und bleibt im Log (ohne Kundendaten), das Dokument bleibt in
|
||||
* 'setup' und der naechste Lauf des 5-Minuten-Jobs fragt erneut. Der Aufrufer uebergibt das unter der Sperre frisch gelesene Dokument.
|
||||
*/
|
||||
async function zeitenFreischaltbar(doc) {
|
||||
try {
|
||||
const [{ ladeZeiten }, { hauptplan, modusUndFenster }] = await Promise.all([import('./zeiten/speicher.js'), import('./zeiten/zeitlogik.js')])
|
||||
const haupt = hauptplan((await ladeZeiten(doc.$id))?.daten ?? null)
|
||||
if (!haupt) return false
|
||||
return [1, 2, 3, 4, 5, 6, 7].some((tag) => modusUndFenster(haupt.tage?.[tag]).modus !== 'zu')
|
||||
} catch (err) {
|
||||
console.error(`[funktionen] Öffnungszeiten ${doc?.$id}: Zeiten für die Freischaltung nicht prüfbar:`, err.message)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nach der Freischaltung der Oeffnungszeiten (Spec 4.4): den Hash des Hauptplan-Wochenplans als ersatzHash merken. Das Ersatz-HTML,
|
||||
* das das Team beim Einbau setzt, zeigt diesen Wochenplan; weicht er beim Abschalten ab, entsteht das Ticket "Ersatz-Tabelle
|
||||
* aktualisieren". setzeErsatzHash nimmt die Sperre zeiten:<projekt> selbst (hier nicht halten) und fasst Daten und Versionen nicht an.
|
||||
* Wirft bei Lese- und Schreibfehlern; der Aufrufer (runActivation) loggt und laesst Freischaltung und K16 davon unberuehrt.
|
||||
*/
|
||||
async function zeitenNachFreischaltung(doc) {
|
||||
const [{ ladeZeiten, setzeErsatzHash }, { wochenplanHash }] = await Promise.all([import('./zeiten/speicher.js'), import('./zeiten/ersatz.js')])
|
||||
await setzeErsatzHash(doc, wochenplanHash((await ladeZeiten(doc.$id))?.daten ?? null))
|
||||
}
|
||||
|
||||
/**
|
||||
* Platzhalter der Widerrufsbelehrung mit Muster-Widerrufsformular, die die Bestellseite vor dem Knopf zeigt und der
|
||||
* Zustimmungsnachweis speichert. Block F (Task F7) ersetzt den Haken belehrung durch widerrufsbelehrungFunktion().
|
||||
@@ -60,12 +89,13 @@ const STANDARD_HAKEN = {
|
||||
freischaltbar: termineFreischaltbar,
|
||||
},
|
||||
// Oeffnungszeiten live: keine Bestellpruefung (die Einstellung entsteht erst im Editor); belehrung und
|
||||
// unterlagenBereit wie beim Terminplaner; freischaltbar ist ein Platzhalter (Task 18 ersetzt ihn)
|
||||
// unterlagenBereit wie beim Terminplaner; freischaltbar: erst mit eingetragenen Zeiten; nachFreischaltung: Ersatz-Hash merken
|
||||
zeiten: {
|
||||
verfuegbar: (email) => zeitenFuerKunde(email),
|
||||
unterlagenBereit: async () => true,
|
||||
belehrung: async () => BELEHRUNG_PLATZHALTER,
|
||||
freischaltbar: async () => true,
|
||||
freischaltbar: zeitenFreischaltbar,
|
||||
nachFreischaltung: zeitenNachFreischaltung,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -89,10 +119,12 @@ export function ticketFreischaltungKeys() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Haken einer Funktion: { verfuegbar?, bestellpruefung?, unterlagenBereit?, belehrung?, freischaltbar? }.
|
||||
* Haken einer Funktion: { verfuegbar?, bestellpruefung?, unterlagenBereit?, belehrung?, freischaltbar?, nachFreischaltung? }.
|
||||
* Wer config.features.<key>.<haken> als Funktion setzt (Tests), ueberschreibt den Standard.
|
||||
* freischaltbar(doc) => Promise<boolean>: darf das Dokument (Zustand 'setup', Ticket geschlossen) jetzt aktiv werden?
|
||||
* Nur true gibt frei; false und jeder Fehler halten es in 'setup' (siehe activateClosedTickets).
|
||||
* nachFreischaltung(doc) => Promise<void>: Nacharbeit nach der Freischaltung (doc ist das aktive Dokument); runActivation ruft sie
|
||||
* vor der K16 und faengt jeden Fehler (Log), Freischaltung und K16 haengen nie davon ab.
|
||||
*/
|
||||
export function featureHaken(key) {
|
||||
const eintrag = featureConfig(key)
|
||||
|
||||
@@ -1037,10 +1037,51 @@ export async function handleFeatureCheckoutEvent(event) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Freischalt-Job: geschlossene Einrichtungs-Tickets -> 'active', K16 an jeden betroffenen Kunden. */
|
||||
/**
|
||||
* Selbstheilung der Oeffnungszeiten (Spec 3.2): fuer jedes Dokument der Zeiten in 'setup' holt holeZeitenNach fehlende Schritte
|
||||
* nach (Neubau, Einbau-Ticket, K24; es sperrt je Dokument selbst und fasst Kauf, aktiv und aus nicht an). Hierher und nicht in
|
||||
* activateClosedTickets: dort zaehlen nur Dokumente MIT Ticket. Jedes Dokument fuer sich abgesichert (ein Fehler stoppt weder die
|
||||
* uebrigen noch den Job; der naechste Lauf versucht es erneut), das Log nennt Dokument-ID und Fehler, nie Kundendaten.
|
||||
* Dynamischer Import: zeiten/* importiert dieses Modul.
|
||||
*/
|
||||
async function heileZeiten({ now }) {
|
||||
if (!featureConfig('zeiten')) return
|
||||
let docs
|
||||
try {
|
||||
docs = await listDocuments(config.collections.portalFeatures, [Query.equal('featureKey', 'zeiten'), Query.equal('state', 'setup'), Query.limit(1000)])
|
||||
} catch (err) {
|
||||
console.error('[funktionen] Selbstheilung Öffnungszeiten: Dokumente nicht lesbar:', err.message)
|
||||
return
|
||||
}
|
||||
if (docs.length === 0) return
|
||||
const { holeZeitenNach } = await import('./zeiten/einschalten.js')
|
||||
for (const doc of docs) {
|
||||
try {
|
||||
await holeZeitenNach(doc, { now })
|
||||
} catch (err) {
|
||||
console.error(`[funktionen] Selbstheilung Öffnungszeiten (${doc.$id}) fehlgeschlagen:`, [err?.name ?? 'Fehler', err?.status, err?.message].filter(Boolean).join(' '))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Freischalt-Job: geschlossene Einrichtungs-Tickets -> 'active' (je Funktion nur, wenn ihr Haken freischaltbar es erlaubt; Oeffnungszeiten:
|
||||
* erst mit eingetragenen Zeiten), danach je Dokument der Haken nachFreischaltung (Oeffnungszeiten: Ersatz-Hash) und K16 an jeden
|
||||
* betroffenen Kunden. Zum Schluss, nur im Lauf des Jobs (ohne customerId), die Selbstheilung der Oeffnungszeiten (heileZeiten): die
|
||||
* Projektliste eines Kunden (GET /api/funktionen, mit customerId) schaltet nur frei und baut, bestellt und sendet nichts nach.
|
||||
*/
|
||||
export async function runActivation({ now = new Date(), customerId = null } = {}) {
|
||||
const activated = await activateClosedTickets({ now, customerId })
|
||||
for (const doc of activated) {
|
||||
// Nacharbeit vor der K16 und vor dem Adress-Check: auch ein Kunde ohne Adresse bekommt sie; ein Fehler bricht nichts ab
|
||||
const { nachFreischaltung } = featureHaken(doc.featureKey)
|
||||
if (typeof nachFreischaltung === 'function') {
|
||||
try {
|
||||
await nachFreischaltung(doc)
|
||||
} catch (err) {
|
||||
console.error(`[funktionen] Nacharbeit nach der Freischaltung ${doc.featureKey} (${doc.$id}) fehlgeschlagen:`, err.message)
|
||||
}
|
||||
}
|
||||
try {
|
||||
const customer = await customerOf(doc.customerId)
|
||||
if (!customer?.email) continue
|
||||
@@ -1054,5 +1095,6 @@ export async function runActivation({ now = new Date(), customerId = null } = {}
|
||||
console.error(`[funktionen] K16 an Kunde ${doc.customerId} fehlgeschlagen:`, err.message)
|
||||
}
|
||||
}
|
||||
if (!customerId) await heileZeiten({ now })
|
||||
return activated
|
||||
}
|
||||
Reference in new issue
Block a user