Phase 9E (Backbone): Stripe-Produkt-Sync und Webhook-Verarbeitung mit STR-Spiegelung

- billing:sync-stripe-plans: legt die Tarife als Netto-Produkte/Preise
  (tax_behavior exclusive, EUR) in Stripe an und pflegt die IDs zurueck
  nach plans; idempotent, --dry-run. Gegen Stripe Test-Mode ausgefuehrt —
  alle 4 Tiers verknuepft.
- ProcessStripeWebhook (Listener auf Cashier WebhookReceived):
  - invoice.payment_succeeded -> Spiegelung in den lokalen STR-Kreis
    (fortlaufende Nummer via InvoiceNumberGenerator, Adress-Snapshot
    bevorzugt aus dem Stripe-Payload inkl. lokaler USt-ID, Status paid,
    idempotent gegen doppelte Zustellung)
  - checkout.session.completed -> markiert den referenzierten
    single_purchases-Datensatz als bezahlt (Metadata single_purchase_id)
- CASHIER_CURRENCY=eur (+ Locale de_DE); Cashier-Webhook-Route aktiv
- Doku: Billing-Referenz §7 + Phase-9-Plan (9E-Backbone) aktualisiert

Offen fuer 9E-Rest: Checkout-Flows (Abo + Einmalkauf), Webhook-Endpoint
im Stripe-Dashboard + STRIPE_WEBHOOK_SECRET, Slot-Logik auf
Plan-Kontingent (fachliche Frage: Grandfathered = unbegrenzt?).

Tests: StripeWebhookProcessingTest (7, inkl. Event-Wiring).
Suite: 497 passed, 4 skipped. Pint clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-06-12 11:07:09 +00:00
parent 62e6b7e70f
commit 38fab64e10
5 changed files with 400 additions and 6 deletions

View file

@ -129,12 +129,22 @@ Stripe/Cashier (`config/cashier.php`):
---
## 7. Offene Punkte (Stand 12.06.2026)
## 7. Offene Punkte (Stand 12.06.2026, nach 9E-Backbone)
1. **Phase 9E**: Stripe-Produkte/Preise anlegen (netto) + IDs in `plans`
pflegen, Checkout (Abo + Einmalkauf), Webhooks inkl. Spiegelung der
Stripe-Rechnungen nach `invoices` mit STR-Nummer, Slot-Logik von
`users.press_release_quota`-Stub auf Plan-Kontingent umstellen.
0. **9E-Backbone erledigt**: Tarife liegen als Netto-Produkte/Preise in
Stripe (Test-Mode, `billing:sync-stripe-plans`, IDs in `plans`);
Webhook-Listener `ProcessStripeWebhook` spiegelt bezahlte
Stripe-Rechnungen in den STR-Kreis (fortlaufende Nummer,
Adress-Snapshot aus dem Stripe-Payload, idempotent) und erfüllt
Einmalkäufe (`checkout.session.completed`
`single_purchases.status = paid`). Cashier-Route `POST /stripe/webhook`
ist aktiv.
1. **Phase 9E (Rest)**: Checkout-Flows (Abo + Einmalkauf) inkl.
Buchungs-Seite, Webhook-Endpoint im Stripe-Dashboard registrieren +
`STRIPE_WEBHOOK_SECRET` setzen, Slot-Logik von
`users.press_release_quota`-Stub auf Plan-Kontingent umstellen
(fachlich zu klären: Kontingent-Semantik für Grandfathered —
Legacy-Produkt war „unbegrenzte PMs pro Pressemappe").
2. **VIES-Validierung** der USt-ID (aktuell Formatprüfung).
3. **PDF-Erzeugung** für MAN-/STR-Rechnungen (Layout inkl. `tax_note`);
Archiv-PDFs existieren bereits on-demand.