2 Commits

Author SHA1 Message Date
Hanan Askarim
0823867277 fix report fpdf 2026-07-17 15:39:07 +07:00
Hanan Askarim
7d8dd0f660 add report payment voucher 2026-07-17 10:03:45 +07:00
18 changed files with 1165 additions and 2667 deletions

View File

@@ -1,532 +0,0 @@
<?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 FakturFpdf 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_faktur extends MY_Controller
{
// -- Properti bersama antar fungsi PDF -------------------------------------
/** @var FakturFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Faktur (Supplier Invoice) Report API";
}
// =========================================================================
// ENDPOINT: pdf
// GET/POST: id (SupplierInvoiceID), 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 FakturFpdf('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_summary();
$this->_pdf_terms();
// -- Output --------------------------------------------------------
$filename = 'INV_' . str_replace('/', '-', $header['SupplierInvoiceNumber']) . '.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
si.*,
sup.SupplierName,
sup.SupplierAddress,
sup.SupplierPhone,
IFNULL(uCr.M_UserUsername, '') AS CreatedByName,
IFNULL(uVe.M_UserUsername, '') AS VerifiedByName,
IFNULL(uAp.M_UserUsername, '') AS ApprovedByName,
IFNULL(uPa.M_UserUsername, '') AS PaidByName,
IFNULL(uRe.M_UserUsername, '') AS ReceivedByName
FROM supplier_invoice si
LEFT JOIN supplier sup ON sup.SupplierID = si.SupplierInvoiceSupplierID
AND sup.SupplierIsActive = 'Y'
LEFT JOIN m_user uCr ON uCr.M_UserID = si.SupplierInvoiceCreatedUserID
LEFT JOIN m_user uVe ON uVe.M_UserID = si.SupplierInvoiceVerifiedUserID
LEFT JOIN m_user uAp ON uAp.M_UserID = si.SupplierInvoiceApprovedUserID
LEFT JOIN m_user uPa ON uPa.M_UserID = si.SupplierInvoicePaidUserID
LEFT JOIN m_user uRe ON uRe.M_UserID = si.SupplierInvoiceReceivedBy
WHERE si.SupplierInvoiceID = ?
AND si.SupplierInvoiceIsActive = 'Y'
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Faktur tidak ditemukan");
exit;
}
return $qry->row_array();
}
// =========================================================================
// DATABASE: Ambil data detail
// =========================================================================
private function _get_detail($id)
{
$sql = "
SELECT
sid.*,
i.M_ItemCode,
i.M_ItemDesc,
iu.ItemUnitName,
iu.ItemUnitCode
FROM supplier_invoice_detail sid
LEFT JOIN m_item i ON i.M_ItemID = sid.SupplierInvoiceDetailItemID
LEFT JOIN itemunit iu ON iu.ItemUnitID = sid.SupplierInvoiceDetailItemUnitID
WHERE sid.SupplierInvoiceDetailSupplierInvoiceID = ?
AND sid.SupplierInvoiceDetailIsActive = 'Y'
ORDER BY sid.SupplierInvoiceDetailID 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, 'FAKTUR (SUPPLIER INVOICE)', 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 Faktur', $header['SupplierInvoiceNumber'], true),
array('Tgl Faktur', $this->_fmt_date($header['SupplierInvoiceDate']), false),
array('Tgl Jatuh Tempo', $this->_fmt_date($header['SupplierInvoiceDueDate']), false),
array('Status', $header['SupplierInvoiceStatus'], false),
array('Supplier', $header['SupplierName'] ?: '-', 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');
}
// Alamat Supplier (MultiCell)
if (!empty($header['SupplierAddress'])) {
$pdf->SetX(15);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, 'Alamat Supplier', 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->SetFont('Arial_Narrow', '', 8);
$pdf->MultiCell($valW, 4, $header['SupplierAddress'], 0, 'L');
$pdf->SetFont('Arial_Narrow', '', 9);
}
// Keterangan
if (!empty($header['SupplierInvoiceNote'])) {
$pdf->SetX(15);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, 'Keterangan', 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->SetFont('Arial_Narrow', '', 8);
$pdf->MultiCell($valW, 4, $header['SupplierInvoiceNote'], 0, 'L');
$pdf->SetFont('Arial_Narrow', '', 9);
}
$leftY = $pdf->GetY();
// -- Kolom Kanan ----------------------------------------------------------
$pdf->SetY($startY);
$rightX = 15 + $halfW;
// No. Supplier Invoice & tgl (jika ada)
$rightItems = array();
if (!empty($header['SupplierInvoiceSupplierInvoiceNumber'])) {
$rightItems[] = array('No. Inv. Supplier', $header['SupplierInvoiceSupplierInvoiceNumber']);
$rightItems[] = array('Tgl Inv. Supplier', $this->_fmt_date($header['SupplierInvoiceSupplierInvoiceDate']));
}
$rightItems[] = array('No. Delivery Order', $header['SupplierInvoiceDeliveryOrderNumber'] ?: '-');
$rightItems[] = array('Dibuat Oleh', $header['CreatedByName'] ?: '-');
$rightItems[] = array('Dibuat Tgl', $this->_fmt_datetime($header['SupplierInvoiceCreated']));
if ($header['SupplierInvoiceStatus'] === 'Verified' || in_array($header['SupplierInvoiceStatus'], ['Approved', 'Scheduled', 'Paid', 'Partially Paid'])) {
if (!empty($header['SupplierInvoiceVerifiedDate'])) {
$rightItems[] = array('Diverifikasi Oleh', $header['VerifiedByName'] ?: '-');
$rightItems[] = array('Tgl Verifikasi', $this->_fmt_datetime($header['SupplierInvoiceVerifiedDate']));
}
}
if (in_array($header['SupplierInvoiceStatus'], ['Approved', 'Scheduled', 'Paid', 'Partially Paid'])) {
if (!empty($header['SupplierInvoiceApprovedDate'])) {
$rightItems[] = array('Disetujui Oleh', $header['ApprovedByName'] ?: '-');
$rightItems[] = array('Tgl Disetujui', $this->_fmt_datetime($header['SupplierInvoiceApprovedDate']));
}
}
if ($header['SupplierInvoiceStatus'] === 'Paid' || $header['SupplierInvoiceStatus'] === 'Partially Paid') {
if (!empty($header['SupplierInvoicePaidDate'])) {
$rightItems[] = array('Dibayar Oleh', $header['PaidByName'] ?: '-');
$rightItems[] = array('Tgl Dibayar', $this->_fmt_datetime($header['SupplierInvoicePaidDate']));
}
}
// Tgl Terima & Penerima (jika ada)
if (!empty($header['SupplierInvoiceReceiveDate'])) {
$rightItems[] = array('Tgl Terima', $this->_fmt_date($header['SupplierInvoiceReceiveDate']));
$rightItems[] = array('Diterima Oleh', $header['ReceivedByName'] ?: '-');
}
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
// =========================================================================
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 + 62 + 15 + 20 + 25 + 25 + 25 = 180
$cols = array(
array('No', 8, 'C'),
array('Deskripsi', 62, 'L'),
array('Unit', 15, 'C'),
array('Qty', 20, 'R'),
array('Harga Satuan', 25, 'R'),
array('Diskon', 25, 'R'),
array('Total', 25, 'R'),
);
// 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;
foreach ($details as $d) {
$qty = floatval($d['SupplierInvoiceDetailQty'] ?? 0);
$price = floatval($d['SupplierInvoiceDetailPrice'] ?? 0);
$discAmount = floatval($d['SupplierInvoiceDetailDiscountAmount'] ?? 0);
$total = floatval($d['SupplierInvoiceDetailTotal'] ?? 0);
$desc = $d['SupplierInvoiceDetailDescription'] ?: ($d['M_ItemDesc'] ?: ($d['M_ItemCode'] ?: '-'));
$pdf->Cell($cols[0][1], 6, $no, 1, 0, 'C');
$pdf->Cell($cols[1][1], 6, $desc, 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($price), 1, 0, 'R');
$pdf->Cell($cols[5][1], 6, $discAmount > 0 ? $this->_fmt_rp($discAmount) : '-', 1, 0, 'R');
$pdf->Cell($cols[6][1], 6, $this->_fmt_rp($total), 1, 0, 'R');
$pdf->Ln();
$no++;
}
$pdf->Ln(4);
}
// =========================================================================
// PDF SECTION: Ringkasan Nilai (SubTotal, Pajak, Grand Total)
// =========================================================================
private function _pdf_summary()
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
$header = $this->_header_data;
// -- Ringkasan nilai (rata kanan) ----------------------------------------
$cW1 = 50;
$cW2 = 40;
$offsetX = 15 + $this->_pageW - $cW1 - $cW2;
// Garis pemisah
$pdf->SetDrawColor(0, 0, 0);
$pdf->SetLineWidth(0.3);
$pdf->Line(15 + $pageW - $cW1 - $cW2 - 4, $pdf->GetY(), 15 + $pageW, $pdf->GetY());
$pdf->Ln(2);
$items = array();
// Sub Total
$items[] = array('Sub Total', $this->_fmt_rp($header['SupplierInvoiceSubTotal']));
// Diskon (jika ada)
$discPct = floatval($header['SupplierInvoiceDiscountPercent'] ?? 0);
$discAmt = floatval($header['SupplierInvoiceDiscountAmount'] ?? 0);
if ($discPct > 0 || $discAmt > 0) {
$label = 'Diskon';
if ($discPct > 0) $label .= ' (' . $this->_fmt_num($discPct) . '%)';
$items[] = array($label, $this->_fmt_rp($discAmt));
}
// PPh (jika ada)
$pphPct = floatval($header['SupplierInvoiceTaxPercentPph'] ?? 0);
$pphAmt = floatval($header['SupplierInvoiceTaxAmountPph'] ?? 0);
if ($pphPct > 0 || $pphAmt > 0) {
$label = 'PPh';
if ($pphPct > 0) $label .= ' (' . $this->_fmt_num($pphPct) . '%)';
$items[] = array($label, $this->_fmt_rp($pphAmt));
}
// PPN (jika ada)
$ppnPct = floatval($header['SupplierInvoiceTaxPercentPpn'] ?? 0);
$ppnAmt = floatval($header['SupplierInvoiceTaxAmountPpn'] ?? 0);
if ($ppnPct > 0 || $ppnAmt > 0) {
$label = 'PPN';
if ($ppnPct > 0) $label .= ' (' . $this->_fmt_num($ppnPct) . '%)';
$items[] = array($label, $this->_fmt_rp($ppnAmt));
}
// Biaya Kirim (jika ada)
$shipCost = floatval($header['SupplierInvoiceShippingCost'] ?? 0);
if ($shipCost > 0) {
$items[] = array('Biaya Kirim', $this->_fmt_rp($shipCost));
}
// Penyesuaian (jika ada)
$adjAmt = floatval($header['SupplierInvoiceAdjustmentAmount'] ?? 0);
if ($adjAmt != 0) {
$label = 'Penyesuaian';
if (!empty($header['SupplierInvoiceAdjustmentNote'])) {
$label .= ' (' . $header['SupplierInvoiceAdjustmentNote'] . ')';
}
$items[] = array($label, $this->_fmt_rp($adjAmt));
}
foreach ($items as $item) {
$pdf->SetX($offsetX);
$pdf->SetFont('Arial_Narrow', '', 8);
$pdf->Cell($cW1, 5, $item[0], 0, 0, 'L');
$pdf->SetFont('Arial_Narrow', '', 8);
$pdf->Cell($cW2, 5, $item[1], 0, 1, 'R');
}
// Grand Total (tebal)
$pdf->SetX($offsetX);
$pdf->SetDrawColor(0, 0, 0);
$pdf->SetLineWidth(0.3);
$pdf->Line($offsetX, $pdf->GetY(), 15 + $pageW, $pdf->GetY());
$pdf->Ln(1);
$pdf->SetX($offsetX);
$pdf->SetFont('Arial_Narrow', 'B', 10);
$pdf->Cell($cW1, 6, 'Grand Total', 0, 0, 'L');
$pdf->Cell($cW2, 6, $this->_fmt_rp($header['SupplierInvoiceGrandTotal']), 0, 1, 'R');
// Sudah dibayar / sisa
$paidAmt = floatval($header['SupplierInvoicePaidAmount'] ?? 0);
$unpaidAmt = floatval($header['SupplierInvoiceUnpaid'] ?? 0);
$isLunas = $header['SupplierInvoiceIsLunas'] ?? 'N';
if ($paidAmt > 0) {
$pdf->SetX($offsetX);
$pdf->SetFont('Arial_Narrow', '', 8);
$pdf->Cell($cW1, 5, 'Dibayar', 0, 0, 'L');
$pdf->SetFont('Arial_Narrow', '', 8);
$pdf->Cell($cW2, 5, $this->_fmt_rp($paidAmt), 0, 1, 'R');
}
if ($isLunas === 'Y') {
$pdf->SetX($offsetX);
$pdf->SetFont('Arial_Narrow', 'B', 9);
$pdf->SetTextColor(0, 128, 0);
$pdf->Cell($cW1 + $cW2, 5, 'LUNAS', 0, 1, 'R');
$pdf->SetTextColor(0, 0, 0);
} elseif ($unpaidAmt > 0) {
$pdf->SetX($offsetX);
$pdf->SetFont('Arial_Narrow', 'B', 8);
$pdf->Cell($cW1, 5, 'Sisa Tagihan', 0, 0, 'L');
$pdf->SetFont('Arial_Narrow', 'B', 8);
$pdf->Cell($cW2, 5, $this->_fmt_rp($unpaidAmt), 0, 1, 'R');
}
$pdf->Ln(4);
}
// =========================================================================
// PDF SECTION: Syarat & Ketentuan
// =========================================================================
private function _pdf_terms()
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
$terms = array(
'Faktur ini diterbitkan berdasarkan barang/jasa yang telah diterima dan sesuai dengan purchase order.',
'Pembayaran harus dilakukan sesuai dengan tanggal jatuh tempo yang tercantum.',
'Keterlambatan pembayaran akan dikenakan sanksi sesuai ketentuan yang berlaku.',
'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, ',', '.');
}
}

View File

@@ -6,7 +6,7 @@ require_once(APPPATH . 'libraries/fpdf/fpdf.php');
// ============================================================================= // =============================================================================
// Custom FPDF: override Footer() agar tampil otomatis di SETIAP halaman // Custom FPDF: override Footer() agar tampil otomatis di SETIAP halaman
// ============================================================================= // =============================================================================
class RequestMutasiFpdf extends FPDF class PaymentVoucherFpdf extends FPDF
{ {
public $printUsername = '-'; public $printUsername = '-';
public $printDate = ''; public $printDate = '';
@@ -14,14 +14,14 @@ class RequestMutasiFpdf extends FPDF
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4') public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
{ {
parent::__construct($orientation, $unit, $size); parent::__construct($orientation, $unit, $size);
// Daftarkan Arial Narrow // Daftarkan Arial Narrow — file font ada di fpdf/font/Arial_Narrow.php
$this->AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular $this->AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular
$this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold $this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold)
} }
public function Footer() public function Footer()
{ {
$pageW = $this->GetPageWidth() - 30; // margin 15+15 $pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15
// ── Posisi: 20mm dari bawah halaman ────────────────────────────────── // ── Posisi: 20mm dari bawah halaman ──────────────────────────────────
$this->SetY(-20); $this->SetY(-20);
@@ -40,15 +40,119 @@ class RequestMutasiFpdf extends FPDF
$this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L'); $this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L');
$this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L'); $this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L');
} }
// Properties untuk tabel multiline
public $widths;
public $aligns;
public function SetWidths($w)
{
$this->widths = $w;
}
public function SetAligns($a)
{
$this->aligns = $a;
}
public function Row($data, $fill = false, $h = 6)
{
// Hitung tinggi maksimum baris berdasarkan multiline
$nb = 0;
for ($i = 0; $i < count($data); $i++) {
$nb = max($nb, $this->NbLines($this->widths[$i], $data[$i]));
}
$rowH = $h * $nb;
// Cek apakah perlu ganti halaman secara otomatis
$this->CheckPageBreak($rowH);
// Gambar cell pada baris
for ($i = 0; $i < count($data); $i++) {
$w = $this->widths[$i];
$a = isset($this->aligns[$i]) ? $this->aligns[$i] : 'L';
$x = $this->GetX();
$y = $this->GetY();
// Gambar border dan background
$this->Rect($x, $y, $w, $rowH, $fill ? 'DF' : 'D');
// Tulis teks menggunakan MultiCell
$this->MultiCell($w, $h, $data[$i], 0, $a);
// Geser posisi X ke kanan untuk cell berikutnya
$this->SetXY($x + $w, $y);
}
// Pindah baris
$this->Ln($rowH);
}
public function CheckPageBreak($h)
{
// Jika tinggi baris melewati batas, buat halaman baru
if ($this->GetY() + $h > $this->PageBreakTrigger) {
$this->AddPage($this->CurOrientation);
}
}
public function NbLines($w, $txt)
{
// Menghitung jumlah baris yang akan dihasilkan oleh MultiCell
$cw =& $this->CurrentFont['cw'];
if ($w == 0) {
$w = $this->w - $this->rMargin - $this->x;
}
$wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
$s = str_replace("\r", '', $txt);
$nb = strlen($s);
if ($nb > 0 && $s[$nb - 1] == "\n") {
$nb--;
}
$sep = -1;
$i = 0;
$j = 0;
$l = 0;
$nl = 1;
while ($i < $nb) {
$c = $s[$i];
if ($c == "\n") {
$i++;
$sep = -1;
$j = $i;
$l = 0;
$nl++;
continue;
}
if ($c == ' ') {
$sep = $i;
}
$l += $cw[$c];
if ($l > $wmax) {
if ($sep == -1) {
if ($i == $j) {
$i++;
}
} else {
$i = $sep + 1;
}
$sep = -1;
$j = $i;
$l = 0;
$nl++;
} else {
$i++;
}
}
return $nl;
}
} }
// ============================================================================= // =============================================================================
// Controller // Controller
// ============================================================================= // =============================================================================
class Rpt_request_mutasi extends MY_Controller class Rpt_payment_voucher extends MY_Controller
{ {
// ── Properti bersama antar fungsi PDF ───────────────────────────────────── // ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var RequestMutasiFpdf */ /** @var PaymentVoucherFpdf */
private $_pdf; private $_pdf;
private $_pageW; private $_pageW;
private $_header_data; private $_header_data;
@@ -61,12 +165,12 @@ class Rpt_request_mutasi extends MY_Controller
public function index() public function index()
{ {
echo "Request Mutasi Report API"; echo "Payment Voucher Report API";
} }
// ========================================================================= // =========================================================================
// ENDPOINT: pdf // ENDPOINT: pdf
// GET/POST: id (MutasiRequestID), username (opsional) // GET/POST: id (PaymentVoucherID), username (opsional)
// ========================================================================= // =========================================================================
public function pdf() public function pdf()
{ {
@@ -84,7 +188,7 @@ class Rpt_request_mutasi extends MY_Controller
$details = $this->_get_detail($id); $details = $this->_get_detail($id);
// ── Inisialisasi FPDF custom ────────────────────────────────────── // ── Inisialisasi FPDF custom ──────────────────────────────────────
$this->_pdf = new RequestMutasiFpdf('P', 'mm', 'A4'); $this->_pdf = new PaymentVoucherFpdf('P', 'mm', 'A4');
$this->_pdf->printUsername = $username !== '' ? $username : '-'; $this->_pdf->printUsername = $username !== '' ? $username : '-';
$this->_pdf->printDate = date('d-m-Y H:i:s'); $this->_pdf->printDate = date('d-m-Y H:i:s');
$this->_pageW = $this->_pdf->GetPageWidth() - 30; $this->_pageW = $this->_pdf->GetPageWidth() - 30;
@@ -102,7 +206,7 @@ class Rpt_request_mutasi extends MY_Controller
$this->_pdf_terms(); $this->_pdf_terms();
// ── Output ──────────────────────────────────────────────────────── // ── Output ────────────────────────────────────────────────────────
$filename = 'RM_' . str_replace('/', '-', $header['MutasiRequestNumber']) . '.pdf'; $filename = 'PV_' . str_replace('/', '-', $header['PaymentVoucherNumber']) . '.pdf';
header('Content-Type: application/pdf'); header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="' . $filename . '"'); header('Content-Disposition: inline; filename="' . $filename . '"');
header('Cache-Control: private, max-age=0, must-revalidate'); header('Cache-Control: private, max-age=0, must-revalidate');
@@ -120,54 +224,55 @@ class Rpt_request_mutasi extends MY_Controller
{ {
$sql = " $sql = "
SELECT SELECT
mr.*, pv.*,
ic.itemCategoryID, cs.coaAccountNo,
ic.itemCategoryName, cs.coaDescription,
a.M_BranchID AS branch_asal_id, ct.coaAccountNo AS coaTempAccountNo,
a.M_BranchCode AS branch_asal_code, ct.coaDescription AS coaTempDescription,
a.M_BranchName AS branch_asal_name, b.M_BranchName,
b.M_BranchID AS branch_tujuan_id, IFNULL(uCr.M_UserUsername, '') AS CreatedByName,
b.M_BranchCode AS branch_tujuan_code, IFNULL(uPd.M_UserUsername, '') AS PaidByName,
b.M_BranchName AS branch_tujuan_name, IFNULL(uRc.M_UserUsername, '') AS PaidReceiveByName
IFNULL(u.M_UserUsername, '') AS CreatedByName, FROM payment_voucher pv
IFNULL(uv.M_UserUsername, '') AS VerifByName, LEFT JOIN coa cs ON cs.coaID = pv.PaymentVoucherCoaSourceID
IFNULL(ua.M_UserUsername, '') AS ApprovedByName LEFT JOIN coa ct ON ct.coaID = pv.PaymentVoucherCoaTemporaryID
FROM mutasi_request mr LEFT JOIN m_branch b ON b.M_BranchCode = pv.PaymentVoucherM_BranchCode
JOIN item_category ic ON ic.itemCategoryID = mr.MutasiRequestItemCategoryID LEFT JOIN m_user uCr ON uCr.M_UserID = pv.PaymentVoucherUserID
JOIN m_branch a ON a.M_BranchID = mr.MutasiRequestFromBranchID LEFT JOIN m_user uPd ON uPd.M_UserID = pv.PaymentVoucherPaidUserID
JOIN m_branch b ON b.M_BranchID = mr.MutasiRequestToBranchID LEFT JOIN m_user uRc ON uRc.M_UserID = pv.PaymentVoucherPaidReceiveUserID
LEFT JOIN m_user u ON u.M_UserID = mr.MutasiRequestUserID WHERE pv.PaymentVoucherIsActive = 'Y'
LEFT JOIN m_user uv ON uv.M_UserID = mr.MutasiRequestVerifUserID AND pv.PaymentVoucherID = ?
LEFT JOIN m_user ua ON ua.M_UserID = mr.MutasiRequestApprovedUserID
WHERE mr.MutasiRequestID = ?
LIMIT 1 LIMIT 1
"; ";
$qry = $this->db->query($sql, array($id)); $qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) { if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Request Mutasi tidak ditemukan"); $this->sys_error("Data Payment Voucher tidak ditemukan");
exit; exit;
} }
return $qry->row_array(); return $qry->row_array();
} }
// =========================================================================
// DATABASE: Ambil data detail
// =========================================================================
private function _get_detail($id) private function _get_detail($id)
{ {
$sql = " $sql = "
SELECT SELECT
mrd.*, pvd.*,
i.M_ItemCode, prd.PurchaseRequestDirectNumber,
i.M_ItemDesc, prdd.PurchaseRequestDirectDescription AS ItemDescription,
iu.ItemUnitName, prdd.PurchaseRequestDirectDetailAccount AS ExpenseAccount,
iu.ItemUnitCode prdd.PurchaseRequestDirectDetailTotalRealitationPrice,
FROM mutasi_request_detail mrd prdd.PurchaseRequestDirectDetailTotalEstimationPrice,
LEFT JOIN m_item i ON i.M_ItemID = mrd.MutasiRequestDetailM_ItemID pdc.PurchaseDirectCategoryName,
LEFT JOIN itemunit iu ON iu.ItemUnitID = mrd.MutasiRequestDetailItemUnitID c.coaDescription AS ExpenseAccountName
WHERE mrd.MutasiRequestDetailMutasiRequestID = ? FROM payment_voucher_detail pvd
AND mrd.MutasiRequestDetailIsActive = 'Y' JOIN purchase_request_direct prd ON prd.PurchaseRequestDirectID = pvd.PaymentVoucherDetailPurchaseRequestDirectID
ORDER BY mrd.MutasiRequestDetailID ASC JOIN purchase_request_direct_detail prdd ON prdd.PurchaseRequestDirectDetailPurchaseRequestDirectID = prd.PurchaseRequestDirectID
AND prdd.PurchaseRequestDirectDetailIsActive = 'Y'
LEFT JOIN purchase_direct_category pdc ON pdc.PurchaseDirectCategoryID = prdd.PurchaseRequestDirectDetailPurchaseRequestDirectCategoryID
LEFT JOIN coa c ON c.coaAccountNo = prdd.PurchaseRequestDirectDetailAccount AND c.coaIsActive = 'Y'
WHERE pvd.PaymentVoucherDetailIsActive = 'Y'
AND pvd.PaymentVoucherDetailPaymentVoucherID = ?
ORDER BY pvd.PaymentVoucherDetailID ASC, prdd.PurchaseRequestDirectDetailID ASC
"; ";
$qry = $this->db->query($sql, array($id)); $qry = $this->db->query($sql, array($id));
return $qry ? $qry->result_array() : array(); return $qry ? $qry->result_array() : array();
@@ -184,7 +289,7 @@ class Rpt_request_mutasi extends MY_Controller
// ── Judul utama ─────────────────────────────────────────────────────── // ── Judul utama ───────────────────────────────────────────────────────
$pdf->SetFont('Arial_Narrow', 'B', 14); $pdf->SetFont('Arial_Narrow', 'B', 14);
$pdf->Cell($pageW, 8, 'REQUEST MUTASI REPORT (RM)', 0, 1, 'L'); $pdf->Cell($pageW, 8, 'PAYMENT VOUCHER (BUKTI PENGELUARAN KAS / BANK)', 0, 1, 'L');
$pdf->SetDrawColor(0, 0, 0); $pdf->SetDrawColor(0, 0, 0);
$pdf->SetLineWidth(0.5); $pdf->SetLineWidth(0.5);
$pdf->Line(15, $pdf->GetY(), 15 + $pageW, $pdf->GetY()); $pdf->Line(15, $pdf->GetY(), 15 + $pageW, $pdf->GetY());
@@ -192,39 +297,62 @@ class Rpt_request_mutasi extends MY_Controller
$startY = $pdf->GetY(); $startY = $pdf->GetY();
$halfW = $pageW / 2; $halfW = $pageW / 2;
$lblW = 30; $lblW = 28;
$valW = $halfW - $lblW - 4; $valW = $halfW - $lblW - 4;
// ── Kolom Kiri ──────────────────────────────────────────────────────── // ── Kolom Kiri ────────────────────────────────────────────────────────
$pdf->SetY($startY); $pdf->SetY($startY);
$coaSource = '-';
if (!empty($header['coaAccountNo'])) {
$coaSource = $header['coaAccountNo'] . ' - ' . $header['coaDescription'];
}
$coaTemp = '';
if (!empty($header['coaTempAccountNo'])) {
$coaTemp = $header['coaTempAccountNo'] . ' - ' . $header['coaTempDescription'];
}
$leftItems = array( $leftItems = array(
array('Nomor', $header['MutasiRequestNumber'], true), array('Nomor', $header['PaymentVoucherNumber'], true),
array('Tanggal', $this->_fmt_date($header['MutasiRequestDate']), false), array('Tanggal', $this->_fmt_date($header['PaymentVoucherDate']), false),
array('Status', $header['MutasiRequestStatus'], false), array('Sumber Dana', $coaSource, false),
array('Kategori', $header['itemCategoryName'], false),
); );
if ($coaTemp !== '') {
$leftItems[] = array('Akun Transit', $coaTemp, false);
}
foreach ($leftItems as $item) { foreach ($leftItems as $item) {
$pdf->SetX(15); $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]) { if ($item[2]) {
$pdf->SetFont('Arial_Narrow', 'B', 9); $pdf->SetFont('Arial_Narrow', 'B', 9);
} else { } else {
$pdf->SetFont('Arial_Narrow', '', 9); $pdf->SetFont('Arial_Narrow', '', 9);
} }
$pdf->Cell($valW, 5, $item[1], 0, 1, 'L'); $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);
}
if ($item[0] === 'Sumber Dana' || $item[0] === 'Akun Transit') {
$pdf->MultiCell($valW, 5, $item[1], 0, 'L');
} else {
$pdf->Cell($valW, 5, $item[1], 0, 1, 'L');
}
} }
// Keterangan (Note) langsung di bawah Status // Keterangan / Paid Note langsung di bawah Status (tanpa spasi vertikal)
if (!empty($header['MutasiRequestNote'])) { if (!empty($header['PaymentVoucherPaidNote'])) {
$pdf->SetX(15); $pdf->SetX(15);
$pdf->SetFont('Arial_Narrow', '', 9); $pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, 'Keterangan', 0, 0, 'L'); $pdf->Cell($lblW, 5, 'Catatan Bayar', 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C'); $pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->MultiCell($valW, 5, $header['MutasiRequestNote'], 0, 'L'); $pdf->MultiCell($valW, 5, $header['PaymentVoucherPaidNote'], 0, 'L');
} }
$leftY = $pdf->GetY(); $leftY = $pdf->GetY();
@@ -233,11 +361,9 @@ class Rpt_request_mutasi extends MY_Controller
$rightX = 15 + $halfW; $rightX = 15 + $halfW;
$rightItems = array( $rightItems = array(
array('Cabang Asal', $header['branch_asal_name']), array('Cabang', $header['M_BranchName'] ?: '-'),
array('Cabang Tujuan', $header['branch_tujuan_name']), array('Tgl Pembayaran', $this->_fmt_date($header['PaymentVoucherPaidDate'])),
array('Dibuat Oleh', $header['CreatedByName']), array('Dibuat Oleh', $header['CreatedByName'] ?: '-'),
array('Diverifikasi Oleh', $header['VerifByName'] ?: '-'),
array('Disetujui Oleh', $header['ApprovedByName'] ?: '-'),
); );
foreach ($rightItems as $item) { foreach ($rightItems as $item) {
@@ -248,22 +374,6 @@ class Rpt_request_mutasi extends MY_Controller
$pdf->SetFont('Arial_Narrow', '', 9); $pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($valW, 5, $item[1], 0, 1, 'L'); $pdf->Cell($valW, 5, $item[1], 0, 1, 'L');
} }
// Tanggal approvals di kolom kanan
$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['MutasiRequestVerifDate']), 0, 1, 'L');
$pdf->SetX($rightX);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, 'Tgl Approved', 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($valW, 5, $this->_fmt_datetime($header['MutasiRequestApprovedDate']), 0, 1, 'L');
$rightY = $pdf->GetY(); $rightY = $pdf->GetY();
// Posisikan Y ke yang paling bawah + margin // Posisikan Y ke yang paling bawah + margin
@@ -271,7 +381,7 @@ class Rpt_request_mutasi extends MY_Controller
} }
// ========================================================================= // =========================================================================
// PDF SECTION: Data — Tabel detail item + ringkasan nilai // PDF SECTION: Data — Tabel detail item
// ========================================================================= // =========================================================================
private function _pdf_data($details) private function _pdf_data($details)
{ {
@@ -281,18 +391,17 @@ class Rpt_request_mutasi extends MY_Controller
// ── Definisi kolom: [label, lebar, align] ───────────────────────────── // ── Definisi kolom: [label, lebar, align] ─────────────────────────────
// Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan) // Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan)
// 8 + 80 + 20 + 20 + 25 + 27 = 180 // 8 + 45 + 30 + 72 + 25 = 180
$cols = array( $cols = array(
array('No', 8, 'C'), array('No', 8, 'C'),
array('Nama Item', 80, 'L'), array('No. Request Direct', 45, 'L'),
array('Unit', 20, 'C'), array('Kategori', 30, 'L'),
array('Qty', 20, 'R'), array('Deskripsi', 72, 'L'),
array('Nilai Buku', 25, 'R'), array('Nominal Bayar', 25, 'R'),
array('Total', 27, 'R'),
); );
// Header kolom // Header kolom
$pdf->SetLineWidth(0.3); $pdf->SetLineWidth(0.3); // border medium
$pdf->SetFont('Arial_Narrow', 'B', 8); $pdf->SetFont('Arial_Narrow', 'B', 8);
$pdf->SetFillColor(220, 220, 220); $pdf->SetFillColor(220, 220, 220);
$pdf->SetDrawColor(0, 0, 0); $pdf->SetDrawColor(0, 0, 0);
@@ -301,37 +410,48 @@ class Rpt_request_mutasi extends MY_Controller
} }
$pdf->Ln(); $pdf->Ln();
// Set lebar dan alignment kolom untuk metode Row()
$pdf->SetWidths(array_column($cols, 1));
$pdf->SetAligns(array_column($cols, 2));
// Baris data // Baris data
$pdf->SetLineWidth(0.2); $pdf->SetLineWidth(0.2); // border lebih tipis di data
$pdf->SetFont('Arial_Narrow', '', 8); $pdf->SetFont('Arial_Narrow', '', 8);
$pdf->SetFillColor(255, 255, 255); $pdf->SetFillColor(255, 255, 255);
$no = 1; $no = 1;
$total_val = 0; $totalPay = 0;
foreach ($details as $d) { foreach ($details as $d) {
$pdf->Cell($cols[0][1], 6, $no, 1, 0, 'C'); $amount = floatval($d['PurchaseRequestDirectDetailTotalRealitationPrice']);
$pdf->Cell($cols[1][1], 6, $d['M_ItemDesc'] ?: ($d['M_ItemCode'] ?: '-'), 1, 0, 'L'); if ($amount <= 0) {
$pdf->Cell($cols[2][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C'); $amount = floatval($d['PurchaseRequestDirectDetailTotalEstimationPrice']);
$pdf->Cell($cols[3][1], 6, $this->_fmt_qty($d['MutasiRequestDetailQty']), 1, 0, 'R'); }
$bookValue = floatval($d['MutasiRequestDetailBookValue'] ?? 0);
$pdf->Cell($cols[4][1], 6, $this->_fmt_rp($bookValue), 1, 0, 'R');
$pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['MutasiRequestDetailQty'] * $bookValue), 1, 0, 'R');
$pdf->Ln();
$total_val += floatval($d['MutasiRequestDetailQty'] * $bookValue); $row_data = array(
$no,
$d['PurchaseRequestDirectNumber'] ?: '-',
$d['PurchaseDirectCategoryName'] ?: '-',
$d['ItemDescription'] ?: '-',
$this->_fmt_rp($amount),
);
$pdf->Row($row_data);
$totalPay += $amount;
$no++; $no++;
} }
// Baris TOTAL // Baris TOTAL
$span = array_sum(array_column(array_slice($cols, 0, 5), 1)); $span = array_sum(array_column(array_slice($cols, 0, 4), 1));
$pdf->SetLineWidth(0.3); $pdf->SetLineWidth(0.3);
$pdf->SetFont('Arial_Narrow', 'B', 9); $pdf->SetFont('Arial_Narrow', 'B', 9); // bold + size 9 agar menonjol
$pdf->SetFillColor(220, 220, 220); $pdf->SetFillColor(220, 220, 220);
$pdf->Cell($span, 7, 'TOTAL', 1, 0, 'R', true); $pdf->Cell($span, 7, 'TOTAL PEMBAYARAN', 1, 0, 'R', true);
$pdf->Cell($cols[5][1], 7, $this->_fmt_rp($total_val), 1, 0, 'R', true); $pdf->Cell($cols[4][1], 7, $this->_fmt_rp($totalPay), 1, 0, 'R', true);
$pdf->Ln(); $pdf->Ln(6);
$pdf->Ln(4); // Ringkasan Biaya di Kanan Bawah (sejajar dengan Nominal Bayar)
$pdf->Ln(2);
} }
// ========================================================================= // =========================================================================
@@ -343,10 +463,10 @@ class Rpt_request_mutasi extends MY_Controller
$pageW = $this->_pageW; $pageW = $this->_pageW;
$terms = array( $terms = array(
'Mutasi barang ini harus mendapatkan persetujuan dari pejabat berwenang sebelum proses mutasi dilakukan.', 'Voucher ini adalah tanda bukti pengeluaran kas/bank yang sah untuk pembayaran dokumen PR Direct di atas.',
'Barang yang dimutasi harus sesuai dengan spesifikasi dan jumlah yang tercantum dalam dokumen ini.', 'Penerima dana bertanggung jawab penuh atas keabsahan penggunaan dana yang diserahterimakan.',
'Proses mutasi dilakukan setelah barang diverifikasi dan disetujui oleh pihak terkait.', 'Realisasi pembayaran harus dilaporkan kembali ke bagian keuangan selambat-lambatnya 3 hari kerja.',
'Dokumen ini bersifat internal dan hanya digunakan untuk keperluan proses mutasi barang.', 'Dokumen ini dicetak secara digital dan divalidasi oleh otorisasi sistem akuntansi ERP.'
); );
$pdf->SetFont('Arial_Narrow', 'B', 9); $pdf->SetFont('Arial_Narrow', 'B', 9);
@@ -379,6 +499,7 @@ class Rpt_request_mutasi extends MY_Controller
return number_format(floatval($n), 2, ',', '.'); return number_format(floatval($n), 2, ',', '.');
} }
// format jumlah/qty: tanpa desimal
private function _fmt_qty($n) private function _fmt_qty($n)
{ {
return number_format(floatval($n), 0, ',', '.'); return number_format(floatval($n), 0, ',', '.');

View File

@@ -1,531 +0,0 @@
<?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, ',', '.');
}
}

