Öffnungszeiten: Fixrunde Server (Schema-Kopplung, K27, Wertersatz, Widerruf, Ticket nachlegen)
- activate() schreibt die Zeiten-Felder (aboEndeAt, behaltenSessionId) nur noch über extra
(nur Abo-Rückkehr und Team-Aktivierung der Zeiten); News und Terminplaner laufen auch vor zeiten-setup.mjs
- Abo-Abgleich: K27 gilt als offen, solange der Marker vor disabledAt liegt (kein Zurücksetzen nach disable() nötig);
K27 geht erst nach dem Ersatz-Ticket raus (scheitert es, wiederholt der nächste Lauf beides);
Löschung setzt auch activatedAt zurück
- Zustimmung "beginn" (bezahlt) mit Wertersatz-Satz (§ 357a Abs. 2 BGB) wie bei News und Terminplaner, Fassung 2026-10-05
- Widerruf: Bestellung "zeiten" in ORDERS, FEATURE_OF_ORDER, orderLabel und widerrufen.html
- Team "Ticket nachlegen" der Zeiten ohne Kauf geht über holeZeitenNach statt über den Zahlungsweg
- Einschalten-Route nimmt nur { zustimmung }, nicht die Altform { consent: true }
- Team-Aktivierung behält kauf/unlockedByPurchase bei einem bisher gekauften Dokument
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c10e50d0b3
commit
ecf67d6978
13 files changed
+337
-48
No files matched your search
@@ -0,0 +1,42 @@
|
||||
import { test, after } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { startAppwriteMock } from './support/appwriteMock.js'
|
||||
import { schemaKeys } from './support/schema.js'
|
||||
import { useTestEnv } from './support/testEnv.js'
|
||||
import { ZEITEN_FEATURE_ATTRIBUTES } from '../server/services/zeiten/schema.js'
|
||||
|
||||
// activate() ist der gemeinsame Schreibpfad aller Funktionen (News, Terminplaner, Zeiten). Die neuen Zeiten-Felder von portalFeatures
|
||||
// (unlockedBy, aboEndeAt, einbau, behaltenSessionId, k24At) legt erst scripts/zeiten-setup.mjs an: laeuft der Code vor diesem Skript,
|
||||
// darf die Aktivierung von News und Terminplaner nie ein Zeiten-Feld schreiben (Appwrite: "Unknown attribute"). Der Nachbau hier hat
|
||||
// darum genau das Schema OHNE die Zeiten-Felder; nur der Zeiten-Pfad (extra) schreibt sie.
|
||||
const ZEITEN_FELDER = ZEITEN_FEATURE_ATTRIBUTES.map((a) => a.key)
|
||||
const aw = await startAppwriteMock({ schema: { portalFeatures: schemaKeys('portalFeatures').filter((k) => !ZEITEN_FELDER.includes(k)) } })
|
||||
after(() => aw.close())
|
||||
useTestEnv({ appwriteUrl: aw.url, stripeUrl: 'http://127.0.0.1:1' })
|
||||
|
||||
const { activate, adminActivate } = await import('../server/services/siteFeatures.js')
|
||||
|
||||
const ZUVOR = '2026-09-20T10:00:00.000Z'
|
||||
const lesen = (id) => aw.docs('portalFeatures').get(id)
|
||||
|
||||
aw.seed('customers', { $id: 'c1', name: 'Kunde Eins' })
|
||||
aw.seed('websiteProjects', { $id: 'p1', customerId: 'c1', projectName: 'Bäckerei' })
|
||||
|
||||
for (const key of ['news', 'termine']) {
|
||||
test(`activate() einer abgeschalteten Funktion (${key}) schreibt keine Zeiten-Felder und scheitert nicht ohne zeiten-setup`, async () => {
|
||||
const id = `f_${key}`
|
||||
aw.seed('portalFeatures', {
|
||||
$id: id, customerId: 'c1', projectId: 'p1', featureKey: key, state: 'disabled', enabled: false,
|
||||
disabledAt: ZUVOR, disabledReason: 'abo_ende', aboEndeMailAt: ZUVOR,
|
||||
})
|
||||
const doc = await activate(id, { by: 'kenso' })
|
||||
assert.deepEqual([doc.state, doc.enabled, doc.disabledAt, doc.disabledReason, doc.aboEndeMailAt], ['active', true, null, null, null])
|
||||
for (const feld of ZEITEN_FELDER) assert.equal(feld in lesen(id), false, `${feld} wurde nicht geschrieben`)
|
||||
})
|
||||
}
|
||||
|
||||
test('adminActivate() (News) schreibt keine Zeiten-Felder', async () => {
|
||||
aw.seed('portalFeatures', { $id: 'f_admin', customerId: 'c1', projectId: 'p1', featureKey: 'news', state: 'setup', enabled: false })
|
||||
const doc = await adminActivate('c1', 'p1', 'news', { by: 'kenso' })
|
||||
assert.equal(doc.state, 'active')
|
||||
})
|
||||
Reference in new issue
Block a user