Merge remote-tracking branch 'origin/main' into feature/oeffnungszeiten

Zusammenführung von TP2-Abschluss und Webshop (origin/main cab9c33) mit Öffnungszeiten live. Beide
Funktionen bleiben vollständig: jeder Konflikt ist als Vereinigung gelöst, Reihenfolge der Funktionsschlüssel
überall news, termine, shop, zeiten.

Konfliktdateien (28): public/app.js, dashboard.html, funktionen.js, widerrufen.html; scripts/stripe-products.mjs;
server/config.js, index.js, middleware/kundenansichtGuard.js, routes/abo.js, routes/admin/funktionenAdmin.js,
routes/funktionen.js, services/customerAdmin.js, customerViewLog.js, featureRegistry.js, retention.js,
siteFeatures.js, stripeBilling.js; test/customerViewLog, featureFreischaltung, featureRegistry, funktionenRoutes,
funktionenTermine, kundenansichtGuard, mailTemplates, publicForms, siteFeatures, stripeProductsScript (je
.test.js) und test/support/schema.js.

Entscheidungen: Mailvorlagen G01–G15, K01–K30, T01–T21 lückenlos (K24–K26 Webshop, K27–K30 Öffnungszeiten);
Stripe-Katalog mit shopSetup und zeitenSetup; Widerruf kennt shop und zeiten; ABO_FUNKTIONEN bleibt analyse
und termine (kein zeiten); activate() schreibt die Zeiten-Felder nur über extra; kein Halter von
feature-activate:<id> ruft disable() auf; die Aufbewahrungs-Löschung löscht Zeiten-Daten vor dem Abschalten und
hält den Kunden bei einem Fehler (held); die Admin-Antwort trägt ersatzTicket und warnung; Hash-Routen webshop
und zeiten, Ansichten view-webshop und view-zeiten; assertOwnProject behält die Meldung von main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-06 06:12:23 +00:00
commit e87140e5ba
245 files changed
+38799 -1050

No files matched your search

+14 -2
View File
@@ -31,12 +31,13 @@ test('Import startet main() nicht: kein Stripe-Aufruf, kein process.exit', () =>
assert.equal(st.calls.length, 0)
})
test('KEYS enthaelt den Terminplaner- und den Oeffnungszeiten-Katalogschluessel', () => {
assert.deepEqual(script.KEYS, ['wartung', 'hosting', 'mailStorage', 'newsSetup', 'termineSetup', 'zeitenSetup'])
test('KEYS enthaelt die Katalogschluessel der Einrichtungen (News, Terminplaner, Webshop, Oeffnungszeiten live)', () => {
assert.deepEqual(script.KEYS, ['wartung', 'hosting', 'mailStorage', 'newsSetup', 'termineSetup', 'shopSetup', 'zeitenSetup'])
})
test('catalogEntry liefert die Katalogeintraege aus der Konfiguration', () => {
assert.equal(script.catalogEntry('termineSetup'), config.termineSetup)
assert.equal(script.catalogEntry('shopSetup'), config.shopSetup)
assert.equal(script.catalogEntry('zeitenSetup'), config.zeitenSetup)
assert.equal(script.catalogEntry('newsSetup'), config.newsSetup)
assert.equal(script.catalogEntry('mailStorage'), config.mailStorage)
@@ -44,6 +45,17 @@ test('catalogEntry liefert die Katalogeintraege aus der Konfiguration', () => {
for (const key of script.KEYS) assert.ok(script.catalogEntry(key)?.lookupKey, `${key} hat einen lookupKey`)
})
test('config.shopSetup: Festwerte', () => {
assert.deepEqual(config.shopSetup, {
key: 'shopSetup',
name: 'Webshop – Einrichtung',
amountCents: 29900,
lookupKey: 'webklar_shop_einrichtung_29900',
oneTime: true,
priceNickname: 'Webshop-Einrichtung 299 €',
})
})
test('config.termineSetup: Festwerte', () => {
assert.deepEqual(config.termineSetup, {
key: 'termineSetup',