View File

@@ -1,427 +0,0 @@
<?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 MutasiPenerimaanFpdf 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_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, ',', '.');
}
}

View File

@@ -1,403 +0,0 @@
<?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 PengeluaranBarangFpdf 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_pengeluaran_barang extends MY_Controller
{
// -- Properti bersama antar fungsi PDF -------------------------------------
/** @var PengeluaranBarangFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Pengeluaran Barang Report API";
}
// =========================================================================
// ENDPOINT: pdf
// GET/POST: id (T_ItemOutID), 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 PengeluaranBarangFpdf('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 = 'IO_' . str_replace('/', '-', $header['T_ItemOutNumber']) . '.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
io.*,
IFNULL(u.M_UserUsername, '') AS CreatedByName,
IFNULL(ur.M_UserUsername, '') AS ReceiveByName,
IFNULL(ua.M_UserUsername, '') AS ApprovedByName,
wh.WarehouseCode,
wh.WarehouseName,
wh.WarehouseType,
d.DivisionCode,
d.DivisionName
FROM t_item_out io
LEFT JOIN m_user u ON u.M_UserID = io.T_ItemOutUserID
LEFT JOIN m_user ur ON ur.M_UserID = io.T_ItemOutReceiveUserID
LEFT JOIN m_user ua ON ua.M_UserID = io.T_ItemOutApproveID
LEFT JOIN warehouse wh ON wh.WarehouseID = io.T_ItemOutWarehouseID
AND wh.WarehouseIsActive = 'Y'
LEFT JOIN division d ON d.DivisionID = io.T_ItemOutDivisionID
AND d.DivisionIsActive = 'Y'
WHERE io.T_ItemOutID = ?
AND io.T_ItemOutIsActive = 'Y'
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Pengeluaran Barang tidak ditemukan");
exit;
}
return $qry->row_array();
}
// =========================================================================
// DATABASE: Ambil data detail
// =========================================================================
private function _get_detail($id)
{
$sql = "
SELECT
iod.*,
i.M_ItemCode,
i.M_ItemDesc,
iu.ItemUnitName,
iu.ItemUnitCode,
rod.RequestItemOutDetailQty AS RequestQty,
rod.RequestItemOutDetailStatus AS RequestStatus
FROM t_item_out_detail iod
LEFT JOIN m_item i ON i.M_ItemID = iod.T_ItemOutDetailM_ItemID
LEFT JOIN itemunit iu ON iu.ItemUnitID = iod.T_ItemOutDetailItemUnitID
LEFT JOIN request_item_out_detail rod
ON rod.RequestItemOutDetailID = iod.T_ItemOutDetailRequestItemOutDetailID
AND rod.RequestItemOutDetailIsActive = 'Y'
WHERE iod.T_ItemOutDetailT_ItemOutID = ?
AND iod.T_ItemOutDetailIsActive = 'Y'
ORDER BY iod.T_ItemOutDetailID 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, 'PENGELUARAN BARANG (ITEM OUT)', 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 IO', $header['T_ItemOutNumber'], true),
array('Tanggal', $this->_fmt_date($header['T_ItemOutDate']), false),
array('Status', $header['T_ItemOutStatus'], false),
array('Confirm', $header['T_ItemOutIsConfirm'] === 'Y' ? 'Ya' : 'Tidak', false),
array('Divisi', $header['DivisionName'] ?: '-', false),
array('Gudang', $header['WarehouseName'] ?: '-', 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 field terakhir
if (!empty($header['T_ItemOutNote'])) {
$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['T_ItemOutNote'], 0, 'L');
}
$leftY = $pdf->GetY();
// -- Kolom Kanan -------------------------------------------------------
$pdf->SetY($startY);
$rightX = 15 + $halfW;
$rightItems = array(
array('Dibuat Oleh', $header['CreatedByName'] ?: '-'),
array('Dibuat Tgl', $this->_fmt_datetime($header['T_ItemOutCreated'])),
array('Penerima', $header['ReceiveByName'] ?: '-'),
array('Disetujui Oleh', $header['ApprovedByName'] ?: '-'),
array('Tgl Approve', $header['T_ItemOutApproveDate'] ? $this->_fmt_datetime($header['T_ItemOutApproveDate']) : '-'),
array('Tgl Dikonfirmasi', $header['T_ItemOutIsConfirmDate'] ? $this->_fmt_datetime($header['T_ItemOutIsConfirmDate']) : '-'),
);
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
// =========================================================================
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 + 20 + 30 + 30 = 180
$cols = array(
array('No', 8, 'C'),
array('Nama Item', 72, 'L'),
array('Unit', 20, 'C'),
array('Qty', 20, 'R'),
array('Batch No.', 30, 'C'),
array('Qty Request', 30, 'R'),
);
// 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_req = 0;
foreach ($details as $d) {
$qty = floatval($d['T_ItemOutDetailQty'] ?? 0);
$qtyReq = floatval($d['T_ItemOutDetailRequestItemOutDetailID'] > 0 ? $qty : 0);
$batchNo = $d['T_ItemOutDetailItemBatchNo'] ?? '';
// Jika batch no berupa JSON array, decode untuk ditampilkan
$batchDisplay = $batchNo;
if (strpos($batchNo, '[') === 0) {
$decoded = json_decode($batchNo, true);
if (is_array($decoded) && count($decoded) > 0) {
$parts = array();
foreach ($decoded as $b) {
$parts[] = isset($b['batchNo']) ? $b['batchNo'] : (isset($b['BatchNo']) ? $b['BatchNo'] : (is_string($b) ? $b : '-'));
}
$batchDisplay = implode(', ', $parts);
}
}
$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, $batchDisplay, 1, 0, 'C');
$reqQty = isset($d['RequestQty']) ? floatval($d['RequestQty']) : 0;
$pdf->Cell($cols[5][1], 6, $reqQty > 0 ? $this->_fmt_qty($reqQty) : '-', 1, 0, 'R');
$pdf->Ln();
$total_qty += $qty;
if ($reqQty > 0) {
$total_req += $reqQty;
}
$no++;
}
// Baris TOTAL
$span = array_sum(array_column(array_slice($cols, 0, 4), 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[4][1], 7, '', 1, 0, 'C', true);
$pdf->Cell($cols[5][1], 7, $this->_fmt_qty($total_qty), 1, 0, 'R', true);
$pdf->Ln();
$pdf->Ln(4);
}
// =========================================================================
// PDF SECTION: Syarat & Ketentuan
// =========================================================================
private function _pdf_terms()
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
$terms = array(
'Barang yang dikeluarkan harus sesuai dengan jumlah dan spesifikasi yang tercantum dalam dokumen ini.',
'Penerima barang wajib memeriksa dan memverifikasi kesesuaian barang sebelum menerima.',
'Dokumen ini merupakan bukti sah pengeluaran barang dari gudang.',
'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, ',', '.');
}
}

View File

@@ -182,17 +182,47 @@ class Rpt_pr_direct extends MY_Controller
$pdf->Line(15, $pdf->GetY(), 15 + $pageW, $pdf->GetY()); $pdf->Line(15, $pdf->GetY(), 15 + $pageW, $pdf->GetY());
$pdf->Ln(2); $pdf->Ln(2);
// ── Info dokumen: 2 kolom (kiri & kanan) ───────────────────────────── $startY = $pdf->GetY();
$half = $pageW / 2; $half = $pageW / 2;
$lbl = 30; $lbl = 28;
$val = $half - $lbl - 4; $val = $half - $lbl - 4;
// ── Kolom Kiri ────────────────────────────────────────────────────────
$pdf->SetY($startY);
$left = array( $left = array(
array('Nomor', $header['PurchaseRequestDirectNumber']), array('Nomor', $header['PurchaseRequestDirectNumber'], true),
array('Tanggal', $this->_fmt_date($header['PurchaseRequestDirectDate'])), array('Tanggal', $this->_fmt_date($header['PurchaseRequestDirectDate']), false),
array('Tanggal Pelaksanaan', $this->_fmt_date($header['PurchaseRequestDirectDateUse'])), array('Tanggal Pelaksanaan', $this->_fmt_date($header['PurchaseRequestDirectDateUse']), false),
array('Status', $header['PurchaseRequestDirectStatus']),
); );
foreach ($left as $item) {
$pdf->SetX(15);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lbl, 5, $item[0], 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
if (isset($item[2]) && $item[2]) {
$pdf->SetFont('Arial_Narrow', 'B', 9);
} else {
$pdf->SetFont('Arial_Narrow', '', 9);
}
$pdf->Cell($val, 5, $item[1], 0, 1, 'L');
}
// Keterangan langsung di bawah info kiri (tanpa spasi vertikal)
if (!empty($header['PurchaseRequestDirectDescription'])) {
$pdf->SetX(15);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lbl, 5, 'Keterangan', 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->MultiCell($val, 5, $header['PurchaseRequestDirectDescription'], 0, 'L');
}
$leftY = $pdf->GetY();
// ── Kolom Kanan ───────────────────────────────────────────────────────
$pdf->SetY($startY);
$rightX = 15 + $half;
$right = array( $right = array(
array('Cabang', $header['M_BranchName']), array('Cabang', $header['M_BranchName']),
array('Regional', $header['S_RegionalName']), array('Regional', $header['S_RegionalName']),
@@ -200,43 +230,22 @@ class Rpt_pr_direct extends MY_Controller
array('Dibuat Oleh', $header['CreatedByName']), array('Dibuat Oleh', $header['CreatedByName']),
); );
$maxRow = max(count($left), count($right)); foreach ($right as $item) {
for ($i = 0; $i < $maxRow; $i++) { $pdf->SetX($rightX);
// kolom kiri
if (isset($left[$i])) {
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lbl, 5, $left[$i][0], 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
if ($left[$i][0] === 'Nomor') {
$pdf->SetFont('Arial_Narrow', 'B', 9);
} else {
$pdf->SetFont('Arial_Narrow', '', 9);
}
$pdf->Cell($val, 5, $left[$i][1], 0, 0, 'L');
} else {
$pdf->Cell($half, 5, '', 0, 0);
}
// kolom kanan
if (isset($right[$i])) {
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lbl, 5, $right[$i][0], 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($val, 5, $right[$i][1], 0, 1, 'L');
} else {
$pdf->Cell($half, 5, '', 0, 1);
}
}
// Keterangan (catatan dihapus)
if (!empty($header['PurchaseRequestDirectDescription'])) {
$pdf->SetFont('Arial_Narrow', '', 9); $pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lbl, 5, 'Keterangan', 0, 0, 'L'); $pdf->Cell($lbl, 5, $item[0], 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C'); $pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->Cell($pageW - $lbl - 4, 5, $header['PurchaseRequestDirectDescription'], 0, 1, 'L'); $pdf->SetFont('Arial_Narrow', '', 9);
if ($item[0] === 'Alamat') {
$pdf->MultiCell($val, 5, $item[1], 0, 'L');
} else {
$pdf->Cell($val, 5, $item[1], 0, 1, 'L');
}
} }
$rightY = $pdf->GetY();
$pdf->Ln(4); $pdf->SetY(max($leftY, $rightY) + 4);
} }
// ========================================================================= // =========================================================================

View File

@@ -202,7 +202,7 @@ class Rpt_pr_direct_approval extends MY_Controller
array('Nomor', $header['PurchaseRequestDirectNumber'], true), array('Nomor', $header['PurchaseRequestDirectNumber'], true),
array('Tanggal', $this->_fmt_date($header['PurchaseRequestDirectDate']), false), array('Tanggal', $this->_fmt_date($header['PurchaseRequestDirectDate']), false),
array('Tanggal Pelaksanaan', $this->_fmt_date($header['PurchaseRequestDirectDateUse']), false), array('Tanggal Pelaksanaan', $this->_fmt_date($header['PurchaseRequestDirectDateUse']), false),
array('Status', $header['PurchaseRequestDirectStatus'], false), array('Tanggal Approved', $this->_fmt_datetime($header['PurchaseRequestDirectApprovedDate'])),
); );
foreach ($leftItems as $item) { foreach ($leftItems as $item) {
@@ -210,7 +210,7 @@ class Rpt_pr_direct_approval extends MY_Controller
$pdf->SetFont('Arial_Narrow', '', 9); $pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, $item[0], 0, 0, 'L'); $pdf->Cell($lblW, 5, $item[0], 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C'); $pdf->Cell(4, 5, ':', 0, 0, 'C');
if ($item[2]) { if (isset($item[2]) && $item[2]) {
$pdf->SetFont('Arial_Narrow', 'B', 9); $pdf->SetFont('Arial_Narrow', 'B', 9);
} else { } else {
$pdf->SetFont('Arial_Narrow', '', 9); $pdf->SetFont('Arial_Narrow', '', 9);
@@ -245,7 +245,6 @@ class Rpt_pr_direct_approval extends MY_Controller
array('Alamat', $header['M_BranchAddress']), array('Alamat', $header['M_BranchAddress']),
array('Dibuat Oleh', $header['CreatedByName']), array('Dibuat Oleh', $header['CreatedByName']),
array('Disetujui Oleh', $header['ApprovedByName']), array('Disetujui Oleh', $header['ApprovedByName']),
array('Tanggal Approved', $this->_fmt_datetime($header['PurchaseRequestDirectApprovedDate'])),
); );
foreach ($rightItems as $item) { foreach ($rightItems as $item) {

View File

@@ -225,9 +225,8 @@ class Rpt_purchase_order_asset extends MY_Controller
} }
$leftItems = array( $leftItems = array(
array('Nomor PO', $header['PurchaseOrderNumber'], true), array('Nomor', $header['PurchaseOrderNumber'], true),
array('Tanggal PO', $this->_fmt_date($header['PurchaseOrderDate']), false), array('Tanggal', $this->_fmt_date($header['PurchaseOrderDate']), false),
array('No. Referensi', $header['PurchaseOrderRefNumber'] ?: '-', false),
array('Nama Kontrak', $header['ContractName'] ?: '-', false), array('Nama Kontrak', $header['ContractName'] ?: '-', false),
array('Tanggal Kontrak', $this->_fmt_date($header['ContractDate']), false), array('Tanggal Kontrak', $this->_fmt_date($header['ContractDate']), false),
array('Periode Kontrak', $periodeKontrak, false), array('Periode Kontrak', $periodeKontrak, false),

View File

@@ -6,7 +6,7 @@ require_once(APPPATH . 'libraries/fpdf/fpdf.php');
// ============================================================================= // =============================================================================
// Custom FPDF: override Footer() agar tampil otomatis di SETIAP halaman // Custom FPDF: override Footer() agar tampil otomatis di SETIAP halaman
// ============================================================================= // =============================================================================
class MutasiHandoverFpdf extends FPDF class PurchaseOrderJasaFpdf extends FPDF
{ {
public $printUsername = '-'; public $printUsername = '-';
public $printDate = ''; public $printDate = '';
@@ -14,14 +14,14 @@ class MutasiHandoverFpdf extends FPDF
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4') public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
{ {
parent::__construct($orientation, $unit, $size); parent::__construct($orientation, $unit, $size);
// Daftarkan Arial Narrow // Daftarkan Arial Narrow — file font ada di fpdf/font/Arial_Narrow.php
$this->AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular $this->AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular
$this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold $this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold)
} }
public function Footer() public function Footer()
{ {
$pageW = $this->GetPageWidth() - 30; // margin 15+15 $pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15
// ── Posisi: 20mm dari bawah halaman ────────────────────────────────── // ── Posisi: 20mm dari bawah halaman ──────────────────────────────────
$this->SetY(-20); $this->SetY(-20);
@@ -45,10 +45,10 @@ class MutasiHandoverFpdf extends FPDF
// ============================================================================= // =============================================================================
// Controller // Controller
// ============================================================================= // =============================================================================
class Rpt_penyerahan_mutasi extends MY_Controller class Rpt_purchase_order_jasa extends MY_Controller
{ {
// ── Properti bersama antar fungsi PDF ───────────────────────────────────── // ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var MutasiHandoverFpdf */ /** @var PurchaseOrderJasaFpdf */
private $_pdf; private $_pdf;
private $_pageW; private $_pageW;
private $_header_data; private $_header_data;
@@ -61,12 +61,12 @@ class Rpt_penyerahan_mutasi extends MY_Controller
public function index() public function index()
{ {
echo "Mutasi Handover (Penyerahan Mutasi) Report API"; echo "Purchase Order Jasa Report API";
} }
// ========================================================================= // =========================================================================
// ENDPOINT: pdf // ENDPOINT: pdf
// GET/POST: id (MutasiHandoverID), username (opsional) // GET/POST: id (PurchaseOrderID), username (opsional)
// ========================================================================= // =========================================================================
public function pdf() public function pdf()
{ {
@@ -84,7 +84,7 @@ class Rpt_penyerahan_mutasi extends MY_Controller
$details = $this->_get_detail($id); $details = $this->_get_detail($id);
// ── Inisialisasi FPDF custom ────────────────────────────────────── // ── Inisialisasi FPDF custom ──────────────────────────────────────
$this->_pdf = new MutasiHandoverFpdf('P', 'mm', 'A4'); $this->_pdf = new PurchaseOrderJasaFpdf('P', 'mm', 'A4');
$this->_pdf->printUsername = $username !== '' ? $username : '-'; $this->_pdf->printUsername = $username !== '' ? $username : '-';
$this->_pdf->printDate = date('d-m-Y H:i:s'); $this->_pdf->printDate = date('d-m-Y H:i:s');
$this->_pageW = $this->_pdf->GetPageWidth() - 30; $this->_pageW = $this->_pdf->GetPageWidth() - 30;
@@ -102,7 +102,7 @@ class Rpt_penyerahan_mutasi extends MY_Controller
$this->_pdf_terms(); $this->_pdf_terms();
// ── Output ──────────────────────────────────────────────────────── // ── Output ────────────────────────────────────────────────────────
$filename = 'PH_' . str_replace('/', '-', $header['MutasiHandoverNumber']) . '.pdf'; $filename = 'PO_JASA_' . str_replace('/', '-', $header['PurchaseOrderNumber']) . '.pdf';
header('Content-Type: application/pdf'); header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="' . $filename . '"'); header('Content-Disposition: inline; filename="' . $filename . '"');
header('Cache-Control: private, max-age=0, must-revalidate'); header('Cache-Control: private, max-age=0, must-revalidate');
@@ -120,44 +120,31 @@ class Rpt_penyerahan_mutasi extends MY_Controller
{ {
$sql = " $sql = "
SELECT SELECT
mh.*, po.*,
mr.MutasiRequestNumber, sup.SupplierName,
ic.itemCategoryID, sup.SupplierAddress,
ic.itemCategoryName, sup.SupplierPhone,
a.M_BranchID AS branch_asal_id, b.M_BranchName,
a.M_BranchCode AS branch_asal_code, b.M_BranchAddress,
a.M_BranchName AS branch_asal_name, r.S_RegionalName,
b.M_BranchID AS branch_tujuan_id, kj.T_KontrakJasaJenisKontrak AS JenisKontrak,
b.M_BranchCode AS branch_tujuan_code, kj.T_KontrakJasaStartDate AS StartDate,
b.M_BranchName AS branch_tujuan_name, kj.T_KontrakJasaEndDate AS EndDate,
IFNULL(u.M_UserUsername, '') AS CreatedByName, kj.T_KontrakJasaJumlahPI AS JumlahPI,
IFNULL(ur.M_UserUsername, '') AS ReceiveByName, kj.T_KontrakJasaStatus AS StatusKontrak
CASE FROM purchase_order po
WHEN wh.WarehouseType = 'B' THEN CONCAT(wh.WarehouseCode, ' ', wh.WarehouseName, ' - ', b.M_BranchName) LEFT JOIN supplier sup ON sup.SupplierID = po.PurchaseOrderSupplierID
ELSE wh.WarehouseName LEFT JOIN s_regional r ON r.S_RegionalID = po.PurchaseOrderS_RegionalID
END AS WarehouseName, LEFT JOIN t_kontrak_jasa kj ON kj.T_KontrakJasaPurchaseOrderID = po.PurchaseOrderID
r.M_RuanganName AND kj.T_KontrakJasaIsActive = 'Y'
FROM mutasi_handover mh LEFT JOIN m_branch b ON b.M_BranchCode = kj.T_KontrakJasaM_BranchCode
LEFT JOIN mutasi_request mr ON mr.MutasiRequestID = mh.MutasiHandoverMutasiRequestID WHERE po.PurchaseOrderIsActive = 'Y'
JOIN item_category ic ON ic.itemCategoryID = mh.MutasiHandoverItemCategoryID AND po.PurchaseOrderID = ?
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 LIMIT 1
"; ";
$qry = $this->db->query($sql, array($id)); $qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) { if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Penyerahan Mutasi tidak ditemukan"); $this->sys_error("Data Purchase Order Jasa tidak ditemukan");
exit; exit;
} }
return $qry->row_array(); return $qry->row_array();
@@ -170,17 +157,22 @@ class Rpt_penyerahan_mutasi extends MY_Controller
{ {
$sql = " $sql = "
SELECT SELECT
mhd.*, pos.PurchaseOrderSummaryQty AS RequestQty,
i.M_ItemCode, pos.PurchaseOrderSummaryPrice AS SupplierPrice,
i.M_ItemDesc, pos.PurchaseOrderSummaryDiscountAmount AS DiskonAmount,
pos.PurchaseOrderSummaryTotal AS TempTotal,
item.M_ItemCode,
item.M_ItemDesc,
iu.ItemUnitName, iu.ItemUnitName,
iu.ItemUnitCode iu.ItemUnitCode
FROM mutasi_handover_detail mhd FROM purchase_order_summary pos
LEFT JOIN m_item i ON i.M_ItemID = mhd.MutasiHandoverDetailM_ItemID JOIN m_item item ON item.M_ItemID = pos.PurchaseOrderSummaryItemID
LEFT JOIN itemunit iu ON iu.ItemUnitID = mhd.MutasiHandoverDetailItemUnitID AND item.M_ItemIsActive = 'Y'
WHERE mhd.MutasiHandoverDetailMutasiHandoverID = ? LEFT JOIN itemunit iu ON iu.ItemUnitID = pos.PurchaseOrderSummaryItemUnitID
AND mhd.MutasiHandoverDetailIsActive = 'Y' AND iu.ItemUnitIsActive = 'Y'
ORDER BY mhd.MutasiHandoverDetailID ASC WHERE pos.PurchaseOrderSummaryIsActive = 'Y'
AND pos.PurchaseOrderSummaryPurchaseOrderID = ?
ORDER BY pos.PurchaseOrderSummaryID ASC
"; ";
$qry = $this->db->query($sql, array($id)); $qry = $this->db->query($sql, array($id));
return $qry ? $qry->result_array() : array(); return $qry ? $qry->result_array() : array();
@@ -197,7 +189,7 @@ class Rpt_penyerahan_mutasi extends MY_Controller
// ── Judul utama ─────────────────────────────────────────────────────── // ── Judul utama ───────────────────────────────────────────────────────
$pdf->SetFont('Arial_Narrow', 'B', 14); $pdf->SetFont('Arial_Narrow', 'B', 14);
$pdf->Cell($pageW, 8, 'PENYERAHAN MUTASI (HANDOVER)', 0, 1, 'L'); $pdf->Cell($pageW, 8, 'PURCHASE ORDER JASA (SERVICE PO)', 0, 1, 'L');
$pdf->SetDrawColor(0, 0, 0); $pdf->SetDrawColor(0, 0, 0);
$pdf->SetLineWidth(0.5); $pdf->SetLineWidth(0.5);
$pdf->Line(15, $pdf->GetY(), 15 + $pageW, $pdf->GetY()); $pdf->Line(15, $pdf->GetY(), 15 + $pageW, $pdf->GetY());
@@ -205,18 +197,34 @@ class Rpt_penyerahan_mutasi extends MY_Controller
$startY = $pdf->GetY(); $startY = $pdf->GetY();
$halfW = $pageW / 2; $halfW = $pageW / 2;
$lblW = 30; $lblW = 28;
$valW = $halfW - $lblW - 4; $valW = $halfW - $lblW - 4;
// ── Kolom Kiri ──────────────────────────────────────────────────────── // ── Kolom Kiri ────────────────────────────────────────────────────────
$pdf->SetY($startY); $pdf->SetY($startY);
// Format Jenis Kontrak
$jenisKontrak = '-';
if (!empty($header['JenisKontrak'])) {
$jenisKontrak = ($header['JenisKontrak'] === 'once') ? 'Sekali Bayar (Once)' : 'Berkala (Recurring)';
}
// Periode kontrak
$periodeJasa = '-';
if (!empty($header['StartDate']) && $header['StartDate'] !== '0000-00-00') {
$periodeJasa = $this->_fmt_date($header['StartDate']) . ' s/d ' . $this->_fmt_date($header['EndDate']);
}
// Jumlah Termin/PI
$jumlahPI = '-';
if (intval($header['JumlahPI'] ?? 0) > 0) {
$jumlahPI = $header['JumlahPI'] . ' Kali Pembayaran';
}
$leftItems = array( $leftItems = array(
array('Nomor Handover', $header['MutasiHandoverNumber'], true), array('Nomor', $header['PurchaseOrderNumber'], true),
array('No. Request', $header['MutasiRequestNumber'] ?: '-', false), array('Tanggal', $this->_fmt_date($header['PurchaseOrderDate']), false),
array('Tanggal', $this->_fmt_date($header['MutasiHandoverDate']), false), array('Cabang', $header['M_BranchName'] ?: '-', false),
array('Status', $header['MutasiHandoverStatus'], false),
array('Kategori', $header['itemCategoryName'], false),
); );
foreach ($leftItems as $item) { foreach ($leftItems as $item) {
@@ -232,13 +240,13 @@ class Rpt_penyerahan_mutasi extends MY_Controller
$pdf->Cell($valW, 5, $item[1], 0, 1, 'L'); $pdf->Cell($valW, 5, $item[1], 0, 1, 'L');
} }
// Keterangan (Note) langsung di bawah Status // Keterangan / Note langsung di bawah (tanpa spasi vertikal)
if (!empty($header['MutasiHandoverNote'])) { if (!empty($header['PurchaseOrderNote'])) {
$pdf->SetX(15); $pdf->SetX(15);
$pdf->SetFont('Arial_Narrow', '', 9); $pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, 'Keterangan', 0, 0, 'L'); $pdf->Cell($lblW, 5, 'Keterangan', 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C'); $pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->MultiCell($valW, 5, $header['MutasiHandoverNote'], 0, 'L'); $pdf->MultiCell($valW, 5, $header['PurchaseOrderNote'], 0, 'L');
} }
$leftY = $pdf->GetY(); $leftY = $pdf->GetY();
@@ -247,11 +255,12 @@ class Rpt_penyerahan_mutasi extends MY_Controller
$rightX = 15 + $halfW; $rightX = 15 + $halfW;
$rightItems = array( $rightItems = array(
array('Cabang Asal', $header['branch_asal_name']), array('Supplier', $header['SupplierName'] ?: '-'),
array('Cabang Tujuan', $header['branch_tujuan_name']), array('Alamat Supplier', $header['SupplierAddress'] ?: '-'),
array('Warehouse Tujuan', $header['WarehouseName'] ?: '-'), array('Telp Supplier', $header['SupplierPhone'] ?: '-'),
array('Ruangan Tujuan', $header['M_RuanganName'] ?: '-'), array('Jenis Kontrak', $jenisKontrak),
array('Dibuat Oleh', $header['CreatedByName']), array('Periode Jasa', $periodeJasa),
array('Termin Bayar', $jumlahPI),
); );
foreach ($rightItems as $item) { foreach ($rightItems as $item) {
@@ -260,27 +269,13 @@ class Rpt_penyerahan_mutasi extends MY_Controller
$pdf->Cell($lblW, 5, $item[0], 0, 0, 'L'); $pdf->Cell($lblW, 5, $item[0], 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C'); $pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->SetFont('Arial_Narrow', '', 9); $pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($valW, 5, $item[1], 0, 1, 'L');
if ($item[0] === 'Alamat Supplier') {
$pdf->MultiCell($valW, 5, $item[1], 0, 'L');
} else {
$pdf->Cell($valW, 5, $item[1], 0, 1, 'L');
}
} }
// Tanggal terima di kolom kanan
$pdf->SetX($rightX);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, 'Tgl Terima', 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($valW, 5, $this->_fmt_date($header['MutasiHandoverReceiveDate']), 0, 1, 'L');
// Penerima di kolom kanan
if ($header['MutasiHandoverStatus'] === 'Received') {
$pdf->SetX($rightX);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, 'Diterima Oleh', 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($valW, 5, $header['ReceiveByName'] ?: '-', 0, 1, 'L');
}
$rightY = $pdf->GetY(); $rightY = $pdf->GetY();
// Posisikan Y ke yang paling bawah + margin // Posisikan Y ke yang paling bawah + margin
@@ -288,7 +283,7 @@ class Rpt_penyerahan_mutasi extends MY_Controller
} }
// ========================================================================= // =========================================================================
// PDF SECTION: Data — Tabel detail item + ringkasan nilai // PDF SECTION: Data — Tabel detail item
// ========================================================================= // =========================================================================
private function _pdf_data($details) private function _pdf_data($details)
{ {
@@ -298,18 +293,19 @@ class Rpt_penyerahan_mutasi extends MY_Controller
// ── Definisi kolom: [label, lebar, align] ───────────────────────────── // ── Definisi kolom: [label, lebar, align] ─────────────────────────────
// Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan) // Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan)
// 8 + 80 + 20 + 20 + 25 + 27 = 180 // 8 + 65 + 20 + 15 + 25 + 22 + 25 = 180
$cols = array( $cols = array(
array('No', 8, 'C'), array('No', 8, 'C'),
array('Nama Item', 80, 'L'), array('Nama', 65, 'L'),
array('Unit', 20, 'C'), array('Unit', 20, 'C'),
array('Qty', 20, 'R'), array('Qty', 15, 'R'),
array('Nilai Buku', 25, 'R'), array('Harga Satuan', 25, 'R'),
array('Total', 27, 'R'), array('Diskon', 22, 'R'),
array('Total', 25, 'R'),
); );
// Header kolom // Header kolom
$pdf->SetLineWidth(0.3); $pdf->SetLineWidth(0.3); // border medium
$pdf->SetFont('Arial_Narrow', 'B', 8); $pdf->SetFont('Arial_Narrow', 'B', 8);
$pdf->SetFillColor(220, 220, 220); $pdf->SetFillColor(220, 220, 220);
$pdf->SetDrawColor(0, 0, 0); $pdf->SetDrawColor(0, 0, 0);
@@ -319,57 +315,71 @@ class Rpt_penyerahan_mutasi extends MY_Controller
$pdf->Ln(); $pdf->Ln();
// Baris data // Baris data
$pdf->SetLineWidth(0.2); $pdf->SetLineWidth(0.2); // border lebih tipis di data
$pdf->SetFont('Arial_Narrow', '', 8); $pdf->SetFont('Arial_Narrow', '', 8);
$pdf->SetFillColor(255, 255, 255); $pdf->SetFillColor(255, 255, 255);
$no = 1; $no = 1;
$total_val = 0; $subTotal = 0;
foreach ($details as $d) { foreach ($details as $d) {
$bookValue = floatval($d['MutasiHandoverDetailBookValue'] ?? 0); $pdf->Cell($cols[0][1], 6, $no, 1, 0, 'C');
$qty = floatval($d['MutasiHandoverDetailQty'] ?? 0); $pdf->Cell($cols[1][1], 6, $d['M_ItemDesc'] ?: ($d['M_ItemCode'] ?: '-'), 1, 0, 'L');
$lineTotal = $qty * $bookValue; $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[0][1], 6, $no, 1, 0, 'C'); $pdf->Cell($cols[4][1], 6, $this->_fmt_rp($d['SupplierPrice']), 1, 0, 'R');
$pdf->Cell($cols[1][1], 6, $d['M_ItemDesc'] ?: ($d['M_ItemCode'] ?: '-'), 1, 0, 'L'); $pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['DiskonAmount']), 1, 0, 'R');
$pdf->Cell($cols[2][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C'); $pdf->Cell($cols[6][1], 6, $this->_fmt_rp($d['TempTotal']), 1, 0, 'R');
$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->Ln(); $pdf->Ln();
$total_val += $lineTotal; $subTotal += floatval($d['TempTotal']);
$no++; $no++;
} }
// Baris TOTAL $pdf->Ln(2);
$span = array_sum(array_column(array_slice($cols, 0, 5), 1));
$pdf->SetLineWidth(0.3); // ── Ringkasan Biaya di Bagian Kanan Bawah ──────────────────────────────
$pdf->SetFont('Arial_Narrow', 'B', 9); $discountPO = floatval($header['PurchaseOrderDiscountAmount'] ?? 0);
$pdf->SetFillColor(220, 220, 220); $ppnAmount = floatval($header['PurchaseOrderTaxAmountPpn'] ?? 0);
$pdf->Cell($span, 7, 'TOTAL', 1, 0, 'R', true); $pphAmount = floatval($header['PurchaseOrderTaxAmountPph'] ?? 0);
$pdf->Cell($cols[5][1], 7, $this->_fmt_rp($total_val), 1, 0, 'R', true); $shipCost = floatval($header['PurchaseOrderShippingCost'] ?? 0);
$pdf->Ln(); $grandTotal = floatval($header['PurchaseOrderGrandTotal'] ?? ($subTotal - $discountPO + $ppnAmount - $pphAmount + $shipCost));
// ── Ringkasan nilai (rata kanan) ──────────────────────────────────────
$pdf->Ln(3);
$summary = array( $summary = array(
array('Total Nilai Penyerahan', $this->_fmt_rp($header['MutasiHandoverTotalValue'])), array('Subtotal', $this->_fmt_rp($subTotal)),
); );
$cW1 = 50; if ($discountPO > 0) {
$cW2 = 40; $summary[] = array('Diskon PO', '-' . $this->_fmt_rp($discountPO));
$offsetX = 15 + $this->_pageW - $cW1 - $cW2; }
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 = 47;
$cW2 = 25;
$offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 4), 1)); // Sejajar dengan Harga Satuan ke kanan
foreach ($summary as $s) { foreach ($summary as $s) {
$pdf->SetX($offsetX); $pdf->SetX($offsetX);
$pdf->SetFont('Arial_Narrow', '', 8); $pdf->SetFont('Arial_Narrow', '', 8);
$pdf->Cell($cW1, 5, $s[0], 0, 0, 'L'); $pdf->Cell($cW1, 5, $s[0], 0, 0, 'L');
$pdf->SetFont('Arial_Narrow', 'B', 8);
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->Cell($cW2, 5, $s[1], 0, 1, 'R');
} }
$pdf->Ln(4); $pdf->Ln(8);
} }
// ========================================================================= // =========================================================================
@@ -381,10 +391,10 @@ class Rpt_penyerahan_mutasi extends MY_Controller
$pageW = $this->_pageW; $pageW = $this->_pageW;
$terms = array( $terms = array(
'Penyerahan mutasi ini dilakukan berdasarkan dokumen mutasi yang telah disetujui sebelumnya.', 'Purchase Order (PO) Jasa ini tunduk pada syarat dan ketentuan kontrak pengerjaan yang disepakati.',
'Barang yang diserahkan harus sesuai dengan jumlah dan spesifikasi yang tercantum dalam dokumen ini.', 'Seluruh termin pembayaran angsuran jasa harus ditagihkan disertai dengan Berita Acara Serah Terima Jasa (BASTJ).',
'Penerima barang wajib memeriksa dan memverifikasi kesesuaian barang sebelum menerima.', 'Klaim ketidaksesuaian hasil pengerjaan harus dilaporkan langsung ke vendor bersangkutan.',
'Dokumen ini bersifat internal dan hanya digunakan untuk keperluan proses mutasi barang.', 'PO ini sah secara hukum setelah disetujui dan divalidasi secara digital melalui sistem ERP.'
); );
$pdf->SetFont('Arial_Narrow', 'B', 9); $pdf->SetFont('Arial_Narrow', 'B', 9);
@@ -417,6 +427,7 @@ class Rpt_penyerahan_mutasi extends MY_Controller
return number_format(floatval($n), 2, ',', '.'); return number_format(floatval($n), 2, ',', '.');
} }
// format jumlah/qty: tanpa desimal
private function _fmt_qty($n) private function _fmt_qty($n)
{ {
return number_format(floatval($n), 0, ',', '.'); return number_format(floatval($n), 0, ',', '.');

View File

@@ -221,7 +221,6 @@ class Rpt_receive_item_po extends MY_Controller
$leftItems = array( $leftItems = array(
array('Nomor', $header['ReceiveOrderPoNumber'], true), array('Nomor', $header['ReceiveOrderPoNumber'], true),
array('Tanggal', $this->_fmt_date($header['ReceiveOrderPoIDate']), false), array('Tanggal', $this->_fmt_date($header['ReceiveOrderPoIDate']), false),
array('No. Referensi', $header['ReceiveOrderPoRefNumber'] ?: '-', false),
array('No. Surat Jalan', $header['ReceiveOrderPoDONumber'] ?: '-', false), array('No. Surat Jalan', $header['ReceiveOrderPoDONumber'] ?: '-', false),
array('Gudang Penerima', $header['ReceivedWarehouseName'] ?: '-', false), array('Gudang Penerima', $header['ReceivedWarehouseName'] ?: '-', false),
); );
@@ -290,15 +289,14 @@ class Rpt_receive_item_po extends MY_Controller
// ── Definisi kolom: [label, lebar, align] ───────────────────────────── // ── Definisi kolom: [label, lebar, align] ─────────────────────────────
// Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan) // Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan)
// 8 + 45 + 38 + 20 + 15 + 24 + 30 = 180 // 8 + 75 + 23 + 15 + 27 + 32 = 180
$cols = array( $cols = array(
array('No', 8, 'C'), array('No', 8, 'C'),
array('Nama', 45, 'L'), array('Nama', 75, 'L'),
array('No. PO', 38, 'L'), array('Unit', 23, 'C'),
array('Unit', 20, 'C'),
array('Qty', 15, 'C'), array('Qty', 15, 'C'),
array('Harga', 24, 'R'), array('Harga', 27, 'R'),
array('Total', 30, 'R'), array('Total', 32, 'R'),
); );
// Header kolom // Header kolom
@@ -321,11 +319,10 @@ class Rpt_receive_item_po extends MY_Controller
foreach ($details as $d) { foreach ($details as $d) {
$pdf->Cell($cols[0][1], 6, $no, 1, 0, 'C'); $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[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[2][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C');
$pdf->Cell($cols[3][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C'); $pdf->Cell($cols[3][1], 6, $this->_fmt_qty($d['ReceiveOrderPoDetailQty']), 1, 0, 'C');
$pdf->Cell($cols[4][1], 6, $this->_fmt_qty($d['ReceiveOrderPoDetailQty']), 1, 0, 'C'); $pdf->Cell($cols[4][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailPrice']), 1, 0, 'R');
$pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailPrice']), 1, 0, 'R'); $pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailTotal']), 1, 0, 'R');
$pdf->Cell($cols[6][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailTotal']), 1, 0, 'R');
$pdf->Ln(); $pdf->Ln();
$grand_tot += floatval($d['ReceiveOrderPoDetailTotal']); $grand_tot += floatval($d['ReceiveOrderPoDetailTotal']);
@@ -333,12 +330,12 @@ class Rpt_receive_item_po extends MY_Controller
} }
// Baris TOTAL // Baris TOTAL
$span = array_sum(array_column(array_slice($cols, 0, 6), 1)); $span = array_sum(array_column(array_slice($cols, 0, 5), 1));
$pdf->SetLineWidth(0.3); $pdf->SetLineWidth(0.3);
$pdf->SetFont('Arial_Narrow', 'B', 9); // bold + size 9 agar menonjol $pdf->SetFont('Arial_Narrow', 'B', 9); // bold + size 9 agar menonjol
$pdf->SetFillColor(220, 220, 220); $pdf->SetFillColor(220, 220, 220);
$pdf->Cell($span, 7, 'TOTAL', 1, 0, 'R', true); $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->Cell($cols[5][1], 7, $this->_fmt_rp($grand_tot), 1, 0, 'R', true);
$pdf->Ln(6); $pdf->Ln(6);
// Ringkasan Biaya jika ada Biaya Ekspedisi (mendukung fallback dari PO) // Ringkasan Biaya jika ada Biaya Ekspedisi (mendukung fallback dari PO)
@@ -360,9 +357,9 @@ class Rpt_receive_item_po extends MY_Controller
array('Grand Total', $this->_fmt_rp($grandTotal)), array('Grand Total', $this->_fmt_rp($grandTotal)),
); );
$cW1 = 39; $cW1 = 27;
$cW2 = 30; $cW2 = 32;
$offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 4), 1)); $offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 4), 1));
foreach ($summary as $s) { foreach ($summary as $s) {
$pdf->SetX($offsetX); $pdf->SetX($offsetX);

View File

@@ -224,8 +224,6 @@ class Rpt_receive_item_po_inventaris extends MY_Controller
$leftItems = array( $leftItems = array(
array('Nomor', $header['ReceiveOrderPoNumber'], true), array('Nomor', $header['ReceiveOrderPoNumber'], true),
array('Tanggal', $this->_fmt_date($header['ReceiveOrderPoIDate']), false), 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('Gudang Penerima', $header['ReceivedWarehouseName'] ?: '-', false),
array('Ruangan / Lokasi', $header['RuanganName'] ?: '-', false), array('Ruangan / Lokasi', $header['RuanganName'] ?: '-', false),
); );
@@ -261,6 +259,7 @@ class Rpt_receive_item_po_inventaris extends MY_Controller
array('Supplier', $header['SupplierName'] ?: '-'), array('Supplier', $header['SupplierName'] ?: '-'),
array('Alamat Supplier', $header['SupplierAddress'] ?: '-'), array('Alamat Supplier', $header['SupplierAddress'] ?: '-'),
array('Telp Supplier', $header['SupplierPhone'] ?: '-'), array('Telp Supplier', $header['SupplierPhone'] ?: '-'),
array('Cabang', $header['M_BranchName'] ?: '-'),
array('Alamat Penerima', $header['M_BranchAddress'] ?: '-'), array('Alamat Penerima', $header['M_BranchAddress'] ?: '-'),
); );
@@ -294,15 +293,14 @@ class Rpt_receive_item_po_inventaris extends MY_Controller
// ── Definisi kolom: [label, lebar, align] ───────────────────────────── // ── Definisi kolom: [label, lebar, align] ─────────────────────────────
// Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan) // Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan)
// 8 + 45 + 38 + 20 + 15 + 24 + 30 = 180 // 8 + 75 + 23 + 15 + 27 + 32 = 180
$cols = array( $cols = array(
array('No', 8, 'C'), array('No', 8, 'C'),
array('Nama', 45, 'L'), array('Nama', 75, 'L'),
array('No. PO', 38, 'L'), array('Unit', 23, 'C'),
array('Unit', 20, 'C'), array('Qty', 15, 'C'),
array('Qty', 15, 'R'), array('Harga', 27, 'R'),
array('Harga', 24, 'R'), array('Total', 32, 'R'),
array('Total', 30, 'R'),
); );
// Header kolom // Header kolom
@@ -325,11 +323,10 @@ class Rpt_receive_item_po_inventaris extends MY_Controller
foreach ($details as $d) { foreach ($details as $d) {
$pdf->Cell($cols[0][1], 6, $no, 1, 0, 'C'); $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[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[2][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C');
$pdf->Cell($cols[3][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C'); $pdf->Cell($cols[3][1], 6, $this->_fmt_qty($d['ReceiveOrderPoDetailQty']), 1, 0, 'C');
$pdf->Cell($cols[4][1], 6, $this->_fmt_qty($d['ReceiveOrderPoDetailQty']), 1, 0, 'C'); $pdf->Cell($cols[4][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailPrice']), 1, 0, 'R');
$pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailPrice']), 1, 0, 'R'); $pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailTotal']), 1, 0, 'R');
$pdf->Cell($cols[6][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailTotal']), 1, 0, 'R');
$pdf->Ln(); $pdf->Ln();
$grand_tot += floatval($d['ReceiveOrderPoDetailTotal']); $grand_tot += floatval($d['ReceiveOrderPoDetailTotal']);
@@ -337,12 +334,12 @@ class Rpt_receive_item_po_inventaris extends MY_Controller
} }
// Baris TOTAL // Baris TOTAL
$span = array_sum(array_column(array_slice($cols, 0, 6), 1)); $span = array_sum(array_column(array_slice($cols, 0, 5), 1));
$pdf->SetLineWidth(0.3); $pdf->SetLineWidth(0.3);
$pdf->SetFont('Arial_Narrow', 'B', 9); // bold + size 9 agar menonjol $pdf->SetFont('Arial_Narrow', 'B', 9); // bold + size 9 agar menonjol
$pdf->SetFillColor(220, 220, 220); $pdf->SetFillColor(220, 220, 220);
$pdf->Cell($span, 7, 'TOTAL', 1, 0, 'R', true); $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->Cell($cols[5][1], 7, $this->_fmt_rp($grand_tot), 1, 0, 'R', true);
$pdf->Ln(6); $pdf->Ln(6);
// Ringkasan Biaya jika ada Biaya Ekspedisi (mendukung fallback dari PO) // Ringkasan Biaya jika ada Biaya Ekspedisi (mendukung fallback dari PO)
@@ -364,8 +361,8 @@ class Rpt_receive_item_po_inventaris extends MY_Controller
array('Grand Total', $this->_fmt_rp($grandTotal)), array('Grand Total', $this->_fmt_rp($grandTotal)),
); );
$cW1 = 39; $cW1 = 27;
$cW2 = 30; $cW2 = 32;
$offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 4), 1)); $offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 4), 1));
foreach ($summary as $s) { foreach ($summary as $s) {

View File

@@ -99,6 +99,7 @@ class Rpt_receive_order_asset extends MY_Controller
// ── Susun isi halaman ───────────────────────────────────────────── // ── Susun isi halaman ─────────────────────────────────────────────
$this->_pdf_header(); $this->_pdf_header();
$this->_pdf_data($details); $this->_pdf_data($details);
$this->_pdf_inspeksi($details);
$this->_pdf_terms(); $this->_pdf_terms();
// ── Output ──────────────────────────────────────────────────────── // ── Output ────────────────────────────────────────────────────────
@@ -177,13 +178,22 @@ class Rpt_receive_order_asset extends MY_Controller
item.M_ItemDesc, item.M_ItemDesc,
iu.ItemUnitName, iu.ItemUnitName,
iu.ItemUnitCode, iu.ItemUnitCode,
po.PurchaseOrderNumber po.PurchaseOrderNumber,
uP.M_UserUsername AS StaffPenerima,
insp.ReceiveOrderPoInspeksiPengirim AS StaffPengirim,
insp.ReceiveOrderPoInspeksiKeadaanKemasan AS KeadaanKemasan,
insp.ReceiveOrderPoInspeksiKondisiPengiriman AS KondisiPengiriman,
insp.ReceiveOrderPoInspeksiSimpulan AS Simpulan,
insp.ReceiveOrderPoInspeksiCatatan AS CatatanInspeksi
FROM receive_order_po_detail ropd FROM receive_order_po_detail ropd
JOIN m_item item ON item.M_ItemID = ropd.ReceiveOrderPoItemID JOIN m_item item ON item.M_ItemID = ropd.ReceiveOrderPoItemID
AND item.M_ItemIsActive = 'Y' AND item.M_ItemIsActive = 'Y'
LEFT JOIN itemunit iu ON iu.ItemUnitID = ropd.ReceiveOrderPoItemUnitID LEFT JOIN itemunit iu ON iu.ItemUnitID = ropd.ReceiveOrderPoItemUnitID
AND iu.ItemUnitIsActive = 'Y' AND iu.ItemUnitIsActive = 'Y'
LEFT JOIN purchase_order po ON po.PurchaseOrderID = ropd.ReceiveOrderPoDetailPurchaseOrderID LEFT JOIN purchase_order po ON po.PurchaseOrderID = ropd.ReceiveOrderPoDetailPurchaseOrderID
LEFT JOIN receive_order_po_inspeksi insp ON insp.ReceiveOrderPoInspeksiReceiveOrderPoDetailID = ropd.ReceiveOrderPoDetailID
AND insp.ReceiveOrderPoInspeksiIsActive = 'Y'
LEFT JOIN m_user uP ON uP.M_UserID = insp.ReceiveOrderPoInspeksiStaffPenerimaID
WHERE ropd.ReceiveOrderPoDetailIsActive = 'Y' WHERE ropd.ReceiveOrderPoDetailIsActive = 'Y'
AND ropd.ReceiveOrderPoDetailReceiveOrderPoID = ? AND ropd.ReceiveOrderPoDetailReceiveOrderPoID = ?
ORDER BY ropd.ReceiveOrderPoDetailID ASC ORDER BY ropd.ReceiveOrderPoDetailID ASC
@@ -220,7 +230,6 @@ class Rpt_receive_order_asset extends MY_Controller
$leftItems = array( $leftItems = array(
array('Nomor', $header['ReceiveOrderPoNumber'], true), array('Nomor', $header['ReceiveOrderPoNumber'], true),
array('Tanggal', $this->_fmt_date($header['ReceiveOrderPoIDate']), false), array('Tanggal', $this->_fmt_date($header['ReceiveOrderPoIDate']), false),
array('No. Referensi', $header['ReceiveOrderPoRefNumber'] ?: '-', false),
array('Gudang Penerima', $header['ReceivedWarehouseName'] ?: '-', false), array('Gudang Penerima', $header['ReceivedWarehouseName'] ?: '-', false),
); );
@@ -289,15 +298,14 @@ class Rpt_receive_order_asset extends MY_Controller
// ── Definisi kolom: [label, lebar, align] ───────────────────────────── // ── Definisi kolom: [label, lebar, align] ─────────────────────────────
// Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan) // Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan)
// 8 + 45 + 38 + 20 + 15 + 24 + 30 = 180 // 8 + 75 + 23 + 15 + 27 + 32 = 180
$cols = array( $cols = array(
array('No', 8, 'C'), array('No', 8, 'C'),
array('Nama', 45, 'L'), array('Nama', 75, 'L'),
array('No. PO', 38, 'L'), array('Unit', 23, 'C'),
array('Unit', 20, 'C'), array('Qty', 15, 'C'),
array('Qty', 15, 'R'), array('Harga', 27, 'R'),
array('Harga', 24, 'R'), array('Total', 32, 'R'),
array('Total', 30, 'R'),
); );
// Header kolom // Header kolom
@@ -320,11 +328,10 @@ class Rpt_receive_order_asset extends MY_Controller
foreach ($details as $d) { foreach ($details as $d) {
$pdf->Cell($cols[0][1], 6, $no, 1, 0, 'C'); $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[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[2][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C');
$pdf->Cell($cols[3][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C'); $pdf->Cell($cols[3][1], 6, $this->_fmt_qty($d['ReceiveOrderPoDetailQty']), 1, 0, 'C');
$pdf->Cell($cols[4][1], 6, $this->_fmt_qty($d['ReceiveOrderPoDetailQty']), 1, 0, 'C'); $pdf->Cell($cols[4][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailPrice']), 1, 0, 'R');
$pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailPrice']), 1, 0, 'R'); $pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailTotal']), 1, 0, 'R');
$pdf->Cell($cols[6][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailTotal']), 1, 0, 'R');
$pdf->Ln(); $pdf->Ln();
$grand_tot += floatval($d['ReceiveOrderPoDetailTotal']); $grand_tot += floatval($d['ReceiveOrderPoDetailTotal']);
@@ -332,13 +339,12 @@ class Rpt_receive_order_asset extends MY_Controller
} }
// Baris TOTAL // Baris TOTAL
$span = array_sum(array_column(array_slice($cols, 0, 6), 1)); $span = array_sum(array_column(array_slice($cols, 0, 5), 1));
$pdf->SetLineWidth(0.3); $pdf->SetLineWidth(0.3);
$pdf->SetFont('Arial_Narrow', 'B', 9); // bold + size 9 agar menonjol $pdf->SetFont('Arial_Narrow', 'B', 9); // bold + size 9 agar menonjol
$pdf->SetFillColor(220, 220, 220); $pdf->SetFillColor(220, 220, 220);
$pdf->Cell($span, 7, 'TOTAL', 1, 0, 'R', true); $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->Cell($cols[5][1], 7, $this->_fmt_rp($grand_tot), 1, 0, 'R', true);
$pdf->Ln(6);
// Ringkasan Biaya jika ada Biaya Ekspedisi (mendukung fallback dari PO) // Ringkasan Biaya jika ada Biaya Ekspedisi (mendukung fallback dari PO)
$shippingCost = floatval($header['ReceiveOrderShippingCostAmount'] ?? 0); $shippingCost = floatval($header['ReceiveOrderShippingCostAmount'] ?? 0);
@@ -350,7 +356,7 @@ class Rpt_receive_order_asset extends MY_Controller
} }
if ($shippingCost > 0) { if ($shippingCost > 0) {
$pdf->Ln(2); $pdf->Ln(7);
$grandTotal = $grand_tot + $shippingCost; $grandTotal = $grand_tot + $shippingCost;
$statusPaid = ($isPaid === 'Y') ? ' (Lunas)' : ' (Belum Lunas)'; $statusPaid = ($isPaid === 'Y') ? ' (Lunas)' : ' (Belum Lunas)';
$summary = array( $summary = array(
@@ -359,8 +365,8 @@ class Rpt_receive_order_asset extends MY_Controller
array('Grand Total', $this->_fmt_rp($grandTotal)), array('Grand Total', $this->_fmt_rp($grandTotal)),
); );
$cW1 = 39; $cW1 = 27;
$cW2 = 30; $cW2 = 32;
$offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 4), 1)); $offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 4), 1));
foreach ($summary as $s) { foreach ($summary as $s) {
@@ -370,9 +376,79 @@ class Rpt_receive_order_asset extends MY_Controller
$pdf->SetFont('Arial_Narrow', 'B', 8); $pdf->SetFont('Arial_Narrow', 'B', 8);
$pdf->Cell($cW2, 5, $s[1], 0, 1, 'R'); $pdf->Cell($cW2, 5, $s[1], 0, 1, 'R');
} }
$pdf->Ln(8);
} else {
$pdf->Ln(8);
}
}
// PDF SECTION: Inspeksi & Verifikasi Barang / Aset (Blok Terpisah)
// =========================================================================
private function _pdf_inspeksi($details)
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
// Cek apakah ada data inspeksi yang terisi
$hasInspeksi = false;
foreach ($details as $d) {
if (!empty($d['Simpulan']) || !empty($d['StaffPenerima']) || !empty($d['CatatanInspeksi'])) {
$hasInspeksi = true;
break;
}
} }
$pdf->Ln(8); if (!$hasInspeksi) {
return;
}
$pdf->Ln(2);
$pdf->SetFont('Arial_Narrow', 'B', 10);
$pdf->Cell($pageW, 6, 'DETAIL HASIL INSPEKSI BARANG / ASET', 0, 1, 'L');
$pdf->SetLineWidth(0.3);
$pdf->Line(15, $pdf->GetY(), 15 + $pageW, $pdf->GetY());
$pdf->Ln(2);
$no = 1;
foreach ($details as $d) {
// Lewati jika item ini tidak memiliki data inspeksi sama sekali
if (empty($d['Simpulan']) && empty($d['StaffPenerima']) && empty($d['CatatanInspeksi'])) {
continue;
}
$pdf->SetFont('Arial_Narrow', 'B', 9);
$pdf->Cell($pageW, 5, $no . '. ' . ($d['M_ItemDesc'] ?: ($d['M_ItemCode'] ?: '-')), 0, 1, 'L');
// Indentasi isi detail inspeksi
$lblW = 32;
$valW = $pageW - $lblW - 4;
$items = array(
array('Staff Penerima', $d['StaffPenerima'] ?: '-'),
array('Kurir Pengirim', $d['StaffPengirim'] ?: '-'),
array('Keadaan Kemasan', $d['KeadaanKemasan'] ?: '-'),
array('Kondisi Pengiriman', $d['KondisiPengiriman'] ?: '-'),
array('Simpulan Hasil', $d['Simpulan'] ?: '-'),
array('Catatan Inspeksi', $d['CatatanInspeksi'] ?: '-'),
);
foreach ($items as $item) {
$pdf->SetX(18); // Indent slightly to the right
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, $item[0], 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->MultiCell($valW, 5, $item[1], 0, 'L');
}
$pdf->Ln(2);
$pdf->SetDrawColor(200, 200, 200);
$pdf->SetLineWidth(0.1);
$pdf->Line(15, $pdf->GetY(), 15 + $pageW, $pdf->GetY());
$pdf->Ln(2);
$pdf->SetDrawColor(0, 0, 0); // restore black
$no++;
}
} }
// ========================================================================= // =========================================================================

