billing: Stripe-Belege auf Deutsch und sprechende Produktnamen
Drei Stellschrauben für die Stripe-Rechnung (Befund Test-Buchung: englischer Beleg, Position nur 'Starter'): - stripePreferredLocales() am User: Stripe rendert Rechnung/Quittung in der Kontosprache (de-DE, bei language=en englisch) - Checkout-Session mit locale in der Kontosprache statt Auto-Erkennung - billing:sync-stripe-plans vergibt sprechende Produktnamen inkl. PM-Kontingent und zieht sie bei bereits verknüpften Plänen an den bestehenden Stripe-Produkten nach (Preise bleiben unverändert) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
f1dcb9cd6b
commit
5585a26380
4 changed files with 51 additions and 2 deletions
|
|
@ -36,7 +36,20 @@ class SyncStripePlans extends Command
|
|||
|
||||
foreach (Plan::query()->active()->get() as $plan) {
|
||||
if ($plan->stripe_product_id && $plan->stripe_price_id_monthly && $plan->stripe_price_id_yearly) {
|
||||
$this->line("{$plan->slug}: vollständig verknüpft, übersprungen.");
|
||||
// Preise sind unveränderlich, der Produktname nicht: Er wird
|
||||
// bei jedem Lauf nachgezogen, damit Stripe-Belege den
|
||||
// sprechenden Namen tragen (statt z. B. nur "Starter").
|
||||
if ($dryRun) {
|
||||
$this->line("[dry-run] {$plan->slug}: verknüpft — Produktname auf \"{$this->stripeProductName($plan)}\" aktualisieren.");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$stripe->products->update($plan->stripe_product_id, [
|
||||
'name' => $this->stripeProductName($plan),
|
||||
]);
|
||||
|
||||
$this->line("{$plan->slug}: verknüpft — Produktname aktualisiert.");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
|
@ -56,7 +69,7 @@ class SyncStripePlans extends Command
|
|||
|
||||
if (! $productId) {
|
||||
$product = $stripe->products->create([
|
||||
'name' => $plan->name,
|
||||
'name' => $this->stripeProductName($plan),
|
||||
'metadata' => ['plan_slug' => $plan->slug],
|
||||
]);
|
||||
$productId = $product->id;
|
||||
|
|
@ -124,6 +137,19 @@ class SyncStripePlans extends Command
|
|||
$this->warn("Bitte in die .env eintragen: STRIPE_PRICE_SINGLE_PM={$price->id}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sprechender Produktname für Stripe-Belege: Auf Rechnung und
|
||||
* Checkout-Seite erscheint sonst nur der nackte Tarifname.
|
||||
*/
|
||||
private function stripeProductName(Plan $plan): string
|
||||
{
|
||||
return sprintf(
|
||||
'Tarif %s — %d Pressemitteilungen/Monat (pressekonto)',
|
||||
$plan->name,
|
||||
$plan->press_release_quota,
|
||||
);
|
||||
}
|
||||
|
||||
private function createPrice(object $stripe, string $productId, Plan $plan, int $unitAmount, string $interval): string
|
||||
{
|
||||
$price = $stripe->prices->create([
|
||||
|
|
|
|||
|
|
@ -123,6 +123,18 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||
return $address?->company ?: ($address?->name ?: $this->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sprache für Stripe-Belege (Cashier-Hook): Rechnungen, Quittungen und
|
||||
* Mahn-Mails von Stripe folgen der Kontosprache statt Stripes
|
||||
* Englisch-Default.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function stripePreferredLocales(): ?array
|
||||
{
|
||||
return [$this->language === 'en' ? 'en' : 'de-DE'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Buchungs-Voraussetzung (Entscheidung 12.06.2026): Tarif- und
|
||||
* Einzel-PM-Checkouts erfordern eine vollständige Rechnungsadresse.
|
||||
|
|
|
|||
|
|
@ -348,6 +348,8 @@ class StripeCheckoutService
|
|||
'cancel_url' => route('me.bookings.index', ['checkout' => 'abbruch']),
|
||||
'billing_address_collection' => 'auto',
|
||||
'automatic_tax' => ['enabled' => true],
|
||||
// Checkout-Seite in der Kontosprache statt Browser-Erkennung.
|
||||
'locale' => $user->language === 'en' ? 'en' : 'de',
|
||||
];
|
||||
|
||||
if ($user->stripeAddress() === null) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue