From 21805c9a93c055a9ec13c82fc3bbe045b5948bd5 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 09:35:40 +0000 Subject: [PATCH] Shop Review A M6: Stripe-Status auf 4000 Zeichen begrenzen (30 Eintraege zu 100 Zeichen, notfalls weiter kuerzen) Co-Authored-By: Claude Opus 5.5 --- server/services/shop/connect.js | 26 +++++++++++++++++++++----- test/shopConnect.test.js | 12 ++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/server/services/shop/connect.js b/server/services/shop/connect.js index 367f489..6e1e4e1 100644 --- a/server/services/shop/connect.js +++ b/server/services/shop/connect.js @@ -80,18 +80,34 @@ export async function onboardingLink(accountId, { returnUrl, refreshUrl }) { return link.url } -/** Bereitschaftsstatus aus einem Konto-Objekt (auch fuer den Webhook account.updated). Rein bis auf die Zeit. */ +const MAX_EINTRAEGE = 30 +const MAX_EINTRAG_ZEICHEN = 100 +/** Die Spalte stripeStatus fasst 4000 Zeichen; darunter bleibt Platz fuer den Hinweis zu Klarna/SEPA (merkeHinweis). */ +const MAX_STATUS_JSON = 3500 +const kapp = (liste) => + (Array.isArray(liste) ? liste : []).filter((e) => typeof e === 'string').slice(0, MAX_EINTRAEGE).map((e) => e.slice(0, MAX_EINTRAG_ZEICHEN)) + +/** + * Bereitschaftsstatus aus einem Konto-Objekt (auch fuer den Webhook account.updated). Rein bis auf die Zeit. Die Listen werden + * auf 30 Eintraege zu je 100 Zeichen gekappt und notfalls weiter gekuerzt, damit das JSON in die Spalte stripeStatus (4000 Zeichen) passt. + */ export function statusAusKonto(account, now = new Date()) { const req = account?.requirements || {} - return { + const status = { charges_enabled: account?.charges_enabled === true, payouts_enabled: account?.payouts_enabled === true, details_submitted: account?.details_submitted === true, - currently_due: Array.isArray(req.currently_due) ? [...req.currently_due] : [], - past_due: Array.isArray(req.past_due) ? [...req.past_due] : [], - disabled_reason: req.disabled_reason ?? null, + currently_due: kapp(req.currently_due), + past_due: kapp(req.past_due), + disabled_reason: typeof req.disabled_reason === 'string' ? req.disabled_reason.slice(0, MAX_EINTRAG_ZEICHEN) : (req.disabled_reason ?? null), geprueftAt: new Date(now).toISOString(), } + while (JSON.stringify(status).length > MAX_STATUS_JSON) { + const laenger = status.currently_due.length >= status.past_due.length ? status.currently_due : status.past_due + if (laenger.length === 0) break + laenger.pop() + } + return status } export async function kontoStatus(accountId) { diff --git a/test/shopConnect.test.js b/test/shopConnect.test.js index 4b42447..1a0c901 100644 --- a/test/shopConnect.test.js +++ b/test/shopConnect.test.js @@ -126,6 +126,18 @@ test('statusAusKonto ist rein und robust gegen fehlende Felder', () => { assert.deepEqual(eingabe.requirements.currently_due, ['a']) }) +test('statusAusKonto M6: lange Listen werden gekappt (30 Eintraege, 100 Zeichen), das Ergebnis passt als JSON in 4000 Zeichen', () => { + const lang = Array.from({ length: 80 }, (_, i) => `individual.verification.document.${'x'.repeat(200)}${i}`) + const aus = connect.statusAusKonto({ requirements: { currently_due: lang, past_due: lang, disabled_reason: 'r'.repeat(500) } }) + assert.ok(aus.currently_due.length <= 30 && aus.past_due.length <= 30) + assert.ok([...aus.currently_due, ...aus.past_due].every((e) => e.length <= 100)) + assert.ok(aus.disabled_reason.length <= 100) + assert.ok(JSON.stringify(aus).length <= 3500, `JSON ${JSON.stringify(aus).length} Zeichen`) + assert.ok(aus.currently_due.length > 0 && aus.past_due.length > 0, 'beide Listen behalten Eintraege') + // kurze Listen bleiben unveraendert, Nicht-Texte werden uebersprungen + assert.deepEqual(connect.statusAusKonto({ requirements: { currently_due: ['a', 5, null, 'b'] } }).currently_due, ['a', 'b']) +}) + test('Checkout, Abruf, Ablauf: Stripe-Account-Kopfzeile, Idempotenz, Ablage je Konto', async () => { const id = await connect.kontoAnlegen({ customer, project }) const other = 'acct_andere1'