@php $paperSize = $paperSize ?? request('paper', 'a4'); if (!in_array($paperSize, ['a4', 'a5', '215x165'], true)) { $paperSize = 'a4'; } $isA4 = $paperSize === 'a4'; $isA5 = $paperSize === 'a5'; $isCustom = $paperSize === '215x165'; /* * A5 dibuat LANDSCAPE supaya tidak gampang jadi 2 halaman. * Ukuran 21,5 x 16,5 juga landscape sesuai kebutuhan nota/faktur custom. */ $pageCss = match ($paperSize) { 'a5' => 'size: A5 landscape; margin: 8mm;', '215x165' => 'size: 215mm 165mm; margin: 7mm;', default => 'size: A4 portrait; margin: 13mm 15mm;', }; $fontSize = match ($paperSize) { 'a5' => '10px', '215x165' => '10px', default => '12px', }; $titleSize = match ($paperSize) { 'a5' => '23px', '215x165' => '23px', default => '30px', }; $logoWidth = match ($paperSize) { 'a5' => '110px', '215x165' => '112px', default => '165px', }; $logoHeight = match ($paperSize) { 'a5' => '38px', '215x165' => '40px', default => '62px', }; $qrSize = match ($paperSize) { 'a5' => 66, '215x165' => 70, default => 88, }; $minRows = match ($paperSize) { 'a5' => 2, '215x165' => 3, default => 7, }; $safeShopName = $shopName ?? config('app.name'); $safeShopAddress = $shopAddress ?? ''; $safeShopPhone = $shopPhone ?? ''; $safeShopFooter = $shopFooter ?? ''; @endphp
@php $items = collect($order->items ?? []); $blankRows = max($minRows - $items->count(), 0); $isUsePpn = (bool) ($usePpn ?? ($order->use_ppn ?? false)); $baseTotal = (float) ($order->subtotal_before_ppn ?? 0); if ($baseTotal <= 0) { $baseTotal = (float) ($order->total_price ?? $order->total ?? $order->grand_total ?? 0); if ($isUsePpn && (($order->ppn_amount ?? 0) > 0)) { $baseTotal = max($baseTotal - (float) $order->ppn_amount, 0); } } $ppnAmountFromOrder = (float) ($order->ppn_amount ?? 0); $ppnRateValue = (float) ($ppnRate ?? ($order->ppn_rate ?? 0)); $ppnAmount = $isUsePpn ? ($ppnAmountFromOrder > 0 ? $ppnAmountFromOrder : round($baseTotal * ($ppnRateValue / 100))) : 0; $grandTotal = $baseTotal + $ppnAmount; $paidAmount = 0; if (isset($order->total_paid)) { $paidAmount = (float) $order->total_paid; } elseif (isset($order->paid_amount)) { $paidAmount = (float) $order->paid_amount; } elseif (isset($order->amount_paid)) { $paidAmount = (float) $order->amount_paid; } $remainingAmount = max($grandTotal - $paidAmount, 0); if ($remainingAmount <= 1) { $remainingAmount = 0; } $invoiceNumber = $order->invoice_number ?? ('INV-' . $order->id); $traceUrl = url('/trace-order?search=' . urlencode($invoiceNumber)); /* * QR dibuat SVG supaya aman di hosting yang tidak punya GD/Imagick. * Penyebab barcode sebelumnya tidak muncul biasanya karena format PNG gagal dibuat, * lalu tertangkap catch dan $qr menjadi null. */ $qrSvg = null; try { if (class_exists(\SimpleSoftwareIO\QrCode\Facades\QrCode::class)) { $qrSvg = \SimpleSoftwareIO\QrCode\Facades\QrCode::format('svg') ->size(260) ->margin(1) ->errorCorrection('H') ->generate($traceUrl); } elseif (class_exists('QrCode')) { $qrSvg = QrCode::format('svg') ->size(260) ->margin(1) ->errorCorrection('H') ->generate($traceUrl); } } catch (\Throwable $e) { $qrSvg = null; } $customerName = $order->customer_name ?? optional($order->customer ?? null)->name ?? '-'; $customerPhone = $order->customer_phone ?? optional($order->customer ?? null)->phone ?? '-'; $logoSrc = ''; if (!empty($shopLogo)) { if (str_starts_with($shopLogo, 'http://') || str_starts_with($shopLogo, 'https://') || str_starts_with($shopLogo, '/') || str_starts_with($shopLogo, 'data:image')) { $logoSrc = $shopLogo; } else { $logoSrc = asset('storage/' . ltrim($shopLogo, '/')); } } $paperLabel = match ($paperSize) { 'a5' => 'A5 Landscape', '215x165' => '21,5 × 16,5 cm', default => 'A4', }; $isPaid = false; try { $isPaid = method_exists($order, 'isPaid') ? $order->isPaid() : (($order->payment_status ?? null) === 'paid'); } catch (\Throwable $e) { $isPaid = false; } $statusLabel = $isPaid ? 'Lunas' : (($order->is_credit ?? false) ? 'Piutang' : 'Belum Lunas'); @endphp|
@if($logoSrc)
{{ $safeShopName }}
|
INVOICE
{{ $invoiceNumber }}
@if($qrSvg)
{!! $qrSvg !!}
@else
QR tidak tersedia
@endif
{{ $invoiceNumber }} Scan untuk trace order
|
|
Kepada
|
Detail Invoice
|
| No | Item | Qty | Harga | Subtotal |
|---|---|---|---|---|
| {{ $index + 1 }} | {{ $itemDesc ?: '-' }} | {{ rtrim(rtrim(number_format($qty, 2, ',', '.'), '0'), ',') }} | Rp {{ number_format($price, 0, ',', '.') }} | Rp {{ number_format($subtotal, 0, ',', '.') }} |
| 1 | - | |||
| Subtotal | Rp {{ number_format($baseTotal, 0, ',', '.') }} |
| PPN {{ rtrim(rtrim(number_format($ppnRateValue, 2, ',', '.'), '0'), ',') }}% | Rp {{ number_format($ppnAmount, 0, ',', '.') }} |
| TOTAL | Rp {{ number_format($grandTotal, 0, ',', '.') }} |
| Terbayar | Rp {{ number_format($paidAmount, 0, ',', '.') }} |
| Sisa | Rp {{ number_format($remainingAmount, 0, ',', '.') }} |
|
@if($safeShopFooter)
{{ $safeShopFooter }}
@else
Terima kasih atas kepercayaan Anda.
@endif
@if($isUsePpn && ($taxSetting->notes ?? null) && $isA4)
{{ $taxSetting->notes }}
@endif
|
Hormat Kami, {{ $safeShopName }} |