Kundenansicht P5: Katalogfelder, consentAbo mit Hinweis und Unterlagen-Quelle im Funktionen-Register

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-16 15:55:19 +00:00
1 parent 8e0d2b2736
commit 4bf1b67e67
4 files changed
+268 -1

No files matched your search

+96
View File
@@ -0,0 +1,96 @@
import { test, after } from 'node:test'
import assert from 'node:assert/strict'
import { startAppwriteMock } from './support/appwriteMock.js'
import { startFakeStripe } from './support/fakeStripe.js'
import { useTestEnv } from './support/testEnv.js'
// Katalogfelder, consentAbo (mit Hinweis) und die Unterlagen-Quelle im Funktionen-Register (P5, V5)
const aw = await startAppwriteMock()
const st = await startFakeStripe()
after(() => Promise.all([aw.close(), st.close()]))
useTestEnv({ appwriteUrl: aw.url, stripeUrl: st.url })
const { config } = await import('../server/config.js')
const reg = await import('../server/services/featureRegistry.js')
const { unterlagenFuer, analyseUnterlagen } = await import('../server/services/aboUnterlagen.js')
const KEYS = ['news', 'termine', 'shop', 'unterkunft', 'zeiten']
test('Reihenfolge und Felder je Funktion', () => {
assert.deepEqual(reg.katalogReihenfolge(), [...KEYS, 'analyse'])
const ablauf = { news: 'direkt', termine: 'fragebogen', shop: 'anfrage', unterkunft: 'anfrage', zeiten: 'direkt', analyse: 'direkt' }
for (const key of [...KEYS, 'analyse']) {
const f = reg.katalogFelder(key)
assert.deepEqual(Object.keys(f).sort(), ['ablauf', 'beschreibung', 'bild', 'einrichtung', 'nurBetrieb'])
assert.deepEqual([f.bild, f.ablauf, f.nurBetrieb], [`/neu/bilder/${key}.webp`, ablauf[key], key === 'shop'], key)
assert.ok(f.beschreibung.split(/(?<=[.!?])\s+/).length <= 2, 'höchstens zwei Sätze')
assert.doesNotMatch(f.beschreibung + f.einrichtung, /€|\bSie\b|\bIhre?[nmrs]?\b/, 'kein Preis, keine Sie-Form')
}
assert.equal(reg.katalogFelder('shop').einrichtung, 'meist in 2–3 Wochen')
assert.equal(reg.katalogFelder('gibtEsNicht'), null)
// die festen Werte der Tabelle
const einrichtung = { news: 'meist in 1–2 Wochen', termine: 'meist in 1–2 Wochen', shop: 'meist in 2–3 Wochen', unterkunft: 'meist in 1–2 Wochen', zeiten: 'meist in wenigen Tagen', analyse: 'meist in wenigen Tagen' }
for (const [key, text] of Object.entries(einrichtung)) assert.equal(reg.katalogFelder(key).einrichtung, text, key)
assert.equal(reg.katalogFelder('news').beschreibung, 'Zeig Neuigkeiten und Aktionen direkt auf deiner Website. Du schreibst sie im Portal, sie erscheinen sofort.')
assert.equal(reg.katalogFelder('analyse').beschreibung, 'Sieh, wie viele Besucher auf deine Website kommen und welche Seiten sie ansehen. Die Auswertung findest du direkt im Portal.')
})
const HINWEIS = { // Pflichten der alten Häkchen verantwortung, stripe, gesundheit; wörtlich wie WORTLAUT_V6.hinweis (P8)
termine: 'Der Terminplaner ist nicht für den Gesundheitsbereich gedacht. Das fragen wir im Fragebogen ab.',
shop: 'Du verkaufst in eigenem Namen und bist für deine Produkte, Preise und Rechtstexte verantwortlich. Die Zahlungen deiner Käufer laufen über dein eigenes Stripe-Konto.',
unterkunft: 'Du vermietest in eigenem Namen und bist für Preise, Stornobedingungen, Rechnungen und Meldepflichten verantwortlich. Online-Zahlungen deiner Gäste laufen über dein eigenes Stripe-Konto.',
}
test('consentAbo: Linkzeile mit Fassung, Hinweis (termine, shop, unterkunft), beginn als Entwurf, kein Häkchen gesundheit', () => {
const V = config.aboFunktionen.fassung
for (const key of KEYS) {
const c = reg.consentAbo(key)
const ids = key in HINWEIS ? ['einschalten-zeile', 'hinweis', 'beginn'] : ['einschalten-zeile', 'beginn']
assert.deepEqual([c.version, c.knopf, c.items.map((i) => i.id)], [V, 'Einschalten', ids], key)
assert.deepEqual(c.items.map((i) => i.haken), ids.map((id) => id === 'beginn'), `${key}: nur beginn ist ein Häkchen`)
assert.deepEqual([c.items.at(-1).text, c.items.at(-1).nurPrivatInFrist], [config.aboFunktionen.texte.beginn, true], key)
if (key in HINWEIS) assert.equal(c.items[1].text, HINWEIS[key], key)
}
assert.equal(config.aboFunktionen.texte.beginn, 'Bitte beginnt sofort mit der Einrichtung. Mir ist klar: Mit der vollständigen Einrichtung erlischt mein Widerrufsrecht, und wenn ich vorher widerrufe, zahle ich den bis dahin erbrachten Teil.')
assert.equal(V, '2026-10-16')
assert.equal(reg.consentAbo('termine').items[0].text, `Es gelten Leistungsbeschreibung und Auftragsverarbeitung (Fassung ${config.termine.avvVersion}).`)
assert.equal(reg.consentAbo('zeiten').items[0].text, 'Es gilt die Leistungsbeschreibung (Fassung 2026-10-04).')
assert.equal(reg.consentAbo('news').items[0].text, `Es gilt die Leistungsbeschreibung (Fassung ${config.termine.avvVersion}).`)
assert.ok(!reg.consentAbo('termine').items.some((i) => i.id === 'gesundheit'), 'das Häkchen gesundheit entfällt, der Satz steht als Hinweis')
assert.doesNotMatch(JSON.stringify(Object.values(HINWEIS)), /€|\bSie\b|\bIhre?[nmrs]?\b/)
assert.equal(reg.consentAbo('analyse'), null)
assert.equal(reg.consentAbo('gibtEsNicht'), null)
})
test('consentAboAktiv und aboweg zeigen nur, was verlangt ist; das alte Register bleibt unverändert', () => {
assert.deepEqual(reg.consentAboAktiv('shop').items.map((i) => i.id), ['einschalten-zeile', 'hinweis'])
assert.deepEqual(reg.consentAboAktiv('news').items.map((i) => i.id), ['einschalten-zeile'])
assert.deepEqual(reg.consentAboAktiv('shop', { beginn: true }).items.map((i) => [i.id, i.haken]), [['einschalten-zeile', false], ['hinweis', false], ['beginn', true]])
const w = reg.aboweg(reg.featureConfig('termine'), { beginn: true })
assert.deepEqual([w.consent.version, w.widerruf, w.avv.version, w.leistungsbeschreibung.version, w.key], [config.aboFunktionen.fassung, null, config.termine.avvVersion, config.termine.avvVersion, 'termine'])
assert.deepEqual(reg.featureConfig('termine').consent.items.map((i) => i.id), ['unterlagen', 'gesundheit', 'beginn', 'information'])
assert.notEqual(reg.featureConfig('termine').widerruf, null, 'aboweg ist eine Kopie, das Register bleibt')
assert.equal(Object.keys(reg.oeffentlicheAnsicht('termine')).length, 11, 'oeffentlicheAnsicht ohne neue Felder')
})
test('unterlagenFuer und analyseUnterlagen: eine Quelle für Katalog, Nachweis und Analyse', () => {
const t = unterlagenFuer('termine')
assert.deepEqual([t.leistungsbeschreibung, t.avv], [{ version: config.termine.avvVersion, url: config.features.termine.leistungsbeschreibung.url }, { version: config.termine.avvVersion, url: config.features.termine.avv.url }])
assert.deepEqual([unterlagenFuer('news').avv, unterlagenFuer('zeiten').avv], [null, null])
assert.ok(unterlagenFuer('news').leistungsbeschreibung.version)
const a = analyseUnterlagen()
assert.deepEqual(a, { avvVersion: config.analyse.avvVersion, legal: { lb: `/rechtliches/leistungsbeschreibung-website-analyse-${config.analyse.avvVersion}.html`, avv: `/rechtliches/avv-website-analyse-${config.analyse.avvVersion}.html` } })
assert.deepEqual(unterlagenFuer('analyse'), {
leistungsbeschreibung: { version: config.analyse.avvVersion, url: a.legal.lb },
avv: { version: config.analyse.avvVersion, url: a.legal.avv },
})
assert.throws(() => unterlagenFuer('gibtEsNicht'), TypeError)
})
test('consentAboAnalyse und abowegAnalyse: Linkzeile, Zielgruppen-Häkchen und Knopf wörtlich wie in P4', () => {
const c = reg.consentAboAnalyse()
assert.deepEqual([c.version, c.avvVersion, c.knopf], [config.aboFunktionen.fassung, config.analyse.avvVersion, 'Analyse einschalten'])
assert.deepEqual(c.items, [
{ id: 'einschalten-zeile', text: `Es gelten Leistungsbeschreibung und Auftragsverarbeitung (Fassung ${config.analyse.avvVersion}).`, haken: false },
{ id: 'zielgruppe', text: 'Meine Website richtet sich nicht gezielt an Kinder unter 16 Jahren.', haken: true },
])
const w = reg.abowegAnalyse()
assert.deepEqual([w.key, w.leistungsbeschreibung.version, w.avv.version, w.widerruf, w.consent.knopf], ['analyse', config.analyse.avvVersion, config.analyse.avvVersion, null, 'Analyse einschalten'])
})