@extends('layouts.dashboard') @section('content') @php /** * Vendor → Payouts / Royalty. What the restaurant is owed (or owes) and its statement history. * Reuses the shared KPI card + .qm-table idiom — no new CSS. In franchise mode the same page reads * as royalty invoices the restaurant owes the platform (labels swap via $producesInvoices); * marketplace shows payouts owed to the restaurant. * * A marketplace payout is read-only here — the admin transfers it, and this page is the * restaurant's window onto that so it is never settled blind. A franchise INVOICE is not: the * restaurant owes that money, so an open one carries the button that settles it, in the status * cell where the owner learns it is waiting for them (the same place the sponsored-placement list * puts its own pay button, for the same reason). * * @var float $pendingNet money owed but not yet on a statement (payout owed / royalty due) * @var int $pendingCount unsettled orders behind that figure * @var array $statements this restaurant's statements, newest first * @var array $pager pagination for $statements * @var float $settledTotal lifetime settled (paid out / royalty paid) * @var bool $hasPayee whether a payee is on file (always true in franchise — not shown) * @var bool $producesInvoices franchise: statements are royalty invoices, not payouts * @var bool $canPayInvoice franchise: an open invoice can be settled from here right now */ $statements = $statements ?? []; $producesInvoices = $producesInvoices ?? false; $canPayInvoice = $canPayInvoice ?? false; // One label set per money model — payouts owed to the restaurant, or royalty invoices it owes. $L = $producesInvoices ? ['title' => 'vendor.royalty.title', 'intro' => 'vendor.royalty.intro', 'pending' => 'vendor.royalty.kpi_pending', 'settled' => 'vendor.royalty.kpi_settled', 'statements' => 'vendor.royalty.kpi_statements', 'history' => 'vendor.royalty.history_title', 'amount' => 'common.royalty', 'net' => 'vendor.royalty.col_net', 'empty' => 'vendor.royalty.empty', 'this_month' => 'vendor.payouts.kpi_this_month', 'avg' => 'vendor.payouts.kpi_avg'] : ['title' => 'vendor.payouts.title', 'intro' => 'vendor.payouts.intro', 'pending' => 'vendor.payouts.kpi_pending', 'settled' => 'vendor.payouts.kpi_settled', 'statements' => 'vendor.payouts.kpi_statements', 'history' => 'vendor.payouts.history_title', 'amount' => 'common.commission', 'net' => 'vendor.payouts.col_net', 'empty' => 'vendor.payouts.empty', 'this_month' => 'vendor.payouts.kpi_this_month', 'avg' => 'vendor.payouts.kpi_avg']; $statusPill = static fn (string $s): string => match ($s) { 'paid' => 'qm-pill-green', 'issued' => 'qm-pill-blue', 'disputed' => 'qm-pill-red', default => 'qm-pill-amber', }; $cur = setting('currency_symbol', '$'); @endphp @php /* .qm-d2: the dashboard density standard (app.css §35) */ @endphp
@php $kpiSparks = $kpiSparks ?? []; @endphp
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'amber', 'icon' => 'fa-hourglass-half', 'label' => t_raw($L['pending']), 'value' => money($pendingNet), 'spark' => $kpiSparks['pending'] ?? [], 'meta' => '' . t('vendor.payouts.kpi_pending_cap', [':n' => (int) $pendingCount]) . '']) @partial('kpi-card', ['variant' => 'panel', 'accent' => 'green', 'icon' => 'fa-check-circle', 'label' => t_raw($L['settled']), 'value' => money($settledTotal), 'spark' => $kpiSparks['settled'] ?? []]) @partial('kpi-card', ['variant' => 'panel', 'accent' => 'blue', 'icon' => 'fa-file-invoice-dollar', 'label' => t_raw($L['statements']), 'value' => number_format((int) ($pager['total'] ?? 0)), 'spark' => $kpiSparks['statements'] ?? []]) @partial('kpi-card', ['variant' => 'panel', 'accent' => 'teal', 'icon' => 'fa-calendar-check', 'label' => t_raw($L['this_month']), 'value' => money($paidThisMonth ?? 0), 'spark' => $kpiSparks['month'] ?? [], 'meta' => '' . t('vendor.payouts.kpi_this_month_cap') . '']) @partial('kpi-card', ['variant' => 'panel', 'accent' => 'violet', 'icon' => 'fa-chart-line', 'label' => t_raw($L['avg']), 'value' => money($avgStatement ?? 0), 'spark' => $kpiSparks['avg'] ?? [], 'meta' => '' . t('vendor.payouts.kpi_avg_cap') . ''])

{{ t_raw($L['title']) }}

{{ t_raw($L['intro']) }}

@if (!$hasPayee)
{{ t_raw('vendor.payouts.no_payee_warning') }} {{ t_raw('vendor.payouts.add_payee_link') }}
@endif

{{ t_raw($L['history']) }}

@if ($statements) @foreach ($statements as $s) @endforeach @else @partial('table-empty', ['colspan' => 7, 'icon' => 'fa-money-check-alt', 'msg' => t_raw($L['empty'])]) @endif
{{ t_raw('vendor.payouts.col_period') }} {{ t_raw('admin.users.col_orders') }} {{ t_raw('vendor.payouts.col_gross') }} {{ t_raw($L['amount']) }} {{ t_raw($L['net']) }} {{ t_raw('common.status') }} {{ t_raw('vendor.payouts.col_reference') }}
{!! fmt_day($s['period_start']) !!} – {!! fmt_day($s['period_end']) !!} {{ number_format((int) $s['orders_count']) }} {{ money($s['gross_sales']) }} {{ money($s['commission_total']) }} {{ money($s['net_payable']) }} {{ status_label('payout', (string) $s['status']) }} @php /* An invoice the platform has raised but not been paid — draft or issued — is money this restaurant owes, so it gets the way to hand it over. ONE button, not one per gateway: which gateway is asked at checkout, next to the figure it applies to. A statement worth nothing has no charge to open and is skipped, exactly as the controller's own payable test does. */ @endphp @if ($canPayInvoice && in_array((string) $s['status'], ['draft', 'issued'], true) && (float) $s['net_payable'] > 0)
@csrf
@endif
{!! $s['payment_ref'] ? e((string) $s['payment_ref']) : dash() !!}
@partial('table-toolbar', ['pager' => $pager, 'base' => '/vendor/payouts'])
@php /* /.qm-d2 */ @endphp @endsection