Buchungskalender: Abschluss – Kleinigkeiten Server (Betrag/Waehrung, Erstattungs-Webhook, Obergrenze, Zaehler, Cache, Kommentare, Setup-Check)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
knsoandClaude Opus 5.5 committed 2026-10-07 15:29:55 +00:00
1 parent 6d35674c1e
commit 1d9515823c
13 files changed
+123 -14

No files matched your search

+38 -2
View File
@@ -223,7 +223,7 @@ test('Webhook: unbezahlt, fremdes Konto, unbekannte Anfrage ohne Wirkung; async_
const { id, token } = await freigegeben()
await post(url(id, token), { rechnungsadresse: ADRESSE, zahlart: 'online' })
const sid = (await sp.ladeAnfrage(id)).stripeSessionId
const unbezahlt = { ...st.completeSession(ACCOUNT, sid, { payment_status: 'unpaid', payment_intent: 'pi_2' }) }
const unbezahlt = { ...st.completeSession(ACCOUNT, sid, { payment_status: 'unpaid', amount_total: 20000, payment_intent: 'pi_2' }) }
await W.verarbeiteUkEreignis({ type: 'checkout.session.completed', account: ACCOUNT, data: { object: unbezahlt } }, NOW)
assert.equal((await sp.ladeAnfrage(id)).status, 'gebucht')
const bezahlt = { ...unbezahlt, payment_status: 'paid' }
@@ -257,7 +257,7 @@ test('POST zahlung: neue Sitzung fuer gebuchte Online-Zahlung; vor Ort oder beza
assert.match(r.body.url, /^https:\/\/checkout\.stripe\.test\//)
assert.equal((await post(url(id, 'falsch', '/zahlung'), {})).status, 404)
const sid = (await sp.ladeAnfrage(id)).stripeSessionId
st.completeSession(ACCOUNT, sid, { payment_status: 'paid', payment_intent: 'pi_4' })
st.completeSession(ACCOUNT, sid, { payment_status: 'paid', amount_total: 20000, payment_intent: 'pi_4' })
const nach = await post(url(id, token, '/zahlung'), {})
assert.equal(nach.status, 409)
assert.equal((await sp.ladeAnfrage(id)).status, 'bezahlt')
@@ -329,6 +329,42 @@ test('Erstattung: Stripe ging durch, Speichern scheiterte, KEIN Webhook -> Wiede
assert.equal(erstattungen('pi_h2').reduce((s, x) => s + x.amount, 0), 20000)
})
test('Zahlung mit falschem Betrag oder falscher Waehrung gilt nicht als Bezahlung: Warnung, automatisch voll erstattet, Buchung bleibt gebucht (Webhook und Abgleich)', async (t) => {
t.mock.method(console, 'warn', () => {})
const f1 = await freigegeben('2026-11-10', '2026-11-12')
await post(url(f1.id, f1.token), { rechnungsadresse: ADRESSE, zahlart: 'online' })
const sid1 = (await sp.ladeAnfrage(f1.id)).stripeSessionId
st.setPaymentIntent(ACCOUNT, 'pi_falsch', { amount: 100 })
const zuWenig = st.completeSession(ACCOUNT, sid1, { payment_status: 'paid', amount_total: 100, payment_intent: 'pi_falsch' })
await W.verarbeiteUkEreignis({ type: 'checkout.session.completed', account: ACCOUNT, data: { object: zuWenig } }, NOW)
assert.equal((await sp.ladeAnfrage(f1.id)).status, 'gebucht')
assert.equal(erstattungen('pi_falsch').length, 1)
assert.equal(erstattungen('pi_falsch')[0].amount, 100)
// andere Waehrung
const f2 = await freigegeben('2026-12-10', '2026-12-12')
await post(url(f2.id, f2.token), { rechnungsadresse: ADRESSE, zahlart: 'online' })
const sid2 = (await sp.ladeAnfrage(f2.id)).stripeSessionId
st.setPaymentIntent(ACCOUNT, 'pi_usd', { amount: 20000 })
const usd = { ...st.completeSession(ACCOUNT, sid2, { payment_status: 'paid', amount_total: 20000, payment_intent: 'pi_usd' }), currency: 'usd' }
await W.verarbeiteUkEreignis({ type: 'checkout.session.completed', account: ACCOUNT, data: { object: usd } }, NOW)
assert.equal((await sp.ladeAnfrage(f2.id)).status, 'gebucht')
assert.equal(erstattungen('pi_usd').length, 1)
})
test('Webhook charge.refunded: ohne gespeicherte Zahlung der Buchung oder mit fremder Zahlung keine Wirkung', async () => {
const { id, ctx } = await bezahlt('pi_r1')
await ab.storniere(ctx, id, { now: NOW })
const charge = (pi, betrag) => ({ type: 'charge.refunded', account: ACCOUNT, data: { object: { id: 'ch_r', payment_intent: pi, amount_refunded: betrag, metadata: { wkUk: '1', webklar: 'unterkunft', anfrageId: id } } } })
await W.verarbeiteUkEreignis(charge('pi_fremd', 5000), NOW)
assert.equal((await sp.ladeAnfrage(id)).erstattetCent ?? 0, 0)
await sp.aktualisiereAnfrage(id, { stripePaymentIntentId: '' })
await W.verarbeiteUkEreignis(charge('pi_r1', 5000), NOW)
assert.equal((await sp.ladeAnfrage(id)).erstattetCent ?? 0, 0, 'Buchung ohne gespeicherte Zahlung')
await sp.aktualisiereAnfrage(id, { stripePaymentIntentId: 'pi_r1' })
await W.verarbeiteUkEreignis(charge('pi_r1', 5000), NOW)
assert.equal((await sp.ladeAnfrage(id)).erstattetCent, 5000)
})
test('Webhook charge.refunded: erstattetCent = Maximum, nie zurueck', async () => {
const { id, ctx } = await bezahlt('pi_8')
await ab.storniere(ctx, id, { now: NOW })