Tarifwechsel im Buchungs-Modal: Abo-Swap mit anteiliger Verrechnung
Tarif-Karten bieten bei bestehendem Abo jetzt 'Zu diesem Tarif wechseln' (pro Intervall, aktueller Tarif deaktiviert). Der Wechsel laeuft ueber das bekannte Bestaetigungs-Modal (T1neu-Checkbox) als POST auf die neue checkout.swap-Route: Cashier swapAndInvoice stellt sofort um, verrechnet anteilig und hebt eine vorgemerkte Kuendigung auf. SCA-Faelle leiten auf die Cashier-Bezahlseite. QA-Befund 07.07. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
256aca6112
commit
9e76e24014
6 changed files with 289 additions and 8 deletions
|
|
@ -13,7 +13,9 @@ use App\Services\Billing\CreditTopupService;
|
|||
use App\Services\Billing\StripeCheckoutService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Laravel\Cashier\Checkout;
|
||||
use Laravel\Cashier\Exceptions\IncompletePayment;
|
||||
|
||||
/**
|
||||
* Einstieg in die Stripe-Checkouts (Phase 9E): Tarif-Abo und Einzel-PM.
|
||||
|
|
@ -41,7 +43,7 @@ class CheckoutController extends Controller
|
|||
}
|
||||
|
||||
if ($user->subscribed()) {
|
||||
return $this->backToBookings(__('Es besteht bereits ein aktives Abo. Ein Tarifwechsel ist aktuell über den Support möglich.'));
|
||||
return $this->backToBookings(__('Es besteht bereits ein aktives Abo. Nutzen Sie den Tarifwechsel direkt an der gewünschten Tarif-Karte.'));
|
||||
}
|
||||
|
||||
$priceId = $interval === 'yearly'
|
||||
|
|
@ -55,6 +57,64 @@ class CheckoutController extends Controller
|
|||
return $this->checkout->forSubscription($user, $plan, $interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tarifwechsel eines aktiven Abos (POST aus dem Buchungs-Modal) — kein
|
||||
* neuer Stripe-Checkout: Stripe stellt das bestehende Abo sofort um und
|
||||
* verrechnet anteilig (swapAndInvoice). Eine vorgemerkte Kündigung wird
|
||||
* durch den Wechsel aufgehoben.
|
||||
*/
|
||||
public function swap(Request $request, string $planSlug, string $interval): RedirectResponse
|
||||
{
|
||||
$plan = Plan::query()->active()->where('slug', $planSlug)->firstOrFail();
|
||||
$user = $request->user();
|
||||
|
||||
if (! $user->hasCompleteBillingAddress()) {
|
||||
return $this->backToProfile();
|
||||
}
|
||||
|
||||
if ($redirect = $this->requireEntrepreneurConfirmation($request)) {
|
||||
return $redirect;
|
||||
}
|
||||
|
||||
$subscription = $user->subscription();
|
||||
|
||||
if (! $subscription || ! $subscription->valid()) {
|
||||
return $this->backToBookings(__('Es besteht kein aktives Abo — bitte buchen Sie den gewünschten Tarif direkt.'));
|
||||
}
|
||||
|
||||
$priceId = $interval === 'yearly'
|
||||
? $plan->stripe_price_id_yearly
|
||||
: $plan->stripe_price_id_monthly;
|
||||
|
||||
if (! $priceId) {
|
||||
return $this->backToBookings(__('Dieser Tarif ist noch nicht buchbar. Bitte versuchen Sie es später erneut.'));
|
||||
}
|
||||
|
||||
if ($subscription->stripe_price === $priceId) {
|
||||
return $this->backToBookings(__('Dieser Tarif ist bereits Ihr aktueller Tarif.'));
|
||||
}
|
||||
|
||||
try {
|
||||
$this->checkout->swapSubscription($user, $plan, $interval);
|
||||
} catch (IncompletePayment $exception) {
|
||||
return redirect()->route('cashier.payment', [
|
||||
$exception->payment->id,
|
||||
'redirect' => route('me.bookings.index', ['checkout' => 'wechsel']),
|
||||
]);
|
||||
} catch (\Throwable $exception) {
|
||||
Log::error('Tarifwechsel fehlgeschlagen.', [
|
||||
'user_id' => $user->id,
|
||||
'plan' => $plan->slug,
|
||||
'interval' => $interval,
|
||||
'error' => $exception->getMessage(),
|
||||
]);
|
||||
|
||||
return $this->backToBookings(__('Der Tarifwechsel konnte nicht durchgeführt werden. Bitte versuchen Sie es erneut oder wenden Sie sich an :email.', ['email' => (string) config('legal.contact_email')]));
|
||||
}
|
||||
|
||||
return redirect()->route('me.bookings.index', ['checkout' => 'wechsel']);
|
||||
}
|
||||
|
||||
public function singlePm(Request $request): Checkout|RedirectResponse
|
||||
{
|
||||
if (! $request->user()->hasCompleteBillingAddress()) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue