active()->where('slug', $planSlug)->firstOrFail(); $user = $request->user(); if (! $user->hasCompleteBillingAddress()) { return $this->backToProfile(); } if ($user->subscribed()) { return $this->backToBookings(__('Es besteht bereits ein aktives Abo. Ein Tarifwechsel ist aktuell über den Support möglich.')); } $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.')); } return $this->checkout->forSubscription($user, $plan, $interval); } public function singlePm(Request $request): Checkout|RedirectResponse { if (! $request->user()->hasCompleteBillingAddress()) { return $this->backToProfile(); } if (! config('billing.single_pm_stripe_price_id')) { return $this->backToBookings(__('Die Einzel-Pressemitteilung ist noch nicht buchbar. Bitte versuchen Sie es später erneut.')); } $purchase = SinglePurchase::query()->create([ 'user_id' => $request->user()->id, 'type' => SinglePurchaseType::SinglePm->value, 'status' => SinglePurchaseStatus::Pending->value, 'price_cents' => (int) config('billing.single_pm_price_cents'), 'currency' => 'EUR', ]); return $this->checkout->forSinglePurchase($request->user(), $purchase); } /** * Stripe Billing Portal: Selbstverwaltung des Abos (Zahlungsmethode, * Rechnungen, Kündigung). Nur mit aktivem Abo sinnvoll. */ public function billingPortal(Request $request): RedirectResponse { $user = $request->user(); if (! $user->hasStripeId() || ! $user->subscribed()) { return $this->backToBookings(__('Es besteht kein aktives Abo, das verwaltet werden könnte.')); } return redirect()->away($this->checkout->billingPortalUrl($user)); } private function backToBookings(string $notice): RedirectResponse { return redirect() ->route('me.bookings.index') ->with('checkout-notice', $notice); } /** * Buchungs-Voraussetzung (12.06.2026): ohne vollständige * Rechnungsadresse kein Checkout — der Hinweis erscheint direkt auf * der Profil-Seite über dem Rechnungsadress-Formular. */ private function backToProfile(): RedirectResponse { return redirect() ->route('me.profile') ->with('checkout-notice', __('Bitte hinterlegen Sie zuerst eine vollständige Rechnungsadresse — sie ist Voraussetzung für jede Buchung und wird an Stripe übergeben.')); } }