Checkout je Funktion: Vorpruefungen in der Reihenfolge der Spezifikation

POST /api/funktionen/:key/checkout ersetzt /news/checkout (der News-Pfad bleibt als
key = news erhalten). Stufen ohne Seiteneffekt: 1 Kundenansicht (403), 2 Schluessel
gegen das Register (404), 3 Zustimmung (400 zustimmung_fehlt, 409 fassung_veraltet mit
der Serverfassung; News weiter mit consent: true), 4 Projekt (400/403; bei fortsetzen
muss das Dokument ordered sein), 5 Schalter (409 nicht_verfuegbar), 5b Unterlagen
(503 unterlagen_fehlen), 6 Bestellpruefung (409 bestellung_offen mit offen), 7 Wartungs-Abo
(409 kein_abo | gekuendigt | nicht_aktiv, Lesefehler 500). fail() gibt err.body weiter.

featureOrder.js: pruefeZustimmung, istFortsetzen, aboMeldung (einzige Quelle der
Abo-Hinweistexte), ladeEntwurf, pruefeAbo, orderDeps. featureRegistry.js: featureSperre
und die Standard-Haken verfuegbar, bestellpruefung (mitAbo: false, ohne abo) und
unterlagenBereit des Terminplaners. Der Rest der Route (Sperre, Zustand, Sitzung,
Nachweis) bleibt bis Task B7 nur fuer News; andere Funktionen enden mit 503.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-04 12:25:09 +00:00
1 parent d568a3798d
commit ded6bb2a77
5 files changed
+960 -11

No files matched your search

+43 -5
View File
@@ -1,19 +1,42 @@
import { config } from '../config.js'
import { termineFuerKunde } from './termine/schalter.js'
// Helfer fuer das Funktionen-Register config.features (News-Pinnwand, Terminplaner; Daten in server/config.js).
// Diese Datei wird von siteFeatures.js importiert und importiert selbst keine Dienste statisch: Standard-Haken
// laden ihre Dienste per dynamischem import() innerhalb der Funktion (sonst entstuenden Importzyklen).
// Diese Datei wird von siteFeatures.js importiert und importiert selbst keine Dienste statisch (einzige Ausnahme:
// termine/schalter.js, das nur config liest): 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']
/**
* Standard-Haken je Funktion (Funktionen, nicht Daten). Leer in Task B1; es fuellen sie B6 (verfuegbar,
* bestellpruefung, unterlagenBereit), B7 (belehrung) und B11 (freischaltbar). News hat keine Standard-Haken.
* Bestellpruefung des Terminplaners im Checkout: die offenen Punkte des Entwurfs (Einstellung und Fragebogen aus
* termineConfig; ohne Dokument beides null) nach termine/fragebogen.js. Ohne abo und mit mitAbo: false: den Abo-Punkt (h)
* wendet der Checkout nicht an, die Abo-Stufe (7) der Route liefert kein_abo | gekuendigt | nicht_aktiv.
*/
async function termineBestellpruefung({ customerId, projectId, feature }) {
const [{ getFeatureDoc }, { ladeEntwurf }, { bestellpruefung }] = await Promise.all([
import('./siteFeatures.js'),
import('./featureOrder.js'),
import('./termine/fragebogen.js'),
])
const doc = await getFeatureDoc(customerId, projectId, 'termine')
const { einstellung, fragebogen } = doc ? await ladeEntwurf(doc.$id) : { einstellung: null, fragebogen: null }
return bestellpruefung({ einstellung, fragebogen, feature, mitAbo: false })
}
/**
* Standard-Haken je Funktion (Funktionen, nicht Daten). B6 fuellt verfuegbar, bestellpruefung und unterlagenBereit
* (Standard immer bereit; F8 haengt die Rechtsunterlagen ein), B7 belehrung und B11 freischaltbar. News hat keine
* Standard-Haken. Feste Funktionen, damit featureHaken bei jedem Aufruf dieselben liefert.
*/
const STANDARD_HAKEN = {
news: {},
termine: {},
termine: {
verfuegbar: (email) => termineFuerKunde(email),
bestellpruefung: termineBestellpruefung,
unterlagenBereit: async () => true,
},
}
/** Registereintrag oder null; nur eigene Schluessel des Registers ('analyse', '__proto__', 'toString' => null). */
@@ -43,6 +66,21 @@ export function featureHaken(key) {
return haken
}
const NICHT_VERFUEGBAR = 'Diese Funktion ist noch nicht verfügbar.'
/**
* Pruefstufe 5 des Checkouts: Text, warum die Funktion diesem Kunden (noch) nicht angeboten wird, sonst null.
* Gefragt wird der Haken verfuegbar(email) (Terminplaner: Schalter TERMINE_ENABLED und Pilotliste); Funktionen ohne
* Haken (News) sind immer verfuegbar. Ein unbekannter Schluessel ist nicht verfuegbar (fail-closed).
*/
export function featureSperre(key, email) {
const eintrag = featureConfig(key)
if (!eintrag) return NICHT_VERFUEGBAR
const { verfuegbar } = featureHaken(key)
if (typeof verfuegbar !== 'function' || verfuegbar(email)) return null
return eintrag.unavailableMessage || NICHT_VERFUEGBAR
}
const fassung = (f) => (f ? { version: f.version, url: f.url ?? '' } : null)
/**