Projektkonto: Stripe-Rechnungen lesen (Liste, Einzellesen fehlender, Ausfall)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3305371111
commit
10679ae726
2 files changed
+125
No files matched your search
@@ -211,3 +211,86 @@ test('rechneOhneProjekt: nur finalisierte Rechnungen zählen', () => {
|
||||
assert.deepEqual(rechneOhneProjekt(rechnungen), { berechnetCents: 23000, bezahltCents: 8500, anzahl: 4 })
|
||||
assert.deepEqual(rechneOhneProjekt([]), { berechnetCents: 0, bezahltCents: 0, anzahl: 0 })
|
||||
})
|
||||
|
||||
// ---------- Stripe lesen (Task 3) ----------
|
||||
|
||||
const noonBerlin = (ymd) => Math.floor(new Date(`${ymd}T12:00:00+02:00`).getTime() / 1000)
|
||||
// Rohe Stripe-Rechnung wie in financeStripeRead.test.js; status in Stripes Schreibweise (draft, open, paid, void, uncollectible)
|
||||
const stripeInvoice = (
|
||||
id,
|
||||
{ status = 'open', total = 0, paid = 0, number = '', kunde = 'c1', created = '2026-10-01', due = '2099-12-31', abo = false } = {}
|
||||
) => ({
|
||||
id,
|
||||
object: 'invoice',
|
||||
number: number || null,
|
||||
status,
|
||||
customer: `cus_${kunde}`,
|
||||
customer_name: 'Kunde',
|
||||
customer_email: 'k@example.invalid',
|
||||
created: noonBerlin(created),
|
||||
due_date: noonBerlin(due),
|
||||
total,
|
||||
amount_due: total,
|
||||
amount_paid: paid,
|
||||
amount_remaining: total - paid,
|
||||
status_transitions: { paid_at: null },
|
||||
metadata: { webklarCustomerId: kunde, quelle: 'woms' },
|
||||
...(abo ? { parent: { type: 'subscription_details', subscription_details: { subscription: 'sub_1' } } } : {}),
|
||||
lines: { object: 'list', data: [], has_more: false },
|
||||
})
|
||||
const pr = (invoiceId) => ({ invoiceId })
|
||||
|
||||
test('ladeStripeRechnungen: Liste zuerst, Fehlendes einzeln gelesen, Unbekanntes bleibt aussen vor', async () => {
|
||||
st.invoices.set('in_1', stripeInvoice('in_1', { total: 4000, number: 'WEBKLAR-0001' }))
|
||||
await listInvoices() // füllt den 60-Sekunden-Zwischenspeicher; in_9 fehlt dort
|
||||
st.invoices.set('in_9', stripeInvoice('in_9', { status: 'paid', total: 7000, paid: 7000, number: 'WEBKLAR-0009' }))
|
||||
st.calls.length = 0
|
||||
const result = await ladeStripeRechnungen([pr('in_1'), pr('in_9'), pr('in_404')])
|
||||
assert.equal(result.ok, true)
|
||||
assert.deepEqual([...result.nachId.keys()].sort(), ['in_1', 'in_9'])
|
||||
assert.deepEqual(result.alle.map((invoice) => invoice.id), ['in_1'])
|
||||
const gelesen = result.nachId.get('in_9')
|
||||
assert.deepEqual([gelesen.status, gelesen.totalCents, gelesen.paidCents], ['bezahlt', 7000, 7000])
|
||||
assert.deepEqual(st.calls.map((call) => `${call.method} ${call.path}`).sort(), ['GET /v1/invoices/in_404', 'GET /v1/invoices/in_9'])
|
||||
})
|
||||
|
||||
test('ladeStripeRechnungen: Stripe-Ausfall ergibt ok false und ein Protokoll ohne Fehlertext', async () => {
|
||||
const warn = mock.method(console, 'warn', () => {})
|
||||
st.failNext({ method: 'GET', path: '/v1/invoices', status: 400, message: 'geheim-kaputt' })
|
||||
const result = await ladeStripeRechnungen([pr('in_1')])
|
||||
assert.deepEqual([result.ok, result.alle, [...result.nachId.keys()]], [false, [], []])
|
||||
assert.equal(warn.mock.callCount(), 1)
|
||||
assert.ok(!JSON.stringify(warn.mock.calls[0].arguments).includes('geheim-kaputt'))
|
||||
})
|
||||
|
||||
test('ladeStripeRechnungen: ein anderer Fehler als 404 beim Einzellesen ist ein Ausfall', async () => {
|
||||
mock.method(console, 'warn', () => {})
|
||||
st.invoices.set('in_1', stripeInvoice('in_1', { total: 4000 }))
|
||||
await listInvoices()
|
||||
st.invoices.set('in_9', stripeInvoice('in_9', { total: 7000 }))
|
||||
st.failNext({ method: 'GET', path: '/v1/invoices/in_9', status: 400, message: 'kaputt' })
|
||||
const result = await ladeStripeRechnungen([pr('in_1'), pr('in_9')])
|
||||
assert.equal(result.ok, false)
|
||||
assert.equal(result.nachId.size, 0)
|
||||
})
|
||||
|
||||
test('ladeStripeRechnungen: viele fehlende Rechnungen werden vollständig gelesen (auch IDs wie die des Stripe-Nachbaus)', async () => {
|
||||
await listInvoices()
|
||||
const ids = Array.from({ length: 25 }, (_, i) => `in_test_${i + 1}`)
|
||||
for (const id of ids) st.invoices.set(id, stripeInvoice(id, { status: 'paid', total: 100, paid: 100 }))
|
||||
st.calls.length = 0
|
||||
const result = await ladeStripeRechnungen(ids.map(pr))
|
||||
assert.equal(result.ok, true)
|
||||
assert.equal(result.nachId.size, 25)
|
||||
assert.equal(st.calls.filter((call) => call.method === 'GET' && /^\/v1\/invoices\/in_/.test(call.path)).length, 25)
|
||||
})
|
||||
|
||||
test('ladeStripeRechnungen: unmögliche Rechnungs-IDs gehen nie an Stripe', async () => {
|
||||
await listInvoices()
|
||||
st.calls.length = 0
|
||||
// Pfadzeichen, ohne Präfix, kein Text, nur das Präfix, zu lang (V1: 1 bis 33 Zeichen nach „in_“)
|
||||
const result = await ladeStripeRechnungen([pr('../customers'), pr('x'), pr(undefined), pr('in_'), pr(`in_${'x'.repeat(34)}`)])
|
||||
assert.equal(result.ok, true)
|
||||
assert.equal(result.nachId.size, 0)
|
||||
assert.equal(st.calls.length, 0)
|
||||
})
|
||||
Reference in new issue
Block a user