532 lines
19 KiB
PHP
532 lines
19 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 PemakaianItemDivisiFpdf 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_pemakaian_item_divisi extends MY_Controller
|
||
{
|
||
// -- Properti bersama antar fungsi PDF -------------------------------------
|
||
/** @var PemakaianItemDivisiFpdf */
|
||
private $_pdf;
|
||
private $_pageW;
|
||
private $_start_date;
|
||
private $_end_date;
|
||
private $_division_id;
|
||
private $_division_name;
|
||
private $_username;
|
||
|
||
public function __construct()
|
||
{
|
||
parent::__construct();
|
||
}
|
||
|
||
public function index()
|
||
{
|
||
echo "Pemakaian Item per Divisi Report API";
|
||
}
|
||
|
||
// =========================================================================
|
||
// ENDPOINT: pdf
|
||
// GET/POST: start_date, end_date, division_id (opsional), username (opsional)
|
||
// =========================================================================
|
||
public function pdf()
|
||
{
|
||
try {
|
||
$start_date = trim($this->input->get_post('start_date') ?? '');
|
||
$end_date = trim($this->input->get_post('end_date') ?? '');
|
||
$division_id = intval($this->input->get_post('division_id'));
|
||
$username = trim($this->input->get_post('username') ?? '');
|
||
|
||
if ($start_date === '' || $end_date === '') {
|
||
$this->sys_error("Periode tanggal harus diisi");
|
||
exit;
|
||
}
|
||
|
||
// -- Ambil data dari DB --------------------------------------------
|
||
$data = $this->_get_data($start_date, $end_date, $division_id);
|
||
if (empty($data)) {
|
||
$this->sys_error("Tidak ada data pemakaian item pada periode tersebut");
|
||
exit;
|
||
}
|
||
|
||
$this->_start_date = $start_date;
|
||
$this->_end_date = $end_date;
|
||
$this->_division_id = $division_id;
|
||
|
||
// Ambil nama divisi jika dipilih
|
||
if ($division_id > 0) {
|
||
$div = $this->_get_division($division_id);
|
||
$this->_division_name = $div ? $div['DivisionName'] : '';
|
||
} else {
|
||
$this->_division_name = 'Semua Divisi';
|
||
}
|
||
|
||
// -- Inisialisasi FPDF custom --------------------------------------
|
||
$this->_pdf = new PemakaianItemDivisiFpdf('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->_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($data);
|
||
$this->_pdf_terms();
|
||
|
||
// -- Output --------------------------------------------------------
|
||
$filename = 'PID_' . date('Ymd') . '.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 divisi
|
||
// =========================================================================
|
||
private function _get_division($id)
|
||
{
|
||
$sql = "
|
||
SELECT DivisionID, DivisionCode, DivisionName
|
||
FROM division
|
||
WHERE DivisionID = ?
|
||
AND DivisionIsActive = 'Y'
|
||
LIMIT 1
|
||
";
|
||
$qry = $this->db->query($sql, array($id));
|
||
return $qry && $qry->num_rows() > 0 ? $qry->row_array() : null;
|
||
}
|
||
|
||
// =========================================================================
|
||
// DATABASE: Ambil data pemakaian item per divisi
|
||
// =========================================================================
|
||
private function _get_data($start_date, $end_date, $division_id = 0)
|
||
{
|
||
$sql_where = "
|
||
WHERE iu.ItemUsedIsActive = 'Y'
|
||
AND iu.ItemUsedIsConfirm = 'Y'
|
||
AND iu.ItemUsedDate BETWEEN ? AND ?
|
||
";
|
||
$params = array($start_date, $end_date);
|
||
|
||
if ($division_id > 0) {
|
||
// Filter by division melalui item_usage
|
||
$sql_where .= " AND iu.ItemUsedItemUsageID IN (
|
||
SELECT ItemUsageID FROM item_usage
|
||
WHERE ItemUsageDivisionID = ?
|
||
AND ItemUsageIsActive = 'Y'
|
||
)";
|
||
$params[] = $division_id;
|
||
}
|
||
|
||
$sql = "
|
||
SELECT
|
||
d.DivisionID,
|
||
d.DivisionCode,
|
||
d.DivisionName,
|
||
iu.ItemUsedID,
|
||
iu.ItemUsedDate,
|
||
iu.ItemUsedNumber,
|
||
iu.ItemUsedBatchNo,
|
||
iu.ItemUsedQty,
|
||
iu.ItemUsedPrice,
|
||
iu.ItemUsedTotal,
|
||
item.M_ItemID,
|
||
item.M_ItemCode,
|
||
item.M_ItemDesc,
|
||
iunit.ItemUnitName,
|
||
iunit.ItemUnitCode,
|
||
us.ItemUsageID,
|
||
us.ItemUsageDivisionID
|
||
FROM item_used iu
|
||
JOIN item_usage us ON us.ItemUsageID = iu.ItemUsedItemUsageID
|
||
AND us.ItemUsageIsActive = 'Y'
|
||
JOIN division d ON d.DivisionID = us.ItemUsageDivisionID
|
||
AND d.DivisionIsActive = 'Y'
|
||
JOIN m_item item ON item.M_ItemID = iu.ItemUsedM_ItemID
|
||
AND item.M_ItemIsActive = 'Y'
|
||
JOIN itemunit iunit ON iunit.ItemUnitID = iu.ItemUsedItemUnitID
|
||
AND iunit.ItemUnitIsActive = 'Y'
|
||
$sql_where
|
||
ORDER BY d.DivisionCode ASC, d.DivisionName ASC, iu.ItemUsedDate ASC, iu.ItemUsedNumber ASC
|
||
";
|
||
$qry = $this->db->query($sql, $params);
|
||
return $qry ? $qry->result_array() : array();
|
||
}
|
||
|
||
// =========================================================================
|
||
// PDF SECTION: Header — Judul + Informasi Laporan
|
||
// =========================================================================
|
||
private function _pdf_header()
|
||
{
|
||
$pdf = $this->_pdf;
|
||
$pageW = $this->_pageW;
|
||
|
||
// -- Judul utama -------------------------------------------------------
|
||
$pdf->SetFont('Arial_Narrow', 'B', 14);
|
||
$pdf->Cell($pageW, 8, 'LAPORAN PEMAKAIAN ITEM PER DIVISI', 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('Periode Awal', $this->_fmt_date($this->_start_date), false),
|
||
array('Periode Akhir', $this->_fmt_date($this->_end_date), false),
|
||
array('Divisi', $this->_division_name, true),
|
||
);
|
||
|
||
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');
|
||
}
|
||
$leftY = $pdf->GetY();
|
||
|
||
// -- Kolom Kanan -------------------------------------------------------
|
||
$pdf->SetY($startY);
|
||
$rightX = 15 + $halfW;
|
||
|
||
$rightItems = array(
|
||
array('Print Oleh', $this->_username),
|
||
array('Tgl Print', $this->_pdf->printDate),
|
||
);
|
||
|
||
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 pemakaian item per divisi
|
||
// =========================================================================
|
||
private function _pdf_data($data)
|
||
{
|
||
$pdf = $this->_pdf;
|
||
$pageW = $this->_pageW;
|
||
|
||
// -- Definisi kolom: [label, lebar, align] -----------------------------
|
||
// Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan)
|
||
// 8 + 8 + 68 + 15 + 15 + 22 + 22 + 22 = 180
|
||
$cols = array(
|
||
array('No', 6, 'C'),
|
||
array('Tgl', 16, 'C'),
|
||
array('Nama Item', 62, 'L'),
|
||
array('Batch No', 24, 'C'),
|
||
array('Unit', 14, 'C'),
|
||
array('Qty', 10, 'R'),
|
||
array('Harga', 18, 'R'),
|
||
array('Total', 30, 'R'),
|
||
);
|
||
|
||
$no = 1;
|
||
$prevDivID = null;
|
||
$divTotalQty = 0;
|
||
$divTotalVal = 0;
|
||
$grandTotalQty = 0;
|
||
$grandTotalVal = 0;
|
||
|
||
// Simpan posisi awal Y untuk setiap divisi — dipakai untuk bounding box
|
||
$divStartY = 0;
|
||
|
||
foreach ($data as $d) {
|
||
$divID = $d['DivisionID'];
|
||
|
||
// -- Jika berganti divisi, cetak subtotal divisi sebelumnya ----------
|
||
if ($prevDivID !== null && $divID !== $prevDivID) {
|
||
$this->_pdf_divisi_subtotal($divTotalQty, $divTotalVal);
|
||
$grandTotalQty += $divTotalQty;
|
||
$grandTotalVal += $divTotalVal;
|
||
$divTotalQty = 0;
|
||
$divTotalVal = 0;
|
||
}
|
||
|
||
// -- Jika divisi baru, cetak header nama divisi ---------------------
|
||
if ($prevDivID === null || $divID !== $prevDivID) {
|
||
// Cek sisa ruang: butuh minimal 8+7+6*n+8 ˜ 40mm untuk header+1 baris+subtotal
|
||
if ($pdf->GetY() > 230) {
|
||
$pdf->AddPage();
|
||
}
|
||
|
||
$divStartY = $pdf->GetY();
|
||
|
||
// Nama Divisi
|
||
$pdf->SetFillColor(50, 80, 130);
|
||
$pdf->SetTextColor(255, 255, 255);
|
||
$pdf->SetFont('Arial_Narrow', 'B', 10);
|
||
$pdf->Cell($pageW, 7, ' ' . $d['DivisionName'] . ' (' . $d['DivisionCode'] . ')', 1, 1, 'L', true);
|
||
$pdf->SetTextColor(0, 0, 0);
|
||
|
||
// 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], 6, $c[0], 1, 0, 'C', true);
|
||
}
|
||
$pdf->Ln();
|
||
|
||
$no = 1;
|
||
}
|
||
|
||
// -- Cek apakah perlu halaman baru (min 12mm untuk 1 baris + subtotal) -
|
||
if ($pdf->GetY() > 258) {
|
||
$pdf->AddPage();
|
||
// Ulang header kolom di halaman baru
|
||
$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], 6, $c[0], 1, 0, 'C', true);
|
||
}
|
||
$pdf->Ln();
|
||
}
|
||
|
||
// -- Baris data item -----------------------------------------------
|
||
$pdf->SetLineWidth(0.2);
|
||
$pdf->SetFont('Arial_Narrow', '', 7.5);
|
||
$pdf->SetFillColor(255, 255, 255);
|
||
|
||
$itemDesc = $d['M_ItemDesc'] ?: ($d['M_ItemCode'] ?: '-');
|
||
$batchNo = $d['ItemUsedBatchNo'] ?: '-';
|
||
$qty = floatval($d['ItemUsedQty']);
|
||
$price = floatval($d['ItemUsedPrice']);
|
||
$total = floatval($d['ItemUsedTotal']);
|
||
|
||
// Simpan posisi Y sebelum cell untuk wrap detection
|
||
$beforeY = $pdf->GetY();
|
||
|
||
$pdf->Cell($cols[0][1], 5, $no, 1, 0, 'C');
|
||
$pdf->Cell($cols[1][1], 5, $this->_fmt_date($d['ItemUsedDate']), 1, 0, 'C');
|
||
$pdf->Cell($cols[2][1], 5, $itemDesc, 1, 0, 'L');
|
||
$pdf->Cell($cols[3][1], 5, $batchNo, 1, 0, 'C');
|
||
$pdf->Cell($cols[4][1], 5, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C');
|
||
$pdf->Cell($cols[5][1], 5, $this->_fmt_qty($qty), 1, 0, 'R');
|
||
$pdf->Cell($cols[6][1], 5, $this->_fmt_rp($price), 1, 0, 'R');
|
||
$pdf->Cell($cols[7][1], 5, $this->_fmt_rp($total), 1, 0, 'R');
|
||
$pdf->Ln();
|
||
|
||
$divTotalQty += $qty;
|
||
$divTotalVal += $total;
|
||
$prevDivID = $divID;
|
||
$no++;
|
||
}
|
||
|
||
// -- Subtotal divisi terakhir -----------------------------------------
|
||
if ($prevDivID !== null) {
|
||
$this->_pdf_divisi_subtotal($divTotalQty, $divTotalVal);
|
||
$grandTotalQty += $divTotalQty;
|
||
$grandTotalVal += $divTotalVal;
|
||
}
|
||
|
||
// -- Grand Total ------------------------------------------------------
|
||
$pdf->Ln(3);
|
||
|
||
// Cek ruang untuk grand total
|
||
if ($pdf->GetY() > 270) {
|
||
$pdf->AddPage();
|
||
}
|
||
|
||
$pdf->SetLineWidth(0.4);
|
||
$pdf->SetFont('Arial_Narrow', 'B', 10);
|
||
$pdf->SetFillColor(180, 200, 220);
|
||
$pdf->SetDrawColor(0, 0, 0);
|
||
|
||
$spanSum = array_sum(array_column(array_slice($cols, 0, 5), 1));
|
||
$pdf->Cell($spanSum, 7, 'GRAND TOTAL', 1, 0, 'R', true);
|
||
$pdf->Cell($cols[5][1], 7, $this->_fmt_qty($grandTotalQty), 1, 0, 'R', true);
|
||
$pdf->Cell($cols[6][1], 7, '', 1, 0, 'R', true);
|
||
$pdf->Cell($cols[7][1], 7, $this->_fmt_rp($grandTotalVal), 1, 0, 'R', true);
|
||
$pdf->Ln();
|
||
|
||
$pdf->Ln(4);
|
||
|
||
// -- Ringkasan Akhir --------------------------------------------------
|
||
$summaryX = 15 + $pageW - 90;
|
||
$cW1 = 50;
|
||
$cW2 = 40;
|
||
|
||
$pdf->SetFont('Arial_Narrow', '', 9);
|
||
$pdf->SetX($summaryX);
|
||
$pdf->Cell($cW1, 5, 'Total Item Digunakan', 0, 0, 'L');
|
||
$pdf->SetFont('Arial_Narrow', 'B', 9);
|
||
$pdf->Cell($cW2, 5, $this->_fmt_qty($grandTotalQty) . ' ' . 'pcs', 0, 1, 'R');
|
||
|
||
$pdf->SetFont('Arial_Narrow', '', 9);
|
||
$pdf->SetX($summaryX);
|
||
$pdf->Cell($cW1, 5, 'Total Nilai Pemakaian', 0, 0, 'L');
|
||
$pdf->SetFont('Arial_Narrow', 'B', 9);
|
||
$pdf->Cell($cW2, 5, $this->_fmt_rp($grandTotalVal), 0, 1, 'R');
|
||
|
||
$pdf->Ln(4);
|
||
}
|
||
|
||
// =========================================================================
|
||
// PDF SUB-SECTION: Subtotal per Divisi
|
||
// =========================================================================
|
||
private function _pdf_divisi_subtotal($qty, $val)
|
||
{
|
||
$pdf = $this->_pdf;
|
||
$pageW = $this->_pageW;
|
||
// Gunakan lebar kolom yang sama persis dengan _pdf_data()
|
||
$cols = array(
|
||
array('No', 6, 'C'),
|
||
array('Tgl', 16, 'C'),
|
||
array('Nama Item', 62, 'L'),
|
||
array('Batch No', 24, 'C'),
|
||
array('Unit', 14, 'C'),
|
||
array('Qty', 10, 'R'),
|
||
array('Harga', 18, 'R'),
|
||
array('Total', 30, 'R'),
|
||
);
|
||
|
||
if ($pdf->GetY() > 270) {
|
||
$pdf->AddPage();
|
||
}
|
||
|
||
$spanSum = array_sum(array_column(array_slice($cols, 0, 5), 1));
|
||
$pdf->SetLineWidth(0.3);
|
||
$pdf->SetFont('Arial_Narrow', 'B', 8);
|
||
$pdf->SetFillColor(235, 240, 248);
|
||
$pdf->SetDrawColor(0, 0, 0);
|
||
$pdf->Cell($spanSum, 6, 'Sub Total', 1, 0, 'R', true);
|
||
$pdf->Cell($cols[5][1], 6, $this->_fmt_qty($qty), 1, 0, 'R', true);
|
||
$pdf->Cell($cols[6][1], 6, '', 1, 0, 'R', true);
|
||
$pdf->Cell($cols[7][1], 6, $this->_fmt_rp($val), 1, 0, 'R', true);
|
||
$pdf->Ln();
|
||
$pdf->Ln(2);
|
||
}
|
||
|
||
// =========================================================================
|
||
// PDF SECTION: Syarat & Ketentuan
|
||
// =========================================================================
|
||
private function _pdf_terms()
|
||
{
|
||
$pdf = $this->_pdf;
|
||
$pageW = $this->_pageW;
|
||
|
||
$terms = array(
|
||
'Laporan ini menampilkan seluruh pemakaian item yang telah dikonfirmasi pada periode yang dipilih.',
|
||
'Data pemakaian dikelompokkan berdasarkan divisi yang melakukan pemakaian.',
|
||
'Harga yang ditampilkan adalah harga rata-rata pada saat pemakaian item.',
|
||
'Dokumen ini bersifat internal dan hanya digunakan untuk keperluan monitoring pemakaian item.',
|
||
);
|
||
|
||
$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, ',', '.');
|
||
}
|
||
}
|