Cashier spiegelt die Periode nicht lokal; neuer SubscriptionPeriodResolver holt start_date + current_period_end (Item-Ebene) gecacht, Fallback null. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
47 lines
1.6 KiB
PHP
47 lines
1.6 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Billing;
|
|
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Laravel\Cashier\Subscription;
|
|
use Throwable;
|
|
|
|
/**
|
|
* Ermittelt Buchungs- und Verlängerungsdatum eines echten Stripe-Abos.
|
|
*
|
|
* Cashier v15 spiegelt die Abrechnungsperiode nicht lokal in die
|
|
* `subscriptions`-Tabelle; in der aktuellen Stripe-API liegt
|
|
* `current_period_end` zudem auf Item-Ebene. Deshalb ein einmaliger,
|
|
* kurz gecachter Stripe-Abruf (überlebt Livewire-Re-Renders, invalidiert
|
|
* bei jeder Abo-Änderung über `updated_at`). Bei Netzwerk-/API-Fehlern
|
|
* wird still `null` zurückgegeben, damit die Buchungsseite immer rendert.
|
|
*/
|
|
class SubscriptionPeriodResolver
|
|
{
|
|
/**
|
|
* @return array{booked_at: Carbon, renews_at: Carbon}|null
|
|
*/
|
|
public function resolve(Subscription $subscription): ?array
|
|
{
|
|
$cacheKey = "subscription-period:{$subscription->stripe_id}:".($subscription->updated_at?->timestamp ?? 0);
|
|
|
|
return Cache::remember($cacheKey, now()->addMinutes(10), function () use ($subscription): ?array {
|
|
try {
|
|
$stripe = $subscription->asStripeSubscription();
|
|
$renewsAt = $stripe->items->data[0]->current_period_end ?? null;
|
|
|
|
if (! $renewsAt) {
|
|
return null;
|
|
}
|
|
|
|
return [
|
|
'booked_at' => Carbon::createFromTimestamp($stripe->start_date),
|
|
'renews_at' => Carbon::createFromTimestamp($renewsAt),
|
|
];
|
|
} catch (Throwable) {
|
|
return null;
|
|
}
|
|
});
|
|
}
|
|
}
|