feat: Folgeraten über Stripe Billing einziehen

Statt eigener Off-Session-Einzüge durch den Worker legt die Anwendung nach
bezahlter erster Rate einen Stripe Subscription Schedule an. Stripe übernimmt
Einzug, Wiederholungen (Smart Retries), 3-D-Secure-Links und Mahnungen.

- Gateway: Zeitplan anlegen/beenden, Rechnungen lesen; chargeOffSession entfällt
- Webhook: invoice.paid, invoice.payment_failed, invoice.payment_action_required
- Worker: fehlende Zeitpläne anlegen, überfällige Raten abgleichen,
  Zeitpläne stornierter Buchungen beenden
- Storno beendet den Zeitplan und storniert offene Rechnungen
- "Rate bezahlen" führt auf Stripes Rechnungsseite
- Migration: Booking.stripeScheduleId, Installment.stripeInvoiceId

Zeitplan-Form mit Stripe-Testuhr gegen die Test-API geprüft.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-10-05 23:52:43 +02:00
1 parent bcf0f5c937
commit c1ad9ad2ca
18 files changed
+800 -555

No files matched your search

+5
View File
@@ -191,6 +191,9 @@ model Booking {
/// Zahlungsmethode. Wird nach der letzten Rate bei Stripe getrennt.
stripePaymentMethodId String?
paymentMethodDetachedAt DateTime?
/// Stripe-Billing-Zeitplan, der die Folgeraten einzieht (nur Ratenzahlung).
/// Stripe uebernimmt Einzug, Wiederholungen und Mahnungen.
stripeScheduleId String? @unique
paidCents Int @default(0)
refundedCents Int @default(0)
@@ -246,6 +249,8 @@ model Installment {
stripePaymentIntentId String? @unique
stripeChargeId String? @unique
/// Stripe-Rechnung, ueber die Stripe Billing diese Folgerate einzieht.
stripeInvoiceId String? @unique
/// Offene Checkout-Session, ueber die die Kundin diese Rate selbst zahlt.
checkoutSessionId String? @unique
checkoutExpiresAt DateTime?