@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
@php $paperUrl = fn ($paper) => request()->fullUrlWithQuery(['paper' => $paper]); $pos80Url = \Illuminate\Support\Facades\Route::has('kasir.receipt') ? route('kasir.receipt', $order) : null; @endphp
@if($logoSrc) @endif
{{ $safeShopName }}
@if($safeShopAddress) {{ $safeShopAddress }}
@endif @if($safeShopPhone) Telp: {{ $safeShopPhone }} @endif
INVOICE
{{ $invoiceNumber }}
@if($qrSvg) {!! $qrSvg !!} @else
QR tidak tersedia
{{ $invoiceNumber }}
@endif
Scan untuk trace order
Kepada
Nama : {{ $customerName }}
No HP : {{ $customerPhone ?: '-' }}
Status : {{ $statusLabel }}
Detail Invoice
@if($isUsePpn && (($taxSetting->npwp ?? null) || ($taxSetting->pkp_name ?? null))) @endif
Tanggal : {{ optional($order->created_at)->format('d/m/Y H:i') }}
No Invoice : {{ $invoiceNumber }}
NPWP/PKP : {{ $taxSetting->npwp ?: $taxSetting->pkp_name }}
@forelse($items as $index => $item) @php $qty = (float) ($item->qty ?? $item->quantity ?? 0); $price = (float) ($item->calculated_price ?? $item->unit_price ?? $item->price ?? $item->harga ?? 0); $subtotal = (float) ($item->subtotal ?? $item->total ?? ($qty * $price)); if ($price <= 0 && $qty > 0 && $subtotal > 0) { $price = $subtotal / $qty; } $itemDesc = collect([ $item->product_name ?? $item->name ?? optional($item->product ?? null)->name ?? null, !empty($item->file_name) ? 'File: ' . $item->file_name : null, !empty($item->size_description) ? 'Ukuran: ' . $item->size_description : null, !empty($item->material_name) ? 'Bahan: ' . $item->material_name : null, !empty($item->finishing_note) ? 'Finishing: ' . $item->finishing_note : null, ])->filter()->implode(' | '); @endphp @empty @endforelse @for($i = 0; $i < $blankRows; $i++) @endfor
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 -
         
@if($isUsePpn) @endif @if($paidAmount > 0) @endif
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, ',', '.') }}