Files
be-accone/application/controllers/report/Rpt_request_pengeluaran_barang.php
2026-07-22 08:26:43 +07:00

411 lines
16 KiB
PHP

<?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 RequestPengeluaranBarangFpdf extends FPDF
{
public $printUsername = '-';
public $printDate = '';
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
{
parent::__construct($orientation, $unit, $size);
// Daftarkan Arial Narrow
$this->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_request_pengeluaran_barang extends MY_Controller
{
// -- Properti bersama antar fungsi PDF -------------------------------------
/** @var RequestPengeluaranBarangFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Request Pengeluaran Barang Report API";
}
// =========================================================================
// ENDPOINT: pdf
// GET/POST: id (RequestItemOutID), 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 RequestPengeluaranBarangFpdf('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 = 'RIO_' . str_replace('/', '-', $header['RequestItemOutNumber']) . '.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
rio.*,
wh.WarehouseCode,
wh.WarehouseName,
wh.WarehouseType,
r.S_RegionalName,
d.DivisionCode,
d.DivisionName,
b.M_BranchName AS BranchName,
IFNULL(u.M_UserUsername, '') AS CreatedByName,
IFNULL(um.M_UserUsername, '') AS ManagerByName,
IFNULL(ua.M_UserUsername, '') AS ApprovedByName,
IFNULL(uv.M_UserUsername, '') AS VerifiedByName
FROM request_item_out rio
LEFT JOIN warehouse wh ON wh.WarehouseID = rio.RequestItemOutWarehouseID
AND wh.WarehouseIsActive = 'Y'
LEFT JOIN s_regional r ON r.S_RegionalID = rio.RequestItemOutS_RegionalID
AND r.S_RegionalIsActive = 'Y'
LEFT JOIN m_branch b ON b.M_BranchCode = rio.RequestItemOutM_BranchCode
AND b.M_BranchIsActive = 'Y'
LEFT JOIN division d ON d.DivisionID = rio.RequestItemOutDivisionID
AND d.DivisionIsActive = 'Y'
LEFT JOIN m_user u ON u.M_UserID = rio.RequestItemOutUserID
LEFT JOIN m_user um ON um.M_UserID = rio.RequestItemOutApprovedManagerUserID
LEFT JOIN m_user ua ON ua.M_UserID = rio.RequestItemOutApprovedUserID
LEFT JOIN m_user uv ON uv.M_UserID = rio.RequestItemOutVerifiedUserID
WHERE rio.RequestItemOutID = ?
AND rio.RequestItemOutIsActive = 'Y'
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Request Pengeluaran Barang tidak ditemukan");
exit;
}
return $qry->row_array();
}
// =========================================================================
// DATABASE: Ambil data detail
// =========================================================================
private function _get_detail($id)
{
$sql = "
SELECT
rod.*,
i.M_ItemCode,
i.M_ItemDesc,
iu.ItemUnitName,
iu.ItemUnitCode
FROM request_item_out_detail rod
LEFT JOIN m_item i ON i.M_ItemID = rod.RequestItemOutDetailM_ItemID
LEFT JOIN itemunit iu ON iu.ItemUnitID = rod.RequestItemOutDetailItemUnitID
WHERE rod.RequestItemOutDetailRequestItemOutID = ?
AND rod.RequestItemOutDetailIsActive = 'Y'
ORDER BY rod.RequestItemOutDetailID 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, 'REQUEST PENGELUARAN BARANG', 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 = 32;
$valW = $halfW - $lblW - 4;
// -- Kolom Kiri -----------------------------------------------------------
$pdf->SetY($startY);
$leftItems = array(
array('Nomor Request', $header['RequestItemOutNumber'], true),
array('Tanggal', $this->_fmt_date($header['RequestItemOutDate']), false),
array('Status', $header['RequestItemOutStatus'], false),
array('Divisi', $header['DivisionName'] ?: '-', false),
array('Gudang', $header['WarehouseName'] ?: '-', false),
array('Regional', $header['S_RegionalName'] ?: '-', 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)
if (!empty($header['RequestItemOutNote'])) {
$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['RequestItemOutNote'], 0, 'L');
}
$leftY = $pdf->GetY();
// -- Kolom Kanan ----------------------------------------------------------
$pdf->SetY($startY);
$rightX = 15 + $halfW;
$rightItems = array(
array('Cabang', $header['BranchName'] ?: '-'),
array('Dibuat Oleh', $header['CreatedByName'] ?: '-'),
array('Dibuat Tgl', $this->_fmt_datetime($header['RequestItemOutCreated'])),
array('Approve Manager', $header['ManagerByName'] ?: '-'),
array('Tgl Appr. Manager',$header['RequestItemOutApprovedManagerDate'] ? $this->_fmt_datetime($header['RequestItemOutApprovedManagerDate']) : '-'),
array('Disetujui Oleh', $header['ApprovedByName'] ?: '-'),
array('Tgl Disetujui', $header['RequestItemOutApprovedDate'] ? $this->_fmt_datetime($header['RequestItemOutApprovedDate']) : '-'),
);
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');
}
// Verifikasi (hanya tampil jika ada)
if (!empty($header['RequestItemOutVerifiedDate'])) {
$pdf->SetX($rightX);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, 'Diverifikasi Oleh', 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($valW, 5, $header['VerifiedByName'] ?: '-', 0, 1, 'L');
$pdf->SetX($rightX);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, 'Tgl Verifikasi', 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($valW, 5, $this->_fmt_datetime($header['RequestItemOutVerifiedDate']), 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 + 25 + 25 + 30 = 180
$cols = array(
array('No', 8, 'C'),
array('Nama Item', 72, 'L'),
array('Unit', 20, 'C'),
array('Qty Request', 25, 'R'),
array('Qty Diterima', 25, 'R'),
array('Status', 30, 'C'),
);
// 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_recv = 0;
foreach ($details as $d) {
$qty = floatval($d['RequestItemOutDetailQty'] ?? 0);
$recvQty = floatval($d['RequestItemOutDetailReceiveQty'] ?? 0);
$status = $d['RequestItemOutDetailStatus'] ?? '-';
$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_qty($recvQty), 1, 0, 'R');
$pdf->Cell($cols[5][1], 6, $status, 1, 0, 'C');
$pdf->Ln();
$total_qty += $qty;
$total_recv += $recvQty;
$no++;
}
// Baris TOTAL
$span = array_sum(array_column(array_slice($cols, 0, 3), 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[3][1], 7, $this->_fmt_qty($total_qty), 1, 0, 'R', true);
$pdf->Cell($cols[4][1], 7, $this->_fmt_qty($total_recv), 1, 0, 'R', true);
$pdf->Cell($cols[5][1], 7, '', 1, 0, 'C', true);
$pdf->Ln();
$pdf->Ln(4);
}
// =========================================================================
// PDF SECTION: Syarat & Ketentuan
// =========================================================================
private function _pdf_terms()
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
$terms = array(
'Request ini harus disetujui oleh atasan (manager) sebelum diproses lebih lanjut.',
'Barang yang diminta akan dikeluarkan sesuai dengan jumlah yang telah disetujui.',
'Apabila jumlah barang tidak tersedia, maka akan dilakukan pengeluaran sebagian (partial).',
'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, ',', '.');
}
}