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, rFrom.S_RegionalName AS RegionalFromName, 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 s_regional rFrom ON rFrom.S_RegionalID = tg.T_GoodsTransferFromS_RegionalID 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 Regional', $header['RegionalFromName'] ?: '-'), 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 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', 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, 'C'); $pdf->Cell($cols[4][1], 6, $d['PurchaseRequestNumber'] ?: '-', 1, 0, 'L'); $pdf->Cell($cols[5][1], 6, $this->_fmt_qty($d['SuratJalanDetailQtyReceived']), 1, 0, 'C'); $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, ',', '.'); } }