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:
commit
e87140e5ba
245 files changed
+38799
-1050
No files matched your search
@@ -67,19 +67,22 @@ test('liste_zustaende', async () => {
|
||||
// Terminplaner: zweite Funktion je Projekt, Schalter TERMINE_ENABLED (Vorgabe off) - Einzelheiten in funktionenTermine.test.js
|
||||
for (const p of body.projects) assert.equal(p.features.termine.state, 'off')
|
||||
assert.deepEqual(body.termine, { verfuegbar: false })
|
||||
// Webshop: Schalter SHOP_ENABLED (Vorgabe off) ⇒ nur das Flag, keine weiteren Felder
|
||||
assert.deepEqual(body.shop, { verfuegbar: false })
|
||||
// Oeffnungszeiten live: Schalter ZEITEN_ENABLED (Vorgabe off): genau { verfuegbar: false } und je Projekt ohne Status, leer
|
||||
// (Angebot, Ansicht und Status: test/zeitenEinschalten.test.js)
|
||||
assert.deepEqual(body.zeiten, { verfuegbar: false })
|
||||
for (const p of body.projects) assert.deepEqual([p.features.zeiten.state, p.zeitenStatus, p.zeitenLeer], ['off', null, true])
|
||||
|
||||
// Register-Ansicht (B12): Preise und Bestelltexte beider Funktionen aus config.features, auch bei termine.verfuegbar: false
|
||||
assert.deepEqual(Object.keys(body.features).sort(), ['news', 'termine', 'zeiten'])
|
||||
assert.deepEqual(Object.keys(body.features).sort(), ['news', 'shop', 'termine', 'zeiten'])
|
||||
assert.equal(body.features.shop.priceLabel, '299 €')
|
||||
assert.equal(body.features.news.priceLabel, '30 €')
|
||||
assert.equal(body.features.termine.priceLabel, '149 €')
|
||||
assert.equal(body.ustHinweis, config.ustHinweis)
|
||||
assert.ok(typeof body.ustHinweis === 'string' && body.ustHinweis.length > 0)
|
||||
// Items vollstaendig: Kennung, Wortlaut und Haken jedes Registerpunkts, dazu Fassung und Knopf
|
||||
for (const key of ['news', 'termine']) {
|
||||
for (const key of ['news', 'termine', 'shop']) {
|
||||
const eintrag = config.features[key]
|
||||
const ansicht = body.features[key]
|
||||
assert.equal(ansicht.key, key)
|
||||
@@ -115,7 +118,7 @@ test('liste_legal: legal.termine mit Fassung, https-Links mit Fassung und der Be
|
||||
const { legalPaths } = await import('../server/services/legalDocs.js')
|
||||
const V = config.termine.avvVersion
|
||||
const body = await get('/api/funktionen', { cookie })
|
||||
assert.deepEqual(Object.keys(body.legal).sort(), ['news', 'termine', 'zeiten'])
|
||||
assert.deepEqual(Object.keys(body.legal).sort(), ['news', 'shop', 'termine', 'zeiten'])
|
||||
assert.equal(body.legal.news, null)
|
||||
// die Oeffnungszeiten haben keine Rechtsdokumente zum Anhaengen (avv und widerruf null): kein Eintrag wie beim Terminplaner
|
||||
assert.equal(body.legal.zeiten, null)
|
||||
@@ -136,6 +139,20 @@ test('liste_legal: legal.termine mit Fassung, https-Links mit Fassung und der Be
|
||||
assert.deepEqual(body.features.termine.avv, { version: V, url: adressen.avv })
|
||||
assert.deepEqual(body.features.termine.leistungsbeschreibung, { version: V, url: adressen.lb })
|
||||
assert.deepEqual(body.features.news.widerruf, null)
|
||||
|
||||
// Webshop: eigene Fassung (config.shop.fassung), eigene Slugs, dieselbe Belehrung der Funktionen
|
||||
const S = config.shop.fassung
|
||||
const shop = body.legal.shop
|
||||
assert.deepEqual(Object.keys(shop).sort(), ['belehrung', 'links', 'version'])
|
||||
assert.equal(shop.version, S)
|
||||
assert.deepEqual(Object.keys(shop.links), ['lb', 'avv', 'widerruf'])
|
||||
const shopAdressen = legalPaths('shop', S)
|
||||
for (const [doc, link] of Object.entries(shop.links)) assert.equal(link, `${config.publicBaseUrl}${shopAdressen[doc]}`)
|
||||
assert.ok(shop.links.lb.includes('leistungsbeschreibung-webshop-'))
|
||||
assert.ok(shop.links.avv.includes('avv-webshop-'))
|
||||
assert.ok(shop.links.widerruf.includes('widerrufsbelehrung-funktionen-'))
|
||||
assert.equal(shop.belehrung, widerrufsbelehrungFunktion())
|
||||
assert.deepEqual(body.features.shop.avv, { version: S, url: shopAdressen.avv })
|
||||
})
|
||||
|
||||
test('liste_register_ohne_freigabe: features.termine steht auch bei Schalter off und Pilot ohne Teilnahme', async () => {
|
||||
@@ -194,7 +211,8 @@ test('checkout_legt_session_an', async () => {
|
||||
assert.equal(doc.stripeSessionId, session.id)
|
||||
assert.equal(doc.consentText, config.funktionen.consentText)
|
||||
assert.ok(doc.consentAt)
|
||||
assert.ok(doc.consentUserAgent)
|
||||
assert.equal(doc.consentUserAgent, '', 'C1: der Browser steht nur im Nachweis, nicht am Funktionsdokument')
|
||||
assert.equal(doc.consentIp, '')
|
||||
// zweite Bestellung waehrend die erste offen ist: dieselbe Zahlungsseite, keine neue Sitzung
|
||||
const again = await checkout('p1')
|
||||
assert.equal(again.status, 200)
|
||||
|
||||
Reference in new issue
Block a user