TP2 Abschlussprüfung: Fragebogen und Bestellseite (veralteter Tab, Abo-Hinweis, Zurück aus Stripe)
- PUT /fragebogen: ein Tab mit veralteter Branche bekommt 409 EINSTELLUNG_VERALTET (die Branche wechselt nur die Vorlage), bestaetigt wird mit dem gespeicherten Stand vereinigt; die ungeprüften Vorlagenpreise können nicht mehr als geprüft gelten - GET /einstellungen liefert in off aboHinweis (aboMeldung, auch bei nicht lesbarem Abo); die Hinweiskarte zeigt ihn immer und hat „Neu laden“ - Bestellseite und Statuskarte laden bei pageshow (persisted) neu, wenn der Browser sie nach der Zahlungsseite aus dem bfcache holt - renderBestellen zeichnet „Ändern“ und „Zum Schritt“ nur mit zumSchritt; nach einem 409 bekommt die Meldung den Fokus - Zusammenfassung nennt „Kleinunternehmer: ja/nein“ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2fc48df915
commit
5f99f08a39
8 files changed
+314
-39
No files matched your search
@@ -15,8 +15,8 @@ import { EXPORT_SEITE, exportSeite, hole, imZeitraum, zaehleAnfragen, zaehleKuen
|
||||
import { einbauSnippet } from '../services/termine/einbauanleitung.js'
|
||||
import { fehlendePflichtangaben, neuerFeedToken, normalisiereEinstellung } from '../services/termine/einstellungen.js'
|
||||
import { loeschTag, loeschzeit } from '../services/termine/frist.js'
|
||||
import { BRANCHEN, bestellpruefung, bestellungAnsicht, leerFragebogen, normalisiereFragebogen } from '../services/termine/fragebogen.js'
|
||||
import { kontextFuerPortal, kontextPerFeature, liveHost, speichereEinstellung, speichereFragebogen } from '../services/termine/kontext.js'
|
||||
import { BRANCHEN, SCHRITTE, bestellpruefung, bestellungAnsicht, leerFragebogen, normalisiereFragebogen } from '../services/termine/fragebogen.js'
|
||||
import { kontextFuerPortal, kontextPerFeature, liveHost, speichereEinstellung, speichereFragebogen, veraltet } from '../services/termine/kontext.js'
|
||||
import { zustellFehler } from '../services/termine/outbox.js'
|
||||
import { termineFuerKunde } from '../services/termine/schalter.js'
|
||||
import { belegungAus, freieZeiten } from '../services/termine/slots.js'
|
||||
@@ -297,7 +297,8 @@ async function aboFuerVorschau(customerId) {
|
||||
/**
|
||||
* Einstellungen und Entwurf für das Portal. Liest in jedem Zustand und auch ohne Funktionsdokument (entwurf: true).
|
||||
* Neben der Einstellung liefert die Antwort den Entwurf des Fragebogens (branchen, fragebogen, kundenansicht, betriebVorschlag
|
||||
* ohne Einstellung) und in `off` die Sicht der Bestellung: abo (bestellbar() oder null bei Lesefehler), offen (Punkte der
|
||||
* ohne Einstellung) und in `off` die Sicht der Bestellung: abo (bestellbar() oder null bei Lesefehler), aboHinweis (der Text dazu, wenn das
|
||||
* Abo nicht bestellbar oder nicht lesbar ist, sonst null), offen (Punkte der
|
||||
* Bestellprüfung inklusive Abo-Punkt (h)) und bestellung (Texte und Preis des Registers). In `ordered` liefert sie bestellung und
|
||||
* offen ebenfalls, nur lesend (Ruling R110: „Zahlung fortsetzen“ ohne Nachweis zeigt dort wieder das Bestellformular); das Abo wird
|
||||
* dort nicht gelesen (abo null), offen hat keinen Abo-Punkt (h). Einbau-Code und Kalender-Links
|
||||
@@ -324,6 +325,9 @@ router.get('/einstellungen', requireSession, withTermine({ entwurf: true }), rou
|
||||
kundenansicht: isKundenansicht(req.session),
|
||||
...(e ? {} : { betriebVorschlag: await betriebVorschlag(customerId, req.project) }),
|
||||
abo,
|
||||
// der Text zum Abo (B2): einzige Quelle aboMeldung wie GET /api/funktionen (R111). In off ohne bestellbares Abo, auch wenn es nicht lesbar war
|
||||
// oder sich zwischen den beiden Abfragen des Browsers geaendert hat; sonst null. Der Browser zeigt ihn an, er hat keine Kopie.
|
||||
aboHinweis: state === 'off' && abo?.ok !== true ? aboMeldung(register, abo?.grund ?? 'unbekannt') : null,
|
||||
offen: bestellbar ? bestellpruefung({ einstellung: e, fragebogen: ctx.fragebogen, feature: register, abo, mitAbo: state === 'off' }) : null,
|
||||
bestellung: bestellbar ? await bestellungAnsicht(register) : null,
|
||||
feeds: e && state === 'active' ? feedLinks(ctx) : {},
|
||||
@@ -462,6 +466,7 @@ const nichtInKundenansicht = route(async (req, _res, next) => {
|
||||
/**
|
||||
* Fragebogen speichern (Branche, bestätigte Schritte, Einbauwünsche; PUT ersetzt den ganzen Fragebogen). Nie in der Kundenansicht:
|
||||
* Schritte bestätigt nur der Kunde selbst (die Erlaubnisliste des Wächters kennt den Pfad nicht, hier gilt es noch einmal).
|
||||
* Veralteter Tab (die gespeicherte Branche ist eine andere): 409 `EINSTELLUNG_VERALTET`; bestaetigt wird mit dem gespeicherten Stand vereinigt.
|
||||
* Zustandsregeln wie beim Entwurf (off mit laufendem Wartungs-Abo und active ja, ordered, setup und disabled 409). Schreibt nur
|
||||
* fragebogen, updatedAt und updatedBy: die Version der Einstellung bleibt, ein offener Einstellungs-Editor kann weiter speichern.
|
||||
* Ohne Einstellung 409 `keine_einstellung`. Antwort { fragebogen, offen }; `offen` wie im GET nur in `off`. Kein Protokolleintrag.
|
||||
@@ -473,7 +478,19 @@ router.put('/fragebogen', requireSession, nichtInKundenansicht, withTermine({ sc
|
||||
|
||||
let gespeichert
|
||||
try {
|
||||
gespeichert = await speichereFragebogen(feature, () => geprueft.fragebogen, { by: von(req), now: uhr() })
|
||||
// Unter der Sperre gegen den gespeicherten Stand gelesen (ein zweiter Tab kann dazwischen gespeichert haben): die Branche muss die
|
||||
// gespeicherte sein, sonst ist dieser Tab veraltet (409 EINSTELLUNG_VERALTET; die Branche wechselt nur POST /einstellungen/vorlage,
|
||||
// und mit ihr Vorlage, Preise und Bestätigungen). Bestätigungen gehen nie verloren: bestaetigt ist die Vereinigung aus dem
|
||||
// gespeicherten und dem gesendeten Stand (zurückgesetzt werden sie nur durch eine neue Vorlage).
|
||||
gespeichert = await speichereFragebogen(
|
||||
feature,
|
||||
(bisher) => {
|
||||
if (bisher.branche && bisher.branche !== geprueft.fragebogen.branche) throw veraltet()
|
||||
const bestaetigt = SCHRITTE.filter((schritt) => bisher.bestaetigt?.includes(schritt) || geprueft.fragebogen.bestaetigt.includes(schritt))
|
||||
return { ...geprueft.fragebogen, bestaetigt }
|
||||
},
|
||||
{ by: von(req), now: uhr() },
|
||||
)
|
||||
} catch (err) {
|
||||
throw err?.code === 'keine_einstellung' ? stop(409, MELDUNG.keineEinstellung, 'keine_einstellung') : err
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user