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_penerimaan_mutasi extends MY_Controller { // ── Properti bersama antar fungsi PDF ───────────────────────────────────── /** @var MutasiPenerimaanFpdf */ private $_pdf; private $_pageW; private $_header_data; private $_username; public function __construct() { parent::__construct(); } public function index() { echo "Mutasi Penerimaan (Receive Mutasi) Report API"; } // ========================================================================= // ENDPOINT: pdf // GET/POST: id (MutasiHandoverID), 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: hanya dokumen berstatus Received yang bisa dicetak if ($header['MutasiHandoverStatus'] !== 'Received') { $this->sys_error("Dokumen belum diterima (Status: " . $header['MutasiHandoverStatus'] . ")"); exit; } $details = $this->_get_detail($id); // ── Inisialisasi FPDF custom ────────────────────────────────────── $this->_pdf = new MutasiPenerimaanFpdf('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 = 'PM_' . str_replace('/', '-', $header['MutasiHandoverNumber']) . '.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 mh.*, mr.MutasiRequestNumber, ic.itemCategoryID, ic.itemCategoryName, a.M_BranchID AS branch_asal_id, a.M_BranchCode AS branch_asal_code, a.M_BranchName AS branch_asal_name, b.M_BranchID AS branch_tujuan_id, b.M_BranchCode AS branch_tujuan_code, b.M_BranchName AS branch_tujuan_name, IFNULL(u.M_UserUsername, '') AS CreatedByName, IFNULL(ur.M_UserUsername, '') AS ReceiveByName, CASE WHEN wh.WarehouseType = 'B' THEN CONCAT(wh.WarehouseCode, ' ', wh.WarehouseName, ' - ', b.M_BranchName) ELSE wh.WarehouseName END AS WarehouseName, r.M_RuanganName FROM mutasi_handover mh LEFT JOIN mutasi_request mr ON mr.MutasiRequestID = mh.MutasiHandoverMutasiRequestID JOIN item_category ic ON ic.itemCategoryID = mh.MutasiHandoverItemCategoryID AND ic.itemCategoryIsActive = 'Y' JOIN m_branch a ON a.M_BranchID = mh.MutasiHandoverFromBranchID AND a.M_BranchIsActive = 'Y' JOIN m_branch b ON b.M_BranchID = mh.MutasiHandoverToBranchID AND b.M_BranchIsActive = 'Y' LEFT JOIN m_user u ON u.M_UserID = mh.MutasiHandoverUserID LEFT JOIN m_user ur ON ur.M_UserID = mh.MutasiHandoverReceiveUserID LEFT JOIN warehouse wh ON wh.WarehouseID = mh.MutasiHandoverReceiveWarehouseID AND wh.WarehouseIsActive = 'Y' LEFT JOIN m_ruangan r ON r.M_RuanganID = mh.MutasiHandoverReceiveM_RuanganID AND r.M_RuanganIsActive = 'Y' WHERE mh.MutasiHandoverID = ? AND mh.MutasiHandoverIsActive = 'Y' LIMIT 1 "; $qry = $this->db->query($sql, array($id)); if (!$qry || $qry->num_rows() === 0) { $this->sys_error("Data Penerimaan Mutasi tidak ditemukan"); exit; } return $qry->row_array(); } // ========================================================================= // DATABASE: Ambil data detail // ========================================================================= private function _get_detail($id) { $sql = " SELECT mhd.*, i.M_ItemCode, i.M_ItemDesc, iu.ItemUnitName, iu.ItemUnitCode, st.StockStockNumber AS StockToNumber, sf.StockStockNumber AS StockFromNumber FROM mutasi_handover_detail mhd LEFT JOIN m_item i ON i.M_ItemID = mhd.MutasiHandoverDetailM_ItemID LEFT JOIN itemunit iu ON iu.ItemUnitID = mhd.MutasiHandoverDetailItemUnitID LEFT JOIN stock sf ON sf.StockID = mhd.MutasiHandoverDetailStockID_From LEFT JOIN stock st ON st.StockID = mhd.MutasiHandoverDetailStockID_To WHERE mhd.MutasiHandoverDetailMutasiHandoverID = ? AND mhd.MutasiHandoverDetailIsActive = 'Y' ORDER BY mhd.MutasiHandoverDetailID 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, 'PENERIMAAN MUTASI', 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 Handover', $header['MutasiHandoverNumber'], true), array('No. Request', $header['MutasiRequestNumber'] ?: '-', false), array('Tgl Kirim', $this->_fmt_date($header['MutasiHandoverDate']), false), array('Tgl Terima', $this->_fmt_date($header['MutasiHandoverReceiveDate']), false), array('Status', $header['MutasiHandoverStatus'], false), array('Kategori', $header['itemCategoryName'], 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 Kategori if (!empty($header['MutasiHandoverNote'])) { $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['MutasiHandoverNote'], 0, 'L'); } $leftY = $pdf->GetY(); // ── Kolom Kanan ─────────────────────────────────────────────────────── $pdf->SetY($startY); $rightX = 15 + $halfW; $rightItems = array( array('Cabang Asal', $header['branch_asal_name']), array('Cabang Tujuan', $header['branch_tujuan_name']), array('Warehouse Tujuan', $header['WarehouseName'] ?: '-'), array('Ruangan Tujuan', $header['M_RuanganName'] ?: '-'), array('Diterima Oleh', $header['MutasiHandoverStatus'] === 'Received' ? $header['ReceiveByName'] : '-'), array('Dibuat Oleh', $header['CreatedByName']), ); 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 + 72 + 15 + 15 + 22 + 22 + 26 = 180 $cols = array( array('No', 8, 'C'), array('Nama Item', 72, 'L'), array('Unit', 15, 'C'), array('Qty', 15, 'R'), array('Nilai Buku', 22, 'R'), array('Total', 22, 'R'), array('Stock Tujuan', 26, 'C'), ); // Header kolom $pdf->SetLineWidth(0.3); $pdf->SetFont('Arial_Narrow', 'B', 7); $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', '', 7.5); $pdf->SetFillColor(255, 255, 255); $no = 1; $total_val = 0; foreach ($details as $d) { $bookValue = floatval($d['MutasiHandoverDetailBookValue'] ?? 0); $qty = floatval($d['MutasiHandoverDetailQty'] ?? 0); $lineTotal = $qty * $bookValue; $stockTo = $d['StockToNumber'] ?: '-'; $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, $this->_fmt_rp($bookValue), 1, 0, 'R'); $pdf->Cell($cols[5][1], 6, $this->_fmt_rp($lineTotal), 1, 0, 'R'); $pdf->Cell($cols[6][1], 6, $stockTo, 1, 0, 'C'); $pdf->Ln(); $total_val += $lineTotal; $no++; } // Baris TOTAL $span = array_sum(array_column(array_slice($cols, 0, 6), 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[6][1], 7, '', 1, 0, 'C', true); $pdf->Ln(); // ── Ringkasan nilai (rata kanan) ────────────────────────────────────── $pdf->Ln(3); $summary = array( array('Total Nilai Penerimaan', $this->_fmt_rp($header['MutasiHandoverTotalValue'])), ); $cW1 = 50; $cW2 = 40; $offsetX = 15 + $this->_pageW - $cW1 - $cW2; foreach ($summary as $s) { $pdf->SetX($offsetX); $pdf->SetFont('Arial_Narrow', '', 8); $pdf->Cell($cW1, 5, $s[0], 0, 0, 'L'); $pdf->SetFont('Arial_Narrow', 'B', 8); $pdf->Cell($cW2, 5, $s[1], 0, 1, 'R'); } $pdf->Ln(4); } // ========================================================================= // PDF SECTION: Syarat & Ketentuan // ========================================================================= private function _pdf_terms() { $pdf = $this->_pdf; $pageW = $this->_pageW; $terms = array( 'Penerimaan mutasi ini dilakukan berdasarkan dokumen handover (penyerahan) yang telah dikirim oleh cabang asal.', 'Penerima wajib memeriksa kesesuaian jumlah, jenis, dan kondisi barang dengan dokumen handover.', 'Setelah diterima, barang menjadi tanggung jawab cabang tujuan dan akan dicatat dalam stok tujuan.', 'Dokumen ini bersifat internal dan hanya digunakan untuk keperluan proses mutasi barang.', ); $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, ',', '.'); } }