Kundenansicht P6: Wechsel merkt sich die gewünschte Funktion (details.funktion, wechselFunktion)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-16 16:50:24 +00:00
1 parent db47f13510
commit d5a7312896
3 files changed
+137 -26

No files matched your search

+39
View File
@@ -1153,3 +1153,42 @@ test('Abgleich mit veraltetem Ereignis nach dem Webhook: kein zweites T12', asyn
assert.equal((await listContractEvents('c1'))[0].$id, stale.$id)
assert.equal((await listContractEvents('c1'))[0].doneBy, 'stripe')
})
// Kundenansicht P6 (Task 12): der Wechsel merkt sich die gewünschte Funktion (details.funktion) und GET /api/abo nennt sie (wechselFunktion)
const NEU_MODUS = { mode: config.kundenansichtNeu.mode, pilotEmails: [...config.kundenansichtNeu.pilotEmails] }
after(() => {
config.kundenansichtNeu.mode = NEU_MODUS.mode
config.kundenansichtNeu.pilotEmails = NEU_MODUS.pilotEmails
})
const pilot = (an) => { config.kundenansichtNeu.mode = an ? 'pilot' : 'off'; config.kundenansichtNeu.pilotEmails = ['k@example.invalid'] }
const F = { key: 'termine', projectId: 'wf_p1' }
aw.seed('websiteProjects', { $id: 'wf_p1', customerId: 'c1', projectName: 'Bäckerei' }); aw.seed('websiteProjects', { $id: 'wf_fremd', customerId: 'c2', projectName: 'Fremd' })
const bestelle = async (extra = {}) => {
await resetHosting(); st.invoicePreview = previewInvoice(line('price_hosting', -900, { proration: true, periodStart: nowUnix() }), line('price_wartung', 5000)); st.nextSubscriptionUpdate = { latest_invoice: switchInvoice() }
return post('/api/abo/switch', { acceptTerms: true, earlyStart: true, termsVersion: config.abo.termsVersion, prorationDate: nowUnix(), amountDueCents: 4100, ...extra }, { cookie: customerCookie() })
}
const wechsel = async () => (await listContractEvents('c1')).find((e) => e.type === 'wechsel')
test('Wechsel mit Funktion: nur in der neuen Ansicht gespeichert; Ungültiges wird verworfen, der Wechsel läuft trotzdem', async () => {
pilot(true); assert.equal((await bestelle({ funktion: F })).status, 200); assert.deepEqual((await wechsel()).details.funktion, F); assert.ok(JSON.stringify((await wechsel()).details).length <= 2000)
for (const funktion of [{ key: 'analyse', projectId: 'wf_p1' }, { key: 'foo', projectId: 'wf_p1' }, { key: 'termine', projectId: 'wf_fremd' }, { key: 'termine' }, 'termine', [], null]) {
assert.equal((await bestelle({ funktion })).status, 200, JSON.stringify(funktion)); assert.equal(Object.hasOwn((await wechsel()).details, 'funktion'), false, JSON.stringify(funktion))
}
pilot(false); assert.equal((await bestelle({ funktion: F })).status, 200); assert.equal(Object.hasOwn((await wechsel()).details, 'funktion'), false)
})
test('GET /api/abo: wechselFunktion folgt dem jüngsten erledigten Wechsel, 14 Tage, Funktion off; alte Ansicht ohne den Schlüssel', async () => {
const { updateDocument } = await import('../server/services/appwriteAdmin.js')
const ts = (tage) => new Date(Date.now() - tage * 86400000).toISOString()
const lege = async ({ status = 'erledigt', paidVor = 2, doneVor = null, funktion = F } = {}) => {
const ev = await recordContractEvent({ customerId: 'c1', subscriptionId: 'sub_h', type: 'wechsel', productKey: 'wartung', consent, status, details: { from: 'hosting', switchedAt: ts(paidVor), ...(status === 'erledigt' && doneVor === null ? { paidAt: ts(paidVor) } : {}), ...(funktion ? { funktion } : {}) } })
if (doneVor !== null) await updateContractEvent(ev.$id, { status: 'erledigt', doneAt: ts(doneVor) })
}
const lies = async () => (await get('/api/abo', { cookie: customerCookie() })).subscription
const neu = async (setup) => { await resetHosting({ patch: { productKey: 'wartung' } }); await lege(setup); return (await lies()).wechselFunktion }
pilot(true)
assert.deepEqual(await neu({}), F); assert.deepEqual(await neu({ paidVor: 20, doneVor: 13 }), F) // sofort bezahlt (paidAt) bzw. später erledigt (doneAt)
for (const setup of [{ status: 'offen' }, { status: 'gescheitert' }, { status: 'widerrufen' }, { paidVor: 20, doneVor: 15 }, { funktion: null }]) assert.equal(await neu(setup), null, JSON.stringify(setup))
await neu({}); await lege({ funktion: null }); assert.equal((await lies()).wechselFunktion, null) // der jüngere Wechsel ohne Funktion gewinnt
await neu({}); aw.seed('portalFeatures', { $id: 'f_wf_p1_termine', customerId: 'c1', projectId: 'wf_p1', featureKey: 'termine', state: 'setup' }); assert.equal((await lies()).wechselFunktion, null)
await updateDocument('portalFeatures', 'f_wf_p1_termine', { state: 'off' }); assert.deepEqual((await lies()).wechselFunktion, F)
pilot(false); assert.equal(Object.hasOwn(await lies(), 'wechselFunktion'), false)
})