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_receive_transfer extends MY_Controller { // ── Properti bersama antar fungsi PDF ───────────────────────────────────── /** @var ReceiveTransferFpdf */ private $_pdf; private $_pageW; private $_header_data; private $_username; public function __construct() { parent::__construct(); } public function index() { echo "Receive Transfer 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 ReceiveTransferFpdf('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 = 'RT_' . 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, wh.WarehouseName AS ReceivedWarehouseName, IFNULL(uRec.M_UserUsername, '') AS ReceivedByName 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 LEFT JOIN warehouse wh ON wh.WarehouseID = sj.SuratJalanReceivedWarehouseID LEFT JOIN m_user uRec ON uRec.M_UserID = sj.SuratJalanReceivedUserID 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 Penerimaan 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, 'RECEIVE TRANSFER REPORT (RT)', 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('Tanggal Terima', $this->_fmt_date($header['SuratJalanReceivedDate']), false), array('Gudang Terima', $header['ReceivedWarehouseName'] ?: '-', 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['SuratJalanReceivedNote'])) { $pdf->SetX(15); $pdf->SetFont('Arial_Narrow', '', 9); $pdf->Cell($lblW, 5, 'Catatan Terima', 0, 0, 'L'); $pdf->Cell(4, 5, ':', 0, 0, 'C'); $pdf->MultiCell($valW, 5, $header['SuratJalanReceivedNote'], 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('Diterima Oleh', $header['ReceivedByName'] ?: '-'), ); 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 + 59 + 20 + 20 + 20 + 17 + 36 = 180 $cols = array( array('No', 8, 'C'), array('Nama', 59, 'L'), array('Unit', 20, 'C'), array('Qty Kirim', 20, 'R'), array('Qty Terima', 20, 'R'), array('Selisih', 17, 'R'), array('No. PR / Ref', 36, 'L'), ); // 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) { $qtyKirim = intval($d['SuratJalanDetailQty']); $qtyTerima = intval($d['SuratJalanDetailQtyReceived']); $selisih = $qtyKirim - $qtyTerima; $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($qtyKirim), 1, 0, 'C'); $pdf->Cell($cols[4][1], 6, $this->_fmt_qty($qtyTerima), 1, 0, 'C'); $pdf->Cell($cols[5][1], 6, $this->_fmt_qty($selisih), 1, 0, 'C'); $pdf->Cell($cols[6][1], 6, $d['PurchaseRequestNumber'] ?: '-', 1, 0, 'L'); $pdf->Ln(); $no++; } $pdf->Ln(4); } // ========================================================================= // PDF SECTION: Syarat & Ketentuan // ========================================================================= private function _pdf_terms() { $pdf = $this->_pdf; $pageW = $this->_pageW; $terms = array( 'Barang yang diterima telah diverifikasi secara kuantitas dan kualitas sesuai dengan fisik yang diserahterimakan.', 'Segala ketidaksesuaian/selisih barang harus dilaporkan dalam waktu 1x24 jam sejak dokumen ini ditandatangani.', 'Penerimaan barang ini sah secara sistem setelah dokumen ini divalidasi dan disimpan di sistem persediaan.', 'Dokumen ini dicetak secara otomatis dari sistem ERP One-API.' ); $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, ',', '.'); } }