fix: ein abgebrochener Checkout hinterlaesst keine Bestellung mehr
Bisher blieb nach einem Abbruch eine Bestellung im Status "STORNIERT" stehen. Im Admin-Bereich sah damit jeder weggeklickte Warenkorb aus wie ein echter, gescheiterter Verkauf — bei einem Shop, in dem die meisten Besuche nicht im Kauf enden, verdecken diese Einträge irgendwann die tatsächlichen Vorgänge. Ein nie bezahlter Checkout wird deshalb gelöscht statt storniert. Es gab kein Geschäft, keine Zahlung, keine Bestätigung und keine Rechnung, also auch nichts aufzubewahren; die Positionen gehen mit (onDelete: Cascade). Betroffen sind der Abbruch-Knopf, die abgelaufene Stripe-Sitzung und der Aufräumlauf. Eine Ausnahme bleibt bewusst bestehen: checkout.session.async_payment_failed. Dort wurde tatsächlich eine Zahlung versucht und ist gescheitert (SEPA-Lastschrift, teils Klarna) — die Kundschaft hat den Checkout abgeschlossen und rechnet mit einer Lieferung. Dieser Fall bleibt als "STORNIERT" nachvollziehbar und wird weiterhin per E-Mail beantwortet. Beim bloßen Abbruch entfällt die Mail: eine Nachricht über einen Vorgang, den man selbst abgebrochen hat, verwirrt mehr als sie hilft. releaseUnpaidOrder unterscheidet die beiden Fälle jetzt über einen Parameter. Beim Löschen ist deleteMany mit der Statusbedingung der atomare Zugriff — es entfernt entweder genau diese eine noch unbezahlte Bestellung oder nichts. Hat inzwischen eine eingehende Zahlung den Status auf "BEZAHLT" gesetzt, fängt count === 0 das ab: eine bezahlte Bestellung darf dieser Weg unter keinen Umständen entfernen. Die Positionen werden vor dem Löschen gelesen, sonst wäre der Bestand danach nicht mehr zurückzubuchen. Die Reservierungsdauer bleibt bei 32 Minuten. Kürzer geht nicht: Stripe lässt als Untergrenze 30 Minuten zu (die zwei Minuten sind Puffer gegen auseinanderlaufende Uhren). Eine kürzere Reservierung ließe sich nur bauen, indem die Sitzung vorzeitig per API geschlossen wird — das hieße, einer Kundschaft, die gerade eine 3-D-Secure-Abfrage beantwortet, die Zahlung unter den Händen wegzunehmen. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
1 parent
a3f91b83fc
commit
dda0a66c6c
5 files changed
+105
-50
No files matched your search
@@ -95,11 +95,14 @@ async function main(): Promise<void> {
|
||||
continue;
|
||||
}
|
||||
|
||||
const result = await releaseUnpaidOrder(order.id, 0);
|
||||
// "delete": nie bezahlt, nie bestaetigt — die Vormerkung verschwindet
|
||||
// mitsamt der Bestellung, statt als "STORNIERT" im Admin-Bereich wie
|
||||
// ein gescheiterter Verkauf auszusehen.
|
||||
const result = await releaseUnpaidOrder(order.id, "delete");
|
||||
if (result) {
|
||||
released += 1;
|
||||
console.log(
|
||||
`[release-stale-orders] ${result.orderNumber}: Bestand freigegeben (Sitzung abgelaufen).`
|
||||
`[release-stale-orders] ${result.orderNumber}: Bestand freigegeben, Vormerkung entfernt (Sitzung abgelaufen).`
|
||||
);
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
|
||||
Reference in new issue
Block a user