loadMissing(['fromCountry', 'toCountry', 'items']); $data = [ 'shipment' => $shipment, 'shipper' => $this->formatAddress($shipment, 'sender'), 'receiver' => $this->formatAddress($shipment, 'receiver'), 'items' => $shipment->items ?? collect(), 'invoice_total_usd' => optional($shipment->items)->sum('total_usd') ?? 0, 'barcode_base64' => $this->generateBarcode($shipment->awb_no), 'service_label' => $this->getServiceLabel($shipment), 'type_label' => $this->getTypeLabel($shipment), ]; $html = view('pdfs.awb', $data)->render(); return $this->generatePdf($html, 'A4', 'portrait'); } /** * تولید Invoice PDF — فقط برای PARCEL و DOC_NORMAL/DOC_ECONOMY * (نه برای محموله‌های DOC خالص که کالا ندارن) */ public function invoice(Shipment $shipment): string { // اگه محموله DOC هست و آیتم نداره، invoice تولید نکن if ($shipment->type === ShipmentType::DocNormal || $shipment->type === ShipmentType::DocEconomy) { if ($shipment->items->isEmpty()) { throw new \InvalidArgumentException( 'فاکتور فقط برای محموله‌های دارای کالا (PARCEL) صادر می‌شود. محموله‌های DOC بدون کالا فاکتور ندارند.' ); } } $shipment->loadMissing(['fromCountry', 'toCountry', 'items']); $data = [ 'shipment' => $shipment, 'shipper' => $this->formatAddress($shipment, 'sender'), 'receiver' => $this->formatAddress($shipment, 'receiver'), 'items' => $shipment->items ?? collect(), 'invoice_total_usd' => optional($shipment->items)->sum('total_usd') ?? 0, 'barcode_base64' => $this->generateBarcode($shipment->awb_no), ]; $html = view('pdfs.invoice', $data)->render(); return $this->generatePdf($html, 'A4', 'portrait'); } /** * تولید Label PDF — اندازه استاندارد لیبل پستی (100x150mm) */ public function label(Shipment $shipment): string { $shipment->loadMissing(['fromCountry', 'toCountry']); $data = [ 'shipment' => $shipment, 'barcode_base64' => $this->generateBarcode($shipment->awb_no), 'origin_iso' => $shipment->fromCountry?->iso_code ?? 'IR', 'dest_iso' => $shipment->toCountry?->iso_code ?? '', ]; $html = view('pdfs.label', $data)->render(); // A5 افقی (Landscape) — استاندارد لیبل پستی: 210×148 mm return $this->generatePdf($html, 'A5', 'landscape'); } /** * تولید بارکد از AWB number — base64 embed (مطمئن‌ترین روش) */ private function generateBarcode(string $awbNo): string { try { $generator = new BarcodeGeneratorPNG(); $barcode = $generator->getBarcode($awbNo, $generator::TYPE_CODE_128, 2, 40); // تبدیل به base64 و استفاده از data URI return 'data:image/png;base64,' . base64_encode($barcode); } catch (\Throwable $e) { Log::error('Barcode generation failed', [ 'awb' => $awbNo, 'error' => $e->getMessage(), ]); return ''; } } /** * برچسب Service برای AWB (Outbound/Inbound) */ private function getServiceLabel(Shipment $shipment): string { return match ($shipment->direction?->value) { 'export' => 'Outbound', 'import' => 'Inbound', default => 'Outbound', }; } /** * برچسب Type برای AWB (NON DOC / DOC) */ private function getTypeLabel(Shipment $shipment): string { return match ($shipment->type) { ShipmentType::Parcel => 'NON DOC', ShipmentType::DocNormal => 'DOC NORMAL', ShipmentType::DocEconomy => 'DOC ECONOMY', default => 'NON DOC', }; } /** * تولید PDF از HTML */ private function generatePdf(string $html, array|string $paper, string $orientation): string { $options = new Options(); $options->set('isHtml5ParserEnabled', true); $options->set('isRemoteEnabled', true); // مهم: برای data URI $options->set('defaultFont', 'DejaVu Sans'); $options->set('dpi', 150); $options->set('debugKeepTemp', false); $options->set('debugCss', false); $options->set('debugLayout', false); $dompdf = new Dompdf($options); $dompdf->loadHtml($html); if (is_array($paper)) { $dompdf->setPaper($paper, $orientation); } else { $dompdf->setPaper($paper, $orientation); } $dompdf->render(); return $dompdf->output(); } /** * فرمت‌بندی آدرس فرستنده/گیرنده */ private function formatAddress(Shipment $shipment, string $prefix): Collection { return collect([ 'name' => $shipment->{$prefix . '_name'}, 'company' => $shipment->{$prefix . '_company'}, 'phone' => $shipment->{$prefix . '_phone'}, 'email' => $shipment->{$prefix . '_email'}, 'address' => $shipment->{$prefix . '_address'}, 'city' => $shipment->{$prefix . '_city'}, 'zip' => $shipment->{$prefix . '_zip'}, 'id_number' => $shipment->{$prefix . '_id_number'}, ]); } }