View File

@@ -0,0 +1,600 @@
<?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 ReceiveOrderJasaFpdf extends FPDF
{
public $printUsername = '-';
public $printDate = '';
// Properties untuk tabel multiline
public $widths;
public $aligns;
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 SetWidths($w)
{
$this->widths = $w;
}
public function SetAligns($a)
{
$this->aligns = $a;
}
public function Row($data, $fill = false, $h = 6)
{
// Hitung tinggi maksimum baris berdasarkan multiline
$nb = 0;
for ($i = 0; $i < count($data); $i++) {
$nb = max($nb, $this->NbLines($this->widths[$i], $data[$i]));
}
$rowH = $h * $nb;
// Cek apakah perlu ganti halaman secara otomatis
$this->CheckPageBreak($rowH);
// Gambar cell pada baris
for ($i = 0; $i < count($data); $i++) {
$w = $this->widths[$i];
$a = isset($this->aligns[$i]) ? $this->aligns[$i] : 'L';
$x = $this->GetX();
$y = $this->GetY();
// Gambar border dan background
$this->Rect($x, $y, $w, $rowH, $fill ? 'DF' : 'D');
// Tulis teks menggunakan MultiCell
$this->MultiCell($w, $h, $data[$i], 0, $a);
// Geser posisi X ke kanan untuk cell berikutnya
$this->SetXY($x + $w, $y);
}
// Pindah baris
$this->Ln($rowH);
}
public function CheckPageBreak($h)
{
// Jika tinggi baris melewati batas, buat halaman baru
if ($this->GetY() + $h > $this->PageBreakTrigger) {
$this->AddPage($this->CurOrientation);
}
}
public function NbLines($w, $txt)
{
// Menghitung jumlah baris yang akan dihasilkan oleh MultiCell
$cw = &$this->CurrentFont['cw'];
if ($w == 0) {
$w = $this->w - $this->rMargin - $this->x;
}
$wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
$s = str_replace("\r", '', $txt);
$nb = strlen($s);
if ($nb > 0 && $s[$nb - 1] == "\n") {
$nb--;
}
$sep = -1;
$i = 0;
$j = 0;
$l = 0;
$nl = 1;
while ($i < $nb) {
$c = $s[$i];
if ($c == "\n") {
$i++;
$sep = -1;
$j = $i;
$l = 0;
$nl++;
continue;
}
if ($c == ' ') {
$sep = $i;
}
$l += $cw[$c];
if ($l > $wmax) {
if ($sep == -1) {
if ($i == $j) {
$i++;
}
} else {
$i = $sep + 1;
}
$sep = -1;
$j = $i;
$l = 0;
$nl++;
} else {
$i++;
}
}
return $nl;
}
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_order_jasa extends MY_Controller
{
// ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var ReceiveOrderJasaFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Receive Order Jasa 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 ReceiveOrderJasaFpdf('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_inspeksi($details);
$this->_pdf_terms();
// ── Output ────────────────────────────────────────────────────────
$filename = 'RO_JASA_' . 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
ro.ReceiveOrderPoID,
ro.ReceiveOrderPoNumber,
ro.ReceiveOrderPoIDate,
ro.ReceiveOrderPoRefNumber,
ro.ReceiveOrderPoNote,
ro.ReceiveOrderPoConfirmed,
sup.SupplierName,
sup.SupplierAddress,
sup.SupplierPhone,
b.M_BranchName,
b.M_BranchAddress,
po.PurchaseOrderNumber,
kj.T_KontrakJasaJenisKontrak AS JenisKontrak,
kj.T_KontrakJasaStartDate AS StartDate,
kj.T_KontrakJasaEndDate AS EndDate,
kj.T_KontrakJasaJumlahPI AS JumlahPI,
kj.T_KontrakJasaUsedCount AS UsedCount
FROM receive_order_po ro
JOIN receive_order_po_detail rod ON rod.ReceiveOrderPoDetailReceiveOrderPoID = ro.ReceiveOrderPoID
AND rod.ReceiveOrderPoDetailIsActive = 'Y'
LEFT JOIN purchase_order po ON po.PurchaseOrderID = rod.ReceiveOrderPoDetailPurchaseOrderID
LEFT JOIN supplier sup ON sup.SupplierID = ro.ReceiveOrderPoSupplierID
LEFT JOIN t_kontrak_jasa kj ON kj.T_KontrakJasaPurchaseOrderID = rod.ReceiveOrderPoDetailPurchaseOrderID
AND kj.T_KontrakJasaM_BranchCode = ro.ReceiveOrderPoM_BranchCode
AND kj.T_KontrakJasaIsActive = 'Y'
LEFT JOIN m_branch b ON b.M_BranchCode = ro.ReceiveOrderPoM_BranchCode
WHERE ro.ReceiveOrderPoIsActive = 'Y'
AND ro.ReceiveOrderPoID = ?
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Receive Order Jasa tidak ditemukan");
exit;
}
return $qry->row_array();
}
// =========================================================================
// DATABASE: Ambil data detail
// =========================================================================
private function _get_detail($id)
{
$sql = "
SELECT
rod.ReceiveOrderPoDetailID,
rod.ReceiveOrderPoDetailQty AS Qty,
rod.ReceiveOrderPoDetailPrice AS Price,
(rod.ReceiveOrderPoDetailQty * rod.ReceiveOrderPoDetailPrice) AS TotalPrice,
item.M_ItemCode,
item.M_ItemDesc,
iu.ItemUnitName,
iu.ItemUnitCode,
insp.OrderJasaInspeksiHasilPengerjaan AS HasilPengerjaan,
insp.OrderJasaInspeksiCatatanPengerjaan AS CatatanPengerjaan,
insp.OrderJasaInspeksiKesimpulan AS Kesimpulan,
insp.OrderJasaInspeksiCatatan AS CatatanKesimpulan,
insp.OrderJasaInspeksiPetugasPengerjaan AS Pekerja,
uP.M_UserUsername AS PemeriksaName
FROM receive_order_po_detail rod
JOIN m_item item ON item.M_ItemID = rod.ReceiveOrderPoItemID
AND item.M_ItemIsActive = 'Y'
LEFT JOIN itemunit iu ON iu.ItemUnitID = rod.ReceiveOrderPoItemUnitID
AND iu.ItemUnitIsActive = 'Y'
LEFT JOIN order_jasa_inspeksi insp ON insp.OrderJasaInspeksiReceiveOrderPoDetailID = rod.ReceiveOrderPoDetailID
AND insp.OrderJasaInspeksiIsActive = 'Y'
LEFT JOIN m_user uP ON uP.M_UserID = insp.OrderJasaInspeksiStaffPemeriksaID
WHERE rod.ReceiveOrderPoDetailIsActive = 'Y'
AND rod.ReceiveOrderPoDetailReceiveOrderPoID = ?
ORDER BY rod.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, 'TANDA TERIMA JASA (RECEIVE ORDER SERVICE)', 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);
// Format Jenis Kontrak
$jenisKontrak = '-';
if (!empty($header['JenisKontrak'])) {
$jenisKontrak = ($header['JenisKontrak'] === 'once') ? 'Sekali Bayar (Once)' : 'Berkala (Recurring)';
}
// Periode kontrak
$periodeJasa = '-';
if (!empty($header['StartDate']) && $header['StartDate'] !== '0000-00-00') {
$periodeJasa = $this->_fmt_date($header['StartDate']) . ' s/d ' . $this->_fmt_date($header['EndDate']);
}
// Termin / usedcount
$terminInfo = '-';
if (intval($header['JumlahPI'] ?? 0) > 0) {
$terminInfo = "Termin ke-" . ($header['UsedCount'] ?? 0) . " dari " . $header['JumlahPI'];
}
$leftItems = array(
array('Nomor', $header['ReceiveOrderPoNumber'], true),
array('Tanggal', $this->_fmt_date($header['ReceiveOrderPoIDate']), false),
array('Cabang', $header['M_BranchName'] ?: '-', 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 (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('Jenis Kontrak', $jenisKontrak),
array('Periode Jasa', $periodeJasa),
array('Termin Realisasi', $terminInfo),
);
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 + 75 + 20 + 15 + 30 + 32 = 180
$cols = array(
array('No', 8, 'C'),
array('Nama', 75, 'L'),
array('Unit', 20, 'C'),
array('Qty', 15, 'C'),
array('Harga', 30, 'R'),
array('Total', 32, '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();
// Set lebar dan alignment kolom untuk metode Row()
$pdf->SetWidths(array_column($cols, 1));
$pdf->SetAligns(array_column($cols, 2));
// Baris data
$pdf->SetLineWidth(0.2); // border lebih tipis di data
$pdf->SetFont('Arial_Narrow', '', 8);
$pdf->SetFillColor(255, 255, 255);
$no = 1;
$totalPay = 0;
foreach ($details as $d) {
$row_data = array(
$no,
$d['M_ItemDesc'] ?: ($d['M_ItemCode'] ?: '-'),
$d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'),
$this->_fmt_qty($d['Qty']),
$this->_fmt_rp($d['Price']),
$this->_fmt_rp($d['TotalPrice']),
);
$pdf->Row($row_data);
$totalPay += floatval($d['TotalPrice']);
$no++;
}
// Baris TOTAL
$span = array_sum(array_column(array_slice($cols, 0, 5), 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[5][1], 7, $this->_fmt_rp($totalPay), 1, 0, 'R', true);
$pdf->Ln(8);
}
// =========================================================================
// PDF SECTION: Inspeksi & Verifikasi Jasa (Blok Terpisah)
// =========================================================================
private function _pdf_inspeksi($details)
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
// Cek apakah ada data inspeksi yang terisi
$hasInspeksi = false;
foreach ($details as $d) {
if (!empty($d['HasilPengerjaan']) || !empty($d['Kesimpulan']) || !empty($d['Pekerja'])) {
$hasInspeksi = true;
break;
}
}
if (!$hasInspeksi) {
return;
}
$pdf->Ln(2);
$pdf->SetFont('Arial_Narrow', 'B', 10);
$pdf->Cell($pageW, 6, 'DETAIL HASIL INSPEKSI & VERIFIKASI JASA', 0, 1, 'L');
$pdf->SetLineWidth(0.3);
$pdf->Line(15, $pdf->GetY(), 15 + $pageW, $pdf->GetY());
$pdf->Ln(2);
$no = 1;
foreach ($details as $d) {
// Lewati jika item ini tidak memiliki data inspeksi sama sekali
if (empty($d['HasilPengerjaan']) && empty($d['Kesimpulan']) && empty($d['Pekerja'])) {
continue;
}
$pdf->SetFont('Arial_Narrow', 'B', 9);
$pdf->Cell($pageW, 5, $no . '. ' . ($d['M_ItemDesc'] ?: ($d['M_ItemCode'] ?: '-')), 0, 1, 'L');
// Indentasi isi detail inspeksi
$lblW = 32;
$valW = $pageW - $lblW - 4;
$items = array(
array('Petugas Pengerjaan', $d['Pekerja'] ?: '-'),
array('Staff Pemeriksa', $d['PemeriksaName'] ?: '-'),
array('Hasil Pengerjaan', $d['HasilPengerjaan'] ?: '-'),
array('Catatan Pengerjaan', $d['CatatanPengerjaan'] ?: '-'),
array('Kesimpulan Hasil', $d['Kesimpulan'] ?: '-'),
array('Catatan Pemeriksa', $d['CatatanKesimpulan'] ?: '-'),
);
foreach ($items as $item) {
$pdf->SetX(18); // Indent slightly to the right
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, $item[0], 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->MultiCell($valW, 5, $item[1], 0, 'L');
}
$pdf->Ln(2);
$pdf->SetDrawColor(200, 200, 200);
$pdf->SetLineWidth(0.1);
$pdf->Line(15, $pdf->GetY(), 15 + $pageW, $pdf->GetY());
$pdf->Ln(2);
$pdf->SetDrawColor(0, 0, 0); // restore black
$no++;
}
}
// =========================================================================
// PDF SECTION: Syarat & Ketentuan
// =========================================================================
private function _pdf_terms()
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
$terms = array(
'Penerimaan pengerjaan jasa ini berdasarkan hasil verifikasi/inspeksi petugas di lapangan.',
'Tanda Terima Jasa (TTJ) ini sah untuk digunakan sebagai lampiran dokumen penagihan vendor.',
'Jika terdapat komplain/ketidaksesuaian hasil pengerjaan di kemudian hari, harap merujuk ke Berita Acara inspeksi.',
'Dokumen ini dicetak dan divalidasi secara otomatis 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, ',', '.');
}
}

View File

@@ -216,11 +216,10 @@ class Rpt_receive_transfer extends MY_Controller
$pdf->SetY($startY); $pdf->SetY($startY);
$leftItems = array( $leftItems = array(
array('Nomor SJ', $header['SuratJalanNumber'], true), array('Nomor', $header['SuratJalanNumber'], true),
array('Tanggal SJ', $this->_fmt_date($header['SuratJalanDate']), false), array('Tanggal', $this->_fmt_date($header['SuratJalanDate']), false),
array('Tanggal Terima', $this->_fmt_date($header['SuratJalanReceivedDate']), false), array('Tanggal Terima', $this->_fmt_date($header['SuratJalanReceivedDate']), false),
array('Gudang Terima', $header['ReceivedWarehouseName'] ?: '-', false), array('Gudang Terima', $header['ReceivedWarehouseName'] ?: '-', false),
array('Status', $header['SuratJalanStatus'], false),
); );
foreach ($leftItems as $item) { foreach ($leftItems as $item) {
@@ -289,15 +288,14 @@ class Rpt_receive_transfer extends MY_Controller
// ── Definisi kolom: [label, lebar, align] ───────────────────────────── // ── Definisi kolom: [label, lebar, align] ─────────────────────────────
// Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan) // Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan)
// 8 + 59 + 20 + 20 + 20 + 17 + 36 = 180 // 8 + 95 + 20 + 20 + 20 + 17 = 180
$cols = array( $cols = array(
array('No', 8, 'C'), array('No', 8, 'C'),
array('Nama', 59, 'L'), array('Nama', 95, 'L'),
array('Unit', 20, 'C'), array('Unit', 20, 'C'),
array('Qty Kirim', 20, 'R'), array('Qty Kirim', 20, 'R'),
array('Qty Terima', 20, 'R'), array('Qty Terima', 20, 'R'),
array('Selisih', 17, 'R'), array('Selisih', 17, 'R'),
array('No. PR / Ref', 36, 'L'),
); );
// Header kolom // Header kolom
@@ -327,7 +325,6 @@ class Rpt_receive_transfer extends MY_Controller
$pdf->Cell($cols[3][1], 6, $this->_fmt_qty($qtyKirim), 1, 0, 'C'); $pdf->Cell($cols[3][1], 6, $this->_fmt_qty($qtyKirim), 1, 0, 'C');
$pdf->Cell($cols[4][1], 6, $this->_fmt_qty($qtyTerima), 1, 0, 'C'); $pdf->Cell($cols[4][1], 6, $this->_fmt_qty($qtyTerima), 1, 0, 'C');
$pdf->Cell($cols[5][1], 6, $this->_fmt_qty($selisih), 1, 0, 'C'); $pdf->Cell($cols[5][1], 6, $this->_fmt_qty($selisih), 1, 0, 'C');
$pdf->Cell($cols[6][1], 6, $d['PurchaseRequestNumber'] ?: '-', 1, 0, 'L');
$pdf->Ln(); $pdf->Ln();
$no++; $no++;

View File

@@ -1,410 +0,0 @@
<?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, ',', '.');
}
}

View File

@@ -197,7 +197,7 @@ class Rpt_stock_request extends MY_Controller
array('Nomor', $header['PurchaseRequestNumber'], true), array('Nomor', $header['PurchaseRequestNumber'], true),
array('Ref Nomor', $header['PurchaseRequestRefNumber'] ?: '-', false), array('Ref Nomor', $header['PurchaseRequestRefNumber'] ?: '-', false),
array('Tanggal', $this->_fmt_date($header['PurchaseRequestDate']), false), array('Tanggal', $this->_fmt_date($header['PurchaseRequestDate']), false),
array('Status', $header['PurchaseRequestStatus'], false), array('Tanggal Approved', $this->_fmt_datetime($header['PurchaseRequestApprovedDate'])),
); );
foreach ($leftItems as $item) { foreach ($leftItems as $item) {
@@ -205,7 +205,7 @@ class Rpt_stock_request extends MY_Controller
$pdf->SetFont('Arial_Narrow', '', 9); $pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, $item[0], 0, 0, 'L'); $pdf->Cell($lblW, 5, $item[0], 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C'); $pdf->Cell(4, 5, ':', 0, 0, 'C');
if ($item[2]) { if (isset($item[2]) && $item[2]) {
$pdf->SetFont('Arial_Narrow', 'B', 9); $pdf->SetFont('Arial_Narrow', 'B', 9);
} else { } else {
$pdf->SetFont('Arial_Narrow', '', 9); $pdf->SetFont('Arial_Narrow', '', 9);
@@ -233,7 +233,6 @@ class Rpt_stock_request extends MY_Controller
array('Kategori', $header['itemCategoryName'] ?: '-'), array('Kategori', $header['itemCategoryName'] ?: '-'),
array('Dibuat Oleh', $header['CreatedByName']), array('Dibuat Oleh', $header['CreatedByName']),
array('Disetujui Oleh', $header['ApprovedByName'] ?: '-'), array('Disetujui Oleh', $header['ApprovedByName'] ?: '-'),
array('Tanggal Approved', $this->_fmt_datetime($header['PurchaseRequestApprovedDate'])),
); );
foreach ($rightItems as $item) { foreach ($rightItems as $item) {

View File

@@ -204,7 +204,7 @@ class Rpt_stock_request_np extends MY_Controller
array('Nomor', $header['PurchaseRequestNumber'], true), array('Nomor', $header['PurchaseRequestNumber'], true),
array('Ref Nomor', $header['PurchaseRequestRefNumber'] ?: '-', false), array('Ref Nomor', $header['PurchaseRequestRefNumber'] ?: '-', false),
array('Tanggal', $this->_fmt_date($header['PurchaseRequestDate']), false), array('Tanggal', $this->_fmt_date($header['PurchaseRequestDate']), false),
array('Status', $header['PurchaseRequestStatus'], false), array('Tanggal Approved', $this->_fmt_datetime($header['PurchaseRequestApprovedDate'])),
); );
foreach ($leftItems as $item) { foreach ($leftItems as $item) {
@@ -212,7 +212,7 @@ class Rpt_stock_request_np extends MY_Controller
$pdf->SetFont('Arial_Narrow', '', 9); $pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, $item[0], 0, 0, 'L'); $pdf->Cell($lblW, 5, $item[0], 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C'); $pdf->Cell(4, 5, ':', 0, 0, 'C');
if ($item[2]) { if (isset($item[2]) && $item[2]) {
$pdf->SetFont('Arial_Narrow', 'B', 9); $pdf->SetFont('Arial_Narrow', 'B', 9);
} else { } else {
$pdf->SetFont('Arial_Narrow', '', 9); $pdf->SetFont('Arial_Narrow', '', 9);
@@ -240,7 +240,6 @@ class Rpt_stock_request_np extends MY_Controller
array('Kategori', $header['itemCategoryName'] ?: '-'), array('Kategori', $header['itemCategoryName'] ?: '-'),
array('Dibuat Oleh', $header['CreatedByName']), array('Dibuat Oleh', $header['CreatedByName']),
array('Disetujui Oleh', $header['ApprovedByName'] ?: '-'), array('Disetujui Oleh', $header['ApprovedByName'] ?: '-'),
array('Tanggal Approved', $this->_fmt_datetime($header['PurchaseRequestApprovedDate'])),
); );
foreach ($rightItems as $item) { foreach ($rightItems as $item) {

View File

@@ -211,10 +211,9 @@ class Rpt_surat_jalan extends MY_Controller
$pdf->SetY($startY); $pdf->SetY($startY);
$leftItems = array( $leftItems = array(
array('Nomor SJ', $header['SuratJalanNumber'], true), array('Nomor', $header['SuratJalanNumber'], true),
array('Tanggal SJ', $this->_fmt_date($header['SuratJalanDate']), false), array('Tanggal', $this->_fmt_date($header['SuratJalanDate']), false),
array('No. Transfer', $header['SuratJalanT_GoodsTransferNum'] ?: '-', false), array('No. Transfer', $header['SuratJalanT_GoodsTransferNum'] ?: '-', false),
array('Status', $header['SuratJalanStatus'], false),
); );
foreach ($leftItems as $item) { foreach ($leftItems as $item) {
@@ -283,13 +282,12 @@ class Rpt_surat_jalan extends MY_Controller
// ── Definisi kolom: [label, lebar, align] ───────────────────────────── // ── Definisi kolom: [label, lebar, align] ─────────────────────────────
// Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan) // Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan)
// 8 + 62 + 20 + 20 + 42 + 28 = 180 // 8 + 104 + 20 + 20 + 28 = 180
$cols = array( $cols = array(
array('No', 8, 'C'), array('No', 8, 'C'),
array('Nama', 62, 'L'), array('Nama', 104, 'L'),
array('Unit', 20, 'C'), array('Unit', 20, 'C'),
array('Qty Kirim', 20, 'R'), array('Qty Kirim', 20, 'R'),
array('No. PR / Ref', 42, 'L'),
array('Qty Diterima', 28, 'R'), array('Qty Diterima', 28, 'R'),
); );
@@ -314,8 +312,7 @@ class Rpt_surat_jalan extends MY_Controller
$pdf->Cell($cols[1][1], 6, $d['M_ItemDesc'] ?: ($d['M_ItemCode'] ?: '-'), 1, 0, 'L'); $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[2][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C');
$pdf->Cell($cols[3][1], 6, $this->_fmt_qty($d['SuratJalanDetailQty']), 1, 0, 'C'); $pdf->Cell($cols[3][1], 6, $this->_fmt_qty($d['SuratJalanDetailQty']), 1, 0, 'C');
$pdf->Cell($cols[4][1], 6, $d['PurchaseRequestNumber'] ?: '-', 1, 0, 'L'); $pdf->Cell($cols[4][1], 6, $this->_fmt_qty($d['SuratJalanDetailQtyReceived']), 1, 0, 'C');
$pdf->Cell($cols[5][1], 6, $this->_fmt_qty($d['SuratJalanDetailQtyReceived']), 1, 0, 'C');
$pdf->Ln(); $pdf->Ln();
$no++; $no++;