Stripe Checkout: automatic_tax aktiviert (USt fehlte in der Session)

Cashier::calculateTaxes() greift nur bei direkter Abo-Erstellung, nicht
bei Checkout-Sessions — Stripe zeigte darum nur den Nettopreis
(QA-Befund 07.07.). Session-Optionen setzen jetzt automatic_tax +
tax_id_collection; Ad-hoc-Buchungen (Credits, Depublikation) laufen
statt ueber checkoutCharge ueber price_data mit tax_behavior=exclusive,
da automatic_tax das verlangt. Stripe Tax im Testmode eingerichtet
(Origin Bielefeld, DE-Registrierung); Live-Schritt in WS-7 ergaenzt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-07 11:25:28 +00:00
parent fa4bc060a0
commit 4b7403bd4e
2 changed files with 37 additions and 10 deletions

View file

@ -82,6 +82,12 @@ class StripeCheckoutService
* Name, Pflicht bei USt-ID-Abfrage) wird darum am Stripe-Customer
* gespeichert (`customer_update: auto`).
*
* `automatic_tax` muss hier explizit gesetzt werden:
* Cashier::calculateTaxes() greift nur bei direkter Abo-Erstellung,
* NICHT bei Checkout-Sessions — ohne das Flag zeigt Stripe nur den
* Nettopreis an (QA-Befund 07.07.). Voraussetzung im Stripe-Account:
* Stripe Tax mit Origin-Adresse und DE-Registrierung (WS-7).
*
* @return array<string, mixed>
*/
private function sessionOptions(): array
@ -90,6 +96,8 @@ class StripeCheckoutService
'success_url' => route('me.bookings.index', ['checkout' => 'erfolg']),
'cancel_url' => route('me.bookings.index', ['checkout' => 'abbruch']),
'billing_address_collection' => 'required',
'automatic_tax' => ['enabled' => true],
'tax_id_collection' => ['enabled' => true],
'customer_update' => [
'address' => 'auto',
'name' => 'auto',
@ -97,6 +105,26 @@ class StripeCheckoutService
];
}
/**
* Line-Item für Ad-hoc-Beträge (ohne Stripe-Price). `tax_behavior`
* ist Pflicht, sobald `automatic_tax` aktiv ist — Cashiers
* checkoutCharge() setzt es nicht und ist darum hier ersetzt.
*
* @return array<string, mixed>
*/
private function adHocLineItem(int $priceCents, string $name): array
{
return [
'price_data' => [
'currency' => config('cashier.currency', 'eur'),
'product_data' => ['name' => $name],
'unit_amount' => $priceCents,
'tax_behavior' => 'exclusive',
],
'quantity' => 1,
];
}
/**
* URL zum Stripe Billing Portal (Zahlungsmethode, Rechnungen, Kündigung).
* Rücksprung auf die Buchungs-Seite.
@ -130,10 +158,8 @@ class StripeCheckoutService
{
$this->syncTaxIdFromBillingAddress($user);
return $user->checkoutCharge(
$purchase->price_cents,
'Depublikation einer Pressemitteilung',
1,
return $user->checkout(
[$this->adHocLineItem($purchase->price_cents, 'Depublikation einer Pressemitteilung')],
[
...$this->sessionOptions(),
'metadata' => ['single_purchase_id' => (string) $purchase->id],
@ -150,10 +176,8 @@ class StripeCheckoutService
{
$this->syncTaxIdFromBillingAddress($user);
return $user->checkoutCharge(
$topup->price_cents,
"Credit-Guthaben ({$topup->credits} Credits)",
1,
return $user->checkout(
[$this->adHocLineItem($topup->price_cents, "Credit-Guthaben ({$topup->credits} Credits)")],
[
...$this->sessionOptions(),
'metadata' => ['credit_topup_id' => (string) $topup->id],