@extends('backend.layout.master-tailwind')
@section('title', __('Payments'))
@section('breadcrumb_section', 'Marketplace')
@section('breadcrumb_page', __('Payments'))
@section('admin_styles')
@endsection
@section('content')
@php
// ── Formatters ───────────────────────────────────────────────────────────────
$fmt = function($v) {
if ($v >= 1_000_000) return '$' . number_format($v / 1_000_000, 1) . 'M';
if ($v >= 1_000) return '$' . number_format($v / 1_000, 1) . 'K';
return '$' . number_format($v, 0);
};
$fmtFull = function($v) {
return '$' . number_format((float)$v, 0);
};
$delta = function($cur, $prev) {
if ($prev == 0) return ['val' => '—', 'dir' => ''];
$pct = round(($cur - $prev) / abs($prev) * 100, 1);
return ['val' => ($pct >= 0 ? '↑ ' : '↓ ') . abs($pct) . '%', 'dir' => $pct >= 0 ? 'up' : 'down'];
};
$deltaAbs = function($cur, $prev) {
$diff = $cur - $prev;
return ['val' => ($diff >= 0 ? '↑ ' : '↓ ') . abs($diff) . ' items', 'dir' => $diff >= 0 ? 'up' : 'down'];
};
$deltaPp = function($cur, $prev) {
$diff = round($cur - $prev, 2);
return ['val' => ($diff >= 0 ? '↑ ' : '↓ ') . abs($diff) . 'pp', 'dir' => $diff >= 0 ? 'up' : 'down'];
};
// ── Sparkline SVG ────────────────────────────────────────────────────────────
$sfn = function($pts, $w, $h) {
$pts = array_values($pts);
$max = count($pts) ? max($pts) : 0;
if (!$max) {
return '';
}
$n = count($pts);
$step = $n > 1 ? $w / ($n - 1) : $w;
$pad = 4;
$coords = [];
foreach ($pts as $i => $v) {
$x = round($i * $step, 1);
$y = round($h - $pad - ($v / $max) * ($h - $pad * 2), 1);
$coords[] = "$x $y";
}
$line = 'M' . implode(' L', $coords);
$fill = $line . ' L' . $w . ' ' . $h . ' L0 ' . $h . ' Z';
$id = 'pay-cf-' . substr(md5(implode(',', array_map('intval', $pts))), 0, 6);
return ''
. ''
. ''
. ''
. ''
. '';
};
// ── Transaction type config ───────────────────────────────────────────────────
$typeConf = [
'escrow_funded' => ['color' => 'var(--info)', 'label' => __('Escrow funded')],
'milestone_release' => ['color' => 'var(--success)', 'label' => __('Milestone release')],
'payout' => ['color' => 'var(--success)', 'label' => __('Payout')],
'refund' => ['color' => 'var(--warn)', 'label' => __('Refund')],
'subscription' => ['color' => 'var(--text-dim)', 'label' => __('Subscription')],
'chargeback' => ['color' => 'var(--danger)', 'label' => __('Chargeback')],
];
// ── State tag + state key ─────────────────────────────────────────────────────
$resolveState = function($tx) {
if (in_array((int)$tx->order_status, [6, 7]) || $tx->tx_type === 'chargeback') return 'flagged';
if ($tx->payment_status === 'complete') return 'cleared';
if ($tx->payment_status === 'cancel') return 'cancelled';
return 'processing';
};
$stateTag = function($state) {
$map = [
'cleared' => '' . __('Cleared') . '',
'processing' => '' . __('Processing') . '',
'flagged' => '' . __('Flagged') . '',
'cancelled' => '' . __('Cancelled') . '',
];
return $map[$state] ?? $map['processing'];
};
// ── Gateway display name ──────────────────────────────────────────────────────
$gwLabel = function($raw) {
$map = [
'stripe' => 'Stripe',
'paypal' => 'PayPal',
'bank_transfer' => 'Wire',
'ach' => 'ACH',
'wise' => 'Wise',
'sepa' => 'SEPA',
'manual' => 'Manual',
];
return $map[strtolower($raw ?? '')] ?? ucfirst($raw ?? '—');
};
// ── Deltas ───────────────────────────────────────────────────────────────────
$dProcessed = $delta($processedToday, $processedYest);
$dPayouts = $deltaAbs($pendingPayoutsCount, $pendingPayoutsCountPrev);
$dEscrow = $delta($escrowNew, $escrowPrev);
$dFailure = $deltaPp($failureRate, $failureRatePrev);
$dCashFlow = $delta($cashFlowTotal, $cashFlowPrevTotal);
// ── Payout bar colours ────────────────────────────────────────────────────────
$barColors = [
'var(--accent)',
'color-mix(in oklch, var(--accent) 70%, white)',
'color-mix(in oklch, var(--accent) 50%, white)',
'color-mix(in oklch, var(--accent) 30%, white)',
'var(--text-dim)',
];
@endphp
{{ __('Payments') }}
{{ __('All escrow, payouts, refunds, and subscription transactions') }}
{{-- KPIs --}}
{{ __('Processed today') }}
{{ $fmt($processedToday) }}
{{ $dProcessed['val'] }}
{{ __('vs yesterday') }}
{{ __('Pending payouts') }}
{{ $fmt($pendingPayoutsAmt) }}
{{ $dPayouts['val'] }}
{{ __('vs yesterday') }}
{{ __('Held in escrow') }}
{{ $fmt($heldEscrow) }}
{{ $dEscrow['val'] }}
{{ __('new this week') }}
{{ __('Failure rate (7d)') }}
{{ $failureRate }}%
{{ $dFailure['val'] }}
{{ __('vs prev 7d') }}
{{-- Recent transactions --}}
{{ __('Recent transactions') }}
{{-- Type filter --}}
{{-- State filter --}}
{{-- Sort --}}
| {{ __('ID') }} |
{{ __('Time') }} |
{{ __('Type') }} |
{{ __('Counterparty') }} |
{{ __('Method') }} |
{{ __('Amount') }} |
{{ __('Fee') }} |
{{ __('Net') }} |
{{ __('State') }} |
@forelse($transactions as $tx)
@php
$conf = $typeConf[$tx->tx_type] ?? ['color' => 'var(--text-dim)', 'label' => $tx->tx_type];
$prefix = $tx->direction ? $tx->direction . ' ' : '';
$fee = (float)$tx->fee;
$net = (float)$tx->net;
$txState = $resolveState($tx);
@endphp
| {{ $tx->tx_id }} |
{{ date('H:i', strtotime($tx->tx_time)) }} |
{{ $conf['label'] }}
|
{{ $prefix }}{{ $tx->counterparty }} |
{{ $gwLabel($tx->method) }} |
{{ $fmtFull($tx->amount) }} |
{{ $fee > 0 ? $fmtFull($fee) : '—' }} |
{{ $fmtFull($net) }} |
{!! $stateTag($txState) !!} |
@empty
| {{ __('No transactions yet') }} |
@endforelse
{{-- No-results row (shown by JS when filters exclude everything) --}}
{{ __('No transactions match the selected filters') }}
{{-- Right column --}}
{{ __('Cash flow (7d)') }}
{{ $fmt($cashFlowTotal) }}
{{ $dCashFlow['val'] }}
{{ __('Payout methods') }}
@forelse($payoutMethods as $i => $gw)
@php $pct = $payoutTotal > 0 ? round($gw->total / $payoutTotal * 100) : 0; @endphp
{{ $gw->gateway_name }}
{{ $pct }}%
@empty
{{ __('No completed payouts yet') }}
@endforelse
{{ __('Velocity spikes') }}
{{ $velocitySpikes }}
{{ __('Chargebacks (7d)') }}
{{ $chargebacks7d }}
{{ __('High-value new users (7d)') }}
{{ $amlHighRisk }}
@endsection
@section('script')
@endsection