@extends('layouts.dashboard') @section('content') @php /** * ONE SCREEN FOR A VENDOR PAYMENT: how it will be paid on the left, what is being paid on the right. * * The panel's checkout used to be two pages — a chooser, then a gateway page — because the gateway * session had to exist before the widget could mount, and it could not exist until a provider was * known. So picking PayPal cost a page load before anything could be typed. The session is now * opened when the owner PAYS (CampaignController::prepare), which removes the reason for the first * page: every tender fits on one screen, and a checkout that is merely LOOKED at opens nothing at * the gateway. * * This is the customer checkout's shape (views/public/checkout.php), not a new one — the same * .qm-pay-option rows, the same reveal-on-select, the same deferred Stripe element — so the two * halves of the product finally read alike. * * ONE
WRAPS BOTH COLUMNS. The tender is chosen on the left and the button that acts on it * sits on the right beside the total; they have to be the same form or the button would submit * nothing. * * @var string $token the checkout handle * @var string $planName what is being bought, in words * @var float $amount the GROSS about to be charged * @var string $currency * @var array $methods enabled gateways, e.g. ['stripe','paypal'] * @var array $savedCards this owner's usable cards * @var int $preselectCardId * @var string $methodUrl where a saved-card choice posts (charged server-side) * @var string $prepareUrl where the browser asks for a gateway session, at pay time * @var string $confirmUrl * @var string $callbackUrl * @var string $trackUrl back to the list, attempt left open * @var string $cancelUrl back to the list, attempt released * @var string $stripeKey '' when Stripe is not enabled * @var string $paypalKey '' when PayPal is not enabled */ $savedCards = $savedCards ?? []; $preselectCardId = (int) ($preselectCardId ?? 0); $methods = $methods ?? []; $stripeKey = (string) ($stripeKey ?? ''); $paypalKey = (string) ($paypalKey ?? ''); /* NON-EMPTY MEANS "THIS IS AN AGREEMENT". No SDK reads it any more — PayPal is reached through the approval link prepare() returns — so the value is only a flag the script uses to mount Stripe around prepare()'s secret instead of the deferred one-off element. */ $planRef = (string) ($planRef ?? ''); $startTime = (string) ($startTime ?? ''); /* WHICH ROW IS CHOSEN WHEN THE PAGE OPENS. The card they last paid with, else the first usable card, else the first gateway — so the common case is: open, press pay. */ $firstCard = null; foreach ($savedCards as $sc) { if (\App\Models\PaymentMethod::isUsable($sc)) { $firstCard = $sc; break; } } $checked = $preselectCardId > 0 ? 'card_' . $preselectCardId : ($firstCard ? 'card_' . (int) $firstCard['id'] : (string) ($methods[0] ?? '')); /* THE SUM, BROKEN OUT. $amount is the gross about to be taken; the summary shows what it is made of, because a total nobody can decompose is a total nobody trusts — the annual list price and discount when one applies, the tax line, the total. partials/pay-summary.php does it, shared with the signup checkout and read from the same Invoice::taxOn() the invoice is carved from. @var float|null $listAmount @var float $discountPct — passed by PlansController only. */ @endphp @php /* .qm-d2: the dashboard density standard (app.css §35) */ @endphp
@csrf
@php /* HOW YOU PAY. The wide column, because this is the only decision on the page. */ @endphp

{{ t_raw('checkout.payment_method') }}

@php /* A saved card is charged by the SERVER — the form posts the choice and the money is taken off-session, exactly as the old chooser did. Only the two gateway rows need a widget, and only the selected one is shown. */ @endphp
@foreach ($savedCards as $sc) @php if (!\App\Models\PaymentMethod::isUsable($sc)) { continue; } @endphp @php $val = 'card_' . (int) $sc['id']; @endphp
@endforeach @foreach ($methods as $m)
@php /* THE WIDGET BELONGS TO THE ROW THAT OPENS IT. Both mounts used to sit in a block below the whole list, so choosing PayPal made a button appear somewhere else on the page and read as a second, unexplained step. Attached here, the row and its control are one thing. PayPal's own button is the only way to open their approval popup — it must be clicked directly, which is why the form's Pay button is hidden while PayPal is the selected tender. */ @endphp @if ($m !== 'paypal') @endif
@endforeach
@php /* WHAT YOU PAY, and the button that acts on it — together, so the sum and the act are read in one glance rather than a scroll apart. */ @endphp

{{ t_raw('cart.summary') }}

@partial('pay-summary', [ 'label' => (string) $planName, 'amount' => (float) $amount, 'listAmount' => $listAmount ?? null, 'discountPct' => (float) ($discountPct ?? 0), ]) @php /* WHAT TERM this buys — the one sentence that separates an annual charge from a monthly one at the moment of paying. Lifetime says nothing: the page already carries no renewal language for it. */ @endphp @php $termCycle = (string) ($termCycle ?? ''); @endphp @if ($termCycle === 'yearly')

{{ t_raw('vendor.billing.term_yearly_note') }}

@elseif ($termCycle === 'monthly')

{{ t_raw('vendor.billing.term_monthly_note') }}

@endif @php /* TWO WAYS OUT, AND THEY ARE NOT THE SAME THING. Back returns to the list with the attempt still open; Cancel releases it. One link read "Cancel and go back to your campaigns", which is both at once and therefore neither. */ @endphp @php /* One way out. Back returns to the list; the staged attempt releases itself when it is next opened or replaced, so a second "cancel" control only asked the owner to understand a distinction that costs them nothing. */ @endphp
@if ($stripeKey !== '') @endif @php /* NO PAYPAL SDK. Its Smart Buttons drew a second, differently-styled control inside a tender list the payer had already chosen from — and only for some purchases. The server opens both an order and an agreement now and hands back an approval link, so PayPal is reached through this page's own button and window, like every other tender. */ @endphp
@php /* /.qm-d2 */ @endphp @endsection