AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular $this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold } public function Footer() { $pageW = $this->GetPageWidth() - 30; // 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_pengeluaran_barang extends MY_Controller { // -- Properti bersama antar fungsi PDF ------------------------------------- /** @var PengeluaranBarangFpdf */ private $_pdf; private $_pageW; private $_header_data; private $_username; public function __construct() { parent::__construct(); } public function index() { echo "Pengeluaran Barang Report API"; } // ========================================================================= // ENDPOINT: pdf // GET/POST: id (T_ItemOutID), 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 PengeluaranBarangFpdf('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 = 'IO_' . str_replace('/', '-', $header['T_ItemOutNumber']) . '.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 io.*, IFNULL(u.M_UserUsername, '') AS CreatedByName, IFNULL(ur.M_UserUsername, '') AS ReceiveByName, IFNULL(ua.M_UserUsername, '') AS ApprovedByName, wh.WarehouseCode, wh.WarehouseName, wh.WarehouseType, d.DivisionCode, d.DivisionName FROM t_item_out io LEFT JOIN m_user u ON u.M_UserID = io.T_ItemOutUserID LEFT JOIN m_user ur ON ur.M_UserID = io.T_ItemOutReceiveUserID LEFT JOIN m_user ua ON ua.M_UserID = io.T_ItemOutApproveID LEFT JOIN warehouse wh ON wh.WarehouseID = io.T_ItemOutWarehouseID AND wh.WarehouseIsActive = 'Y' LEFT JOIN division d ON d.DivisionID = io.T_ItemOutDivisionID AND d.DivisionIsActive = 'Y' WHERE io.T_ItemOutID = ? AND io.T_ItemOutIsActive = 'Y' LIMIT 1 "; $qry = $this->db->query($sql, array($id)); if (!$qry || $qry->num_rows() === 0) { $this->sys_error("Data Pengeluaran Barang tidak ditemukan"); exit; } return $qry->row_array(); } // ========================================================================= // DATABASE: Ambil data detail // ========================================================================= private function _get_detail($id) { $sql = " SELECT iod.*, i.M_ItemCode, i.M_ItemDesc, iu.ItemUnitName, iu.ItemUnitCode, rod.RequestItemOutDetailQty AS RequestQty, rod.RequestItemOutDetailStatus AS RequestStatus FROM t_item_out_detail iod LEFT JOIN m_item i ON i.M_ItemID = iod.T_ItemOutDetailM_ItemID LEFT JOIN itemunit iu ON iu.ItemUnitID = iod.T_ItemOutDetailItemUnitID LEFT JOIN request_item_out_detail rod ON rod.RequestItemOutDetailID = iod.T_ItemOutDetailRequestItemOutDetailID AND rod.RequestItemOutDetailIsActive = 'Y' WHERE iod.T_ItemOutDetailT_ItemOutID = ? AND iod.T_ItemOutDetailIsActive = 'Y' ORDER BY iod.T_ItemOutDetailID 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, 'PENGELUARAN BARANG (ITEM OUT)', 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 = 30; $valW = $halfW - $lblW - 4; // -- Kolom Kiri -------------------------------------------------------- $pdf->SetY($startY); $leftItems = array( array('Nomor IO', $header['T_ItemOutNumber'], true), array('Tanggal', $this->_fmt_date($header['T_ItemOutDate']), false), array('Status', $header['T_ItemOutStatus'], false), array('Confirm', $header['T_ItemOutIsConfirm'] === 'Y' ? 'Ya' : 'Tidak', false), array('Divisi', $header['DivisionName'] ?: '-', false), array('Gudang', $header['WarehouseName'] ?: '-', 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 field terakhir if (!empty($header['T_ItemOutNote'])) { $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['T_ItemOutNote'], 0, 'L'); } $leftY = $pdf->GetY(); // -- Kolom Kanan ------------------------------------------------------- $pdf->SetY($startY); $rightX = 15 + $halfW; $rightItems = array( array('Dibuat Oleh', $header['CreatedByName'] ?: '-'), array('Dibuat Tgl', $this->_fmt_datetime($header['T_ItemOutCreated'])), array('Penerima', $header['ReceiveByName'] ?: '-'), array('Disetujui Oleh', $header['ApprovedByName'] ?: '-'), array('Tgl Approve', $header['T_ItemOutApproveDate'] ? $this->_fmt_datetime($header['T_ItemOutApproveDate']) : '-'), array('Tgl Dikonfirmasi', $header['T_ItemOutIsConfirmDate'] ? $this->_fmt_datetime($header['T_ItemOutIsConfirmDate']) : '-'), ); 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 // ========================================================================= private function _pdf_data($details) { $pdf = $this->_pdf; $pageW = $this->_pageW; // -- Definisi kolom: [label, lebar, align] ----------------------------- // Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan) // 8 + 72 + 20 + 20 + 30 + 30 = 180 $cols = array( array('No', 8, 'C'), array('Nama Item', 72, 'L'), array('Unit', 20, 'C'), array('Qty', 20, 'R'), array('Batch No.', 30, 'C'), array('Qty Request', 30, 'R'), ); // Header kolom $pdf->SetLineWidth(0.3); $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); $pdf->SetFont('Arial_Narrow', '', 8); $pdf->SetFillColor(255, 255, 255); $no = 1; $total_qty = 0; $total_req = 0; foreach ($details as $d) { $qty = floatval($d['T_ItemOutDetailQty'] ?? 0); $qtyReq = floatval($d['T_ItemOutDetailRequestItemOutDetailID'] > 0 ? $qty : 0); $batchNo = $d['T_ItemOutDetailItemBatchNo'] ?? ''; // Jika batch no berupa JSON array, decode untuk ditampilkan $batchDisplay = $batchNo; if (strpos($batchNo, '[') === 0) { $decoded = json_decode($batchNo, true); if (is_array($decoded) && count($decoded) > 0) { $parts = array(); foreach ($decoded as $b) { $parts[] = isset($b['batchNo']) ? $b['batchNo'] : (isset($b['BatchNo']) ? $b['BatchNo'] : (is_string($b) ? $b : '-')); } $batchDisplay = implode(', ', $parts); } } $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($qty), 1, 0, 'R'); $pdf->Cell($cols[4][1], 6, $batchDisplay, 1, 0, 'C'); $reqQty = isset($d['RequestQty']) ? floatval($d['RequestQty']) : 0; $pdf->Cell($cols[5][1], 6, $reqQty > 0 ? $this->_fmt_qty($reqQty) : '-', 1, 0, 'R'); $pdf->Ln(); $total_qty += $qty; if ($reqQty > 0) { $total_req += $reqQty; } $no++; } // Baris TOTAL $span = array_sum(array_column(array_slice($cols, 0, 4), 1)); $pdf->SetLineWidth(0.3); $pdf->SetFont('Arial_Narrow', 'B', 8); $pdf->SetFillColor(220, 220, 220); $pdf->Cell($span, 7, 'TOTAL', 1, 0, 'R', true); $pdf->Cell($cols[4][1], 7, '', 1, 0, 'C', true); $pdf->Cell($cols[5][1], 7, $this->_fmt_qty($total_qty), 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( 'Barang yang dikeluarkan harus sesuai dengan jumlah dan spesifikasi yang tercantum dalam dokumen ini.', 'Penerima barang wajib memeriksa dan memverifikasi kesesuaian barang sebelum menerima.', 'Dokumen ini merupakan bukti sah pengeluaran barang dari gudang.', 'Dokumen ini bersifat internal dan hanya digunakan untuk keperluan administrasi perusahaan.', ); $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, ',', '.'); } private function _fmt_qty($n) { return number_format(floatval($n), 0, ',', '.'); } private function _fmt_rp($n) { return 'Rp ' . number_format(floatval($n), 2, ',', '.'); } }