Finanzen: Zeitgrenzen fuer Stripe-Lesen, Schutz vor doppelt angelegten Rechnungen

I2: Leseanfragen an Stripe mit timeout 15 s und einer Wiederholung (auch Folgeseiten), die Uebersicht
wartet hoechstens 20 s auf Stripe und rechnet sonst ohne Stripe weiter.
I3: idempotencyKey vom Aufrufer an stripe.invoices.create, Schutz im Prozess gegen gleichzeitiges und
30 s spaeteres Doppelanlegen (409), 502 mit invoiceId/Nummer wenn die fertige Rechnung nicht lesbar ist.
M9: Warnung, wenn die Rechnungsliste bei 1000 abgeschnitten wird.
M11: Ursache eines 502 an einer bestehenden Rechnung (Art, Status, Code) im Protokoll.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-01 15:42:06 +00:00
1 parent ef2ce49669
commit daa451094a
8 files changed
+476 -48

No files matched your search

+4 -2
View File
@@ -21,7 +21,7 @@ const { seedFixtures } = await import('./support/fixtures.js')
const { startTestApp, get, post, rawGet } = await import('./support/testApp.js')
const { default: financeRoutes } = await import('../server/routes/admin/finanzen.js')
const settings = await import('../server/services/finance/settings.js')
const { createProjectInvoice, invalidateFinanceCache } = await import('../server/services/finance/stripeFinance.js')
const { createProjectInvoice, invalidateFinanceCache, resetInvoiceCreateGuardForTests } = await import('../server/services/finance/stripeFinance.js')
const { deleteDocument } = await import('../server/services/appwriteAdmin.js')
const app = await startTestApp({ '/api/admin/finanzen': financeRoutes })
@@ -49,6 +49,7 @@ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
async function reset() {
mock.restoreAll()
invalidateFinanceCache()
resetInvoiceCreateGuardForTests()
st.calls.length = 0
st.invoices.clear()
st.customers.clear()
@@ -568,8 +569,9 @@ test('Rechnung: nach PATCH { bankDetailsText } steht die IBAN-Zeile im Rechnungs
`${config.stripe.invoiceFooter}\nIBAN DE00 0000 0000 0000 0000 00\nBIC TESTDEFF\n${PAYMENT_NOTE}`
)
// wieder leer: der Fuss hat keine Bankzeile mehr
// wieder leer: der Fuss hat keine Bankzeile mehr (derselbe Inhalt wie eben: den Schutz vor doppeltem Anlegen zuruecksetzen)
assert.equal((await patchSettings({ bankDetailsText: '' })).status, 200)
resetInvoiceCreateGuardForTests()
await createProjectInvoice({ customerId: 'c1', items: ITEMS, createdBy: 'kenso@example.invalid' })
assert.equal(footerOfLastDraft(), `${config.stripe.invoiceFooter}\n${PAYMENT_NOTE}`)
})