Abo-Baustein aboStatus.js: Wechsel-Regel in laeuft/bestellbar, aboLage; Analyse nutzt ihn

aboStatus.js (Kernversion aus B5 ausgebaut): ein privater Lader lage(customerId, { altbestand })
ueber getCurrentSubscription und listContractEvents, alle Praedikate bauen darauf. laeuft kennt
altbestand (Vorgabe true: productKey || 'wartung' plus Wechsel-Regel; false: die heutige Regel der
Analyse, keine Ereignisabfrage). Wechsel-Regel: sagt der Spiegel "Wartung laeuft" und ist das
juengste wechsel-Ereignis des Abos widerrufen, laeuft das Wartungs-Abo nicht (kein_abo beim
Bestell-Gate, Freischaltung bleibt in setup). Neu aboLage ({ laeuft, art, endedAt }) und
aboMemo().lage; der Memo merkt eine Ablehnung fuer den Lauf. analyse.js nutzt
laeuft(id, { altbestand: false }); Verhalten der Analyse unveraendert (+1 Pin-Test).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-04 13:50:51 +00:00
1 parent cf9f9b30a0
commit 144b053851
6 files changed
+449 -58

No files matched your search

+25 -1
View File
@@ -18,6 +18,7 @@ const aw = await startAppwriteMock({
subscriptions: schemaKeys('subscriptions'),
featureConsents: schemaKeys('featureConsents'),
termineConfig: schemaKeys('termineConfig'),
contractEvents: schemaKeys('contractEvents'),
},
})
const st = await startFakeStripe()
@@ -44,7 +45,7 @@ const wartung = (patch = {}) => aw.seed('subscriptions', subscriptionDoc('sub_h'
// Jeder Test beginnt sauber: Standard-Abos (c1 Wartung), Pilot fuer alle, keine Haken-Ueberschreibungen, keine Dokumente
beforeEach(async () => {
for (const col of ['subscriptions', 'portalFeatures', 'featureConsents', 'termineConfig']) {
for (const col of ['subscriptions', 'portalFeatures', 'featureConsents', 'termineConfig', 'contractEvents']) {
for (const id of aw.docs(col).keys()) await deleteDocument(col, id)
}
seedFixtures(aw)
@@ -404,6 +405,29 @@ test('Abo-Gruende: kein Abo (c3, c2 mit Hosting), Kuendigung, offene Zahlung', a
assert.notEqual(ok.body?.grund, 'nicht_aktiv')
})
test('Wechsel-Regel (E1): Spiegel Wartung active, aber juengstes wechsel-Ereignis widerrufen => 409 kein_abo ohne Spur; ein neueres erledigtes hebt es auf', async () => {
T.bestellpruefung = async () => []
const wechsel = (nr, status) =>
aw.seed('contractEvents', {
$id: `ev_w${nr}`,
$createdAt: new Date(Date.UTC(2026, 8, 1, 0, 0, nr)).toISOString(),
customerId: 'c1',
subscriptionId: 'sub_h',
type: 'wechsel',
productKey: 'wartung',
details: '{}',
status,
})
wechsel(1, 'widerrufen')
aboAbgelehnt(await checkout('termine', bodyT()), 'kein_abo')
assert.equal(aw.docs('portalFeatures').size, 0, 'kein Dokument entstanden')
wechsel(2, 'erledigt')
const ok = await checkout('termine', bodyT())
assert.notEqual(ok.body?.code, 'kein_abo')
assert.notEqual(ok.body?.grund, 'nicht_aktiv')
})
test('Abo-Lesefehler: 500 ohne Rohtext, fail-closed ohne Spur', async () => {
T.bestellpruefung = async () => []
aw.failNext({ collection: 'subscriptions', status: 500, message: 'GEHEIMER-ROHTEXT interner Fehler' })