@php use App\Models\Payment; $money = fn ($value) => 'R '.number_format((float) $value, 2); $totalPaid = $invoice->totalPaid(); $remainingBalance = $invoice->remainingBalance(); $adjustedTotal = $invoice->adjustedTotal(); $paymentProgress = $adjustedTotal > 0 ? min(100, round(($totalPaid / $adjustedTotal) * 100)) : 100; @endphp Back to invoices Download PDF @can('manage-credit-notes') @if ($invoice->isActive()) Create Credit Note @endif @endcan @can('send-invoice-emails') @if ($invoice->isActive())
@csrf
@endif @endcan

Invoice

{{ $invoice->invoice_number }}

{{ $invoice->statusLabel() }}

{{ $invoice->client->name }} - {{ $invoice->client->email ?: 'No email on file' }}

Balance due

{{ $money($remainingBalance) }}

{{ $paymentProgress }}% paid

Issue date {{ $invoice->issue_date->format('d M Y') }}
Due date {{ $invoice->due_date->format('d M Y') }}
Email status {{ $invoice->sent_at?->format('d M Y H:i') ?? 'Not sent' }}
Payment status {{ $invoice->paid_at?->format('d M Y H:i') ?? 'Awaiting payment' }}

Invoice journey

Lifecycle timeline

Created, sent, viewed, paid, credited, settled.

{{ $invoice->isCollectible() ? 'Collectible' : ($remainingBalance <= 0.01 && ! $invoice->isTerminal() && $invoice->status !== \App\Models\Invoice::STATUS_DRAFT ? 'Settled' : $invoice->statusLabel()) }}
@foreach ($timelineSteps as $step) @php $stateClass = match ($step['state']) { 'complete' => 'border-green-200 bg-green-50 text-green-800', 'current' => 'border-blue-200 bg-blue-50 text-blue-800', 'stopped' => 'border-rose-200 bg-rose-50 text-rose-800', 'unavailable' => 'border-slate-200 bg-slate-50 text-slate-500', default => 'border-slate-200 bg-white text-slate-600', }; $iconClass = match ($step['state']) { 'current' => 'invoice-timeline-icon-current', 'stopped' => 'invoice-timeline-icon-stopped', 'unavailable' => 'invoice-timeline-icon-muted', default => '', }; @endphp

{{ $step['label'] }}

{{ $step['timestamp'] ? $step['timestamp']->format('d M Y H:i') : ucfirst($step['state']) }}

{{ $step['description'] }}

@if (! empty($step['note']))

{{ $step['note'] }}

@endif @if (! empty($step['url']) && ! empty($step['link_label'])) Open {{ $step['link_label'] }} @endif
@endforeach
@if (auth()->user()->can('record-payments') || auth()->user()->can('send-invoice-reminders') || auth()->user()->can('cancel-invoices') || auth()->user()->can('void-invoices') || auth()->user()->can('mark-invoices-paid'))

Invoice actions

Choose an invoice action.

@can('record-payments') @if ($invoice->isCollectible()) Record payment @endif @endcan @can('send-invoice-reminders') @if ($reminderEligible)
@csrf
@endif @endcan @if ($invoice->isCollectible()) @can('cancel-invoices')
@csrf
@endcan @can('void-invoices')
@csrf
@endcan @endif
@can('mark-invoices-paid') @if ($invoice->isActive())
@csrf @method('PATCH')
@endif @endcan
@endif

Line items

Itemized work and pricing for this invoice.

@foreach ($invoice->items as $item) @endforeach
Description Qty Price Total
{{ $item->description }} {{ $item->quantity }} {{ $money($item->unit_price) }} {{ $money($item->line_total) }}

Record payment

Capture method, amount, date, and reference while keeping the invoice status automatic.

{{ $remainingBalance <= 0 ? 'Fully paid' : 'Balance '.$money($remainingBalance) }}
@can('record-payments') @if ($invoice->isTerminal())
This invoice is {{ strtolower($invoice->statusLabel()) }} and no longer accepts payments.
@elseif ($remainingBalance <= 0)
This invoice is fully paid. Additional payments are blocked to prevent accidental overpayment.
@else
@csrf

Full payment automatically marks the invoice as paid. Partial payment keeps the balance visible.

@endif @else
Only admins can record invoice payments.
@endcan

Credit notes

Refunds and adjustments linked to this invoice.

@can('manage-credit-notes') @if ($invoice->isActive()) Create credit note @endif @endcan
@if ($invoice->creditNotes->isEmpty())

No credit notes issued

Credit notes will appear here when an invoice correction or refund is created.

@else
@foreach ($invoice->creditNotes->sortByDesc('issue_date') as $creditNote) @endforeach
Credit note Type Status Amount
{{ $creditNote->credit_note_number }}{{ $creditNote->issue_date->format('d M Y') }} {{ $creditNote->typeLabel() }} {{ $creditNote->statusLabel() }} {{ $money($creditNote->amount) }}
@endif

Payment history

Successful payments, pending gateway attempts, and failed or cancelled payment records in one audit-friendly view.

@if ($invoice->payments->isEmpty())

No payments recorded yet

When a client pays this invoice, the payment will appear here.

@else
@foreach ($invoice->payments->sortByDesc(fn ($payment) => $payment->paid_at ?? $payment->created_at) as $payment) @php $paymentStatusClass = match ($payment->status) { Payment::STATUS_SUCCEEDED => 'status-badge status-paid', Payment::STATUS_PENDING => 'status-badge status-sent', Payment::STATUS_FAILED => 'status-badge status-overdue', Payment::STATUS_CANCELLED => 'status-badge status-cancelled', Payment::STATUS_REJECTED => 'status-badge status-void', default => 'status-badge status-draft', }; @endphp @endforeach
Date Method Status Reference Proof / notes Amount Actions
{{ ($payment->paid_at ?? $payment->payment_date)->format('d M Y') }} {{ $payment->methodLabel() }} @if ($payment->gateway) {{ Str::headline($payment->gateway) }} @endif {{ $payment->statusLabel() }} {{ $payment->payment_reference ?: ($payment->gateway_reference ?: 'No reference') }}

{{ $payment->notes ?: 'No notes' }}

@if ($payment->hasProof()) View proof @endif @if (data_get($payment->metadata, 'client_note'))

Client note: {{ data_get($payment->metadata, 'client_note') }}

@endif
{{ $money($payment->amount_paid) }} @if ($payment->isPending())
@csrf
@csrf
@else No action @endif
@endif

Reminder history

Current interval for this invoice: every {{ $reminderIntervalDays }} {{ Str::plural('day', $reminderIntervalDays) }}.

@if ($reminderEligible) {{ $reminderDue ? 'Auto reminder due' : 'Waiting interval' }} @else Not eligible @endif
@if ($invoice->reminders->isEmpty())

No reminders sent yet

Reminder emails will appear here once sent manually or by the scheduler.

@else
@foreach ($invoice->reminders->sortByDesc('sent_at') as $reminder) @endforeach
Sent at Sent to Sent by Type Status
{{ $reminder->sent_at?->format('d M Y H:i') ?? 'Not sent' }} {{ $reminder->sent_to }} {{ $reminder->sender?->name ?? 'Automatic scheduler' }} {{ $reminder->was_manual ? 'Manual' : 'Automatic' }} {{ Str::headline($reminder->status) }}
@endif
@if (! file_exists(public_path('build/manifest.json'))) @include('components.documents.list-script') @endif