From eee6993679103aac8763d44183ed0c88028b2e7c Mon Sep 17 00:00:00 2001 From: Hanan Askarim Date: Thu, 16 Jul 2026 10:12:30 +0700 Subject: [PATCH] add report stock request np dan surat jalan --- .../report/Rpt_stock_request_np.php | 378 +++++++++++++++++ .../controllers/report/Rpt_surat_jalan.php | 385 ++++++++++++++++++ 2 files changed, 763 insertions(+) create mode 100644 application/controllers/report/Rpt_stock_request_np.php create mode 100644 application/controllers/report/Rpt_surat_jalan.php diff --git a/application/controllers/report/Rpt_stock_request_np.php b/application/controllers/report/Rpt_stock_request_np.php new file mode 100644 index 0000000..28478c4 --- /dev/null +++ b/application/controllers/report/Rpt_stock_request_np.php @@ -0,0 +1,378 @@ +AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular + $this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold) + } + + public function Footer() + { + $pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15 + + // ── Posisi: 20mm dari bawah halaman ────────────────────────────────── + $this->SetY(-20); + + // ── Baris 1: Print Oleh (kiri) | Nomor Halaman (tengah) ─────────────── + $colSide = ($pageW - 40) / 2; + $colCenter = 40; + + $this->SetFont('Arial_Narrow', '', 7); + $this->Cell($colSide, 4, 'Print Oleh : ' . $this->printUsername, 0, 0, 'L'); + $this->Cell($colCenter, 4, $this->PageNo() . ' / {nb}', 0, 0, 'C'); + $this->Cell($colSide, 4, '', 0, 1, 'R'); + + // ── Baris 2: Tgl Print (kiri) ────────────────────────────────────────── + $this->SetFont('Arial_Narrow', '', 7); + $this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L'); + $this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L'); + } +} + +// ============================================================================= +// Controller +// ============================================================================= +class Rpt_stock_request_np extends MY_Controller +{ + // ── Properti bersama antar fungsi PDF ───────────────────────────────────── + /** @var StockReqNpFpdf */ + private $_pdf; + private $_pageW; + private $_header_data; + private $_username; + + public function __construct() + { + parent::__construct(); + } + + public function index() + { + echo "Stock Request Non Persediaan (PR-NP) Report API"; + } + + // ========================================================================= + // ENDPOINT: pdf + // GET/POST: id (PurchaseRequestID), username (opsional) + // ========================================================================= + public function pdf() + { + try { + $id = intval($this->input->get_post('id')); + $username = trim($this->input->get_post('username') ?? ''); + + if ($id <= 0) { + $this->sys_error("ID tidak valid"); + exit; + } + + // ── Ambil data header & detail dari DB ──────────────────────────── + $header = $this->_get_header($id); + + // Validasi: Pastikan Kategori Item BUKAN '1' (Bukan Persediaan / Inventory) + if ($header['PurchaseRequestItemCategoryID'] == '1') { + $this->sys_error("Dokumen ini adalah kategori Persediaan. Gunakan report Stock Request biasa."); + exit; + } + + $details = $this->_get_detail($id); + + // ── Inisialisasi FPDF custom ────────────────────────────────────── + $this->_pdf = new StockReqNpFpdf('P', 'mm', 'A4'); + $this->_pdf->printUsername = $username !== '' ? $username : '-'; + $this->_pdf->printDate = date('d-m-Y H:i:s'); + $this->_pageW = $this->_pdf->GetPageWidth() - 30; + $this->_header_data = $header; + $this->_username = $this->_pdf->printUsername; + + $this->_pdf->AliasNbPages(); // aktifkan alias total halaman + $this->_pdf->SetMargins(15, 15, 15); + $this->_pdf->SetAutoPageBreak(true, 22); // 22mm ruang footer di bawah + $this->_pdf->AddPage(); + + // ── Susun isi halaman ───────────────────────────────────────────── + $this->_pdf_header(); + $this->_pdf_data($details); + $this->_pdf_terms(); + + // ── Output ──────────────────────────────────────────────────────── + $filename = 'SR_NP_' . str_replace('/', '-', $header['PurchaseRequestNumber']) . '.pdf'; + header('Content-Type: application/pdf'); + header('Content-Disposition: inline; filename="' . $filename . '"'); + header('Cache-Control: private, max-age=0, must-revalidate'); + header('Pragma: public'); + echo $this->_pdf->Output('S'); + } catch (Exception $exc) { + $this->sys_error($exc->getMessage()); + } + } + + // ========================================================================= + // DATABASE: Ambil data header + // ========================================================================= + private function _get_header($id) + { + $sql = " + SELECT + pr.*, + b.M_BranchName, + b.M_BranchAddress, + r.S_RegionalName, + ic.itemCategoryName, + IFNULL(u.M_UserUsername,'') AS CreatedByName, + IFNULL(ua.M_UserUsername,'') AS ApprovedByName + FROM purchase_request pr + LEFT JOIN m_branch b ON b.M_BranchCode = pr.PurchaseRequestM_BranchCode + LEFT JOIN s_regional r ON r.S_RegionalID = pr.PurchaseRequestS_RegionalID + LEFT JOIN item_category ic ON ic.itemCategoryID = pr.PurchaseRequestItemCategoryID + LEFT JOIN m_user u ON u.M_UserID = pr.PurchaseRequestCreatedUserID + LEFT JOIN m_user ua ON ua.M_UserID = pr.PurchaseRequestApprovedBy + WHERE pr.PurchaseRequestID = ? + LIMIT 1 + "; + $qry = $this->db->query($sql, array($id)); + if (!$qry || $qry->num_rows() === 0) { + $this->sys_error("Data Purchase Request tidak ditemukan"); + exit; + } + return $qry->row_array(); + } + + // ========================================================================= + // DATABASE: Ambil data detail + // ========================================================================= + private function _get_detail($id) + { + $sql = " + SELECT + prd.*, + item.M_ItemCode, + item.M_ItemDesc, + iu.ItemUnitName, + iu.ItemUnitCode + FROM purchase_request_detail prd + LEFT JOIN m_item item ON item.M_ItemID = prd.PurchaseRequestDetailM_ItemID + LEFT JOIN itemunit iu ON iu.ItemUnitID = prd.PurchaseRequestDetailItemUnitID + WHERE prd.PurchaseRequestDetailPurchaseRequestID = ? + AND prd.PurchaseRequestDetailIsActive = 'Y' + ORDER BY prd.PurchaseRequestDetailID ASC + "; + $qry = $this->db->query($sql, array($id)); + return $qry ? $qry->result_array() : array(); + } + + // ========================================================================= + // PDF SECTION: Header — Judul + Informasi Dokumen (2 kolom) + // ========================================================================= + private function _pdf_header() + { + $pdf = $this->_pdf; + $pageW = $this->_pageW; + $header = $this->_header_data; + + // ── Judul utama ─────────────────────────────────────────────────────── + $pdf->SetFont('Arial_Narrow', 'B', 14); + $pdf->Cell($pageW, 8, 'STOCK REQUEST REPORT (PR) - NON PERSEDIAAN', 0, 1, 'L'); + $pdf->SetDrawColor(0, 0, 0); + $pdf->SetLineWidth(0.5); + $pdf->Line(15, $pdf->GetY(), 15 + $pageW, $pdf->GetY()); + $pdf->Ln(2); + + $startY = $pdf->GetY(); + $halfW = $pageW / 2; + $lblW = 28; + $valW = $halfW - $lblW - 4; + + // ── Kolom Kiri ──────────────────────────────────────────────────────── + $pdf->SetY($startY); + + $leftItems = array( + array('Nomor', $header['PurchaseRequestNumber'], true), + array('Ref Nomor', $header['PurchaseRequestRefNumber'] ?: '-', false), + array('Tanggal', $this->_fmt_date($header['PurchaseRequestDate']), false), + array('Status', $header['PurchaseRequestStatus'], false), + ); + + foreach ($leftItems as $item) { + $pdf->SetX(15); + $pdf->SetFont('Arial_Narrow', '', 9); + $pdf->Cell($lblW, 5, $item[0], 0, 0, 'L'); + $pdf->Cell(4, 5, ':', 0, 0, 'C'); + if ($item[2]) { + $pdf->SetFont('Arial_Narrow', 'B', 9); + } else { + $pdf->SetFont('Arial_Narrow', '', 9); + } + $pdf->Cell($valW, 5, $item[1], 0, 1, 'L'); + } + + // Keterangan / Note langsung di bawah Status (tanpa spasi vertikal) + if (!empty($header['PurchaseRequestNote'])) { + $pdf->SetX(15); + $pdf->SetFont('Arial_Narrow', '', 9); + $pdf->Cell($lblW, 5, 'Keterangan', 0, 0, 'L'); + $pdf->Cell(4, 5, ':', 0, 0, 'C'); + $pdf->MultiCell($valW, 5, $header['PurchaseRequestNote'], 0, 'L'); + } + $leftY = $pdf->GetY(); + + // ── Kolom Kanan ─────────────────────────────────────────────────────── + $pdf->SetY($startY); + $rightX = 15 + $halfW; + + $rightItems = array( + array('Cabang', $header['M_BranchName']), + array('Regional', $header['S_RegionalName']), + array('Kategori', $header['itemCategoryName'] ?: '-'), + array('Dibuat Oleh', $header['CreatedByName']), + array('Disetujui Oleh', $header['ApprovedByName'] ?: '-'), + array('Tanggal Approved', $this->_fmt_datetime($header['PurchaseRequestApprovedDate'])), + ); + + foreach ($rightItems as $item) { + $pdf->SetX($rightX); + $pdf->SetFont('Arial_Narrow', '', 9); + $pdf->Cell($lblW, 5, $item[0], 0, 0, 'L'); + $pdf->Cell(4, 5, ':', 0, 0, 'C'); + $pdf->SetFont('Arial_Narrow', '', 9); + $pdf->Cell($valW, 5, $item[1], 0, 1, 'L'); + } + $rightY = $pdf->GetY(); + + // Posisikan Y ke yang paling bawah + margin + $pdf->SetY(max($leftY, $rightY) + 4); + } + + // ========================================================================= + // PDF SECTION: Data — Tabel detail item + ringkasan nilai + // ========================================================================= + private function _pdf_data($details) + { + $pdf = $this->_pdf; + $pageW = $this->_pageW; + $header = $this->_header_data; + + // ── Definisi kolom: [label, lebar, align] ───────────────────────────── + // Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan) + // 8 + 82 + 20 + 20 + 25 + 25 = 180 + $cols = array( + array('No', 8, 'C'), + array('Nama / Item', 82, 'L'), + array('Unit', 20, 'C'), + array('Qty', 20, 'R'), + array('Harga', 25, 'R'), + array('Total', 25, 'R'), + ); + + // Header kolom + $pdf->SetLineWidth(0.3); // border medium + $pdf->SetFont('Arial_Narrow', 'B', 8); + $pdf->SetFillColor(220, 220, 220); + $pdf->SetDrawColor(0, 0, 0); + foreach ($cols as $c) { + $pdf->Cell($c[1], 7, $c[0], 1, 0, 'C', true); + } + $pdf->Ln(); + + // Baris data + $pdf->SetLineWidth(0.2); // border lebih tipis di data + $pdf->SetFont('Arial_Narrow', '', 8); + $pdf->SetFillColor(255, 255, 255); + $no = 1; + $total_est = 0; + + foreach ($details as $d) { + $pdf->Cell($cols[0][1], 6, $no, 1, 0, 'C'); + $pdf->Cell($cols[1][1], 6, $d['M_ItemDesc'] ?: ($d['M_ItemCode'] ?: '-'), 1, 0, 'L'); + $pdf->Cell($cols[2][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C'); + $pdf->Cell($cols[3][1], 6, $this->_fmt_qty($d['PurchaseRequestDetailQty']), 1, 0, 'C'); + $pdf->Cell($cols[4][1], 6, $this->_fmt_rp($d['PurchaseRequestDetailPrice']), 1, 0, 'R'); + $pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['PurchaseRequestDetailTotal']), 1, 0, 'R'); + $pdf->Ln(); + + $total_est += floatval($d['PurchaseRequestDetailTotal']); + $no++; + } + + // Baris TOTAL + $span = array_sum(array_column(array_slice($cols, 0, 5), 1)); + $pdf->SetLineWidth(0.3); + $pdf->SetFont('Arial_Narrow', 'B', 9); // bold + size 9 agar menonjol + $pdf->SetFillColor(220, 220, 220); + $pdf->Cell($span, 7, 'TOTAL', 1, 0, 'R', true); + $pdf->Cell($cols[5][1], 7, $this->_fmt_rp($total_est), 1, 0, 'R', true); + $pdf->Ln(); + + $pdf->Ln(4); + } + + // ========================================================================= + // PDF SECTION: Syarat & Ketentuan + // ========================================================================= + private function _pdf_terms() + { + $pdf = $this->_pdf; + $pageW = $this->_pageW; + + $terms = array( + 'Pengajuan pembelian ini harus mendapatkan persetujuan dari pejabat berwenang sebelum proses pembelian dilakukan.', + 'Barang/jasa yang dibeli harus sesuai dengan spesifikasi dan kebutuhan yang tercantum dalam dokumen ini.', + 'Pembayaran dilakukan setelah barang/jasa diterima dan diverifikasi sesuai pesanan.', + 'Dokumen ini bersifat internal dan hanya digunakan untuk keperluan proses pengadaan.', + ); + + $pdf->SetFont('Arial_Narrow', 'B', 9); + $pdf->Cell($pageW, 5, 'Syarat & Ketentuan:', 0, 1, 'L'); + + $pdf->SetFont('Arial_Narrow', '', 8); + foreach ($terms as $i => $t) { + $pdf->Cell(6, 5, ($i + 1) . '.', 0, 0, 'R'); + $pdf->Cell($pageW - 6, 5, $t, 0, 1, 'L'); + } + } + + // ========================================================================= + // HELPER: Format tampilan + // ========================================================================= + private function _fmt_date($d) + { + if (!$d || $d === '0000-00-00') return '-'; + return date('d-m-Y', strtotime($d)); + } + + private function _fmt_datetime($d) + { + if (!$d || $d === '0000-00-00 00:00:00') return '-'; + return date('d-m-Y H:i', strtotime($d)); + } + + private function _fmt_num($n) + { + return number_format(floatval($n), 2, ',', '.'); + } + + // format jumlah/qty: tanpa desimal + private function _fmt_qty($n) + { + return number_format(floatval($n), 0, ',', '.'); + } + + private function _fmt_rp($n) + { + return 'Rp ' . number_format(floatval($n), 2, ',', '.'); + } +} diff --git a/application/controllers/report/Rpt_surat_jalan.php b/application/controllers/report/Rpt_surat_jalan.php new file mode 100644 index 0000000..c37d80e --- /dev/null +++ b/application/controllers/report/Rpt_surat_jalan.php @@ -0,0 +1,385 @@ +AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular + $this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold) + } + + public function Footer() + { + $pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15 + + // ── Posisi: 20mm dari bawah halaman ────────────────────────────────── + $this->SetY(-20); + + // ── Baris 1: Print Oleh (kiri) | Nomor Halaman (tengah) ─────────────── + $colSide = ($pageW - 40) / 2; + $colCenter = 40; + + $this->SetFont('Arial_Narrow', '', 7); + $this->Cell($colSide, 4, 'Print Oleh : ' . $this->printUsername, 0, 0, 'L'); + $this->Cell($colCenter, 4, $this->PageNo() . ' / {nb}', 0, 0, 'C'); + $this->Cell($colSide, 4, '', 0, 1, 'R'); + + // ── Baris 2: Tgl Print (kiri) ────────────────────────────────────────── + $this->SetFont('Arial_Narrow', '', 7); + $this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L'); + $this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L'); + } +} + +// ============================================================================= +// Controller +// ============================================================================= +class Rpt_surat_jalan extends MY_Controller +{ + // ── Properti bersama antar fungsi PDF ───────────────────────────────────── + /** @var SuratJalanFpdf */ + private $_pdf; + private $_pageW; + private $_header_data; + private $_username; + + public function __construct() + { + parent::__construct(); + } + + public function index() + { + echo "Surat Jalan Report API"; + } + + // ========================================================================= + // ENDPOINT: pdf + // GET/POST: id (SuratJalanID), username (opsional) + // ========================================================================= + public function pdf() + { + try { + $id = intval($this->input->get_post('id')); + $username = trim($this->input->get_post('username') ?? ''); + + if ($id <= 0) { + $this->sys_error("ID tidak valid"); + exit; + } + + // ── Ambil data header & detail dari DB ──────────────────────────── + $header = $this->_get_header($id); + $details = $this->_get_detail($id); + + // ── Inisialisasi FPDF custom ────────────────────────────────────── + $this->_pdf = new SuratJalanFpdf('P', 'mm', 'A4'); + $this->_pdf->printUsername = $username !== '' ? $username : '-'; + $this->_pdf->printDate = date('d-m-Y H:i:s'); + $this->_pageW = $this->_pdf->GetPageWidth() - 30; + $this->_header_data = $header; + $this->_username = $this->_pdf->printUsername; + + $this->_pdf->AliasNbPages(); // aktifkan alias total halaman + $this->_pdf->SetMargins(15, 15, 15); + $this->_pdf->SetAutoPageBreak(true, 22); // 22mm ruang footer di bawah + $this->_pdf->AddPage(); + + // ── Susun isi halaman ───────────────────────────────────────────── + $this->_pdf_header(); + $this->_pdf_data($details); + $this->_pdf_terms(); + + // ── Output ──────────────────────────────────────────────────────── + $filename = 'SJ_' . str_replace('/', '-', $header['SuratJalanNumber']) . '.pdf'; + header('Content-Type: application/pdf'); + header('Content-Disposition: inline; filename="' . $filename . '"'); + header('Cache-Control: private, max-age=0, must-revalidate'); + header('Pragma: public'); + echo $this->_pdf->Output('S'); + + } catch (Exception $exc) { + $this->sys_error($exc->getMessage()); + } + } + + // ========================================================================= + // DATABASE: Ambil data header + // ========================================================================= + private function _get_header($id) + { + $sql = " + SELECT + sj.*, + ex.ExpeditionName, + ex.ExpeditionIsInternal, + exs.ExpeditionStaffName, + exs.ExpeditionStaffMobile, + tg.T_GoodsTransferNum, + tg.T_GoodsTransferDate, + tg.T_GoodsTransferType, + tg.T_GoodsTransferFromM_BranchCode, + tg.T_GoodsTransferToM_BranchCode, + bFrom.M_BranchName AS BranchFromName, + bFrom.M_BranchAddress AS BranchFromAddress, + bTo.M_BranchName AS BranchToName, + bTo.M_BranchAddress AS BranchToAddress + FROM suratjalan sj + LEFT JOIN t_goods_transfer tg ON tg.T_GoodsTransferID = sj.SuratJalanT_GoodsTransferID + AND tg.T_GoodsTransferIsActive = 'Y' + LEFT JOIN expedition ex ON ex.ExpeditionID = sj.SuratJalanEkspedisiID + AND ex.ExpeditionIsActive = 'Y' + LEFT JOIN expeditionstaff exs ON exs.ExpeditionStaffID = sj.SuratJalanEkspedisiStaffID + AND exs.ExpeditionStaffIsActive = 'Y' + LEFT JOIN m_branch bFrom ON bFrom.M_BranchCode = tg.T_GoodsTransferFromM_BranchCode + LEFT JOIN m_branch bTo ON bTo.M_BranchCode = tg.T_GoodsTransferToM_BranchCode + WHERE sj.SuratJalanIsActive = 'Y' + AND sj.SuratJalanID = ? + LIMIT 1 + "; + $qry = $this->db->query($sql, array($id)); + if (!$qry || $qry->num_rows() === 0) { + $this->sys_error("Data Surat Jalan tidak ditemukan"); + exit; + } + return $qry->row_array(); + } + + // ========================================================================= + // DATABASE: Ambil data detail + // ========================================================================= + private function _get_detail($id) + { + $sql = " + SELECT + sjd.*, + item.M_ItemCode, + item.M_ItemDesc, + iu.ItemUnitName, + iu.ItemUnitCode, + pr.PurchaseRequestNumber + FROM suratjalan_detail sjd + JOIN m_item item ON item.M_ItemID = sjd.SuratJalanDetailM_ItemID + AND item.M_ItemIsActive = 'Y' + LEFT JOIN itemunit iu ON iu.ItemUnitID = sjd.SuratJalanDetailItemUnitID + AND iu.ItemUnitIsActive = 'Y' + LEFT JOIN purchase_request_flag prf ON prf.PurchaseRequestFlagID = sjd.SuratJalanDetailPurchaseRequestFlagID + AND prf.PurchaseRequestFlagIsActive = 'Y' + LEFT JOIN purchase_request_detail prd ON prd.PurchaseRequestDetailID = prf.PurchaseRequestFlagPurchaseRequestDetailID + LEFT JOIN purchase_request pr ON pr.PurchaseRequestID = prd.PurchaseRequestDetailPurchaseRequestID + WHERE sjd.SuratJalanDetailIsActive = 'Y' + AND sjd.SuratJalanDetailSuratJalanID = ? + ORDER BY sjd.SuratJalanDetailID ASC + "; + $qry = $this->db->query($sql, array($id)); + return $qry ? $qry->result_array() : array(); + } + + // ========================================================================= + // PDF SECTION: Header — Judul + Informasi Dokumen (2 kolom) + // ========================================================================= + private function _pdf_header() + { + $pdf = $this->_pdf; + $pageW = $this->_pageW; + $header = $this->_header_data; + + // ── Judul utama ─────────────────────────────────────────────────────── + $pdf->SetFont('Arial_Narrow', 'B', 14); + $pdf->Cell($pageW, 8, 'SURAT JALAN (DELIVERY ORDER)', 0, 1, 'L'); + $pdf->SetDrawColor(0, 0, 0); + $pdf->SetLineWidth(0.5); + $pdf->Line(15, $pdf->GetY(), 15 + $pageW, $pdf->GetY()); + $pdf->Ln(2); + + $startY = $pdf->GetY(); + $halfW = $pageW / 2; + $lblW = 28; + $valW = $halfW - $lblW - 4; + + // ── Kolom Kiri ──────────────────────────────────────────────────────── + $pdf->SetY($startY); + + $leftItems = array( + array('Nomor SJ', $header['SuratJalanNumber'], true), + array('Tanggal SJ', $this->_fmt_date($header['SuratJalanDate']), false), + array('No. Transfer', $header['SuratJalanT_GoodsTransferNum'] ?: '-', false), + array('Status', $header['SuratJalanStatus'], false), + ); + + foreach ($leftItems as $item) { + $pdf->SetX(15); + $pdf->SetFont('Arial_Narrow', '', 9); + $pdf->Cell($lblW, 5, $item[0], 0, 0, 'L'); + $pdf->Cell(4, 5, ':', 0, 0, 'C'); + if ($item[2]) { + $pdf->SetFont('Arial_Narrow', 'B', 9); + } else { + $pdf->SetFont('Arial_Narrow', '', 9); + } + $pdf->Cell($valW, 5, $item[1], 0, 1, 'L'); + } + + // Keterangan / Note langsung di bawah Status (tanpa spasi vertikal) + if (!empty($header['SuratJalanNote'])) { + $pdf->SetX(15); + $pdf->SetFont('Arial_Narrow', '', 9); + $pdf->Cell($lblW, 5, 'Keterangan', 0, 0, 'L'); + $pdf->Cell(4, 5, ':', 0, 0, 'C'); + $pdf->MultiCell($valW, 5, $header['SuratJalanNote'], 0, 'L'); + } + $leftY = $pdf->GetY(); + + // ── Kolom Kanan ─────────────────────────────────────────────────────── + $pdf->SetY($startY); + $rightX = 15 + $halfW; + + $rightItems = array( + array('Dari Cabang', $header['BranchFromName'] ?: '-'), + array('Alamat Asal', $header['BranchFromAddress'] ?: '-'), + array('Tujuan Cabang', $header['BranchToName'] ?: '-'), + array('Alamat Tujuan', $header['BranchToAddress'] ?: '-'), + array('Ekspedisi', $header['ExpeditionName'] ?: '-'), + array('Driver / Staf', $header['ExpeditionStaffName'] ?: '-'), + array('Kontak Driver', $header['SuratJalanEkspedisiStaffContact'] ?: '-'), + ); + + foreach ($rightItems as $item) { + $pdf->SetX($rightX); + $pdf->SetFont('Arial_Narrow', '', 9); + $pdf->Cell($lblW, 5, $item[0], 0, 0, 'L'); + $pdf->Cell(4, 5, ':', 0, 0, 'C'); + $pdf->SetFont('Arial_Narrow', '', 9); + + if ($item[0] === 'Alamat Asal' || $item[0] === 'Alamat Tujuan') { + $pdf->MultiCell($valW, 5, $item[1], 0, 'L'); + } else { + $pdf->Cell($valW, 5, $item[1], 0, 1, 'L'); + } + } + $rightY = $pdf->GetY(); + + // Posisikan Y ke yang paling bawah + margin + $pdf->SetY(max($leftY, $rightY) + 4); + } + + // ========================================================================= + // PDF SECTION: Data — Tabel detail item + // ========================================================================= + private function _pdf_data($details) + { + $pdf = $this->_pdf; + $pageW = $this->_pageW; + $header = $this->_header_data; + + // ── Definisi kolom: [label, lebar, align] ───────────────────────────── + // Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan) + // 8 + 62 + 20 + 20 + 42 + 28 = 180 + $cols = array( + array('No', 8, 'C'), + array('Nama / Uraian', 62, 'L'), + array('Unit', 20, 'C'), + array('Qty Kirim', 20, 'R'), + array('No. PR / Ref', 42, 'L'), + array('Qty Diterima', 28, 'R'), + ); + + // Header kolom + $pdf->SetLineWidth(0.3); // border medium + $pdf->SetFont('Arial_Narrow', 'B', 8); + $pdf->SetFillColor(220, 220, 220); + $pdf->SetDrawColor(0, 0, 0); + foreach ($cols as $c) { + $pdf->Cell($c[1], 7, $c[0], 1, 0, 'C', true); + } + $pdf->Ln(); + + // Baris data + $pdf->SetLineWidth(0.2); // border lebih tipis di data + $pdf->SetFont('Arial_Narrow', '', 8); + $pdf->SetFillColor(255, 255, 255); + $no = 1; + + foreach ($details as $d) { + $pdf->Cell($cols[0][1], 6, $no, 1, 0, 'C'); + $pdf->Cell($cols[1][1], 6, $d['M_ItemDesc'] ?: ($d['M_ItemCode'] ?: '-'), 1, 0, 'L'); + $pdf->Cell($cols[2][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C'); + $pdf->Cell($cols[3][1], 6, $this->_fmt_qty($d['SuratJalanDetailQty']), 1, 0, 'R'); + $pdf->Cell($cols[4][1], 6, $d['PurchaseRequestNumber'] ?: '-', 1, 0, 'L'); + $pdf->Cell($cols[5][1], 6, $this->_fmt_qty($d['SuratJalanDetailQtyReceived']), 1, 0, 'R'); + $pdf->Ln(); + + $no++; + } + + $pdf->Ln(4); + } + + // ========================================================================= + // PDF SECTION: Syarat & Ketentuan + // ========================================================================= + private function _pdf_terms() + { + $pdf = $this->_pdf; + $pageW = $this->_pageW; + + $terms = array( + 'Barang yang dikirimkan harus diperiksa kesesuaiannya dengan fisik sebelum ditandatangani oleh penerima.', + 'Segala klaim kerusakan atau kekurangan barang setelah serah terima menjadi tanggung jawab penerima barang.', + 'Surat jalan ini harus dikembalikan ke bagian logistik pengirim setelah ditandatangani oleh penerima.', + 'Dokumen ini merupakan bukti sah serah terima barang antar cabang.' + ); + + $pdf->SetFont('Arial_Narrow', 'B', 9); + $pdf->Cell($pageW, 5, 'Syarat & Ketentuan:', 0, 1, 'L'); + + $pdf->SetFont('Arial_Narrow', '', 8); + foreach ($terms as $i => $t) { + $pdf->Cell(6, 5, ($i + 1) . '.', 0, 0, 'R'); + $pdf->Cell($pageW - 6, 5, $t, 0, 1, 'L'); + } + } + + // ========================================================================= + // HELPER: Format tampilan + // ========================================================================= + private function _fmt_date($d) + { + if (!$d || $d === '0000-00-00') return '-'; + return date('d-m-Y', strtotime($d)); + } + + private function _fmt_datetime($d) + { + if (!$d || $d === '0000-00-00 00:00:00') return '-'; + return date('d-m-Y H:i', strtotime($d)); + } + + private function _fmt_num($n) + { + return number_format(floatval($n), 2, ',', '.'); + } + + // format jumlah/qty: tanpa desimal + private function _fmt_qty($n) + { + return number_format(floatval($n), 0, ',', '.'); + } + + private function _fmt_rp($n) + { + return 'Rp ' . number_format(floatval($n), 2, ',', '.'); + } +}