add report receive item po inventaris

This commit is contained in:
Hanan Askarim
2026-07-16 15:40:38 +07:00
committed by sasadib
parent 1f9c56d9a3
commit 49ab9e9e3c

View File

@@ -0,0 +1,438 @@
<?php
defined('BASEPATH') or exit('No direct script access allowed');
require_once(APPPATH . 'libraries/fpdf/fpdf.php');
// =============================================================================
// Custom FPDF: override Footer() agar tampil otomatis di SETIAP halaman
// =============================================================================
class ReceiveItemPoInventarisFpdf extends FPDF
{
public $printUsername = '-';
public $printDate = '';
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
{
parent::__construct($orientation, $unit, $size);
// Daftarkan Arial Narrow — file font ada di fpdf/font/Arial_Narrow.php
$this->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_item_po_inventaris extends MY_Controller
{
// ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var ReceiveItemPoInventarisFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Receive Item PO (Inventaris) Report API";
}
// =========================================================================
// ENDPOINT: pdf
// GET/POST: id (ReceiveOrderPoID), 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 ReceiveItemPoInventarisFpdf('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 = 'RI_PO_INV_' . str_replace('/', '-', $header['ReceiveOrderPoNumber']) . '.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
rop.*,
sup.SupplierName,
sup.SupplierAddress,
sup.SupplierPhone,
b.M_BranchName,
b.M_BranchAddress,
r.S_RegionalName,
wh.WarehouseName AS ReceivedWarehouseName,
ru.M_RuanganName AS RuanganName,
IFNULL(uCr.M_UserUsername, '') AS CreatedByName,
IFNULL(uCf.M_UserUsername, '') AS ConfirmedByName,
IFNULL((
SELECT po.PurchaseOrderShippingCost
FROM receive_order_po_detail d
JOIN purchase_order po ON po.PurchaseOrderID = d.ReceiveOrderPoDetailPurchaseOrderID
WHERE d.ReceiveOrderPoDetailReceiveOrderPoID = rop.ReceiveOrderPoID
AND d.ReceiveOrderPoDetailIsActive = 'Y'
LIMIT 1
), 0) AS PoShippingCostAmount,
IFNULL((
SELECT po.PurchaseOrderShippingCostStatus
FROM receive_order_po_detail d
JOIN purchase_order po ON po.PurchaseOrderID = d.ReceiveOrderPoDetailPurchaseOrderID
WHERE d.ReceiveOrderPoDetailReceiveOrderPoID = rop.ReceiveOrderPoID
AND d.ReceiveOrderPoDetailIsActive = 'Y'
LIMIT 1
), 'N') AS PoShippingCostIsPaid
FROM receive_order_po rop
LEFT JOIN supplier sup ON sup.SupplierID = rop.ReceiveOrderPoSupplierID
LEFT JOIN m_branch b ON b.M_BranchCode = rop.ReceiveOrderPoM_BranchCode
LEFT JOIN s_regional r ON r.S_RegionalID = rop.ReceiveOrderPoS_RegionalID
LEFT JOIN warehouse wh ON wh.WarehouseID = rop.ReceiveOrderPoWarehouseID
LEFT JOIN asset_handover ah ON ah.AssetHandoverReceiveOrderPoID = rop.ReceiveOrderPoID
AND ah.AssetHandoverIsActive = 'Y'
LEFT JOIN m_ruangan ru ON ru.M_RuanganID = ah.AssetHandoverM_RuanganID
LEFT JOIN m_user uCr ON uCr.M_UserID = rop.ReceiveOrderPoCreatedUserID
LEFT JOIN m_user uCf ON uCf.M_UserID = rop.ReceiveOrderPoConfirmedUserID
WHERE rop.ReceiveOrderPoIsActive = 'Y'
AND rop.ReceiveOrderPoID = ?
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Penerimaan PO tidak ditemukan");
exit;
}
return $qry->row_array();
}
// =========================================================================
// DATABASE: Ambil data detail
// =========================================================================
private function _get_detail($id)
{
$sql = "
SELECT
ropd.*,
item.M_ItemCode,
item.M_ItemDesc,
iu.ItemUnitName,
iu.ItemUnitCode,
po.PurchaseOrderNumber
FROM receive_order_po_detail ropd
JOIN m_item item ON item.M_ItemID = ropd.ReceiveOrderPoItemID
AND item.M_ItemIsActive = 'Y'
LEFT JOIN itemunit iu ON iu.ItemUnitID = ropd.ReceiveOrderPoItemUnitID
AND iu.ItemUnitIsActive = 'Y'
LEFT JOIN purchase_order po ON po.PurchaseOrderID = ropd.ReceiveOrderPoDetailPurchaseOrderID
WHERE ropd.ReceiveOrderPoDetailIsActive = 'Y'
AND ropd.ReceiveOrderPoDetailReceiveOrderPoID = ?
ORDER BY ropd.ReceiveOrderPoDetailID 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 BARANG PO INVENTARIS (RECEIVE PO)', 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['ReceiveOrderPoNumber'], true),
array('Tanggal', $this->_fmt_date($header['ReceiveOrderPoIDate']), false),
array('No. Referensi', $header['ReceiveOrderPoRefNumber'] ?: '-', false),
array('No. Surat Jalan', $header['ReceiveOrderPoDONumber'] ?: '-', false),
array('Gudang Penerima', $header['ReceivedWarehouseName'] ?: '-', false),
array('Ruangan / Lokasi', $header['RuanganName'] ?: '-', 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 Ruangan (tanpa spasi vertikal)
if (!empty($header['ReceiveOrderPoNote'])) {
$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['ReceiveOrderPoNote'], 0, 'L');
}
$leftY = $pdf->GetY();
// ── Kolom Kanan ───────────────────────────────────────────────────────
$pdf->SetY($startY);
$rightX = 15 + $halfW;
$rightItems = array(
array('Supplier', $header['SupplierName'] ?: '-'),
array('Alamat Supplier', $header['SupplierAddress'] ?: '-'),
array('Telp Supplier', $header['SupplierPhone'] ?: '-'),
array('Alamat Penerima', $header['M_BranchAddress'] ?: '-'),
);
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 Supplier' || $item[0] === 'Alamat Penerima') {
$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 + 45 + 38 + 20 + 15 + 24 + 30 = 180
$cols = array(
array('No', 8, 'C'),
array('Nama', 45, 'L'),
array('No. PO', 38, 'L'),
array('Unit', 20, 'C'),
array('Qty', 15, 'R'),
array('Harga', 24, 'R'),
array('Total', 30, '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;
$grand_tot = 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['PurchaseOrderNumber'] ?: '-', 1, 0, 'L');
$pdf->Cell($cols[3][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C');
$pdf->Cell($cols[4][1], 6, $this->_fmt_qty($d['ReceiveOrderPoDetailQty']), 1, 0, 'C');
$pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailPrice']), 1, 0, 'R');
$pdf->Cell($cols[6][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailTotal']), 1, 0, 'R');
$pdf->Ln();
$grand_tot += floatval($d['ReceiveOrderPoDetailTotal']);
$no++;
}
// Baris TOTAL
$span = array_sum(array_column(array_slice($cols, 0, 6), 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[6][1], 7, $this->_fmt_rp($grand_tot), 1, 0, 'R', true);
$pdf->Ln(6);
// Ringkasan Biaya jika ada Biaya Ekspedisi (mendukung fallback dari PO)
$shippingCost = floatval($header['ReceiveOrderShippingCostAmount'] ?? 0);
$isPaid = $header['ReceiveOrderShippingCostIsPaid'] ?? 'N';
if ($shippingCost <= 0) {
$shippingCost = floatval($header['PoShippingCostAmount'] ?? 0);
$isPaid = $header['PoShippingCostIsPaid'] ?? 'N';
}
if ($shippingCost > 0) {
$pdf->Ln(2);
$grandTotal = $grand_tot + $shippingCost;
$statusPaid = ($isPaid === 'Y') ? ' (Lunas)' : ' (Belum Lunas)';
$summary = array(
array('Total Item', $this->_fmt_rp($grand_tot)),
array('Biaya Ekspedisi' . $statusPaid, $this->_fmt_rp($shippingCost)),
array('Grand Total', $this->_fmt_rp($grandTotal)),
);
$cW1 = 39;
$cW2 = 30;
$offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 4), 1));
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(8);
}
// =========================================================================
// PDF SECTION: Syarat & Ketentuan
// =========================================================================
private function _pdf_terms()
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
$terms = array(
'Barang inventaris/aset yang diterima telah dicocokkan dengan fisik barang dan Purchase Order asli.',
'Penempatan barang inventaris/aset disesuaikan dengan Ruangan/Lokasi yang tertera di dokumen ini.',
'Penerimaan barang inventaris/aset ini akan otomatis didaftarkan ke sistem manajemen aset perusahaan.',
'Dokumen ini dicetak secara otomatis dan sah sebagai bukti penerimaan barang masuk.'
);
$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, ',', '.');
}
}