@extends('layouts.finance') @section('title', 'Transactions') @section('subtitle', 'All deposits, withdrawals, transfers and payments') @section('content') @php /* * Tile definitions — "examism" and "invoices" are intentionally excluded here. * * - "examism to bank" transfer entries are filtered out at the query layer * (FinanceTransactionController::EXCLUDED_SOURCES). They do not belong on * this listing because they represent internal bookkeeping movements. * * - "invoice" entries are similarly excluded at the query layer and live * exclusively on the dedicated Invoices page (/invoices). * * The Figma reference (renderTxTiles, order array) shows only: pakBanks, wallets, usBanks. */ $bankIcon = ''; $walletIcon = ''; $creditCardIcon = ''; $tileStyles = [ 'pak-banks' => ['pill-amber', 'ico-bg-amber'], 'wallets' => ['pill-cyan', 'ico-bg-cyan'], 'us-banks' => ['pill-blue', 'ico-bg-purple'], 'aus-banks' => ['pill-teal', 'ico-bg-teal'], 'credit-cards' => ['pill-red', 'ico-bg-red'], ]; $tiles = collect($categoryLabels)->map(function($label, $key) use ($tileStyles, $bankIcon, $walletIcon, $creditCardIcon) { [$pill, $iconBg] = $tileStyles[$key] ?? ['pill-blue', 'ico-bg-purple']; $icon = match($key) { 'wallets' => $walletIcon, 'credit-cards' => $creditCardIcon, default => $bankIcon, }; return [ 'title' => strtoupper($label), 'subtitle' => $label.' transactions', 'pill' => $pill, 'iconBg' => $iconBg, 'icon' => $icon, ]; })->all(); $activeTile = $tiles[$bucket] ?? null; $bucketCurrency = match($bucket) { 'pak-banks' => 'PKR', 'us-banks' => 'USD', 'aus-banks' => 'AUD', default => null, }; $displayCurrency = $bucketCurrency ?? $selectedBankAccount?->currency ?? 'USD'; $transactionCurrency = fn($transaction) => $bucketCurrency ?? $transaction->bankAccount?->currency ?? $transaction->metadata['currency'] ?? 'USD'; $isAccountBucket = $activeTile !== null; $bucketAccent = match($bucket) { 'pak-banks' => ['linear-gradient(135deg,#fffbeb,#ffffff)', '#fde68a', 'pill-amber', 'Pakistan Bank Accounts', 'Click any account to add credit or debit'], 'aus-banks' => ['linear-gradient(135deg,#ecfeff,#ffffff)', '#a5f3fc', 'pill-teal', 'Australia Bank Accounts', 'Click any account to view or record transactions'], 'wallets' => ['linear-gradient(135deg,#fdf2f8,#ffffff)', '#fecdd3', 'pill-cyan', 'Wallets', 'Wallet and payment gateway accounts - click one to view transactions'], 'us-banks' => ['linear-gradient(135deg,#eef2ff,#ffffff)', '#c7d2fe', 'pill-blue', 'US Banks', 'United States Bank Accounts - click a bank to view or record transactions'], default => ['linear-gradient(135deg,#eef2ff,#ffffff)', '#c7d2fe', 'pill-blue', $categoryLabels[$bucket] ?? 'Accounts', 'Click any account to view or record transactions'], }; $storeSource = match($bucket) { 'pak-banks' => 'pakBanks', 'us-banks' => 'usBanks', 'aus-banks' => 'ausBanks', 'wallets' => 'wallet', default => $bucket, }; $accountInitials = fn($account) => collect(preg_split('/\s+/', trim($account->bank_name ?: $account->name))) ->filter() ->take(2) ->map(fn($part) => strtoupper(substr($part, 0, 1))) ->implode('') ?: 'BA'; $maskedAccount = fn($account) => $account->account_number ? '****'.substr(preg_replace('/\D+/', '', $account->account_number) ?: $account->account_number, -4) : 'No acct'; $debitSupplierOptions = $selectedBankAccount ? $selectedBankAccount->debitDestinations ->toBase() ->map(fn($account) => trim($account->name.' - '.($account->bank_name ?: 'Linked Account'))) ->merge(($supplierOptions ?? collect())->toBase()) ->filter() ->unique() ->values() : collect(); /* * Build the structured payload behind the "amount details" popup. * Returns a JSON string (or null when there is nothing to show) that the * shared modal renders as a definition list, a per-date "Received on" * breakdown table, and an optional partial-amounts section. */ $amountDetailJson = function ($transaction, $currency, $approvalOriginal, $approvalApproved, $approvalRemaining, $partialAmounts = null, $partialCurrency = null) use ($metrics) { $hasApproval = $approvalOriginal !== null && $approvalApproved !== null && $approvalRemaining !== null; $breakdown = collect($transaction->metadata['approval_breakdown'] ?? []) ->filter(fn($entry) => is_array($entry) && isset($entry['amount']) && is_numeric($entry['amount'])) ->map(fn($entry) => [ 'date' => ! empty($entry['date']) ? \Illuminate\Support\Carbon::parse($entry['date'])->format('d M Y') : null, 'amount' => $metrics->smartAmount($entry['amount']), ]) ->values(); $partials = ($partialAmounts !== null && $partialAmounts->isNotEmpty()) ? [ 'currency' => $partialCurrency, 'items' => $partialAmounts->map(fn($amount) => $metrics->smartAmount($amount))->values()->all(), 'total' => $metrics->smartAmount($partialAmounts->sum()), ] : null; // Build whichever approval rows are available so the approved (partial) // amount always appears, even when only some approval fields are stored. $rows = []; if ($approvalOriginal !== null) { $rows[] = ['label' => 'Original amount', 'value' => $metrics->smartAmount($approvalOriginal)]; } if ($approvalApproved !== null) { $rows[] = ['label' => 'Received / approved amount', 'value' => $metrics->smartAmount($approvalApproved)]; } if ($approvalRemaining !== null) { $rows[] = ['label' => 'Remaining amount', 'value' => $metrics->smartAmount($approvalRemaining)]; } if (! empty($rows)) { $rows[] = ['label' => 'This row amount', 'value' => $metrics->smartAmount($transaction->amount)]; } if (empty($rows) && $breakdown->isEmpty() && $partials === null) { return null; } return json_encode([ 'currency' => $currency, 'rows' => $rows, 'breakdown' => $breakdown->all(), 'partials' => $partials, ], JSON_UNESCAPED_UNICODE); }; @endphp @if(! $activeTile) {{-- Top-level tile picker --}}
@foreach($tiles as $key => $tile)
{!! $tile['icon'] !!}
{{ $tile['title'] }}
@endforeach
Click any card to view, edit, or add transactions
@else @php $txTab = $txTab ?? 'account'; $rows = $transactions->getCollection(); $totalCurrency = $displayCurrency; $postedDisplayAmount = function ($transaction) { $metadata = $transaction->metadata ?? []; $status = $metadata['status'] ?? 'Cleared'; $approved = $metadata['approval_approved_amount'] ?? null; $extra = is_numeric($metadata['approval_extra_amount'] ?? null) ? (float) $metadata['approval_extra_amount'] : 0.0; if ($status === 'Pending' && is_numeric($approved) && (float) $approved > 0) { return (float) $approved; } return (float) $transaction->amount + $extra; }; $totalAmount = fn($transaction) => ($bucketCurrency || $selectedBankAccount) ? $postedDisplayAmount($transaction) : $metrics->usd($postedDisplayAmount($transaction), $transactionCurrency($transaction)); // IN / OUT classification is driven by the authoritative `type` column // (income / expense), not the display-only tx_kind. A transfer's source // leg is an expense and its destination leg is an income — using // tx_kind here would misclassify the credit leg as outgoing. $totalIn = $rows->filter(fn($t) => $t->type === 'income')->sum($totalAmount); $totalOut = $rows->filter(fn($t) => $t->type === 'expense')->sum($totalAmount); $net = $totalIn - $totalOut; @endphp {{-- Breadcrumb & back button --}}
Back
Transactions / {{ $activeTile['title'] }}
@if($bucket === 'credit-cards') {{-- ------------------------------------------------------------------ --}} {{-- Credit Cards — grid overview OR selected-card ledger. --}} {{-- ------------------------------------------------------------------ --}} @php $ccCount = $creditCards->count(); @endphp @if($selectedCreditCard) {{-- ── Selected card: header + action buttons ─────────────────── --}} @php $cardPayableBalance = (float) $selectedCreditCard->payable_balance; $signedCardBalance = -1 * $cardPayableBalance; $cardAvailableBalance = (float) $selectedCreditCard->credit_limit - $cardPayableBalance; $scUtil = (float) $selectedCreditCard->credit_limit > 0 ? ($cardPayableBalance / (float) $selectedCreditCard->credit_limit) * 100 : 0; $scBarColor = $scUtil > 80 ? '#ef4444' : ($scUtil > 50 ? '#f59e0b' : '#10b981'); @endphp
{{ $selectedCreditCard->issuer }}
{{ $selectedCreditCard->card_name }}
{{ $selectedCreditCard->holder }}
Payable Balance
{{ $metrics->money($signedCardBalance, $selectedCreditCard->currency) }}
Available {{ $metrics->money($cardAvailableBalance, $selectedCreditCard->currency) }} · Limit {{ $metrics->money($selectedCreditCard->credit_limit, $selectedCreditCard->currency) }} · {{ number_format($scUtil, 0) }}% used
{{-- Utilization bar --}}
All Cards
{{-- ── Card transaction modal ───────────────────────────────── --}} {{-- ── Card ledger table ────────────────────────────────────── --}}
{!! $creditCardIcon !!}
Card Transactions
All charges and payments for this card
@foreach(request()->except(['transaction_id_search', 'page']) as $queryKey => $queryValue) @if(is_array($queryValue)) @foreach($queryValue as $item) @endforeach @else @endif @endforeach
@foreach(request()->except(['per_page', 'page']) as $queryKey => $queryValue) @if(is_array($queryValue)) @foreach($queryValue as $item) @endforeach @else @endif @endforeach
{{ $transactions->total() }} tx
{{-- KPI strip: Charges / Payments / Net Payable --}} @php $cardRows = $transactions->getCollection(); $totalCharges = $cardRows->filter(fn($t) => $t->type === 'expense')->sum(fn($t) => (float) $t->amount); $totalPayments = $cardRows->filter(fn($t) => $t->type === 'income')->sum(fn($t) => (float) $t->amount); $cardNet = $totalCharges - $totalPayments; @endphp
Charges
{{ $metrics->money($totalCharges, $selectedCreditCard->currency) }}
Payments
{{ $metrics->money($totalPayments, $selectedCreditCard->currency) }}
Page Net
{{ $metrics->money($cardNet, $selectedCreditCard->currency) }}
{{-- Transaction table --}}
@forelse($transactions as $tx) @php // On a card: expense = charge (payable up), income = payment (payable down). $isCharge = $tx->type === 'expense'; $pillClass = $isCharge ? 'pill-red' : 'pill-green'; $pillLabel = $isCharge ? 'Charge' : 'Payment'; $txStatus = $tx->metadata['status'] ?? 'Cleared'; $amtColor = $isCharge ? '#ef4444' : '#10b981'; $amtPrefix = $isCharge ? '-' : '+'; $txInvNumber = $tx->display_invoice_number ?? ($tx->metadata['invoice_number'] ?? null); $txInvProduct = $tx->display_invoice_product_name ?? ($tx->metadata['invoice_product_name'] ?? null); $approvalOriginalAmount = is_numeric($tx->metadata['approval_original_amount'] ?? null) ? (float) $tx->metadata['approval_original_amount'] : null; $approvalApprovedAmount = is_numeric($tx->metadata['approval_approved_amount'] ?? null) ? (float) $tx->metadata['approval_approved_amount'] : null; $approvalRemainingAmount = is_numeric($tx->metadata['approval_remaining_amount'] ?? null) ? (float) $tx->metadata['approval_remaining_amount'] : null; $approvalExtraAmount = is_numeric($tx->metadata['approval_extra_amount'] ?? null) ? (float) $tx->metadata['approval_extra_amount'] : 0.0; $hasApprovalDetail = $approvalOriginalAmount !== null && $approvalApprovedAmount !== null && $approvalRemainingAmount !== null; $showApprovalRemaining = $txStatus === 'Pending' && $hasApprovalDetail; $approvedPartialAmounts = collect($tx->metadata['approval_breakdown'] ?? []) ->filter(fn($entry) => is_array($entry) && isset($entry['amount']) && is_numeric($entry['amount']) && (float) $entry['amount'] > 0) ->map(fn($entry) => (float) $entry['amount']) ->values(); if ($approvedPartialAmounts->isEmpty() && $showApprovalRemaining && (float) ($approvalApprovedAmount ?? 0) > 0) { $approvedPartialAmounts = collect([(float) $approvalApprovedAmount]); } // Approved/posted amount (matches the summary + balance); // original total stays in the amount-details popup. $displayAmount = $postedDisplayAmount($tx); $amountDetailMessage = $amountDetailJson($tx, $selectedCreditCard->currency, $approvalOriginalAmount, $approvalApprovedAmount, $approvalRemainingAmount); $balanceTransactionId = (int) $tx->id; $canReorder = true; $txDate = $tx->transaction_date?->toDateString(); @endphp @empty @endforelse @if($openingCardBalance !== null) @php $cardOpeningBalance = (float) ($openingCardBalance ?? 0); $cardOpeningColor = $cardOpeningBalance < 0 ? '#ef4444' : '#10b981'; @endphp @endif
Order Date Type Transaction ID Category / Ref Description Amount Balance Actions
@if($canReorder && $txDate)
@else - @endif
{{ $tx->transaction_date?->format('d M Y') }} {{ $pillLabel }} @if($txStatus === 'Pending')
Pending
@endif
{{ $tx->transaction_id ?: '-' }} {{ $tx->referenceLabel() }} @if($txInvNumber)
Invoice {{ $txInvNumber }}
@endif
{{ $tx->description ?: '-' }} @if($txInvProduct)
{{ $txInvProduct }}
@endif @if($tx->counterparty)
{{ $isCharge ? 'To' : 'From' }}: {{ $tx->counterparty }}
@endif
@if($amountDetailMessage) @else {{ $amtPrefix }}{{ $metrics->smartAmount($displayAmount) }} @endif @if($showApprovalRemaining) @foreach($approvedPartialAmounts as $approvedPartialAmount)
Approved {{ $metrics->smartAmount($approvedPartialAmount) }}
@endforeach
Remaining to approve: {{ $metrics->smartAmount($approvalRemainingAmount) }}
@endif @if($approvalExtraAmount > 0)
Extra: {{ $metrics->smartAmount($approvalExtraAmount) }}
@endif
@if(isset($runningCardPayable[$balanceTransactionId])) {{ $metrics->money($runningCardPayable[$balanceTransactionId], $selectedCreditCard->currency) }} @else - @endif
@if($txStatus === 'Pending')
@csrf @if($tx->source === 'linked_bank_transfer' || $tx->source === 'credit_card_payment') @endif
@endif
@csrf @method('DELETE')
No transactions yet · click + Credit Transaction or - Debit Transaction to create one
- {{ $selectedCreditCard->created_at?->format('d M Y') }} - - Opening Balance Starting card balance before listed transactions - {{ $metrics->money($cardOpeningBalance, $selectedCreditCard->currency) }} -
{{ $transactions->links() }}
@else {{-- ── No card selected: show the card grid ─────────────────── --}} @push('styles') @endpush
Active credit cards overview
Credit Cards
{{ $ccCount }} card{{ $ccCount === 1 ? '' : 's' }}
@if($creditCards->isNotEmpty())
@foreach($creditCards as $card) @php $cardUtil = (float) $card->credit_limit > 0 ? min(100, ((float) $card->payable_balance / (float) $card->credit_limit) * 100) : 0; $days = $card->due_date ? now()->startOfDay()->diffInDays($card->due_date->startOfDay(), false) : null; $dueText = $card->due_date?->format('M d') ?: 'Not set'; $dueStatus = $days === null ? null : ($days < 0 ? 'Overdue '.abs((int) $days).'d' : ((int) $days).'d left'); @endphp {{-- Each card is a clickable link to the card's ledger. --}}
{{ \Illuminate\Support\Str::upper($card->issuer ?: ($card->short_name ?: 'CARD')) }}
Card #{{ $card->id }}{{ $card->short_name ? ' · '.$card->short_name : '' }}
Payable
{{ $metrics->money($card->payable_balance, $card->currency) }}
Limit {{ $metrics->money($card->credit_limit, $card->currency) }}
{{ $card->card_name ?: $card->holder ?: $card->issuer }} {{ number_format($cardUtil, 0) }}%
Due {{ $dueText }} @if($dueStatus) {{ $dueStatus }} @endif
{{ $card->invoices_count }} invoice{{ (int) $card->invoices_count === 1 ? '' : 's' }} →
@endforeach
@else
No credit cards yet.
@endif @endif @elseif($isAccountBucket && ! $selectedBankAccount)
{{ $bucketAccent[4] }}
{{ $bucketAccent[3] }}
{{ $bankAccounts->count() }} account{{ $bankAccounts->count() === 1 ? '' : 's' }}
@if($bucket === 'pak-banks') @php $linkedAccounts = $bankAccounts->filter(fn($account) => $account->creditSources->isNotEmpty() || $account->debitDestinations->isNotEmpty()); $standaloneAccounts = $bankAccounts->diff($linkedAccounts); $accountGroups = [ ['Linked to Payment Gateways', $linkedAccounts, 'KuickPay / PayFast linked flow', 'pill-cyan'], ['Not Connected to Payment Gateways', $standaloneAccounts, 'Direct deposits only', 'pill'], ]; @endphp @foreach($accountGroups as [$groupTitle, $accounts, $groupSubtitle, $groupPill])
{{ $groupTitle }}
{{ $accounts->count() }} account{{ $accounts->count() === 1 ? '' : 's' }} {{ $groupSubtitle }}
@if($accounts->isNotEmpty())
@foreach($accounts as $account) @include('transactions._bank-card', ['account' => $account, 'bucket' => $bucket, 'bucketAccent' => $bucketAccent, 'accountInitials' => $accountInitials, 'maskedAccount' => $maskedAccount, 'metrics' => $metrics]) @endforeach
@else
No accounts in this group yet.
@endif
@endforeach @else @if($bankAccounts->isNotEmpty())
@foreach($bankAccounts as $account) @include('transactions._bank-card', ['account' => $account, 'bucket' => $bucket, 'bucketAccent' => $bucketAccent, 'accountInitials' => $accountInitials, 'maskedAccount' => $maskedAccount, 'metrics' => $metrics]) @endforeach
@else
No {{ $bucketAccent[3] }} yet. Add one from Bank Accounts.
@endif @endif @else @if($selectedBankAccount) @php $siblingBankAccounts = $bankAccounts ->reject(fn($account) => (int) $account->id === (int) $selectedBankAccount->id) ->values(); @endphp
{{ $selectedBankAccount->bank_name }}
{{ $selectedBankAccount->name }}
{{ $maskedAccount($selectedBankAccount) }}
Current Balance
{{ $metrics->money($selectedBankAccount->current_balance, $selectedBankAccount->currency) }}
@if($siblingBankAccounts->isNotEmpty())
Other {{ $activeTile['title'] }}
@foreach($siblingBankAccounts as $siblingAccount) {{ $siblingAccount->name }} {{ $metrics->money($siblingAccount->current_balance, $siblingAccount->currency) }} @endforeach
@endif
@endif
{{-- Bucket header --}}
{!! $activeTile['icon'] !!}
{{ $selectedBankAccount ? 'Account Transactions' : $activeTile['title'] }}
{{ $selectedBankAccount ? 'All credits and debits for this account' : $activeTile['subtitle'] }}
@foreach(request()->except(['transaction_id_search', 'page']) as $queryKey => $queryValue) @if(is_array($queryValue)) @foreach($queryValue as $item) @endforeach @else @endif @endforeach
@foreach(request()->except(['per_page', 'page']) as $queryKey => $queryValue) @if(is_array($queryValue)) @foreach($queryValue as $item) @endforeach @else @endif @endforeach
{{ $transactions->total() }} tx
{{-- View tabs: "Account" shows consolidated rows; "Bulk" expands each partial leg / split-approval child into its own single-entry row. --}} @if($selectedBankAccount)
Bulk Transactions Account Transactions
@endif {{-- KPI strip: In / Out / Net --}}
In
{{ $metrics->money($totalIn, $totalCurrency) }}
Out
{{ $metrics->money($totalOut, $totalCurrency) }}
Net
{{ $metrics->money($net, $totalCurrency) }}
@if($selectedBankAccount) @endif {{-- Transaction table --}}
@if($selectedBankAccount) @endif @forelse($transactions as $transaction) @php $txCurrency = $transactionCurrency($transaction); // Direction is driven by the authoritative `type` column so a // transfer's destination CREDIT leg renders green on the // receiving account and red on the sending account. $isIn = $transaction->type === 'income'; $txStatus = $transaction->metadata['status'] ?? 'Cleared'; $amtColor = $isIn ? '#10b981' : '#ef4444'; $invoiceNumber = $transaction->display_invoice_number ?? ($transaction->metadata['invoice_number'] ?? null); $invoiceProductName = $transaction->display_invoice_product_name ?? ($transaction->metadata['invoice_product_name'] ?? null); $transferPartialAmounts = collect($transaction->metadata['transfer_partial_amounts'] ?? []) ->filter(fn($amount) => is_numeric($amount) && (float) $amount > 0) ->values(); $transferPartialCurrency = $transaction->metadata['transfer_partial_currency'] ?? $txCurrency; $approvalOriginalAmount = is_numeric($transaction->metadata['approval_original_amount'] ?? null) ? (float) $transaction->metadata['approval_original_amount'] : null; $approvalApprovedAmount = is_numeric($transaction->metadata['approval_approved_amount'] ?? null) ? (float) $transaction->metadata['approval_approved_amount'] : null; $approvalRemainingAmount = is_numeric($transaction->metadata['approval_remaining_amount'] ?? null) ? (float) $transaction->metadata['approval_remaining_amount'] : null; $approvalExtraAmount = is_numeric($transaction->metadata['approval_extra_amount'] ?? null) ? (float) $transaction->metadata['approval_extra_amount'] : 0.0; $hasApprovalDetail = $approvalOriginalAmount !== null && $approvalApprovedAmount !== null && $approvalRemainingAmount !== null; $showApprovalRemaining = $txStatus === 'Pending' && $hasApprovalDetail; $approvedPartialAmounts = collect($transaction->metadata['approval_breakdown'] ?? []) ->filter(fn($entry) => is_array($entry) && isset($entry['amount']) && is_numeric($entry['amount']) && (float) $entry['amount'] > 0) ->map(fn($entry) => (float) $entry['amount']) ->values(); if ($approvedPartialAmounts->isEmpty() && $showApprovalRemaining && (float) ($approvalApprovedAmount ?? 0) > 0) { $approvedPartialAmounts = collect([(float) $approvalApprovedAmount]); } // Per-leg amounts of a collapsed split transfer, already in the // account currency (USD), so each received installment shows its // real dollar figure. Falls back to the approval breakdown for // partial-approval rows that aren't split transfers. $transferPartialDisplayAmounts = collect($transaction->metadata['transfer_partial_display_amounts'] ?? []) ->filter(fn($amount) => is_numeric($amount) && (float) $amount > 0) ->map(fn($amount) => (float) $amount) ->values(); $partialBreakdownAmounts = $transferPartialDisplayAmounts->isNotEmpty() ? $transferPartialDisplayAmounts : $approvedPartialAmounts; // Show what actually posted/was approved (the same figure the // IN/OUT/NET summary uses): for a partially-approved pending // transfer this is the approved-so-far amount, not the original // total. The original + per-date breakdown remain in the popup. $displayAmount = $postedDisplayAmount($transaction); $amountDetailMessage = $amountDetailJson($transaction, $txCurrency, $approvalOriginalAmount, $approvalApprovedAmount, $approvalRemainingAmount, $transferPartialAmounts, $transferPartialCurrency); $balanceTransactionId = (int) $transaction->id; $canReorder = (bool) $selectedBankAccount; $txDate = $transaction->transaction_date?->toDateString(); @endphp @if($selectedBankAccount) @endif @empty @endforelse @if($selectedBankAccount && $transactions->currentPage() === $transactions->lastPage()) @endif
OrderDate Type Transaction ID Transaction Type Description Amount Cur Balance Actions
@if($canReorder && $txDate)
@else - @endif
{{ $transaction->transaction_date?->format('d M Y') }} {{-- Credit/Debit direction, driven by the authoritative `type` column. --}} {{ $isIn ? 'Credit' : 'Debit' }} @if($txStatus === 'Pending')
Pending
@endif
{{ $transaction->transaction_id ?: '-' }} {{-- Originating reference (Manual, KuickPay, Invoice, Transfer…), with the invoice number underneath when the row is tied to one. --}} {{ $transaction->referenceLabel() }} @if($invoiceNumber)
Invoice {{ $invoiceNumber }}
@endif
{{ $transaction->description ?: '-' }} @if($invoiceProductName)
Product: {{ $invoiceProductName }}
@endif @if($transaction->counterparty) {{-- Who the money came from (credit) or went to (debit). --}}
{{ $isIn ? 'From' : 'To' }}: {{ $transaction->counterparty }}
@endif @if($txTab !== 'bulk' && $transferPartialAmounts->isNotEmpty())
Partials ({{ $transferPartialCurrency }}):
@foreach($transferPartialAmounts as $partialAmount)
{{ $metrics->smartAmount($partialAmount) }}
@endforeach
@endif @php // A multi-day KuickPay deposit is one credit that settles // several days; show each day's share inline so the single // entry carries its full breakdown. $kuickpayAllocations = collect($transaction->metadata['kuickpay_allocations'] ?? []) ->filter(fn($a) => is_array($a) && isset($a['amount']) && is_numeric($a['amount'])) ->values(); @endphp @if($txTab !== 'bulk' && $kuickpayAllocations->isNotEmpty())
Days settled (PKR):
@foreach($kuickpayAllocations as $alloc)
{{ \Illuminate\Support\Carbon::parse($alloc['collection_date'])->format('d M Y') }} · {{ $alloc['provider_label'] ?? 'KuickPay' }}: {{ $metrics->smartAmount($alloc['amount']) }}
@endforeach
Total: {{ $metrics->smartAmount($kuickpayAllocations->sum(fn($a) => (float) $a['amount'])) }}
@endif
@if($amountDetailMessage) @else {{ $isIn ? '+' : '-' }}{{ $metrics->smartAmount($displayAmount) }} @endif @if($showApprovalRemaining) @foreach($approvedPartialAmounts as $approvedPartialAmount)
{{ $metrics->smartAmount($approvedPartialAmount) }}
@endforeach
Remaining to approve: {{ $metrics->smartAmount($approvalRemainingAmount) }}
@endif @if($approvalExtraAmount > 0)
Extra: {{ $metrics->smartAmount($approvalExtraAmount) }}
@endif {{-- Per-installment breakdown of the received amount, shown in the account currency (USD). These are the real per-leg/approved figures (e.g. 5,000.00 then 28.27), NOT an even split of the PKR composition. Shown for already-posted rows; the Pending block above handles in-flight approvals. --}} @if($txTab !== 'bulk' && ! $showApprovalRemaining && $partialBreakdownAmounts->count() > 1) @foreach($partialBreakdownAmounts as $partialBreakdownAmount)
{{ $isIn ? '+' : '-' }}{{ $metrics->smartAmount($partialBreakdownAmount) }}
@endforeach @endif @php $feeMeta = $transaction->metadata ?? []; $feeEligible = $transaction->type === 'income' && (float) ($transaction->conversion_rate ?? 0) > 0 && ! empty($transaction->bank_account_id) && empty($transaction->credit_card_id) && $transaction->source !== 'credit_card_payment' && empty($transaction->kuickpay_settlement_id) && empty($feeMeta['kuickpay_settlement_ids']) && $txStatus !== 'Pending'; // cleared rows only: amount is the true received figure $feeGross = isset($feeMeta['gross_amount']) && is_numeric($feeMeta['gross_amount']) ? (float) $feeMeta['gross_amount'] : (float) $transaction->amount; $feeBaseRate = isset($feeMeta['base_conversion_rate']) && is_numeric($feeMeta['base_conversion_rate']) ? (float) $feeMeta['base_conversion_rate'] : (float) ($transaction->conversion_rate ?? 0); $feeCurrent = isset($feeMeta['fee_amount']) && is_numeric($feeMeta['fee_amount']) ? (float) $feeMeta['fee_amount'] : 0.0; @endphp @if($feeEligible)
@endif
{{ $txCurrency }} @if(isset($runningBalances[$balanceTransactionId])) {{ $metrics->money($runningBalances[$balanceTransactionId], $selectedBankAccount?->currency ?? $displayCurrency) }} @else - @endif
{{-- View detail (eye) --}} {{-- Edit (pencil) --}} @if($txStatus === 'Pending')
@csrf @if($transaction->source === 'linked_bank_transfer' || $transaction->source === 'credit_card_payment') @endif
@endif {{-- Delete (trash) --}}
@csrf @method('DELETE')
No transactions yet.
- {{ $selectedBankAccount->created_at?->format('d M Y') }} - - Opening Balance - - {{ $selectedBankAccount->currency }} {{ $metrics->money($selectedBankAccount->opening_balance, $selectedBankAccount->currency) }} -
{{-- Pagination --}}
{{ $transactions->links() }}
@endif @endif {{-- Add Fee modal (shared; opened from any row's "+ Fee" button) --}} @endsection @if($selectedBankAccount || $selectedCreditCard) @push('styles') @endpush @push('scripts') @endpush @endif @if($selectedBankAccount) @push('styles') @endpush @push('scripts') @endpush @endif {{-- ─── Card transaction modal CSS + JS (rendered only when a card is selected) ─── --}} @if($selectedCreditCard ?? null) @push('styles') @endpush @push('scripts') @endpush @endif @push('styles') @endpush @push('scripts') @endpush