add report po asset
This commit is contained in:
464
application/controllers/report/Rpt_purchase_order_asset.php
Normal file
464
application/controllers/report/Rpt_purchase_order_asset.php
Normal file
@@ -0,0 +1,464 @@
|
||||
<?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 PurchaseOrderAssetFpdf 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_purchase_order_asset extends MY_Controller
|
||||
{
|
||||
// ── Properti bersama antar fungsi PDF ─────────────────────────────────────
|
||||
/** @var PurchaseOrderAssetFpdf */
|
||||
private $_pdf;
|
||||
private $_pageW;
|
||||
private $_header_data;
|
||||
private $_username;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
echo "Purchase Order Asset Report API";
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// ENDPOINT: pdf
|
||||
// GET/POST: id (PurchaseOrderID), 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 PurchaseOrderAssetFpdf('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 = 'PO_ASSET_' . str_replace('/', '-', $header['PurchaseOrderNumber']) . '.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
|
||||
po.*,
|
||||
sup.SupplierName,
|
||||
sup.SupplierAddress,
|
||||
sup.SupplierPhone,
|
||||
b.M_BranchName,
|
||||
b.M_BranchAddress,
|
||||
r.S_RegionalName,
|
||||
ac.PurchaseOrderAssetContractName AS ContractName,
|
||||
ac.PurchaseOrderAssetContractDate AS ContractDate,
|
||||
ac.PurchaseOrderAssetContractStartDate AS ContractStart,
|
||||
ac.PurchaseOrderAssetContractEndDate AS ContractEnd,
|
||||
ac.PurchaseOrderAssetContractDuration AS ContractDuration,
|
||||
ac.PurchaseOrderAssetContractInstallmentNumber AS InstallmentNumber,
|
||||
ac.PurchaseOrderAssetContractInstallmentPayAmount AS InstallmentPayAmount,
|
||||
ac.PurchaseOrderAssetContractInstallmentDownPayment AS InstallmentDownPayment,
|
||||
ac.PurchaseOrderAssetContractInstallmentDownPaymentType AS InstallmentDownPaymentType,
|
||||
ac.PurchaseOrderAssetContractStatus AS ContractStatus
|
||||
FROM purchase_order po
|
||||
LEFT JOIN supplier sup ON sup.SupplierID = po.PurchaseOrderSupplierID
|
||||
LEFT JOIN s_regional r ON r.S_RegionalID = po.PurchaseOrderS_RegionalID
|
||||
LEFT JOIN purchase_order_asset_contract ac ON ac.PurchaseOrderAssetContractPurchaseOrderID = po.PurchaseOrderID
|
||||
AND ac.PurchaseOrderAssetContractIsActive = 'Y'
|
||||
LEFT JOIN m_branch b ON b.M_BranchID = (
|
||||
-- Cabang pengirim/tujuan diambil dari detail pertama
|
||||
SELECT pod.PurchaseOrderDetailWarehouseID
|
||||
FROM purchase_order_detail pod
|
||||
WHERE pod.PurchaseOrderDetailPurchaseOrderID = po.PurchaseOrderID
|
||||
AND pod.PurchaseOrderDetailIsActive = 'Y'
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE po.PurchaseOrderIsActive = 'Y'
|
||||
AND po.PurchaseOrderID = ?
|
||||
LIMIT 1
|
||||
";
|
||||
$qry = $this->db->query($sql, array($id));
|
||||
if (!$qry || $qry->num_rows() === 0) {
|
||||
$this->sys_error("Data Purchase Order tidak ditemukan");
|
||||
exit;
|
||||
}
|
||||
return $qry->row_array();
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// DATABASE: Ambil data detail (menggunakan summary agar teragregasi)
|
||||
// =========================================================================
|
||||
private function _get_detail($id)
|
||||
{
|
||||
$sql = "
|
||||
SELECT
|
||||
pos.PurchaseOrderSummaryQty AS RequestQty,
|
||||
pos.PurchaseOrderSummaryPrice AS SupplierPrice,
|
||||
pos.PurchaseOrderSummaryDiscountAmount AS DiskonAmount,
|
||||
pos.PurchaseOrderSummaryTotal AS TempTotal,
|
||||
item.M_ItemCode,
|
||||
item.M_ItemDesc,
|
||||
iu.ItemUnitName,
|
||||
iu.ItemUnitCode
|
||||
FROM purchase_order_summary pos
|
||||
JOIN m_item item ON item.M_ItemID = pos.PurchaseOrderSummaryItemID
|
||||
AND item.M_ItemIsActive = 'Y'
|
||||
LEFT JOIN itemunit iu ON iu.ItemUnitID = pos.PurchaseOrderSummaryItemUnitID
|
||||
AND iu.ItemUnitIsActive = 'Y'
|
||||
WHERE pos.PurchaseOrderSummaryIsActive = 'Y'
|
||||
AND pos.PurchaseOrderSummaryPurchaseOrderID = ?
|
||||
ORDER BY pos.PurchaseOrderSummaryID 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, 'PURCHASE ORDER ASET (KONTRAK / CICILAN)', 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);
|
||||
|
||||
// Periode kontrak
|
||||
$periodeKontrak = '-';
|
||||
if (!empty($header['ContractStart']) && $header['ContractStart'] !== '0000-00-00') {
|
||||
$periodeKontrak = $this->_fmt_date($header['ContractStart']) . ' s/d ' . $this->_fmt_date($header['ContractEnd']);
|
||||
if (intval($header['ContractDuration']) > 0) {
|
||||
$periodeKontrak .= ' (' . $header['ContractDuration'] . ' Bln)';
|
||||
}
|
||||
}
|
||||
|
||||
$leftItems = array(
|
||||
array('Nomor PO', $header['PurchaseOrderNumber'], true),
|
||||
array('Tanggal PO', $this->_fmt_date($header['PurchaseOrderDate']), false),
|
||||
array('No. Referensi', $header['PurchaseOrderRefNumber'] ?: '-', false),
|
||||
array('Nama Kontrak', $header['ContractName'] ?: '-', false),
|
||||
array('Tanggal Kontrak', $this->_fmt_date($header['ContractDate']), false),
|
||||
array('Periode Kontrak', $periodeKontrak, 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 Status (tanpa spasi vertikal)
|
||||
if (!empty($header['PurchaseOrderNote'])) {
|
||||
$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['PurchaseOrderNote'], 0, 'L');
|
||||
}
|
||||
$leftY = $pdf->GetY();
|
||||
|
||||
// ── Kolom Kanan ───────────────────────────────────────────────────────
|
||||
$pdf->SetY($startY);
|
||||
$rightX = 15 + $halfW;
|
||||
|
||||
// Down Payment format
|
||||
$dpVal = '-';
|
||||
$dpNominal = floatval($header['InstallmentDownPayment'] ?? 0);
|
||||
if ($dpNominal > 0) {
|
||||
if (($header['InstallmentDownPaymentType'] ?? 'nominal') === 'percent') {
|
||||
$dpVal = number_format($dpNominal, 0, ',', '.') . '%';
|
||||
} else {
|
||||
$dpVal = $this->_fmt_rp($dpNominal);
|
||||
}
|
||||
}
|
||||
|
||||
// Cicilan format
|
||||
$installmentVal = '-';
|
||||
$instNum = intval($header['InstallmentNumber'] ?? 0);
|
||||
$instAmount = floatval($header['InstallmentPayAmount'] ?? 0);
|
||||
if ($instNum > 0) {
|
||||
$installmentVal = $instNum . ' Kali x ' . $this->_fmt_rp($instAmount);
|
||||
}
|
||||
|
||||
$rightItems = array(
|
||||
array('Supplier', $header['SupplierName'] ?: '-'),
|
||||
array('Alamat Supplier', $header['SupplierAddress'] ?: '-'),
|
||||
array('Telp Supplier', $header['SupplierPhone'] ?: '-'),
|
||||
array('Down Payment (DP)', $dpVal),
|
||||
array('Cicilan / Tenor', $installmentVal),
|
||||
);
|
||||
|
||||
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') {
|
||||
$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 + 60 + 20 + 15 + 25 + 22 + 30 = 180
|
||||
$cols = array(
|
||||
array('No', 8, 'C'),
|
||||
array('Nama', 60, 'L'),
|
||||
array('Unit', 20, 'C'),
|
||||
array('Qty', 15, 'R'),
|
||||
array('Harga Satuan', 25, 'R'),
|
||||
array('Diskon', 22, '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;
|
||||
$subTotal = 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['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C');
|
||||
$pdf->Cell($cols[3][1], 6, $this->_fmt_qty($d['RequestQty']), 1, 0, 'C');
|
||||
$pdf->Cell($cols[4][1], 6, $this->_fmt_rp($d['SupplierPrice']), 1, 0, 'R');
|
||||
$pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['DiskonAmount']), 1, 0, 'R');
|
||||
$pdf->Cell($cols[6][1], 6, $this->_fmt_rp($d['TempTotal']), 1, 0, 'R');
|
||||
$pdf->Ln();
|
||||
|
||||
$subTotal += floatval($d['TempTotal']);
|
||||
$no++;
|
||||
}
|
||||
|
||||
$pdf->Ln(2);
|
||||
|
||||
// ── Ringkasan Biaya di Bagian Kanan Bawah ──────────────────────────────
|
||||
$discountPO = floatval($header['PurchaseOrderDiscountAmount'] ?? 0);
|
||||
$ppnAmount = floatval($header['PurchaseOrderTaxAmountPpn'] ?? 0);
|
||||
$pphAmount = floatval($header['PurchaseOrderTaxAmountPph'] ?? 0);
|
||||
$shipCost = floatval($header['PurchaseOrderShippingCost'] ?? 0);
|
||||
$grandTotal = floatval($header['PurchaseOrderGrandTotal'] ?? ($subTotal - $discountPO + $ppnAmount - $pphAmount + $shipCost));
|
||||
|
||||
$summary = array(
|
||||
array('Subtotal', $this->_fmt_rp($subTotal)),
|
||||
);
|
||||
|
||||
if ($discountPO > 0) {
|
||||
$summary[] = array('Diskon PO', '-' . $this->_fmt_rp($discountPO));
|
||||
}
|
||||
if ($ppnAmount > 0) {
|
||||
$summary[] = array('PPN', $this->_fmt_rp($ppnAmount));
|
||||
}
|
||||
if ($pphAmount > 0) {
|
||||
$summary[] = array('PPH', '-' . $this->_fmt_rp($pphAmount));
|
||||
}
|
||||
if ($shipCost > 0) {
|
||||
$summary[] = array('Ongkos Kirim', $this->_fmt_rp($shipCost));
|
||||
}
|
||||
$summary[] = array('Grand Total', $this->_fmt_rp($grandTotal));
|
||||
|
||||
$cW1 = 62;
|
||||
$cW2 = 30;
|
||||
$offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 3), 1)); // Sejajar dengan Qty ke kanan
|
||||
|
||||
foreach ($summary as $s) {
|
||||
$pdf->SetX($offsetX);
|
||||
$pdf->SetFont('Arial_Narrow', '', 8);
|
||||
$pdf->Cell($cW1, 5, $s[0], 0, 0, 'L');
|
||||
|
||||
if ($s[0] === 'Grand Total') {
|
||||
$pdf->SetFont('Arial_Narrow', 'B', 9);
|
||||
} else {
|
||||
$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(
|
||||
'Purchase Order (PO) ini tunduk pada syarat dan ketentuan kontrak sewa/beli aset yang disepakati.',
|
||||
'Seluruh pembayaran DP dan angsuran harus disetorkan tepat waktu sesuai jadwal kontrak.',
|
||||
'Serah terima aset akan didokumentasikan terpisah menggunakan Berita Acara Serah Terima (BAST).',
|
||||
'PO ini sah secara hukum setelah disetujui dan divalidasi secara digital melalui sistem ERP.'
|
||||
);
|
||||
|
||||
$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, ',', '.');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user