@php // $preview = true renders the same template for the on-screen preview // (served as HTML rather than dompdf). The only differences: the logo is // loaded by URL instead of base64 (dompdf needs the bytes inlined; a browser // does not), so the shared markup/CSS below stays the single source of truth. $preview = $preview ?? false; // When true, the totals box shows the refunded amount and the adjusted net // total, and a refund-history table is printed below the payment history. $showRefunds = ($showRefunds ?? false) && (float) $invoice->refunded_total > 0; $netTotal = round((float) $invoice->total - (float) $invoice->refunded_total, 2); $primary = $setting?->primary_color ?: '#3B82F6'; $headerColor = $setting?->table_header_color ?: $primary; $symbol = $currencySymbol ?: ''; $code = $invoice->currency_code ?: ''; $money = function ($value) use ($symbol, $code) { $formatted = number_format((float) $value, 2); return ($symbol !== '' ? $symbol . ' ' : ($code !== '' ? $code . ' ' : '')) . $formatted; }; // The badge says whether it is paid (Unpaid / Partially paid / Paid / // Void), never the internal send state: a customer has no use for "SENT". $statusKey = $invoice->isOverdue() ? 'OVERDUE' : $invoice->displayStatus(); $statusColors = [ 'UNPAID' => '#f59e0b', 'PARTIAL' => '#3b82f6', 'PAID' => '#10b981', 'OVERDUE' => '#ef4444', 'VOID' => '#6b7280', ]; $statusColor = $statusColors[$statusKey] ?? '#6b7280'; $statusText = $statusKey === 'OVERDUE' ? __('Unpaid, overdue') : $invoice->displayLabel(); $logoData = null; if ($setting?->logo_path) { try { if ($preview) { $logoData = \Illuminate\Support\Facades\Storage::disk('public')->url($setting->logo_path); } else { $logoFull = \Illuminate\Support\Facades\Storage::disk('public')->path($setting->logo_path); if (is_file($logoFull)) { $logoData = 'data:' . (mime_content_type($logoFull) ?: 'image/png') . ';base64,' . base64_encode(file_get_contents($logoFull)); } } } catch (\Throwable $e) { $logoData = null; } } // Banking / payment details are only useful while money is still owed. // Once an invoice is fully paid (or voided) we don't attach them. $needsPayment = $invoice->status !== 'VOID' && (float) $invoice->balance_due > 0.01; // Short link a customer can type off the printed page. Only on an unpaid // invoice, a settled one should not invite another payment. $payLink = $needsPayment ? $invoice->shortPayUrl() : null; $payLinkPlain = $payLink ? preg_replace('#^https?://#', '', $payLink) : null; // How this invoice can be paid, resolved for ITS currency: a USD account // never appears on a ZAR invoice. Resolved here rather than in the // controller because this template is rendered from eight places (preview, // download, portal, email attachment, combined letters) and every one of // them has to agree. // // The payment method goes in because the bank details are conditional on // it: they print only when the customer said they were paying by transfer, // which is the only case where this total has the transfer charge in it. $banking = \App\Support\DocumentBanking::for( $invoice->team_id, $invoice->currency_code, $setting, $invoice->paymentMethod ); // The printed page carries bank details and the pay link only, so it is // those two that decide whether there is a page at all. $hasBankingPage = $needsPayment && ($banking['showsBanking'] || $payLink); @endphp
|
@if ($logoData)
@endif {{ $setting?->company_name ?: $invoice->team?->name }}@if ($setting?->address){{ __('Address') }}: {!! nl2br(e($setting->address)) !!} @endif @if ($setting?->email){{ __('Email') }}: {{ $setting->email }} @endif @if ($setting?->website){{ __('Web') }}: {{ $setting->website }} @endif @if ($setting?->phone){{ __('Phone') }}: {{ $setting->phone }} @endif @if ($setting?->tin_number){{ __('TIN') }}: {{ $setting->tin_number }} @endif |
|
{{ $invoice->payerName() ?: '—' }}
@if ($invoice->customer) @if ($invoice->customer->address){{ __('Address') }}: {!! nl2br(e($invoice->customer->address)) !!}
@endif @if ($invoice->customer->email){{ __('Email') }}: {{ $invoice->customer->email }}
@endif @if ($invoice->customer->phone){{ __('Phone') }}: {{ $invoice->customer->phone }}
@endif @if ($invoice->customer->tin_number){{ __('TIN') }}: {{ $invoice->customer->tin_number }}
@endif @elseif ($invoice->tenant) @if ($invoice->tenant->space){{ __('Space') }}: {{ $invoice->tenant->space }}
@endif @if ($invoice->tenant->email){{ __('Email') }}: {{ $invoice->tenant->email }}
@endif @if ($invoice->tenant->phone){{ __('Phone') }}: {{ $invoice->tenant->phone }}
@endif @endif| # | {{ __('Item Description') }} | {{ __('Qty') }} | {{ __('Rate') }} | {{ __('Discount') }} | {{ __('Total') }} |
|---|---|---|---|---|---|
| {{ $i + 1 }} |
{{ $line->name }}
@if ($line->description){!! nl2br(e($line->description)) !!} @endif
|
{{ number_format((float) $line->qty, 2) }} | {{ $money($line->unit_price) }} | {{ $money($line->discount) }} | {{ $money($line->line_total) }} |
| {{ __('No items.') }} | |||||
|
| # | {{ __('Date') }} | {{ __('Method') }} | {{ __('Reference') }} | {{ __('Amount') }} |
|---|---|---|---|---|
| {{ $i + 1 }} | {{ optional($payment->paid_at)->format('d/m/Y') }} | {{ $payment->channel }} @if ((float) $payment->surcharge > 0) (+{{ $money($payment->surcharge) }} {{ __('fee') }}) @endif | {{ $payment->reference ?: '—' }} | {{ $money($payment->amount) }} |
| {{ __('Total Paid') }}: | {{ $money($invoice->amount_paid) }} | |||
{{ $invoice->notes }}
{{ __('Make a secure online payment through Paynow:') }} {{ $payLinkPlain }}