Buchungskalender: Buchungsseite, Stripe-Zahlung und Webhook
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
40a366b8ae
commit
ca0f762272
6 files changed
+679
-18
No files matched your search
@@ -29,6 +29,11 @@ beforeEach(async () => {
|
||||
for (const c of NAMEN) for (const id of aw.docs(c).keys()) await deleteDocument(c, id)
|
||||
mails._aufrufe.length = 0
|
||||
zahlung._aufrufe.length = 0
|
||||
// Erstattung ohne Stripe: wie der fruehere Stub (die echte Erstattung testet unterkunftBuchung.test.js)
|
||||
zahlung.setzeErstattungFuerTests(async (c, a, betragCent) => {
|
||||
if (!c?.einstellungen?.stripeAccountId) throw new UkFehler(409, 'online_aus')
|
||||
return { erstattetCent: betragCent }
|
||||
})
|
||||
aw.seed('ukUnterkuenfte', { $id: 'u1', featureId: 'f1', name: 'Wohnung', maxPersonen: 4, mindestNaechte: 2, aktiv: true })
|
||||
aw.seed('ukPreise', {
|
||||
$id: 'p1', unterkunftId: 'u1', featureId: 'f1', staffeln: JSON.stringify([{ abNaechten: 1, preisProNachtCent: 10000 }]),
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
import { test, after, beforeEach, afterEach } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { startAppwriteMock } from './support/appwriteMock.js'
|
||||
import { startFakeStripe } from './support/fakeStripe.js'
|
||||
import { useTestEnv } from './support/testEnv.js'
|
||||
import { schemaKeys } from './support/schema.js'
|
||||
|
||||
// Buchungskalender Task 7: Buchungsseite, Stripe-Zahlung, Webhook (Stripe ist der Nachbau)
|
||||
const NAMEN = ['portalFeatures', 'websiteProjects', 'customers', 'ukEinstellungen', 'ukUnterkuenfte', 'ukPreise', 'ukSperren', 'ukAnfragen', 'ukRechnungen']
|
||||
const aw = await startAppwriteMock({
|
||||
schema: Object.fromEntries(NAMEN.filter((n) => !['websiteProjects', 'customers'].includes(n)).map((n) => [n, schemaKeys(n)])),
|
||||
datetimes: { ukAnfragen: ['fristAt', 'freigegebenAt', 'gebuchtAt', 'abgelehntAt', 'abgelaufenAt', 'storniertAt', 'bezahltAt'] },
|
||||
defaultLimit: 25,
|
||||
})
|
||||
const st = await startFakeStripe()
|
||||
useTestEnv({ appwriteUrl: aw.url, stripeUrl: st.url })
|
||||
|
||||
const { config } = await import('../server/config.js')
|
||||
const { startTestApp, send } = await import('./support/testApp.js')
|
||||
const { deleteDocument } = await import('../server/services/appwriteAdmin.js')
|
||||
const K = await import('../server/services/unterkunft/kontext.js')
|
||||
const mails = await import('../server/services/unterkunft/mails.js')
|
||||
const ab = await import('../server/services/unterkunft/ablauf.js')
|
||||
const sp = await import('../server/services/unterkunft/speicher.js')
|
||||
const zahlung = await import('../server/services/unterkunft/zahlung.js')
|
||||
const W = await import('../server/routes/unterkunftWebhook.js')
|
||||
const { resetTermineLimitsForTests } = await import('../server/services/termine/limits.js')
|
||||
const { default: publicRoutes, setzeUhrFuerTests } = await import('../server/routes/publicUnterkunft.js')
|
||||
const app = await startTestApp({ '/api/public/unterkunft/v1': publicRoutes })
|
||||
after(async () => {
|
||||
await Promise.all([app.close(), aw.close(), st.close()])
|
||||
})
|
||||
|
||||
const SITE = 'abcdefghijklmnop'
|
||||
const FEATURE = 'f_uk'
|
||||
const ACCOUNT = 'acct_haendler1'
|
||||
const NOW = new Date('2026-11-01T12:00:00.000Z')
|
||||
const BASE = `/api/public/unterkunft/v1/${SITE}`
|
||||
const ORIGIN = 'https://donau-home.example'
|
||||
const ADRESSE = { name: 'Eva Gast', strasse: 'Weg 1', plz: '12345', ort: 'Berlin', land: 'DE' }
|
||||
const vorher = { ...config.unterkunft }
|
||||
|
||||
const einstellungen = (extra = {}) => ({
|
||||
$id: FEATURE, featureId: FEATURE, firma: 'Donau Home', inhaber: 'Mimi', strasse: 'Str 1', plz: '78576', ort: 'Stetten', email: 'x@y.de',
|
||||
steuernummer: '12/345', iban: 'DE00', akzentfarbe: '#112233', ...extra,
|
||||
})
|
||||
|
||||
async function seedBasis(einstExtra = {}) {
|
||||
for (const c of NAMEN) for (const id of [...aw.docs(c).keys()]) await deleteDocument(config.collections[c], id)
|
||||
aw.seed('portalFeatures', { $id: FEATURE, customerId: 'c1', projectId: 'p1', featureKey: 'unterkunft', siteKey: SITE, state: 'active', enabled: true })
|
||||
aw.seed('customers', { $id: 'c1', name: 'Mimi', email: 'mimi@example.com' })
|
||||
aw.seed('websiteProjects', { $id: 'p1', customerId: 'c1', projectName: 'Donau', subdomain: 'donau', liveDomain: 'donau-home.example' })
|
||||
aw.seed('ukEinstellungen', einstellungen(einstExtra))
|
||||
aw.seed('ukUnterkuenfte', { $id: 'u1', featureId: FEATURE, customerId: 'c1', projectId: 'p1', name: 'Erste', maxPersonen: 4, mindestNaechte: 1, checkIn: '15:00', checkOut: '10:00', sort: 1, aktiv: true })
|
||||
aw.seed('ukPreise', {
|
||||
$id: 'pr1', unterkunftId: 'u1', featureId: FEATURE, staffeln: JSON.stringify([{ abNaechten: 1, preisProNachtCent: 10000 }]),
|
||||
reinigungCent: 0, personenInklusive: 2, aufpreisPersonNachtCent: 0, direktrabattProzent: 0, steuerart: 'regel',
|
||||
ustUebernachtung: 7, ustReinigung: 19, fristTage: 3, stornobedingungen: 'Kostenlos bis 7 Tage vorher.',
|
||||
})
|
||||
K.leereCache()
|
||||
}
|
||||
|
||||
beforeEach(async () => {
|
||||
Object.assign(config.unterkunft, vorher, { mode: 'on', minAntwortMs: 0 })
|
||||
resetTermineLimitsForTests()
|
||||
mails._aufrufe.length = 0
|
||||
zahlung._aufrufe.length = 0
|
||||
zahlung.setzeErstattungFuerTests(null)
|
||||
W.setzeUkEreignisHandlerFuerTests(null)
|
||||
st.calls.length = 0
|
||||
setzeUhrFuerTests(() => NOW)
|
||||
await seedBasis({ onlineZahlung: true, stripeAccountId: ACCOUNT })
|
||||
})
|
||||
afterEach(() => Object.assign(config.unterkunft, vorher))
|
||||
|
||||
/** Freigegebene Anfrage mit Token (wie der Vermieter sie freigibt). */
|
||||
async function freigegeben(von = '2026-11-10', bis = '2026-11-12') {
|
||||
const ctx = await K.unterkunftPerSiteKey(SITE, { now: NOW })
|
||||
const a = await ab.legeAnfrageAn(ctx, { unterkunftId: 'u1', von, bis, personen: 2, gast: { name: 'Eva Gast', firma: '', email: 'eva@example.com', telefon: '', nachricht: '' } }, { now: NOW, ipHash: 'x' })
|
||||
const { token } = await ab.gibFrei(ctx, a.$id, { now: NOW })
|
||||
mails._aufrufe.length = 0
|
||||
return { id: a.$id, token, ctx }
|
||||
}
|
||||
const url = (id, t, rest = '') => `${BASE}/buchung/${id}${rest}?t=${encodeURIComponent(t)}`
|
||||
const post = (pfad, body, headers = { origin: ORIGIN }) => send('POST', pfad, { body, headers })
|
||||
const arten = () => mails._aufrufe.map((m) => m.art || m.template)
|
||||
|
||||
test('GET buchung: falsches Token und unbekannte ID sind identisch 404', async () => {
|
||||
const { id, token } = await freigegeben()
|
||||
const falsch = await send('GET', url(id, 'falsch'))
|
||||
const fremd = await send('GET', url('gibtsnicht', token))
|
||||
const kaputt = await send('GET', url('a.b', token))
|
||||
const ohne = await send('GET', `${BASE}/buchung/${id}`)
|
||||
for (const r of [falsch, fremd, kaputt, ohne]) {
|
||||
assert.equal(r.status, 404)
|
||||
assert.deepEqual(r.body, { fehler: 'nicht_gefunden' })
|
||||
}
|
||||
})
|
||||
|
||||
test('GET buchung: Vertrag, ohne interne Felder, zahlarten ohne online wenn Stripe fehlt', async () => {
|
||||
await seedBasis({})
|
||||
const { id, token } = await freigegeben()
|
||||
const r = await send('GET', url(id, token))
|
||||
assert.equal(r.status, 200)
|
||||
assert.equal(r.body.status, 'freigegeben')
|
||||
assert.equal(r.body.unterkunft.name, 'Erste')
|
||||
assert.equal(r.body.naechte, 2)
|
||||
assert.equal(r.body.summen.bruttoCent, 20000)
|
||||
assert.equal(r.body.akzentfarbe, '#112233')
|
||||
assert.equal(r.body.anbieter.datenschutzUrl, 'https://donau-home.example/datenschutz')
|
||||
assert.equal(r.body.anbieter.firma, 'Donau Home')
|
||||
assert.deepEqual(r.body.zahlarten, ['vorort'])
|
||||
assert.equal(r.body.bezahlt, false)
|
||||
assert.equal(r.body.rechnungNummer, undefined)
|
||||
assert.equal(r.body.stornobedingungen, 'Kostenlos bis 7 Tage vorher.')
|
||||
const roh = JSON.stringify(r.body)
|
||||
for (const verboten of ['tokenHash', 'ipHash', 'steuernummer', 'iban', 'featureId', 'customerId', 'eva@example.com']) assert.ok(!roh.includes(verboten), verboten)
|
||||
const mitOnline = await (async () => {
|
||||
await seedBasis({ onlineZahlung: true, stripeAccountId: ACCOUNT })
|
||||
const f = await freigegeben()
|
||||
return send('GET', url(f.id, f.token))
|
||||
})()
|
||||
assert.deepEqual(mitOnline.body.zahlarten, ['vorort', 'online'])
|
||||
})
|
||||
|
||||
test('POST buchung vor Ort: gebucht, Rechnung; zweites POST gleiche Antwort ohne zweite Rechnung', async () => {
|
||||
const { id, token } = await freigegeben()
|
||||
const r1 = await post(url(id, token), { rechnungsadresse: ADRESSE, zahlart: 'vorort' })
|
||||
assert.equal(r1.status, 200)
|
||||
assert.deepEqual(r1.body, { status: 'gebucht', rechnungNummer: 'RE-2026-0001' })
|
||||
assert.equal(r1.headers.get('access-control-allow-origin'), ORIGIN)
|
||||
const r2 = await post(url(id, token), { rechnungsadresse: ADRESSE, zahlart: 'vorort' })
|
||||
assert.deepEqual(r2.body, r1.body)
|
||||
assert.equal(aw.docs('ukRechnungen').size, 1)
|
||||
assert.deepEqual(arten(), ['G19', 'K32'])
|
||||
const g = await send('GET', url(id, token))
|
||||
assert.equal(g.body.status, 'gebucht')
|
||||
assert.equal(g.body.rechnungNummer, 'RE-2026-0001')
|
||||
assert.equal(g.body.zahlart, 'vorort')
|
||||
assert.equal(g.body.rechnungsadresse.ort, 'Berlin')
|
||||
})
|
||||
|
||||
test('POST buchung: falsches Token 404, fremde Herkunft 403, Adresse fehlt 400, Frist abgelaufen 410', async () => {
|
||||
const { id, token } = await freigegeben()
|
||||
const falsch = await post(url(id, 'falsch'), { rechnungsadresse: ADRESSE, zahlart: 'vorort' })
|
||||
assert.equal(falsch.status, 404)
|
||||
assert.deepEqual(falsch.body, { fehler: 'nicht_gefunden' })
|
||||
assert.equal((await post(url(id, token), { rechnungsadresse: ADRESSE, zahlart: 'vorort' }, { origin: 'https://boese.example' })).status, 403)
|
||||
const luecke = await post(url(id, token), { rechnungsadresse: { name: 'x' }, zahlart: 'vorort' })
|
||||
assert.equal(luecke.status, 400)
|
||||
assert.equal(luecke.body.fehler, 'ungueltig')
|
||||
setzeUhrFuerTests(() => new Date(NOW.getTime() + 4 * 86400000))
|
||||
const spaet = await post(url(id, token), { rechnungsadresse: ADRESSE, zahlart: 'vorort' })
|
||||
assert.equal(spaet.status, 410)
|
||||
assert.deepEqual(spaet.body, { fehler: 'frist_abgelaufen' })
|
||||
assert.equal(aw.docs('ukRechnungen').size, 0)
|
||||
})
|
||||
|
||||
test('POST buchung online: zahlungUrl vom Stripe-Nachbau, Sitzung auf dem Konto des Vermieters', async () => {
|
||||
const { id, token } = await freigegeben()
|
||||
const r = await post(url(id, token), { rechnungsadresse: ADRESSE, zahlart: 'online' })
|
||||
assert.equal(r.status, 200)
|
||||
assert.equal(r.body.status, 'gebucht')
|
||||
assert.match(r.body.zahlungUrl, /^https:\/\/checkout\.stripe\.test\/c\/pay\/cs_/)
|
||||
const [call] = st.calls.filter((c) => c.path === '/v1/checkout/sessions')
|
||||
assert.equal(call.account, ACCOUNT)
|
||||
assert.equal(call.body.mode, 'payment')
|
||||
assert.equal(call.body['metadata[wkUk]'], '1')
|
||||
assert.equal(call.body['metadata[anfrageId]'], id)
|
||||
assert.equal(call.body['payment_intent_data[metadata][anfrageId]'], id)
|
||||
assert.equal(call.body['payment_intent_data[metadata][webklar]'], 'unterkunft')
|
||||
assert.equal(call.body['line_items[0][price_data][unit_amount]'], '20000')
|
||||
assert.match(call.body['line_items[0][price_data][product_data][name]'], /^Aufenthalt Erste 10\.11\.2026–12\.11\.2026, Rechnung RE-2026-0001$/)
|
||||
assert.equal(call.body['payment_method_types[0]'], 'card')
|
||||
assert.equal(call.body['payment_method_types[1]'], undefined)
|
||||
assert.equal(call.body.locale, 'de')
|
||||
assert.match(call.body.success_url, new RegExp(`/unterkunft/${SITE}/buchung/${id}\\?t=.*&wk_zahlung=ok$`))
|
||||
assert.match(call.body.cancel_url, /&wk_zahlung=abbruch$/)
|
||||
assert.equal(Number(call.body.expires_at), Math.floor(NOW.getTime() / 1000) + 31 * 60)
|
||||
assert.match(call.idempotencyKey, new RegExp(`^uk-zahlung-${id}-\\d+$`))
|
||||
assert.ok((await sp.ladeAnfrage(id)).stripeSessionId.startsWith('cs_'))
|
||||
})
|
||||
|
||||
test('SEPA nur bei gemeldetem Status', async () => {
|
||||
await seedBasis({ onlineZahlung: true, stripeAccountId: ACCOUNT, stripeStatus: JSON.stringify({ charges_enabled: true, sepa_debit: true }) })
|
||||
const { id, token } = await freigegeben()
|
||||
await post(url(id, token), { rechnungsadresse: ADRESSE, zahlart: 'online' })
|
||||
const call = st.calls.find((c) => c.path === '/v1/checkout/sessions')
|
||||
assert.equal(call.body['payment_method_types[1]'], 'sepa_debit')
|
||||
})
|
||||
|
||||
test('Webhook checkout.session.completed: bezahlt, G20, zweimal nur ein Uebergang', async () => {
|
||||
const { id, token } = await freigegeben()
|
||||
const r = await post(url(id, token), { rechnungsadresse: ADRESSE, zahlart: 'online' })
|
||||
const sid = (await sp.ladeAnfrage(id)).stripeSessionId
|
||||
mails._aufrufe.length = 0
|
||||
const session = st.completeSession(ACCOUNT, sid, { payment_status: 'paid', amount_total: 20000, payment_intent: 'pi_1' })
|
||||
const event = { type: 'checkout.session.completed', account: ACCOUNT, data: { object: session } }
|
||||
await W.verarbeiteUkEreignis(event, NOW)
|
||||
await W.verarbeiteUkEreignis(event, NOW)
|
||||
const a = await sp.ladeAnfrage(id)
|
||||
assert.equal(a.status, 'bezahlt')
|
||||
assert.equal(a.bezahltVia, 'stripe')
|
||||
assert.equal(a.stripePaymentIntentId, 'pi_1')
|
||||
assert.deepEqual(arten(), ['G20'])
|
||||
assert.ok(r.body.zahlungUrl)
|
||||
})
|
||||
|
||||
test('Webhook: unbezahlt, fremdes Konto, unbekannte Anfrage ohne Wirkung; async_payment_succeeded bucht', 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' }) }
|
||||
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' }
|
||||
await W.verarbeiteUkEreignis({ type: 'checkout.session.completed', account: 'acct_fremd', data: { object: bezahlt } }, NOW)
|
||||
assert.equal((await sp.ladeAnfrage(id)).status, 'gebucht')
|
||||
await W.verarbeiteUkEreignis({ type: 'checkout.session.completed', account: ACCOUNT, data: { object: { ...bezahlt, metadata: { wkUk: '1', anfrageId: 'gibtsnicht' } } } }, NOW)
|
||||
await W.verarbeiteUkEreignis({ type: 'checkout.session.async_payment_succeeded', account: ACCOUNT, data: { object: bezahlt } }, NOW)
|
||||
assert.equal((await sp.ladeAnfrage(id)).status, 'bezahlt')
|
||||
})
|
||||
|
||||
test('Rueckkehr mit wk_zahlung=ok schliesst ohne Webhook selbst ab', async () => {
|
||||
const { id, token } = await freigegeben()
|
||||
await post(url(id, token), { rechnungsadresse: ADRESSE, zahlart: 'online' })
|
||||
const sid = (await sp.ladeAnfrage(id)).stripeSessionId
|
||||
const offen = await send('GET', url(id, token, '') + '&wk_zahlung=ok')
|
||||
assert.equal(offen.body.status, 'gebucht')
|
||||
mails._aufrufe.length = 0
|
||||
st.completeSession(ACCOUNT, sid, { payment_status: 'paid', amount_total: 20000, payment_intent: 'pi_3' })
|
||||
const r = await send('GET', url(id, token) + '&wk_zahlung=ok')
|
||||
assert.equal(r.body.status, 'bezahlt')
|
||||
assert.equal(r.body.bezahlt, true)
|
||||
assert.deepEqual(arten(), ['G20'])
|
||||
assert.equal((await sp.ladeAnfrage(id)).stripePaymentIntentId, 'pi_3')
|
||||
})
|
||||
|
||||
test('POST zahlung: neue Sitzung fuer gebuchte Online-Zahlung; vor Ort oder bezahlt 409', async () => {
|
||||
const { id, token } = await freigegeben()
|
||||
await post(url(id, token), { rechnungsadresse: ADRESSE, zahlart: 'online' })
|
||||
const r = await post(url(id, token, '/zahlung'), {})
|
||||
assert.equal(r.status, 200)
|
||||
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' })
|
||||
const nach = await post(url(id, token, '/zahlung'), {})
|
||||
assert.equal(nach.status, 409)
|
||||
assert.equal((await sp.ladeAnfrage(id)).status, 'bezahlt')
|
||||
const g = await freigegeben('2026-12-10', '2026-12-12')
|
||||
await post(url(g.id, g.token), { rechnungsadresse: ADRESSE, zahlart: 'vorort' })
|
||||
assert.equal((await post(url(g.id, g.token, '/zahlung'), {})).status, 409)
|
||||
})
|
||||
|
||||
async function bezahlt(pi = 'pi_5') {
|
||||
const { id, token, ctx } = await freigegeben()
|
||||
await post(url(id, token), { rechnungsadresse: ADRESSE, zahlart: 'online' })
|
||||
const sid = (await sp.ladeAnfrage(id)).stripeSessionId
|
||||
const session = st.completeSession(ACCOUNT, sid, { payment_status: 'paid', amount_total: 20000, payment_intent: pi })
|
||||
await W.verarbeiteUkEreignis({ type: 'checkout.session.completed', account: ACCOUNT, data: { object: session } }, NOW)
|
||||
return { id, token, ctx }
|
||||
}
|
||||
|
||||
test('Erstattung echt: Stripe-Aufruf mit Metadaten unterkunft und Idempotency-Key, erstattetCent aus Stripe', async () => {
|
||||
const { id, ctx } = await bezahlt('pi_6')
|
||||
st.setPaymentIntent(ACCOUNT, 'pi_6', { amount: 20000 })
|
||||
st.calls.length = 0
|
||||
const r = await ab.storniere(ctx, id, { grund: 'Krank', erstattungCent: 12000, now: NOW })
|
||||
assert.equal(r.anfrage.erstattetCent, 12000)
|
||||
const [call] = st.calls.filter((c) => c.path === '/v1/refunds')
|
||||
assert.equal(call.account, ACCOUNT)
|
||||
assert.equal(call.body.payment_intent, 'pi_6')
|
||||
assert.equal(call.body.amount, '12000')
|
||||
assert.equal(call.body['metadata[webklar]'], 'unterkunft')
|
||||
assert.equal(call.idempotencyKey, `uk-erstattung-${id}-12000`)
|
||||
assert.equal(zahlung._aufrufe.length, 1)
|
||||
})
|
||||
|
||||
test('Erstattung: Stripe scheitert -> 502, Storno bleibt, erstattetCent unveraendert', async () => {
|
||||
const { id, ctx } = await bezahlt('pi_7')
|
||||
st.setPaymentIntent(ACCOUNT, 'pi_7', { amount: 20000 })
|
||||
st.failNext({ status: 400, path: '/v1/refunds' })
|
||||
await assert.rejects(ab.storniere(ctx, id, { erstattungCent: 5000, now: NOW }), (e) => e.status === 502 && e.code === 'erstattung_fehlgeschlagen')
|
||||
const a = await sp.ladeAnfrage(id)
|
||||
assert.equal(a.status, 'storniert')
|
||||
assert.equal(a.erstattetCent ?? 0, 0)
|
||||
})
|
||||
|
||||
test('Webhook charge.refunded: erstattetCent = Maximum, nie zurueck', async () => {
|
||||
const { id, ctx } = await bezahlt('pi_8')
|
||||
await ab.storniere(ctx, id, { now: NOW })
|
||||
const charge = (betrag) => ({ type: 'charge.refunded', account: ACCOUNT, data: { object: { id: 'ch_1', payment_intent: 'pi_8', amount_refunded: betrag, metadata: { wkUk: '1', webklar: 'unterkunft', anfrageId: id } } } })
|
||||
await W.verarbeiteUkEreignis(charge(7000), NOW)
|
||||
assert.equal((await sp.ladeAnfrage(id)).erstattetCent, 7000)
|
||||
await W.verarbeiteUkEreignis(charge(3000), NOW)
|
||||
assert.equal((await sp.ladeAnfrage(id)).erstattetCent, 7000)
|
||||
await W.verarbeiteUkEreignis(charge(7000), NOW)
|
||||
assert.equal((await sp.ladeAnfrage(id)).erstattetCent, 7000)
|
||||
await W.verarbeiteUkEreignis({ ...charge(9000), account: 'acct_fremd' }, NOW)
|
||||
assert.equal((await sp.ladeAnfrage(id)).erstattetCent, 7000)
|
||||
})
|
||||
|
||||
test('rechnung.pdf: 200 mit PDF oder 501 ohne Erzeuger; falsches Token 404', async () => {
|
||||
const { id, token } = await freigegeben()
|
||||
await post(url(id, token), { rechnungsadresse: ADRESSE, zahlart: 'vorort' })
|
||||
const r = await send('GET', url(id, token, '/rechnung.pdf'))
|
||||
assert.ok([200, 501].includes(r.status), String(r.status))
|
||||
if (r.status === 200) assert.equal(r.headers.get('content-type'), 'application/pdf')
|
||||
assert.equal((await send('GET', url(id, 'falsch', '/rechnung.pdf'))).status, 404)
|
||||
assert.equal((await send('GET', url(id, token, '/rechnung.pdf') + '&art=storno')).status, 404)
|
||||
assert.equal((await send('GET', url(id, token, '/rechnung.pdf') + '&art=x')).status, 400)
|
||||
})
|
||||
Reference in new issue
Block a user