138 lines
7.2 KiB
PHP
138 lines
7.2 KiB
PHP
{{--
|
|
The body of an invoice, for TCPDF's writeHTML().
|
|
|
|
Tables and inline styles, and a narrower dialect than even an email: TCPDF
|
|
understands a small subset of HTML and almost no CSS. No flexbox, no grid,
|
|
no shorthand borders on table cells, no percentage padding. What works is a
|
|
table with widths, and text-align.
|
|
|
|
Every value comes from the frozen snapshot ($s). Nothing here reads a
|
|
setting or a model — that is the whole reason no PDF has to be stored.
|
|
--}}
|
|
@php
|
|
use App\Services\Billing\InvoiceMath;
|
|
|
|
$issuer = $s['issuer'] ?? [];
|
|
$customer = $s['customer'] ?? [];
|
|
$meta = $s['meta'] ?? [];
|
|
$lines = $s['lines'] ?? [];
|
|
$totals = $s['totals'] ?? [];
|
|
@endphp
|
|
|
|
{{-- Sender line above the address, small — the line that shows through a
|
|
window envelope and tells the postman where to return it. --}}
|
|
<table cellpadding="0" cellspacing="0" style="width:100%;">
|
|
<tr>
|
|
<td style="width:58%; font-size:6.5pt; color:#6e6e7a; border-bottom:0.2mm solid #b4b4be;">
|
|
{{ collect([$issuer['name'] ?? null, $issuer['address'] ?? null, trim(($issuer['postcode'] ?? '').' '.($issuer['city'] ?? '')), $issuer['country'] ?? null])->filter()->join(' | ') }}
|
|
</td>
|
|
<td style="width:42%;"></td>
|
|
</tr>
|
|
</table>
|
|
|
|
<table cellpadding="0" cellspacing="0" style="width:100%; margin-top:2mm;">
|
|
<tr>
|
|
{{-- No leading whitespace inside these cells. TCPDF prints it: every indented
|
|
line came out indented, and only the last one — which had none — sat flush
|
|
against the margin. --}}
|
|
<td style="width:58%; font-size:10pt; line-height:145%;"><b>{{ $customer['name'] ?? '' }}</b><br>{{ $customer['address'] ?? '' }}<br>{{ trim(($customer['postcode'] ?? '').' '.($customer['city'] ?? '')) }}<br>{{ $customer['country'] ?? '' }}@if (! empty($customer['vat_id']))<br>{{ __('invoice.customer_vat') }}: {{ $customer['vat_id'] }}@endif</td>
|
|
<td style="width:42%;"></td>
|
|
</tr>
|
|
</table>
|
|
|
|
{{-- The data block, right, level with the address. Its own table because
|
|
TCPDF has no way to float one beside the other. --}}
|
|
<table cellpadding="1" cellspacing="0" style="width:100%; margin-top:14mm; font-size:9pt;">
|
|
<tr><td style="width:55%;"></td>
|
|
<td style="width:22%; color:#43434e;">{{ __('invoice.date') }}</td>
|
|
<td style="width:23%; text-align:right;">{{ $meta['issued_on'] ?? '' }}</td></tr>
|
|
@if (! empty($meta['customer_number']))
|
|
<tr><td></td>
|
|
<td style="color:#43434e;">{{ __('invoice.customer_number') }}</td>
|
|
<td style="text-align:right;">{{ $meta['customer_number'] }}</td></tr>
|
|
@endif
|
|
<tr><td></td>
|
|
<td style="color:#43434e;">{{ __('invoice.number') }}</td>
|
|
<td style="text-align:right;"><b>{{ $meta['number'] ?? '' }}</b></td></tr>
|
|
@if (! empty($meta['due_on']))
|
|
<tr><td></td>
|
|
<td style="color:#43434e;">{{ __('invoice.due') }}</td>
|
|
<td style="text-align:right;">{{ $meta['due_on'] }}</td></tr>
|
|
@endif
|
|
</table>
|
|
|
|
{{-- One block, not a heading with a paragraph beneath it: TCPDF gives an h1 a
|
|
margin of its own and the two drifted a centimetre apart. --}}
|
|
<table cellpadding="0" cellspacing="0" style="width:100%; margin-top:9mm;">
|
|
<tr><td style="font-size:16pt; font-weight:bold; line-height:125%;">{{ $meta['title'] ?? __('invoice.title') }}<br>{{ $meta['number'] ?? '' }}</td></tr>
|
|
</table>
|
|
|
|
@if (! empty($meta['salutation']))
|
|
<p style="font-size:9.5pt; margin-top:6mm;">{{ $meta['salutation'] }}</p>
|
|
@endif
|
|
@if (! empty($meta['intro']))
|
|
<p style="font-size:9.5pt; line-height:150%;">{{ $meta['intro'] }}</p>
|
|
@endif
|
|
|
|
{{-- Quantity, net unit price, net total AND gross total per line: the invoice
|
|
goes to businesses and to consumers, and each reads a different column
|
|
first. --}}
|
|
<table cellpadding="3" cellspacing="0" style="width:100%; margin-top:6mm; font-size:8.5pt;">
|
|
<tr style="font-weight:bold; background-color:#fafafb;">
|
|
<td style="width:7%; border-bottom:0.2mm solid #b4b4be;">{{ __('invoice.col_pos') }}</td>
|
|
<td style="width:41%; border-bottom:0.2mm solid #b4b4be;">{{ __('invoice.col_description') }}</td>
|
|
<td style="width:12%; text-align:right; border-bottom:0.2mm solid #b4b4be;">{{ __('invoice.col_quantity') }}</td>
|
|
<td style="width:14%; text-align:right; border-bottom:0.2mm solid #b4b4be;">{{ __('invoice.col_unit_net') }}</td>
|
|
<td style="width:13%; text-align:right; border-bottom:0.2mm solid #b4b4be;">{{ __('invoice.col_total_net') }}</td>
|
|
<td style="width:13%; text-align:right; border-bottom:0.2mm solid #b4b4be;">{{ __('invoice.col_total_gross') }}</td>
|
|
</tr>
|
|
@foreach ($lines as $index => $line)
|
|
@php
|
|
$net = InvoiceMath::lineNet((int) $line['unit_net_cents'], (int) $line['quantity_milli']);
|
|
$gross = $net + InvoiceMath::tax($net, (int) ($totals['rate_basis_points'] ?? 2000));
|
|
@endphp
|
|
<tr>
|
|
<td style="border-bottom:0.1mm solid #e9e9ee;">{{ $index + 1 }}</td>
|
|
<td style="border-bottom:0.1mm solid #e9e9ee;">{{ $line['description'] ?? '' }}@foreach (($line['details'] ?? []) as $detail)<br><span style="color:#6e6e7a;">{{ $detail }}</span>@endforeach</td>
|
|
<td style="text-align:right; border-bottom:0.1mm solid #e9e9ee;">{{ InvoiceMath::quantity((int) $line['quantity_milli']) }}@if (! empty($line['unit'])) {{ $line['unit'] }}@endif</td>
|
|
<td style="text-align:right; border-bottom:0.1mm solid #e9e9ee;">{{ InvoiceMath::money((int) $line['unit_net_cents']) }}</td>
|
|
<td style="text-align:right; border-bottom:0.1mm solid #e9e9ee;">{{ InvoiceMath::money($net) }}</td>
|
|
<td style="text-align:right; border-bottom:0.1mm solid #e9e9ee;">{{ InvoiceMath::money($gross) }}</td>
|
|
</tr>
|
|
@endforeach
|
|
</table>
|
|
|
|
<table cellpadding="3" cellspacing="0" style="width:100%; margin-top:4mm; font-size:9pt;">
|
|
@if (! empty($totals['adjustment']))
|
|
<tr>
|
|
<td style="width:60%;"></td>
|
|
<td style="width:25%;">{{ $meta['adjustment_label'] ?? __('invoice.adjustment') }}</td>
|
|
<td style="width:15%; text-align:right;">{{ InvoiceMath::money((int) $totals['adjustment']) }}</td>
|
|
</tr>
|
|
@endif
|
|
<tr>
|
|
<td></td>
|
|
<td>{{ __('invoice.net') }}</td>
|
|
<td style="text-align:right;">{{ InvoiceMath::money((int) ($totals['net'] ?? 0)) }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td></td>
|
|
<td>{{ __('invoice.tax', ['rate' => rtrim(rtrim(number_format(($totals['rate_basis_points'] ?? 2000) / 100, 2, ',', '.'), '0'), ',')]) }}</td>
|
|
<td style="text-align:right;">{{ InvoiceMath::money((int) ($totals['tax'] ?? 0)) }}</td>
|
|
</tr>
|
|
<tr style="font-weight:bold;">
|
|
<td></td>
|
|
<td style="border-top:0.2mm solid #b4b4be;">{{ __('invoice.gross') }}</td>
|
|
<td style="text-align:right; border-top:0.2mm solid #b4b4be;">{{ InvoiceMath::money((int) ($totals['gross'] ?? 0)) }} {{ $meta['currency'] ?? 'EUR' }}</td>
|
|
</tr>
|
|
</table>
|
|
|
|
@if (! empty($meta['payment_terms']))
|
|
<p style="font-size:9pt; margin-top:10mm;"><b>{{ __('invoice.payment_title') }}</b></p>
|
|
<p style="font-size:9pt; line-height:150%; margin-top:0;">{{ $meta['payment_terms'] }}</p>
|
|
@endif
|
|
|
|
@if (! empty($meta['closing']))
|
|
<p style="font-size:9pt; line-height:150%; margin-top:6mm;">{{ $meta['closing'] }}</p>
|
|
@endif
|