@php $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(300) ->margin(2) ->errorCorrection('H') ->generate($traceUrl); } elseif (class_exists('QrCode')) { $qrSvg = QrCode::format('svg') ->size(300) ->margin(2) ->errorCorrection('H') ->generate($traceUrl); } } catch (\Throwable $e) { $qrSvg = null; } $usePpn = (bool) ($order->use_ppn ?? false); $ppnRate = (float) ($order->ppn_rate ?? 0); $ppnAmount = (float) ($order->ppn_amount ?? 0); $activeNotaItems = collect($order->items ?? []) ->filter(fn ($item) => !(bool) ($item->is_cancelled ?? false)) ->values(); $calculateNotaItemSubtotal = function ($item) { if (class_exists(\App\Support\OrderMoney::class)) { return (float) \App\Support\OrderMoney::itemSubtotal($item); } $unit = strtolower(trim((string) ($item->size_unit ?? 'lembar'))); $unit = match ($unit) { 'm2', 'm²', 'meter2', 'meter persegi', 'per meter persegi' => 'm2', 'meter', 'm', 'per meter' => 'meter', default => $unit !== '' ? $unit : 'lembar', }; $roundUp = function (float $amount): int { if ($amount <= 0) { return 0; } $base = (int) floor($amount / 1000) * 1000; $remainder = (int) round($amount - $base); if ($remainder === 0 || $remainder === 500) { return (int) round($amount); } return $remainder < 500 ? $base + 500 : $base + 1000; }; $qty = max((float) ($item->qty ?? $item->quantity ?? 1), 1); $sisi = max((int) ($item->sisi ?? 1), 1); $manualUnit = (float) ($item->manual_price ?? 0); if ($manualUnit > 0) { return round($manualUnit * $qty * $sisi, 2); } $basePrice = (float) ($item->base_price ?? 0); $sizeValue = (float) ($item->size_value ?? 0); if (in_array($unit, ['m2', 'meter'], true) && $basePrice > 0 && $sizeValue > 0) { $raw = round($basePrice * $sizeValue * $qty, 2); $raw = ($raw > 0 && $raw < 10000) ? 10000 : $raw; return $roundUp($raw); } return (float) ($item->subtotal ?? $item->system_subtotal ?? $item->total ?? 0); }; $itemsCalculatedTotal = (float) $activeNotaItems->sum(fn ($item) => $calculateNotaItemSubtotal($item)); $subtotalBeforePpn = $itemsCalculatedTotal > 0 ? $itemsCalculatedTotal : (float) ($order->subtotal_before_ppn ?? 0); if ($subtotalBeforePpn <= 0) { $subtotalBeforePpn = (float) ($order->total_price ?? 0); if ($usePpn && $ppnAmount > 0) { $subtotalBeforePpn = max($subtotalBeforePpn - $ppnAmount, 0); } } if ($usePpn && $ppnAmount <= 0 && $ppnRate > 0) { $ppnAmount = round($subtotalBeforePpn * ($ppnRate / 100)); } $grandTotal = $usePpn ? ($subtotalBeforePpn + $ppnAmount) : $subtotalBeforePpn; $paidAmount = 0; if (isset($order->report_paid_amount)) { $paidAmount = (float) $order->report_paid_amount; } elseif ($order->relationLoaded('payments')) { $paidAmount = (float) $order->payments->sum('amount'); } elseif (isset($order->paid_amount)) { $paidAmount = (float) $order->paid_amount; } $changeAmount = max($paidAmount - $grandTotal, 0); $remainingAmount = max($grandTotal - $paidAmount, 0); $paymentStatusLabel = $remainingAmount <= 0 && $grandTotal > 0 ? 'LUNAS' : ($paidAmount > 0 ? 'DP / BELUM LUNAS' : 'BELUM BAYAR'); if ($changeAmount <= 1) { $changeAmount = 0; } $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, '/')); } } @endphp
@if(env('APP_DEMO', false))
DEMO MODE
@endif
@if($logoSrc) @endif

{{ $shopName }}

@if($shopAddress)
{{ $shopAddress }}
@endif @if($shopPhone)
Telp: {{ $shopPhone }}
@endif
@if($qrSvg) {!! $qrSvg !!} @else
QR tidak tersedia
{{ $invoiceNumber }}
@endif
{{ $invoiceNumber }}
{{ $usePpn ? 'INVOICE + PPN ' . rtrim(rtrim(number_format($ppnRate, 2, ',', '.'), '0'), ',') . '%' : 'TANPA PPN' }}
@if(env('APP_DEMO', false))
Demo Mode
Nota ini adalah simulasi / percobaan
termasuk transaksi palsu dan bukan bukti pembayaran sah
@endif
Tgl: {{ optional($order->paid_at)->format('d/m/Y H:i') ?: now()->format('d/m/Y H:i') }}
Pelanggan: {{ $order->customer_name }}
Kasir: {{ $order->cashier->name ?? '-' }}
Designer: {{ $order->designer->name ?? '-' }}
@foreach($activeNotaItems as $item) @php $qty = max((float) ($item->qty ?? $item->quantity ?? 1), 1); $sisi = max((int) ($item->sisi ?? 1), 1); $manualUnit = (float) ($item->manual_price ?? 0); if ($manualUnit > 0) { $price = $manualUnit; $subtotal = $manualUnit * $qty * $sisi; } else { $subtotal = $calculateNotaItemSubtotal($item); $price = $subtotal > 0 ? ($subtotal / max($qty * $sisi, 1)) : (float) ($item->calculated_price ?? $item->unit_price ?? $item->price ?? 0); } @endphp
{{ $item->product_name }} - {{ $item->file_name }}
{{ $item->size_description }} | {{ ($item->sisi ?? 1) }} sisi | {{ $item->material_name ?? '-' }}
{{ rtrim(rtrim(number_format($qty, 2, ',', '.'), '0'), ',') }} x Rp {{ number_format($price,0,',','.') }} Rp {{ number_format($subtotal,0,',','.') }}
@endforeach
Subtotal Rp {{ number_format($subtotalBeforePpn,0,',','.') }}
@if($usePpn)
PPN {{ rtrim(rtrim(number_format($ppnRate, 2, ',', '.'), '0'), ',') }}% Rp {{ number_format($ppnAmount,0,',','.') }}
@endif
TOTAL Rp {{ number_format($grandTotal,0,',','.') }}
Dibayar Rp {{ number_format($paidAmount,0,',','.') }}
@if($remainingAmount > 0)
Sisa Rp {{ number_format($remainingAmount,0,',','.') }}
@endif
Kembalian Rp {{ number_format($changeAmount,0,',','.') }}
*** {{ $paymentStatusLabel }} ***
@if(env('APP_DEMO', false)) @endif