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:
1 parent
ef2ce49669
commit
daa451094a
8 files changed
+476
-48
No files matched your search
@@ -46,7 +46,8 @@ const BANK_UNAVAILABLE_MESSAGE = 'Die Bank hat die Freigabe nicht bestätigt. Bi
|
||||
const publicDoc = (doc) => Object.fromEntries(Object.entries(doc).filter(([key]) => key === '$id' || !key.startsWith('$')))
|
||||
|
||||
/** Fehlerart fuers Protokoll: nie die Meldung (sie koennte Kennungen der Bank oder von Appwrite enthalten). */
|
||||
const logFailure = (what, err) => console.error(`[finanzen] ${what} fehlgeschlagen:`, err?.name || 'Error', err?.status ?? '', err?.code ?? '')
|
||||
const logFailure = (what, err) =>
|
||||
console.error(`[finanzen] ${what} fehlgeschlagen:`, err?.type || err?.name || 'Error', err?.status ?? err?.statusCode ?? '', err?.code ?? '')
|
||||
|
||||
router.get('/uebersicht', async (_req, res) => {
|
||||
try {
|
||||
@@ -148,6 +149,8 @@ const isStripeError = (err) => typeof err?.type === 'string' && err.type.startsW
|
||||
*/
|
||||
function sendFinanceError(res, what, err) {
|
||||
if (err instanceof AssignError || err instanceof InvoiceError) {
|
||||
// Ein 502 an einer bestehenden Rechnung (nicht gesendet, nicht lesbar) hat seine Ursache bei Stripe: nur Art, Status und Code ins Protokoll
|
||||
if (err.status === 502 && err.cause) logFailure(what, err.cause)
|
||||
const body = { error: err.message }
|
||||
if (err.invoiceId) body.invoiceId = err.invoiceId
|
||||
if (err.invoiceNumber !== undefined) body.invoiceNumber = err.invoiceNumber
|
||||
@@ -205,7 +208,7 @@ router.get('/rechnungen', async (req, res) => {
|
||||
})
|
||||
|
||||
router.post('/rechnungen', async (req, res) => {
|
||||
const { customerId, items, daysUntilDue, memo, senden } = req.body || {}
|
||||
const { customerId, items, daysUntilDue, memo, senden, idempotencyKey } = req.body || {}
|
||||
try {
|
||||
const rechnung = await createProjectInvoice({
|
||||
customerId,
|
||||
@@ -214,6 +217,8 @@ router.post('/rechnungen', async (req, res) => {
|
||||
memo,
|
||||
// Nur ein echtes Ja sendet sofort: alles andere bleibt ein Entwurf
|
||||
senden: senden === true || senden === 'true',
|
||||
// Optional: ein Schluessel je beabsichtigter Rechnung schuetzt vor doppeltem Anlegen (siehe createProjectInvoice)
|
||||
idempotencyKey,
|
||||
createdBy: req.appwriteUser?.email,
|
||||
})
|
||||
return res.json({ rechnung })
|
||||
|
||||
Reference in new issue
Block a user