diff --git a/application/controllers/report/Rpt_payment_voucher.php b/application/controllers/report/Rpt_payment_voucher.php index a7328a1..9081a1f 100644 --- a/application/controllers/report/Rpt_payment_voucher.php +++ b/application/controllers/report/Rpt_payment_voucher.php @@ -40,6 +40,110 @@ class PaymentVoucherFpdf extends FPDF $this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, '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; + } } // ============================================================================= @@ -123,12 +227,15 @@ class Rpt_payment_voucher extends MY_Controller pv.*, cs.coaAccountNo, cs.coaDescription, + ct.coaAccountNo AS coaTempAccountNo, + ct.coaDescription AS coaTempDescription, b.M_BranchName, IFNULL(uCr.M_UserUsername, '') AS CreatedByName, IFNULL(uPd.M_UserUsername, '') AS PaidByName, IFNULL(uRc.M_UserUsername, '') AS PaidReceiveByName FROM payment_voucher pv LEFT JOIN coa cs ON cs.coaID = pv.PaymentVoucherCoaSourceID + LEFT JOIN coa ct ON ct.coaID = pv.PaymentVoucherCoaTemporaryID LEFT JOIN m_branch b ON b.M_BranchCode = pv.PaymentVoucherM_BranchCode LEFT JOIN m_user uCr ON uCr.M_UserID = pv.PaymentVoucherUserID LEFT JOIN m_user uPd ON uPd.M_UserID = pv.PaymentVoucherPaidUserID @@ -145,22 +252,27 @@ class Rpt_payment_voucher extends MY_Controller return $qry->row_array(); } - // ========================================================================= - // DATABASE: Ambil data detail - // ========================================================================= private function _get_detail($id) { $sql = " SELECT pvd.*, prd.PurchaseRequestDirectNumber, - prd.PurchaseRequestDirectDescription, - prd.PurchaseRequestDirectNote + prdd.PurchaseRequestDirectDescription AS ItemDescription, + prdd.PurchaseRequestDirectDetailAccount AS ExpenseAccount, + prdd.PurchaseRequestDirectDetailTotalRealitationPrice, + prdd.PurchaseRequestDirectDetailTotalEstimationPrice, + pdc.PurchaseDirectCategoryName, + c.coaDescription AS ExpenseAccountName FROM payment_voucher_detail pvd - LEFT JOIN purchase_request_direct prd ON prd.PurchaseRequestDirectID = pvd.PaymentVoucherDetailPurchaseRequestDirectID + JOIN purchase_request_direct prd ON prd.PurchaseRequestDirectID = pvd.PaymentVoucherDetailPurchaseRequestDirectID + 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 + ORDER BY pvd.PaymentVoucherDetailID ASC, prdd.PurchaseRequestDirectDetailID ASC "; $qry = $this->db->query($sql, array($id)); return $qry ? $qry->result_array() : array(); @@ -196,24 +308,42 @@ class Rpt_payment_voucher extends MY_Controller $coaSource = $header['coaAccountNo'] . ' - ' . $header['coaDescription']; } + $coaTemp = ''; + if (!empty($header['coaTempAccountNo'])) { + $coaTemp = $header['coaTempAccountNo'] . ' - ' . $header['coaTempDescription']; + } + $leftItems = array( array('Nomor', $header['PaymentVoucherNumber'], true), - array('Tanggal', $this->_fmt_datetime($header['PaymentVoucherDate']), false), + array('Tanggal', $this->_fmt_date($header['PaymentVoucherDate']), false), array('Sumber Dana', $coaSource, false), - array('Status', $header['PaymentVoucherStatus'] ?: '-', false), ); + if ($coaTemp !== '') { + $leftItems[] = array('Akun Transit', $coaTemp, 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'); + $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 / Paid Note langsung di bawah Status (tanpa spasi vertikal) @@ -232,10 +362,8 @@ class Rpt_payment_voucher extends MY_Controller $rightItems = array( array('Cabang', $header['M_BranchName'] ?: '-'), - array('Tgl Pembayaran', $this->_fmt_datetime($header['PaymentVoucherPaidDate'])), + array('Tgl Pembayaran', $this->_fmt_date($header['PaymentVoucherPaidDate'])), array('Dibuat Oleh', $header['CreatedByName'] ?: '-'), - array('Dibayar Oleh', $header['PaidByName'] ?: '-'), - array('Diterima Oleh', $header['PaidReceiveByName'] ?: '-'), ); foreach ($rightItems as $item) { @@ -263,13 +391,13 @@ class Rpt_payment_voucher extends MY_Controller // ── Definisi kolom: [label, lebar, align] ───────────────────────────── // Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan) - // 8 + 42 + 55 + 45 + 30 = 180 + // 8 + 45 + 30 + 72 + 25 = 180 $cols = array( array('No', 8, 'C'), - array('No. Request Direct', 42, 'L'), - array('Deskripsi', 55, 'L'), - array('Catatan PR', 45, 'L'), - array('Nominal Bayar', 30, 'R'), + array('No. Request Direct', 45, 'L'), + array('Kategori', 30, 'L'), + array('Deskripsi', 72, 'L'), + array('Nominal Bayar', 25, 'R'), ); // Header kolom @@ -282,6 +410,10 @@ class Rpt_payment_voucher extends MY_Controller } $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); @@ -290,14 +422,22 @@ class Rpt_payment_voucher extends MY_Controller $totalPay = 0; foreach ($details as $d) { - $pdf->Cell($cols[0][1], 6, $no, 1, 0, 'C'); - $pdf->Cell($cols[1][1], 6, $d['PurchaseRequestDirectNumber'] ?: '-', 1, 0, 'L'); - $pdf->Cell($cols[2][1], 6, $d['PurchaseRequestDirectDescription'] ?: '-', 1, 0, 'L'); - $pdf->Cell($cols[3][1], 6, $d['PurchaseRequestDirectNote'] ?: '-', 1, 0, 'L'); - $pdf->Cell($cols[4][1], 6, $this->_fmt_rp($d['PaymentVoucherDetailTotal']), 1, 0, 'R'); - $pdf->Ln(); + $amount = floatval($d['PurchaseRequestDirectDetailTotalRealitationPrice']); + if ($amount <= 0) { + $amount = floatval($d['PurchaseRequestDirectDetailTotalEstimationPrice']); + } - $totalPay += floatval($d['PaymentVoucherDetailTotal']); + $row_data = array( + $no, + $d['PurchaseRequestDirectNumber'] ?: '-', + $d['PurchaseDirectCategoryName'] ?: '-', + $d['ItemDescription'] ?: '-', + $this->_fmt_rp($amount), + ); + + $pdf->Row($row_data); + + $totalPay += $amount; $no++; } diff --git a/application/controllers/report/Rpt_pr_direct.php b/application/controllers/report/Rpt_pr_direct.php index 26a8420..96caf33 100644 --- a/application/controllers/report/Rpt_pr_direct.php +++ b/application/controllers/report/Rpt_pr_direct.php @@ -182,17 +182,47 @@ class Rpt_pr_direct extends MY_Controller $pdf->Line(15, $pdf->GetY(), 15 + $pageW, $pdf->GetY()); $pdf->Ln(2); - // ── Info dokumen: 2 kolom (kiri & kanan) ───────────────────────────── - $half = $pageW / 2; - $lbl = 30; - $val = $half - $lbl - 4; + $startY = $pdf->GetY(); + $half = $pageW / 2; + $lbl = 28; + $val = $half - $lbl - 4; + + // ── Kolom Kiri ──────────────────────────────────────────────────────── + $pdf->SetY($startY); $left = array( - array('Nomor', $header['PurchaseRequestDirectNumber']), - array('Tanggal', $this->_fmt_date($header['PurchaseRequestDirectDate'])), - array('Tanggal Pelaksanaan', $this->_fmt_date($header['PurchaseRequestDirectDateUse'])), - array('Status', $header['PurchaseRequestDirectStatus']), + array('Nomor', $header['PurchaseRequestDirectNumber'], true), + array('Tanggal', $this->_fmt_date($header['PurchaseRequestDirectDate']), false), + array('Tanggal Pelaksanaan', $this->_fmt_date($header['PurchaseRequestDirectDateUse']), false), ); + + 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( array('Cabang', $header['M_BranchName']), array('Regional', $header['S_RegionalName']), @@ -200,43 +230,22 @@ class Rpt_pr_direct extends MY_Controller array('Dibuat Oleh', $header['CreatedByName']), ); - $maxRow = max(count($left), count($right)); - for ($i = 0; $i < $maxRow; $i++) { - // 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'])) { + foreach ($right as $item) { + $pdf->SetX($rightX); $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($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); } // ========================================================================= diff --git a/application/controllers/report/Rpt_pr_direct_approval.php b/application/controllers/report/Rpt_pr_direct_approval.php index 310331c..dd65431 100644 --- a/application/controllers/report/Rpt_pr_direct_approval.php +++ b/application/controllers/report/Rpt_pr_direct_approval.php @@ -202,7 +202,7 @@ class Rpt_pr_direct_approval extends MY_Controller array('Nomor', $header['PurchaseRequestDirectNumber'], true), array('Tanggal', $this->_fmt_date($header['PurchaseRequestDirectDate']), 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) { @@ -210,7 +210,7 @@ class Rpt_pr_direct_approval extends MY_Controller $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 (isset($item[2]) && $item[2]) { $pdf->SetFont('Arial_Narrow', 'B', 9); } else { $pdf->SetFont('Arial_Narrow', '', 9); @@ -245,7 +245,6 @@ class Rpt_pr_direct_approval extends MY_Controller array('Alamat', $header['M_BranchAddress']), array('Dibuat Oleh', $header['CreatedByName']), array('Disetujui Oleh', $header['ApprovedByName']), - array('Tanggal Approved', $this->_fmt_datetime($header['PurchaseRequestDirectApprovedDate'])), ); foreach ($rightItems as $item) { diff --git a/application/controllers/report/Rpt_purchase_order_asset.php b/application/controllers/report/Rpt_purchase_order_asset.php index 6135e62..474bddc 100644 --- a/application/controllers/report/Rpt_purchase_order_asset.php +++ b/application/controllers/report/Rpt_purchase_order_asset.php @@ -225,9 +225,8 @@ class Rpt_purchase_order_asset extends MY_Controller } $leftItems = array( - array('Nomor PO', $header['PurchaseOrderNumber'], true), - array('Tanggal PO', $this->_fmt_date($header['PurchaseOrderDate']), false), - array('No. Referensi', $header['PurchaseOrderRefNumber'] ?: '-', false), + array('Nomor', $header['PurchaseOrderNumber'], true), + array('Tanggal', $this->_fmt_date($header['PurchaseOrderDate']), false), array('Nama Kontrak', $header['ContractName'] ?: '-', false), array('Tanggal Kontrak', $this->_fmt_date($header['ContractDate']), false), array('Periode Kontrak', $periodeKontrak, false), diff --git a/application/controllers/report/Rpt_purchase_order_jasa.php b/application/controllers/report/Rpt_purchase_order_jasa.php new file mode 100644 index 0000000..a30d71b --- /dev/null +++ b/application/controllers/report/Rpt_purchase_order_jasa.php @@ -0,0 +1,440 @@ +AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular + $this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold) + } + + public function Footer() + { + $pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15 + + // ── Posisi: 20mm dari bawah halaman ────────────────────────────────── + $this->SetY(-20); + + // ── Baris 1: Print Oleh (kiri) | Nomor Halaman (tengah) ─────────────── + $colSide = ($pageW - 40) / 2; + $colCenter = 40; + + $this->SetFont('Arial_Narrow', '', 7); + $this->Cell($colSide, 4, 'Print Oleh : ' . $this->printUsername, 0, 0, 'L'); + $this->Cell($colCenter, 4, $this->PageNo() . ' / {nb}', 0, 0, 'C'); + $this->Cell($colSide, 4, '', 0, 1, 'R'); + + // ── Baris 2: Tgl Print (kiri) ────────────────────────────────────────── + $this->SetFont('Arial_Narrow', '', 7); + $this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L'); + $this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L'); + } +} + +// ============================================================================= +// Controller +// ============================================================================= +class Rpt_purchase_order_jasa extends MY_Controller +{ + // ── Properti bersama antar fungsi PDF ───────────────────────────────────── + /** @var PurchaseOrderJasaFpdf */ + private $_pdf; + private $_pageW; + private $_header_data; + private $_username; + + public function __construct() + { + parent::__construct(); + } + + public function index() + { + echo "Purchase Order Jasa Report API"; + } + + // ========================================================================= + // ENDPOINT: pdf + // GET/POST: id (PurchaseOrderID), username (opsional) + // ========================================================================= + public function pdf() + { + try { + $id = intval($this->input->get_post('id')); + $username = trim($this->input->get_post('username') ?? ''); + + if ($id <= 0) { + $this->sys_error("ID tidak valid"); + exit; + } + + // ── Ambil data header & detail dari DB ──────────────────────────── + $header = $this->_get_header($id); + $details = $this->_get_detail($id); + + // ── Inisialisasi FPDF custom ────────────────────────────────────── + $this->_pdf = new PurchaseOrderJasaFpdf('P', 'mm', 'A4'); + $this->_pdf->printUsername = $username !== '' ? $username : '-'; + $this->_pdf->printDate = date('d-m-Y H:i:s'); + $this->_pageW = $this->_pdf->GetPageWidth() - 30; + $this->_header_data = $header; + $this->_username = $this->_pdf->printUsername; + + $this->_pdf->AliasNbPages(); // aktifkan alias total halaman + $this->_pdf->SetMargins(15, 15, 15); + $this->_pdf->SetAutoPageBreak(true, 22); // 22mm ruang footer di bawah + $this->_pdf->AddPage(); + + // ── Susun isi halaman ───────────────────────────────────────────── + $this->_pdf_header(); + $this->_pdf_data($details); + $this->_pdf_terms(); + + // ── Output ──────────────────────────────────────────────────────── + $filename = 'PO_JASA_' . str_replace('/', '-', $header['PurchaseOrderNumber']) . '.pdf'; + header('Content-Type: application/pdf'); + header('Content-Disposition: inline; filename="' . $filename . '"'); + header('Cache-Control: private, max-age=0, must-revalidate'); + header('Pragma: public'); + echo $this->_pdf->Output('S'); + } catch (Exception $exc) { + $this->sys_error($exc->getMessage()); + } + } + + // ========================================================================= + // DATABASE: Ambil data header + // ========================================================================= + private function _get_header($id) + { + $sql = " + SELECT + po.*, + sup.SupplierName, + sup.SupplierAddress, + sup.SupplierPhone, + b.M_BranchName, + b.M_BranchAddress, + r.S_RegionalName, + kj.T_KontrakJasaJenisKontrak AS JenisKontrak, + kj.T_KontrakJasaStartDate AS StartDate, + kj.T_KontrakJasaEndDate AS EndDate, + kj.T_KontrakJasaJumlahPI AS JumlahPI, + kj.T_KontrakJasaStatus AS StatusKontrak + FROM purchase_order po + LEFT JOIN supplier sup ON sup.SupplierID = po.PurchaseOrderSupplierID + LEFT JOIN s_regional r ON r.S_RegionalID = po.PurchaseOrderS_RegionalID + LEFT JOIN t_kontrak_jasa kj ON kj.T_KontrakJasaPurchaseOrderID = po.PurchaseOrderID + AND kj.T_KontrakJasaIsActive = 'Y' + LEFT JOIN m_branch b ON b.M_BranchCode = kj.T_KontrakJasaM_BranchCode + WHERE po.PurchaseOrderIsActive = 'Y' + AND po.PurchaseOrderID = ? + LIMIT 1 + "; + $qry = $this->db->query($sql, array($id)); + if (!$qry || $qry->num_rows() === 0) { + $this->sys_error("Data Purchase Order Jasa tidak ditemukan"); + exit; + } + return $qry->row_array(); + } + + // ========================================================================= + // DATABASE: Ambil data detail + // ========================================================================= + private function _get_detail($id) + { + $sql = " + SELECT + pos.PurchaseOrderSummaryQty AS RequestQty, + pos.PurchaseOrderSummaryPrice AS SupplierPrice, + pos.PurchaseOrderSummaryDiscountAmount AS DiskonAmount, + pos.PurchaseOrderSummaryTotal AS TempTotal, + item.M_ItemCode, + item.M_ItemDesc, + iu.ItemUnitName, + iu.ItemUnitCode + FROM purchase_order_summary pos + JOIN m_item item ON item.M_ItemID = pos.PurchaseOrderSummaryItemID + AND item.M_ItemIsActive = 'Y' + LEFT JOIN itemunit iu ON iu.ItemUnitID = pos.PurchaseOrderSummaryItemUnitID + AND iu.ItemUnitIsActive = 'Y' + WHERE pos.PurchaseOrderSummaryIsActive = 'Y' + AND pos.PurchaseOrderSummaryPurchaseOrderID = ? + ORDER BY pos.PurchaseOrderSummaryID ASC + "; + $qry = $this->db->query($sql, array($id)); + return $qry ? $qry->result_array() : array(); + } + + // ========================================================================= + // PDF SECTION: Header — Judul + Informasi Dokumen (2 kolom) + // ========================================================================= + private function _pdf_header() + { + $pdf = $this->_pdf; + $pageW = $this->_pageW; + $header = $this->_header_data; + + // ── Judul utama ─────────────────────────────────────────────────────── + $pdf->SetFont('Arial_Narrow', 'B', 14); + $pdf->Cell($pageW, 8, 'PURCHASE ORDER JASA (SERVICE PO)', 0, 1, 'L'); + $pdf->SetDrawColor(0, 0, 0); + $pdf->SetLineWidth(0.5); + $pdf->Line(15, $pdf->GetY(), 15 + $pageW, $pdf->GetY()); + $pdf->Ln(2); + + $startY = $pdf->GetY(); + $halfW = $pageW / 2; + $lblW = 28; + $valW = $halfW - $lblW - 4; + + // ── Kolom Kiri ──────────────────────────────────────────────────────── + $pdf->SetY($startY); + + // 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( + array('Nomor', $header['PurchaseOrderNumber'], true), + array('Tanggal', $this->_fmt_date($header['PurchaseOrderDate']), 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['PurchaseOrderNote'])) { + $pdf->SetX(15); + $pdf->SetFont('Arial_Narrow', '', 9); + $pdf->Cell($lblW, 5, 'Keterangan', 0, 0, 'L'); + $pdf->Cell(4, 5, ':', 0, 0, 'C'); + $pdf->MultiCell($valW, 5, $header['PurchaseOrderNote'], 0, 'L'); + } + $leftY = $pdf->GetY(); + + // ── Kolom Kanan ─────────────────────────────────────────────────────── + $pdf->SetY($startY); + $rightX = 15 + $halfW; + + $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 Bayar', $jumlahPI), + ); + + 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 + 65 + 20 + 15 + 25 + 22 + 25 = 180 + $cols = array( + array('No', 8, 'C'), + array('Nama', 65, 'L'), + array('Unit', 20, 'C'), + array('Qty', 15, 'R'), + array('Harga Satuan', 25, 'R'), + array('Diskon', 22, 'R'), + array('Total', 25, 'R'), + ); + + // Header kolom + $pdf->SetLineWidth(0.3); // border medium + $pdf->SetFont('Arial_Narrow', 'B', 8); + $pdf->SetFillColor(220, 220, 220); + $pdf->SetDrawColor(0, 0, 0); + foreach ($cols as $c) { + $pdf->Cell($c[1], 7, $c[0], 1, 0, 'C', true); + } + $pdf->Ln(); + + // Baris data + $pdf->SetLineWidth(0.2); // border lebih tipis di data + $pdf->SetFont('Arial_Narrow', '', 8); + $pdf->SetFillColor(255, 255, 255); + $no = 1; + $subTotal = 0; + + foreach ($details as $d) { + $pdf->Cell($cols[0][1], 6, $no, 1, 0, 'C'); + $pdf->Cell($cols[1][1], 6, $d['M_ItemDesc'] ?: ($d['M_ItemCode'] ?: '-'), 1, 0, 'L'); + $pdf->Cell($cols[2][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C'); + $pdf->Cell($cols[3][1], 6, $this->_fmt_qty($d['RequestQty']), 1, 0, 'C'); + $pdf->Cell($cols[4][1], 6, $this->_fmt_rp($d['SupplierPrice']), 1, 0, 'R'); + $pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['DiskonAmount']), 1, 0, 'R'); + $pdf->Cell($cols[6][1], 6, $this->_fmt_rp($d['TempTotal']), 1, 0, 'R'); + $pdf->Ln(); + + $subTotal += floatval($d['TempTotal']); + $no++; + } + + $pdf->Ln(2); + + // ── Ringkasan Biaya di Bagian Kanan Bawah ────────────────────────────── + $discountPO = floatval($header['PurchaseOrderDiscountAmount'] ?? 0); + $ppnAmount = floatval($header['PurchaseOrderTaxAmountPpn'] ?? 0); + $pphAmount = floatval($header['PurchaseOrderTaxAmountPph'] ?? 0); + $shipCost = floatval($header['PurchaseOrderShippingCost'] ?? 0); + $grandTotal = floatval($header['PurchaseOrderGrandTotal'] ?? ($subTotal - $discountPO + $ppnAmount - $pphAmount + $shipCost)); + + $summary = array( + array('Subtotal', $this->_fmt_rp($subTotal)), + ); + + if ($discountPO > 0) { + $summary[] = array('Diskon PO', '-' . $this->_fmt_rp($discountPO)); + } + if ($ppnAmount > 0) { + $summary[] = array('PPN', $this->_fmt_rp($ppnAmount)); + } + if ($pphAmount > 0) { + $summary[] = array('PPH', '-' . $this->_fmt_rp($pphAmount)); + } + if ($shipCost > 0) { + $summary[] = array('Ongkos Kirim', $this->_fmt_rp($shipCost)); + } + $summary[] = array('Grand Total', $this->_fmt_rp($grandTotal)); + + $cW1 = 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) { + $pdf->SetX($offsetX); + $pdf->SetFont('Arial_Narrow', '', 8); + $pdf->Cell($cW1, 5, $s[0], 0, 0, 'L'); + + if ($s[0] === 'Grand Total') { + $pdf->SetFont('Arial_Narrow', 'B', 9); + } else { + $pdf->SetFont('Arial_Narrow', 'B', 8); + } + $pdf->Cell($cW2, 5, $s[1], 0, 1, 'R'); + } + + $pdf->Ln(8); + } + + // ========================================================================= + // PDF SECTION: Syarat & Ketentuan + // ========================================================================= + private function _pdf_terms() + { + $pdf = $this->_pdf; + $pageW = $this->_pageW; + + $terms = array( + 'Purchase Order (PO) Jasa ini tunduk pada syarat dan ketentuan kontrak pengerjaan yang disepakati.', + 'Seluruh termin pembayaran angsuran jasa harus ditagihkan disertai dengan Berita Acara Serah Terima Jasa (BASTJ).', + 'Klaim ketidaksesuaian hasil pengerjaan harus dilaporkan langsung ke vendor bersangkutan.', + 'PO ini sah secara hukum setelah disetujui dan divalidasi secara digital melalui sistem ERP.' + ); + + $pdf->SetFont('Arial_Narrow', 'B', 9); + $pdf->Cell($pageW, 5, 'Syarat & Ketentuan:', 0, 1, 'L'); + + $pdf->SetFont('Arial_Narrow', '', 8); + foreach ($terms as $i => $t) { + $pdf->Cell(6, 5, ($i + 1) . '.', 0, 0, 'R'); + $pdf->Cell($pageW - 6, 5, $t, 0, 1, 'L'); + } + } + + // ========================================================================= + // HELPER: Format tampilan + // ========================================================================= + private function _fmt_date($d) + { + if (!$d || $d === '0000-00-00') return '-'; + return date('d-m-Y', strtotime($d)); + } + + private function _fmt_datetime($d) + { + if (!$d || $d === '0000-00-00 00:00:00') return '-'; + return date('d-m-Y H:i', strtotime($d)); + } + + private function _fmt_num($n) + { + return number_format(floatval($n), 2, ',', '.'); + } + + // format jumlah/qty: tanpa desimal + private function _fmt_qty($n) + { + return number_format(floatval($n), 0, ',', '.'); + } + + private function _fmt_rp($n) + { + return 'Rp ' . number_format(floatval($n), 2, ',', '.'); + } +} diff --git a/application/controllers/report/Rpt_receive_item_po.php b/application/controllers/report/Rpt_receive_item_po.php index 6a6cd7b..080a685 100644 --- a/application/controllers/report/Rpt_receive_item_po.php +++ b/application/controllers/report/Rpt_receive_item_po.php @@ -221,7 +221,6 @@ class Rpt_receive_item_po extends MY_Controller $leftItems = array( array('Nomor', $header['ReceiveOrderPoNumber'], true), array('Tanggal', $this->_fmt_date($header['ReceiveOrderPoIDate']), false), - array('No. Referensi', $header['ReceiveOrderPoRefNumber'] ?: '-', false), array('No. Surat Jalan', $header['ReceiveOrderPoDONumber'] ?: '-', false), array('Gudang Penerima', $header['ReceivedWarehouseName'] ?: '-', false), ); @@ -290,15 +289,14 @@ class Rpt_receive_item_po extends MY_Controller // ── Definisi kolom: [label, lebar, align] ───────────────────────────── // 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( array('No', 8, 'C'), - array('Nama', 45, 'L'), - array('No. PO', 38, 'L'), - array('Unit', 20, 'C'), + array('Nama', 75, 'L'), + array('Unit', 23, 'C'), array('Qty', 15, 'C'), - array('Harga', 24, 'R'), - array('Total', 30, 'R'), + array('Harga', 27, 'R'), + array('Total', 32, 'R'), ); // Header kolom @@ -321,11 +319,10 @@ class Rpt_receive_item_po extends MY_Controller foreach ($details as $d) { $pdf->Cell($cols[0][1], 6, $no, 1, 0, 'C'); $pdf->Cell($cols[1][1], 6, $d['M_ItemDesc'] ?: ($d['M_ItemCode'] ?: '-'), 1, 0, 'L'); - $pdf->Cell($cols[2][1], 6, $d['PurchaseOrderNumber'] ?: '-', 1, 0, 'L'); - $pdf->Cell($cols[3][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C'); - $pdf->Cell($cols[4][1], 6, $this->_fmt_qty($d['ReceiveOrderPoDetailQty']), 1, 0, 'C'); - $pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailPrice']), 1, 0, 'R'); - $pdf->Cell($cols[6][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailTotal']), 1, 0, 'R'); + $pdf->Cell($cols[2][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_rp($d['ReceiveOrderPoDetailPrice']), 1, 0, 'R'); + $pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailTotal']), 1, 0, 'R'); $pdf->Ln(); $grand_tot += floatval($d['ReceiveOrderPoDetailTotal']); @@ -333,12 +330,12 @@ class Rpt_receive_item_po extends MY_Controller } // 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->SetFont('Arial_Narrow', 'B', 9); // bold + size 9 agar menonjol $pdf->SetFillColor(220, 220, 220); $pdf->Cell($span, 7, 'TOTAL', 1, 0, 'R', true); - $pdf->Cell($cols[6][1], 7, $this->_fmt_rp($grand_tot), 1, 0, 'R', true); + $pdf->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) @@ -360,9 +357,9 @@ class Rpt_receive_item_po extends MY_Controller array('Grand Total', $this->_fmt_rp($grandTotal)), ); - $cW1 = 39; - $cW2 = 30; - $offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 4), 1)); + $cW1 = 27; + $cW2 = 32; + $offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 4), 1)); foreach ($summary as $s) { $pdf->SetX($offsetX); diff --git a/application/controllers/report/Rpt_receive_item_po_inventaris.php b/application/controllers/report/Rpt_receive_item_po_inventaris.php index 1276dcd..fe62e20 100644 --- a/application/controllers/report/Rpt_receive_item_po_inventaris.php +++ b/application/controllers/report/Rpt_receive_item_po_inventaris.php @@ -224,8 +224,6 @@ class Rpt_receive_item_po_inventaris extends MY_Controller $leftItems = array( array('Nomor', $header['ReceiveOrderPoNumber'], true), array('Tanggal', $this->_fmt_date($header['ReceiveOrderPoIDate']), false), - array('No. Referensi', $header['ReceiveOrderPoRefNumber'] ?: '-', false), - array('No. Surat Jalan', $header['ReceiveOrderPoDONumber'] ?: '-', false), array('Gudang Penerima', $header['ReceivedWarehouseName'] ?: '-', false), array('Ruangan / Lokasi', $header['RuanganName'] ?: '-', false), ); @@ -261,6 +259,7 @@ class Rpt_receive_item_po_inventaris extends MY_Controller array('Supplier', $header['SupplierName'] ?: '-'), array('Alamat Supplier', $header['SupplierAddress'] ?: '-'), array('Telp Supplier', $header['SupplierPhone'] ?: '-'), + array('Cabang', $header['M_BranchName'] ?: '-'), array('Alamat Penerima', $header['M_BranchAddress'] ?: '-'), ); @@ -294,15 +293,14 @@ class Rpt_receive_item_po_inventaris extends MY_Controller // ── Definisi kolom: [label, lebar, align] ───────────────────────────── // 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( array('No', 8, 'C'), - array('Nama', 45, 'L'), - array('No. PO', 38, 'L'), - array('Unit', 20, 'C'), - array('Qty', 15, 'R'), - array('Harga', 24, 'R'), - array('Total', 30, 'R'), + array('Nama', 75, 'L'), + array('Unit', 23, 'C'), + array('Qty', 15, 'C'), + array('Harga', 27, 'R'), + array('Total', 32, 'R'), ); // Header kolom @@ -325,11 +323,10 @@ class Rpt_receive_item_po_inventaris extends MY_Controller foreach ($details as $d) { $pdf->Cell($cols[0][1], 6, $no, 1, 0, 'C'); $pdf->Cell($cols[1][1], 6, $d['M_ItemDesc'] ?: ($d['M_ItemCode'] ?: '-'), 1, 0, 'L'); - $pdf->Cell($cols[2][1], 6, $d['PurchaseOrderNumber'] ?: '-', 1, 0, 'L'); - $pdf->Cell($cols[3][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C'); - $pdf->Cell($cols[4][1], 6, $this->_fmt_qty($d['ReceiveOrderPoDetailQty']), 1, 0, 'C'); - $pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailPrice']), 1, 0, 'R'); - $pdf->Cell($cols[6][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailTotal']), 1, 0, 'R'); + $pdf->Cell($cols[2][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_rp($d['ReceiveOrderPoDetailPrice']), 1, 0, 'R'); + $pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailTotal']), 1, 0, 'R'); $pdf->Ln(); $grand_tot += floatval($d['ReceiveOrderPoDetailTotal']); @@ -337,12 +334,12 @@ class Rpt_receive_item_po_inventaris extends MY_Controller } // 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->SetFont('Arial_Narrow', 'B', 9); // bold + size 9 agar menonjol $pdf->SetFillColor(220, 220, 220); $pdf->Cell($span, 7, 'TOTAL', 1, 0, 'R', true); - $pdf->Cell($cols[6][1], 7, $this->_fmt_rp($grand_tot), 1, 0, 'R', true); + $pdf->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) @@ -364,8 +361,8 @@ class Rpt_receive_item_po_inventaris extends MY_Controller array('Grand Total', $this->_fmt_rp($grandTotal)), ); - $cW1 = 39; - $cW2 = 30; + $cW1 = 27; + $cW2 = 32; $offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 4), 1)); foreach ($summary as $s) { diff --git a/application/controllers/report/Rpt_receive_order_asset.php b/application/controllers/report/Rpt_receive_order_asset.php index 6251da0..457758b 100644 --- a/application/controllers/report/Rpt_receive_order_asset.php +++ b/application/controllers/report/Rpt_receive_order_asset.php @@ -99,6 +99,7 @@ class Rpt_receive_order_asset extends MY_Controller // ── Susun isi halaman ───────────────────────────────────────────── $this->_pdf_header(); $this->_pdf_data($details); + $this->_pdf_inspeksi($details); $this->_pdf_terms(); // ── Output ──────────────────────────────────────────────────────── @@ -177,13 +178,22 @@ class Rpt_receive_order_asset extends MY_Controller item.M_ItemDesc, iu.ItemUnitName, 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 JOIN m_item item ON item.M_ItemID = ropd.ReceiveOrderPoItemID AND item.M_ItemIsActive = 'Y' LEFT JOIN itemunit iu ON iu.ItemUnitID = ropd.ReceiveOrderPoItemUnitID AND iu.ItemUnitIsActive = 'Y' LEFT JOIN purchase_order po ON po.PurchaseOrderID = ropd.ReceiveOrderPoDetailPurchaseOrderID + 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' AND ropd.ReceiveOrderPoDetailReceiveOrderPoID = ? ORDER BY ropd.ReceiveOrderPoDetailID ASC @@ -220,7 +230,6 @@ class Rpt_receive_order_asset extends MY_Controller $leftItems = array( array('Nomor', $header['ReceiveOrderPoNumber'], true), array('Tanggal', $this->_fmt_date($header['ReceiveOrderPoIDate']), false), - array('No. Referensi', $header['ReceiveOrderPoRefNumber'] ?: '-', false), array('Gudang Penerima', $header['ReceivedWarehouseName'] ?: '-', false), ); @@ -289,15 +298,14 @@ class Rpt_receive_order_asset extends MY_Controller // ── Definisi kolom: [label, lebar, align] ───────────────────────────── // 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( array('No', 8, 'C'), - array('Nama', 45, 'L'), - array('No. PO', 38, 'L'), - array('Unit', 20, 'C'), - array('Qty', 15, 'R'), - array('Harga', 24, 'R'), - array('Total', 30, 'R'), + array('Nama', 75, 'L'), + array('Unit', 23, 'C'), + array('Qty', 15, 'C'), + array('Harga', 27, 'R'), + array('Total', 32, 'R'), ); // Header kolom @@ -320,11 +328,10 @@ class Rpt_receive_order_asset extends MY_Controller foreach ($details as $d) { $pdf->Cell($cols[0][1], 6, $no, 1, 0, 'C'); $pdf->Cell($cols[1][1], 6, $d['M_ItemDesc'] ?: ($d['M_ItemCode'] ?: '-'), 1, 0, 'L'); - $pdf->Cell($cols[2][1], 6, $d['PurchaseOrderNumber'] ?: '-', 1, 0, 'L'); - $pdf->Cell($cols[3][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C'); - $pdf->Cell($cols[4][1], 6, $this->_fmt_qty($d['ReceiveOrderPoDetailQty']), 1, 0, 'C'); - $pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailPrice']), 1, 0, 'R'); - $pdf->Cell($cols[6][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailTotal']), 1, 0, 'R'); + $pdf->Cell($cols[2][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_rp($d['ReceiveOrderPoDetailPrice']), 1, 0, 'R'); + $pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['ReceiveOrderPoDetailTotal']), 1, 0, 'R'); $pdf->Ln(); $grand_tot += floatval($d['ReceiveOrderPoDetailTotal']); @@ -332,13 +339,12 @@ class Rpt_receive_order_asset extends MY_Controller } // 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->SetFont('Arial_Narrow', 'B', 9); // bold + size 9 agar menonjol $pdf->SetFillColor(220, 220, 220); $pdf->Cell($span, 7, 'TOTAL', 1, 0, 'R', true); - $pdf->Cell($cols[6][1], 7, $this->_fmt_rp($grand_tot), 1, 0, 'R', true); - $pdf->Ln(6); + $pdf->Cell($cols[5][1], 7, $this->_fmt_rp($grand_tot), 1, 0, 'R', true); // Ringkasan Biaya jika ada Biaya Ekspedisi (mendukung fallback dari PO) $shippingCost = floatval($header['ReceiveOrderShippingCostAmount'] ?? 0); @@ -350,7 +356,7 @@ class Rpt_receive_order_asset extends MY_Controller } if ($shippingCost > 0) { - $pdf->Ln(2); + $pdf->Ln(7); $grandTotal = $grand_tot + $shippingCost; $statusPaid = ($isPaid === 'Y') ? ' (Lunas)' : ' (Belum Lunas)'; $summary = array( @@ -359,8 +365,8 @@ class Rpt_receive_order_asset extends MY_Controller array('Grand Total', $this->_fmt_rp($grandTotal)), ); - $cW1 = 39; - $cW2 = 30; + $cW1 = 27; + $cW2 = 32; $offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 4), 1)); foreach ($summary as $s) { @@ -370,9 +376,79 @@ class Rpt_receive_order_asset extends MY_Controller $pdf->SetFont('Arial_Narrow', 'B', 8); $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++; + } } // ========================================================================= diff --git a/application/controllers/report/Rpt_receive_order_jasa.php b/application/controllers/report/Rpt_receive_order_jasa.php new file mode 100644 index 0000000..5a6e372 --- /dev/null +++ b/application/controllers/report/Rpt_receive_order_jasa.php @@ -0,0 +1,600 @@ +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, ',', '.'); + } +} diff --git a/application/controllers/report/Rpt_receive_transfer.php b/application/controllers/report/Rpt_receive_transfer.php index b9b7dd8..c2214ae 100644 --- a/application/controllers/report/Rpt_receive_transfer.php +++ b/application/controllers/report/Rpt_receive_transfer.php @@ -216,11 +216,10 @@ class Rpt_receive_transfer extends MY_Controller $pdf->SetY($startY); $leftItems = array( - array('Nomor SJ', $header['SuratJalanNumber'], true), - array('Tanggal SJ', $this->_fmt_date($header['SuratJalanDate']), false), + array('Nomor', $header['SuratJalanNumber'], true), + array('Tanggal', $this->_fmt_date($header['SuratJalanDate']), false), array('Tanggal Terima', $this->_fmt_date($header['SuratJalanReceivedDate']), false), array('Gudang Terima', $header['ReceivedWarehouseName'] ?: '-', false), - array('Status', $header['SuratJalanStatus'], false), ); foreach ($leftItems as $item) { @@ -289,15 +288,14 @@ class Rpt_receive_transfer extends MY_Controller // ── Definisi kolom: [label, lebar, align] ───────────────────────────── // 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( array('No', 8, 'C'), - array('Nama', 59, 'L'), + array('Nama', 95, 'L'), array('Unit', 20, 'C'), array('Qty Kirim', 20, 'R'), array('Qty Terima', 20, 'R'), array('Selisih', 17, 'R'), - array('No. PR / Ref', 36, 'L'), ); // 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[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[6][1], 6, $d['PurchaseRequestNumber'] ?: '-', 1, 0, 'L'); $pdf->Ln(); $no++; diff --git a/application/controllers/report/Rpt_stock_request.php b/application/controllers/report/Rpt_stock_request.php index bc62fb8..1718698 100644 --- a/application/controllers/report/Rpt_stock_request.php +++ b/application/controllers/report/Rpt_stock_request.php @@ -197,7 +197,7 @@ class Rpt_stock_request extends MY_Controller array('Nomor', $header['PurchaseRequestNumber'], true), array('Ref Nomor', $header['PurchaseRequestRefNumber'] ?: '-', 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) { @@ -205,7 +205,7 @@ class Rpt_stock_request extends MY_Controller $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 (isset($item[2]) && $item[2]) { $pdf->SetFont('Arial_Narrow', 'B', 9); } else { $pdf->SetFont('Arial_Narrow', '', 9); @@ -233,7 +233,6 @@ class Rpt_stock_request extends MY_Controller array('Kategori', $header['itemCategoryName'] ?: '-'), array('Dibuat Oleh', $header['CreatedByName']), array('Disetujui Oleh', $header['ApprovedByName'] ?: '-'), - array('Tanggal Approved', $this->_fmt_datetime($header['PurchaseRequestApprovedDate'])), ); foreach ($rightItems as $item) { diff --git a/application/controllers/report/Rpt_stock_request_np.php b/application/controllers/report/Rpt_stock_request_np.php index 28478c4..a4ba32a 100644 --- a/application/controllers/report/Rpt_stock_request_np.php +++ b/application/controllers/report/Rpt_stock_request_np.php @@ -204,7 +204,7 @@ class Rpt_stock_request_np extends MY_Controller array('Nomor', $header['PurchaseRequestNumber'], true), array('Ref Nomor', $header['PurchaseRequestRefNumber'] ?: '-', 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) { @@ -212,7 +212,7 @@ class Rpt_stock_request_np extends MY_Controller $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 (isset($item[2]) && $item[2]) { $pdf->SetFont('Arial_Narrow', 'B', 9); } else { $pdf->SetFont('Arial_Narrow', '', 9); @@ -240,7 +240,6 @@ class Rpt_stock_request_np extends MY_Controller array('Kategori', $header['itemCategoryName'] ?: '-'), array('Dibuat Oleh', $header['CreatedByName']), array('Disetujui Oleh', $header['ApprovedByName'] ?: '-'), - array('Tanggal Approved', $this->_fmt_datetime($header['PurchaseRequestApprovedDate'])), ); foreach ($rightItems as $item) { diff --git a/application/controllers/report/Rpt_surat_jalan.php b/application/controllers/report/Rpt_surat_jalan.php index 60c196a..a38c57f 100644 --- a/application/controllers/report/Rpt_surat_jalan.php +++ b/application/controllers/report/Rpt_surat_jalan.php @@ -211,10 +211,9 @@ class Rpt_surat_jalan extends MY_Controller $pdf->SetY($startY); $leftItems = array( - array('Nomor SJ', $header['SuratJalanNumber'], true), - array('Tanggal SJ', $this->_fmt_date($header['SuratJalanDate']), false), + array('Nomor', $header['SuratJalanNumber'], true), + array('Tanggal', $this->_fmt_date($header['SuratJalanDate']), false), array('No. Transfer', $header['SuratJalanT_GoodsTransferNum'] ?: '-', false), - array('Status', $header['SuratJalanStatus'], false), ); foreach ($leftItems as $item) { @@ -283,13 +282,12 @@ class Rpt_surat_jalan extends MY_Controller // ── Definisi kolom: [label, lebar, align] ───────────────────────────── // 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( array('No', 8, 'C'), - array('Nama', 62, 'L'), + array('Nama', 104, 'L'), array('Unit', 20, 'C'), array('Qty Kirim', 20, 'R'), - array('No. PR / Ref', 42, 'L'), 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[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[4][1], 6, $d['PurchaseRequestNumber'] ?: '-', 1, 0, 'L'); - $pdf->Cell($cols[5][1], 6, $this->_fmt_qty($d['SuratJalanDetailQtyReceived']), 1, 0, 'C'); + $pdf->Cell($cols[4][1], 6, $this->_fmt_qty($d['SuratJalanDetailQtyReceived']), 1, 0, 'C'); $pdf->Ln(); $no++;