resolveRedeemableLink($token); return view('portal.abo.card_update_link', [ 'user_abo' => $link->user_abo, 'token' => $token, ]); } public function store(UpdateAboCreditCardRequest $request, string $token, AboPaymentMethodService $service) { $link = $this->resolveRedeemableLink($token); $user_abo = $link->user_abo; $returnUrls = [ 'successurl' => route('abo_card_update_return', [$token, 'success']), 'errorurl' => route('abo_card_update_return', [$token, 'error']), 'backurl' => route('abo_card_update_return', [$token, 'cancel']), ]; $result = $service->updateCreditCard($user_abo, $request->toDto(), $returnUrls, 'link'); if ($result->isApproved()) { $link->forceFill(['used_at' => now()])->save(); return view('portal.abo.card_update_done', ['success' => true]); } if ($result->isRedirect()) { session(['abo_card_update.'.$user_abo->id => [ 'carddata' => $result->carddata, 'userid' => $result->userid, ]]); return redirect()->away($result->redirectUrl); } return redirect(route('abo_card_update_show', [$token])) ->withErrors(['cc_cardpan' => $result->errorMessage ?? __('abo.card_update_failed')]); } /** * Startet den Stripe-Setup-Flow "Zahlungsart ändern" (Plan S5) über den * tokenisierten Link: Redirect zur Hosted-Seite, freie Zahlartenwahl. */ public function startStripe(string $token, AboPaymentMethodService $service) { $link = $this->resolveRedeemableLink($token); abort_unless($service->usesStripeChange(), 404); $result = $service->beginStripeChange( $link->user_abo, route('abo_card_update_return', [$token, 'success']).'?session_id={CHECKOUT_SESSION_ID}', route('abo_card_update_return', [$token, 'cancel']), 'link', ); if ($result->isRedirect()) { return redirect()->away($result->redirectUrl); } return redirect(route('abo_card_update_show', [$token])) ->withErrors(['cc_cardpan' => $result->errorMessage ?? __('abo.payment_method_change_failed')]); } public function return(string $token, string $status, AboPaymentMethodService $service) { $link = $this->resolveRedeemableLink($token); $user_abo = $link->user_abo; // Stripe-Setup-Return (Plan S5): Session prüfen, Zahlungsart verankern, Link entwerten. if ($status === 'success' && ($sessionId = request('session_id'))) { if ($service->finalizeStripeChangeFromSession($user_abo, (string) $sessionId, 'link')) { $link->forceFill(['used_at' => now()])->save(); return view('portal.abo.card_update_done', ['success' => true]); } return view('portal.abo.card_update_done', ['success' => false]); } $stash = session()->pull('abo_card_update.'.$user_abo->id); if ($status === 'success' && is_array($stash)) { $service->applyNewCard($user_abo, $stash['carddata'], (int) ($stash['userid'] ?? 0), 'link'); $link->forceFill(['used_at' => now()])->save(); return view('portal.abo.card_update_done', ['success' => true]); } $user_abo->forceFill(['card_update_pending_at' => null])->save(); return view('portal.abo.card_update_done', ['success' => false]); } private function resolveRedeemableLink(string $token): AboCardUpdateLink { $link = AboCardUpdateLink::where('token_hash', AboCardUpdateLink::hashToken($token))->first(); if (! $link || ! $link->isRedeemable()) { abort(410, __('abo.card_update_link_invalid')); } $abo = $link->user_abo; if (! $abo || ! app(AboPaymentMethodService::class)->canStartChange($abo)) { abort(410, __('abo.card_update_link_invalid')); } return $link; } }