Downgrade-Vorkehrungen: Kontingent-Sperre beim Tarifwechsel, Gutschriften nicht spiegeln

QA-Befund 07.07.: Der Wechsel zurück in einen kleineren Tarif erzeugte
eine Proration-Gutschrift (negative Stripe-Rechnung) — die STR-Spiegelung
crashte an den unsigned-Spalten (Webhook-500), und der Wechsel war trotz
verbrauchtem Monatskontingent möglich.

- ProcessStripeWebhook: Belege ohne positiven Rechnungsbetrag
  (Gutschrift/Null-Rechnung) werden geloggt übersprungen statt gespiegelt
- CheckoutController::swap: Wechsel gesperrt, wenn der Monatsverbrauch
  das Kontingent des Ziel-Tarifs übersteigt (möglich ab Monatserstem)
- Buchungs-Modal: erklärt die Sperre inkl. Datum statt Bestätigungs-
  Button; Proration-Hinweis deckt jetzt auch die Guthaben-Richtung ab

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-07 13:22:30 +00:00
parent 090a893cc6
commit 4b7f6d3f0f
6 changed files with 165 additions and 3 deletions

View file

@ -160,3 +160,29 @@ test('the listener is wired to the cashier webhook event', function () {
ProcessStripeWebhook::class,
);
});
test('a proration credit with a negative total is skipped without an invoice', function () {
// Downgrade-Gutschrift (QA-Befund 07.07.): negative Beträge sprengten
// die unsigned-Spalten und beantworteten den Webhook mit 500.
$user = User::factory()->create(['stripe_id' => 'cus_test_1']);
app(ProcessStripeWebhook::class)->handle(new WebhookReceived(stripeInvoicePayload($user, [
'subtotal' => -6992,
'tax' => -1329,
'total' => -8321,
])));
expect(Invoice::count())->toBe(0);
});
test('a zero-total stripe invoice is skipped without an invoice', function () {
$user = User::factory()->create(['stripe_id' => 'cus_test_1']);
app(ProcessStripeWebhook::class)->handle(new WebhookReceived(stripeInvoicePayload($user, [
'subtotal' => 0,
'tax' => 0,
'total' => 0,
])));
expect(Invoice::count())->toBe(0);
});