2 Commits

Author SHA1 Message Date
33666a2f5f add: inventaris item coa mapping API 2026-07-09 16:30:53 +07:00
b29ba9f225 add: inventaris coa mapping API 2026-07-09 15:47:24 +07:00
150 changed files with 2247 additions and 29140 deletions

View File

@@ -1,10 +1,8 @@
<?php <?php
class InventarisCoaMapping extends MY_Controller class InventarisCoaMapping extends MY_Controller {
{
var $db; var $db;
public function index() public function index() {
{
echo "Inventaris COA Mapping API"; echo "Inventaris COA Mapping API";
} }
@@ -13,226 +11,8 @@ class InventarisCoaMapping extends MY_Controller
parent::__construct(); parent::__construct();
} }
## QUERY ##
public function getListCoa()
{
try {
if (!$this->isLogin) {
throw new Exception('Invalid token');
}
$para = $this->sys_input;
$keyword = "%" . $para['keyword'] . "%";
$sql = "SELECT
coaID,
coaAccountNo,
coaDescription
FROM coa
WHERE coaIsInput = 'Y'
AND (
coaDescription LIKE ?
OR coaAccountNo LIKE ?
)
AND coaIsActive = 'Y'
LIMIT 15";
$que = $this->db->query($sql, [$keyword, $keyword]);
if (!$que) {
throw new Exception('failed to query data inventaris gol', 1);
}
$data = $que->result_array();
$this->sys_ok($data);
} catch (Exception $e) {
$msg = '[Error] ' . $e->getMessage();
$code = $e->getCode();
if ($code == 0) {
$this->sys_error($msg);
} else {
$this->sys_error_db($msg);
}
exit;
}
}
public function getListInventarisGol()
{
try {
if (!$this->isLogin) {
throw new Exception('Invalid token');
}
$sql = "SELECT
M_InventarisGolID,
M_InventarisGolCode,
M_InventarisGolName
FROM m_inventaris_gol gol
WHERE gol.M_InventarisGolIsActive = 'Y'
AND NOT EXISTS (
SELECT 1
FROM m_inventaris_coa_mapping m
WHERE m.M_InventarisCoaMappingM_InventarisGolID = gol.M_InventarisGolID
AND m.M_InventarisCoaMappingIsActive = 'Y'
);";
$que = $this->db->query($sql);
if (!$que) {
throw new Exception('failed to query data inventaris gol', 1);
}
$data = $que->result_array();
$output = [
'records' => $data,
'total' => count($data)
];
$this->sys_ok($output);
} catch (Exception $e) {
$msg = '[Error] ' . $e->getMessage();
$code = $e->getCode();
if ($code == 0) {
$this->sys_error($msg);
} else {
$this->sys_error_db($msg);
}
exit;
}
}
public function getListInventorygolMapping()
{
try {
if (!$this->isLogin) {
throw new Exception('invalid token');
}
$para = $this->sys_input;
$keyword = "%" . $para['keyword'] . "%";
$limit = 10;
$offset = 0;
if ($para['currpage'] > 0) {
$offset = ($para['currpage'] - 1) * $limit;
}
$sql = "SELECT
M_InventarisGolID,
M_InventarisGolCode,
M_InventarisGolName,
M_InventarisCoaMappingID,
M_InventarisCoaMappingCoaInventarisID,
coaInv.coaAccountNo AS CoaInventarisAccountNo,
coaInv.coaDescription AS CoaInventarisDescription,
M_InventarisCoaMappingCoaHutangID,
coaHtg.coaAccountNo AS CoaHutangAccountNo,
coaHtg.coaDescription AS CoaHutangDescription,
M_InventarisCoaMappingCoaBebanPenyusutanID,
coaBbn.coaAccountNo AS CoaBebanPenyusutanAccountNo,
coaBbn.coaDescription AS CoaBebanPenyusutanDescription,
M_InventarisCoaMappingCoaAkumulasiPenyusutanID,
coaAkm.coaAccountNo AS CoaAkumulasiPenyusutanAccountNo,
coaAkm.coaDescription AS CoaAkumulasiPenyusutanDescription,
M_InventarisCoaMappingCoaLabaPelepasanID,
coaLab.coaAccountNo AS CoaLabaPelepasanAccountNo,
coaLab.coaDescription AS CoaLabaPelepasanDescription,
M_InventarisCoaMappingCoaRugiPelepasanID,
coaRug.coaAccountNo AS CoaRugiPelepasanAccountNo,
coaRug.coaDescription AS CoaRugiPelepasanDescription
FROM m_inventaris_gol
JOIN m_inventaris_coa_mapping
ON M_InventarisCoaMappingM_InventarisGolID = M_InventarisGolID
AND M_InventarisCoaMappingIsActive = 'Y'
AND M_InventarisGolIsActive = 'Y'
AND M_InventarisGolName LIKE ?
LEFT JOIN coa AS coaInv
ON M_InventarisCoaMappingCoaInventarisID = coaInv.coaID
LEFT JOIN coa AS coaHtg
ON M_InventarisCoaMappingCoaHutangID = coaHtg.coaID
LEFT JOIN coa AS coaBbn
ON M_InventarisCoaMappingCoaBebanPenyusutanID = coaBbn.coaID
LEFT JOIN coa AS coaAkm
ON M_InventarisCoaMappingCoaAkumulasiPenyusutanID = coaAkm.coaID
LEFT JOIN coa AS coaLab
ON M_InventarisCoaMappingCoaLabaPelepasanID = coaLab.coaID
LEFT JOIN coa AS coaRug
ON M_InventarisCoaMappingCoaRugiPelepasanID = coaRug.coaID
WHERE M_InventarisGolIsActive = 'Y'";
$sql_data = $sql . " ORDER BY M_InventarisGolID LIMIT ? OFFSET ? ";
$que = $this->db->query($sql_data, [
$keyword,
$limit,
$offset
]);
if (!$que) {
throw new Exception('failed to query data mapping coa inventaris golongan', 1);
}
$sql_total = "SELECT COUNT(*) AS total FROM ($sql) AS x";
$que_total = $this->db->query($sql_total, [$keyword]);
if (!$que_total) {
throw new Exception('failed to get total rows data', 1);
}
$this->sys_ok([
"records" => $que->result_array(),
"total" => $que_total->row_array()['total']
]);
} catch (Exception $e) {
$msg = '[Error] ' . $e->getMessage();
$code = $e->getCode();
if ($code == 0) {
$this->sys_error($msg);
} else {
$this->sys_error_db($msg);
}
exit;
}
}
public function getInvCoaMappingDetail()
{
try {
if (!$this->isLogin) {
$this->sys_error("invalid token");
exit;
}
$para = $this->sys_input;
$sql = "SELECT
M_InventarisCoaMappingID,
M_InventarisCoaMappingM_InventarisGolID,
M_InventarisCoaMappingCoaInventarisID,
M_InventarisCoaMappingCoaHutangID,
M_InventarisCoaMappingCoaPembelianID,
M_InventarisCoaMappingCoaBebanPenyusutanID,
M_InventarisCoaMappingCoaAkumulasiPenyusutanID,
M_InventarisCoaMappingCoaLabaPelepasanID,
M_InventarisCoaMappingCoaRugiPelepasanID,
M_InventarisCoaMappingCreatedUserID,
M_InventarisCoaMappingCreated,
M_InventarisCoaMappingLastUpdated
FROM m_inventaris_coa_mapping
WHERE M_InventarisCoaMappingIsActive = 'Y'
AND M_InventarisCoaMappingID = ?";
$query = $this->db->query($sql, [$para['M_InventarisCoaMappingID']]);
if (!$query) {
$this->sys_error_db("[Error] get data m_inventaris_coa_mapping");
exit;
}
$data = $query->row_array();
$this->sys_ok($data);
} catch (Exception $exc) {
$msg = $exc->getMessage();
$this->sys_error($msg);
}
}
## MUTATIONS ## ## MUTATIONS ##
public function createInvCoaMapping() public function createInvCoaMapping() {
{
try { try {
if (!$this->isLogin) { if (!$this->isLogin) {
$this->sys_error("invalid token"); $this->sys_error("invalid token");
@@ -284,8 +64,48 @@ class InventarisCoaMapping extends MY_Controller
} }
} }
public function editInvCoaMapping() ## QUERY ##
{ public function getInvCoaMapping() {
try {
if (!$this->isLogin) {
$this->sys_error("invalid token");
exit;
}
$para = $this->sys_input;
$sql = "SELECT
M_InventarisCoaMappingID,
M_InventarisCoaMappingM_InventarisGolID,
M_InventarisCoaMappingCoaInventarisID,
M_InventarisCoaMappingCoaHutangID,
M_InventarisCoaMappingCoaPembelianID,
M_InventarisCoaMappingCoaBebanPenyusutanID,
M_InventarisCoaMappingCoaAkumulasiPenyusutanID,
M_InventarisCoaMappingCoaLabaPelepasanID,
M_InventarisCoaMappingCoaRugiPelepasanID,
M_InventarisCoaMappingCreatedUserID,
M_InventarisCoaMappingCreated,
M_InventarisCoaMappingLastUpdated
FROM m_inventaris_coa_mapping
WHERE M_InventarisCoaMappingIsActive = 'Y'
AND M_InventarisCoaMappingID = ?";
$query = $this->db->query($sql, [$para['M_InventarisCoaMappingID']]);
if (!$query) {
$this->sys_error_db("[Error] get data m_inventaris_coa_mapping");
exit;
}
$data = $query->row_array();
$this->sys_ok($data);
} catch (Exception $exc) {
$msg = $exc->getMessage();
$this->sys_error($msg);
}
}
## MUTATIONS ##
public function editInvCoaMapping() {
try { try {
if (!$this->isLogin) { if (!$this->isLogin) {
$this->sys_error("invalid token"); $this->sys_error("invalid token");
@@ -334,8 +154,7 @@ class InventarisCoaMapping extends MY_Controller
} }
} }
public function deleteInvCoaMapping() public function deleteInvCoaMapping() {
{
try { try {
if (!$this->isLogin) { if (!$this->isLogin) {
$this->sys_error("invalid token"); $this->sys_error("invalid token");
@@ -366,129 +185,8 @@ class InventarisCoaMapping extends MY_Controller
} }
} }
## QUERY ITEM ##
public function getListItemInventaris()
{
try {
if (!$this->isLogin) {
throw new Exception('Invalid token');
}
$para = $this->sys_input;
$sql = "SELECT
M_ItemID,
M_ItemCode,
M_ItemDesc,
M_ItemM_InventarisGolID AS itemGolID,
IFNULL(M_InventarisItemCoaMappingID, 0) AS itemCoaMapID,
M_InventarisItemCoaMappingCoaInventarisID,
coaInv.coaAccountNo AS CoaInventarisAccountNo,
coaInv.coaDescription AS CoaInventarisDescription,
M_InventarisItemCoaMappingCoaHutangID,
coaHtg.coaAccountNo AS CoaHutangAccountNo,
coaHtg.coaDescription AS CoaHutangDescription,
M_InventarisItemCoaMappingCoaBebanPenyusutanID,
coaBbn.coaAccountNo AS CoaBebanPenyusutanAccountNo,
coaBbn.coaDescription AS CoaBebanPenyusutanDescription,
M_InventarisItemCoaMappingCoaAkumulasiPenyusutanID,
coaAkm.coaAccountNo AS CoaAkumulasiPenyusutanAccountNo,
coaAkm.coaDescription AS CoaAkumulasiPenyusutanDescription,
M_InventarisItemCoaMappingCoaLabaPelepasanID,
coaLab.coaAccountNo AS CoaLabaPelepasanAccountNo,
coaLab.coaDescription AS CoaLabaPelepasanDescription,
M_InventarisItemCoaMappingCoaRugiPelepasanID,
coaRug.coaAccountNo AS CoaRugiPelepasanAccountNo,
coaRug.coaDescription AS CoaRugiPelepasanDescription
FROM m_item
LEFT JOIN m_inventaris_item_coa_mapping
ON M_ItemID = M_InventarisItemCoaMappingM_ItemID
AND M_InventarisItemCoaMappingIsActive = 'Y'
LEFT JOIN coa AS coaInv
ON M_InventarisItemCoaMappingCoaInventarisID = coaInv.coaID
LEFT JOIN coa AS coaHtg
ON M_InventarisItemCoaMappingCoaHutangID = coaHtg.coaID
LEFT JOIN coa AS coaBbn
ON M_InventarisItemCoaMappingCoaBebanPenyusutanID = coaBbn.coaID
LEFT JOIN coa AS coaAkm
ON M_InventarisItemCoaMappingCoaAkumulasiPenyusutanID = coaAkm.coaID
LEFT JOIN coa AS coaLab
ON M_InventarisItemCoaMappingCoaLabaPelepasanID = coaLab.coaID
LEFT JOIN coa AS coaRug
ON M_InventarisItemCoaMappingCoaRugiPelepasanID = coaRug.coaID
WHERE M_ItemItem_CategoryID = 2
AND M_ItemM_InventarisGolID = ?
AND M_ItemIsActive = 'Y'";
$que = $this->db->query($sql, [
$para['golID']
]);
if (!$que) {
throw new Exception('failed to query data inventaris gol', 1);
}
$data = $que->result_array();
$output = [
'records' => $data,
'total' => count($data)
];
$this->sys_ok($output);
} catch (Exception $e) {
$msg = '[Error] ' . $e->getMessage();
$code = $e->getCode();
if ($code == 0) {
$this->sys_error($msg);
} else {
$this->sys_error_db($msg);
}
exit;
}
}
public function getInvItemCoaMapping()
{
try {
if (!$this->isLogin) {
$this->sys_error("invalid token");
exit;
}
$para = $this->sys_input;
$sql = "SELECT
M_InventarisItemCoaMappingID,
M_InventarisItemCoaMappingM_ItemID,
M_InventarisItemCoaMappingCoaInventarisID,
M_InventarisItemCoaMappingCoaHutangID,
M_InventarisItemCoaMappingCoaPembelianID,
M_InventarisItemCoaMappingCoaBebanPenyusutanID,
M_InventarisItemCoaMappingCoaAkumulasiPenyusutanID,
M_InventarisItemCoaMappingCoaLabaPelepasanID,
M_InventarisItemCoaMappingCoaRugiPelepasanID,
M_InventarisItemCoaMappingCreatedUserID,
M_InventarisItemCoaMappingCreated,
M_InventarisItemCoaMappingLastUpdated
FROM m_inventaris_item_coa_mapping
WHERE M_InventarisItemCoaMappingIsActive = 'Y'
AND M_InventarisItemCoaMappingID = ?";
$query = $this->db->query($sql, [$para['M_InventarisItemCoaMappingID']]);
if (!$query) {
$this->sys_error_db("[Error] get data m_inventaris_item_coa_mapping");
exit;
}
$data = $query->row_array();
$this->sys_ok($data);
} catch (Exception $exc) {
$msg = $exc->getMessage();
$this->sys_error($msg);
}
}
## MUTATIONS ITEM ## ## MUTATIONS ITEM ##
public function createInvItemCoaMapping() public function createInvItemCoaMapping() {
{
try { try {
if (!$this->isLogin) { if (!$this->isLogin) {
$this->sys_error("invalid token"); $this->sys_error("invalid token");
@@ -533,15 +231,55 @@ class InventarisCoaMapping extends MY_Controller
$insertID = $this->db->insert_id(); $insertID = $this->db->insert_id();
$this->db->trans_commit(); $this->db->trans_commit();
$this->sys_ok("[Success] insert coa item"); $this->sys_ok($insertID);
} catch (Exception $exc) { } catch (Exception $exc) {
$msg = $exc->getMessage(); $msg = $exc->getMessage();
$this->sys_error($msg); $this->sys_error($msg);
} }
} }
public function editInvItemCoaMapping() ## QUERY ITEM ##
{ public function getInvItemCoaMapping() {
try {
if (!$this->isLogin) {
$this->sys_error("invalid token");
exit;
}
$para = $this->sys_input;
$sql = "SELECT
M_InventarisItemCoaMappingID,
M_InventarisItemCoaMappingM_ItemID,
M_InventarisItemCoaMappingCoaInventarisID,
M_InventarisItemCoaMappingCoaHutangID,
M_InventarisItemCoaMappingCoaPembelianID,
M_InventarisItemCoaMappingCoaBebanPenyusutanID,
M_InventarisItemCoaMappingCoaAkumulasiPenyusutanID,
M_InventarisItemCoaMappingCoaLabaPelepasanID,
M_InventarisItemCoaMappingCoaRugiPelepasanID,
M_InventarisItemCoaMappingCreatedUserID,
M_InventarisItemCoaMappingCreated,
M_InventarisItemCoaMappingLastUpdated
FROM m_inventaris_item_coa_mapping
WHERE M_InventarisItemCoaMappingIsActive = 'Y'
AND M_InventarisItemCoaMappingID = ?";
$query = $this->db->query($sql, [$para['M_InventarisItemCoaMappingID']]);
if (!$query) {
$this->sys_error_db("[Error] get data m_inventaris_item_coa_mapping");
exit;
}
$data = $query->row_array();
$this->sys_ok($data);
} catch (Exception $exc) {
$msg = $exc->getMessage();
$this->sys_error($msg);
}
}
## MUTATIONS ITEM ##
public function editInvItemCoaMapping() {
try { try {
if (!$this->isLogin) { if (!$this->isLogin) {
$this->sys_error("invalid token"); $this->sys_error("invalid token");
@@ -590,8 +328,7 @@ class InventarisCoaMapping extends MY_Controller
} }
} }
public function deleteInvItemCoaMapping() public function deleteInvItemCoaMapping() {
{
try { try {
if (!$this->isLogin) { if (!$this->isLogin) {
$this->sys_error("invalid token"); $this->sys_error("invalid token");

View File

@@ -496,7 +496,6 @@ class Fakturv4 extends MY_Controller
ELSE '' ELSE ''
END as WarehouseName, END as WarehouseName,
ReceiveOrderPoID, ReceiveOrderPoID,
ReceiveOrderPoTypePurchase,
PurchaseOrderItemCategoryID PurchaseOrderItemCategoryID
FROM supplier_invoice FROM supplier_invoice
JOIN supplier_invoice_detail ON SupplierInvoiceID = SupplierInvoiceDetailSupplierInvoiceID JOIN supplier_invoice_detail ON SupplierInvoiceID = SupplierInvoiceDetailSupplierInvoiceID
@@ -589,11 +588,12 @@ class Fakturv4 extends MY_Controller
'P' 'P'
) AS DiscountType, ) AS DiscountType,
SupplierInvoiceReceiveOrderPoID, SupplierInvoiceReceiveOrderPoID,
ReceiveOrderPoNumber, ReceiveOrderPoNumber
ReceiveOrderPoTypePurchase AS typePurchase
FROM supplier_invoice FROM supplier_invoice
JOIN supplier ON SupplierInvoiceSupplierID = SupplierID JOIN supplier ON SupplierInvoiceSupplierID = SupplierID
JOIN receive_order_po ON ReceiveOrderPoID = SupplierInvoiceReceiveOrderPoID JOIN receive_order_po ON ReceiveOrderPoID = SupplierInvoiceReceiveOrderPoID
-- JOIN purchase_order ON SupplierInvoicePurchaseOrderID = PurchaseOrderID
-- AND PurchaseOrderIsActive = 'Y'
WHERE SupplierInvoiceIsActive = 'Y' WHERE SupplierInvoiceIsActive = 'Y'
AND SupplierInvoiceID = ?"; AND SupplierInvoiceID = ?";
$que = $this->db->query($sql, $para['SInvoiceID']); $que = $this->db->query($sql, $para['SInvoiceID']);
@@ -601,7 +601,6 @@ class Fakturv4 extends MY_Controller
$this->sys_error_db('[Error] get detail data invoice'); $this->sys_error_db('[Error] get detail data invoice');
exit; exit;
} }
$data = $que->row_array();
$sqldet = "SELECT $sqldet = "SELECT
SupplierInvoiceDetailID, SupplierInvoiceDetailID,
@@ -637,30 +636,7 @@ class Fakturv4 extends MY_Controller
exit; exit;
} }
if (isset($data['typePurchase']) && $data['typePurchase'] == 'aset') { $data = $que->result_array()[0];
$sql_dp = "SELECT
IFNULL(SupplierDownpaymentAmount, 0) AS dp_amount
FROM supplier_invoice
JOIN receive_order_po
ON ReceiveOrderPoID = SupplierInvoiceReceiveOrderPoID
JOIN purchase_order_asset_contract
ON PurchaseOrderAssetContractReceiveOrderPoID = ReceiveOrderPoID
AND PurchaseOrderAssetContractIsActive = 'Y'
JOIN supplier_downpayment
ON SupplierDownpaymentPurchasOrderID = PurchaseOrderAssetContractPurchaseOrderID
AND SupplierDownpaymentIsActive = 'Y'
WHERE SupplierInvoiceID = ?";
$que_dp = $this->db->query($sql_dp, [
$para['SInvoiceID']
]);
if (!$que_dp) {
$this->sys_error_db("[Error] get info contract asset");
exit;
}
$dp_amount = $que_dp->row_array()['dp_amount'];
$data['dp_amount'] = $dp_amount;
}
$data['detail'] = $quedet->result_array(); $data['detail'] = $quedet->result_array();
$result = $data; $result = $data;
@@ -1341,8 +1317,7 @@ class Fakturv4 extends MY_Controller
supplier_invoice_detail.*, supplier_invoice_detail.*,
ReceiveOrderPoNumber, ReceiveOrderPoNumber,
ReceiveOrderPoM_BranchCode, ReceiveOrderPoM_BranchCode,
ReceiveOrderPoS_RegionalID, ReceiveOrderPoS_RegionalID
ReceiveOrderPoTypePurchase AS typePurchase
FROM supplier_invoice FROM supplier_invoice
JOIN supplier_invoice_detail ON SupplierInvoiceDetailSupplierInvoiceID = SupplierInvoiceID JOIN supplier_invoice_detail ON SupplierInvoiceDetailSupplierInvoiceID = SupplierInvoiceID
AND SupplierInvoiceDetailIsActive = 'Y' AND SupplierInvoiceDetailIsActive = 'Y'
@@ -1478,6 +1453,7 @@ class Fakturv4 extends MY_Controller
$coapph = $quepph->result_array()[0]; $coapph = $quepph->result_array()[0];
$pphval = doubleval($invoice[0]['SupplierInvoiceTaxAmountPph']); $pphval = doubleval($invoice[0]['SupplierInvoiceTaxAmountPph']);
if ($pphval > 0.00) { if ($pphval > 0.00) {
$insertpph = $this->InsertJurnalTx( $insertpph = $this->InsertJurnalTx(
$jurnalID, $jurnalID,
@@ -1489,22 +1465,22 @@ class Fakturv4 extends MY_Controller
); );
if (!$insertpph['status']) { if (!$insertpph['status']) {
$this->db->trans_rollback(); $this->db->trans_rollback();
$this->sys_error_db($insertpph['msg']); $this->sys_error_db($insertpajak['msg']);
exit; exit;
} }
} }
# insert shipping cost ke jurnal # # insert shipping cost ke jurnal #
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
if ($ship_cost > 0.00) { $queryshipcost = $this->db->query($sqlcoa, ['5320700001']);
$queryshipcost = $this->db->query($sqlcoa, ['5320700001']); if (!$queryshipcost) {
if (!$queryshipcost) { $this->db->trans_rollback();
$this->db->trans_rollback(); $this->sys_error_db("[Error] get coa cost ");
$this->sys_error_db("[Error] get coa cost "); exit;
exit; }
} $coashipcost = $queryshipcost->result_array()[0];
$coashipcost = $queryshipcost->result_array()[0];
if ($ship_cost > 0.00) {
$insertcost = $this->InsertJurnalTx( $insertcost = $this->InsertJurnalTx(
$jurnalID, $jurnalID,
$coashipcost['coaID'], $coashipcost['coaID'],
@@ -1520,63 +1496,6 @@ class Fakturv4 extends MY_Controller
} }
} }
/* Insert jurnal tx for down payment asset */
// ----------------------------------------------------------------------------------------
if (isset($invoice[0]['typePurchase']) && $invoice[0]['typePurchase'] == 'aset') {
$sql_dpasset = "SELECT
PurchaseOrderAssetContractID,
PurchaseOrderAssetContractName,
SupplierDownpaymentAmount,
coaID,
coaDescription
FROM purchase_order_asset_contract
JOIN purchase_order ON PurchaseOrderID = PurchaseOrderAssetContractPurchaseOrderID
JOIN supplier_downpayment
ON SupplierDownpaymentPurchasOrderID = PurchaseOrderID
AND SupplierDownpaymentIsActive = 'Y'
JOIN purchase_order_detail
ON PurchaseOrderID = PurchaseOrderDetailPurchaseOrderID
AND PurchaseOrderDetailIsActive = 'Y'
JOIN m_item ON M_ItemID = PurchaseOrderDetailItemID
AND M_ItemItem_CategoryID = 3
JOIN fa_class ON Fa_ClassID = M_ItemFa_ClassID
AND Fa_ClassIsActive = 'Y'
JOIN coa ON coaID = Fa_ClassDownPaymentCoaID
AND coaIsActive = 'Y'
WHERE PurchaseOrderAssetContractReceiveOrderPoID = ?
AND PurchaseOrderAssetContractIsActive = 'Y'
LIMIT 1";
$que_dpasset = $this->db->query($sql_dpasset, [
$invoice[0]['SupplierInvoiceReceiveOrderPoID']
]);
if (!$que_dpasset) {
$this->db->trans_rollback();
$this->sys_error_db("[Error] query dp asset not error");
exit;
}
$dpasset_coa = $que_dpasset->row_array();
if (!empty($dpasset_coa)) {
$totalDP = round($dpasset_coa['SupplierDownpaymentAmount'], 2);
if ($totalDP > 0) {
$insert_dp = $this->InsertJurnalTx(
$jurnalID,
$dpasset_coa['coaID'],
$dpasset_coa['coaDescription'],
$user['M_UserID'],
0,
$totalDP
);
if (!$insert_dp['status']) {
$this->db->trans_rollback();
$this->sys_error_db($insert_dp['msg']);
exit;
}
$invoice = $this->CalcProrateDownPaymentAsset($invoice, $totalDP);
}
}
}
// insert jurnal tx hutang per item (kredit) // insert jurnal tx hutang per item (kredit)
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
foreach ($invoice as $key => $inv) { foreach ($invoice as $key => $inv) {
@@ -1684,20 +1603,52 @@ class Fakturv4 extends MY_Controller
$this->sys_error_db($status['msg']); $this->sys_error_db($status['msg']);
exit; exit;
} }
} else if ($item['M_ItemItem_CategoryID'] == '3') { } else if ($item['M_ItemItem_CategoryID'] == '3' && !empty($item['M_ItemFa_ClassID'])) {
$this->InsertJurnalTxAsset($jurnalID, $item['M_ItemID'], $inv, $user['M_UserID']); $sqlsgp = "SELECT * FROM fa_class WHERE Fa_ClassID = ? AND Fa_ClassIsActive = 'Y'";
$quesgp = $this->db->query($sqlsgp, [$item['M_ItemFa_ClassID']]);
if (!$quesgp) {
$this->db->trans_rollback();
$this->sys_error_db("[Error] get map_nat_subgroup");
exit;
}
$itemGroup = $quesgp->row_array();
if (empty($itemGroup)) {
$this->db->trans_rollback();
$this->sys_error_db("[Error] fa class item tidak ditemukan / belum dimapping");
exit;
}
$price = (doubleval($inv['SupplierInvoiceDetailTotal']) - doubleval($inv['SupplierInvoiceDetailDiscountPoProrata']));
// $taxPPH = doubleval($inv['SupplierInvoiceTaxPercentPph']) * $price / 100;
$taxPPN = doubleval($inv['SupplierInvoiceTaxPercentPpn']) * $price / 100;
$kredit = round($price + $taxPPN, 2);
$status = $this->InsertJurnalTx(
$jurnalID,
$itemGroup['Fa_ClassCoaID'],
$itemGroup['Fa_ClassCoaDesc'],
$user['M_UserID'],
0,
$kredit
);
if (!$status) {
$this->sys_error_db($status['msg']);
exit;
}
} else if ($item['M_ItemItem_CategoryID'] == '4') { } else if ($item['M_ItemItem_CategoryID'] == '4') {
$this->InsertJurnalTxJasa($jurnalID, $item['M_ItemID'], $inv, $user['M_UserID']); $this->InsertJurnalTxJasa($jurnalID, $item['M_ItemID'], $inv, $user['M_UserID']);
} }
} }
$sqlinvgr = "INSERT INTO jurnal_addon ( $sqlinvgr = "INSERT INTO jurnal_addon (
jurnalAddOnJurnalID, jurnalAddOnJurnalID,
jurnalAddOnCode, jurnalAddOnCode,
jurnalAddOnValue, jurnalAddOnValue,
jurnalAddOnCreated, jurnalAddOnCreated,
jurnalAddOnCreatedUserID jurnalAddOnCreatedUserID
) VALUES (?,?,?,NOW(),?)"; ) VALUES (?,?,?,NOW(),?)";
$queinvgr = $this->db->query($sqlinvgr, [ $queinvgr = $this->db->query($sqlinvgr, [
$jurnalID, $jurnalID,
'INVGR', 'INVGR',
@@ -1723,13 +1674,13 @@ class Fakturv4 extends MY_Controller
private function InsertJurnalTxJasa($jurnalID, $itemid, $invoice, $userid) private function InsertJurnalTxJasa($jurnalID, $itemid, $invoice, $userid)
{ {
$sql_coa = "SELECT $sql_coa = "SELECT
JasaCoaMapHutangCoaID, JasaCoaMapHutangCoaID,
JasaCoaMapHutangCoaNo, JasaCoaMapHutangCoaNo,
JasaCoaMapHutangCoaDesc JasaCoaMapHutangCoaDesc
FROM jasa_coa_map FROM jasa_coa_map
JOIN coa ON coaID = JasaCoaMapHutangCoaID JOIN coa ON coaID = JasaCoaMapHutangCoaID
AND coaIsActive = 'Y' AND coaIsActive = 'Y'
WHERE JasaCoaMapM_ItemID = ?"; WHERE JasaCoaMapM_ItemID = ?";
$que_coa = $this->db->query($sql_coa, [$itemid]); $que_coa = $this->db->query($sql_coa, [$itemid]);
if (!$que_coa) { if (!$que_coa) {
$this->db->trans_rollback(); $this->db->trans_rollback();
@@ -1766,93 +1717,6 @@ class Fakturv4 extends MY_Controller
} }
} }
private function InsertJurnalTxAsset($jurnalID, $itemid, $invoice, $userid)
{
$sql_coa = "SELECT
Fa_ClassHutangCoaID,
Fa_ClassHutangCoaAccountNo,
Fa_ClassHutangCoaDesc
FROM m_item
JOIN fa_class ON Fa_ClassID = M_ItemFa_ClassID
WHERE M_ItemID = ?";
$que_coa = $this->db->query($sql_coa, $itemid);
if (!$que_coa) {
$this->db->trans_rollback();
$this->sys_error_db("[Error] failed get coa hutang asset");
exit;
}
$coaasset = $que_coa->row_array();
if ($que_coa->num_rows() <= 0) {
$this->db->trans_rollback();
$this->sys_error_db("[Error] aset debt coa not found");
exit;
}
$invtotal = doubleval($invoice['SupplierInvoiceDetailTotal']);
$disprorata = doubleval($invoice['SupplierInvoiceDetailDiscountPoProrata']);
$price = $invtotal - $disprorata;
$taxPPN = doubleval($invoice['SupplierInvoiceTaxPercentPpn']) * $price / 100;
$kredit = round($price + $taxPPN, 2);
$finalValue = round($kredit - doubleval($invoice['dpReduction']), 2);
$insert = $this->InsertJurnalTx(
$jurnalID,
$coaasset['Fa_ClassHutangCoaID'],
$coaasset['Fa_ClassHutangCoaDesc'],
$userid,
0,
$finalValue
);
if (!$insert) {
$this->db->trans_rollback();
$this->sys_error_db($insert['msg']);
exit;
}
}
private function CalcProrateDownPaymentAsset($items, $dpAmount)
{
$totalKredit = 0;
foreach ($items as $key => $value) {
$invtotal = doubleval($value['SupplierInvoiceDetailTotal']);
$disprorata = doubleval($value['SupplierInvoiceDetailDiscountPoProrata']);
$price = $invtotal - $disprorata;
$taxPPN = doubleval($value['SupplierInvoiceTaxPercentPpn']) * $price / 100;
$kredit = round($price + $taxPPN, 2);
$totalKredit = $totalKredit + $kredit;
$items[$key]['kredit'] = $kredit;
}
if ($totalKredit <= 0) {
foreach ($items as $key => $value) {
$items[$key]['dpReduction'] = 0;
}
return $items;
}
$runningReduction = 0;
end($items);
$lastKey = key($items);
reset($items);
foreach ($items as $key => $value) {
if ($key === $lastKey) {
$reduction = round($dpAmount - $runningReduction, 2);
} else {
$ratio = $value['kredit'] / $totalKredit;
$reduction = round($dpAmount * $ratio, 2);
$runningReduction += $reduction;
}
$items[$key]['dpReduction'] = $reduction;
}
return $items;
}
function InsertJurnalTx($jurnalID, $coaID, $desc, $userID, $debit = 0, $kredit = 0): array function InsertJurnalTx($jurnalID, $coaID, $desc, $userID, $debit = 0, $kredit = 0): array
{ {
try { try {

View File

@@ -1705,38 +1705,22 @@ class ReceiveItemPoInventaris extends MY_Controller
exit; exit;
} }
$sql_invcoa = "SELECT $sql_coa_inv = "SELECT
COALESCE( CoaMapInventarisCoaID,
i.M_InventarisItemCoaMappingID, CoaMapInventarisCoaNo,
g.M_InventarisCoaMappingID CoaMapInventarisCoaDesc
) AS MappingID, FROM coa_map_inventaris
COALESCE( WHERE CoaMapInventarisM_InventarisGolID = ?
i.M_InventarisItemCoaMappingCoaInventarisID, AND CoaMapInventarisIsActive = 'Y'";
g.M_InventarisCoaMappingCoaInventarisID $que_coa_inv = $this->db->query($sql_coa_inv, [$item_cek['M_ItemM_InventarisGolID']]);
) AS CoaInventarisID, if (!$que_coa_inv) {
c.coaDescription AS CoaInventarisDesc
FROM (SELECT 1) AS inventory
LEFT JOIN m_inventaris_item_coa_mapping i
ON i.M_InventarisItemCoaMappingM_ItemID = ?
AND i.M_InventarisItemCoaMappingIsActive = 'Y'
LEFT JOIN m_inventaris_coa_mapping g
ON g.M_InventarisCoaMappingM_InventarisGolID = ?
AND g.M_InventarisCoaMappingIsActive = 'Y'
LEFT JOIN coa c
ON c.coaID = COALESCE(i.M_InventarisItemCoaMappingCoaInventarisID, g.M_InventarisCoaMappingCoaInventarisID)
AND c.coaIsActive = 'Y'";
$que_invcoa = $this->db->query($sql_invcoa, [
$item_cek['M_ItemID'],
$item_cek['M_ItemM_InventarisGolID']
]);
if (!$que_invcoa) {
$this->db->trans_rollback(); $this->db->trans_rollback();
$this->sys_error_db("[Error] failed to get coa biaya item inventaris"); $this->sys_error_db("[Error] failed to get coa biaya item inventaris");
exit; exit;
} }
$iteminv_coa = $que_invcoa->row_array(); $iteminv_coa = $que_coa_inv->row_array();
if (empty($iteminv_coa['CoaInventarisID'])) { if (empty($iteminv_coa['CoaMapInventarisCoaID'])) {
$this->db->trans_rollback(); $this->db->trans_rollback();
$this->sys_error_db("[Error] coa gol inventaris not found"); $this->sys_error_db("[Error] coa gol inventaris not found");
exit; exit;
@@ -1756,8 +1740,8 @@ class ReceiveItemPoInventaris extends MY_Controller
) VALUES (?,?,?,?,?,?)"; ) VALUES (?,?,?,?,?,?)";
$que_tx_jurnal = $this->db->query($sql_tx_jurnal, [ $que_tx_jurnal = $this->db->query($sql_tx_jurnal, [
$jurnal_ID, $jurnal_ID,
$iteminv_coa['CoaInventarisID'], $iteminv_coa['CoaMapInventarisCoaID'],
$iteminv_coa['CoaInventarisDesc'], $iteminv_coa['CoaMapInventarisCoaDesc'],
$debet, $debet,
0, 0,
$user['M_UserID'] $user['M_UserID']
@@ -1770,7 +1754,7 @@ class ReceiveItemPoInventaris extends MY_Controller
} }
$juranl_tx_ID = $this->db->insert_id(); $juranl_tx_ID = $this->db->insert_id();
$each_desc[] = "- Add detail Jurnal debet {$item_cek['M_ItemDesc']} $each_desc[] = "- Add detail Jurnal debet {$item_cek['M_ItemDesc']}
{$iteminv_coa['CoaInventarisDesc']} sejumlah {$this->formatRupiah($debet)}"; {$iteminv_coa['CoaMapInventarisCoaDesc']} sejumlah {$this->formatRupiah($debet)}";
# INSERT JURNAL ADDON # # INSERT JURNAL ADDON #
$sql_addon_jurnal = "INSERT INTO jurnal_addon ( $sql_addon_jurnal = "INSERT INTO jurnal_addon (
@@ -1960,6 +1944,20 @@ class ReceiveItemPoInventaris extends MY_Controller
$this->sys_error_db("[Error] insert update stock"); $this->sys_error_db("[Error] insert update stock");
exit; exit;
} }
// insert stockid barcode barang
// $sql_update_barcode = "UPDATE t_barcode_barang SET
// T_BarcodeBarangStockID = ?
// WHERE T_BarcodeBarangReceiveOrderPoDetailID = ?";
// $qry_update_barcode = $this->db->query($sql_update_barcode, [
// $stock_ID,
// $detail['ReceiveOrderPoDetailID']
// ]);
// if (!$qry_update_barcode) {
// $this->db->trans_rollback();
// $this->sys_error_db("[Error] update barcode stockID", $this->db);
// exit;
// }
} else { } else {
$sql_insert_stock = "INSERT INTO stock ( $sql_insert_stock = "INSERT INTO stock (
StockWarehouseAlmariID, StockWarehouseAlmariID,
@@ -1987,9 +1985,23 @@ class ReceiveItemPoInventaris extends MY_Controller
exit; exit;
} }
$stock_ID = $this->db->insert_id(); $stockID = $this->db->insert_id();
$stock_qty_ori = 0; $stock_qty_ori = 0;
$stock_qty_end = intval($batch['qty']); $stock_qty_end = intval($batch['qty']);
// insert stockid barcode barang
// $sql_update_barcode = "UPDATE t_barcode_barang SET
// T_BarcodeBarangStockID = ?
// WHERE T_BarcodeBarangReceiveOrderPoDetailID = ?";
// $qry_update_barcode = $this->db->query($sql_update_barcode, [
// $stockID,
// $detail['ReceiveOrderPoDetailID']
// ]);
// if (!$qry_update_barcode) {
// $this->db->trans_rollback();
// $this->sys_error_db("[Error] update barcode stockID", $this->db);
// exit;
// }
} }
// insert stock card // insert stock card

View File

@@ -1,90 +0,0 @@
@host = https://accone.aplikasi.web.id/one-api
@date = 2026-07-14
@coaBayarID = 1110100001
@coaHutangID = 2110100030
# =============================================================================
# JurnalPiCicilanOrderAset — Contoh Pemanggilan Endpoint
# =============================================================================
# Urutan penggunaan yang disarankan:
# 1. ListEligiblePurchaseOrderAssetContracts → lihat kontrak yang akan diproses
# 2. GenerateJournalsFromContracts (dryRun=Y) → simulasi tanpa simpan ke DB
# 3. GenerateJournalsFromContracts (dryRun=N) → generate jurnal sesungguhnya
# 4. CreateJournal → buat jurnal manual 1 per 1
# =============================================================================
### 1. Lihat kontrak aset yang eligible untuk dibuatkan jurnal bulan ini
GET {{host}}/index.php/mockup/scheduler/JurnalPiCicilanOrderAset/ListEligiblePurchaseOrderAssetContracts
Content-Type: application/json
{
"startDate": "2026-07-01",
"endDate": "2026-07-31"
}
### 2. Simulasi generate jurnal (dryRun=Y) — tidak menyimpan ke database
POST {{host}}/index.php/mockup/scheduler/JurnalPiCicilanOrderAset/GenerateJournalsFromContracts
Content-Type: application/json
{
"date" : "{{date}}",
"dryRun" : "Y"
}
### 3. Generate jurnal untuk semua kontrak eligible bulan ini (sesungguhnya)
POST {{host}}/index.php/mockup/scheduler/JurnalPiCicilanOrderAset/GenerateJournalsFromContracts
Content-Type: application/json
{
"date" : "{{date}}",
"dryRun" : "N"
}
### 4. Generate jurnal untuk 1 kontrak tertentu saja (contractID=99)
POST {{host}}/index.php/mockup/scheduler/JurnalPiCicilanOrderAset/GenerateJournalsFromContracts
Content-Type: application/json
{
"date" : "{{date}}",
"dryRun" : "Y",
"contractID" : 00
}
### 5. Buat jurnal manual (1 jurnal, input detail sendiri)
POST {{host}}/index.php/mockup/scheduler/JurnalPiCicilanOrderAset/CreateJournal
Content-Type: application/json
{
"date" : "{{date}}",
"branchCode" : "BA",
"regionalID" : 8,
"branchCompanyID": 1,
"jurnalTypeID" : 11,
"title" : "Jurnal PI Cicilan Order Aset",
"description" : "Cicilan ke-1 dari 12 | Kontrak Kendaraan Operasional | Periode 2026-07",
"details" : [
{
"coaID" : {{coaHutangID}},
"description": "Hutang cicilan aset - Kendaraan Operasional",
"debit" : 15000000,
"credit" : 0,
"addonCode" : "PIINSTALMENT",
"addonValue" : "42",
"mItemID" : 123
},
{
"coaID" : {{coaBayarID}},
"description": "Pembayaran cicilan aset - Kendaraan Operasional",
"debit" : 0,
"credit" : 15000000,
"addonCode" : "PIINSTALMENT",
"addonValue" : "42",
"mItemID" : 123
}
]
}

View File

@@ -1,970 +0,0 @@
<?php
/**
* JurnalPiCicilanOrderAset
*
* Controller scheduler untuk membuat jurnal akuntansi atas Purchase Invoice (PI)
* cicilan order aset secara otomatis.
*
* Alur bisnis proses:
* 1. Validasi parameter input (tanggal, branchCode, title, description, details)
* 2. Insert header jurnal ke tabel `jurnal`
* - Nomor jurnal di-generate via fn_numbering('J')
* - Tipe jurnal: PAYMENT
* - Berisi: title, description, tanggal, regionalID, kode cabang, branchCompanyID
* 3. Insert baris transaksi ke tabel `jurnal_tx` (untuk setiap baris cicilan)
* - Referensi ke jurnalID header
* - COA (Chart of Account) dan deskripsinya:
* * Sisi hutang cicilan → nilai DEBIT (diambil dari HutangCoaID di fa_class)
* * Sisi pembayaran cicilan → nilai KREDIT (diambil dari ItemCoaID di fa_class)
* 4. Insert data tambahan ke tabel `jurnal_addon` (jika ada addonValue atau mItemID)
* - Referensi ke jurnalID dan jurnalTxID
* - Berisi: addonCode (default: "PIINSTALMENT"), addonValue, mItemID
*
* Endpoint:
* POST /mockup/scheduler/JurnalPiCicilanOrderAset/CreateJournal
* POST /mockup/scheduler/JurnalPiCicilanOrderAset/GenerateJournalsFromContracts
* GET /mockup/scheduler/JurnalPiCicilanOrderAset/ListEligiblePurchaseOrderAssetContracts
*/
class JurnalPiCicilanOrderAset extends MY_Controller
{
var $db;
/**
* Endpoint default — menampilkan nama controller sebagai penanda aktif.
*/
public function index()
{
echo "Jurnal PI Cicilan Order Aset";
}
/**
* Konstruktor — inisialisasi parent controller.
*/
public function __construct()
{
parent::__construct();
}
/**
* CreateJournal — Membuat jurnal PI cicilan order aset.
*
* Proses bisnis:
* 1. Validasi semua parameter wajib: date, branchCode, title, description, details
* 2. Ambil periodeID dari tanggal transaksi (tabel periode)
* 3. Ambil regionalID dari branchCode (tabel m_branch)
* 4. Ambil branchCompanyID dari branchCode (tabel m_branch_companydetail)
* 5. Ambil jurnalTypeID dari kode tipe jurnal (default: "PAYMENT")
* 6. Generate nomor jurnal otomatis via fn_numbering('J')
* 7. Validasi balance: total debit harus sama dengan total credit
* 8. INSERT header jurnal ke tabel `jurnal`:
* - jurnalNo : nomor jurnal hasil generate
* - jurnalJurnalTypeID: tipe PAYMENT
* - jurnalTitle : judul jurnal
* - jurnalDescription: keterangan jurnal
* - jurnalDate : tanggal transaksi
* - JurnalS_RegionalID: ID regional cabang
* - jurnalM_BranchCode: kode cabang
* 9. Untuk setiap baris detail, INSERT ke `jurnal_tx`:
* - jurnalTxJurnalID : referensi ke header jurnal
* - jurnalTxCoaID : COA yang digunakan (hutang cicilan / kas/bank)
* - jurnalTxDescription: keterangan baris (nama cicilan/aset)
* - jurnalTxDebit : nilai hutang (sisi debit)
* - jurnalTxCredit : nilai bayar (sisi kredit)
* 10. Jika ada addonValue atau mItemID, INSERT ke `jurnal_addon`:
* - jurnalAddOnJurnalID : referensi ke header jurnal
* - jurnalAddOnJurnalTxID: referensi ke baris jurnal_tx
* - jurnalAddOnCode : kode addon (default: "PIINSTALMENT")
* - jurnalAddOnValue : nilai tambahan (misal: nomor PI/kontrak)
* - jurnalAddOnM_ItemID : ID item aset yang terkait
*
* Parameter (POST JSON):
* - date : Tanggal jurnal (YYYY-MM-DD). Default: hari ini.
* - branchCode : Kode cabang. WAJIB.
* - title : Judul jurnal. WAJIB.
* - description : Keterangan jurnal. WAJIB.
* - details : Array baris transaksi. WAJIB, minimal 1 baris.
* - coaID : ID Chart of Account. WAJIB per baris.
* - description : Keterangan baris.
* - debit : Nilai debit (hutang cicilan).
* - credit : Nilai kredit (pembayaran cicilan).
* - addonValue : (opsional) Nilai addon, misal nomor PI.
* - mItemID : (opsional) ID item aset.
* - addonCode : (opsional) Kode addon. Default: "PIINSTALMENT".
* - periodeID : (opsional) ID periode. Default: diambil dari tanggal.
* - regionalID : (opsional) ID regional. Default: diambil dari branchCode.
* - branchCompanyID: (opsional) ID branch company. Default: diambil dari branchCode.
* - jurnalTypeID : (opsional) ID tipe jurnal. Default: diambil dari jurnalTypeCode.
* - jurnalTypeCode: (opsional) Kode tipe jurnal. Default: "PAYMENT".
* - userID : ID user yang membuat jurnal.
*
* @return JSON { jurnalID, jurnalNo, detailCount, addonCount }
*/
public function CreateJournal()
{
try {
$para = $this->sys_input;
$date = isset($para["date"]) && $para["date"] != "" ? $para["date"] : date("Y-m-d");
if (!$this->isValidDate($date)) {
throw new Exception("Format tanggal tidak valid. Gunakan YYYY-MM-DD.");
}
$branchCode = isset($para["branchCode"]) ? trim($para["branchCode"]) : "";
if ($branchCode == "") {
throw new Exception("branchCode wajib diisi.");
}
$title = isset($para["title"]) ? trim($para["title"]) : "";
if ($title == "") {
throw new Exception("title wajib diisi.");
}
$description = isset($para["description"]) ? trim($para["description"]) : "";
if ($description == "") {
throw new Exception("description wajib diisi.");
}
$details = isset($para["details"]) && is_array($para["details"]) ? $para["details"] : [];
if (count($details) == 0) {
throw new Exception("details wajib diisi minimal 1 baris.");
}
$periodeID = isset($para["periodeID"]) && (int) $para["periodeID"] > 0
? (int) $para["periodeID"]
: $this->getPeriodeIDByDate($date);
if ($periodeID <= 0) {
throw new Exception("Periode jurnal tidak ditemukan untuk tanggal {$date}.");
}
$regionalID = isset($para["regionalID"]) && (int) $para["regionalID"] > 0
? (int) $para["regionalID"]
: $this->getRegionalIDByBranchCode($branchCode);
if ($regionalID <= 0) {
throw new Exception("regionalID wajib diisi atau harus bisa diturunkan dari branchCode.");
}
$branchCompanyID = isset($para["branchCompanyID"]) && (int) $para["branchCompanyID"] > 0
? (int) $para["branchCompanyID"]
: $this->getBranchCompanyIDByBranchCode($branchCode);
if ($branchCompanyID <= 0) {
throw new Exception("branchCompanyID wajib diisi atau harus bisa diturunkan dari branchCode.");
}
$jurnalTypeID = isset($para["jurnalTypeID"]) && (int) $para["jurnalTypeID"] > 0
? (int) $para["jurnalTypeID"]
: $this->getJurnalTypeID(isset($para["jurnalTypeCode"]) && $para["jurnalTypeCode"] != "" ? $para["jurnalTypeCode"] : "PAYMENT");
if ($jurnalTypeID <= 0) {
throw new Exception("jurnalTypeID / jurnalTypeCode tidak valid.");
}
$userID = 0;
$result = $this->insertJournal(
$date,
$branchCode,
$title,
$description,
$details,
$periodeID,
$regionalID,
$branchCompanyID,
$jurnalTypeID,
$userID
);
if ($result === false) {
exit;
}
$this->sys_ok($result);
} catch (Exception $exc) {
$this->sys_error($exc->getMessage());
}
}
/**
* GenerateJournalsFromContracts — Generate jurnal otomatis dari seluruh kontrak aset eligible.
*
* Fungsi ini mengintegrasikan data dari getEligiblePurchaseOrderAssetContracts()
* dengan proses pembuatan jurnal (insertJournal()) secara otomatis.
*
* Untuk setiap kontrak yang eligible, dibuat 1 jurnal dengan 2 baris transaksi:
* - Baris DEBIT : COA hutang cicilan (HutangCoaID dari fa_class) — mencatat hutang cicilan
* - Baris KREDIT : COA kas/bank/aset (ItemCoaID dari fa_class) — mencatat pembayaran cicilan
* Addon (jurnal_addon): menyimpan ID kontrak sebagai addonValue dan ItemID sebagai mItemID
*
* Parameter (POST JSON):
* - date : Tanggal jurnal (YYYY-MM-DD). Default: hari ini.
* - userID : ID user yang membuat jurnal.
* - dryRun : "Y" = simulasi tanpa simpan ke DB. Default: "N".
* - contractID : (opsional) Filter hanya 1 kontrak tertentu.
*
* Syarat kontrak dilewati (skipped):
* - branchCode kosong (data cabang belum lengkap)
* - COA hutang (HutangCoaID) tidak ditemukan di fa_class
* - COA bayar/aset (ItemCoaID) tidak ditemukan di fa_class
*
* @return JSON { tanggal, totalDibuat, totalDilewati, daftarDibuat[], daftarDilewati[] }
*/
public function GenerateJournalsFromContracts()
{
try {
$para = $this->sys_input;
$date = isset($para["date"]) && $para["date"] != "" ? $para["date"] : date("Y-m-d");
if (!$this->isValidDate($date)) {
throw new Exception("Format tanggal tidak valid. Gunakan YYYY-MM-DD.");
}
$userID = 0;
$dryRun = isset($para["dryRun"]) && ($para["dryRun"] === true || $para["dryRun"] == "Y" || $para["dryRun"] == "1");
$filterContractID = isset($para["contractID"]) && (int) $para["contractID"] > 0
? (int) $para["contractID"]
: null;
$monthStart = date("Y-m-01", strtotime($date));
$monthEnd = date("Y-m-t", strtotime($date));
// Ambil semua kontrak yang eligible untuk periode bulan ini
$contracts = $this->getEligiblePurchaseOrderAssetContracts($monthStart, $monthEnd);
$dibuat = [];
$dilewati = [];
foreach ($contracts as $kontrak) {
$contractID = (int) $kontrak["PurchaseOrderAssetContractID"];
// Filter 1 kontrak jika diminta
if ($filterContractID !== null && $contractID !== $filterContractID) {
continue;
}
$branchCode = $kontrak["M_BranchCode"] ?? "";
$regionalID = (int) ($kontrak["M_BranchS_RegionalID"] ?? 0);
$branchCompanyID = (int) ($kontrak["M_BranchCompanyID"] ?? 0);
$coaHutangID = (int) ($kontrak["HutangCoaID"] ?? 0); // COA debit dari fa_class (Fa_ClassHutangCoaID)
$coaBayarID = (int) ($kontrak["ItemCoaID"] ?? 0); // COA kredit dari fa_class (Fa_ClassCoaID)
$jumlah = (float) $kontrak["PurchaseOrderAssetContractInstallmentPayAmount"];
$itemID = (int) ($kontrak["PurchaseOrderSummaryItemID"] ?? 0);
$namaKontrak = $kontrak["PurchaseOrderAssetContractName"] != ""
? $kontrak["PurchaseOrderAssetContractName"]
: "Kontrak ID {$contractID}";
$nomorPO = $kontrak["PurchaseOrderNumber"] ?? "";
$cicilanKe = ((int) $kontrak["PurchaseOrderAssetContractInstallmentPaid"]) + 1;
$totalCicilan = (int) $kontrak["PurchaseOrderAssetContractInstallmentNumber"];
$periode = date("Y-m", strtotime($date));
$invoiceNumber = $kontrak["SupplierInvoiceNumber"] ?? "";
$invoiceID = (int) ($kontrak["SupplierInvoiceID"] ?? 0);
// Validasi: branchCode harus ada
if ($branchCode == "") {
$dilewati[] = [
"kontrakID" => $contractID,
"alasan" => "Kode cabang (branchCode) tidak ditemukan. Pastikan warehouse PO sudah terhubung ke data cabang."
];
continue;
}
// Validasi: COA hutang harus ada (untuk sisi DEBIT)
if ($coaHutangID <= 0) {
$dilewati[] = [
"kontrakID" => $contractID,
"branchCode" => $branchCode,
"alasan" => "COA hutang tidak ditemukan. Pastikan item PO memiliki Fa_Class dengan Fa_ClassHutangCoaID."
];
continue;
}
// Validasi: COA bayar/aset harus ada (untuk sisi KREDIT)
if ($coaBayarID <= 0) {
$dilewati[] = [
"kontrakID" => $contractID,
"branchCode" => $branchCode,
"alasan" => "COA bayar/aset tidak ditemukan. Pastikan item PO memiliki Fa_Class dengan Fa_ClassCoaID."
];
continue;
}
// Mode simulasi: catat tanpa simpan ke DB
if ($dryRun) {
$dibuat[] = [
"kontrakID" => $contractID,
"branchCode" => $branchCode,
"namaKontrak" => $namaKontrak,
"invoiceNumber" => $invoiceNumber,
"jumlah" => $jumlah,
"coaHutangID" => $coaHutangID,
"coaBayarID" => $coaBayarID,
"keterangan" => "Mode simulasi (dryRun), data tidak disimpan."
];
continue;
}
// Susun title dan description jurnal
$title = "PI Cicilan Aset - {$invoiceNumber}";
$description = "Jurnal cicilan ke-{$cicilanKe} dari {$totalCicilan} | {$namaKontrak} | PO: {$nomorPO} | Periode {$periode}";
// Ambil periodeID dari tanggal
$periodeID = $this->getPeriodeIDByDate($date);
if ($periodeID <= 0) {
$dilewati[] = [
"kontrakID" => $contractID,
"branchCode" => $branchCode,
"alasan" => "Periode jurnal tidak ditemukan untuk tanggal {$date}."
];
continue;
}
// Ambil jurnalTypeID untuk tipe PAYMENT
$jurnalTypeID = $this->getJurnalTypeID("PAYMENTINV");
if ($jurnalTypeID <= 0) {
$dilewati[] = [
"kontrakID" => $contractID,
"branchCode" => $branchCode,
"alasan" => "Tipe jurnal PAYMENT tidak ditemukan di tabel jurnal_type."
];
continue;
}
// Ambil description detail dari database fa_class dengan fallback jika kosong
$descHutang = isset($kontrak["HutangCoaDesc"]) && $kontrak["HutangCoaDesc"] != ""
? $kontrak["HutangCoaDesc"]
: "Hutang cicilan aset - {$namaKontrak}";
$descBayar = isset($kontrak["ItemCoaDesc"]) && $kontrak["ItemCoaDesc"] != ""
? $kontrak["ItemCoaDesc"]
: "Pembayaran cicilan aset - {$namaKontrak}";
// Susun 2 baris detail jurnal:
// Baris 1 — DEBIT : hutang cicilan aset (COA dari fa_class)
// Baris 2 — KREDIT : pembayaran cicilan (COA kas/bank dari parameter)
$details = [
[
"coaID" => $coaHutangID,
"description" => $descHutang,
"debit" => $jumlah,
"credit" => 0,
"addonValue" => $invoiceNumber,
"mItemID" => $itemID,
"addonCode" => "PIINSTALMENT"
],
[
"coaID" => $coaBayarID,
"description" => $descBayar,
"debit" => 0,
"credit" => $jumlah,
"addonValue" => $invoiceNumber,
"mItemID" => $itemID,
"addonCode" => "PIINSTALMENT"
]
];
// Panggil insertJournal() untuk simpan ke DB
$result = $this->insertJournal(
$date,
$branchCode,
$title,
$description,
$details,
$periodeID,
$regionalID,
$branchCompanyID,
$jurnalTypeID,
$userID
);
if ($result === false) {
$dilewati[] = [
"kontrakID" => $contractID,
"branchCode" => $branchCode,
"alasan" => "Gagal menyimpan jurnal ke database."
];
continue;
}
$dibuat[] = [
"kontrakID" => $contractID,
"branchCode" => $branchCode,
"namaKontrak" => $namaKontrak,
"jurnalID" => $result["jurnalID"],
"jurnalNo" => $result["jurnalNo"],
"jumlah" => $jumlah
];
}
$this->sys_ok([
"tanggal" => $date,
"periodeAwal" => $monthStart,
"periodeAkhir" => $monthEnd,
"totalDibuat" => count($dibuat),
"totalDilewati" => count($dilewati),
"daftarDibuat" => $dibuat,
"daftarDilewati" => $dilewati
]);
} catch (Exception $exc) {
$this->sys_error($exc->getMessage());
}
}
/**
* ListEligiblePurchaseOrderAssetContracts — Menampilkan daftar kontrak aset
* yang memenuhi syarat untuk dibuatkan jurnal PI cicilan pada periode tertentu.
*
* Syarat kontrak eligible:
* - Kontrak aktif dan berstatus "belum lunas"
* - Nilai cicilan > 0
* - Jumlah cicilan terbayar < total cicilan
* - Tanggal kontrak masuk dalam rentang startDateendDate
* - PO sudah berstatus Approved
* - Barang sudah diterima (receive_order_po sudah confirmed)
*
* Endpoint ini digunakan untuk preview/verifikasi sebelum proses generate jurnal
* dijalankan secara massal oleh CRON.
*
* Parameter (GET/POST):
* - startDate : Awal periode (YYYY-MM-DD). Default: tanggal 1 bulan ini.
* - endDate : Akhir periode (YYYY-MM-DD). Default: tanggal akhir bulan ini.
*
* @return JSON { startDate, endDate, total, records[] }
*/
public function ListEligiblePurchaseOrderAssetContracts()
{
try {
$para = $this->sys_input;
$startDate = isset($para["startDate"]) && $para["startDate"] != ""
? $para["startDate"]
: date("Y-m-01");
$endDate = isset($para["endDate"]) && $para["endDate"] != ""
? $para["endDate"]
: date("Y-m-t");
if (!$this->isValidDate($startDate) || !$this->isValidDate($endDate)) {
throw new Exception("Format tanggal tidak valid. Gunakan YYYY-MM-DD.");
}
if (strtotime($startDate) > strtotime($endDate)) {
throw new Exception("startDate tidak boleh lebih besar dari endDate");
}
$records = $this->getEligiblePurchaseOrderAssetContracts($startDate, $endDate);
$this->sys_ok([
"startDate" => $startDate,
"endDate" => $endDate,
"total" => count($records),
"records" => $records
]);
} catch (Exception $exc) {
$this->sys_error($exc->getMessage());
}
}
// =========================================================================
// FUNGSI PRIVATE / HELPER
// =========================================================================
/**
* insertJournal — Menyimpan 1 jurnal lengkap ke database (header + tx + addon).
*
* Fungsi internal yang dipanggil oleh CreateJournal() dan GenerateJournalsFromContracts().
* Mengelola transaksi DB secara penuh (begin → commit/rollback).
*
* Alur:
* 1. Validasi balance debit == kredit
* 2. Generate nomor jurnal via fn_numbering('J')
* 3. INSERT header ke tabel `jurnal`
* 4. INSERT baris transaksi ke `jurnal_tx` (per detail)
* 5. INSERT addon ke `jurnal_addon` (jika addonValue atau mItemID ada)
*
* @param string $date Tanggal jurnal (YYYY-MM-DD)
* @param string $branchCode Kode cabang
* @param string $title Judul jurnal
* @param string $description Keterangan jurnal
* @param array $details Baris transaksi [ coaID, description, debit, credit, addonValue?, mItemID?, addonCode? ]
* @param int $periodeID ID periode akuntansi
* @param int $regionalID ID regional
* @param int $branchCompanyID ID branch company
* @param int $jurnalTypeID ID tipe jurnal
* @param int $userID ID user pembuat jurnal
*
* @return array|false Array { jurnalID, jurnalNo, detailCount, addonCount }, atau false jika gagal
*/
private function insertJournal($date, $branchCode, $title, $description, $details, $periodeID, $regionalID, $branchCompanyID, $jurnalTypeID, $userID)
{
// Validasi balance sebelum menyimpan
$totalDebit = 0;
$totalCredit = 0;
foreach ($details as $idx => $detail) {
$debit = isset($detail["debit"]) ? (float) $detail["debit"] : 0;
$credit = isset($detail["credit"]) ? (float) $detail["credit"] : 0;
if ($debit < 0 || $credit < 0) {
$this->sys_error("Nilai debit/credit tidak boleh negatif pada detail ke-" . ($idx + 1));
return false;
}
$totalDebit += $debit;
$totalCredit += $credit;
}
if (round($totalDebit, 2) !== round($totalCredit, 2)) {
$this->sys_error("Total debit dan credit harus sama. Debit={$totalDebit}, Credit={$totalCredit}");
return false;
}
$jurnalNo = $this->generateJournalNumber();
if ($jurnalNo === false || $jurnalNo == "") {
$this->sys_error("Gagal generate nomor jurnal.");
return false;
}
$this->db->trans_begin();
// -----------------------------------------------------------------
// INSERT header jurnal ke tabel `jurnal`
// -----------------------------------------------------------------
$sqlHeader = "INSERT INTO jurnal (
jurnalM_BranchCompanyID,
JurnalS_RegionalID,
jurnalM_BranchCode,
jurnalperiodeID,
jurnalNo,
jurnalTitle,
jurnalDescription,
jurnalDate,
jurnalJurnalTypeID,
jurnalCreated,
jurnalM_UserID
) VALUES (?,?,?,?,?,?,?,?,?,NOW(),?)";
$qryHeader = $this->db->query($sqlHeader, [
$branchCompanyID,
$regionalID,
$branchCode,
$periodeID,
$jurnalNo,
$title,
$description,
$date,
$jurnalTypeID,
$userID
]);
if (!$qryHeader) {
$this->db->trans_rollback();
$this->sys_error_db("Gagal insert jurnal header.");
return false;
}
$jurnalID = $this->db->insert_id();
$createdAddonCount = 0;
// -----------------------------------------------------------------
// INSERT baris transaksi ke tabel `jurnal_tx` (per baris cicilan)
// -----------------------------------------------------------------
foreach ($details as $idx => $detail) {
$coaID = isset($detail["coaID"]) ? (int) $detail["coaID"] : 0;
$descriptionTx = isset($detail["description"]) ? trim($detail["description"]) : "";
$debit = isset($detail["debit"]) ? (float) $detail["debit"] : 0;
$credit = isset($detail["credit"]) ? (float) $detail["credit"] : 0;
if ($coaID <= 0) {
$this->db->trans_rollback();
$this->sys_error_db("coaID wajib diisi pada detail ke-" . ($idx + 1));
return false;
}
// Sisi debit = hutang cicilan (COA hutang aset dari fa_class)
// Sisi kredit = pembayaran cicilan (COA kas/bank)
$sqlTx = "INSERT INTO jurnal_tx (
jurnalTxJurnalID,
jurnalTxCoaID,
jurnalTxDescription,
jurnalTxDebit,
jurnalTxCredit,
jurnalTxCreated,
jurnalTxM_UserID
) VALUES (?,?,?,?,?,NOW(),?)";
$qryTx = $this->db->query($sqlTx, [
$jurnalID,
$coaID,
$descriptionTx,
$debit,
$credit,
$userID
]);
if (!$qryTx) {
$this->db->trans_rollback();
$this->sys_error_db("Gagal insert jurnal_tx pada detail ke-" . ($idx + 1));
return false;
}
$jurnalTxID = $this->db->insert_id();
// -----------------------------------------------------------------
// INSERT addon ke `jurnal_addon` (jika addonValue atau mItemID ada)
// addonValue = ID kontrak aset (untuk tracing)
// mItemID = ID item aset dari purchase_order_summary
// -----------------------------------------------------------------
$addonValue = isset($detail["addonValue"]) ? trim($detail["addonValue"]) : "";
$mItemID = isset($detail["mItemID"]) ? (int) $detail["mItemID"] : 0;
$addonCode = isset($detail["addonCode"]) && $detail["addonCode"] != "" ? trim($detail["addonCode"]) : "PIINSTALMENT";
if ($addonValue != "" || $mItemID > 0) {
$sqlAddon = "INSERT INTO jurnal_addon (
jurnalAddOnJurnalID,
jurnalAddOnJurnalTxID,
jurnalAddOnCode,
jurnalAddOnValue,
jurnalAddOnM_ItemID,
jurnalAddOnCreated,
jurnalAddOnCreatedUserID
) VALUES (?,?,?,?,?,NOW(),?)";
$qryAddon = $this->db->query($sqlAddon, [
$jurnalID,
$jurnalTxID,
$addonCode,
$addonValue,
$mItemID > 0 ? $mItemID : null,
$userID
]);
if (!$qryAddon) {
$this->db->trans_rollback();
$this->sys_error_db("Gagal insert jurnal_addon pada detail ke-" . ($idx + 1));
return false;
}
$createdAddonCount++;
}
}
if ($this->db->trans_status() === false) {
$this->db->trans_rollback();
$this->sys_error_db("Transaksi jurnal gagal.");
return false;
}
$this->db->trans_commit();
return [
"jurnalID" => $jurnalID,
"jurnalNo" => $jurnalNo,
"detailCount" => count($details),
"addonCount" => $createdAddonCount
];
}
/**
* generateJournalNumber — Generate nomor jurnal otomatis.
*
* Memanggil stored function MySQL fn_numbering('J') untuk mendapatkan
* nomor jurnal berikutnya sesuai urutan penomoran yang berlaku.
*
* @return string|false Nomor jurnal (misal: "J/2025/07/0001"), atau false jika gagal.
*/
private function generateJournalNumber()
{
$qry = $this->db->query("SELECT fn_numbering('J') AS JNumber");
if (!$qry || $qry->num_rows() == 0) {
return false;
}
return $qry->row_array()["JNumber"];
}
/**
* getPeriodeIDByDate — Ambil ID periode akuntansi berdasarkan tanggal transaksi.
*
* Periode diambil dari tabel `periode` yang aktif dan mencakup tanggal yang diberikan.
* Digunakan untuk mengisi field jurnalperiodeID pada header jurnal.
*
* @param string $date Tanggal transaksi (format YYYY-MM-DD)
* @return int periodeID yang sesuai, atau 0 jika tidak ditemukan
*/
private function getPeriodeIDByDate($date)
{
$sql = "SELECT periodeID
FROM periode
WHERE periodeIsActive = 'Y'
AND DATE(?) BETWEEN periodeStartDate AND periodeEndDate
LIMIT 1";
$qry = $this->db->query($sql, [$date]);
if (!$qry || $qry->num_rows() == 0) {
return 0;
}
return (int) $qry->row_array()["periodeID"];
}
/**
* getBranchCompanyIDByBranchCode — Ambil ID branch company berdasarkan kode cabang.
*
* Data diambil dari tabel `m_branch_companydetail` yang aktif.
* Digunakan untuk mengisi field jurnalM_BranchCompanyID pada header jurnal.
*
* @param string $branchCode Kode cabang (misal: "JKT-01")
* @return int branchCompanyID yang sesuai, atau 0 jika tidak ditemukan
*/
private function getBranchCompanyIDByBranchCode($branchCode)
{
$sql = "SELECT M_BranchCompanyDetailM_BranchCompanyID AS branchCompanyID
FROM m_branch_companydetail
WHERE M_BranchCompanyDetailM_BranchCode = ?
AND M_BranchCompanyDetailIsActive = 'Y'
LIMIT 1";
$qry = $this->db->query($sql, [$branchCode]);
if (!$qry || $qry->num_rows() == 0) {
return 0;
}
return (int) $qry->row_array()["branchCompanyID"];
}
/**
* getRegionalIDByBranchCode — Ambil ID regional berdasarkan kode cabang.
*
* Data diambil dari tabel `m_branch` yang aktif.
* Digunakan untuk mengisi field JurnalS_RegionalID pada header jurnal.
*
* @param string $branchCode Kode cabang (misal: "JKT-01")
* @return int regionalID yang sesuai, atau 0 jika tidak ditemukan
*/
private function getRegionalIDByBranchCode($branchCode)
{
$sql = "SELECT M_BranchS_RegionalID AS regionalID
FROM m_branch
WHERE M_BranchCode = ?
AND M_BranchIsActive = 'Y'
LIMIT 1";
$qry = $this->db->query($sql, [$branchCode]);
if (!$qry || $qry->num_rows() == 0) {
return 0;
}
return (int) $qry->row_array()["regionalID"];
}
/**
* getJurnalTypeID — Ambil ID tipe jurnal berdasarkan kode tipe.
*
* Data diambil dari tabel `jurnal_type` yang aktif.
* Untuk PI cicilan order aset, kode yang digunakan adalah "PAYMENT".
*
* @param string $jurnalTypeCode Kode tipe jurnal (misal: "PAYMENT")
* @return int JurnalTypeID yang sesuai, atau 0 jika tidak ditemukan
*/
private function getJurnalTypeID($jurnalTypeCode)
{
$sql = "SELECT JurnalTypeID
FROM jurnal_type
WHERE JurnalTypeCode = ?
AND JurnalTypeIsActive = 'Y'
LIMIT 1";
$qry = $this->db->query($sql, [$jurnalTypeCode]);
if (!$qry || $qry->num_rows() == 0) {
return 0;
}
return (int) $qry->row_array()["JurnalTypeID"];
}
/**
* getEligiblePurchaseOrderAssetContracts — Ambil kontrak aset yang layak dibuatkan jurnal.
*
* Query ini mengambil semua kontrak dari `purchase_order_asset_contract` yang memenuhi
* syarat berikut:
* - Kontrak aktif, status "belum lunas", nilai cicilan > 0
* - Cicilan terbayar masih kurang dari total cicilan
* - Tanggal kontrak masuk dalam rentang periode yang diberikan
* - Tanggal jatuh tempo cicilan sudah lewat atau sama dengan hari ini
* - PO sudah Approved dan aktif
* - Barang sudah diterima dan receive order sudah confirmed
*
* Data yang dikembalikan mencakup:
* - Detail kontrak (ID, nama, tanggal, nilai cicilan)
* - Data PO (nomor PO, supplier, payment term, warehouse)
* - Data cabang (kode cabang, nama, regionalID, branchCompanyID)
* - Data item PO pertama (sebagai referensi baris jurnal)
*
* @param string $startDate Awal periode filter (YYYY-MM-DD)
* @param string $endDate Akhir periode filter (YYYY-MM-DD)
* @return array Array of row kontrak yang eligible
*/
private function getEligiblePurchaseOrderAssetContracts($startDate, $endDate)
{
$sql = "SELECT
c.PurchaseOrderAssetContractID,
si.SupplierInvoiceID,
si.SupplierInvoiceNumber,
c.PurchaseOrderAssetContractPurchaseOrderID,
c.PurchaseOrderAssetContractName,
c.PurchaseOrderAssetContractStartDate,
c.PurchaseOrderAssetContractEndDate,
c.PurchaseOrderAssetContractInstallmentNumber,
c.PurchaseOrderAssetContractInstallmentPaid,
c.PurchaseOrderAssetContractInstallmentDate,
c.PurchaseOrderAssetContractInstallmentPayAmount,
c.PurchaseOrderAssetContractReceiveOrderPoID,
po.PurchaseOrderID,
po.PurchaseOrderNumber,
po.PurchaseOrderSupplierID,
po.PurchaseOrderPaymentTerm,
po.PurchaseOrderWarehouseType,
po.PurchaseOrderWarehouseID,
wh.WarehouseCode,
wh.WarehouseName,
wh.WarehouseType,
wh.WarehouseS_RegionalID AS WarehouseS_RegionalID,
wh.WarehouseM_BranchID AS WarehouseM_BranchID,
ro.ReceiveOrderPoID,
ro.ReceiveOrderPoConfirmed,
mi.M_ItemID AS ItemID,
mi.M_ItemCode AS ItemCode,
mi.M_ItemDesc AS ItemDesc,
mi.M_ItemFa_ClassID,
fc.Fa_ClassID AS ItemFaClassID,
fc.Fa_ClassName AS ItemFaClassName,
coa_bayar.coaID AS ItemCoaID,
coa_bayar.coaAccountNo AS ItemCoaAccountNo,
coa_bayar.coaDescription AS ItemCoaDesc,
coa_hutang.coaID AS HutangCoaID,
coa_hutang.coaAccountNo AS HutangCoaAccountNo,
coa_hutang.coaDescription AS HutangCoaDesc,
m_branch.M_BranchCode,
m_branch.M_BranchName,
m_branch.M_BranchS_RegionalID,
m_branch_companydetail.M_BranchCompanyDetailM_BranchCompanyID AS M_BranchCompanyID,
ps.PurchaseOrderSummaryID,
ps.PurchaseOrderSummaryItemID,
ps.PurchaseOrderSummaryItemUnitID
FROM purchase_order_asset_contract c
-- Pastikan PO sudah Approved dan aktif
JOIN purchase_order po
ON po.PurchaseOrderID = c.PurchaseOrderAssetContractPurchaseOrderID
AND po.PurchaseOrderIsActive = 'Y'
AND po.PurchaseOrderStatus = 'Approved'
-- Data warehouse/gudang tujuan PO
LEFT JOIN warehouse wh
ON wh.WarehouseID = po.PurchaseOrderWarehouseID
-- Ambil 1 item PO pertama sebagai referensi baris jurnal
LEFT JOIN (
SELECT ps0.*
FROM purchase_order_summary ps0
JOIN (
SELECT
PurchaseOrderSummaryPurchaseOrderID,
MIN(PurchaseOrderSummaryID) AS PurchaseOrderSummaryID
FROM purchase_order_summary
WHERE PurchaseOrderSummaryIsActive = 'Y'
GROUP BY PurchaseOrderSummaryPurchaseOrderID
) psx
ON psx.PurchaseOrderSummaryID = ps0.PurchaseOrderSummaryID
) ps
ON ps.PurchaseOrderSummaryPurchaseOrderID = po.PurchaseOrderID
-- Hubungkan dengan detail supplier_invoice_detail terlebih dahulu
JOIN supplier_invoice_detail sid
ON sid.SupplierInvoiceDetailPurchaseOrderID = po.PurchaseOrderID
AND sid.SupplierInvoiceDetailPurchaseOrderSummaryID = ps.PurchaseOrderSummaryID
AND sid.SupplierInvoiceDetailIsActive = 'Y'
-- Baru hubungkan ke header supplier_invoice untuk mengambil nomor invoice
JOIN supplier_invoice si
ON si.SupplierInvoiceID = sid.SupplierInvoiceDetailSupplierInvoiceID
AND si.SupplierInvoiceDate >= DATE(?)
AND si.SupplierInvoiceDate <= DATE(?)
AND si.SupplierInvoiceIsActive = 'Y'
-- Pastikan barang sudah diterima (receive order confirmed)
JOIN (
SELECT
rd.ReceiveOrderPoDetailPurchaseOrderID,
MIN(ro0.ReceiveOrderPoID) AS ReceiveOrderPoID,
MAX(ro0.ReceiveOrderPoConfirmed) AS ReceiveOrderPoConfirmed
FROM receive_order_po ro0
JOIN receive_order_po_detail rd
ON rd.ReceiveOrderPoDetailReceiveOrderPoID = ro0.ReceiveOrderPoID
AND rd.ReceiveOrderPoDetailIsActive = 'Y'
WHERE ro0.ReceiveOrderPoIsActive = 'Y'
AND ro0.ReceiveOrderPoConfirmed = 'Y'
GROUP BY rd.ReceiveOrderPoDetailPurchaseOrderID
) ro
ON ro.ReceiveOrderPoDetailPurchaseOrderID = po.PurchaseOrderID
-- Data cabang dari warehouse
LEFT JOIN m_branch
ON m_branch.M_BranchID = wh.WarehouseM_BranchID
AND m_branch.M_BranchIsActive = 'Y'
-- Data branch company untuk header jurnal
LEFT JOIN m_branch_companydetail
ON m_branch_companydetail.M_BranchCompanyDetailM_BranchCode = m_branch.M_BranchCode
AND m_branch_companydetail.M_BranchCompanyDetailIsActive = 'Y'
-- COA jurnal diambil dari item -> fa_class
LEFT JOIN m_item mi
ON mi.M_ItemID = ps.PurchaseOrderSummaryItemID
AND mi.M_ItemIsActive = 'Y'
LEFT JOIN fa_class fc
ON fc.Fa_ClassID = mi.M_ItemFa_ClassID
AND fc.Fa_ClassIsActive = 'Y'
-- Join langsung ke tabel coa untuk memastikan kevalidan akun dan deskripsi
LEFT JOIN coa coa_hutang
ON coa_hutang.coaID = fc.Fa_ClassHutangCoaID
AND coa_hutang.coaIsActive = 'Y'
LEFT JOIN coa coa_bayar
ON coa_bayar.coaID = fc.Fa_ClassCoaID
AND coa_bayar.coaIsActive = 'Y'
WHERE c.PurchaseOrderAssetContractIsActive = 'Y'
AND c.PurchaseOrderAssetContractStatus = 'belum lunas'
-- Hanya kontrak yang ada nilai cicilannya
AND IFNULL(c.PurchaseOrderAssetContractInstallmentPayAmount, 0) > 0
-- Hanya kontrak yang belum selesai seluruh cicilannya
AND IFNULL(c.PurchaseOrderAssetContractInstallmentPaid, 0) < IFNULL(c.PurchaseOrderAssetContractInstallmentNumber, 0)
-- Kontrak sudah mulai sebelum atau pada akhir periode
AND DATE(c.PurchaseOrderAssetContractStartDate) <= DATE(?)
-- Kontrak belum berakhir (atau tidak ada tanggal akhir)
AND (
c.PurchaseOrderAssetContractEndDate IS NULL
OR DATE(c.PurchaseOrderAssetContractEndDate) >= DATE(?)
)
-- Tanggal jatuh tempo cicilan sudah tiba
AND IFNULL(c.PurchaseOrderAssetContractInstallmentDate, 1) <= ?
-- Pastikan belum pernah dibuatkan jurnal untuk invoice cicilan ini
AND NOT EXISTS (
SELECT 1
FROM jurnal_addon ja
JOIN jurnal j ON j.jurnalID = ja.jurnalAddOnJurnalID
WHERE ja.jurnalAddOnCode = 'PIINSTALMENT'
AND ja.jurnalAddOnValue = si.SupplierInvoiceNumber
)
ORDER BY c.PurchaseOrderAssetContractID ASC";
$qry = $this->db->query($sql, [
$startDate,
$endDate,
$endDate,
$startDate,
(int) date("d", strtotime($endDate))
]);
if (!$qry) {
$this->sys_error_db("Gagal mengambil data purchase_order_asset_contract.");
exit;
}
return $qry->result_array();
}
/**
* isValidDate — Validasi format tanggal YYYY-MM-DD.
*
* @param string $tanggal String tanggal yang akan divalidasi
* @return bool true jika format valid, false jika tidak
*/
private function isValidDate($tanggal)
{
$d = DateTime::createFromFormat("Y-m-d", $tanggal);
return $d && $d->format("Y-m-d") === $tanggal;
}
}

View File

@@ -1,65 +0,0 @@
# ============================================================
# FILE : PurchaseInvoiceInstallment.http
# MODUL : Scheduler — Generate Supplier Installment Cicilan Aset
# ============================================================
#
# DESKRIPSI
# ---------
# File ini berisi HTTP request untuk menguji endpoint scheduler
# yang secara otomatis membuat baris cicilan ke tabel
# supplier_installment setiap bulan.
#
# CARA PAKAI
# ----------
# 1. Gunakan ekstensi "REST Client" di VS Code (humao.rest-client)
# atau tool sejenis (IntelliJ HTTP Client, Postman, dll).
# 2. Ganti nilai @host sesuai environment.
# 3. Klik "Send Request" di atas tiap blok ###
#
# ALUR
# ----
# [1] GenerateMonthlyInvoices → Jalankan proses generate installment
#
# CATATAN
# -------
# - Default periode: bulan berjalan (tanggal 1 s/d akhir bulan)
# - Aman dijalankan ulang — dedup berdasarkan PO + bulan mencegah
# duplikasi
# - Tidak membuat jurnal — jurnal dibuat saat pembayaran cashier
# - Tidak update kontrak — InstallmentPaid diupdate saat pembayaran
# ============================================================
@host = https://accone.aplikasi.web.id/one-api
# ============================================================
# [1] GENERATE INSTALLMENT BULANAN (MAIN ENDPOINT)
# ============================================================
# Satu request ini akan:
# Step 1: Validasi kontrak (aktif, belum lunas, dalam rentang)
# Step 2: Validasi PO (Approved, Active)
# Step 3: Validasi RO (Confirmed, Active)
# Step 4: Validasi parent invoice (IsInstallment = 'Y')
# Step 5: Cek dedup (belum ada installment bulan ini)
# Step 6: INSERT ke supplier_installment (Status = 'Pending')
#
# Response:
# - totalEligible : jumlah kontrak lolos validasi
# - totalInserted : jumlah baris berhasil diinsert
# - created[] : detail tiap installment yang dibuat
# ============================================================
### [1] Generate installment untuk periode tertentu
POST {{host}}/mockup/scheduler/PurchaseInvoiceInstallment/GenerateMonthlyInvoices
Content-Type: application/json
{
"startDate": "2026-07-01",
"endDate": "2026-07-31"
}
### [1a] Generate installment bulan berjalan (tanpa parameter)
POST {{host}}/mockup/scheduler/PurchaseInvoiceInstallment/GenerateMonthlyInvoices
Content-Type: application/json
{}

View File

@@ -1,302 +0,0 @@
<?php
/**
* PurchaseInvoiceInstallment
*
* CRON scheduler untuk membuat baris cicilan otomatis ke tabel supplier_installment
* setiap bulan berdasarkan kontrak aset yang aktif dan belum lunas.
*
* Endpoint:
* POST /scheduler/PurchaseInvoiceInstallment/GenerateMonthlyInvoices
*/
class PurchaseInvoiceInstallment extends MY_Controller
{
var $db;
public function index()
{
echo "Purchase Invoice Installment — Auto Generate Installment Cicilan Aset";
}
public function __construct()
{
parent::__construct();
}
/**
* GenerateMonthlyInvoices — Step 6
*
* Creates supplier_installment rows for all eligible contracts this month.
* No journal is created here — that happens at cashier payment time.
* Contract InstallmentPaid is NOT updated here — that happens at payment time.
*
* Called by CRON daily at 1:00 AM.
* Defaults to current month if no startDate/endDate provided.
*/
public function GenerateMonthlyInvoices()
{
try {
$para = $this->sys_input;
$userID = !empty($this->sys_user["M_UserID"])
? (int) $this->sys_user["M_UserID"]
: 0;
$startDate = !empty($para["startDate"])
? $para["startDate"]
: date("Y-m-01");
$endDate = !empty($para["endDate"])
? $para["endDate"]
: date("Y-m-t");
if (!$this->isValidDate($startDate) || !$this->isValidDate($endDate)) {
throw new Exception("Format tanggal tidak valid.");
}
if (strtotime($startDate) > strtotime($endDate)) {
throw new Exception("startDate > endDate.");
}
// ── Steps 15: Get eligible contracts ────────────────────
$eligible = $this->getEligibleInstallments($startDate, $endDate);
$created = [];
$inserted = 0;
$this->db->trans_begin();
foreach ($eligible as $row) {
$amount = (float) $row["PurchaseOrderAssetContractInstallmentPayAmount"];
$dayOfMonth = (int) ($row["PurchaseOrderAssetContractInstallmentDate"] ?? 1);
$lastDay = (int) date("t", strtotime($endDate));
$dayOfMonth = min($dayOfMonth, $lastDay);
$installDate = date("Y-m", strtotime($endDate)) . "-" . str_pad($dayOfMonth, 2, "0", STR_PAD_LEFT);
$dueDate = date("Y-m-d", strtotime($installDate . " +7 days"));
$createdBy = (int) ($row["PurchaseOrderAssetContractCreatedUserID"] ?? $userID);
// ── Step 6: INSERT supplier_installment ──────────────
$sql = "INSERT INTO supplier_installment (
SupplierInstallmentPurchaseOrderID,
SupplierInstallmentSupplierID,
SupplierInstallmentSupplierInvoiceID,
SupplierInstallmentAmount,
SupplierInstallmentDate,
SupplierInstallmentDueDate,
SupplierInstallmentPaymentID,
SupplierInstallmentStatus,
SupplierInstallmentIsLunas,
SupplierInstallmentIsActive,
SupplierInstallmentCreated,
SupplierInstallmentCreatedUserID
) VALUES (?, ?, ?, ?, ?, ?, 0, 'Pending', 'N', 'Y', NOW(), ?)";
$que = $this->db->query($sql, [
$row["PurchaseOrderID"],
$row["PurchaseOrderSupplierID"],
$row["SupplierInvoiceID"],
$amount,
$installDate,
$dueDate,
$createdBy
]);
if (!$que) {
$this->db->trans_rollback();
$this->sys_error_db("Gagal insert supplier_installment.");
exit;
}
$installmentID = $this->db->insert_id();
$inserted++;
$created[] = [
"installmentID" => $installmentID,
"contractID" => $row["PurchaseOrderAssetContractID"],
"purchaseOrderID" => $row["PurchaseOrderID"],
"parentInvoiceID" => $row["SupplierInvoiceID"],
"parentInvoiceNumber" => $row["SupplierInvoiceNumber"],
"amount" => $amount,
"installDate" => $installDate,
"dueDate" => $dueDate
];
}
if ($this->db->trans_status() === false) {
$this->db->trans_rollback();
$this->sys_error_db("Transaksi gagal.");
exit;
}
$this->db->trans_commit();
$this->sys_ok([
"startDate" => $startDate,
"endDate" => $endDate,
"totalEligible" => count($eligible),
"totalInserted" => $inserted,
"created" => $created
]);
} catch (Exception $exc) {
if ($this->db->trans_status() === false) {
$this->db->trans_rollback();
}
$this->sys_error($exc->getMessage());
}
}
/**
* Ambil data user berdasarkan userID untuk keperluan CRON.
* Jika user tidak ditemukan, kembalikan data default (tanpa branch/regional).
*
* @param int $userID
* @return array
*/
private function getCronUser($userID)
{
$sql = "SELECT
M_UserID,
M_UserM_BranchID AS M_BranchID,
M_UserS_RegionalID AS S_RegionalID
FROM m_user
WHERE M_UserID = ?
LIMIT 1";
$qry = $this->db->query($sql, [$userID]);
if ($qry && $qry->num_rows() > 0) {
$user = $qry->row_array();
$user["loginLevel"] = "branch";
return $user;
}
// User tidak ditemukan, gunakan data kosong agar proses tetap berjalan
return [
"M_UserID" => $userID,
"M_BranchID" => 0,
"S_RegionalID" => 0,
"loginLevel" => "branch"
];
}
/**
* Hitung tanggal jatuh tempo berdasarkan tanggal acuan dan payment term (dalam hari).
*
* @param string $tanggal Format YYYY-MM-DD
* @param int $term Jumlah hari payment term
* @return string Tanggal jatuh tempo (YYYY-MM-DD)
*/
private function hitungJatuhTempo($tanggal, $term)
{
$hari = is_numeric($term) ? (int) $term : 0;
if ($hari < 0) {
$hari = 0;
}
return date("Y-m-d", strtotime($tanggal . " +" . $hari . " days"));
}
/**
* Validasi apakah string adalah tanggal yang valid dengan format YYYY-MM-DD.
*
* @param string $tanggal
* @return bool
*/
private function isValidDate($tanggal)
{
$d = DateTime::createFromFormat("Y-m-d", $tanggal);
return $d && $d->format("Y-m-d") === $tanggal;
}
/**
* getEligibleInstallments — Steps 15 combined
*
* Returns contracts that:
* Step 1: Are active, not paid off, within date range, due date reached
* Step 2: Have approved & active PO
* Step 3: Have confirmed & active RO
* Step 4: Have a parent supplier_invoice with IsInstallment = 'Y'
* Step 5: Do NOT already have a supplier_installment for this month
*
* @param string $startDate YYYY-MM-DD
* @param string $endDate YYYY-MM-DD
* @return array
*/
private function getEligibleInstallments($startDate, $endDate)
{
$dayOfMonth = (int) date("d", strtotime($endDate));
$sql = "SELECT
c.PurchaseOrderAssetContractID,
c.PurchaseOrderAssetContractInstallmentPayAmount,
c.PurchaseOrderAssetContractInstallmentDate,
c.PurchaseOrderAssetContractCreatedUserID,
po.PurchaseOrderID,
po.PurchaseOrderSupplierID,
si.SupplierInvoiceID,
si.SupplierInvoiceNumber
FROM purchase_order_asset_contract c
-- Step 2: PO must be Approved and Active
JOIN purchase_order po
ON po.PurchaseOrderID = c.PurchaseOrderAssetContractPurchaseOrderID
AND po.PurchaseOrderIsActive = 'Y'
AND po.PurchaseOrderStatus = 'Approved'
-- Step 3: RO must be Confirmed and Active
JOIN (
SELECT
rd.ReceiveOrderPoDetailPurchaseOrderID,
MIN(ro0.ReceiveOrderPoID) AS ReceiveOrderPoID,
MAX(ro0.ReceiveOrderPoConfirmed) AS ReceiveOrderPoConfirmed
FROM receive_order_po ro0
JOIN receive_order_po_detail rd
ON rd.ReceiveOrderPoDetailReceiveOrderPoID = ro0.ReceiveOrderPoID
AND rd.ReceiveOrderPoDetailIsActive = 'Y'
WHERE ro0.ReceiveOrderPoIsActive = 'Y'
AND ro0.ReceiveOrderPoConfirmed = 'Y'
GROUP BY rd.ReceiveOrderPoDetailPurchaseOrderID
) ro ON ro.ReceiveOrderPoDetailPurchaseOrderID = po.PurchaseOrderID
-- Step 4: Parent invoice must exist with IsInstallment = 'Y'
JOIN supplier_invoice si
ON si.SupplierInvoiceReceiveOrderPoID = ro.ReceiveOrderPoID
AND si.SupplierInvoiceIsActive = 'Y'
AND si.SupplierInvoiceIsInstallment = 'Y'
-- Step 1: Contract eligibility
WHERE c.PurchaseOrderAssetContractIsActive = 'Y'
AND c.PurchaseOrderAssetContractStatus = 'belum lunas'
AND IFNULL(c.PurchaseOrderAssetContractInstallmentPayAmount, 0) > 0
AND IFNULL(c.PurchaseOrderAssetContractInstallmentPaid, 0)
< IFNULL(c.PurchaseOrderAssetContractInstallmentNumber, 0)
AND DATE(c.PurchaseOrderAssetContractStartDate) <= DATE(?)
AND (
c.PurchaseOrderAssetContractEndDate IS NULL
OR DATE(c.PurchaseOrderAssetContractEndDate) >= DATE(?)
)
AND IFNULL(c.PurchaseOrderAssetContractInstallmentDate, 1) <= ?
-- Step 5: Dedup — no existing supplier_installment this month (any status)
AND NOT EXISTS (
SELECT 1
FROM supplier_installment inst
WHERE inst.SupplierInstallmentIsActive = 'Y'
AND inst.SupplierInstallmentPurchaseOrderID = po.PurchaseOrderID
AND DATE_FORMAT(inst.SupplierInstallmentDate, '%Y-%m') = DATE_FORMAT(?, '%Y-%m')
)
ORDER BY c.PurchaseOrderAssetContractID ASC";
$params = [$endDate, $startDate, $dayOfMonth, $endDate];
$qry = $this->db->query($sql, $params);
if (!$qry) {
$this->sys_error_db("Gagal mengambil daftar installment eligible.");
exit;
}
return $qry->result_array();
}
}

View File

@@ -1,220 +0,0 @@
<?php
/**
* PurchaseInvoiceInstallmentInsert
*
* Endpoint khusus untuk menyimpan supplier_invoice dan supplier_invoice_detail
* dari payload yang dikirim controller generator via cURL.
*/
class PurchaseInvoiceInstallmentInsert extends MY_Controller
{
var $db;
public function index()
{
echo "Purchase Invoice Installment Insert";
}
public function __construct()
{
parent::__construct();
}
public function InsertSupplierInvoice()
{
try {
$para = $this->sys_input;
$required = [
"nomorPI",
"tanggalPI",
"tanggalJatuhTempo",
"jumlahCicilan",
"catatan",
"deskripsi",
"userID",
"purchaseOrderAssetContractID",
"purchaseOrderID",
"receiveOrderPoID",
"supplierID",
"purchaseOrderSummaryID",
"purchaseOrderSummaryItemID",
"purchaseOrderSummaryItemUnitID"
];
foreach ($required as $field) {
if (!isset($para[$field]) || $para[$field] === "" || $para[$field] === null) {
throw new Exception("Field wajib belum lengkap: " . $field);
}
}
$tanggalPI = $para["tanggalPI"];
$tanggalJatuhTempo = $para["tanggalJatuhTempo"];
if (!$this->isValidDate($tanggalPI) || !$this->isValidDate($tanggalJatuhTempo)) {
throw new Exception("Format tanggal tidak valid. Gunakan YYYY-MM-DD.");
}
$jumlahCicilan = (float) $para["jumlahCicilan"];
if ($jumlahCicilan <= 0) {
throw new Exception("jumlahCicilan harus lebih besar dari 0.");
}
$receiveOrderPoID = (int) $para["receiveOrderPoID"];
$monthKey = date("Y-m", strtotime($tanggalPI));
$sqlDuplikat = "SELECT SupplierInvoiceID, SupplierInvoiceNumber
FROM supplier_invoice
WHERE SupplierInvoiceIsActive = 'Y'
AND SupplierInvoiceStatus = 'Draft'
AND SupplierInvoiceReceiveOrderPoID = ?
AND DATE_FORMAT(SupplierInvoiceDate, '%Y-%m') = ?
LIMIT 1";
$qryDuplikat = $this->db->query($sqlDuplikat, [$receiveOrderPoID, $monthKey]);
if (!$qryDuplikat) {
$this->sys_error_db("Gagal mengecek duplikasi supplier_invoice.");
exit;
}
if ($qryDuplikat->num_rows() > 0) {
$existing = $qryDuplikat->row_array();
$this->sys_ok([
"duplicate" => true,
"supplierInvoiceID" => $existing["SupplierInvoiceID"],
"supplierInvoiceNumber" => $existing["SupplierInvoiceNumber"]
]);
return;
}
$this->db->trans_begin();
$sqlHeader = "INSERT INTO supplier_invoice (
SupplierInvoiceNumber,
SupplierInvoiceReceiveOrderPoID,
SupplierInvoiceDate,
SupplierInvoiceDueDate,
SupplierInvoiceDraftPaymentDate,
SupplierInvoiceSupplierID,
SupplierInvoiceSupplierInvoiceNumber,
SupplierInvoiceSupplierInvoiceDate,
SupplierInvoiceSubTotal,
SupplierInvoiceDiscountPercent,
SupplierInvoiceDiscountAmount,
SupplierInvoiceTaxPercentPph,
SupplierInvoiceTaxAmountPph,
SupplierInvoiceTaxPercentPpn,
SupplierInvoiceTaxAmountPpn,
SupplierInvoiceShippingCost,
SupplierInvoiceAdjustmentAmount,
SupplierInvoiceAdjustmentNote,
SupplierInvoiceGrandTotal,
SupplierInvoiceUnpaid,
SupplierInvoiceNote,
SupplierInvoiceStatus,
SupplierInvoiceCreatedUserID
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
$qryHeader = $this->db->query($sqlHeader, [
$para["nomorPI"],
$receiveOrderPoID,
$tanggalPI,
$tanggalJatuhTempo,
$tanggalPI,
(int) $para["supplierID"],
null,
null,
$jumlahCicilan,
0,
0,
0,
0,
0,
0,
0,
0,
null,
$jumlahCicilan,
$jumlahCicilan,
$para["catatan"],
"Draft",
(int) $para["userID"]
]);
if (!$qryHeader) {
$this->db->trans_rollback();
$this->sys_error_db("Gagal insert header supplier_invoice.");
exit;
}
$supplierInvoiceID = $this->db->insert_id();
$sqlDetail = "INSERT INTO supplier_invoice_detail (
SupplierInvoiceDetailSupplierInvoiceID,
SupplierInvoiceDetailPurchaseOrderID,
SupplierInvoiceDetailReceiveOrderPoID,
SupplierInvoiceDetailPurchaseOrderSummaryID,
SupplierInvoiceDetailItemID,
SupplierInvoiceDetailItemUnitID,
SupplierInvoiceDetailDescription,
SupplierInvoiceDetailQty,
SupplierInvoiceDetailPrice,
SupplierInvoiceDetailDiscountPercent,
SupplierInvoiceDetailDiscountDiscountRupiah,
SupplierInvoiceDetailDiscountDiscountType,
SupplierInvoiceDetailDiscountPoProrata,
SupplierInvoiceDetailDiscountAmount,
SupplierInvoiceDetailTotal,
SupplierInvoiceDetailUnpaid,
SupplierInvoiceDetailCreatedUserID
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
$qryDetail = $this->db->query($sqlDetail, [
$supplierInvoiceID,
(int) $para["purchaseOrderID"],
$receiveOrderPoID,
(int) $para["purchaseOrderSummaryID"],
(int) $para["purchaseOrderSummaryItemID"],
(int) $para["purchaseOrderSummaryItemUnitID"],
$para["deskripsi"],
1,
$jumlahCicilan,
0,
0,
"R",
0,
0,
$jumlahCicilan,
$jumlahCicilan,
(int) $para["userID"]
]);
if (!$qryDetail) {
$this->db->trans_rollback();
$this->sys_error_db("Gagal insert detail supplier_invoice_detail.");
exit;
}
if ($this->db->trans_status() === false) {
$this->db->trans_rollback();
$this->sys_error_db("Transaksi insert supplier_invoice gagal.");
exit;
}
$this->db->trans_commit();
$this->sys_ok([
"duplicate" => false,
"supplierInvoiceID" => $supplierInvoiceID,
"supplierInvoiceNumber" => $para["nomorPI"]
]);
} catch (Exception $exc) {
$this->sys_error($exc->getMessage());
}
}
private function isValidDate($tanggal)
{
$d = DateTime::createFromFormat("Y-m-d", $tanggal);
return $d && $d->format("Y-m-d") === $tanggal;
}
}

View File

@@ -28,92 +28,29 @@ class Billv2 extends MY_Controller {
$offset = ($params['currentpage'] - 1) * $limit; $offset = ($params['currentpage'] - 1) * $limit;
} }
// ── UNION base — invoice + downpayment + installment ─── $sql_base = "SELECT
$sql_base = " SupplierPaymentID,
SELECT SupplierPaymentDate,
sp.SupplierPaymentID, SupplierPaymentNumber,
sp.SupplierPaymentDate, SupplierPaymentAmount,
sp.SupplierPaymentNumber, SupplierPaymentStatus,
sp.SupplierPaymentAmount, SupplierPaymentIsVerif,
sp.SupplierPaymentStatus, SupplierPaymentIsApproved,
sp.SupplierPaymentIsVerif, SupplierInvoiceID,
sp.SupplierPaymentIsApproved, SupplierInvoiceNumber,
sp.SupplierPaymentIsActive, SupplierInvoiceDraftPaymentDate,
si.SupplierInvoiceID, SupplierCode,
si.SupplierInvoiceNumber, SupplierName
si.SupplierInvoiceDraftPaymentDate, FROM supplier_payment
sup.SupplierCode, JOIN supplier_invoice ON SupplierInvoiceID = SupplierPaymentSupplierInvoiceID
sup.SupplierName, AND SupplierPaymentNumber LIKE ?
'INVOICE' AS type AND (SupplierPaymentDate BETWEEN DATE(?) AND DATE(?))
FROM supplier_payment sp AND (SupplierPaymentStatus = ? OR ? = 'All')
JOIN supplier_invoice si JOIN supplier ON SupplierID = SupplierInvoiceSupplierID
ON si.SupplierInvoiceID = sp.SupplierPaymentSupplierInvoiceID WHERE SupplierPaymentIsActive = 'Y'
JOIN supplier sup ORDER BY SupplierPaymentID DESC";
ON sup.SupplierID = si.SupplierInvoiceSupplierID
WHERE sp.SupplierPaymentSupplierInvoiceID > 0
UNION ALL
SELECT
sp.SupplierPaymentID,
sp.SupplierPaymentDate,
sp.SupplierPaymentNumber,
sp.SupplierPaymentAmount,
sp.SupplierPaymentStatus,
sp.SupplierPaymentIsVerif,
sp.SupplierPaymentIsApproved,
sp.SupplierPaymentIsActive,
dp.SupplierDownpaymentID * -1 AS SupplierInvoiceID,
CONCAT('DP-', po.PurchaseOrderNumber) AS SupplierInvoiceNumber,
dp.SupplierDownpaymentDueDate AS SupplierInvoiceDraftPaymentDate,
dp_sup.SupplierCode AS SupplierCode,
dp_sup.SupplierName AS SupplierName,
'DP' AS type
FROM supplier_payment sp
JOIN supplier_downpayment dp
ON dp.SupplierDownpaymentID = sp.SupplierPaymentSupplierDownpaymentID
JOIN supplier dp_sup
ON dp_sup.SupplierID = dp.SupplierDownpaymentSupplierID
JOIN purchase_order po
ON po.PurchaseOrderID = dp.SupplierDownpaymentPurchasOrderID
WHERE sp.SupplierPaymentSupplierDownpaymentID IS NOT NULL
UNION ALL
SELECT
sp.SupplierPaymentID,
sp.SupplierPaymentDate,
sp.SupplierPaymentNumber,
sp.SupplierPaymentAmount,
sp.SupplierPaymentStatus,
sp.SupplierPaymentIsVerif,
sp.SupplierPaymentIsApproved,
sp.SupplierPaymentIsActive,
0 AS SupplierInvoiceID,
CONCAT('INST-', si_inst.SupplierInvoiceNumber) AS SupplierInvoiceNumber,
inst.SupplierInstallmentDueDate AS SupplierInvoiceDraftPaymentDate,
inst_sup.SupplierCode AS SupplierCode,
inst_sup.SupplierName AS SupplierName,
'INSTALLMENT' AS type
FROM supplier_payment sp
JOIN supplier_installment inst
ON inst.SupplierInstallmentID = sp.SupplierPaymentSupplierInstallmentID
JOIN supplier_invoice si_inst
ON si_inst.SupplierInvoiceID = inst.SupplierInstallmentSupplierInvoiceID
JOIN supplier inst_sup
ON inst_sup.SupplierID = inst.SupplierInstallmentSupplierID
WHERE sp.SupplierPaymentSupplierInstallmentID IS NOT NULL";
// ── Outer: common filters + ordering + pagination ───────
$sql_data = "
SELECT * FROM ($sql_base) AS combined
WHERE SupplierPaymentIsActive = 'Y'
AND SupplierPaymentNumber LIKE ?
AND (SupplierPaymentDate BETWEEN DATE(?) AND DATE(?))
AND (SupplierPaymentStatus = ? OR ? = 'All')
ORDER BY SupplierPaymentID DESC
LIMIT ? OFFSET ?";
$sql_data = $sql_base . " LIMIT ? OFFSET ? ";
$que_data = $this->db->query($sql_data, [ $que_data = $this->db->query($sql_data, [
$keyword, $params['startdate'], $params['enddate'], $keyword, $params['startdate'], $params['enddate'],
$params['status'], $params['status'], $limit, $offset $params['status'], $params['status'], $limit, $offset
@@ -122,13 +59,7 @@ class Billv2 extends MY_Controller {
throw new Exception("[Error] failed get data supplier payment", 2); throw new Exception("[Error] failed get data supplier payment", 2);
} }
// ── COUNT — wrap UNION in outer filter ────────────────── $sql_total = "SELECT COUNT(*) AS total FROM ($sql_base) AS x";
$sql_total = "SELECT COUNT(*) AS total FROM ($sql_base) AS combined
WHERE SupplierPaymentIsActive = 'Y'
AND SupplierPaymentNumber LIKE ?
AND (SupplierPaymentDate BETWEEN DATE(?) AND DATE(?))
AND (SupplierPaymentStatus = ? OR ? = 'All')";
$que_total = $this->db->query($sql_total, [ $que_total = $this->db->query($sql_total, [
$keyword, $params['startdate'], $params['enddate'], $keyword, $params['startdate'], $params['enddate'],
$params['status'], $params['status'] $params['status'], $params['status']
@@ -139,10 +70,11 @@ class Billv2 extends MY_Controller {
$output = [ $output = [
"records" => $que_data->result_array(), "records" => $que_data->result_array(),
"total" => $que_total->row_array()['total'] "total" =>$que_total->row_array()['total']
]; ];
$this->sys_ok($output); $this->sys_ok($output);
exit;
} catch (Exception $exc) { } catch (Exception $exc) {
$message = $exc->getMessage(); $message = $exc->getMessage();
$code = $exc->getCode(); $code = $exc->getCode();
@@ -164,169 +96,70 @@ class Billv2 extends MY_Controller {
$para = $this->sys_input; $para = $this->sys_input;
// ── Detect payment type ────────────────────────────────── $sql = "SELECT
$sql_type = "SELECT SupplierInvoiceID,
SupplierPaymentSupplierInvoiceID, SupplierInvoiceRefNumber,
SupplierPaymentSupplierDownpaymentID, SupplierInvoiceDeliveryOrderNumber,
SupplierPaymentSupplierInstallmentID SupplierInvoiceSupplierInvoiceNumber,
FROM supplier_payment SupplierInvoiceSupplierInvoiceDate,
WHERE SupplierPaymentID = ? AND SupplierPaymentIsActive = 'Y'"; SupplierInvoiceSubTotal,
SupplierInvoiceTaxPercentPph,
$que_type = $this->db->query($sql_type, [$para['paymentID']]); SupplierInvoiceTaxPercentPpn,
if (!$que_type) { SupplierInvoiceTaxAmountPpn,
throw new Exception("[Error] failed get payment header", 2); SupplierInvoiceDiscountAmount,
SupplierInvoiceDiscountPercent,
SupplierInvoiceShippingCost,
SupplierInvoiceGrandTotal,
SupplierInvoiceAdjustmentAmount,
SupplierInvoiceAdjustmentNote,
SupplierInvoiceNote,
IF (SupplierInvoiceDiscountAmount > 0, 'R', 'P') AS DiscountType
FROM supplier_payment
JOIN supplier_invoice ON SupplierPaymentSupplierInvoiceID = SupplierInvoiceID
AND SupplierPaymentID = ?
AND SupplierPaymentIsActive = 'Y'";
$que = $this->db->query($sql, [$para['paymentID']]);
if (!$que) {
throw new Exception("[Error] failed get row data", 2);
} }
$payment = $que_type->row_array(); $data = $que->row_array();
if (!$payment) {
throw new Exception("[Error] payment not found", 2); $sql_detail = "SELECT
SupplierInvoiceDetailID,
SupplierInvoiceDetailSupplierInvoiceID,
SupplierInvoiceDetailPurchaseOrderID,
SupplierInvoiceDetailPurchaseOrderSummaryID,
SupplierInvoiceDetailReceiveOrderPoID,
SupplierInvoiceDetailReceiveOrderPoDetailID,
SupplierInvoiceDetailItemID,
SupplierInvoiceDetailItemUnitID,
SupplierInvoiceDetailDescription,
SupplierInvoiceDetailQty,
SupplierInvoiceDetailPrice,
SupplierInvoiceDetailDiscountPercent,
SupplierInvoiceDetailDiscountDiscountRupiah,
SupplierInvoiceDetailDiscountDiscountType,
SupplierInvoiceDetailDiscountAmount,
(SupplierInvoiceDetailPrice - SupplierInvoiceDetailDiscountAmount) AS DiscountedPrice,
SupplierInvoiceDetailDiscountPoProrata,
SupplierInvoiceDetailTotal,
M_ItemCode,
M_ItemDesc
FROM supplier_payment_detail
JOIN supplier_invoice_detail ON SupplierInvoiceDetailIsActive = 'Y'
AND SupplierPaymentDetailSupplierPaymentID = ?
AND SupplierInvoiceDetailSupplierInvoiceID = ?
JOIN m_item ON M_ItemID = SupplierInvoiceDetailItemID
AND M_ItemIsActive = 'Y'
GROUP BY SupplierInvoiceDetailID";
$que_detail = $this->db->query($sql_detail, [
$para['paymentID'], $data['SupplierInvoiceID']
]);
if (!$que_detail) {
throw new Exception("[Error] failed to get item payments", 2);
} }
// ── INVOICE branch ────────────────────────────────────── $data['detail'] = $que_detail->result_array();
if ($payment['SupplierPaymentSupplierInvoiceID'] > 0) {
$sql = "SELECT
si.SupplierInvoiceSubTotal,
si.SupplierInvoiceShippingCost,
si.SupplierInvoiceDiscountPercent,
si.SupplierInvoiceDiscountAmount,
si.SupplierInvoiceTaxPercentPpn,
si.SupplierInvoiceTaxAmountPpn,
si.SupplierInvoiceGrandTotal,
si.SupplierInvoiceID,
'INVOICE' AS type
FROM supplier_payment sp
JOIN supplier_invoice si
ON si.SupplierInvoiceID = sp.SupplierPaymentSupplierInvoiceID
WHERE sp.SupplierPaymentID = ? AND sp.SupplierPaymentIsActive = 'Y'";
$que = $this->db->query($sql, [$para['paymentID']]);
if (!$que) {
throw new Exception("[Error] failed get row data", 2);
}
$data = $que->row_array();
$sql_detail = "SELECT
M_ItemDesc,
SupplierInvoiceDetailQty,
SupplierInvoiceDetailPrice,
SupplierInvoiceDetailDiscountAmount,
(SupplierInvoiceDetailPrice - SupplierInvoiceDetailDiscountAmount) AS DiscountedPrice,
SupplierInvoiceDetailTotal
FROM supplier_payment_detail
JOIN supplier_invoice_detail
ON SupplierInvoiceDetailIsActive = 'Y'
AND SupplierPaymentDetailSupplierPaymentID = ?
AND SupplierInvoiceDetailSupplierInvoiceID = ?
JOIN m_item
ON M_ItemID = SupplierInvoiceDetailItemID AND M_ItemIsActive = 'Y'
GROUP BY SupplierInvoiceDetailID";
$que_detail = $this->db->query($sql_detail, [
$para['paymentID'], $data['SupplierInvoiceID']
]);
if (!$que_detail) {
throw new Exception("[Error] failed to get item payments", 2);
}
unset($data['SupplierInvoiceID']);
$data['detail'] = $que_detail->result_array();
// ── DOWNPAYMENT branch ──────────────────────────────────
} elseif ($payment['SupplierPaymentSupplierDownpaymentID'] > 0) {
$sql = "SELECT
dp.SupplierDownpaymentPurchasOrderID,
dp.SupplierDownpaymentAmount AS SupplierInvoiceSubTotal,
0 AS SupplierInvoiceShippingCost,
0 AS SupplierInvoiceDiscountPercent,
0 AS SupplierInvoiceDiscountAmount,
0 AS SupplierInvoiceTaxPercentPpn,
0 AS SupplierInvoiceTaxAmountPpn,
dp.SupplierDownpaymentAmount AS SupplierInvoiceGrandTotal,
'DP' AS type
FROM supplier_payment sp
JOIN supplier_downpayment dp
ON dp.SupplierDownpaymentID = sp.SupplierPaymentSupplierDownpaymentID
WHERE sp.SupplierPaymentID = ? AND sp.SupplierPaymentIsActive = 'Y'";
$que = $this->db->query($sql, [$para['paymentID']]);
if (!$que) {
throw new Exception("[Error] failed get DP row data", 2);
}
$data = $que->row_array();
$sql_detail = "SELECT
CONCAT('DP-', M_ItemDesc) AS M_ItemDesc,
PurchaseOrderDetailQty AS SupplierInvoiceDetailQty,
PurchaseOrderDetailPrice AS SupplierInvoiceDetailPrice,
PurchaseOrderSummaryDiscountAmount AS SupplierInvoiceDetailDiscountAmount,
(PurchaseOrderDetailPrice - PurchaseOrderSummaryDiscountAmount) AS DiscountedPrice,
PurchaseOrderSummaryTotal AS SupplierInvoiceDetailTotal
FROM supplier_downpayment
JOIN purchase_order
ON SupplierDownpaymentPurchasOrderID = PurchaseOrderID
JOIN purchase_order_detail
ON PurchaseOrderDetailPurchaseOrderID = PurchaseOrderID
AND PurchaseOrderDetailIsActive = 'Y'
JOIN purchase_order_summary
ON PurchaseOrderSummaryID = PurchaseOrderDetailPurchaseSummaryID
AND PurchaseOrderSummaryIsActive = 'Y'
JOIN m_item
ON M_ItemID = PurchaseOrderDetailItemID
WHERE SupplierDownpaymentPurchasOrderID = ?";
$que_detail = $this->db->query($sql_detail, [
$data['SupplierDownpaymentPurchasOrderID']
]);
if (!$que_detail) {
throw new Exception('failed to get dp detail', 2);
}
$data['detail'] = $que_detail->result_array();
} else {
$sql = "SELECT
inst.SupplierInstallmentAmount AS SupplierInvoiceSubTotal,
0 AS SupplierInvoiceShippingCost,
0 AS SupplierInvoiceDiscountPercent,
0 AS SupplierInvoiceDiscountAmount,
0 AS SupplierInvoiceTaxPercentPpn,
0 AS SupplierInvoiceTaxAmountPpn,
inst.SupplierInstallmentAmount AS SupplierInvoiceGrandTotal,
si.SupplierInvoiceID,
'INSTALLMENT' AS type
FROM supplier_payment sp
JOIN supplier_installment inst
ON inst.SupplierInstallmentID = sp.SupplierPaymentSupplierInstallmentID
JOIN supplier_invoice si
ON si.SupplierInvoiceID = inst.SupplierInstallmentSupplierInvoiceID
WHERE sp.SupplierPaymentID = ? AND sp.SupplierPaymentIsActive = 'Y'";
$que = $this->db->query($sql, [$para['paymentID']]);
if (!$que) {
throw new Exception("[Error] failed get Installment row data", 2);
}
$data = $que->row_array();
$sql_detail = "SELECT
M_ItemDesc,
SupplierInvoiceDetailQty,
SupplierInvoiceDetailPrice,
SupplierInvoiceDetailDiscountAmount,
(SupplierInvoiceDetailPrice - SupplierInvoiceDetailDiscountAmount) AS DiscountedPrice,
SupplierInvoiceDetailTotal
FROM supplier_invoice_detail
JOIN m_item
ON M_ItemID = SupplierInvoiceDetailItemID AND M_ItemIsActive = 'Y'
WHERE SupplierInvoiceDetailSupplierInvoiceID = ?
AND SupplierInvoiceDetailIsActive = 'Y'
GROUP BY SupplierInvoiceDetailID";
$que_detail = $this->db->query($sql_detail, [$data['SupplierInvoiceID']]);
if (!$que_detail) {
throw new Exception("[Error] failed to get installment item payments", 2);
}
unset($data['SupplierInvoiceID']);
$data['detail'] = $que_detail->result_array();
}
$this->sys_ok($data); $this->sys_ok($data);
} catch (Exception $exc) { } catch (Exception $exc) {
@@ -381,12 +214,12 @@ class Billv2 extends MY_Controller {
$user = $this->sys_user; $user = $this->sys_user;
if ($para['userlevel'] == '1') { if ($para['userlevel'] == '1') {
$sql = "UPDATE supplier_payment SET $sql = "UPDATE supplier_payment SET
SupplierPaymentIsVerif = 'Y', SupplierPaymentIsVerif = 'Y',
SupplierPaymentStatus = 'Verified', SupplierPaymentStatus = 'Verified',
SupplierPaymentVerifUserID = ?, SupplierPaymentVerifUserID = ?,
SupplierPaymentVerifDate = NOW() SupplierPaymentVerifDate = NOW()
WHERE SupplierPaymentID = ? WHERE SupplierPaymentID = ?
AND SupplierPaymentIsActive = 'Y'"; AND SupplierPaymentIsActive = 'Y'";
$query = $this->db->query($sql, [ $query = $this->db->query($sql, [
$user['M_UserID'], $para['paymentID'] $user['M_UserID'], $para['paymentID']
@@ -398,12 +231,12 @@ class Billv2 extends MY_Controller {
} }
if ($para['userlevel'] == '2') { if ($para['userlevel'] == '2') {
$sql = "UPDATE supplier_payment SET $sql = "UPDATE supplier_payment SET
SupplierPaymentIsApproved = 'Y', SupplierPaymentIsApproved = 'Y',
SupplierPaymentStatus = 'Approved', SupplierPaymentStatus = 'Approved',
SupplierPaymentApprovedUserID = ?, SupplierPaymentApprovedUserID = ?,
SupplierPaymentApprovedDate = NOW() SupplierPaymentApprovedDate = NOW()
WHERE SupplierPaymentID = ? WHERE SupplierPaymentID = ?
AND SupplierPaymentIsActive = 'Y'"; AND SupplierPaymentIsActive = 'Y'";
$query = $this->db->query($sql, [ $query = $this->db->query($sql, [
$user['M_UserID'], $para['paymentID'] $user['M_UserID'], $para['paymentID']
@@ -428,4 +261,4 @@ class Billv2 extends MY_Controller {
exit; exit;
} }
} }
} }

View File

@@ -1,22 +1,20 @@
<?php <?php
class Bill extends MY_Controller class Bill extends MY_Controller
{ {
var $db_onedev; var $db_onedev;
public function index() public function index()
{ {
echo "Bill API"; echo "Bill API";
} }
public function __construct()
public function __construct() {
{ parent::__construct();
parent::__construct(); $this->db_onedev = $this->load->database("onedev", true);
$this->db_onedev = $this->load->database("onedev", true); }
}
public function add_notes($orderid){
public function add_notes($orderid) $sql = " SELECT SupplierPaymentSupplierInvoiceID as note_order_id,
{ SupplierPaymentID as note_id,
$sql = "SELECT SupplierPaymentSupplierInvoiceID as note_order_id,
SupplierPaymentID as note_id,
SupplierPaymentDetailSupplierInvoiceDetailID as detail_id, SupplierPaymentDetailSupplierInvoiceDetailID as detail_id,
SupplierPaymentDate as note_date, SupplierPaymentDate as note_date,
SupplierPaymentNumber as note_number, SupplierPaymentNumber as note_number,
@@ -43,205 +41,63 @@ class Bill extends MY_Controller
LEFT JOIN m_user a ON SupplierPaymentApprovedUserID = a.M_UserID LEFT JOIN m_user a ON SupplierPaymentApprovedUserID = a.M_UserID
LEFT JOIN m_user b ON SupplierPaymentVerifUserID = b.M_UserID LEFT JOIN m_user b ON SupplierPaymentVerifUserID = b.M_UserID
WHERE WHERE
SupplierPaymentSupplierInvoiceID = {$orderid} SupplierPaymentSupplierInvoiceID = {$orderid}
AND AND
SupplierPaymentIsActive = 'Y' SupplierPaymentIsActive = 'Y'
GROUP BY SupplierPaymentID"; GROUP BY SupplierPaymentID";
$query = $this->db_onedev->query($sql); $query = $this->db_onedev->query($sql);
if ($query) { if ($query) {
$rows = $query->result_array(); $rows = $query->result_array();
if ($rows) { if($rows){
foreach ($rows as $k => $v) { foreach($rows as $k => $v){
$rows[$k]['tests'] = $this->add_tests($v['note_id']); $rows[$k]['tests'] = $this->add_tests($v['note_id']);
} }
} }
return $rows; return $rows;
} else {
$this->sys_error_db("get notes", $this->db_onedev); } else {
exit; $this->sys_error_db("get notes", $this->db_onedev);
} exit;
} }
}
public function add_tagihans($orderid){
$sql = "SELECT SupplierInvoiceID as tagihan_id,
PurchaseOrderNumber as tagihan_number,
jurnalTxDescription as pasien,
jurnalTxCredit as tagihan_total,
IF(SupplierPaymentDetailID IS NULL , jurnalTxCredit, jurnalTxCredit - SUM(SupplierPaymentDetailAmount)) as tagihan_tagihan,
0 as tagihan_bayar,
DATE_FORMAT(SupplierInvoiceDueDate,'%d-%m-%Y') as tagihan_duedate,
SupplierInvoiceIsActive as tagihan_active,
'N' as show_detail,
jurnalTxID SupplierInvoiceDetailID,
PurchaseOrderID SupplierInvoiceDetailPurchaseOrderID
public function add_notes_downpayment($orderid) FROM supplier_invoice
{ JOIN receive_order_po ON ReceiveOrderPoID = SupplierInvoiceReceiveOrderPoID
$sql = "SELECT SupplierPaymentSupplierDownpaymentID AS note_order_id, JOIN receive_order_po_detail ON ReceiveOrderPoDetailReceiveOrderPoID = ReceiveOrderPoID
SupplierPaymentID AS note_id, JOIN purchase_order ON ReceiveOrderPoDetailPurchaseOrderID = PurchaseOrderID
SupplierDownpaymentID AS detail_id, JOIN jurnal_addon ON jurnalAddOnValue = SupplierInvoiceNumber
SupplierPaymentDate AS note_date, JOIN jurnal_tx ON jurnalTxJurnalID = jurnalAddOnJurnalID AND jurnalTxCredit <> 0 AND jurnalTxCoaID <> 563
SupplierPaymentNumber AS note_number, LEFT JOIN supplier_payment ON SupplierPaymentSupplierInvoiceID = SupplierInvoiceID AND SupplierInvoiceIsActive = 'Y'
GROUP_CONCAT(DISTINCT coaDescription separator ' , ') AS paymenttypes_name, LEFT JOIN supplier_payment_detail ON SupplierPaymentDetailSupplierPaymentID = SupplierPaymentID AND SupplierPaymentDetailSupplierInvoiceDetailID = jurnalTxID AND SupplierPaymentDetailIsActive = 'Y'
SUM(SupplierDownpaymentAmount) AS note_amount, WHERE
n.M_UserUsername AS note_user, SupplierInvoiceID = {$orderid}
SupplierDownpaymentIsActive AS note_active, GROUP BY jurnalTxID
'N' AS show_detail, ";
SupplierPaymentNote AS keterangan, $query = $this->db_onedev->query($sql);
SupplierPaymentCoaID, if ($query) {
coaID, $rows = $query->result_array();
coaDescription, return $rows;
SupplierPaymentIsConfirm,
CONCAT( } else {
'Confirmed by : ',c.M_UserUsername, ' ', $this->sys_error_db("get notes", $this->db_onedev);
DATE_FORMAT(SupplierPaymentConfirmDate, '%d-%m-%Y %H:%i') exit;
) AS d_confirm, }
SupplierPaymentIsApproved, }
CONCAT( public function add_tests($orderid){
'Approved by : ',a.M_UserUsername, ' ', $sql = " SELECT SupplierPaymentSupplierInvoiceID as note_order_id,
DATE_FORMAT(SupplierPaymentApprovedDate,'%d-%m-%Y %H:%i') SupplierPaymentID as note_id,
) AS d_approved,
CONCAT(
'Verified by : ',b.M_UserUsername, ' ',
DATE_FORMAT(SupplierPaymentVerifDate,'%d-%m-%Y %H:%i')
) AS d_verif
FROM supplier_payment
JOIN supplier_downpayment
ON SupplierDownpaymentID = SupplierPaymentSupplierDownpaymentID
AND SupplierDownpaymentIsActive = 'Y'
LEFT JOIN coa ON SupplierPaymentCoaID = coaID
LEFT JOIN m_user n ON SupplierPaymentUserID = n.M_UserID
LEFT JOIN m_user c ON SupplierPaymentConfirmUserID = c.M_UserID
LEFT JOIN m_user a ON SupplierPaymentApprovedUserID = a.M_UserID
LEFT JOIN m_user b ON SupplierPaymentVerifUserID = b.M_UserID
WHERE SupplierPaymentSupplierDownpaymentID = {$orderid}
AND SupplierPaymentIsActive = 'Y'
GROUP BY SupplierPaymentID";
$query = $this->db_onedev->query($sql);
if ($query) {
$rows = $query->result_array();
return $rows ?: [];
} else {
$this->sys_error_db("get DP notes", $this->db_onedev);
exit;
}
}
public function add_notes_installment($orderid)
{
$sql = "SELECT SupplierPaymentSupplierInstallmentID as note_order_id,
SupplierPaymentID as note_id,
SupplierInstallmentID as detail_id,
SupplierPaymentDate as note_date,
SupplierPaymentNumber as note_number,
GROUP_CONCAT(DISTINCT coaDescription separator ' , ') as paymenttypes_name,
SUM(SupplierInstallmentAmount) as note_amount,
n.M_UserUsername as note_user,
SupplierInstallmentIsActive as note_active,
'N' as show_detail,
SupplierPaymentNote as keterangan,
SupplierPaymentCoaID,
coaID,
coaDescription,
SupplierPaymentIsConfirm,
CONCAT(
'Confirmed by : ',c.M_UserUsername, ' ',
DATE_FORMAT(SupplierPaymentConfirmDate,'%d-%m-%Y %H:%i')
) AS d_confirm,
SupplierPaymentIsApproved,
CONCAT(
'Approved by : ',a.M_UserUsername, ' ',
DATE_FORMAT(SupplierPaymentApprovedDate,'%d-%m-%Y %H:%i')
) AS d_approved,
CONCAT(
'Verified by : ',b.M_UserUsername, ' ',
DATE_FORMAT(SupplierPaymentVerifDate,'%d-%m-%Y %H:%i')
) AS d_verif
FROM supplier_payment
JOIN supplier_installment
ON SupplierInstallmentID = SupplierPaymentSupplierInstallmentID
AND SupplierInstallmentIsActive = 'Y'
LEFT JOIN coa ON SupplierPaymentCoaID = coaID
LEFT JOIN m_user n ON SupplierPaymentUserID = n.M_UserID
LEFT JOIN m_user c ON SupplierPaymentConfirmUserID = c.M_UserID
LEFT JOIN m_user a ON SupplierPaymentApprovedUserID = a.M_UserID
LEFT JOIN m_user b ON SupplierPaymentVerifUserID = b.M_UserID
WHERE SupplierPaymentSupplierInstallmentID = {$orderid}
AND SupplierPaymentIsActive = 'Y'
GROUP BY SupplierPaymentID";
$query = $this->db_onedev->query($sql);
if ($query) {
$rows = $query->result_array();
return $rows ?: [];
} else {
$this->sys_error_db("get Installment notes", $this->db_onedev);
exit;
}
}
public function add_tagihans($orderid)
{
$sql_dp = "SELECT
Fa_ClassDownPaymentCoaID
FROM supplier_invoice_detail
JOIN m_item
ON M_ItemID = SupplierInvoiceDetailItemID
AND SupplierInvoiceDetailSupplierInvoiceID = ?
AND SupplierInvoiceDetailIsActive = 'Y'
AND SupplierInvoiceDetailIsVerified = 'Y'
JOIN fa_class
ON Fa_ClassID = M_ItemFa_ClassID
AND Fa_ClassIsActive = 'Y'";
$que_dp = $this->db_onedev->query($sql_dp, [$orderid]);
if (!$que_dp) {
$this->sys_error_db("failed to get coa id dp tagihans", $this->db_onedev);
exit;
}
$dataDP = $que_dp->result_array();
$excludeIds = array_column($dataDP, 'Fa_ClassDownPaymentCoaID');
$excludeIds[] = 563; // always excluded
$excludeIds = array_unique($excludeIds);
$excludeIds = array_values($excludeIds); // re-index
$notInPlaceholders = implode(',', array_fill(0, count($excludeIds), '?'));
$sql = "SELECT
SupplierInvoiceID as tagihan_id,
PurchaseOrderNumber as tagihan_number,
jurnalTxDescription as pasien,
jurnalTxCredit as tagihan_total,
IF(SupplierPaymentDetailID IS NULL , jurnalTxCredit, jurnalTxCredit - SUM(SupplierPaymentDetailAmount)) as tagihan_tagihan,
0 as tagihan_bayar,
DATE_FORMAT(SupplierInvoiceDueDate,'%d-%m-%Y') as tagihan_duedate,
SupplierInvoiceIsActive as tagihan_active,
'N' as show_detail,
jurnalTxID SupplierInvoiceDetailID,
PurchaseOrderID SupplierInvoiceDetailPurchaseOrderID
FROM supplier_invoice
JOIN receive_order_po
ON ReceiveOrderPoID = SupplierInvoiceReceiveOrderPoID
JOIN receive_order_po_detail
ON ReceiveOrderPoDetailReceiveOrderPoID = ReceiveOrderPoID
JOIN purchase_order
ON ReceiveOrderPoDetailPurchaseOrderID = PurchaseOrderID
JOIN jurnal_addon
ON jurnalAddOnValue = SupplierInvoiceNumber
AND jurnalAddOnIsActive = 'Y'
JOIN jurnal_tx
ON jurnalTxJurnalID = jurnalAddOnJurnalID
AND jurnalTxIsActive = 'Y'
AND jurnalTxCredit <> 0
AND jurnalTxCoaID NOT IN ($notInPlaceholders)
LEFT JOIN supplier_payment
ON SupplierPaymentSupplierInvoiceID = SupplierInvoiceID
AND SupplierInvoiceIsActive = 'Y'
LEFT JOIN supplier_payment_detail
ON SupplierPaymentDetailSupplierPaymentID = SupplierPaymentID
AND SupplierPaymentDetailSupplierInvoiceDetailID = jurnalTxID
AND SupplierPaymentDetailIsActive = 'Y'
WHERE SupplierInvoiceID = ?
GROUP BY jurnalTxID";
$query = $this->db_onedev->query($sql, array_merge($excludeIds, [$orderid]));
if ($query) {
$rows = $query->result_array();
return $rows;
} else {
$this->sys_error_db("get tagihans", $this->db_onedev);
exit;
}
}
public function add_tests($orderid)
{
$sql = " SELECT SupplierPaymentSupplierInvoiceID as note_order_id,
SupplierPaymentID as note_id,
SupplierPaymentDate as note_date, SupplierPaymentDate as note_date,
SupplierPaymentNumber as note_number, SupplierPaymentNumber as note_number,
GROUP_CONCAT(coaDescription separator ' , ') as paymenttypes_name, GROUP_CONCAT(coaDescription separator ' , ') as paymenttypes_name,
@@ -252,537 +108,150 @@ class Bill extends MY_Controller
SupplierInvoiceDetailTotal, SupplierInvoiceDetailTotal,
SupplierPaymentDetailAmount SupplierPaymentDetailAmount
FROM supplier_payment FROM supplier_payment
JOIN supplier_payment_detail ON SupplierPaymentDetailSupplierPaymentID = SupplierPaymentID JOIN supplier_payment_detail ON SupplierPaymentDetailSupplierPaymentID = SupplierPaymentID
LEFT JOIN supplier_invoice_detail ON SupplierPaymentDetailSupplierInvoiceDetailID = SupplierInvoiceDetailID LEFT JOIN supplier_invoice_detail ON SupplierPaymentDetailSupplierInvoiceDetailID = SupplierInvoiceDetailID
LEFT JOIN purchase_order ON SupplierInvoiceDetailPurchaseOrderID = PurchaseOrderID LEFT JOIN purchase_order ON SupplierInvoiceDetailPurchaseOrderID = PurchaseOrderID
LEFT JOIN coa ON SupplierPaymentCoaID = coaID LEFT JOIN coa ON SupplierPaymentCoaID = coaID
LEFT JOIN m_user ON SupplierPaymentDetailUserID = M_UserID LEFT JOIN m_user ON SupplierPaymentDetailUserID = M_UserID
WHERE WHERE
SupplierPaymentID = {$orderid} SupplierPaymentID = {$orderid}
GROUP BY SupplierPaymentDetailID"; GROUP BY SupplierPaymentDetailID";
$query = $this->db_onedev->query($sql); $query = $this->db_onedev->query($sql);
if ($query) { if ($query) {
$rows = $query->result_array(); $rows = $query->result_array();
if ($rows) { if($rows){
} }
return $rows; return $rows;
} else {
$this->sys_error_db("get notes", $this->db_onedev); } else {
exit; $this->sys_error_db("get notes", $this->db_onedev);
} exit;
} }
}
public function search_old() public function search()
{ {
//# cek token valid //# cek token valid
if (! $this->isLogin) { if (! $this->isLogin) {
$this->sys_error("Invalid Token"); $this->sys_error("Invalid Token");
exit; exit;
} }
$prm = $this->sys_input;
$prm = $this->sys_input; $supplier = $prm["supplier"];
$supplier = $prm["supplier"]; $search = $prm["search"];
$search = $prm["search"]; $status = $prm["status"];
$status = $prm["status"]; $startdate = $prm["startdate"];
$startdate = $prm["startdate"]; $enddate = $prm["enddate"];
$enddate = $prm["enddate"]; $regionalid = $this->sys_user['S_RegionalID'];
$regionalid = $this->sys_user['S_RegionalID'];
$number_limit = 10;
$number_limit = 10; $number_offset = ($prm['current_page'] - 1) * $number_limit ;
$number_offset = ($prm['current_page'] - 1) * $number_limit;
$where = "SupplierInvoiceIsActive = 'Y'
$where = "SupplierInvoiceIsActive = 'Y' AND SupplierInvoiceStatus = 'Approved'
AND SupplierInvoiceStatus = 'Approved' AND SupplierInvoiceGrandTotal > 0
AND SupplierInvoiceGrandTotal > 0 AND IF(SupplierPaymentID IS NULL,'N','Y') = '{$status}'
AND IF(SupplierPaymentID IS NULL,'N','Y') = '{$status}' AND (SupplierInvoiceNumber LIKE '%{$search}%' AND SupplierName LIKE '%{$supplier}%')
AND (SupplierInvoiceNumber LIKE '%{$search}%' AND SupplierName LIKE '%{$supplier}%') AND ReceiveOrderPoS_RegionalID = {$regionalid}
AND ReceiveOrderPoS_RegionalID = {$regionalid} AND SupplierInvoiceDraftPaymentDate BETWEEN '{$startdate}' AND '{$enddate}'";
AND SupplierInvoiceDraftPaymentDate BETWEEN '{$startdate}' AND '{$enddate}'";
$sql = " SELECT count(*) as total
$sql = " SELECT count(*) as total FROM supplier_invoice
FROM supplier_invoice JOIN jurnal_addon ON jurnalAddOnValue = SupplierInvoiceNumber
JOIN jurnal_addon ON jurnalAddOnValue = SupplierInvoiceNumber LEFT JOIN supplier_payment ON SupplierInvoiceID = SupplierPaymentSupplierInvoiceID AND SupplierPaymentIsActive = 'Y'
LEFT JOIN supplier_payment ON SupplierInvoiceID = SupplierPaymentSupplierInvoiceID AND SupplierPaymentIsActive = 'Y' LEFT JOIN supplier ON SupplierInvoiceSupplierID = SupplierID
LEFT JOIN supplier ON SupplierInvoiceSupplierID = SupplierID JOIN receive_order_po ON SupplierInvoiceReceiveOrderPoID = ReceiveOrderPoID
JOIN receive_order_po ON SupplierInvoiceReceiveOrderPoID = ReceiveOrderPoID WHERE
WHERE $where
$where ";
"; // echo $sql;
// echo $sql; $query = $this->db_onedev->query($sql, $sql_param);
$query = $this->db_onedev->query($sql, $sql_param);
$tot_count = 0;
$tot_count = 0; $tot_page = 0;
$tot_page = 0; if ($query) {
if ($query) { $tot_count = $query->result_array()[0]["total"];
$tot_count = $query->result_array()[0]["total"]; $tot_page = ceil($tot_count/$number_limit);
$tot_page = ceil($tot_count / $number_limit); } else {
} else { $this->sys_error_db("supplier_invoice count", $this->db_onedev);
$this->sys_error_db("supplier_invoice count", $this->db_onedev); exit;
exit; }
}
$sql = "SELECT supplier_invoice.*,
$sql = "SELECT supplier_invoice.*, SupplierName,
SupplierName, '' M_MouName,
'' M_MouName, 0 as totalbill,
0 as totalbill, 0 as paid,
0 as paid, 0 as unpaid,
0 as unpaid, SupplierInvoiceIsLunas as flaglunas,
SupplierInvoiceIsLunas as flaglunas, 0 as SupplierPaymentID,
0 as SupplierPaymentID, '' as SupplierPaymentNumber,
'' as SupplierPaymentNumber, 0 as SupplierPaymentAmount,
0 as SupplierPaymentAmount, '' as SupplierPaymentDate,
'' as SupplierPaymentDate, '' as SupplierInvoiceIssueRefNumber,
'' as SupplierInvoiceIssueRefNumber, '' as notes,
'' as notes, '' as tagihans,
'' as tagihans, 'N' as isbillterpusat,
'N' as isbillterpusat, DATE_FORMAT(SupplierInvoiceDraftPaymentDate,'%d-%m-%Y') as tanggalbayar,
DATE_FORMAT(SupplierInvoiceDraftPaymentDate,'%d-%m-%Y') as tanggalbayar, DATE_FORMAT(SupplierInvoiceDraftPaymentDate,'%d%m%Y') as tanggalbayartext,
DATE_FORMAT(SupplierInvoiceDraftPaymentDate,'%d%m%Y') as tanggalbayartext, IF(SupplierPaymentID IS NULL,'N','Y') as status_invoice,
IF(SupplierPaymentID IS NULL,'N','Y') as status_invoice, IFNULL(SupplierPaymentIsApproved,'N') as SupplierPaymentIsApproved,
IFNULL(SupplierPaymentIsApproved,'N') as SupplierPaymentIsApproved, IFNULL(SupplierPaymentIsVerif,'N') as SupplierPaymentIsVerif,
IFNULL(SupplierPaymentIsVerif,'N') as SupplierPaymentIsVerif, IFNULL(SupplierPaymentCashierNumber,'') SupplierPaymentCashierNumber
IFNULL(SupplierPaymentCashierNumber,'') SupplierPaymentCashierNumber
FROM supplier_invoice
FROM supplier_invoice LEFT JOIN supplier ON SupplierInvoiceSupplierID = SupplierID
LEFT JOIN supplier ON SupplierInvoiceSupplierID = SupplierID JOIN jurnal_addon ON jurnalAddOnValue = SupplierInvoiceNumber
JOIN jurnal_addon ON jurnalAddOnValue = SupplierInvoiceNumber JOIN receive_order_po ON SupplierInvoiceReceiveOrderPoID = ReceiveOrderPoID
JOIN receive_order_po ON SupplierInvoiceReceiveOrderPoID = ReceiveOrderPoID LEFT JOIN supplier_payment ON SupplierPaymentSupplierInvoiceID = SupplierInvoiceID AND SupplierPaymentIsActive = 'Y'
LEFT JOIN supplier_payment ON SupplierPaymentSupplierInvoiceID = SupplierInvoiceID AND SupplierPaymentIsActive = 'Y' WHERE
WHERE $where
$where GROUP BY SupplierInvoiceID
GROUP BY SupplierInvoiceID ORDER BY SupplierInvoiceID ASC
ORDER BY SupplierInvoiceID ASC limit $number_limit offset $number_offset";
limit $number_limit offset $number_offset"; //echo $sql;
//echo $sql; $query = $this->db_onedev->query($sql, $sql_param);
$query = $this->db_onedev->query($sql, $sql_param); $rows = $query->result_array();
$rows = $query->result_array(); if($rows){
if ($rows) { foreach($rows as $k => $v){
foreach ($rows as $k => $v) { $s_payment = $this->db_onedev->query("SELECT GROUP_CONCAT(SupplierPaymentNumber SEPARATOR ', ') as SupplierPaymentNumber,
$s_payment = $this->db_onedev->query("SELECT GROUP_CONCAT(SupplierPaymentNumber SEPARATOR ', ') as SupplierPaymentNumber, SUM(IFNULL(SupplierPaymentAmount,0)) as SupplierPaymentAmount,
SUM(IFNULL(SupplierPaymentAmount,0)) as SupplierPaymentAmount, IFNULL(SupplierPaymentID,0) SupplierPaymentID,
IFNULL(SupplierPaymentID,0) SupplierPaymentID, GROUP_CONCAT(DATE_FORMAT(SupplierPaymentDate,'%d-%m-%Y') SEPARATOR ', ') as SupplierPaymentDate
GROUP_CONCAT(DATE_FORMAT(SupplierPaymentDate,'%d-%m-%Y') SEPARATOR ', ') as SupplierPaymentDate FROM supplier_payment
FROM supplier_payment WHERE SupplierPaymentIsActive = 'Y' AND SupplierPaymentSupplierInvoiceID = {$v['SupplierInvoiceID']}")->row();
WHERE SupplierPaymentIsActive = 'Y' AND SupplierPaymentSupplierInvoiceID = {$v['SupplierInvoiceID']}")->row();
$s_jurnal = $this->db_onedev->query("SELECT SUM(jurnalTxCredit) totalbill
$s_jurnal = $this->db_onedev->query("SELECT SUM(jurnalTxCredit) totalbill FROM supplier_invoice
FROM supplier_invoice JOIN jurnal_addon ON jurnalAddOnValue = SupplierInvoiceNumber
JOIN jurnal_addon ON jurnalAddOnValue = SupplierInvoiceNumber JOIN jurnal_tx ON jurnalTxJurnalID = jurnalAddOnJurnalID AND jurnalTxCredit <> 0 AND jurnalTxCoaID <> 563
JOIN jurnal_tx ON jurnalTxJurnalID = jurnalAddOnJurnalID AND jurnalTxCredit <> 0 AND jurnalTxCoaID <> 563 WHERE SupplierInvoiceID = {$v['SupplierInvoiceID']}
WHERE SupplierInvoiceID = {$v['SupplierInvoiceID']} GROUP BY SupplierInvoiceID")->row();
GROUP BY SupplierInvoiceID")->row(); $amount = $s_payment->SupplierPaymentAmount ? $s_payment->SupplierPaymentAmount : "0.00";
$amount = $s_payment->SupplierPaymentAmount ? $s_payment->SupplierPaymentAmount : "0.00"; $unpaid = (float)$s_jurnal->totalbill - (float)$amount;
$unpaid = (float)$s_jurnal->totalbill - (float)$amount; $rows[$k]['SupplierPaymentID'] = $s_payment->SupplierPaymentID ? $s_payment->SupplierPaymentID : '0';
$rows[$k]['SupplierPaymentID'] = $s_payment->SupplierPaymentID ? $s_payment->SupplierPaymentID : '0'; $rows[$k]['SupplierPaymentNumber'] = $s_payment->SupplierPaymentNumber ? $s_payment->SupplierPaymentNumber : '';
$rows[$k]['SupplierPaymentNumber'] = $s_payment->SupplierPaymentNumber ? $s_payment->SupplierPaymentNumber : ''; $rows[$k]['SupplierPaymentAmount'] = $amount;
$rows[$k]['SupplierPaymentAmount'] = $amount; $rows[$k]['SupplierPaymentDate'] = $s_payment->SupplierPaymentDate;
$rows[$k]['SupplierPaymentDate'] = $s_payment->SupplierPaymentDate; $rows[$k]['paid'] = $amount;
$rows[$k]['paid'] = $amount; $rows[$k]['totalbill'] = $s_jurnal->totalbill ? $s_jurnal->totalbill : "0.00";
$rows[$k]['totalbill'] = $s_jurnal->totalbill ? $s_jurnal->totalbill : "0.00"; $rows[$k]['unpaid'] = number_format($unpaid, 2, '.', '');
$rows[$k]['unpaid'] = number_format($unpaid, 2, '.', '');
$rows[$k]['notes'] = $this->add_notes($v['SupplierInvoiceID']);
$rows[$k]['notes'] = $this->add_notes($v['SupplierInvoiceID']); $rows[$k]['tagihans'] = $this->add_tagihans($v['SupplierInvoiceID']);
$rows[$k]['tagihans'] = $this->add_tagihans($v['SupplierInvoiceID']);
} }
} }
$result = array("total" => $tot_page, "records" => $rows, "sql" => $this->db_onedev->last_query()); $result = array("total" => $tot_page, "records" => $rows, "sql"=> $this->db_onedev->last_query());
$this->sys_ok($result); $this->sys_ok($result);
exit; exit;
} }
/**
* search — unified invoice + downpayment list:
* - Only columns the frontend actually reads (no wildcard, no dead aliases)
* - UNION ALL merges supplier_invoice and supplier_downpayment
* - DP rows enriched via SupplierPaymentSupplierDownpaymentID FK
* - All queries use PDO parameterised placeholders
*/
public function search()
{
if (! $this->isLogin) {
$this->sys_error("Invalid Token");
exit;
}
$prm = $this->sys_input;
$supplier = $prm["supplier"];
$search = $prm["search"];
$status = $prm["status"];
$startdate = $prm["startdate"];
$enddate = $prm["enddate"];
$regionalid = $this->sys_user['S_RegionalID'];
$number_limit = 10;
$number_offset = ((int)$prm['current_page'] - 1) * $number_limit;
// ── INVOICE WHERE ──────────────────────────────────────────
$inv_where = " SupplierInvoiceIsActive = 'Y'
AND SupplierInvoiceStatus = 'Approved'
AND SupplierInvoiceGrandTotal > 0
AND SupplierInvoiceIsInstallment = 'N'
AND IF(SupplierPaymentID IS NULL,'N','Y') = ?
AND SupplierInvoiceNumber LIKE ?
AND SupplierName LIKE ?
AND ReceiveOrderPoS_RegionalID = ?
AND SupplierInvoiceDraftPaymentDate BETWEEN ? AND ? ";
$inv_params = [
$status,
'%' . $search . '%',
'%' . $supplier . '%',
$regionalid,
$startdate,
$enddate,
];
// ── DOWNPAYMENT WHERE ──────────────────────────────────────
$dp_where = " SupplierDownpaymentIsActive = 'Y'
AND IF(SupplierDownpaymentStatus = 'Paid','Y','N') = ?
AND PurchaseOrderNumber LIKE ?
AND SupplierName LIKE ?
AND PurchaseOrderS_RegionalID = ?
AND SupplierDownpaymentDueDate BETWEEN ? AND ? ";
$dp_params = [
$status,
'%' . $search . '%',
'%' . $supplier . '%',
$regionalid,
$startdate,
$enddate,
];
// ── INSTALLMENT WHERE ───────────────────────────────────
$inst_where = " inst.SupplierInstallmentIsActive = 'Y'
AND IF(sp.SupplierPaymentID IS NULL,'N','Y') = ?
AND CONCAT('INST-', si.SupplierInvoiceNumber) LIKE ?
AND sup.SupplierName LIKE ?
AND rop.ReceiveOrderPoS_RegionalID = ?
AND inst.SupplierInstallmentDueDate BETWEEN ? AND ? ";
$inst_params = [
$status,
'%' . $search . '%',
'%' . $supplier . '%',
$regionalid,
$startdate,
$enddate,
];
// ── COUNT query — UNION of all three sources ────────────
$sql_count = "SELECT SUM(cnt) as total FROM (
SELECT count(*) as cnt
FROM supplier_invoice
JOIN jurnal_addon ON jurnalAddOnValue = SupplierInvoiceNumber
LEFT JOIN supplier_payment
ON SupplierInvoiceID = SupplierPaymentSupplierInvoiceID
AND SupplierPaymentIsActive = 'Y'
LEFT JOIN supplier ON SupplierInvoiceSupplierID = SupplierID
JOIN receive_order_po ON SupplierInvoiceReceiveOrderPoID = ReceiveOrderPoID
WHERE $inv_where
UNION ALL
SELECT count(*) as cnt
FROM supplier_downpayment
JOIN purchase_order ON PurchaseOrderID = SupplierDownpaymentPurchasOrderID
JOIN supplier ON SupplierID = SupplierDownpaymentSupplierID
WHERE $dp_where
UNION ALL
SELECT count(*) as cnt
FROM supplier_installment inst
LEFT JOIN supplier_payment sp
ON sp.SupplierPaymentSupplierInstallmentID = inst.SupplierInstallmentID
AND sp.SupplierPaymentIsActive = 'Y'
JOIN supplier_invoice si
ON si.SupplierInvoiceID = inst.SupplierInstallmentSupplierInvoiceID
JOIN receive_order_po rop
ON rop.ReceiveOrderPoID = si.SupplierInvoiceReceiveOrderPoID
JOIN supplier sup
ON sup.SupplierID = inst.SupplierInstallmentSupplierID
WHERE $inst_where
) AS combined";
$count_params = array_merge($inv_params, $dp_params, $inst_params);
$query = $this->db_onedev->query($sql_count, $count_params);
$tot_count = 0;
$tot_page = 0;
if ($query) {
$tot_count = $query->result_array()[0]["total"];
$tot_page = ceil($tot_count / $number_limit);
} else {
$this->sys_error_db("payment instructions count", $this->db_onedev);
exit;
}
// ── DATA query — UNION with identical columns ──────────────
$sql_data = "
SELECT * FROM (
SELECT
SupplierInvoiceID,
0 as DownpaymentID,
0 as InstallmentID,
SupplierInvoiceNumber,
SupplierInvoiceDraftPaymentDate,
SupplierInvoiceIsLunas as flaglunas,
SupplierName,
DATE_FORMAT(SupplierInvoiceDraftPaymentDate,'%d-%m-%Y') as tanggalbayar,
IFNULL(SupplierPaymentIsApproved,'N') as SupplierPaymentIsApproved,
IFNULL(SupplierPaymentCashierNumber,'') as SupplierPaymentCashierNumber,
0 as totalbill,
0 as paid,
0 as unpaid,
0 as SupplierPaymentID,
'' as SupplierPaymentNumber,
0 as SupplierPaymentAmount,
'' as SupplierPaymentDate,
'' as notes,
'' as tagihans,
0 as parent_invoice_id,
'INVOICE' as type
FROM supplier_invoice
LEFT JOIN supplier ON SupplierInvoiceSupplierID = SupplierID
JOIN jurnal_addon ON jurnalAddOnValue = SupplierInvoiceNumber
JOIN receive_order_po ON SupplierInvoiceReceiveOrderPoID = ReceiveOrderPoID
LEFT JOIN supplier_payment
ON SupplierPaymentSupplierInvoiceID = SupplierInvoiceID
AND SupplierPaymentIsActive = 'Y'
WHERE $inv_where
GROUP BY SupplierInvoiceID
UNION ALL
SELECT
0 as SupplierInvoiceID,
SupplierDownpaymentID as DownpaymentID,
0 as InstallmentID,
CONCAT('DP-', PurchaseOrderNumber) as SupplierInvoiceNumber,
SupplierDownpaymentDueDate as SupplierInvoiceDraftPaymentDate,
SupplierDownpaymentIsLunas as flaglunas,
SupplierName,
DATE_FORMAT(SupplierDownpaymentDueDate,'%d-%m-%Y') as tanggalbayar,
IFNULL(SupplierPaymentIsApproved,'N') as SupplierPaymentIsApproved,
IFNULL(SupplierPaymentCashierNumber,'') as SupplierPaymentCashierNumber,
SupplierDownpaymentAmount as totalbill,
CASE WHEN SupplierDownpaymentStatus = 'Paid'
THEN SupplierDownpaymentAmount
ELSE 0 END as paid,
CASE WHEN SupplierDownpaymentStatus = 'Paid'
THEN 0
ELSE SupplierDownpaymentAmount END as unpaid,
0 as SupplierPaymentID,
'' as SupplierPaymentNumber,
0 as SupplierPaymentAmount,
'' as SupplierPaymentDate,
'' as notes,
'' as tagihans,
0 as parent_invoice_id,
'DP' as type
FROM supplier_downpayment
JOIN purchase_order ON PurchaseOrderID = SupplierDownpaymentPurchasOrderID
JOIN supplier ON SupplierID = SupplierDownpaymentSupplierID
LEFT JOIN supplier_payment
ON SupplierPaymentSupplierDownpaymentID = SupplierDownpaymentID
AND SupplierPaymentIsActive = 'Y'
WHERE $dp_where
UNION ALL
SELECT
0 as SupplierInvoiceID,
0 as DownpaymentID,
inst.SupplierInstallmentID as InstallmentID,
CONCAT('INST-', si.SupplierInvoiceNumber) as SupplierInvoiceNumber,
inst.SupplierInstallmentDueDate as SupplierInvoiceDraftPaymentDate,
inst.SupplierInstallmentIsLunas as flaglunas,
sup.SupplierName,
DATE_FORMAT(inst.SupplierInstallmentDueDate,'%d-%m-%Y') as tanggalbayar,
IFNULL(sp.SupplierPaymentIsApproved,'N') as SupplierPaymentIsApproved,
IFNULL(sp.SupplierPaymentCashierNumber,'') as SupplierPaymentCashierNumber,
inst.SupplierInstallmentAmount as totalbill,
CASE WHEN inst.SupplierInstallmentStatus = 'Paid'
THEN inst.SupplierInstallmentAmount
ELSE 0 END as paid,
CASE WHEN inst.SupplierInstallmentStatus = 'Paid'
THEN 0
ELSE inst.SupplierInstallmentAmount END as unpaid,
0 as SupplierPaymentID,
'' as SupplierPaymentNumber,
0 as SupplierPaymentAmount,
'' as SupplierPaymentDate,
'' as notes,
'' as tagihans,
si.SupplierInvoiceID as parent_invoice_id,
'INSTALLMENT' as type
FROM supplier_installment inst
LEFT JOIN supplier_payment sp
ON sp.SupplierPaymentSupplierInstallmentID = inst.SupplierInstallmentID
AND sp.SupplierPaymentIsActive = 'Y'
JOIN supplier_invoice si
ON si.SupplierInvoiceID = inst.SupplierInstallmentSupplierInvoiceID
JOIN receive_order_po rop
ON rop.ReceiveOrderPoID = si.SupplierInvoiceReceiveOrderPoID
JOIN supplier sup
ON sup.SupplierID = inst.SupplierInstallmentSupplierID
WHERE $inst_where
) AS combined
ORDER BY SupplierInvoiceID ASC
LIMIT ? OFFSET ?";
$data_params = array_merge($inv_params, $dp_params, $inst_params, [$number_limit, $number_offset]);
$query = $this->db_onedev->query($sql_data, $data_params);
if (!$query) {
$this->sys_error_db("payment instructions data", $this->db_onedev);
exit;
}
$rows = $query->result_array();
// ── ENRICH — per-row sub-queries ───────────────────────────
if ($rows) {
foreach ($rows as $k => $v) {
// ── Downpayment branch ──────────────────────────
if ($v['type'] === 'DP') {
$dp_id = $v['DownpaymentID'];
$s_payment = $this->db_onedev->query("
SELECT
GROUP_CONCAT(SupplierPaymentNumber SEPARATOR ', ') as SupplierPaymentNumber,
SUM(IFNULL(SupplierPaymentAmount,0)) as SupplierPaymentAmount,
IFNULL(SupplierPaymentID,0) as SupplierPaymentID,
GROUP_CONCAT(
DATE_FORMAT(SupplierPaymentDate,'%d-%m-%Y')
SEPARATOR ', '
) as SupplierPaymentDate
FROM supplier_payment
WHERE SupplierPaymentIsActive = 'Y'
AND SupplierPaymentSupplierDownpaymentID = ?",
[$dp_id]
)->row();
$amount = $s_payment->SupplierPaymentAmount
? $s_payment->SupplierPaymentAmount
: "0.00";
$rows[$k]['SupplierPaymentID'] = $s_payment->SupplierPaymentID
? $s_payment->SupplierPaymentID
: '0';
$rows[$k]['SupplierPaymentNumber'] = $s_payment->SupplierPaymentNumber
? $s_payment->SupplierPaymentNumber
: '';
$rows[$k]['SupplierPaymentAmount'] = $amount;
$rows[$k]['SupplierPaymentDate'] = $s_payment->SupplierPaymentDate;
$rows[$k]['paid'] = $amount;
$rows[$k]['notes'] = $this->add_notes_downpayment($dp_id);
$rows[$k]['tagihans'] = [];
// totalbill, unpaid already correct from UNION CASE
continue;
}
// ── Installment branch ─────────────────────────
if ($v['type'] === 'INSTALLMENT') {
$inst_id = $v['InstallmentID'];
$parent_invoice_id = $v['parent_invoice_id'];
$s_payment = $this->db_onedev->query("
SELECT
GROUP_CONCAT(SupplierPaymentNumber SEPARATOR ', ') as SupplierPaymentNumber,
SUM(IFNULL(SupplierPaymentAmount,0)) as SupplierPaymentAmount,
IFNULL(SupplierPaymentID,0) as SupplierPaymentID,
GROUP_CONCAT(
DATE_FORMAT(SupplierPaymentDate,'%d-%m-%Y')
SEPARATOR ', '
) as SupplierPaymentDate
FROM supplier_payment
WHERE SupplierPaymentIsActive = 'Y'
AND SupplierPaymentSupplierInstallmentID = ?",
[$inst_id]
)->row();
$amount = $s_payment->SupplierPaymentAmount
? $s_payment->SupplierPaymentAmount
: "0.00";
$rows[$k]['SupplierPaymentID'] = $s_payment->SupplierPaymentID
? $s_payment->SupplierPaymentID
: '0';
$rows[$k]['SupplierPaymentNumber'] = $s_payment->SupplierPaymentNumber
? $s_payment->SupplierPaymentNumber
: '';
$rows[$k]['SupplierPaymentAmount'] = $amount;
$rows[$k]['SupplierPaymentDate'] = $s_payment->SupplierPaymentDate;
$rows[$k]['paid'] = $amount;
$rows[$k]['notes'] = $this->add_notes_installment($inst_id);
$rows[$k]['tagihans'] = $this->add_tagihans($parent_invoice_id);
// totalbill, unpaid already correct from UNION CASE
continue;
}
// ── Invoice branch ───────────────────────────────
$inv_id = $v['SupplierInvoiceID'];
$s_payment = $this->db_onedev->query("
SELECT
GROUP_CONCAT(SupplierPaymentNumber SEPARATOR ', ') as SupplierPaymentNumber,
SUM(IFNULL(SupplierPaymentAmount,0)) as SupplierPaymentAmount,
IFNULL(SupplierPaymentID,0) as SupplierPaymentID,
GROUP_CONCAT(
DATE_FORMAT(SupplierPaymentDate,'%d-%m-%Y')
SEPARATOR ', '
) as SupplierPaymentDate
FROM supplier_payment
WHERE SupplierPaymentIsActive = 'Y'
AND SupplierPaymentSupplierInvoiceID = ?",
[$inv_id]
)->row();
$s_jurnal = $this->db_onedev->query("
SELECT SUM(jurnalTxCredit) totalbill
FROM supplier_invoice
JOIN jurnal_addon ON jurnalAddOnValue = SupplierInvoiceNumber
JOIN jurnal_tx
ON jurnalTxJurnalID = jurnalAddOnJurnalID
AND jurnalTxCredit <> 0
AND jurnalTxCoaID <> 563
WHERE SupplierInvoiceID = ?
GROUP BY SupplierInvoiceID",
[$inv_id]
)->row();
$amount = $s_payment->SupplierPaymentAmount
? $s_payment->SupplierPaymentAmount
: "0.00";
$unpaid = (float)$s_jurnal->totalbill - (float)$amount;
$rows[$k]['SupplierPaymentID'] = $s_payment->SupplierPaymentID
? $s_payment->SupplierPaymentID
: '0';
$rows[$k]['SupplierPaymentNumber'] = $s_payment->SupplierPaymentNumber
? $s_payment->SupplierPaymentNumber
: '';
$rows[$k]['SupplierPaymentAmount'] = $amount;
$rows[$k]['SupplierPaymentDate'] = $s_payment->SupplierPaymentDate;
$rows[$k]['paid'] = $amount;
$rows[$k]['totalbill'] = $s_jurnal->totalbill
? $s_jurnal->totalbill
: "0.00";
$rows[$k]['unpaid'] = number_format($unpaid, 2, '.', '');
$rows[$k]['notes'] = $this->add_notes($inv_id);
$rows[$k]['tagihans'] = $this->add_tagihans($inv_id);
}
}
$result = array("total" => $tot_page, "records" => $rows);
$this->sys_ok($result);
exit;
}
} }

File diff suppressed because it is too large Load Diff

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

@@ -1,512 +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 PaymentVoucherFpdf extends FPDF
{
public $printUsername = '-';
public $printDate = '';
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
{
parent::__construct($orientation, $unit, $size);
// Daftarkan Arial Narrow — file font ada di fpdf/font/Arial_Narrow.php
$this->AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular
$this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold)
}
public function Footer()
{
$pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15
// ── Posisi: 20mm dari bawah halaman ──────────────────────────────────
$this->SetY(-20);
// ── Baris 1: Print Oleh (kiri) | Nomor Halaman (tengah) ───────────────
$colSide = ($pageW - 40) / 2;
$colCenter = 40;
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Print Oleh : ' . $this->printUsername, 0, 0, 'L');
$this->Cell($colCenter, 4, $this->PageNo() . ' / {nb}', 0, 0, 'C');
$this->Cell($colSide, 4, '', 0, 1, 'R');
// ── Baris 2: Tgl Print (kiri) ──────────────────────────────────────────
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L');
$this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L');
}
// 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
// =============================================================================
class Rpt_payment_voucher extends MY_Controller
{
// ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var PaymentVoucherFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Payment Voucher Report API";
}
// =========================================================================
// ENDPOINT: pdf
// GET/POST: id (PaymentVoucherID), 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 PaymentVoucherFpdf('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 = 'PV_' . str_replace('/', '-', $header['PaymentVoucherNumber']) . '.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
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
LEFT JOIN m_user uRc ON uRc.M_UserID = pv.PaymentVoucherPaidReceiveUserID
WHERE pv.PaymentVoucherIsActive = 'Y'
AND pv.PaymentVoucherID = ?
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Payment Voucher tidak ditemukan");
exit;
}
return $qry->row_array();
}
private function _get_detail($id)
{
$sql = "
SELECT
pvd.*,
prd.PurchaseRequestDirectNumber,
prdd.PurchaseRequestDirectDescription AS ItemDescription,
prdd.PurchaseRequestDirectDetailAccount AS ExpenseAccount,
prdd.PurchaseRequestDirectDetailTotalRealitationPrice,
prdd.PurchaseRequestDirectDetailTotalEstimationPrice,
pdc.PurchaseDirectCategoryName,
c.coaDescription AS ExpenseAccountName
FROM payment_voucher_detail pvd
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, prdd.PurchaseRequestDirectDetailID 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, 'PAYMENT VOUCHER (BUKTI PENGELUARAN KAS / BANK)', 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);
$coaSource = '-';
if (!empty($header['coaAccountNo'])) {
$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_date($header['PaymentVoucherDate']), false),
array('Sumber Dana', $coaSource, false),
);
if ($coaTemp !== '') {
$leftItems[] = array('Akun Transit', $coaTemp, false);
}
foreach ($leftItems as $item) {
$pdf->SetX(15);
if ($item[2]) {
$pdf->SetFont('Arial_Narrow', 'B', 9);
} else {
$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);
}
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)
if (!empty($header['PaymentVoucherPaidNote'])) {
$pdf->SetX(15);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, 'Catatan Bayar', 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->MultiCell($valW, 5, $header['PaymentVoucherPaidNote'], 0, 'L');
}
$leftY = $pdf->GetY();
// ── Kolom Kanan ───────────────────────────────────────────────────────
$pdf->SetY($startY);
$rightX = 15 + $halfW;
$rightItems = array(
array('Cabang', $header['M_BranchName'] ?: '-'),
array('Tgl Pembayaran', $this->_fmt_date($header['PaymentVoucherPaidDate'])),
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
// =========================================================================
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 + 45 + 30 + 72 + 25 = 180
$cols = array(
array('No', 8, 'C'),
array('No. Request Direct', 45, 'L'),
array('Kategori', 30, 'L'),
array('Deskripsi', 72, 'L'),
array('Nominal Bayar', 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();
// 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) {
$amount = floatval($d['PurchaseRequestDirectDetailTotalRealitationPrice']);
if ($amount <= 0) {
$amount = floatval($d['PurchaseRequestDirectDetailTotalEstimationPrice']);
}
$row_data = array(
$no,
$d['PurchaseRequestDirectNumber'] ?: '-',
$d['PurchaseDirectCategoryName'] ?: '-',
$d['ItemDescription'] ?: '-',
$this->_fmt_rp($amount),
);
$pdf->Row($row_data);
$totalPay += $amount;
$no++;
}
// Baris TOTAL
$span = array_sum(array_column(array_slice($cols, 0, 4), 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 PEMBAYARAN', 1, 0, 'R', true);
$pdf->Cell($cols[4][1], 7, $this->_fmt_rp($totalPay), 1, 0, 'R', true);
$pdf->Ln(6);
// Ringkasan Biaya di Kanan Bawah (sejajar dengan Nominal Bayar)
$pdf->Ln(2);
}
// =========================================================================
// PDF SECTION: Syarat & Ketentuan
// =========================================================================
private function _pdf_terms()
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
$terms = array(
'Voucher ini adalah tanda bukti pengeluaran kas/bank yang sah untuk pembayaran dokumen PR Direct di atas.',
'Penerima dana bertanggung jawab penuh atas keabsahan penggunaan dana yang diserahterimakan.',
'Realisasi pembayaran harus dilaporkan kembali ke bagian keuangan selambat-lambatnya 3 hari kerja.',
'Dokumen ini dicetak secara digital dan divalidasi oleh otorisasi sistem akuntansi 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

@@ -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

@@ -1,429 +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 MutasiHandoverFpdf 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_penyerahan_mutasi extends MY_Controller
{
// ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var MutasiHandoverFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Mutasi Handover (Penyerahan 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);
$details = $this->_get_detail($id);
// ── Inisialisasi FPDF custom ──────────────────────────────────────
$this->_pdf = new MutasiHandoverFpdf('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 = 'PH_' . 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 Penyerahan 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
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
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, 'PENYERAHAN MUTASI (HANDOVER)', 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('Tanggal', $this->_fmt_date($header['MutasiHandoverDate']), 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 Status
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('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');
}
// 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();
// 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 + 80 + 20 + 20 + 25 + 27 = 180
$cols = array(
array('No', 8, 'C'),
array('Nama Item', 80, 'L'),
array('Unit', 20, 'C'),
array('Qty', 20, 'R'),
array('Nilai Buku', 25, 'R'),
array('Total', 27, '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_val = 0;
foreach ($details as $d) {
$bookValue = floatval($d['MutasiHandoverDetailBookValue'] ?? 0);
$qty = floatval($d['MutasiHandoverDetailQty'] ?? 0);
$lineTotal = $qty * $bookValue;
$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->Ln();
$total_val += $lineTotal;
$no++;
}
// Baris TOTAL
$span = array_sum(array_column(array_slice($cols, 0, 5), 1));
$pdf->SetLineWidth(0.3);
$pdf->SetFont('Arial_Narrow', 'B', 9);
$pdf->SetFillColor(220, 220, 220);
$pdf->Cell($span, 7, 'TOTAL', 1, 0, 'R', true);
$pdf->Cell($cols[5][1], 7, $this->_fmt_rp($total_val), 1, 0, 'R', true);
$pdf->Ln();
// ── Ringkasan nilai (rata kanan) ──────────────────────────────────────
$pdf->Ln(3);
$summary = array(
array('Total Nilai Penyerahan', $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(
'Penyerahan mutasi ini dilakukan berdasarkan dokumen mutasi yang telah disetujui sebelumnya.',
'Barang yang diserahkan harus sesuai dengan jumlah dan spesifikasi yang tercantum dalam dokumen ini.',
'Penerima barang wajib memeriksa dan memverifikasi kesesuaian barang sebelum menerima.',
'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,395 +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
// Footer tidak bisa bergeser karena FPDF memanggil Footer() sebelum ganti hal.
// =============================================================================
class PrdFpdf extends FPDF
{
public $printUsername = '-';
public $printDate = '';
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
{
parent::__construct($orientation, $unit, $size);
// Daftarkan Arial Narrow — file font ada di fpdf/font/Arial_Narrow.php
$this->AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular
$this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold)
}
public function Footer()
{
$pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15
// ── Posisi: 20mm dari bawah halaman ──────────────────────────────────
$this->SetY(-20);
// ── Baris 1: Print Oleh (kiri) | Nomor Halaman (tengah) ───────────────
$colSide = ($pageW - 40) / 2;
$colCenter = 40;
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Print Oleh : ' . $this->printUsername, 0, 0, 'L');
$this->Cell($colCenter, 4, $this->PageNo() . ' / {nb}', 0, 0, 'C');
$this->Cell($colSide, 4, '', 0, 1, 'R');
// ── Baris 2: Tgl Print (kiri) ──────────────────────────────────────────
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L');
$this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L');
}
}
// =============================================================================
// Controller
// =============================================================================
class Rpt_pr_direct extends MY_Controller
{
// ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var PrdFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Purchase Request Direct Report API";
}
// =========================================================================
// ENDPOINT: pdf
// GET/POST: id (PurchaseRequestDirectID), 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 PrdFpdf('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 = 'PRD_' . str_replace('/', '-', $header['PurchaseRequestDirectNumber']) . '.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
prd.*,
b.M_BranchName,
b.M_BranchAddress,
r.S_RegionalName,
IFNULL(u.M_UserUsername,'') AS CreatedByName,
IFNULL(ua.M_UserUsername,'') AS ApprovedByName
FROM purchase_request_direct prd
LEFT JOIN m_branch b ON b.M_BranchCode = prd.PurchaseRequestDirectM_BranchCode
LEFT JOIN s_regional r ON r.S_RegionalID = prd.PurchaseRequestDirectS_RegionalID
LEFT JOIN m_user u ON u.M_UserID = prd.PurchaseRequestCreatedUserID
LEFT JOIN m_user ua ON ua.M_UserID = prd.PurchaseRequestDirectApprovedBy
WHERE prd.PurchaseRequestDirectID = ?
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Purchase Request Direct tidak ditemukan");
exit;
}
return $qry->row_array();
}
// =========================================================================
// DATABASE: Ambil data detail
// =========================================================================
private function _get_detail($id)
{
$sql = "
SELECT
prdd.*,
iu.ItemUnitName,
iu.ItemUnitCode,
pdc.PurchaseDirectCategoryName
FROM purchase_request_direct_detail prdd
LEFT JOIN itemunit iu ON iu.ItemUnitID = prdd.PurchaseRequestDirectDetailItemUnitID
LEFT JOIN purchase_direct_category pdc ON pdc.PurchaseDirectCategoryID = prdd.PurchaseRequestDirectDetailPurchaseRequestDirectCategoryID
WHERE prdd.PurchaseRequestDirectDetailPurchaseRequestDirectID = ?
AND prdd.PurchaseRequestDirectDetailIsActive = 'Y'
ORDER BY prdd.PurchaseRequestDirectDetailID 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 REQUEST DIRECT (PRD)', 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();
$half = $pageW / 2;
$lbl = 28;
$val = $half - $lbl - 4;
// ── Kolom Kiri ────────────────────────────────────────────────────────
$pdf->SetY($startY);
$left = array(
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']),
array('Alamat', $header['M_BranchAddress']),
array('Dibuat Oleh', $header['CreatedByName']),
);
foreach ($right as $item) {
$pdf->SetX($rightX);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lbl, 5, $item[0], 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$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->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 + 50 + 30 + 15 + 22 + 28 + 27 = 180 (Qty Disetujui dihapus)
$cols = array(
array('No', 8, 'C'),
array('Nama', 50, 'L'),
array('Kategori', 30, 'L'),
array('Unit', 15, 'C'),
array('Qty Request', 22, 'R'),
array('Harga', 28, 'R'),
array('Total', 27, '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;
$total_est = 0;
foreach ($details as $d) {
$pdf->Cell($cols[0][1], 6, $no, 1, 0, 'C');
$pdf->Cell($cols[1][1], 6, $d['PurchaseRequestDirectDescription'] ?: $d['ItemUnitName'], 1, 0, 'L');
$pdf->Cell($cols[2][1], 6, $d['PurchaseDirectCategoryName'] ?: '-', 1, 0, 'L');
$pdf->Cell($cols[3][1], 6, $d['ItemUnitName'], 1, 0, 'C');
$pdf->Cell($cols[4][1], 6, $this->_fmt_qty($d['PurchaseRequestDirectDetailAmountRequest']), 1, 0, 'R');
$pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['PurchaseRequestDirectDetailEstimationPrice']), 1, 0, 'R');
$pdf->Cell($cols[6][1], 6, $this->_fmt_rp($d['PurchaseRequestDirectDetailTotalEstimationPrice']), 1, 0, 'R');
$pdf->Ln();
$total_est += floatval($d['PurchaseRequestDirectDetailTotalEstimationPrice']);
$no++;
}
// Baris TOTAL
$span = array_sum(array_column(array_slice($cols, 0, 6), 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($total_est), 1, 0, 'R', true);
$pdf->Ln();
// ── Ringkasan nilai (rata kanan) ──────────────────────────────────────
$pdf->Ln(4);
$summary = array(
array('Total Estimasi', $this->_fmt_rp($header['PurchaseRequestDirectTotalEstimation'])),
array('Adjustment', $this->_fmt_rp($header['PurchaseRequestDirectAdjustment'])),
array('Total Realisasi', $this->_fmt_rp($header['PurchaseRequestDirectTotalRealitation'])),
array('Total Pembayaran', $this->_fmt_rp($header['PurchaseRequestDirectTotalPaid'])),
);
$cW1 = 50;
$cW2 = 40;
$offsetX = 15 + $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(
'Pengajuan pembelian ini harus mendapatkan persetujuan dari pejabat berwenang sebelum proses pembelian dilakukan.',
'Barang/jasa yang dibeli harus sesuai dengan spesifikasi dan kebutuhan yang tercantum dalam dokumen ini.',
'Pembayaran dilakukan setelah barang/jasa diterima dan diverifikasi sesuai pesanan.',
'Dokumen ini bersifat internal dan hanya digunakan untuk keperluan proses pengadaan.',
);
$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

@@ -1,412 +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
// Footer tidak bisa bergeser karena FPDF memanggil Footer() sebelum ganti hal.
// =============================================================================
class PrdApprovalFpdf extends FPDF
{
public $printUsername = '-';
public $printDate = '';
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
{
parent::__construct($orientation, $unit, $size);
// Daftarkan Arial Narrow — file font ada di fpdf/font/Arial_Narrow.php
$this->AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular
$this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold)
}
public function Footer()
{
$pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15
// ── Posisi: 20mm dari bawah halaman ──────────────────────────────────
$this->SetY(-20);
// ── Baris 1: Print Oleh (kiri) | Nomor Halaman (tengah) ───────────────
$colSide = ($pageW - 40) / 2;
$colCenter = 40;
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Print Oleh : ' . $this->printUsername, 0, 0, 'L');
$this->Cell($colCenter, 4, $this->PageNo() . ' / {nb}', 0, 0, 'C');
$this->Cell($colSide, 4, '', 0, 1, 'R');
// ── Baris 2: Tgl Print (kiri) ──────────────────────────────────────────
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L');
$this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L');
}
}
// =============================================================================
// Controller
// =============================================================================
class Rpt_pr_direct_approval extends MY_Controller
{
// ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var PrdApprovalFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Purchase Request Direct Approval Report API";
}
// =========================================================================
// ENDPOINT: pdf
// GET/POST: id (PurchaseRequestDirectID), 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 status Approved, Paid, atau Completed yang bisa dicetak di report Approval
if (!in_array($header['PurchaseRequestDirectStatus'], array('Approved', 'Paid', 'Completed'))) {
$this->sys_error("Dokumen belum disetujui (Status: " . $header['PurchaseRequestDirectStatus'] . ")");
exit;
}
$details = $this->_get_detail($id);
// ── Inisialisasi FPDF custom ──────────────────────────────────────
$this->_pdf = new PrdApprovalFpdf('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 = 'PRD_APPROVAL_' . str_replace('/', '-', $header['PurchaseRequestDirectNumber']) . '.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
prd.*,
b.M_BranchName,
b.M_BranchAddress,
r.S_RegionalName,
IFNULL(u.M_UserUsername,'') AS CreatedByName,
IFNULL(ua.M_UserUsername,'') AS ApprovedByName
FROM purchase_request_direct prd
LEFT JOIN m_branch b ON b.M_BranchCode = prd.PurchaseRequestDirectM_BranchCode
LEFT JOIN s_regional r ON r.S_RegionalID = prd.PurchaseRequestDirectS_RegionalID
LEFT JOIN m_user u ON u.M_UserID = prd.PurchaseRequestCreatedUserID
LEFT JOIN m_user ua ON ua.M_UserID = prd.PurchaseRequestDirectApprovedBy
WHERE prd.PurchaseRequestDirectID = ?
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Purchase Request Direct tidak ditemukan");
exit;
}
return $qry->row_array();
}
// =========================================================================
// DATABASE: Ambil data detail
// =========================================================================
private function _get_detail($id)
{
$sql = "
SELECT
prdd.*,
iu.ItemUnitName,
iu.ItemUnitCode,
pdc.PurchaseDirectCategoryName
FROM purchase_request_direct_detail prdd
LEFT JOIN itemunit iu ON iu.ItemUnitID = prdd.PurchaseRequestDirectDetailItemUnitID
LEFT JOIN purchase_direct_category pdc ON pdc.PurchaseDirectCategoryID = prdd.PurchaseRequestDirectDetailPurchaseRequestDirectCategoryID
WHERE prdd.PurchaseRequestDirectDetailPurchaseRequestDirectID = ?
AND prdd.PurchaseRequestDirectDetailIsActive = 'Y'
ORDER BY prdd.PurchaseRequestDirectDetailID 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 REQUEST DIRECT APPROVAL (PRD)', 0, 1, 'L');
$pdf->SetDrawColor(0, 0, 0);
$pdf->SetLineWidth(0.5);
$pdf->Line(15, $pdf->GetY(), 15 + $pageW, $pdf->GetY());
$pdf->Ln(2);
// ── Info dokumen: 2 kolom (kiri & kanan) ─────────────────────────────
$startY = $pdf->GetY();
$halfW = $pageW / 2;
$lblW = 28;
$valW = $halfW - $lblW - 4;
// ── Kolom Kiri ────────────────────────────────────────────────────────
$pdf->SetY($startY);
$leftItems = array(
array('Nomor', $header['PurchaseRequestDirectNumber'], true),
array('Tanggal', $this->_fmt_date($header['PurchaseRequestDirectDate']), false),
array('Tanggal Pelaksanaan', $this->_fmt_date($header['PurchaseRequestDirectDateUse']), false),
array('Tanggal Approved', $this->_fmt_datetime($header['PurchaseRequestDirectApprovedDate'])),
);
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 (isset($item[2]) && $item[2]) {
$pdf->SetFont('Arial_Narrow', 'B', 9);
} else {
$pdf->SetFont('Arial_Narrow', '', 9);
}
$pdf->Cell($valW, 5, $item[1], 0, 1, 'L');
}
// Keterangan & Catatan langsung di bawah Status (tanpa spasi vertikal)
if (!empty($header['PurchaseRequestDirectDescription'])) {
$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['PurchaseRequestDirectDescription'], 0, 'L');
}
if (!empty($header['PurchaseRequestDirectNote'])) {
$pdf->SetX(15);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, 'Catatan', 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->MultiCell($valW, 5, $header['PurchaseRequestDirectNote'], 0, 'L');
}
$leftY = $pdf->GetY();
// ── Kolom Kanan ───────────────────────────────────────────────────────
$pdf->SetY($startY);
$rightX = 15 + $halfW;
$rightItems = array(
array('Cabang', $header['M_BranchName']),
array('Regional', $header['S_RegionalName']),
array('Alamat', $header['M_BranchAddress']),
array('Dibuat Oleh', $header['CreatedByName']),
array('Disetujui Oleh', $header['ApprovedByName']),
);
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') {
$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 + 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 + 42 + 25 + 15 + 17 + 18 + 28 + 27 = 180
$cols = array(
array('No', 8, 'C'),
array('Nama', 42, 'L'),
array('Kategori', 25, 'L'),
array('Unit', 15, 'C'),
array('Qty Request', 17, 'R'),
array('Qty Disetujui', 18, 'R'),
array('Harga', 28, 'R'),
array('Total', 27, '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;
$total_est = 0;
foreach ($details as $d) {
$pdf->Cell($cols[0][1], 6, $no, 1, 0, 'C');
$pdf->Cell($cols[1][1], 6, $d['PurchaseRequestDirectDescription'] ?: $d['ItemUnitName'], 1, 0, 'L');
$pdf->Cell($cols[2][1], 6, $d['PurchaseDirectCategoryName'] ?: '-', 1, 0, 'L');
$pdf->Cell($cols[3][1], 6, $d['ItemUnitName'], 1, 0, 'C');
$pdf->Cell($cols[4][1], 6, $this->_fmt_qty($d['PurchaseRequestDirectDetailAmountRequest']), 1, 0, 'R');
$pdf->Cell($cols[5][1], 6, $this->_fmt_qty($d['PurchaseRequestDirectDetailAmount']), 1, 0, 'R');
$pdf->Cell($cols[6][1], 6, $this->_fmt_rp($d['PurchaseRequestDirectDetailEstimationPrice']), 1, 0, 'R');
$pdf->Cell($cols[7][1], 6, $this->_fmt_rp($d['PurchaseRequestDirectDetailTotalEstimationPrice']), 1, 0, 'R');
$pdf->Ln();
$total_est += floatval($d['PurchaseRequestDirectDetailTotalEstimationPrice']);
$no++;
}
// Baris TOTAL
$span = array_sum(array_column(array_slice($cols, 0, 7), 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[7][1], 7, $this->_fmt_rp($total_est), 1, 0, 'R', true);
$pdf->Ln();
// ── Ringkasan nilai (rata kanan) ──────────────────────────────────────
$pdf->Ln(4);
$summary = array(
array('Total Estimasi', $this->_fmt_rp($header['PurchaseRequestDirectTotalEstimation'])),
array('Adjustment', $this->_fmt_rp($header['PurchaseRequestDirectAdjustment'])),
array('Total Realisasi', $this->_fmt_rp($header['PurchaseRequestDirectTotalRealitation'])),
array('Total Pembayaran', $this->_fmt_rp($header['PurchaseRequestDirectTotalPaid'])),
);
$cW1 = 50;
$cW2 = 40;
$offsetX = 15 + $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(
'Pengajuan pembelian ini harus mendapatkan persetujuan dari pejabat berwenang sebelum proses pembelian dilakukan.',
'Barang/jasa yang dibeli harus sesuai dengan spesifikasi dan kebutuhan yang tercantum dalam dokumen ini.',
'Pembayaran dilakukan setelah barang/jasa diterima dan diverifikasi sesuai pesanan.',
'Dokumen ini bersifat internal dan hanya digunakan untuk keperluan proses pengadaan.',
);
$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

@@ -1,463 +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 PurchaseOrderAssetFpdf extends FPDF
{
public $printUsername = '-';
public $printDate = '';
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
{
parent::__construct($orientation, $unit, $size);
// Daftarkan Arial Narrow — file font ada di fpdf/font/Arial_Narrow.php
$this->AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular
$this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold)
}
public function Footer()
{
$pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15
// ── Posisi: 20mm dari bawah halaman ──────────────────────────────────
$this->SetY(-20);
// ── Baris 1: Print Oleh (kiri) | Nomor Halaman (tengah) ───────────────
$colSide = ($pageW - 40) / 2;
$colCenter = 40;
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Print Oleh : ' . $this->printUsername, 0, 0, 'L');
$this->Cell($colCenter, 4, $this->PageNo() . ' / {nb}', 0, 0, 'C');
$this->Cell($colSide, 4, '', 0, 1, 'R');
// ── Baris 2: Tgl Print (kiri) ──────────────────────────────────────────
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L');
$this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L');
}
}
// =============================================================================
// Controller
// =============================================================================
class Rpt_purchase_order_asset extends MY_Controller
{
// ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var PurchaseOrderAssetFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Purchase Order Asset Report API";
}
// =========================================================================
// ENDPOINT: pdf
// GET/POST: id (PurchaseOrderID), username (opsional)
// =========================================================================
public function pdf()
{
try {
$id = intval($this->input->get_post('id'));
$username = trim($this->input->get_post('username') ?? '');
if ($id <= 0) {
$this->sys_error("ID tidak valid");
exit;
}
// ── Ambil data header & detail dari DB ────────────────────────────
$header = $this->_get_header($id);
$details = $this->_get_detail($id);
// ── Inisialisasi FPDF custom ──────────────────────────────────────
$this->_pdf = new PurchaseOrderAssetFpdf('P', 'mm', 'A4');
$this->_pdf->printUsername = $username !== '' ? $username : '-';
$this->_pdf->printDate = date('d-m-Y H:i:s');
$this->_pageW = $this->_pdf->GetPageWidth() - 30;
$this->_header_data = $header;
$this->_username = $this->_pdf->printUsername;
$this->_pdf->AliasNbPages(); // aktifkan alias total halaman
$this->_pdf->SetMargins(15, 15, 15);
$this->_pdf->SetAutoPageBreak(true, 22); // 22mm ruang footer di bawah
$this->_pdf->AddPage();
// ── Susun isi halaman ─────────────────────────────────────────────
$this->_pdf_header();
$this->_pdf_data($details);
$this->_pdf_terms();
// ── Output ────────────────────────────────────────────────────────
$filename = 'PO_ASSET_' . str_replace('/', '-', $header['PurchaseOrderNumber']) . '.pdf';
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="' . $filename . '"');
header('Cache-Control: private, max-age=0, must-revalidate');
header('Pragma: public');
echo $this->_pdf->Output('S');
} catch (Exception $exc) {
$this->sys_error($exc->getMessage());
}
}
// =========================================================================
// DATABASE: Ambil data header
// =========================================================================
private function _get_header($id)
{
$sql = "
SELECT
po.*,
sup.SupplierName,
sup.SupplierAddress,
sup.SupplierPhone,
b.M_BranchName,
b.M_BranchAddress,
r.S_RegionalName,
ac.PurchaseOrderAssetContractName AS ContractName,
ac.PurchaseOrderAssetContractDate AS ContractDate,
ac.PurchaseOrderAssetContractStartDate AS ContractStart,
ac.PurchaseOrderAssetContractEndDate AS ContractEnd,
ac.PurchaseOrderAssetContractDuration AS ContractDuration,
ac.PurchaseOrderAssetContractInstallmentNumber AS InstallmentNumber,
ac.PurchaseOrderAssetContractInstallmentPayAmount AS InstallmentPayAmount,
ac.PurchaseOrderAssetContractInstallmentDownPayment AS InstallmentDownPayment,
ac.PurchaseOrderAssetContractInstallmentDownPaymentType AS InstallmentDownPaymentType,
ac.PurchaseOrderAssetContractStatus AS ContractStatus
FROM purchase_order po
LEFT JOIN supplier sup ON sup.SupplierID = po.PurchaseOrderSupplierID
LEFT JOIN s_regional r ON r.S_RegionalID = po.PurchaseOrderS_RegionalID
LEFT JOIN purchase_order_asset_contract ac ON ac.PurchaseOrderAssetContractPurchaseOrderID = po.PurchaseOrderID
AND ac.PurchaseOrderAssetContractIsActive = 'Y'
LEFT JOIN m_branch b ON b.M_BranchID = (
-- Cabang pengirim/tujuan diambil dari detail pertama
SELECT pod.PurchaseOrderDetailWarehouseID
FROM purchase_order_detail pod
WHERE pod.PurchaseOrderDetailPurchaseOrderID = po.PurchaseOrderID
AND pod.PurchaseOrderDetailIsActive = 'Y'
LIMIT 1
)
WHERE po.PurchaseOrderIsActive = 'Y'
AND po.PurchaseOrderID = ?
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Purchase Order tidak ditemukan");
exit;
}
return $qry->row_array();
}
// =========================================================================
// DATABASE: Ambil data detail (menggunakan summary agar teragregasi)
// =========================================================================
private function _get_detail($id)
{
$sql = "
SELECT
pos.PurchaseOrderSummaryQty AS RequestQty,
pos.PurchaseOrderSummaryPrice AS SupplierPrice,
pos.PurchaseOrderSummaryDiscountAmount AS DiskonAmount,
pos.PurchaseOrderSummaryTotal AS TempTotal,
item.M_ItemCode,
item.M_ItemDesc,
iu.ItemUnitName,
iu.ItemUnitCode
FROM purchase_order_summary pos
JOIN m_item item ON item.M_ItemID = pos.PurchaseOrderSummaryItemID
AND item.M_ItemIsActive = 'Y'
LEFT JOIN itemunit iu ON iu.ItemUnitID = pos.PurchaseOrderSummaryItemUnitID
AND iu.ItemUnitIsActive = 'Y'
WHERE pos.PurchaseOrderSummaryIsActive = 'Y'
AND pos.PurchaseOrderSummaryPurchaseOrderID = ?
ORDER BY pos.PurchaseOrderSummaryID ASC
";
$qry = $this->db->query($sql, array($id));
return $qry ? $qry->result_array() : array();
}
// =========================================================================
// PDF SECTION: Header — Judul + Informasi Dokumen (2 kolom)
// =========================================================================
private function _pdf_header()
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
$header = $this->_header_data;
// ── Judul utama ───────────────────────────────────────────────────────
$pdf->SetFont('Arial_Narrow', 'B', 14);
$pdf->Cell($pageW, 8, 'PURCHASE ORDER ASET (KONTRAK / CICILAN)', 0, 1, 'L');
$pdf->SetDrawColor(0, 0, 0);
$pdf->SetLineWidth(0.5);
$pdf->Line(15, $pdf->GetY(), 15 + $pageW, $pdf->GetY());
$pdf->Ln(2);
$startY = $pdf->GetY();
$halfW = $pageW / 2;
$lblW = 28;
$valW = $halfW - $lblW - 4;
// ── Kolom Kiri ────────────────────────────────────────────────────────
$pdf->SetY($startY);
// Periode kontrak
$periodeKontrak = '-';
if (!empty($header['ContractStart']) && $header['ContractStart'] !== '0000-00-00') {
$periodeKontrak = $this->_fmt_date($header['ContractStart']) . ' s/d ' . $this->_fmt_date($header['ContractEnd']);
if (intval($header['ContractDuration']) > 0) {
$periodeKontrak .= ' (' . $header['ContractDuration'] . ' Bln)';
}
}
$leftItems = array(
array('Nomor', $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),
);
foreach ($leftItems as $item) {
$pdf->SetX(15);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, $item[0], 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
if ($item[2]) {
$pdf->SetFont('Arial_Narrow', 'B', 9);
} else {
$pdf->SetFont('Arial_Narrow', '', 9);
}
$pdf->Cell($valW, 5, $item[1], 0, 1, 'L');
}
// Keterangan / Note langsung di bawah Status (tanpa spasi vertikal)
if (!empty($header['PurchaseOrderNote'])) {
$pdf->SetX(15);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, 'Keterangan', 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->MultiCell($valW, 5, $header['PurchaseOrderNote'], 0, 'L');
}
$leftY = $pdf->GetY();
// ── Kolom Kanan ───────────────────────────────────────────────────────
$pdf->SetY($startY);
$rightX = 15 + $halfW;
// Down Payment format
$dpVal = '-';
$dpNominal = floatval($header['InstallmentDownPayment'] ?? 0);
if ($dpNominal > 0) {
if (($header['InstallmentDownPaymentType'] ?? 'nominal') === 'percent') {
$dpVal = number_format($dpNominal, 0, ',', '.') . '%';
} else {
$dpVal = $this->_fmt_rp($dpNominal);
}
}
// Cicilan format
$installmentVal = '-';
$instNum = intval($header['InstallmentNumber'] ?? 0);
$instAmount = floatval($header['InstallmentPayAmount'] ?? 0);
if ($instNum > 0) {
$installmentVal = $instNum . ' Kali x ' . $this->_fmt_rp($instAmount);
}
$rightItems = array(
array('Supplier', $header['SupplierName'] ?: '-'),
array('Alamat Supplier', $header['SupplierAddress'] ?: '-'),
array('Telp Supplier', $header['SupplierPhone'] ?: '-'),
array('Down Payment (DP)', $dpVal),
array('Cicilan / Tenor', $installmentVal),
);
foreach ($rightItems as $item) {
$pdf->SetX($rightX);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, $item[0], 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->SetFont('Arial_Narrow', '', 9);
if ($item[0] === 'Alamat Supplier') {
$pdf->MultiCell($valW, 5, $item[1], 0, 'L');
} else {
$pdf->Cell($valW, 5, $item[1], 0, 1, 'L');
}
}
$rightY = $pdf->GetY();
// Posisikan Y ke yang paling bawah + margin
$pdf->SetY(max($leftY, $rightY) + 4);
}
// =========================================================================
// PDF SECTION: Data — Tabel detail item
// =========================================================================
private function _pdf_data($details)
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
$header = $this->_header_data;
// ── Definisi kolom: [label, lebar, align] ─────────────────────────────
// Total lebar = 180mm (A4 portrait: 210 - margin 15 kiri - 15 kanan)
// 8 + 60 + 20 + 15 + 25 + 22 + 30 = 180
$cols = array(
array('No', 8, 'C'),
array('Nama', 60, 'L'),
array('Unit', 20, 'C'),
array('Qty', 15, 'R'),
array('Harga Satuan', 25, 'R'),
array('Diskon', 22, 'R'),
array('Total', 30, 'R'),
);
// Header kolom
$pdf->SetLineWidth(0.3); // border medium
$pdf->SetFont('Arial_Narrow', 'B', 8);
$pdf->SetFillColor(220, 220, 220);
$pdf->SetDrawColor(0, 0, 0);
foreach ($cols as $c) {
$pdf->Cell($c[1], 7, $c[0], 1, 0, 'C', true);
}
$pdf->Ln();
// Baris data
$pdf->SetLineWidth(0.2); // border lebih tipis di data
$pdf->SetFont('Arial_Narrow', '', 8);
$pdf->SetFillColor(255, 255, 255);
$no = 1;
$subTotal = 0;
foreach ($details as $d) {
$pdf->Cell($cols[0][1], 6, $no, 1, 0, 'C');
$pdf->Cell($cols[1][1], 6, $d['M_ItemDesc'] ?: ($d['M_ItemCode'] ?: '-'), 1, 0, 'L');
$pdf->Cell($cols[2][1], 6, $d['ItemUnitName'] ?: ($d['ItemUnitCode'] ?: '-'), 1, 0, 'C');
$pdf->Cell($cols[3][1], 6, $this->_fmt_qty($d['RequestQty']), 1, 0, 'C');
$pdf->Cell($cols[4][1], 6, $this->_fmt_rp($d['SupplierPrice']), 1, 0, 'R');
$pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['DiskonAmount']), 1, 0, 'R');
$pdf->Cell($cols[6][1], 6, $this->_fmt_rp($d['TempTotal']), 1, 0, 'R');
$pdf->Ln();
$subTotal += floatval($d['TempTotal']);
$no++;
}
$pdf->Ln(2);
// ── Ringkasan Biaya di Bagian Kanan Bawah ──────────────────────────────
$discountPO = floatval($header['PurchaseOrderDiscountAmount'] ?? 0);
$ppnAmount = floatval($header['PurchaseOrderTaxAmountPpn'] ?? 0);
$pphAmount = floatval($header['PurchaseOrderTaxAmountPph'] ?? 0);
$shipCost = floatval($header['PurchaseOrderShippingCost'] ?? 0);
$grandTotal = floatval($header['PurchaseOrderGrandTotal'] ?? ($subTotal - $discountPO + $ppnAmount - $pphAmount + $shipCost));
$summary = array(
array('Subtotal', $this->_fmt_rp($subTotal)),
);
if ($discountPO > 0) {
$summary[] = array('Diskon PO', '-' . $this->_fmt_rp($discountPO));
}
if ($ppnAmount > 0) {
$summary[] = array('PPN', $this->_fmt_rp($ppnAmount));
}
if ($pphAmount > 0) {
$summary[] = array('PPH', '-' . $this->_fmt_rp($pphAmount));
}
if ($shipCost > 0) {
$summary[] = array('Ongkos Kirim', $this->_fmt_rp($shipCost));
}
$summary[] = array('Grand Total', $this->_fmt_rp($grandTotal));
$cW1 = 62;
$cW2 = 30;
$offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 3), 1)); // Sejajar dengan Qty ke kanan
foreach ($summary as $s) {
$pdf->SetX($offsetX);
$pdf->SetFont('Arial_Narrow', '', 8);
$pdf->Cell($cW1, 5, $s[0], 0, 0, 'L');
if ($s[0] === 'Grand Total') {
$pdf->SetFont('Arial_Narrow', 'B', 9);
} else {
$pdf->SetFont('Arial_Narrow', 'B', 8);
}
$pdf->Cell($cW2, 5, $s[1], 0, 1, 'R');
}
$pdf->Ln(8);
}
// =========================================================================
// PDF SECTION: Syarat & Ketentuan
// =========================================================================
private function _pdf_terms()
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
$terms = array(
'Purchase Order (PO) ini tunduk pada syarat dan ketentuan kontrak sewa/beli aset yang disepakati.',
'Seluruh pembayaran DP dan angsuran harus disetorkan tepat waktu sesuai jadwal kontrak.',
'Serah terima aset akan didokumentasikan terpisah menggunakan Berita Acara Serah Terima (BAST).',
'PO ini sah secara hukum setelah disetujui dan divalidasi secara digital melalui sistem ERP.'
);
$pdf->SetFont('Arial_Narrow', 'B', 9);
$pdf->Cell($pageW, 5, 'Syarat & Ketentuan:', 0, 1, 'L');
$pdf->SetFont('Arial_Narrow', '', 8);
foreach ($terms as $i => $t) {
$pdf->Cell(6, 5, ($i + 1) . '.', 0, 0, 'R');
$pdf->Cell($pageW - 6, 5, $t, 0, 1, 'L');
}
}
// =========================================================================
// HELPER: Format tampilan
// =========================================================================
private function _fmt_date($d)
{
if (!$d || $d === '0000-00-00') return '-';
return date('d-m-Y', strtotime($d));
}
private function _fmt_datetime($d)
{
if (!$d || $d === '0000-00-00 00:00:00') return '-';
return date('d-m-Y H:i', strtotime($d));
}
private function _fmt_num($n)
{
return number_format(floatval($n), 2, ',', '.');
}
// format jumlah/qty: tanpa desimal
private function _fmt_qty($n)
{
return number_format(floatval($n), 0, ',', '.');
}
private function _fmt_rp($n)
{
return 'Rp ' . number_format(floatval($n), 2, ',', '.');
}
}

View File

@@ -1,440 +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 PurchaseOrderJasaFpdf extends FPDF
{
public $printUsername = '-';
public $printDate = '';
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
{
parent::__construct($orientation, $unit, $size);
// Daftarkan Arial Narrow — file font ada di fpdf/font/Arial_Narrow.php
$this->AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular
$this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold)
}
public function Footer()
{
$pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15
// ── Posisi: 20mm dari bawah halaman ──────────────────────────────────
$this->SetY(-20);
// ── Baris 1: Print Oleh (kiri) | Nomor Halaman (tengah) ───────────────
$colSide = ($pageW - 40) / 2;
$colCenter = 40;
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Print Oleh : ' . $this->printUsername, 0, 0, 'L');
$this->Cell($colCenter, 4, $this->PageNo() . ' / {nb}', 0, 0, 'C');
$this->Cell($colSide, 4, '', 0, 1, 'R');
// ── Baris 2: Tgl Print (kiri) ──────────────────────────────────────────
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L');
$this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L');
}
}
// =============================================================================
// Controller
// =============================================================================
class Rpt_purchase_order_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, ',', '.');
}
}

View File

@@ -1,431 +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
// Footer tidak bisa bergeser karena FPDF memanggil Footer() sebelum ganti hal.
// =============================================================================
class ReceiveItemPoFpdf extends FPDF
{
public $printUsername = '-';
public $printDate = '';
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
{
parent::__construct($orientation, $unit, $size);
// Daftarkan Arial Narrow — file font ada di fpdf/font/Arial_Narrow.php
$this->AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular
$this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold)
}
public function Footer()
{
$pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15
// ── Posisi: 20mm dari bawah halaman ──────────────────────────────────
$this->SetY(-20);
// ── Baris 1: Print Oleh (kiri) | Nomor Halaman (tengah) ───────────────
$colSide = ($pageW - 40) / 2;
$colCenter = 40;
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Print Oleh : ' . $this->printUsername, 0, 0, 'L');
$this->Cell($colCenter, 4, $this->PageNo() . ' / {nb}', 0, 0, 'C');
$this->Cell($colSide, 4, '', 0, 1, 'R');
// ── Baris 2: Tgl Print (kiri) ──────────────────────────────────────────
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L');
$this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L');
}
}
// =============================================================================
// Controller
// =============================================================================
class Rpt_receive_item_po extends MY_Controller
{
// ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var ReceiveItemPoFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Receive Item PO (Persediaan) 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 ReceiveItemPoFpdf('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 = 'RI_PO_' . 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
rop.*,
sup.SupplierName,
sup.SupplierAddress,
sup.SupplierPhone,
b.M_BranchName,
b.M_BranchAddress,
r.S_RegionalName,
wh.WarehouseName AS ReceivedWarehouseName,
IFNULL(uCr.M_UserUsername, '') AS CreatedByName,
IFNULL(uCf.M_UserUsername, '') AS ConfirmedByName,
IFNULL((
SELECT po.PurchaseOrderShippingCost
FROM receive_order_po_detail d
JOIN purchase_order po ON po.PurchaseOrderID = d.ReceiveOrderPoDetailPurchaseOrderID
WHERE d.ReceiveOrderPoDetailReceiveOrderPoID = rop.ReceiveOrderPoID
AND d.ReceiveOrderPoDetailIsActive = 'Y'
LIMIT 1
), 0) AS PoShippingCostAmount,
IFNULL((
SELECT po.PurchaseOrderShippingCostStatus
FROM receive_order_po_detail d
JOIN purchase_order po ON po.PurchaseOrderID = d.ReceiveOrderPoDetailPurchaseOrderID
WHERE d.ReceiveOrderPoDetailReceiveOrderPoID = rop.ReceiveOrderPoID
AND d.ReceiveOrderPoDetailIsActive = 'Y'
LIMIT 1
), 'N') AS PoShippingCostIsPaid
FROM receive_order_po rop
LEFT JOIN supplier sup ON sup.SupplierID = rop.ReceiveOrderPoSupplierID
LEFT JOIN m_branch b ON b.M_BranchCode = rop.ReceiveOrderPoM_BranchCode
LEFT JOIN s_regional r ON r.S_RegionalID = rop.ReceiveOrderPoS_RegionalID
LEFT JOIN warehouse wh ON wh.WarehouseID = rop.ReceiveOrderPoWarehouseID
LEFT JOIN m_user uCr ON uCr.M_UserID = rop.ReceiveOrderPoCreatedUserID
LEFT JOIN m_user uCf ON uCf.M_UserID = rop.ReceiveOrderPoConfirmedUserID
WHERE rop.ReceiveOrderPoIsActive = 'Y'
AND rop.ReceiveOrderPoID = ?
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Penerimaan PO tidak ditemukan");
exit;
}
return $qry->row_array();
}
// =========================================================================
// DATABASE: Ambil data detail
// =========================================================================
private function _get_detail($id)
{
$sql = "
SELECT
ropd.*,
item.M_ItemCode,
item.M_ItemDesc,
iu.ItemUnitName,
iu.ItemUnitCode,
po.PurchaseOrderNumber
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
WHERE ropd.ReceiveOrderPoDetailIsActive = 'Y'
AND ropd.ReceiveOrderPoDetailReceiveOrderPoID = ?
ORDER BY ropd.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, 'PENERIMAAN BARANG PO (RECEIVE 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);
$leftItems = array(
array('Nomor', $header['ReceiveOrderPoNumber'], true),
array('Tanggal', $this->_fmt_date($header['ReceiveOrderPoIDate']), false),
array('No. Surat Jalan', $header['ReceiveOrderPoDONumber'] ?: '-', false),
array('Gudang Penerima', $header['ReceivedWarehouseName'] ?: '-', false),
);
foreach ($leftItems as $item) {
$pdf->SetX(15);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, $item[0], 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
if ($item[2]) {
$pdf->SetFont('Arial_Narrow', 'B', 9);
} else {
$pdf->SetFont('Arial_Narrow', '', 9);
}
$pdf->Cell($valW, 5, $item[1], 0, 1, 'L');
}
// Keterangan / Note langsung di bawah Status (tanpa spasi vertikal)
if (!empty($header['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('Alamat Penerima', $header['M_BranchAddress'] ?: '-'),
);
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' || $item[0] === 'Alamat Penerima') {
$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 + 23 + 15 + 27 + 32 = 180
$cols = array(
array('No', 8, 'C'),
array('Nama', 75, 'L'),
array('Unit', 23, 'C'),
array('Qty', 15, 'C'),
array('Harga', 27, '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();
// Baris data
$pdf->SetLineWidth(0.2); // border lebih tipis di data
$pdf->SetFont('Arial_Narrow', '', 8);
$pdf->SetFillColor(255, 255, 255);
$no = 1;
$grand_tot = 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['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']);
$no++;
}
// Baris TOTAL
$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[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)
$shippingCost = floatval($header['ReceiveOrderShippingCostAmount'] ?? 0);
$isPaid = $header['ReceiveOrderShippingCostIsPaid'] ?? 'N';
if ($shippingCost <= 0) {
$shippingCost = floatval($header['PoShippingCostAmount'] ?? 0);
$isPaid = $header['PoShippingCostIsPaid'] ?? 'N';
}
if ($shippingCost > 0) {
$pdf->Ln(2);
$grandTotal = $grand_tot + $shippingCost;
$statusPaid = ($isPaid === 'Y') ? ' (Lunas)' : ' (Belum Lunas)';
$summary = array(
array('Total Item', $this->_fmt_rp($grand_tot)),
array('Biaya Ekspedisi' . $statusPaid, $this->_fmt_rp($shippingCost)),
array('Grand Total', $this->_fmt_rp($grandTotal)),
);
$cW1 = 27;
$cW2 = 32;
$offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 4), 1));
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(8);
}
// =========================================================================
// PDF SECTION: Syarat & Ketentuan
// =========================================================================
private function _pdf_terms()
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
$terms = array(
'Barang yang diterima telah dicocokkan dengan Surat Jalan supplier dan Purchase Order asli.',
'Segala klaim ketidaksesuaian jumlah atau jenis barang harus diselesaikan langsung dengan supplier bersangkutan.',
'Penerimaan barang ini akan otomatis memperbarui stok/inventori gudang persediaan.',
'Dokumen ini dicetak secara otomatis dan sah sebagai bukti penerimaan barang masuk.'
);
$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

@@ -1,435 +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 ReceiveItemPoInventarisFpdf extends FPDF
{
public $printUsername = '-';
public $printDate = '';
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
{
parent::__construct($orientation, $unit, $size);
// Daftarkan Arial Narrow — file font ada di fpdf/font/Arial_Narrow.php
$this->AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular
$this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold)
}
public function Footer()
{
$pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15
// ── Posisi: 20mm dari bawah halaman ──────────────────────────────────
$this->SetY(-20);
// ── Baris 1: Print Oleh (kiri) | Nomor Halaman (tengah) ───────────────
$colSide = ($pageW - 40) / 2;
$colCenter = 40;
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Print Oleh : ' . $this->printUsername, 0, 0, 'L');
$this->Cell($colCenter, 4, $this->PageNo() . ' / {nb}', 0, 0, 'C');
$this->Cell($colSide, 4, '', 0, 1, 'R');
// ── Baris 2: Tgl Print (kiri) ──────────────────────────────────────────
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L');
$this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L');
}
}
// =============================================================================
// Controller
// =============================================================================
class Rpt_receive_item_po_inventaris extends MY_Controller
{
// ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var ReceiveItemPoInventarisFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Receive Item PO (Inventaris) 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 ReceiveItemPoInventarisFpdf('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 = 'RI_PO_INV_' . 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
rop.*,
sup.SupplierName,
sup.SupplierAddress,
sup.SupplierPhone,
b.M_BranchName,
b.M_BranchAddress,
r.S_RegionalName,
wh.WarehouseName AS ReceivedWarehouseName,
ru.M_RuanganName AS RuanganName,
IFNULL(uCr.M_UserUsername, '') AS CreatedByName,
IFNULL(uCf.M_UserUsername, '') AS ConfirmedByName,
IFNULL((
SELECT po.PurchaseOrderShippingCost
FROM receive_order_po_detail d
JOIN purchase_order po ON po.PurchaseOrderID = d.ReceiveOrderPoDetailPurchaseOrderID
WHERE d.ReceiveOrderPoDetailReceiveOrderPoID = rop.ReceiveOrderPoID
AND d.ReceiveOrderPoDetailIsActive = 'Y'
LIMIT 1
), 0) AS PoShippingCostAmount,
IFNULL((
SELECT po.PurchaseOrderShippingCostStatus
FROM receive_order_po_detail d
JOIN purchase_order po ON po.PurchaseOrderID = d.ReceiveOrderPoDetailPurchaseOrderID
WHERE d.ReceiveOrderPoDetailReceiveOrderPoID = rop.ReceiveOrderPoID
AND d.ReceiveOrderPoDetailIsActive = 'Y'
LIMIT 1
), 'N') AS PoShippingCostIsPaid
FROM receive_order_po rop
LEFT JOIN supplier sup ON sup.SupplierID = rop.ReceiveOrderPoSupplierID
LEFT JOIN m_branch b ON b.M_BranchCode = rop.ReceiveOrderPoM_BranchCode
LEFT JOIN s_regional r ON r.S_RegionalID = rop.ReceiveOrderPoS_RegionalID
LEFT JOIN warehouse wh ON wh.WarehouseID = rop.ReceiveOrderPoWarehouseID
LEFT JOIN asset_handover ah ON ah.AssetHandoverReceiveOrderPoID = rop.ReceiveOrderPoID
AND ah.AssetHandoverIsActive = 'Y'
LEFT JOIN m_ruangan ru ON ru.M_RuanganID = ah.AssetHandoverM_RuanganID
LEFT JOIN m_user uCr ON uCr.M_UserID = rop.ReceiveOrderPoCreatedUserID
LEFT JOIN m_user uCf ON uCf.M_UserID = rop.ReceiveOrderPoConfirmedUserID
WHERE rop.ReceiveOrderPoIsActive = 'Y'
AND rop.ReceiveOrderPoID = ?
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Penerimaan PO tidak ditemukan");
exit;
}
return $qry->row_array();
}
// =========================================================================
// DATABASE: Ambil data detail
// =========================================================================
private function _get_detail($id)
{
$sql = "
SELECT
ropd.*,
item.M_ItemCode,
item.M_ItemDesc,
iu.ItemUnitName,
iu.ItemUnitCode,
po.PurchaseOrderNumber
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
WHERE ropd.ReceiveOrderPoDetailIsActive = 'Y'
AND ropd.ReceiveOrderPoDetailReceiveOrderPoID = ?
ORDER BY ropd.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, 'PENERIMAAN BARANG PO INVENTARIS (RECEIVE 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);
$leftItems = array(
array('Nomor', $header['ReceiveOrderPoNumber'], true),
array('Tanggal', $this->_fmt_date($header['ReceiveOrderPoIDate']), false),
array('Gudang Penerima', $header['ReceivedWarehouseName'] ?: '-', false),
array('Ruangan / Lokasi', $header['RuanganName'] ?: '-', 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 Ruangan (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('Cabang', $header['M_BranchName'] ?: '-'),
array('Alamat Penerima', $header['M_BranchAddress'] ?: '-'),
);
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' || $item[0] === 'Alamat Penerima') {
$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 + 23 + 15 + 27 + 32 = 180
$cols = array(
array('No', 8, 'C'),
array('Nama', 75, 'L'),
array('Unit', 23, 'C'),
array('Qty', 15, 'C'),
array('Harga', 27, '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();
// Baris data
$pdf->SetLineWidth(0.2); // border lebih tipis di data
$pdf->SetFont('Arial_Narrow', '', 8);
$pdf->SetFillColor(255, 255, 255);
$no = 1;
$grand_tot = 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['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']);
$no++;
}
// Baris TOTAL
$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[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)
$shippingCost = floatval($header['ReceiveOrderShippingCostAmount'] ?? 0);
$isPaid = $header['ReceiveOrderShippingCostIsPaid'] ?? 'N';
if ($shippingCost <= 0) {
$shippingCost = floatval($header['PoShippingCostAmount'] ?? 0);
$isPaid = $header['PoShippingCostIsPaid'] ?? 'N';
}
if ($shippingCost > 0) {
$pdf->Ln(2);
$grandTotal = $grand_tot + $shippingCost;
$statusPaid = ($isPaid === 'Y') ? ' (Lunas)' : ' (Belum Lunas)';
$summary = array(
array('Total Item', $this->_fmt_rp($grand_tot)),
array('Biaya Ekspedisi' . $statusPaid, $this->_fmt_rp($shippingCost)),
array('Grand Total', $this->_fmt_rp($grandTotal)),
);
$cW1 = 27;
$cW2 = 32;
$offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 4), 1));
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(8);
}
// =========================================================================
// PDF SECTION: Syarat & Ketentuan
// =========================================================================
private function _pdf_terms()
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
$terms = array(
'Barang inventaris/aset yang diterima telah dicocokkan dengan fisik barang dan Purchase Order asli.',
'Penempatan barang inventaris/aset disesuaikan dengan Ruangan/Lokasi yang tertera di dokumen ini.',
'Penerimaan barang inventaris/aset ini akan otomatis didaftarkan ke sistem manajemen aset perusahaan.',
'Dokumen ini dicetak secara otomatis dan sah sebagai bukti penerimaan barang masuk.'
);
$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

@@ -1,509 +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 ReceiveOrderAssetFpdf extends FPDF
{
public $printUsername = '-';
public $printDate = '';
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
{
parent::__construct($orientation, $unit, $size);
// Daftarkan Arial Narrow — file font ada di fpdf/font/Arial_Narrow.php
$this->AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular
$this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold)
}
public function Footer()
{
$pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15
// ── Posisi: 20mm dari bawah halaman ──────────────────────────────────
$this->SetY(-20);
// ── Baris 1: Print Oleh (kiri) | Nomor Halaman (tengah) ───────────────
$colSide = ($pageW - 40) / 2;
$colCenter = 40;
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Print Oleh : ' . $this->printUsername, 0, 0, 'L');
$this->Cell($colCenter, 4, $this->PageNo() . ' / {nb}', 0, 0, 'C');
$this->Cell($colSide, 4, '', 0, 1, 'R');
// ── Baris 2: Tgl Print (kiri) ──────────────────────────────────────────
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L');
$this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L');
}
}
// =============================================================================
// Controller
// =============================================================================
class Rpt_receive_order_asset extends MY_Controller
{
// ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var ReceiveOrderAssetFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Receive Order Asset 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 ReceiveOrderAssetFpdf('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 = 'RI_PO_ASSET_' . 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
rop.*,
sup.SupplierName,
sup.SupplierAddress,
sup.SupplierPhone,
b.M_BranchName,
b.M_BranchAddress,
r.S_RegionalName,
wh.WarehouseName AS ReceivedWarehouseName,
IFNULL(uCr.M_UserUsername, '') AS CreatedByName,
IFNULL(uCf.M_UserUsername, '') AS ConfirmedByName,
IFNULL((
SELECT po.PurchaseOrderShippingCost
FROM receive_order_po_detail d
JOIN purchase_order po ON po.PurchaseOrderID = d.ReceiveOrderPoDetailPurchaseOrderID
WHERE d.ReceiveOrderPoDetailReceiveOrderPoID = rop.ReceiveOrderPoID
AND d.ReceiveOrderPoDetailIsActive = 'Y'
LIMIT 1
), 0) AS PoShippingCostAmount,
IFNULL((
SELECT po.PurchaseOrderShippingCostStatus
FROM receive_order_po_detail d
JOIN purchase_order po ON po.PurchaseOrderID = d.ReceiveOrderPoDetailPurchaseOrderID
WHERE d.ReceiveOrderPoDetailReceiveOrderPoID = rop.ReceiveOrderPoID
AND d.ReceiveOrderPoDetailIsActive = 'Y'
LIMIT 1
), 'N') AS PoShippingCostIsPaid
FROM receive_order_po rop
LEFT JOIN supplier sup ON sup.SupplierID = rop.ReceiveOrderPoSupplierID
LEFT JOIN m_branch b ON b.M_BranchCode = rop.ReceiveOrderPoM_BranchCode
LEFT JOIN s_regional r ON r.S_RegionalID = rop.ReceiveOrderPoS_RegionalID
LEFT JOIN warehouse wh ON wh.WarehouseID = rop.ReceiveOrderPoWarehouseID
LEFT JOIN m_user uCr ON uCr.M_UserID = rop.ReceiveOrderPoCreatedUserID
LEFT JOIN m_user uCf ON uCf.M_UserID = rop.ReceiveOrderPoConfirmedUserID
WHERE rop.ReceiveOrderPoIsActive = 'Y'
AND rop.ReceiveOrderPoID = ?
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Penerimaan PO tidak ditemukan");
exit;
}
return $qry->row_array();
}
// =========================================================================
// DATABASE: Ambil data detail
// =========================================================================
private function _get_detail($id)
{
$sql = "
SELECT
ropd.*,
item.M_ItemCode,
item.M_ItemDesc,
iu.ItemUnitName,
iu.ItemUnitCode,
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
";
$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 BARANG PO ASET (RECEIVE PO ASSET)', 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);
$leftItems = array(
array('Nomor', $header['ReceiveOrderPoNumber'], true),
array('Tanggal', $this->_fmt_date($header['ReceiveOrderPoIDate']), false),
array('Gudang Penerima', $header['ReceivedWarehouseName'] ?: '-', 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 Ruangan (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('Cabang', $header['M_BranchName'] ?: '-'),
array('Alamat Penerima', $header['M_BranchAddress'] ?: '-'),
);
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' || $item[0] === 'Alamat Penerima') {
$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 + 23 + 15 + 27 + 32 = 180
$cols = array(
array('No', 8, 'C'),
array('Nama', 75, 'L'),
array('Unit', 23, 'C'),
array('Qty', 15, 'C'),
array('Harga', 27, '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();
// Baris data
$pdf->SetLineWidth(0.2); // border lebih tipis di data
$pdf->SetFont('Arial_Narrow', '', 8);
$pdf->SetFillColor(255, 255, 255);
$no = 1;
$grand_tot = 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['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']);
$no++;
}
// Baris TOTAL
$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[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);
$isPaid = $header['ReceiveOrderShippingCostIsPaid'] ?? 'N';
if ($shippingCost <= 0) {
$shippingCost = floatval($header['PoShippingCostAmount'] ?? 0);
$isPaid = $header['PoShippingCostIsPaid'] ?? 'N';
}
if ($shippingCost > 0) {
$pdf->Ln(7);
$grandTotal = $grand_tot + $shippingCost;
$statusPaid = ($isPaid === 'Y') ? ' (Lunas)' : ' (Belum Lunas)';
$summary = array(
array('Total Item', $this->_fmt_rp($grand_tot)),
array('Biaya Ekspedisi' . $statusPaid, $this->_fmt_rp($shippingCost)),
array('Grand Total', $this->_fmt_rp($grandTotal)),
);
$cW1 = 27;
$cW2 = 32;
$offsetX = 15 + array_sum(array_column(array_slice($cols, 0, 4), 1));
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(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;
}
}
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++;
}
}
// =========================================================================
// PDF SECTION: Syarat & Ketentuan
// =========================================================================
private function _pdf_terms()
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
$terms = array(
'Barang aset yang diterima telah dicocokkan dengan fisik barang dan Purchase Order asli.',
'Penempatan barang aset disesuaikan dengan Ruangan/Lokasi yang tertera di dokumen ini.',
'Penerimaan barang aset ini akan otomatis didaftarkan ke sistem manajemen aset perusahaan.',
'Dokumen ini dicetak secara otomatis dan sah sebagai bukti penerimaan barang masuk.'
);
$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

@@ -1,600 +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 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

@@ -1,391 +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
// Footer tidak bisa bergeser karena FPDF memanggil Footer() sebelum ganti hal.
// =============================================================================
class ReceiveTransferFpdf extends FPDF
{
public $printUsername = '-';
public $printDate = '';
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
{
parent::__construct($orientation, $unit, $size);
// Daftarkan Arial Narrow — file font ada di fpdf/font/Arial_Narrow.php
$this->AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular
$this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold)
}
public function Footer()
{
$pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15
// ── Posisi: 20mm dari bawah halaman ──────────────────────────────────
$this->SetY(-20);
// ── Baris 1: Print Oleh (kiri) | Nomor Halaman (tengah) ───────────────
$colSide = ($pageW - 40) / 2;
$colCenter = 40;
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Print Oleh : ' . $this->printUsername, 0, 0, 'L');
$this->Cell($colCenter, 4, $this->PageNo() . ' / {nb}', 0, 0, 'C');
$this->Cell($colSide, 4, '', 0, 1, 'R');
// ── Baris 2: Tgl Print (kiri) ──────────────────────────────────────────
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L');
$this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L');
}
}
// =============================================================================
// Controller
// =============================================================================
class Rpt_receive_transfer extends MY_Controller
{
// ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var ReceiveTransferFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Receive Transfer Report API";
}
// =========================================================================
// ENDPOINT: pdf
// GET/POST: id (SuratJalanID), 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 ReceiveTransferFpdf('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 = 'RT_' . str_replace('/', '-', $header['SuratJalanNumber']) . '.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
sj.*,
ex.ExpeditionName,
ex.ExpeditionIsInternal,
exs.ExpeditionStaffName,
exs.ExpeditionStaffMobile,
tg.T_GoodsTransferNum,
tg.T_GoodsTransferDate,
tg.T_GoodsTransferType,
tg.T_GoodsTransferFromM_BranchCode,
tg.T_GoodsTransferToM_BranchCode,
rFrom.S_RegionalName AS RegionalFromName,
bTo.M_BranchName AS BranchToName,
bTo.M_BranchAddress AS BranchToAddress,
wh.WarehouseName AS ReceivedWarehouseName,
IFNULL(uRec.M_UserUsername, '') AS ReceivedByName
FROM suratjalan sj
LEFT JOIN t_goods_transfer tg ON tg.T_GoodsTransferID = sj.SuratJalanT_GoodsTransferID
AND tg.T_GoodsTransferIsActive = 'Y'
LEFT JOIN expedition ex ON ex.ExpeditionID = sj.SuratJalanEkspedisiID
AND ex.ExpeditionIsActive = 'Y'
LEFT JOIN expeditionstaff exs ON exs.ExpeditionStaffID = sj.SuratJalanEkspedisiStaffID
AND exs.ExpeditionStaffIsActive = 'Y'
LEFT JOIN s_regional rFrom ON rFrom.S_RegionalID = tg.T_GoodsTransferFromS_RegionalID
LEFT JOIN m_branch bTo ON bTo.M_BranchCode = tg.T_GoodsTransferToM_BranchCode
LEFT JOIN warehouse wh ON wh.WarehouseID = sj.SuratJalanReceivedWarehouseID
LEFT JOIN m_user uRec ON uRec.M_UserID = sj.SuratJalanReceivedUserID
WHERE sj.SuratJalanIsActive = 'Y'
AND sj.SuratJalanID = ?
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Penerimaan Surat Jalan tidak ditemukan");
exit;
}
return $qry->row_array();
}
// =========================================================================
// DATABASE: Ambil data detail
// =========================================================================
private function _get_detail($id)
{
$sql = "
SELECT
sjd.*,
item.M_ItemCode,
item.M_ItemDesc,
iu.ItemUnitName,
iu.ItemUnitCode,
pr.PurchaseRequestNumber
FROM suratjalan_detail sjd
JOIN m_item item ON item.M_ItemID = sjd.SuratJalanDetailM_ItemID
AND item.M_ItemIsActive = 'Y'
LEFT JOIN itemunit iu ON iu.ItemUnitID = sjd.SuratJalanDetailItemUnitID
AND iu.ItemUnitIsActive = 'Y'
LEFT JOIN purchase_request_flag prf ON prf.PurchaseRequestFlagID = sjd.SuratJalanDetailPurchaseRequestFlagID
AND prf.PurchaseRequestFlagIsActive = 'Y'
LEFT JOIN purchase_request_detail prd ON prd.PurchaseRequestDetailID = prf.PurchaseRequestFlagPurchaseRequestDetailID
LEFT JOIN purchase_request pr ON pr.PurchaseRequestID = prd.PurchaseRequestDetailPurchaseRequestID
WHERE sjd.SuratJalanDetailIsActive = 'Y'
AND sjd.SuratJalanDetailSuratJalanID = ?
ORDER BY sjd.SuratJalanDetailID 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, 'RECEIVE TRANSFER REPORT (RT)', 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);
$leftItems = array(
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),
);
foreach ($leftItems as $item) {
$pdf->SetX(15);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, $item[0], 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
if ($item[2]) {
$pdf->SetFont('Arial_Narrow', 'B', 9);
} else {
$pdf->SetFont('Arial_Narrow', '', 9);
}
$pdf->Cell($valW, 5, $item[1], 0, 1, 'L');
}
// Keterangan / Note langsung di bawah Status (tanpa spasi vertikal)
if (!empty($header['SuratJalanReceivedNote'])) {
$pdf->SetX(15);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, 'Catatan Terima', 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
$pdf->MultiCell($valW, 5, $header['SuratJalanReceivedNote'], 0, 'L');
}
$leftY = $pdf->GetY();
// ── Kolom Kanan ───────────────────────────────────────────────────────
$pdf->SetY($startY);
$rightX = 15 + $halfW;
$rightItems = array(
array('Dari Regional', $header['RegionalFromName'] ?: '-'),
array('Tujuan Cabang', $header['BranchToName'] ?: '-'),
array('Alamat Tujuan', $header['BranchToAddress'] ?: '-'),
array('Ekspedisi', $header['ExpeditionName'] ?: '-'),
array('Driver / Staf', $header['ExpeditionStaffName'] ?: '-'),
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);
if ($item[0] === 'Alamat Tujuan') {
$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 + 95 + 20 + 20 + 20 + 17 = 180
$cols = array(
array('No', 8, 'C'),
array('Nama', 95, 'L'),
array('Unit', 20, 'C'),
array('Qty Kirim', 20, 'R'),
array('Qty Terima', 20, 'R'),
array('Selisih', 17, '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;
foreach ($details as $d) {
$qtyKirim = intval($d['SuratJalanDetailQty']);
$qtyTerima = intval($d['SuratJalanDetailQtyReceived']);
$selisih = $qtyKirim - $qtyTerima;
$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($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->Ln();
$no++;
}
$pdf->Ln(4);
}
// =========================================================================
// PDF SECTION: Syarat & Ketentuan
// =========================================================================
private function _pdf_terms()
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
$terms = array(
'Barang yang diterima telah diverifikasi secara kuantitas dan kualitas sesuai dengan fisik yang diserahterimakan.',
'Segala ketidaksesuaian/selisih barang harus dilaporkan dalam waktu 1x24 jam sejak dokumen ini ditandatangani.',
'Penerimaan barang ini sah secara sistem setelah dokumen ini divalidasi dan disimpan di sistem persediaan.',
'Dokumen ini dicetak secara otomatis dari sistem ERP One-API.'
);
$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

@@ -1,391 +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 RequestMutasiFpdf 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_mutasi extends MY_Controller
{
// ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var RequestMutasiFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Request Mutasi Report API";
}
// =========================================================================
// ENDPOINT: pdf
// GET/POST: id (MutasiRequestID), 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 RequestMutasiFpdf('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 = 'RM_' . str_replace('/', '-', $header['MutasiRequestNumber']) . '.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
mr.*,
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(uv.M_UserUsername, '') AS VerifByName,
IFNULL(ua.M_UserUsername, '') AS ApprovedByName
FROM mutasi_request mr
JOIN item_category ic ON ic.itemCategoryID = mr.MutasiRequestItemCategoryID
JOIN m_branch a ON a.M_BranchID = mr.MutasiRequestFromBranchID
JOIN m_branch b ON b.M_BranchID = mr.MutasiRequestToBranchID
LEFT JOIN m_user u ON u.M_UserID = mr.MutasiRequestUserID
LEFT JOIN m_user uv ON uv.M_UserID = mr.MutasiRequestVerifUserID
LEFT JOIN m_user ua ON ua.M_UserID = mr.MutasiRequestApprovedUserID
WHERE mr.MutasiRequestID = ?
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Request Mutasi tidak ditemukan");
exit;
}
return $qry->row_array();
}
// =========================================================================
// DATABASE: Ambil data detail
// =========================================================================
private function _get_detail($id)
{
$sql = "
SELECT
mrd.*,
i.M_ItemCode,
i.M_ItemDesc,
iu.ItemUnitName,
iu.ItemUnitCode
FROM mutasi_request_detail mrd
LEFT JOIN m_item i ON i.M_ItemID = mrd.MutasiRequestDetailM_ItemID
LEFT JOIN itemunit iu ON iu.ItemUnitID = mrd.MutasiRequestDetailItemUnitID
WHERE mrd.MutasiRequestDetailMutasiRequestID = ?
AND mrd.MutasiRequestDetailIsActive = 'Y'
ORDER BY mrd.MutasiRequestDetailID 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 MUTASI REPORT (RM)', 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', $header['MutasiRequestNumber'], true),
array('Tanggal', $this->_fmt_date($header['MutasiRequestDate']), false),
array('Status', $header['MutasiRequestStatus'], 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 Status
if (!empty($header['MutasiRequestNote'])) {
$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['MutasiRequestNote'], 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('Dibuat Oleh', $header['CreatedByName']),
array('Diverifikasi Oleh', $header['VerifByName'] ?: '-'),
array('Disetujui Oleh', $header['ApprovedByName'] ?: '-'),
);
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');
}
// 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();
// 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 + 80 + 20 + 20 + 25 + 27 = 180
$cols = array(
array('No', 8, 'C'),
array('Nama Item', 80, 'L'),
array('Unit', 20, 'C'),
array('Qty', 20, 'R'),
array('Nilai Buku', 25, 'R'),
array('Total', 27, '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_val = 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['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);
$no++;
}
// Baris TOTAL
$span = array_sum(array_column(array_slice($cols, 0, 5), 1));
$pdf->SetLineWidth(0.3);
$pdf->SetFont('Arial_Narrow', 'B', 9);
$pdf->SetFillColor(220, 220, 220);
$pdf->Cell($span, 7, 'TOTAL', 1, 0, 'R', true);
$pdf->Cell($cols[5][1], 7, $this->_fmt_rp($total_val), 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(
'Mutasi barang ini harus mendapatkan persetujuan dari pejabat berwenang sebelum proses mutasi dilakukan.',
'Barang yang dimutasi harus sesuai dengan spesifikasi dan jumlah yang tercantum dalam dokumen ini.',
'Proses mutasi dilakukan setelah barang diverifikasi dan disetujui oleh pihak terkait.',
'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,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

@@ -1,370 +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
// Footer tidak bisa bergeser karena FPDF memanggil Footer() sebelum ganti hal.
// =============================================================================
class StockReqFpdf extends FPDF
{
public $printUsername = '-';
public $printDate = '';
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
{
parent::__construct($orientation, $unit, $size);
// Daftarkan Arial Narrow — file font ada di fpdf/font/Arial_Narrow.php
$this->AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular
$this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold)
}
public function Footer()
{
$pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15
// ── Posisi: 20mm dari bawah halaman ──────────────────────────────────
$this->SetY(-20);
// ── Baris 1: Print Oleh (kiri) | Nomor Halaman (tengah) ───────────────
$colSide = ($pageW - 40) / 2;
$colCenter = 40;
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Print Oleh : ' . $this->printUsername, 0, 0, 'L');
$this->Cell($colCenter, 4, $this->PageNo() . ' / {nb}', 0, 0, 'C');
$this->Cell($colSide, 4, '', 0, 1, 'R');
// ── Baris 2: Tgl Print (kiri) ──────────────────────────────────────────
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L');
$this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L');
}
}
// =============================================================================
// Controller
// =============================================================================
class Rpt_stock_request extends MY_Controller
{
// ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var StockReqFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Stock Request (PR) Report API";
}
// =========================================================================
// ENDPOINT: pdf
// GET/POST: id (PurchaseRequestID), 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 StockReqFpdf('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 = 'SR_' . str_replace('/', '-', $header['PurchaseRequestNumber']) . '.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
pr.*,
b.M_BranchName,
b.M_BranchAddress,
r.S_RegionalName,
ic.itemCategoryName,
IFNULL(u.M_UserUsername,'') AS CreatedByName,
IFNULL(ua.M_UserUsername,'') AS ApprovedByName
FROM purchase_request pr
LEFT JOIN m_branch b ON b.M_BranchCode = pr.PurchaseRequestM_BranchCode
LEFT JOIN s_regional r ON r.S_RegionalID = pr.PurchaseRequestS_RegionalID
LEFT JOIN item_category ic ON ic.itemCategoryID = pr.PurchaseRequestItemCategoryID
LEFT JOIN m_user u ON u.M_UserID = pr.PurchaseRequestCreatedUserID
LEFT JOIN m_user ua ON ua.M_UserID = pr.PurchaseRequestApprovedBy
WHERE pr.PurchaseRequestID = ?
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Purchase Request tidak ditemukan");
exit;
}
return $qry->row_array();
}
// =========================================================================
// DATABASE: Ambil data detail
// =========================================================================
private function _get_detail($id)
{
$sql = "
SELECT
prd.*,
item.M_ItemCode,
item.M_ItemDesc,
iu.ItemUnitName,
iu.ItemUnitCode
FROM purchase_request_detail prd
LEFT JOIN m_item item ON item.M_ItemID = prd.PurchaseRequestDetailM_ItemID
LEFT JOIN itemunit iu ON iu.ItemUnitID = prd.PurchaseRequestDetailItemUnitID
WHERE prd.PurchaseRequestDetailPurchaseRequestID = ?
AND prd.PurchaseRequestDetailIsActive = 'Y'
ORDER BY prd.PurchaseRequestDetailID 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, 'STOCK REQUEST REPORT (PR)', 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);
$leftItems = array(
array('Nomor', $header['PurchaseRequestNumber'], true),
array('Ref Nomor', $header['PurchaseRequestRefNumber'] ?: '-', false),
array('Tanggal', $this->_fmt_date($header['PurchaseRequestDate']), false),
array('Tanggal Approved', $this->_fmt_datetime($header['PurchaseRequestApprovedDate'])),
);
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 (isset($item[2]) && $item[2]) {
$pdf->SetFont('Arial_Narrow', 'B', 9);
} else {
$pdf->SetFont('Arial_Narrow', '', 9);
}
$pdf->Cell($valW, 5, $item[1], 0, 1, 'L');
}
// Keterangan / Note langsung di bawah Status (tanpa spasi vertikal)
if (!empty($header['PurchaseRequestNote'])) {
$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['PurchaseRequestNote'], 0, 'L');
}
$leftY = $pdf->GetY();
// ── Kolom Kanan ───────────────────────────────────────────────────────
$pdf->SetY($startY);
$rightX = 15 + $halfW;
$rightItems = array(
array('Cabang', $header['M_BranchName']),
array('Regional', $header['S_RegionalName']),
array('Kategori', $header['itemCategoryName'] ?: '-'),
array('Dibuat Oleh', $header['CreatedByName']),
array('Disetujui Oleh', $header['ApprovedByName'] ?: '-'),
);
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 + 82 + 20 + 20 + 25 + 25 = 180
$cols = array(
array('No', 8, 'C'),
array('Nama / Item', 82, 'L'),
array('Unit', 20, 'C'),
array('Qty', 20, 'R'),
array('Harga', 25, '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;
$total_est = 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['PurchaseRequestDetailQty']), 1, 0, 'C');
$pdf->Cell($cols[4][1], 6, $this->_fmt_rp($d['PurchaseRequestDetailPrice']), 1, 0, 'R');
$pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['PurchaseRequestDetailTotal']), 1, 0, 'R');
$pdf->Ln();
$total_est += floatval($d['PurchaseRequestDetailTotal']);
$no++;
}
// Baris TOTAL
$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[5][1], 7, $this->_fmt_rp($total_est), 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(
'Pengajuan pembelian ini harus mendapatkan persetujuan dari pejabat berwenang sebelum proses pembelian dilakukan.',
'Barang/jasa yang dibeli harus sesuai dengan spesifikasi dan kebutuhan yang tercantum dalam dokumen ini.',
'Pembayaran dilakukan setelah barang/jasa diterima dan diverifikasi sesuai pesanan.',
'Dokumen ini bersifat internal dan hanya digunakan untuk keperluan proses pengadaan.',
);
$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

@@ -1,377 +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
// Footer tidak bisa bergeser karena FPDF memanggil Footer() sebelum ganti hal.
// =============================================================================
class StockReqNpFpdf extends FPDF
{
public $printUsername = '-';
public $printDate = '';
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
{
parent::__construct($orientation, $unit, $size);
// Daftarkan Arial Narrow — file font ada di fpdf/font/Arial_Narrow.php
$this->AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular
$this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold)
}
public function Footer()
{
$pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15
// ── Posisi: 20mm dari bawah halaman ──────────────────────────────────
$this->SetY(-20);
// ── Baris 1: Print Oleh (kiri) | Nomor Halaman (tengah) ───────────────
$colSide = ($pageW - 40) / 2;
$colCenter = 40;
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Print Oleh : ' . $this->printUsername, 0, 0, 'L');
$this->Cell($colCenter, 4, $this->PageNo() . ' / {nb}', 0, 0, 'C');
$this->Cell($colSide, 4, '', 0, 1, 'R');
// ── Baris 2: Tgl Print (kiri) ──────────────────────────────────────────
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L');
$this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L');
}
}
// =============================================================================
// Controller
// =============================================================================
class Rpt_stock_request_np extends MY_Controller
{
// ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var StockReqNpFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Stock Request Non Persediaan (PR-NP) Report API";
}
// =========================================================================
// ENDPOINT: pdf
// GET/POST: id (PurchaseRequestID), 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: Pastikan Kategori Item BUKAN '1' (Bukan Persediaan / Inventory)
if ($header['PurchaseRequestItemCategoryID'] == '1') {
$this->sys_error("Dokumen ini adalah kategori Persediaan. Gunakan report Stock Request biasa.");
exit;
}
$details = $this->_get_detail($id);
// ── Inisialisasi FPDF custom ──────────────────────────────────────
$this->_pdf = new StockReqNpFpdf('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 = 'SR_NP_' . str_replace('/', '-', $header['PurchaseRequestNumber']) . '.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
pr.*,
b.M_BranchName,
b.M_BranchAddress,
r.S_RegionalName,
ic.itemCategoryName,
IFNULL(u.M_UserUsername,'') AS CreatedByName,
IFNULL(ua.M_UserUsername,'') AS ApprovedByName
FROM purchase_request pr
LEFT JOIN m_branch b ON b.M_BranchCode = pr.PurchaseRequestM_BranchCode
LEFT JOIN s_regional r ON r.S_RegionalID = pr.PurchaseRequestS_RegionalID
LEFT JOIN item_category ic ON ic.itemCategoryID = pr.PurchaseRequestItemCategoryID
LEFT JOIN m_user u ON u.M_UserID = pr.PurchaseRequestCreatedUserID
LEFT JOIN m_user ua ON ua.M_UserID = pr.PurchaseRequestApprovedBy
WHERE pr.PurchaseRequestID = ?
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Purchase Request tidak ditemukan");
exit;
}
return $qry->row_array();
}
// =========================================================================
// DATABASE: Ambil data detail
// =========================================================================
private function _get_detail($id)
{
$sql = "
SELECT
prd.*,
item.M_ItemCode,
item.M_ItemDesc,
iu.ItemUnitName,
iu.ItemUnitCode
FROM purchase_request_detail prd
LEFT JOIN m_item item ON item.M_ItemID = prd.PurchaseRequestDetailM_ItemID
LEFT JOIN itemunit iu ON iu.ItemUnitID = prd.PurchaseRequestDetailItemUnitID
WHERE prd.PurchaseRequestDetailPurchaseRequestID = ?
AND prd.PurchaseRequestDetailIsActive = 'Y'
ORDER BY prd.PurchaseRequestDetailID 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, 'STOCK REQUEST REPORT (PR) - NON PERSEDIAAN', 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);
$leftItems = array(
array('Nomor', $header['PurchaseRequestNumber'], true),
array('Ref Nomor', $header['PurchaseRequestRefNumber'] ?: '-', false),
array('Tanggal', $this->_fmt_date($header['PurchaseRequestDate']), false),
array('Tanggal Approved', $this->_fmt_datetime($header['PurchaseRequestApprovedDate'])),
);
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 (isset($item[2]) && $item[2]) {
$pdf->SetFont('Arial_Narrow', 'B', 9);
} else {
$pdf->SetFont('Arial_Narrow', '', 9);
}
$pdf->Cell($valW, 5, $item[1], 0, 1, 'L');
}
// Keterangan / Note langsung di bawah Status (tanpa spasi vertikal)
if (!empty($header['PurchaseRequestNote'])) {
$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['PurchaseRequestNote'], 0, 'L');
}
$leftY = $pdf->GetY();
// ── Kolom Kanan ───────────────────────────────────────────────────────
$pdf->SetY($startY);
$rightX = 15 + $halfW;
$rightItems = array(
array('Cabang', $header['M_BranchName']),
array('Regional', $header['S_RegionalName']),
array('Kategori', $header['itemCategoryName'] ?: '-'),
array('Dibuat Oleh', $header['CreatedByName']),
array('Disetujui Oleh', $header['ApprovedByName'] ?: '-'),
);
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 + 82 + 20 + 20 + 25 + 25 = 180
$cols = array(
array('No', 8, 'C'),
array('Nama / Item', 82, 'L'),
array('Unit', 20, 'C'),
array('Qty', 20, 'R'),
array('Harga', 25, '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;
$total_est = 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['PurchaseRequestDetailQty']), 1, 0, 'C');
$pdf->Cell($cols[4][1], 6, $this->_fmt_rp($d['PurchaseRequestDetailPrice']), 1, 0, 'R');
$pdf->Cell($cols[5][1], 6, $this->_fmt_rp($d['PurchaseRequestDetailTotal']), 1, 0, 'R');
$pdf->Ln();
$total_est += floatval($d['PurchaseRequestDetailTotal']);
$no++;
}
// Baris TOTAL
$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[5][1], 7, $this->_fmt_rp($total_est), 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(
'Pengajuan pembelian ini harus mendapatkan persetujuan dari pejabat berwenang sebelum proses pembelian dilakukan.',
'Barang/jasa yang dibeli harus sesuai dengan spesifikasi dan kebutuhan yang tercantum dalam dokumen ini.',
'Pembayaran dilakukan setelah barang/jasa diterima dan diverifikasi sesuai pesanan.',
'Dokumen ini bersifat internal dan hanya digunakan untuk keperluan proses pengadaan.',
);
$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

@@ -1,379 +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
// Footer tidak bisa bergeser karena FPDF memanggil Footer() sebelum ganti hal.
// =============================================================================
class SuratJalanFpdf extends FPDF
{
public $printUsername = '-';
public $printDate = '';
public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
{
parent::__construct($orientation, $unit, $size);
// Daftarkan Arial Narrow — file font ada di fpdf/font/Arial_Narrow.php
$this->AddFont('Arial_Narrow', '', 'Arial_Narrow.php'); // regular
$this->AddFont('Arial_Narrow', 'B', 'Arial_Narrow_B.php'); // bold (Liberation Sans Narrow Bold)
}
public function Footer()
{
$pageW = $this->GetPageWidth() - 30; // sama dengan margin 15+15
// ── Posisi: 20mm dari bawah halaman ──────────────────────────────────
$this->SetY(-20);
// ── Baris 1: Print Oleh (kiri) | Nomor Halaman (tengah) ───────────────
$colSide = ($pageW - 40) / 2;
$colCenter = 40;
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Print Oleh : ' . $this->printUsername, 0, 0, 'L');
$this->Cell($colCenter, 4, $this->PageNo() . ' / {nb}', 0, 0, 'C');
$this->Cell($colSide, 4, '', 0, 1, 'R');
// ── Baris 2: Tgl Print (kiri) ──────────────────────────────────────────
$this->SetFont('Arial_Narrow', '', 7);
$this->Cell($colSide, 4, 'Tgl Print : ' . $this->printDate, 0, 0, 'L');
$this->Cell($colCenter + $colSide, 4, '', 0, 1, 'L');
}
}
// =============================================================================
// Controller
// =============================================================================
class Rpt_surat_jalan extends MY_Controller
{
// ── Properti bersama antar fungsi PDF ─────────────────────────────────────
/** @var SuratJalanFpdf */
private $_pdf;
private $_pageW;
private $_header_data;
private $_username;
public function __construct()
{
parent::__construct();
}
public function index()
{
echo "Surat Jalan Report API";
}
// =========================================================================
// ENDPOINT: pdf
// GET/POST: id (SuratJalanID), 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 SuratJalanFpdf('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 = 'SJ_' . str_replace('/', '-', $header['SuratJalanNumber']) . '.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
sj.*,
ex.ExpeditionName,
ex.ExpeditionIsInternal,
exs.ExpeditionStaffName,
exs.ExpeditionStaffMobile,
tg.T_GoodsTransferNum,
tg.T_GoodsTransferDate,
tg.T_GoodsTransferType,
tg.T_GoodsTransferFromM_BranchCode,
tg.T_GoodsTransferToM_BranchCode,
rFrom.S_RegionalName AS RegionalFromName,
bTo.M_BranchName AS BranchToName,
bTo.M_BranchAddress AS BranchToAddress
FROM suratjalan sj
LEFT JOIN t_goods_transfer tg ON tg.T_GoodsTransferID = sj.SuratJalanT_GoodsTransferID
AND tg.T_GoodsTransferIsActive = 'Y'
LEFT JOIN expedition ex ON ex.ExpeditionID = sj.SuratJalanEkspedisiID
AND ex.ExpeditionIsActive = 'Y'
LEFT JOIN expeditionstaff exs ON exs.ExpeditionStaffID = sj.SuratJalanEkspedisiStaffID
AND exs.ExpeditionStaffIsActive = 'Y'
LEFT JOIN s_regional rFrom ON rFrom.S_RegionalID = tg.T_GoodsTransferFromS_RegionalID
LEFT JOIN m_branch bTo ON bTo.M_BranchCode = tg.T_GoodsTransferToM_BranchCode
WHERE sj.SuratJalanIsActive = 'Y'
AND sj.SuratJalanID = ?
LIMIT 1
";
$qry = $this->db->query($sql, array($id));
if (!$qry || $qry->num_rows() === 0) {
$this->sys_error("Data Surat Jalan tidak ditemukan");
exit;
}
return $qry->row_array();
}
// =========================================================================
// DATABASE: Ambil data detail
// =========================================================================
private function _get_detail($id)
{
$sql = "
SELECT
sjd.*,
item.M_ItemCode,
item.M_ItemDesc,
iu.ItemUnitName,
iu.ItemUnitCode,
pr.PurchaseRequestNumber
FROM suratjalan_detail sjd
JOIN m_item item ON item.M_ItemID = sjd.SuratJalanDetailM_ItemID
AND item.M_ItemIsActive = 'Y'
LEFT JOIN itemunit iu ON iu.ItemUnitID = sjd.SuratJalanDetailItemUnitID
AND iu.ItemUnitIsActive = 'Y'
LEFT JOIN purchase_request_flag prf ON prf.PurchaseRequestFlagID = sjd.SuratJalanDetailPurchaseRequestFlagID
AND prf.PurchaseRequestFlagIsActive = 'Y'
LEFT JOIN purchase_request_detail prd ON prd.PurchaseRequestDetailID = prf.PurchaseRequestFlagPurchaseRequestDetailID
LEFT JOIN purchase_request pr ON pr.PurchaseRequestID = prd.PurchaseRequestDetailPurchaseRequestID
WHERE sjd.SuratJalanDetailIsActive = 'Y'
AND sjd.SuratJalanDetailSuratJalanID = ?
ORDER BY sjd.SuratJalanDetailID 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, 'SURAT JALAN (DELIVERY ORDER)', 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);
$leftItems = array(
array('Nomor', $header['SuratJalanNumber'], true),
array('Tanggal', $this->_fmt_date($header['SuratJalanDate']), false),
array('No. Transfer', $header['SuratJalanT_GoodsTransferNum'] ?: '-', false),
);
foreach ($leftItems as $item) {
$pdf->SetX(15);
$pdf->SetFont('Arial_Narrow', '', 9);
$pdf->Cell($lblW, 5, $item[0], 0, 0, 'L');
$pdf->Cell(4, 5, ':', 0, 0, 'C');
if ($item[2]) {
$pdf->SetFont('Arial_Narrow', 'B', 9);
} else {
$pdf->SetFont('Arial_Narrow', '', 9);
}
$pdf->Cell($valW, 5, $item[1], 0, 1, 'L');
}
// Keterangan / Note langsung di bawah Status (tanpa spasi vertikal)
if (!empty($header['SuratJalanNote'])) {
$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['SuratJalanNote'], 0, 'L');
}
$leftY = $pdf->GetY();
// ── Kolom Kanan ───────────────────────────────────────────────────────
$pdf->SetY($startY);
$rightX = 15 + $halfW;
$rightItems = array(
array('Dari Regional', $header['RegionalFromName'] ?: '-'),
array('Tujuan Cabang', $header['BranchToName'] ?: '-'),
array('Alamat Tujuan', $header['BranchToAddress'] ?: '-'),
array('Ekspedisi', $header['ExpeditionName'] ?: '-'),
array('Driver / Staf', $header['ExpeditionStaffName'] ?: '-'),
array('Kontak Driver', $header['SuratJalanEkspedisiStaffContact'] ?: '-'),
);
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 Tujuan') {
$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 + 104 + 20 + 20 + 28 = 180
$cols = array(
array('No', 8, 'C'),
array('Nama', 104, 'L'),
array('Unit', 20, 'C'),
array('Qty Kirim', 20, 'R'),
array('Qty Diterima', 28, '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;
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['SuratJalanDetailQty']), 1, 0, 'C');
$pdf->Cell($cols[4][1], 6, $this->_fmt_qty($d['SuratJalanDetailQtyReceived']), 1, 0, 'C');
$pdf->Ln();
$no++;
}
$pdf->Ln(4);
}
// =========================================================================
// PDF SECTION: Syarat & Ketentuan
// =========================================================================
private function _pdf_terms()
{
$pdf = $this->_pdf;
$pageW = $this->_pageW;
$terms = array(
'Barang yang dikirimkan harus diperiksa kesesuaiannya dengan fisik sebelum ditandatangani oleh penerima.',
'Segala klaim kerusakan atau kekurangan barang setelah serah terima menjadi tanggung jawab penerima barang.',
'Surat jalan ini harus dikembalikan ke bagian logistik pengirim setelah ditandatangani oleh penerima.',
'Dokumen ini merupakan bukti sah serah terima barang antar cabang.'
);
$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

@@ -1,272 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>FAQ</title>
<link type="text/css" rel="stylesheet" href="fpdf.css">
<style type="text/css">
ul {list-style-type:none; margin:0; padding:0}
ul#answers li {margin-top:1.8em}
.question {font-weight:bold; color:#900000}
</style>
</head>
<body>
<h1>FAQ</h1>
<ul>
<li><b>1.</b> <a href='#q1'>What's exactly the license of FPDF? Are there any usage restrictions?</a></li>
<li><b>2.</b> <a href='#q2'>I get the following error when I try to generate a PDF: Some data has already been output, can't send PDF file</a></li>
<li><b>3.</b> <a href='#q3'>Accented letters are replaced with some strange characters like é.</a></li>
<li><b>4.</b> <a href='#q4'>I try to display the Euro symbol but it doesn't work.</a></li>
<li><b>5.</b> <a href='#q5'>I try to display a variable in the Header method but nothing prints.</a></li>
<li><b>6.</b> <a href='#q6'>I have defined the Header and Footer methods in my PDF class but nothing shows.</a></li>
<li><b>7.</b> <a href='#q7'>I can't make line breaks work. I put \n in the string printed by MultiCell but it doesn't work.</a></li>
<li><b>8.</b> <a href='#q8'>I use jQuery to generate the PDF but it doesn't show.</a></li>
<li><b>9.</b> <a href='#q9'>I draw a frame with very precise dimensions, but when printed I notice some differences.</a></li>
<li><b>10.</b> <a href='#q10'>I'd like to use the whole surface of the page, but when printed I always have some margins. How can I get rid of them?</a></li>
<li><b>11.</b> <a href='#q11'>How can I put a background in my PDF?</a></li>
<li><b>12.</b> <a href='#q12'>How can I set a specific header or footer on the first page?</a></li>
<li><b>13.</b> <a href='#q13'>I'd like to use extensions provided by different scripts. How can I combine them?</a></li>
<li><b>14.</b> <a href='#q14'>How can I open the PDF in a new tab?</a></li>
<li><b>15.</b> <a href='#q15'>How can I send the PDF by email?</a></li>
<li><b>16.</b> <a href='#q16'>What's the limit of the file sizes I can generate with FPDF?</a></li>
<li><b>17.</b> <a href='#q17'>Can I modify a PDF with FPDF?</a></li>
<li><b>18.</b> <a href='#q18'>I'd like to make a search engine in PHP and index PDF files. Can I do it with FPDF?</a></li>
<li><b>19.</b> <a href='#q19'>Can I convert an HTML page to PDF with FPDF?</a></li>
<li><b>20.</b> <a href='#q20'>Can I concatenate PDF files with FPDF?</a></li>
</ul>
<ul id='answers'>
<li id='q1'>
<p><b>1.</b> <span class='question'>What's exactly the license of FPDF? Are there any usage restrictions?</span></p>
FPDF is released under a permissive license: there is no usage restriction. You may embed it
freely in your application (commercial or not), with or without modifications.
</li>
<li id='q2'>
<p><b>2.</b> <span class='question'>I get the following error when I try to generate a PDF: Some data has already been output, can't send PDF file</span></p>
You must send nothing to the browser except the PDF itself: no HTML, no space, no carriage return. A common
case is having extra blank at the end of an included script file.<br>
If you can't figure out where the problem comes from, this other message appearing just before can help you:<br>
<br>
<b>Warning:</b> Cannot modify header information - headers already sent by (output started at script.php:X)<br>
<br>
It means that script.php outputs something at line X. Go to this line and fix it.
In case the message doesn't show, first check that you didn't disable warnings, then add this at the very
beginning of your script:
<div class="doc-source">
<pre><code>ob_end_clean();</code></pre>
</div>
If you still don't see it, disable zlib.output_compression in your php.ini and it should appear.
</li>
<li id='q3'>
<p><b>3.</b> <span class='question'>Accented letters are replaced with some strange characters like é.</span></p>
Don't use UTF-8 with the standard fonts; they expect text encoded in ISO-8859-1 or windows-1252.
You can use utf8_decode() to perform a conversion to ISO-8859-1:
<div class="doc-source">
<pre><code>$str = utf8_decode($str);</code></pre>
</div>
But some characters such as Euro won't be translated correctly. If the iconv extension is available, the
right way to do it is the following:
<div class="doc-source">
<pre><code>$str = iconv('UTF-8', 'windows-1252', $str);</code></pre>
</div>
In case you need characters outside windows-1252, take a look at tutorial #7 or
<a href="http://www.fpdf.org/?go=script&amp;id=92" target="_blank">tFPDF</a>.
</li>
<li id='q4'>
<p><b>4.</b> <span class='question'>I try to display the Euro symbol but it doesn't work.</span></p>
The standard fonts have the Euro character at position 128. You can define a constant like this
for convenience:
<div class="doc-source">
<pre><code>define('EURO', chr(128));</code></pre>
</div>
</li>
<li id='q5'>
<p><b>5.</b> <span class='question'>I try to display a variable in the Header method but nothing prints.</span></p>
You have to use the <code>global</code> keyword to access global variables, for example:
<div class="doc-source">
<pre><code>function Header()
{
global $title;
$this-&gt;SetFont('Arial', 'B', 15);
$this-&gt;Cell(0, 10, $title, 1, 1, 'C');
}
$title = 'My title';</code></pre>
</div>
Alternatively, you can use an object property:
<div class="doc-source">
<pre><code>function Header()
{
$this-&gt;SetFont('Arial', 'B', 15);
$this-&gt;Cell(0, 10, $this-&gt;title, 1, 1, 'C');
}
$pdf-&gt;title = 'My title';</code></pre>
</div>
</li>
<li id='q6'>
<p><b>6.</b> <span class='question'>I have defined the Header and Footer methods in my PDF class but nothing shows.</span></p>
You have to create an object from the PDF class, not FPDF:
<div class="doc-source">
<pre><code>$pdf = new PDF();</code></pre>
</div>
</li>
<li id='q7'>
<p><b>7.</b> <span class='question'>I can't make line breaks work. I put \n in the string printed by MultiCell but it doesn't work.</span></p>
You have to enclose your string with double quotes, not single ones.
</li>
<li id='q8'>
<p><b>8.</b> <span class='question'>I use jQuery to generate the PDF but it doesn't show.</span></p>
Don't use an AJAX request to retrieve the PDF.
</li>
<li id='q9'>
<p><b>9.</b> <span class='question'>I draw a frame with very precise dimensions, but when printed I notice some differences.</span></p>
To respect dimensions, select "None" for the Page Scaling setting instead of "Shrink to Printable Area" in the print dialog box.
</li>
<li id='q10'>
<p><b>10.</b> <span class='question'>I'd like to use the whole surface of the page, but when printed I always have some margins. How can I get rid of them?</span></p>
Printers have physical margins (different depending on the models); it is therefore impossible to remove
them and print on the whole surface of the paper.
</li>
<li id='q11'>
<p><b>11.</b> <span class='question'>How can I put a background in my PDF?</span></p>
For a picture, call Image() in the Header() method, before any other output. To set a background color, use Rect().
</li>
<li id='q12'>
<p><b>12.</b> <span class='question'>How can I set a specific header or footer on the first page?</span></p>
Just test the page number:
<div class="doc-source">
<pre><code>function Header()
{
if($this-&gt;PageNo()==1)
{
//First page
...
}
else
{
//Other pages
...
}
}</code></pre>
</div>
</li>
<li id='q13'>
<p><b>13.</b> <span class='question'>I'd like to use extensions provided by different scripts. How can I combine them?</span></p>
Use an inheritance chain. If you have two classes, say A in a.php:
<div class="doc-source">
<pre><code>require('fpdf.php');
class A extends FPDF
{
...
}</code></pre>
</div>
and B in b.php:
<div class="doc-source">
<pre><code>require('fpdf.php');
class B extends FPDF
{
...
}</code></pre>
</div>
then make B extend A:
<div class="doc-source">
<pre><code>require('a.php');
class B extends A
{
...
}</code></pre>
</div>
and make your own class extend B:
<div class="doc-source">
<pre><code>require('b.php');
class PDF extends B
{
...
}
$pdf = new PDF();</code></pre>
</div>
</li>
<li id='q14'>
<p><b>14.</b> <span class='question'>How can I open the PDF in a new tab?</span></p>
Just do the same as you would for an HTML page or anything else: add a target="_blank" to your link or form.
</li>
<li id='q15'>
<p><b>15.</b> <span class='question'>How can I send the PDF by email?</span></p>
As for any other file, but an easy way is to use <a href="https://github.com/PHPMailer/PHPMailer" target="_blank">PHPMailer</a> and
its in-memory attachment:
<div class="doc-source">
<pre><code>$mail = new PHPMailer();
...
$doc = $pdf-&gt;Output('S');
$mail-&gt;AddStringAttachment($doc, 'doc.pdf', 'base64', 'application/pdf');
$mail-&gt;Send();</code></pre>
</div>
</li>
<li id='q16'>
<p><b>16.</b> <span class='question'>What's the limit of the file sizes I can generate with FPDF?</span></p>
There is no particular limit. There are some constraints, however:
<br>
<br>
- There is usually a maximum memory size allocated to PHP scripts. For very big documents,
especially with images, the limit may be reached (the file being built in memory). The
parameter is configured in the php.ini file.
<br>
<br>
- The maximum execution time allocated to scripts defaults to 30 seconds. This limit can of course
be easily reached. It is configured in php.ini and may be altered dynamically with set_time_limit().
<br>
<br>
You can work around the memory limit with <a href="http://www.fpdf.org/?go=script&amp;id=76" target="_blank">this script</a>.
</li>
<li id='q17'>
<p><b>17.</b> <span class='question'>Can I modify a PDF with FPDF?</span></p>
It's possible to import pages from an existing PDF document thanks to the
<a href="https://www.setasign.com/products/fpdi/about/" target="_blank">FPDI</a> extension.
Then you can add some content to them.
</li>
<li id='q18'>
<p><b>18.</b> <span class='question'>I'd like to make a search engine in PHP and index PDF files. Can I do it with FPDF?</span></p>
No. But a GPL C utility does exist, pdftotext, which is able to extract the textual content from a PDF.
It's provided with the <a href="https://www.xpdfreader.com" target="_blank">Xpdf</a> package.
</li>
<li id='q19'>
<p><b>19.</b> <span class='question'>Can I convert an HTML page to PDF with FPDF?</span></p>
Not real-world pages. But a GPL C utility does exist, <a href="https://www.msweet.org/htmldoc/" target="_blank">HTMLDOC</a>,
which allows to do it and gives good results.
</li>
<li id='q20'>
<p><b>20.</b> <span class='question'>Can I concatenate PDF files with FPDF?</span></p>
Not directly, but it's possible to use <a href="https://www.setasign.com/products/fpdi/demos/concatenate-fake/" target="_blank">FPDI</a>
to perform that task. Some free command-line tools also exist:
<a href="https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/" target="_blank">pdftk</a> and
<a href="http://thierry.schmit.free.fr/spip/spip.php?article15" target="_blank">mbtPdfAsm</a>.
</li>
</ul>
</body>
</html>

View File

@@ -1,167 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Changelog</title>
<link type="text/css" rel="stylesheet" href="fpdf.css">
<style type="text/css">
dd {margin:1em 0 1em 1em}
</style>
</head>
<body>
<h1>Changelog</h1>
<dl>
<dt><strong>v1.82</strong> (2019-12-07)</dt>
<dd>
- Removed a deprecation notice under PHP 7.4.<br>
</dd>
<dt><strong>v1.81</strong> (2015-12-20)</dt>
<dd>
- Added GetPageWidth() and GetPageHeight().<br>
- Fixed a bug in SetXY().<br>
</dd>
<dt><strong>v1.8</strong> (2015-11-29)</dt>
<dd>
- PHP 5.1.0 or higher is now required.<br>
- The MakeFont utility now subsets fonts, which can greatly reduce font sizes.<br>
- Added ToUnicode CMaps to improve text extraction.<br>
- Added a parameter to AddPage() to rotate the page.<br>
- Added a parameter to SetY() to indicate whether the x position should be reset or not.<br>
- Added a parameter to Output() to specify the encoding of the name, and special characters are now properly encoded. Additionally the order of the first two parameters was reversed to be more logical (however the old order is still supported for compatibility).<br>
- The Error() method now throws an exception.<br>
- Adding contents before the first AddPage() or after Close() now raises an error.<br>
- Outputting text with no font selected now raises an error.<br>
</dd>
<dt><strong>v1.7</strong> (2011-06-18)</dt>
<dd>
- The MakeFont utility has been completely rewritten and doesn't depend on ttf2pt1 anymore.<br>
- Alpha channel is now supported for PNGs.<br>
- When inserting an image, it's now possible to specify its resolution.<br>
- Default resolution for images was increased from 72 to 96 dpi.<br>
- When inserting a GIF image, no temporary file is used anymore if the PHP version is 5.1 or higher.<br>
- When output buffering is enabled and the PDF is about to be sent, the buffer is now cleared if it contains only a UTF-8 BOM and/or whitespace (instead of throwing an error).<br>
- Symbol and ZapfDingbats fonts now support underline style.<br>
- Custom page sizes are now checked to ensure that width is smaller than height.<br>
- Standard font files were changed to use the same format as user fonts.<br>
- A bug in the embedding of Type1 fonts was fixed.<br>
- A bug related to SetDisplayMode() and the current locale was fixed.<br>
- A display issue occurring with the Adobe Reader X plug-in was fixed.<br>
- An issue related to transparency with some versions of Adobe Reader was fixed.<br>
- The Content-Length header was removed because it caused an issue when the HTTP server applies compression.<br>
</dd>
<dt><strong>v1.6</strong> (2008-08-03)</dt>
<dd>
- PHP 4.3.10 or higher is now required.<br>
- GIF image support.<br>
- Images can now trigger page breaks.<br>
- Possibility to have different page formats in a single document.<br>
- Document properties (author, creator, keywords, subject and title) can now be specified in UTF-8.<br>
- Fixed a bug: when a PNG was inserted through a URL, an error sometimes occurred.<br>
- An automatic page break in Header() doesn't cause an infinite loop any more.<br>
- Removed some warning messages appearing with recent PHP versions.<br>
- Added HTTP headers to reduce problems with IE.<br>
</dd>
<dt><strong>v1.53</strong> (2004-12-31)</dt>
<dd>
- When the font subdirectory is in the same directory as fpdf.php, it's no longer necessary to define the FPDF_FONTPATH constant.<br>
- The array $HTTP_SERVER_VARS is no longer used. It could cause trouble on PHP5-based configurations with the register_long_arrays option disabled.<br>
- Fixed a problem related to Type1 font embedding which caused trouble to some PDF processors.<br>
- The file name sent to the browser could not contain a space character.<br>
- The Cell() method could not print the number 0 (you had to pass the string '0').<br>
</dd>
<dt><strong>v1.52</strong> (2003-12-30)</dt>
<dd>
- Image() now displays the image at 72 dpi if no dimension is given.<br>
- Output() takes a string as second parameter to indicate destination.<br>
- Open() is now called automatically by AddPage().<br>
- Inserting remote JPEG images doesn't generate an error any longer.<br>
- Decimal separator is forced to dot in the constructor.<br>
- Added several encodings (Turkish, Thai, Hebrew, Ukrainian and Vietnamese).<br>
- The last line of a right-aligned MultiCell() was not correctly aligned if it was terminated by a carriage return.<br>
- No more error message about already sent headers when outputting the PDF to the standard output from the command line.<br>
- The underlining was going too far for text containing characters \, ( or ).<br>
- $HTTP_ENV_VARS has been replaced by $HTTP_SERVER_VARS.<br>
</dd>
<dt><strong>v1.51</strong> (2002-08-03)</dt>
<dd>
- Type1 font support.<br>
- Added Baltic encoding.<br>
- The class now works internally in points with the origin at the bottom in order to avoid two bugs occurring with Acrobat 5:<br>&nbsp;&nbsp;* The line thickness was too large when printed under Windows 98 SE and ME.<br>&nbsp;&nbsp;* TrueType fonts didn't appear immediately inside the plug-in (a substitution font was used), one had to cause a window refresh to make them show up.<br>
- It's no longer necessary to set the decimal separator as dot to produce valid documents.<br>
- The clickable area in a cell was always on the left independently from the text alignment.<br>
- JPEG images in CMYK mode appeared in inverted colors.<br>
- Transparent PNG images in grayscale or true color mode were incorrectly handled.<br>
- Adding new fonts now works correctly even with the magic_quotes_runtime option set to on.<br>
</dd>
<dt><strong>v1.5</strong> (2002-05-28)</dt>
<dd>
- TrueType font (AddFont()) and encoding support (Western and Eastern Europe, Cyrillic and Greek).<br>
- Added Write() method.<br>
- Added underlined style.<br>
- Internal and external link support (AddLink(), SetLink(), Link()).<br>
- Added right margin management and methods SetRightMargin(), SetTopMargin().<br>
- Modification of SetDisplayMode() to select page layout.<br>
- The border parameter of MultiCell() now lets choose borders to draw as Cell().<br>
- When a document contains no page, Close() now calls AddPage() instead of causing a fatal error.<br>
</dd>
<dt><strong>v1.41</strong> (2002-03-13)</dt>
<dd>
- Fixed SetDisplayMode() which no longer worked (the PDF viewer used its default display).<br>
</dd>
<dt><strong>v1.4</strong> (2002-03-02)</dt>
<dd>
- PHP3 is no longer supported.<br>
- Page compression (SetCompression()).<br>
- Choice of page format and possibility to change orientation inside document.<br>
- Added AcceptPageBreak() method.<br>
- Ability to print the total number of pages (AliasNbPages()).<br>
- Choice of cell borders to draw.<br>
- New mode for Cell(): the current position can now move under the cell.<br>
- Ability to include an image by specifying height only (width is calculated automatically).<br>
- Fixed a bug: when a justified line triggered a page break, the footer inherited the corresponding word spacing.<br>
</dd>
<dt><strong>v1.31</strong> (2002-01-12)</dt>
<dd>
- Fixed a bug in drawing frame with MultiCell(): the last line always started from the left margin.<br>
- Removed Expires HTTP header (gives trouble in some situations).<br>
- Added Content-disposition HTTP header (seems to help in some situations).<br>
</dd>
<dt><strong>v1.3</strong> (2001-12-03)</dt>
<dd>
- Line break and text justification support (MultiCell()).<br>
- Color support (SetDrawColor(), SetFillColor(), SetTextColor()). Possibility to draw filled rectangles and paint cell background.<br>
- A cell whose width is declared null extends up to the right margin of the page.<br>
- Line width is now retained from page to page and defaults to 0.2 mm.<br>
- Added SetXY() method.<br>
- Fixed a passing by reference done in a deprecated manner for PHP4.<br>
</dd>
<dt><strong>v1.2</strong> (2001-11-11)</dt>
<dd>
- Added font metric files and GetStringWidth() method.<br>
- Centering and right-aligning text in cells.<br>
- Display mode control (SetDisplayMode()).<br>
- Added methods to set document properties (SetAuthor(), SetCreator(), SetKeywords(), SetSubject(), SetTitle()).<br>
- Possibility to force PDF download by browser.<br>
- Added SetX() and GetX() methods.<br>
- During automatic page break, current abscissa is now retained.<br>
</dd>
<dt><strong>v1.11</strong> (2001-10-20)</dt>
<dd>
- PNG support doesn't require PHP4/zlib any more. Data are now put directly into PDF without any decompression/recompression stage.<br>
- Image insertion now works correctly even with magic_quotes_runtime option set to on.<br>
</dd>
<dt><strong>v1.1</strong> (2001-10-07)</dt>
<dd>
- JPEG and PNG image support.<br>
</dd>
<dt><strong>v1.01</strong> (2001-10-03)</dt>
<dd>
- Fixed a bug involving page break: in case when Header() doesn't specify a font, the one from previous page was not restored and produced an incorrect document.<br>
</dd>
<dt><strong>v1.0</strong> (2001-09-17)</dt>
<dd>
- First version.<br>
</dd>
</dl>
</body>
</html>

View File

@@ -1,63 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>__construct</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>__construct</h1>
<code>__construct([<b>string</b> orientation [, <b>string</b> unit [, <b>mixed</b> size]]])</code>
<h2>Description</h2>
This is the class constructor. It allows to set up the page size, the orientation and the
unit of measure used in all methods (except for font sizes).
<h2>Parameters</h2>
<dl class="param">
<dt><code>orientation</code></dt>
<dd>
Default page orientation. Possible values are (case insensitive):
<ul>
<li><code>P</code> or <code>Portrait</code></li>
<li><code>L</code> or <code>Landscape</code></li>
</ul>
Default value is <code>P</code>.
</dd>
<dt><code>unit</code></dt>
<dd>
User unit. Possible values are:
<ul>
<li><code>pt</code>: point</li>
<li><code>mm</code>: millimeter</li>
<li><code>cm</code>: centimeter</li>
<li><code>in</code>: inch</li>
</ul>
A point equals 1/72 of inch, that is to say about 0.35 mm (an inch being 2.54 cm). This
is a very common unit in typography; font sizes are expressed in that unit.
<br>
<br>
Default value is <code>mm</code>.
</dd>
<dt><code>size</code></dt>
<dd>
The size used for pages. It can be either one of the following values (case insensitive):
<ul>
<li><code>A3</code></li>
<li><code>A4</code></li>
<li><code>A5</code></li>
<li><code>Letter</code></li>
<li><code>Legal</code></li>
</ul>
or an array containing the width and the height (expressed in the unit given by <code>unit</code>).<br>
<br>
Default value is <code>A4</code>.
</dd>
</dl>
<h2>Example</h2>
Example with a custom 100x150 mm page size:
<div class="doc-source">
<pre><code>$pdf = new FPDF('P','mm',array(100,150));</code></pre>
</div>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,63 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>AcceptPageBreak</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>AcceptPageBreak</h1>
<code><b>boolean</b> AcceptPageBreak()</code>
<h2>Description</h2>
Whenever a page break condition is met, the method is called, and the break is issued or not
depending on the returned value. The default implementation returns a value according to the
mode selected by SetAutoPageBreak().
<br>
This method is called automatically and should not be called directly by the application.
<h2>Example</h2>
The method is overriden in an inherited class in order to obtain a 3 column layout:
<div class="doc-source">
<pre><code>class PDF extends FPDF
{
var $col = 0;
function SetCol($col)
{
// Move position to a column
$this-&gt;col = $col;
$x = 10+$col*65;
$this-&gt;SetLeftMargin($x);
$this-&gt;SetX($x);
}
function AcceptPageBreak()
{
if($this-&gt;col&lt;2)
{
// Go to next column
$this-&gt;SetCol($this-&gt;col+1);
$this-&gt;SetY(10);
return false;
}
else
{
// Go back to first column and issue page break
$this-&gt;SetCol(0);
return true;
}
}
}
$pdf = new PDF();
$pdf-&gt;AddPage();
$pdf-&gt;SetFont('Arial','',12);
for($i=1;$i&lt;=300;$i++)
$pdf-&gt;Cell(0,5,"Line $i",0,1);
$pdf-&gt;Output();</code></pre>
</div>
<h2>See also</h2>
<a href="setautopagebreak.htm">SetAutoPageBreak</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,55 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>AddFont</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>AddFont</h1>
<code>AddFont(<b>string</b> family [, <b>string</b> style [, <b>string</b> file]])</code>
<h2>Description</h2>
Imports a TrueType, OpenType or Type1 font and makes it available. It is necessary to generate a font
definition file first with the MakeFont utility.
<br>
The definition file (and the font file itself when embedding) must be present in the font directory.
If it is not found, the error "Could not include font definition file" is raised.
<h2>Parameters</h2>
<dl class="param">
<dt><code>family</code></dt>
<dd>
Font family. The name can be chosen arbitrarily. If it is a standard family name, it will
override the corresponding font.
</dd>
<dt><code>style</code></dt>
<dd>
Font style. Possible values are (case insensitive):
<ul>
<li>empty string: regular</li>
<li><code>B</code>: bold</li>
<li><code>I</code>: italic</li>
<li><code>BI</code> or <code>IB</code>: bold italic</li>
</ul>
The default value is regular.
</dd>
<dt><code>file</code></dt>
<dd>
The font definition file.
<br>
By default, the name is built from the family and style, in lower case with no space.
</dd>
</dl>
<h2>Example</h2>
<div class="doc-source">
<pre><code>$pdf-&gt;AddFont('Comic','I');</code></pre>
</div>
is equivalent to:
<div class="doc-source">
<pre><code>$pdf-&gt;AddFont('Comic','I','comici.php');</code></pre>
</div>
<h2>See also</h2>
<a href="setfont.htm">SetFont</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,26 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>AddLink</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>AddLink</h1>
<code><b>int</b> AddLink()</code>
<h2>Description</h2>
Creates a new internal link and returns its identifier. An internal link is a clickable area
which directs to another place within the document.
<br>
The identifier can then be passed to Cell(), Write(), Image() or Link(). The destination is
defined with SetLink().
<h2>See also</h2>
<a href="cell.htm">Cell</a>,
<a href="write.htm">Write</a>,
<a href="image.htm">Image</a>,
<a href="link.htm">Link</a>,
<a href="setlink.htm">SetLink</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,61 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>AddPage</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>AddPage</h1>
<code>AddPage([<b>string</b> orientation [, <b>mixed</b> size [, <b>int</b> rotation]]])</code>
<h2>Description</h2>
Adds a new page to the document. If a page is already present, the Footer() method is called
first to output the footer. Then the page is added, the current position set to the top-left
corner according to the left and top margins, and Header() is called to display the header.
<br>
The font which was set before calling is automatically restored. There is no need to call
SetFont() again if you want to continue with the same font. The same is true for colors and
line width.
<br>
The origin of the coordinate system is at the top-left corner and increasing ordinates go
downwards.
<h2>Parameters</h2>
<dl class="param">
<dt><code>orientation</code></dt>
<dd>
Page orientation. Possible values are (case insensitive):
<ul>
<li><code>P</code> or <code>Portrait</code></li>
<li><code>L</code> or <code>Landscape</code></li>
</ul>
The default value is the one passed to the constructor.
</dd>
<dt><code>size</code></dt>
<dd>
Page size. It can be either one of the following values (case insensitive):
<ul>
<li><code>A3</code></li>
<li><code>A4</code></li>
<li><code>A5</code></li>
<li><code>Letter</code></li>
<li><code>Legal</code></li>
</ul>
or an array containing the width and the height (expressed in user unit).<br>
<br>
The default value is the one passed to the constructor.
</dd>
<dt><code>rotation</code></dt>
<dd>
Angle by which to rotate the page. It must be a multiple of 90; positive values
mean clockwise rotation. The default value is <code>0</code>.
</dd>
</dl>
<h2>See also</h2>
<a href="__construct.htm">__construct</a>,
<a href="header.htm">Header</a>,
<a href="footer.htm">Footer</a>,
<a href="setmargins.htm">SetMargins</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,45 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>AliasNbPages</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>AliasNbPages</h1>
<code>AliasNbPages([<b>string</b> alias])</code>
<h2>Description</h2>
Defines an alias for the total number of pages. It will be substituted as the document is
closed.
<h2>Parameters</h2>
<dl class="param">
<dt><code>alias</code></dt>
<dd>
The alias. Default value: <code>{nb}</code>.
</dd>
</dl>
<h2>Example</h2>
<div class="doc-source">
<pre><code>class PDF extends FPDF
{
function Footer()
{
// Go to 1.5 cm from bottom
$this-&gt;SetY(-15);
// Select Arial italic 8
$this-&gt;SetFont('Arial','I',8);
// Print current and total page numbers
$this-&gt;Cell(0,10,'Page '.$this-&gt;PageNo().'/{nb}',0,0,'C');
}
}
$pdf = new PDF();
$pdf-&gt;AliasNbPages();</code></pre>
</div>
<h2>See also</h2>
<a href="pageno.htm">PageNo</a>,
<a href="footer.htm">Footer</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,104 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Cell</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>Cell</h1>
<code>Cell(<b>float</b> w [, <b>float</b> h [, <b>string</b> txt [, <b>mixed</b> border [, <b>int</b> ln [, <b>string</b> align [, <b>boolean</b> fill [, <b>mixed</b> link]]]]]]])</code>
<h2>Description</h2>
Prints a cell (rectangular area) with optional borders, background color and character string.
The upper-left corner of the cell corresponds to the current position. The text can be aligned
or centered. After the call, the current position moves to the right or to the next line. It is
possible to put a link on the text.
<br>
If automatic page breaking is enabled and the cell goes beyond the limit, a page break is
done before outputting.
<h2>Parameters</h2>
<dl class="param">
<dt><code>w</code></dt>
<dd>
Cell width. If <code>0</code>, the cell extends up to the right margin.
</dd>
<dt><code>h</code></dt>
<dd>
Cell height.
Default value: <code>0</code>.
</dd>
<dt><code>txt</code></dt>
<dd>
String to print.
Default value: empty string.
</dd>
<dt><code>border</code></dt>
<dd>
Indicates if borders must be drawn around the cell. The value can be either a number:
<ul>
<li><code>0</code>: no border</li>
<li><code>1</code>: frame</li>
</ul>
or a string containing some or all of the following characters (in any order):
<ul>
<li><code>L</code>: left</li>
<li><code>T</code>: top</li>
<li><code>R</code>: right</li>
<li><code>B</code>: bottom</li>
</ul>
Default value: <code>0</code>.
</dd>
<dt><code>ln</code></dt>
<dd>
Indicates where the current position should go after the call. Possible values are:
<ul>
<li><code>0</code>: to the right</li>
<li><code>1</code>: to the beginning of the next line</li>
<li><code>2</code>: below</li>
</ul>
Putting <code>1</code> is equivalent to putting <code>0</code> and calling Ln() just after.
Default value: <code>0</code>.
</dd>
<dt><code>align</code></dt>
<dd>
Allows to center or align the text. Possible values are:
<ul>
<li><code>L</code> or empty string: left align (default value)</li>
<li><code>C</code>: center</li>
<li><code>R</code>: right align</li>
</ul>
</dd>
<dt><code>fill</code></dt>
<dd>
Indicates if the cell background must be painted (<code>true</code>) or transparent (<code>false</code>).
Default value: <code>false</code>.
</dd>
<dt><code>link</code></dt>
<dd>
URL or identifier returned by AddLink().
</dd>
</dl>
<h2>Example</h2>
<div class="doc-source">
<pre><code>// Set font
$pdf-&gt;SetFont('Arial','B',16);
// Move to 8 cm to the right
$pdf-&gt;Cell(80);
// Centered text in a framed 20*10 mm cell and line break
$pdf-&gt;Cell(20,10,'Title',1,1,'C');</code></pre>
</div>
<h2>See also</h2>
<a href="setfont.htm">SetFont</a>,
<a href="setdrawcolor.htm">SetDrawColor</a>,
<a href="setfillcolor.htm">SetFillColor</a>,
<a href="settextcolor.htm">SetTextColor</a>,
<a href="setlinewidth.htm">SetLineWidth</a>,
<a href="addlink.htm">AddLink</a>,
<a href="ln.htm">Ln</a>,
<a href="multicell.htm">MultiCell</a>,
<a href="write.htm">Write</a>,
<a href="setautopagebreak.htm">SetAutoPageBreak</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,21 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Close</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>Close</h1>
<code>Close()</code>
<h2>Description</h2>
Terminates the PDF document. It is not necessary to call this method explicitly because Output()
does it automatically.
<br>
If the document contains no page, AddPage() is called to prevent from getting an invalid document.
<h2>See also</h2>
<a href="output.htm">Output</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,26 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Error</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>Error</h1>
<code>Error(<b>string</b> msg)</code>
<h2>Description</h2>
This method is automatically called in case of a fatal error; it simply throws an exception
with the provided message.<br>
An inherited class may override it to customize the error handling but the method should
never return, otherwise the resulting document would probably be invalid.
<h2>Parameters</h2>
<dl class="param">
<dt><code>msg</code></dt>
<dd>
The error message.
</dd>
</dl>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,35 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Footer</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>Footer</h1>
<code>Footer()</code>
<h2>Description</h2>
This method is used to render the page footer. It is automatically called by AddPage() and
Close() and should not be called directly by the application. The implementation in FPDF is
empty, so you have to subclass it and override the method if you want a specific processing.
<h2>Example</h2>
<div class="doc-source">
<pre><code>class PDF extends FPDF
{
function Footer()
{
// Go to 1.5 cm from bottom
$this-&gt;SetY(-15);
// Select Arial italic 8
$this-&gt;SetFont('Arial','I',8);
// Print centered page number
$this-&gt;Cell(0,10,'Page '.$this-&gt;PageNo(),0,0,'C');
}
}</code></pre>
</div>
<h2>See also</h2>
<a href="header.htm">Header</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,18 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>GetPageHeight</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>GetPageHeight</h1>
<code><b>float</b> GetPageHeight()</code>
<h2>Description</h2>
Returns the current page height.
<h2>See also</h2>
<a href="getpagewidth.htm">GetPageWidth</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,18 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>GetPageWidth</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>GetPageWidth</h1>
<code><b>float</b> GetPageWidth()</code>
<h2>Description</h2>
Returns the current page width.
<h2>See also</h2>
<a href="getpageheight.htm">GetPageHeight</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,23 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>GetStringWidth</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>GetStringWidth</h1>
<code><b>float</b> GetStringWidth(<b>string</b> s)</code>
<h2>Description</h2>
Returns the length of a string in user unit. A font must be selected.
<h2>Parameters</h2>
<dl class="param">
<dt><code>s</code></dt>
<dd>
The string whose length is to be computed.
</dd>
</dl>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,20 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>GetX</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>GetX</h1>
<code><b>float</b> GetX()</code>
<h2>Description</h2>
Returns the abscissa of the current position.
<h2>See also</h2>
<a href="setx.htm">SetX</a>,
<a href="gety.htm">GetY</a>,
<a href="sety.htm">SetY</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,20 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>GetY</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>GetY</h1>
<code><b>float</b> GetY()</code>
<h2>Description</h2>
Returns the ordinate of the current position.
<h2>See also</h2>
<a href="sety.htm">SetY</a>,
<a href="getx.htm">GetX</a>,
<a href="setx.htm">SetX</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,37 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Header</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>Header</h1>
<code>Header()</code>
<h2>Description</h2>
This method is used to render the page header. It is automatically called by AddPage() and
should not be called directly by the application. The implementation in FPDF is empty, so
you have to subclass it and override the method if you want a specific processing.
<h2>Example</h2>
<div class="doc-source">
<pre><code>class PDF extends FPDF
{
function Header()
{
// Select Arial bold 15
$this-&gt;SetFont('Arial','B',15);
// Move to the right
$this-&gt;Cell(80);
// Framed title
$this-&gt;Cell(30,10,'Title',1,0,'C');
// Line break
$this-&gt;Ln(20);
}
}</code></pre>
</div>
<h2>See also</h2>
<a href="footer.htm">Footer</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,99 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Image</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>Image</h1>
<code>Image(<b>string</b> file [, <b>float</b> x [, <b>float</b> y [, <b>float</b> w [, <b>float</b> h [, <b>string</b> type [, <b>mixed</b> link]]]]]])</code>
<h2>Description</h2>
Puts an image. The size it will take on the page can be specified in different ways:
<ul>
<li>explicit width and height (expressed in user unit or dpi)</li>
<li>one explicit dimension, the other being calculated automatically in order to keep the original proportions</li>
<li>no explicit dimension, in which case the image is put at 96 dpi</li>
</ul>
Supported formats are JPEG, PNG and GIF. The GD extension is required for GIF.
<br>
<br>
For JPEGs, all flavors are allowed:
<ul>
<li>gray scales</li>
<li>true colors (24 bits)</li>
<li>CMYK (32 bits)</li>
</ul>
For PNGs, are allowed:
<ul>
<li>gray scales on at most 8 bits (256 levels)</li>
<li>indexed colors</li>
<li>true colors (24 bits)</li>
</ul>
For GIFs: in case of an animated GIF, only the first frame is displayed.<br>
<br>
Transparency is supported.<br>
<br>
The format can be specified explicitly or inferred from the file extension.<br>
<br>
It is possible to put a link on the image.<br>
<br>
Remark: if an image is used several times, only one copy is embedded in the file.
<h2>Parameters</h2>
<dl class="param">
<dt><code>file</code></dt>
<dd>
Path or URL of the image.
</dd>
<dt><code>x</code></dt>
<dd>
Abscissa of the upper-left corner. If not specified or equal to <code>null</code>, the current abscissa
is used.
</dd>
<dt><code>y</code></dt>
<dd>
Ordinate of the upper-left corner. If not specified or equal to <code>null</code>, the current ordinate
is used; moreover, a page break is triggered first if necessary (in case automatic page breaking is enabled)
and, after the call, the current ordinate is moved to the bottom of the image.
</dd>
<dt><code>w</code></dt>
<dd>
Width of the image in the page. There are three cases:
<ul>
<li>If the value is positive, it represents the width in user unit</li>
<li>If the value is negative, the absolute value represents the horizontal resolution in dpi</li>
<li>If the value is not specified or equal to zero, it is automatically calculated</li>
</ul>
</dd>
<dt><code>h</code></dt>
<dd>
Height of the image in the page. There are three cases:
<ul>
<li>If the value is positive, it represents the height in user unit</li>
<li>If the value is negative, the absolute value represents the vertical resolution in dpi</li>
<li>If the value is not specified or equal to zero, it is automatically calculated</li>
</ul>
</dd>
<dt><code>type</code></dt>
<dd>
Image format. Possible values are (case insensitive): <code>JPG</code>, <code>JPEG</code>, <code>PNG</code> and <code>GIF</code>.
If not specified, the type is inferred from the file extension.
</dd>
<dt><code>link</code></dt>
<dd>
URL or identifier returned by AddLink().
</dd>
</dl>
<h2>Example</h2>
<div class="doc-source">
<pre><code>// Insert a logo in the top-left corner at 300 dpi
$pdf-&gt;Image('logo.png',10,10,-300);
// Insert a dynamic image from a URL
$pdf-&gt;Image('http://chart.googleapis.com/chart?cht=p3&amp;chd=t:60,40&amp;chs=250x100&amp;chl=Hello|World',60,30,90,0,'PNG');</code></pre>
</div>
<h2>See also</h2>
<a href="addlink.htm">AddLink</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,59 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>FPDF 1.82 Reference Manual</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>FPDF 1.82 Reference Manual</h1>
<a href="__construct.htm">__construct</a> - constructor<br>
<a href="acceptpagebreak.htm">AcceptPageBreak</a> - accept or not automatic page break<br>
<a href="addfont.htm">AddFont</a> - add a new font<br>
<a href="addlink.htm">AddLink</a> - create an internal link<br>
<a href="addpage.htm">AddPage</a> - add a new page<br>
<a href="aliasnbpages.htm">AliasNbPages</a> - define an alias for number of pages<br>
<a href="cell.htm">Cell</a> - print a cell<br>
<a href="close.htm">Close</a> - terminate the document<br>
<a href="error.htm">Error</a> - fatal error<br>
<a href="footer.htm">Footer</a> - page footer<br>
<a href="getpageheight.htm">GetPageHeight</a> - get current page height<br>
<a href="getpagewidth.htm">GetPageWidth</a> - get current page width<br>
<a href="getstringwidth.htm">GetStringWidth</a> - compute string length<br>
<a href="getx.htm">GetX</a> - get current x position<br>
<a href="gety.htm">GetY</a> - get current y position<br>
<a href="header.htm">Header</a> - page header<br>
<a href="image.htm">Image</a> - output an image<br>
<a href="line.htm">Line</a> - draw a line<br>
<a href="link.htm">Link</a> - put a link<br>
<a href="ln.htm">Ln</a> - line break<br>
<a href="multicell.htm">MultiCell</a> - print text with line breaks<br>
<a href="output.htm">Output</a> - save or send the document<br>
<a href="pageno.htm">PageNo</a> - page number<br>
<a href="rect.htm">Rect</a> - draw a rectangle<br>
<a href="setauthor.htm">SetAuthor</a> - set the document author<br>
<a href="setautopagebreak.htm">SetAutoPageBreak</a> - set the automatic page breaking mode<br>
<a href="setcompression.htm">SetCompression</a> - turn compression on or off<br>
<a href="setcreator.htm">SetCreator</a> - set document creator<br>
<a href="setdisplaymode.htm">SetDisplayMode</a> - set display mode<br>
<a href="setdrawcolor.htm">SetDrawColor</a> - set drawing color<br>
<a href="setfillcolor.htm">SetFillColor</a> - set filling color<br>
<a href="setfont.htm">SetFont</a> - set font<br>
<a href="setfontsize.htm">SetFontSize</a> - set font size<br>
<a href="setkeywords.htm">SetKeywords</a> - associate keywords with document<br>
<a href="setleftmargin.htm">SetLeftMargin</a> - set left margin<br>
<a href="setlinewidth.htm">SetLineWidth</a> - set line width<br>
<a href="setlink.htm">SetLink</a> - set internal link destination<br>
<a href="setmargins.htm">SetMargins</a> - set margins<br>
<a href="setrightmargin.htm">SetRightMargin</a> - set right margin<br>
<a href="setsubject.htm">SetSubject</a> - set document subject<br>
<a href="settextcolor.htm">SetTextColor</a> - set text color<br>
<a href="settitle.htm">SetTitle</a> - set document title<br>
<a href="settopmargin.htm">SetTopMargin</a> - set top margin<br>
<a href="setx.htm">SetX</a> - set current x position<br>
<a href="setxy.htm">SetXY</a> - set current x and y positions<br>
<a href="sety.htm">SetY</a> - set current y position and optionally reset x<br>
<a href="text.htm">Text</a> - print a string<br>
<a href="write.htm">Write</a> - print flowing text<br>
</body>
</html>

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Line</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>Line</h1>
<code>Line(<b>float</b> x1, <b>float</b> y1, <b>float</b> x2, <b>float</b> y2)</code>
<h2>Description</h2>
Draws a line between two points.
<h2>Parameters</h2>
<dl class="param">
<dt><code>x1</code></dt>
<dd>
Abscissa of first point.
</dd>
<dt><code>y1</code></dt>
<dd>
Ordinate of first point.
</dd>
<dt><code>x2</code></dt>
<dd>
Abscissa of second point.
</dd>
<dt><code>y2</code></dt>
<dd>
Ordinate of second point.
</dd>
</dl>
<h2>See also</h2>
<a href="setlinewidth.htm">SetLineWidth</a>,
<a href="setdrawcolor.htm">SetDrawColor</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,46 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Link</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>Link</h1>
<code>Link(<b>float</b> x, <b>float</b> y, <b>float</b> w, <b>float</b> h, <b>mixed</b> link)</code>
<h2>Description</h2>
Puts a link on a rectangular area of the page. Text or image links are generally put via Cell(),
Write() or Image(), but this method can be useful for instance to define a clickable area inside
an image.
<h2>Parameters</h2>
<dl class="param">
<dt><code>x</code></dt>
<dd>
Abscissa of the upper-left corner of the rectangle.
</dd>
<dt><code>y</code></dt>
<dd>
Ordinate of the upper-left corner of the rectangle.
</dd>
<dt><code>w</code></dt>
<dd>
Width of the rectangle.
</dd>
<dt><code>h</code></dt>
<dd>
Height of the rectangle.
</dd>
<dt><code>link</code></dt>
<dd>
URL or identifier returned by AddLink().
</dd>
</dl>
<h2>See also</h2>
<a href="addlink.htm">AddLink</a>,
<a href="cell.htm">Cell</a>,
<a href="write.htm">Write</a>,
<a href="image.htm">Image</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,28 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Ln</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>Ln</h1>
<code>Ln([<b>float</b> h])</code>
<h2>Description</h2>
Performs a line break. The current abscissa goes back to the left margin and the ordinate
increases by the amount passed in parameter.
<h2>Parameters</h2>
<dl class="param">
<dt><code>h</code></dt>
<dd>
The height of the break.
<br>
By default, the value equals the height of the last printed cell.
</dd>
</dl>
<h2>See also</h2>
<a href="cell.htm">Cell</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,76 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>MultiCell</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>MultiCell</h1>
<code>MultiCell(<b>float</b> w, <b>float</b> h, <b>string</b> txt [, <b>mixed</b> border [, <b>string</b> align [, <b>boolean</b> fill]]])</code>
<h2>Description</h2>
This method allows printing text with line breaks. They can be automatic (as soon as the
text reaches the right border of the cell) or explicit (via the \n character). As many cells
as necessary are output, one below the other.
<br>
Text can be aligned, centered or justified. The cell block can be framed and the background
painted.
<h2>Parameters</h2>
<dl class="param">
<dt><code>w</code></dt>
<dd>
Width of cells. If <code>0</code>, they extend up to the right margin of the page.
</dd>
<dt><code>h</code></dt>
<dd>
Height of cells.
</dd>
<dt><code>txt</code></dt>
<dd>
String to print.
</dd>
<dt><code>border</code></dt>
<dd>
Indicates if borders must be drawn around the cell block. The value can be either a number:
<ul>
<li><code>0</code>: no border</li>
<li><code>1</code>: frame</li>
</ul>
or a string containing some or all of the following characters (in any order):
<ul>
<li><code>L</code>: left</li>
<li><code>T</code>: top</li>
<li><code>R</code>: right</li>
<li><code>B</code>: bottom</li>
</ul>
Default value: <code>0</code>.
</dd>
<dt><code>align</code></dt>
<dd>
Sets the text alignment. Possible values are:
<ul>
<li><code>L</code>: left alignment</li>
<li><code>C</code>: center</li>
<li><code>R</code>: right alignment</li>
<li><code>J</code>: justification (default value)</li>
</ul>
</dd>
<dt><code>fill</code></dt>
<dd>
Indicates if the cell background must be painted (<code>true</code>) or transparent (<code>false</code>).
Default value: <code>false</code>.
</dd>
</dl>
<h2>See also</h2>
<a href="setfont.htm">SetFont</a>,
<a href="setdrawcolor.htm">SetDrawColor</a>,
<a href="setfillcolor.htm">SetFillColor</a>,
<a href="settextcolor.htm">SetTextColor</a>,
<a href="setlinewidth.htm">SetLineWidth</a>,
<a href="cell.htm">Cell</a>,
<a href="write.htm">Write</a>,
<a href="setautopagebreak.htm">SetAutoPageBreak</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,46 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Output</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>Output</h1>
<code><b>string</b> Output([<b>string</b> dest [, <b>string</b> name [, <b>boolean</b> isUTF8]]])</code>
<h2>Description</h2>
Send the document to a given destination: browser, file or string. In the case of a browser, the
PDF viewer may be used or a download may be forced.
<br>
The method first calls Close() if necessary to terminate the document.
<h2>Parameters</h2>
<dl class="param">
<dt><code>dest</code></dt>
<dd>
Destination where to send the document. It can be one of the following:
<ul>
<li><code>I</code>: send the file inline to the browser. The PDF viewer is used if available.</li>
<li><code>D</code>: send to the browser and force a file download with the name given by <code>name</code>.</li>
<li><code>F</code>: save to a local file with the name given by <code>name</code> (may include a path).</li>
<li><code>S</code>: return the document as a string.</li>
</ul>
The default value is <code>I</code>.
</dd>
<dt><code>name</code></dt>
<dd>
The name of the file. It is ignored in case of destination <code>S</code>.<br>
The default value is <code>doc.pdf</code>.
</dd>
<dt><code>isUTF8</code></dt>
<dd>
Indicates if <code>name</code> is encoded in ISO-8859-1 (<code>false</code>) or UTF-8 (<code>true</code>).
Only used for destinations <code>I</code> and <code>D</code>.<br>
The default value is <code>false</code>.
</dd>
</dl>
<h2>See also</h2>
<a href="close.htm">Close</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,18 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>PageNo</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>PageNo</h1>
<code><b>int</b> PageNo()</code>
<h2>Description</h2>
Returns the current page number.
<h2>See also</h2>
<a href="aliasnbpages.htm">AliasNbPages</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,48 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Rect</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>Rect</h1>
<code>Rect(<b>float</b> x, <b>float</b> y, <b>float</b> w, <b>float</b> h [, <b>string</b> style])</code>
<h2>Description</h2>
Outputs a rectangle. It can be drawn (border only), filled (with no border) or both.
<h2>Parameters</h2>
<dl class="param">
<dt><code>x</code></dt>
<dd>
Abscissa of upper-left corner.
</dd>
<dt><code>y</code></dt>
<dd>
Ordinate of upper-left corner.
</dd>
<dt><code>w</code></dt>
<dd>
Width.
</dd>
<dt><code>h</code></dt>
<dd>
Height.
</dd>
<dt><code>style</code></dt>
<dd>
Style of rendering. Possible values are:
<ul>
<li><code>D</code> or empty string: draw. This is the default value.</li>
<li><code>F</code>: fill</li>
<li><code>DF</code> or <code>FD</code>: draw and fill</li>
</ul>
</dd>
</dl>
<h2>See also</h2>
<a href="setlinewidth.htm">SetLineWidth</a>,
<a href="setdrawcolor.htm">SetDrawColor</a>,
<a href="setfillcolor.htm">SetFillColor</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,33 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetAuthor</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetAuthor</h1>
<code>SetAuthor(<b>string</b> author [, <b>boolean</b> isUTF8])</code>
<h2>Description</h2>
Defines the author of the document.
<h2>Parameters</h2>
<dl class="param">
<dt><code>author</code></dt>
<dd>
The name of the author.
</dd>
<dt><code>isUTF8</code></dt>
<dd>
Indicates if the string is encoded in ISO-8859-1 (<code>false</code>) or UTF-8 (<code>true</code>).<br>
Default value: <code>false</code>.
</dd>
</dl>
<h2>See also</h2>
<a href="setcreator.htm">SetCreator</a>,
<a href="setkeywords.htm">SetKeywords</a>,
<a href="setsubject.htm">SetSubject</a>,
<a href="settitle.htm">SetTitle</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,33 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetAutoPageBreak</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetAutoPageBreak</h1>
<code>SetAutoPageBreak(<b>boolean</b> auto [, <b>float</b> margin])</code>
<h2>Description</h2>
Enables or disables the automatic page breaking mode. When enabling, the second parameter is
the distance from the bottom of the page that defines the triggering limit. By default, the
mode is on and the margin is 2 cm.
<h2>Parameters</h2>
<dl class="param">
<dt><code>auto</code></dt>
<dd>
Boolean indicating if mode should be on or off.
</dd>
<dt><code>margin</code></dt>
<dd>
Distance from the bottom of the page.
</dd>
</dl>
<h2>See also</h2>
<a href="cell.htm">Cell</a>,
<a href="multicell.htm">MultiCell</a>,
<a href="acceptpagebreak.htm">AcceptPageBreak</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,31 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetCompression</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetCompression</h1>
<code>SetCompression(<b>boolean</b> compress)</code>
<h2>Description</h2>
Activates or deactivates page compression. When activated, the internal representation of
each page is compressed, which leads to a compression ratio of about 2 for the resulting
document.
<br>
Compression is on by default.
<br>
<br>
<strong>Note:</strong> the Zlib extension is required for this feature. If not present, compression
will be turned off.
<h2>Parameters</h2>
<dl class="param">
<dt><code>compress</code></dt>
<dd>
Boolean indicating if compression must be enabled.
</dd>
</dl>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,34 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetCreator</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetCreator</h1>
<code>SetCreator(<b>string</b> creator [, <b>boolean</b> isUTF8])</code>
<h2>Description</h2>
Defines the creator of the document. This is typically the name of the application that
generates the PDF.
<h2>Parameters</h2>
<dl class="param">
<dt><code>creator</code></dt>
<dd>
The name of the creator.
</dd>
<dt><code>isUTF8</code></dt>
<dd>
Indicates if the string is encoded in ISO-8859-1 (<code>false</code>) or UTF-8 (<code>true</code>).<br>
Default value: <code>false</code>.
</dd>
</dl>
<h2>See also</h2>
<a href="setauthor.htm">SetAuthor</a>,
<a href="setkeywords.htm">SetKeywords</a>,
<a href="setsubject.htm">SetSubject</a>,
<a href="settitle.htm">SetTitle</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,45 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetDisplayMode</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetDisplayMode</h1>
<code>SetDisplayMode(<b>mixed</b> zoom [, <b>string</b> layout])</code>
<h2>Description</h2>
Defines the way the document is to be displayed by the viewer. The zoom level can be set: pages can be
displayed entirely on screen, occupy the full width of the window, use real size, be scaled by a
specific zooming factor or use viewer default (configured in the Preferences menu of Adobe Reader).
The page layout can be specified too: single at once, continuous display, two columns or viewer
default.
<h2>Parameters</h2>
<dl class="param">
<dt><code>zoom</code></dt>
<dd>
The zoom to use. It can be one of the following string values:
<ul>
<li><code>fullpage</code>: displays the entire page on screen</li>
<li><code>fullwidth</code>: uses maximum width of window</li>
<li><code>real</code>: uses real size (equivalent to 100% zoom)</li>
<li><code>default</code>: uses viewer default mode</li>
</ul>
or a number indicating the zooming factor to use.
</dd>
<dt><code>layout</code></dt>
<dd>
The page layout. Possible values are:
<ul>
<li><code>single</code>: displays one page at once</li>
<li><code>continuous</code>: displays pages continuously</li>
<li><code>two</code>: displays two pages on two columns</li>
<li><code>default</code>: uses viewer default mode</li>
</ul>
Default value is <code>default</code>.
</dd>
</dl>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,41 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetDrawColor</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetDrawColor</h1>
<code>SetDrawColor(<b>int</b> r [, <b>int</b> g, <b>int</b> b])</code>
<h2>Description</h2>
Defines the color used for all drawing operations (lines, rectangles and cell borders). It
can be expressed in RGB components or gray scale. The method can be called before the first
page is created and the value is retained from page to page.
<h2>Parameters</h2>
<dl class="param">
<dt><code>r</code></dt>
<dd>
If <code>g</code> et <code>b</code> are given, red component; if not, indicates the gray level.
Value between 0 and 255.
</dd>
<dt><code>g</code></dt>
<dd>
Green component (between 0 and 255).
</dd>
<dt><code>b</code></dt>
<dd>
Blue component (between 0 and 255).
</dd>
</dl>
<h2>See also</h2>
<a href="setfillcolor.htm">SetFillColor</a>,
<a href="settextcolor.htm">SetTextColor</a>,
<a href="line.htm">Line</a>,
<a href="rect.htm">Rect</a>,
<a href="cell.htm">Cell</a>,
<a href="multicell.htm">MultiCell</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,40 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetFillColor</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetFillColor</h1>
<code>SetFillColor(<b>int</b> r [, <b>int</b> g, <b>int</b> b])</code>
<h2>Description</h2>
Defines the color used for all filling operations (filled rectangles and cell backgrounds).
It can be expressed in RGB components or gray scale. The method can be called before the first
page is created and the value is retained from page to page.
<h2>Parameters</h2>
<dl class="param">
<dt><code>r</code></dt>
<dd>
If <code>g</code> and <code>b</code> are given, red component; if not, indicates the gray level.
Value between 0 and 255.
</dd>
<dt><code>g</code></dt>
<dd>
Green component (between 0 and 255).
</dd>
<dt><code>b</code></dt>
<dd>
Blue component (between 0 and 255).
</dd>
</dl>
<h2>See also</h2>
<a href="setdrawcolor.htm">SetDrawColor</a>,
<a href="settextcolor.htm">SetTextColor</a>,
<a href="rect.htm">Rect</a>,
<a href="cell.htm">Cell</a>,
<a href="multicell.htm">MultiCell</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,92 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetFont</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetFont</h1>
<code>SetFont(<b>string</b> family [, <b>string</b> style [, <b>float</b> size]])</code>
<h2>Description</h2>
Sets the font used to print character strings. It is mandatory to call this method
at least once before printing text or the resulting document would not be valid.
<br>
The font can be either a standard one or a font added via the AddFont() method. Standard fonts
use the Windows encoding cp1252 (Western Europe).
<br>
The method can be called before the first page is created and the font is kept from page
to page.
<br>
If you just wish to change the current font size, it is simpler to call SetFontSize().
<br>
<br>
<strong>Note:</strong> the font definition files must be accessible. They are searched successively in:
<ul>
<li>The directory defined by the <code>FPDF_FONTPATH</code> constant (if this constant is defined)</li>
<li>The <code>font</code> directory located in the same directory as <code>fpdf.php</code> (if it exists)</li>
<li>The directories accessible through <code>include()</code></li>
</ul>
Example using <code>FPDF_FONTPATH</code>:
<div class="doc-source">
<pre><code>define('FPDF_FONTPATH','/home/www/font');
require('fpdf.php');</code></pre>
</div>
If the file corresponding to the requested font is not found, the error "Could not include font
definition file" is raised.
<h2>Parameters</h2>
<dl class="param">
<dt><code>family</code></dt>
<dd>
Family font. It can be either a name defined by AddFont() or one of the standard families (case
insensitive):
<ul>
<li><code>Courier</code> (fixed-width)</li>
<li><code>Helvetica</code> or <code>Arial</code> (synonymous; sans serif)</li>
<li><code>Times</code> (serif)</li>
<li><code>Symbol</code> (symbolic)</li>
<li><code>ZapfDingbats</code> (symbolic)</li>
</ul>
It is also possible to pass an empty string. In that case, the current family is kept.
</dd>
<dt><code>style</code></dt>
<dd>
Font style. Possible values are (case insensitive):
<ul>
<li>empty string: regular</li>
<li><code>B</code>: bold</li>
<li><code>I</code>: italic</li>
<li><code>U</code>: underline</li>
</ul>
or any combination. The default value is regular.
Bold and italic styles do not apply to <code>Symbol</code> and <code>ZapfDingbats</code>.
</dd>
<dt><code>size</code></dt>
<dd>
Font size in points.
<br>
The default value is the current size. If no size has been specified since the beginning of
the document, the value taken is 12.
</dd>
</dl>
<h2>Example</h2>
<div class="doc-source">
<pre><code>// Times regular 12
$pdf-&gt;SetFont('Times');
// Arial bold 14
$pdf-&gt;SetFont('Arial','B',14);
// Removes bold
$pdf-&gt;SetFont('');
// Times bold, italic and underlined 14
$pdf-&gt;SetFont('Times','BIU');</code></pre>
</div>
<h2>See also</h2>
<a href="addfont.htm">AddFont</a>,
<a href="setfontsize.htm">SetFontSize</a>,
<a href="cell.htm">Cell</a>,
<a href="multicell.htm">MultiCell</a>,
<a href="write.htm">Write</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,25 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetFontSize</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetFontSize</h1>
<code>SetFontSize(<b>float</b> size)</code>
<h2>Description</h2>
Defines the size of the current font.
<h2>Parameters</h2>
<dl class="param">
<dt><code>size</code></dt>
<dd>
The size (in points).
</dd>
</dl>
<h2>See also</h2>
<a href="setfont.htm">SetFont</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,33 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetKeywords</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetKeywords</h1>
<code>SetKeywords(<b>string</b> keywords [, <b>boolean</b> isUTF8])</code>
<h2>Description</h2>
Associates keywords with the document, generally in the form 'keyword1 keyword2 ...'.
<h2>Parameters</h2>
<dl class="param">
<dt><code>keywords</code></dt>
<dd>
The list of keywords.
</dd>
<dt><code>isUTF8</code></dt>
<dd>
Indicates if the string is encoded in ISO-8859-1 (<code>false</code>) or UTF-8 (<code>true</code>).<br>
Default value: <code>false</code>.
</dd>
</dl>
<h2>See also</h2>
<a href="setauthor.htm">SetAuthor</a>,
<a href="setcreator.htm">SetCreator</a>,
<a href="setsubject.htm">SetSubject</a>,
<a href="settitle.htm">SetTitle</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,30 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetLeftMargin</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetLeftMargin</h1>
<code>SetLeftMargin(<b>float</b> margin)</code>
<h2>Description</h2>
Defines the left margin. The method can be called before creating the first page.
<br>
If the current abscissa gets out of page, it is brought back to the margin.
<h2>Parameters</h2>
<dl class="param">
<dt><code>margin</code></dt>
<dd>
The margin.
</dd>
</dl>
<h2>See also</h2>
<a href="settopmargin.htm">SetTopMargin</a>,
<a href="setrightmargin.htm">SetRightMargin</a>,
<a href="setautopagebreak.htm">SetAutoPageBreak</a>,
<a href="setmargins.htm">SetMargins</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,29 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetLineWidth</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetLineWidth</h1>
<code>SetLineWidth(<b>float</b> width)</code>
<h2>Description</h2>
Defines the line width. By default, the value equals 0.2 mm. The method can be called before
the first page is created and the value is retained from page to page.
<h2>Parameters</h2>
<dl class="param">
<dt><code>width</code></dt>
<dd>
The width.
</dd>
</dl>
<h2>See also</h2>
<a href="line.htm">Line</a>,
<a href="rect.htm">Rect</a>,
<a href="cell.htm">Cell</a>,
<a href="multicell.htm">MultiCell</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,34 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetLink</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetLink</h1>
<code>SetLink(<b>int</b> link [, <b>float</b> y [, <b>int</b> page]])</code>
<h2>Description</h2>
Defines the page and position a link points to.
<h2>Parameters</h2>
<dl class="param">
<dt><code>link</code></dt>
<dd>
The link identifier returned by AddLink().
</dd>
<dt><code>y</code></dt>
<dd>
Ordinate of target position; <code>-1</code> indicates the current position.
The default value is <code>0</code> (top of page).
</dd>
<dt><code>page</code></dt>
<dd>
Number of target page; <code>-1</code> indicates the current page. This is the default value.
</dd>
</dl>
<h2>See also</h2>
<a href="addlink.htm">AddLink</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,37 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetMargins</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetMargins</h1>
<code>SetMargins(<b>float</b> left, <b>float</b> top [, <b>float</b> right])</code>
<h2>Description</h2>
Defines the left, top and right margins. By default, they equal 1 cm. Call this method to change
them.
<h2>Parameters</h2>
<dl class="param">
<dt><code>left</code></dt>
<dd>
Left margin.
</dd>
<dt><code>top</code></dt>
<dd>
Top margin.
</dd>
<dt><code>right</code></dt>
<dd>
Right margin. Default value is the left one.
</dd>
</dl>
<h2>See also</h2>
<a href="setleftmargin.htm">SetLeftMargin</a>,
<a href="settopmargin.htm">SetTopMargin</a>,
<a href="setrightmargin.htm">SetRightMargin</a>,
<a href="setautopagebreak.htm">SetAutoPageBreak</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,28 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetRightMargin</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetRightMargin</h1>
<code>SetRightMargin(<b>float</b> margin)</code>
<h2>Description</h2>
Defines the right margin. The method can be called before creating the first page.
<h2>Parameters</h2>
<dl class="param">
<dt><code>margin</code></dt>
<dd>
The margin.
</dd>
</dl>
<h2>See also</h2>
<a href="setleftmargin.htm">SetLeftMargin</a>,
<a href="settopmargin.htm">SetTopMargin</a>,
<a href="setautopagebreak.htm">SetAutoPageBreak</a>,
<a href="setmargins.htm">SetMargins</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,33 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetSubject</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetSubject</h1>
<code>SetSubject(<b>string</b> subject [, <b>boolean</b> isUTF8])</code>
<h2>Description</h2>
Defines the subject of the document.
<h2>Parameters</h2>
<dl class="param">
<dt><code>subject</code></dt>
<dd>
The subject.
</dd>
<dt><code>isUTF8</code></dt>
<dd>
Indicates if the string is encoded in ISO-8859-1 (<code>false</code>) or UTF-8 (<code>true</code>).<br>
Default value: <code>false</code>.
</dd>
</dl>
<h2>See also</h2>
<a href="setauthor.htm">SetAuthor</a>,
<a href="setcreator.htm">SetCreator</a>,
<a href="setkeywords.htm">SetKeywords</a>,
<a href="settitle.htm">SetTitle</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,40 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetTextColor</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetTextColor</h1>
<code>SetTextColor(<b>int</b> r [, <b>int</b> g, <b>int</b> b])</code>
<h2>Description</h2>
Defines the color used for text. It can be expressed in RGB components or gray scale. The
method can be called before the first page is created and the value is retained from page to
page.
<h2>Parameters</h2>
<dl class="param">
<dt><code>r</code></dt>
<dd>
If <code>g</code> et <code>b</code> are given, red component; if not, indicates the gray level.
Value between 0 and 255.
</dd>
<dt><code>g</code></dt>
<dd>
Green component (between 0 and 255).
</dd>
<dt><code>b</code></dt>
<dd>
Blue component (between 0 and 255).
</dd>
</dl>
<h2>See also</h2>
<a href="setdrawcolor.htm">SetDrawColor</a>,
<a href="setfillcolor.htm">SetFillColor</a>,
<a href="text.htm">Text</a>,
<a href="cell.htm">Cell</a>,
<a href="multicell.htm">MultiCell</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,33 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetTitle</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetTitle</h1>
<code>SetTitle(<b>string</b> title [, <b>boolean</b> isUTF8])</code>
<h2>Description</h2>
Defines the title of the document.
<h2>Parameters</h2>
<dl class="param">
<dt><code>title</code></dt>
<dd>
The title.
</dd>
<dt><code>isUTF8</code></dt>
<dd>
Indicates if the string is encoded in ISO-8859-1 (<code>false</code>) or UTF-8 (<code>true</code>).<br>
Default value: <code>false</code>.
</dd>
</dl>
<h2>See also</h2>
<a href="setauthor.htm">SetAuthor</a>,
<a href="setcreator.htm">SetCreator</a>,
<a href="setkeywords.htm">SetKeywords</a>,
<a href="setsubject.htm">SetSubject</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,28 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetTopMargin</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetTopMargin</h1>
<code>SetTopMargin(<b>float</b> margin)</code>
<h2>Description</h2>
Defines the top margin. The method can be called before creating the first page.
<h2>Parameters</h2>
<dl class="param">
<dt><code>margin</code></dt>
<dd>
The margin.
</dd>
</dl>
<h2>See also</h2>
<a href="setleftmargin.htm">SetLeftMargin</a>,
<a href="setrightmargin.htm">SetRightMargin</a>,
<a href="setautopagebreak.htm">SetAutoPageBreak</a>,
<a href="setmargins.htm">SetMargins</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,29 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetX</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetX</h1>
<code>SetX(<b>float</b> x)</code>
<h2>Description</h2>
Defines the abscissa of the current position. If the passed value is negative, it is relative
to the right of the page.
<h2>Parameters</h2>
<dl class="param">
<dt><code>x</code></dt>
<dd>
The value of the abscissa.
</dd>
</dl>
<h2>See also</h2>
<a href="getx.htm">GetX</a>,
<a href="gety.htm">GetY</a>,
<a href="sety.htm">SetY</a>,
<a href="setxy.htm">SetXY</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,31 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetXY</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetXY</h1>
<code>SetXY(<b>float</b> x, <b>float</b> y)</code>
<h2>Description</h2>
Defines the abscissa and ordinate of the current position. If the passed values are negative,
they are relative respectively to the right and bottom of the page.
<h2>Parameters</h2>
<dl class="param">
<dt><code>x</code></dt>
<dd>
The value of the abscissa.
</dd>
<dt><code>y</code></dt>
<dd>
The value of the ordinate.
</dd>
</dl>
<h2>See also</h2>
<a href="setx.htm">SetX</a>,
<a href="sety.htm">SetY</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,33 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>SetY</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>SetY</h1>
<code>SetY(<b>float</b> y [, <b>boolean</b> resetX])</code>
<h2>Description</h2>
Sets the ordinate and optionally moves the current abscissa back to the left margin. If the value
is negative, it is relative to the bottom of the page.
<h2>Parameters</h2>
<dl class="param">
<dt><code>y</code></dt>
<dd>
The value of the ordinate.
</dd>
<dt><code>resetX</code></dt>
<dd>
Whether to reset the abscissa. Default value: <code>true</code>.
</dd>
</dl>
<h2>See also</h2>
<a href="getx.htm">GetX</a>,
<a href="gety.htm">GetY</a>,
<a href="setx.htm">SetX</a>,
<a href="setxy.htm">SetXY</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,39 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Text</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>Text</h1>
<code>Text(<b>float</b> x, <b>float</b> y, <b>string</b> txt)</code>
<h2>Description</h2>
Prints a character string. The origin is on the left of the first character, on the baseline.
This method allows to place a string precisely on the page, but it is usually easier to use
Cell(), MultiCell() or Write() which are the standard methods to print text.
<h2>Parameters</h2>
<dl class="param">
<dt><code>x</code></dt>
<dd>
Abscissa of the origin.
</dd>
<dt><code>y</code></dt>
<dd>
Ordinate of the origin.
</dd>
<dt><code>txt</code></dt>
<dd>
String to print.
</dd>
</dl>
<h2>See also</h2>
<a href="setfont.htm">SetFont</a>,
<a href="settextcolor.htm">SetTextColor</a>,
<a href="cell.htm">Cell</a>,
<a href="multicell.htm">MultiCell</a>,
<a href="write.htm">Write</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,51 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Write</title>
<link type="text/css" rel="stylesheet" href="../fpdf.css">
</head>
<body>
<h1>Write</h1>
<code>Write(<b>float</b> h, <b>string</b> txt [, <b>mixed</b> link])</code>
<h2>Description</h2>
This method prints text from the current position. When the right margin is reached (or the \n
character is met) a line break occurs and text continues from the left margin. Upon method exit,
the current position is left just at the end of the text.
<br>
It is possible to put a link on the text.
<h2>Parameters</h2>
<dl class="param">
<dt><code>h</code></dt>
<dd>
Line height.
</dd>
<dt><code>txt</code></dt>
<dd>
String to print.
</dd>
<dt><code>link</code></dt>
<dd>
URL or identifier returned by AddLink().
</dd>
</dl>
<h2>Example</h2>
<div class="doc-source">
<pre><code>// Begin with regular font
$pdf-&gt;SetFont('Arial','',14);
$pdf-&gt;Write(5,'Visit ');
// Then put a blue underlined link
$pdf-&gt;SetTextColor(0,0,255);
$pdf-&gt;SetFont('','U');
$pdf-&gt;Write(5,'www.fpdf.org','http://www.fpdf.org');</code></pre>
</div>
<h2>See also</h2>
<a href="setfont.htm">SetFont</a>,
<a href="settextcolor.htm">SetTextColor</a>,
<a href="addlink.htm">AddLink</a>,
<a href="multicell.htm">MultiCell</a>,
<a href="setautopagebreak.htm">SetAutoPageBreak</a>
<hr style="margin-top:1.5em">
<div style="text-align:center"><a href="index.htm">Index</a></div>
</body>
</html>

View File

@@ -1,10 +0,0 @@
<?php
$type = 'Core';
$name = 'Courier';
$up = -100;
$ut = 50;
for($i=0;$i<=255;$i++)
$cw[chr($i)] = 600;
$enc = 'cp1252';
$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96));
?>

View File

@@ -1,10 +0,0 @@
<?php
$type = 'Core';
$name = 'Courier-Bold';
$up = -100;
$ut = 50;
for($i=0;$i<=255;$i++)
$cw[chr($i)] = 600;
$enc = 'cp1252';
$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96));
?>

View File

@@ -1,10 +0,0 @@
<?php
$type = 'Core';
$name = 'Courier-BoldOblique';
$up = -100;
$ut = 50;
for($i=0;$i<=255;$i++)
$cw[chr($i)] = 600;
$enc = 'cp1252';
$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96));
?>

View File

@@ -1,10 +0,0 @@
<?php
$type = 'Core';
$name = 'Courier-Oblique';
$up = -100;
$ut = 50;
for($i=0;$i<=255;$i++)
$cw[chr($i)] = 600;
$enc = 'cp1252';
$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96));
?>

View File

@@ -1,21 +0,0 @@
<?php
$type = 'Core';
$name = 'Helvetica';
$up = -100;
$ut = 50;
$cw = array(
chr(0)=>278,chr(1)=>278,chr(2)=>278,chr(3)=>278,chr(4)=>278,chr(5)=>278,chr(6)=>278,chr(7)=>278,chr(8)=>278,chr(9)=>278,chr(10)=>278,chr(11)=>278,chr(12)=>278,chr(13)=>278,chr(14)=>278,chr(15)=>278,chr(16)=>278,chr(17)=>278,chr(18)=>278,chr(19)=>278,chr(20)=>278,chr(21)=>278,
chr(22)=>278,chr(23)=>278,chr(24)=>278,chr(25)=>278,chr(26)=>278,chr(27)=>278,chr(28)=>278,chr(29)=>278,chr(30)=>278,chr(31)=>278,' '=>278,'!'=>278,'"'=>355,'#'=>556,'$'=>556,'%'=>889,'&'=>667,'\''=>191,'('=>333,')'=>333,'*'=>389,'+'=>584,
','=>278,'-'=>333,'.'=>278,'/'=>278,'0'=>556,'1'=>556,'2'=>556,'3'=>556,'4'=>556,'5'=>556,'6'=>556,'7'=>556,'8'=>556,'9'=>556,':'=>278,';'=>278,'<'=>584,'='=>584,'>'=>584,'?'=>556,'@'=>1015,'A'=>667,
'B'=>667,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>722,'I'=>278,'J'=>500,'K'=>667,'L'=>556,'M'=>833,'N'=>722,'O'=>778,'P'=>667,'Q'=>778,'R'=>722,'S'=>667,'T'=>611,'U'=>722,'V'=>667,'W'=>944,
'X'=>667,'Y'=>667,'Z'=>611,'['=>278,'\\'=>278,']'=>278,'^'=>469,'_'=>556,'`'=>333,'a'=>556,'b'=>556,'c'=>500,'d'=>556,'e'=>556,'f'=>278,'g'=>556,'h'=>556,'i'=>222,'j'=>222,'k'=>500,'l'=>222,'m'=>833,
'n'=>556,'o'=>556,'p'=>556,'q'=>556,'r'=>333,'s'=>500,'t'=>278,'u'=>556,'v'=>500,'w'=>722,'x'=>500,'y'=>500,'z'=>500,'{'=>334,'|'=>260,'}'=>334,'~'=>584,chr(127)=>350,chr(128)=>556,chr(129)=>350,chr(130)=>222,chr(131)=>556,
chr(132)=>333,chr(133)=>1000,chr(134)=>556,chr(135)=>556,chr(136)=>333,chr(137)=>1000,chr(138)=>667,chr(139)=>333,chr(140)=>1000,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>222,chr(146)=>222,chr(147)=>333,chr(148)=>333,chr(149)=>350,chr(150)=>556,chr(151)=>1000,chr(152)=>333,chr(153)=>1000,
chr(154)=>500,chr(155)=>333,chr(156)=>944,chr(157)=>350,chr(158)=>500,chr(159)=>667,chr(160)=>278,chr(161)=>333,chr(162)=>556,chr(163)=>556,chr(164)=>556,chr(165)=>556,chr(166)=>260,chr(167)=>556,chr(168)=>333,chr(169)=>737,chr(170)=>370,chr(171)=>556,chr(172)=>584,chr(173)=>333,chr(174)=>737,chr(175)=>333,
chr(176)=>400,chr(177)=>584,chr(178)=>333,chr(179)=>333,chr(180)=>333,chr(181)=>556,chr(182)=>537,chr(183)=>278,chr(184)=>333,chr(185)=>333,chr(186)=>365,chr(187)=>556,chr(188)=>834,chr(189)=>834,chr(190)=>834,chr(191)=>611,chr(192)=>667,chr(193)=>667,chr(194)=>667,chr(195)=>667,chr(196)=>667,chr(197)=>667,
chr(198)=>1000,chr(199)=>722,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>278,chr(205)=>278,chr(206)=>278,chr(207)=>278,chr(208)=>722,chr(209)=>722,chr(210)=>778,chr(211)=>778,chr(212)=>778,chr(213)=>778,chr(214)=>778,chr(215)=>584,chr(216)=>778,chr(217)=>722,chr(218)=>722,chr(219)=>722,
chr(220)=>722,chr(221)=>667,chr(222)=>667,chr(223)=>611,chr(224)=>556,chr(225)=>556,chr(226)=>556,chr(227)=>556,chr(228)=>556,chr(229)=>556,chr(230)=>889,chr(231)=>500,chr(232)=>556,chr(233)=>556,chr(234)=>556,chr(235)=>556,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>556,chr(241)=>556,
chr(242)=>556,chr(243)=>556,chr(244)=>556,chr(245)=>556,chr(246)=>556,chr(247)=>584,chr(248)=>611,chr(249)=>556,chr(250)=>556,chr(251)=>556,chr(252)=>556,chr(253)=>500,chr(254)=>556,chr(255)=>500);
$enc = 'cp1252';
$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96));
?>

View File

@@ -1,21 +0,0 @@
<?php
$type = 'Core';
$name = 'Helvetica-Bold';
$up = -100;
$ut = 50;
$cw = array(
chr(0)=>278,chr(1)=>278,chr(2)=>278,chr(3)=>278,chr(4)=>278,chr(5)=>278,chr(6)=>278,chr(7)=>278,chr(8)=>278,chr(9)=>278,chr(10)=>278,chr(11)=>278,chr(12)=>278,chr(13)=>278,chr(14)=>278,chr(15)=>278,chr(16)=>278,chr(17)=>278,chr(18)=>278,chr(19)=>278,chr(20)=>278,chr(21)=>278,
chr(22)=>278,chr(23)=>278,chr(24)=>278,chr(25)=>278,chr(26)=>278,chr(27)=>278,chr(28)=>278,chr(29)=>278,chr(30)=>278,chr(31)=>278,' '=>278,'!'=>333,'"'=>474,'#'=>556,'$'=>556,'%'=>889,'&'=>722,'\''=>238,'('=>333,')'=>333,'*'=>389,'+'=>584,
','=>278,'-'=>333,'.'=>278,'/'=>278,'0'=>556,'1'=>556,'2'=>556,'3'=>556,'4'=>556,'5'=>556,'6'=>556,'7'=>556,'8'=>556,'9'=>556,':'=>333,';'=>333,'<'=>584,'='=>584,'>'=>584,'?'=>611,'@'=>975,'A'=>722,
'B'=>722,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>722,'I'=>278,'J'=>556,'K'=>722,'L'=>611,'M'=>833,'N'=>722,'O'=>778,'P'=>667,'Q'=>778,'R'=>722,'S'=>667,'T'=>611,'U'=>722,'V'=>667,'W'=>944,
'X'=>667,'Y'=>667,'Z'=>611,'['=>333,'\\'=>278,']'=>333,'^'=>584,'_'=>556,'`'=>333,'a'=>556,'b'=>611,'c'=>556,'d'=>611,'e'=>556,'f'=>333,'g'=>611,'h'=>611,'i'=>278,'j'=>278,'k'=>556,'l'=>278,'m'=>889,
'n'=>611,'o'=>611,'p'=>611,'q'=>611,'r'=>389,'s'=>556,'t'=>333,'u'=>611,'v'=>556,'w'=>778,'x'=>556,'y'=>556,'z'=>500,'{'=>389,'|'=>280,'}'=>389,'~'=>584,chr(127)=>350,chr(128)=>556,chr(129)=>350,chr(130)=>278,chr(131)=>556,
chr(132)=>500,chr(133)=>1000,chr(134)=>556,chr(135)=>556,chr(136)=>333,chr(137)=>1000,chr(138)=>667,chr(139)=>333,chr(140)=>1000,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>278,chr(146)=>278,chr(147)=>500,chr(148)=>500,chr(149)=>350,chr(150)=>556,chr(151)=>1000,chr(152)=>333,chr(153)=>1000,
chr(154)=>556,chr(155)=>333,chr(156)=>944,chr(157)=>350,chr(158)=>500,chr(159)=>667,chr(160)=>278,chr(161)=>333,chr(162)=>556,chr(163)=>556,chr(164)=>556,chr(165)=>556,chr(166)=>280,chr(167)=>556,chr(168)=>333,chr(169)=>737,chr(170)=>370,chr(171)=>556,chr(172)=>584,chr(173)=>333,chr(174)=>737,chr(175)=>333,
chr(176)=>400,chr(177)=>584,chr(178)=>333,chr(179)=>333,chr(180)=>333,chr(181)=>611,chr(182)=>556,chr(183)=>278,chr(184)=>333,chr(185)=>333,chr(186)=>365,chr(187)=>556,chr(188)=>834,chr(189)=>834,chr(190)=>834,chr(191)=>611,chr(192)=>722,chr(193)=>722,chr(194)=>722,chr(195)=>722,chr(196)=>722,chr(197)=>722,
chr(198)=>1000,chr(199)=>722,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>278,chr(205)=>278,chr(206)=>278,chr(207)=>278,chr(208)=>722,chr(209)=>722,chr(210)=>778,chr(211)=>778,chr(212)=>778,chr(213)=>778,chr(214)=>778,chr(215)=>584,chr(216)=>778,chr(217)=>722,chr(218)=>722,chr(219)=>722,
chr(220)=>722,chr(221)=>667,chr(222)=>667,chr(223)=>611,chr(224)=>556,chr(225)=>556,chr(226)=>556,chr(227)=>556,chr(228)=>556,chr(229)=>556,chr(230)=>889,chr(231)=>556,chr(232)=>556,chr(233)=>556,chr(234)=>556,chr(235)=>556,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>611,chr(241)=>611,
chr(242)=>611,chr(243)=>611,chr(244)=>611,chr(245)=>611,chr(246)=>611,chr(247)=>584,chr(248)=>611,chr(249)=>611,chr(250)=>611,chr(251)=>611,chr(252)=>611,chr(253)=>556,chr(254)=>611,chr(255)=>556);
$enc = 'cp1252';
$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96));
?>

View File

@@ -1,21 +0,0 @@
<?php
$type = 'Core';
$name = 'Helvetica-BoldOblique';
$up = -100;
$ut = 50;
$cw = array(
chr(0)=>278,chr(1)=>278,chr(2)=>278,chr(3)=>278,chr(4)=>278,chr(5)=>278,chr(6)=>278,chr(7)=>278,chr(8)=>278,chr(9)=>278,chr(10)=>278,chr(11)=>278,chr(12)=>278,chr(13)=>278,chr(14)=>278,chr(15)=>278,chr(16)=>278,chr(17)=>278,chr(18)=>278,chr(19)=>278,chr(20)=>278,chr(21)=>278,
chr(22)=>278,chr(23)=>278,chr(24)=>278,chr(25)=>278,chr(26)=>278,chr(27)=>278,chr(28)=>278,chr(29)=>278,chr(30)=>278,chr(31)=>278,' '=>278,'!'=>333,'"'=>474,'#'=>556,'$'=>556,'%'=>889,'&'=>722,'\''=>238,'('=>333,')'=>333,'*'=>389,'+'=>584,
','=>278,'-'=>333,'.'=>278,'/'=>278,'0'=>556,'1'=>556,'2'=>556,'3'=>556,'4'=>556,'5'=>556,'6'=>556,'7'=>556,'8'=>556,'9'=>556,':'=>333,';'=>333,'<'=>584,'='=>584,'>'=>584,'?'=>611,'@'=>975,'A'=>722,
'B'=>722,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>722,'I'=>278,'J'=>556,'K'=>722,'L'=>611,'M'=>833,'N'=>722,'O'=>778,'P'=>667,'Q'=>778,'R'=>722,'S'=>667,'T'=>611,'U'=>722,'V'=>667,'W'=>944,
'X'=>667,'Y'=>667,'Z'=>611,'['=>333,'\\'=>278,']'=>333,'^'=>584,'_'=>556,'`'=>333,'a'=>556,'b'=>611,'c'=>556,'d'=>611,'e'=>556,'f'=>333,'g'=>611,'h'=>611,'i'=>278,'j'=>278,'k'=>556,'l'=>278,'m'=>889,
'n'=>611,'o'=>611,'p'=>611,'q'=>611,'r'=>389,'s'=>556,'t'=>333,'u'=>611,'v'=>556,'w'=>778,'x'=>556,'y'=>556,'z'=>500,'{'=>389,'|'=>280,'}'=>389,'~'=>584,chr(127)=>350,chr(128)=>556,chr(129)=>350,chr(130)=>278,chr(131)=>556,
chr(132)=>500,chr(133)=>1000,chr(134)=>556,chr(135)=>556,chr(136)=>333,chr(137)=>1000,chr(138)=>667,chr(139)=>333,chr(140)=>1000,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>278,chr(146)=>278,chr(147)=>500,chr(148)=>500,chr(149)=>350,chr(150)=>556,chr(151)=>1000,chr(152)=>333,chr(153)=>1000,
chr(154)=>556,chr(155)=>333,chr(156)=>944,chr(157)=>350,chr(158)=>500,chr(159)=>667,chr(160)=>278,chr(161)=>333,chr(162)=>556,chr(163)=>556,chr(164)=>556,chr(165)=>556,chr(166)=>280,chr(167)=>556,chr(168)=>333,chr(169)=>737,chr(170)=>370,chr(171)=>556,chr(172)=>584,chr(173)=>333,chr(174)=>737,chr(175)=>333,
chr(176)=>400,chr(177)=>584,chr(178)=>333,chr(179)=>333,chr(180)=>333,chr(181)=>611,chr(182)=>556,chr(183)=>278,chr(184)=>333,chr(185)=>333,chr(186)=>365,chr(187)=>556,chr(188)=>834,chr(189)=>834,chr(190)=>834,chr(191)=>611,chr(192)=>722,chr(193)=>722,chr(194)=>722,chr(195)=>722,chr(196)=>722,chr(197)=>722,
chr(198)=>1000,chr(199)=>722,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>278,chr(205)=>278,chr(206)=>278,chr(207)=>278,chr(208)=>722,chr(209)=>722,chr(210)=>778,chr(211)=>778,chr(212)=>778,chr(213)=>778,chr(214)=>778,chr(215)=>584,chr(216)=>778,chr(217)=>722,chr(218)=>722,chr(219)=>722,
chr(220)=>722,chr(221)=>667,chr(222)=>667,chr(223)=>611,chr(224)=>556,chr(225)=>556,chr(226)=>556,chr(227)=>556,chr(228)=>556,chr(229)=>556,chr(230)=>889,chr(231)=>556,chr(232)=>556,chr(233)=>556,chr(234)=>556,chr(235)=>556,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>611,chr(241)=>611,
chr(242)=>611,chr(243)=>611,chr(244)=>611,chr(245)=>611,chr(246)=>611,chr(247)=>584,chr(248)=>611,chr(249)=>611,chr(250)=>611,chr(251)=>611,chr(252)=>611,chr(253)=>556,chr(254)=>611,chr(255)=>556);
$enc = 'cp1252';
$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96));
?>

View File

@@ -1,21 +0,0 @@
<?php
$type = 'Core';
$name = 'Helvetica-Oblique';
$up = -100;
$ut = 50;
$cw = array(
chr(0)=>278,chr(1)=>278,chr(2)=>278,chr(3)=>278,chr(4)=>278,chr(5)=>278,chr(6)=>278,chr(7)=>278,chr(8)=>278,chr(9)=>278,chr(10)=>278,chr(11)=>278,chr(12)=>278,chr(13)=>278,chr(14)=>278,chr(15)=>278,chr(16)=>278,chr(17)=>278,chr(18)=>278,chr(19)=>278,chr(20)=>278,chr(21)=>278,
chr(22)=>278,chr(23)=>278,chr(24)=>278,chr(25)=>278,chr(26)=>278,chr(27)=>278,chr(28)=>278,chr(29)=>278,chr(30)=>278,chr(31)=>278,' '=>278,'!'=>278,'"'=>355,'#'=>556,'$'=>556,'%'=>889,'&'=>667,'\''=>191,'('=>333,')'=>333,'*'=>389,'+'=>584,
','=>278,'-'=>333,'.'=>278,'/'=>278,'0'=>556,'1'=>556,'2'=>556,'3'=>556,'4'=>556,'5'=>556,'6'=>556,'7'=>556,'8'=>556,'9'=>556,':'=>278,';'=>278,'<'=>584,'='=>584,'>'=>584,'?'=>556,'@'=>1015,'A'=>667,
'B'=>667,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>722,'I'=>278,'J'=>500,'K'=>667,'L'=>556,'M'=>833,'N'=>722,'O'=>778,'P'=>667,'Q'=>778,'R'=>722,'S'=>667,'T'=>611,'U'=>722,'V'=>667,'W'=>944,
'X'=>667,'Y'=>667,'Z'=>611,'['=>278,'\\'=>278,']'=>278,'^'=>469,'_'=>556,'`'=>333,'a'=>556,'b'=>556,'c'=>500,'d'=>556,'e'=>556,'f'=>278,'g'=>556,'h'=>556,'i'=>222,'j'=>222,'k'=>500,'l'=>222,'m'=>833,
'n'=>556,'o'=>556,'p'=>556,'q'=>556,'r'=>333,'s'=>500,'t'=>278,'u'=>556,'v'=>500,'w'=>722,'x'=>500,'y'=>500,'z'=>500,'{'=>334,'|'=>260,'}'=>334,'~'=>584,chr(127)=>350,chr(128)=>556,chr(129)=>350,chr(130)=>222,chr(131)=>556,
chr(132)=>333,chr(133)=>1000,chr(134)=>556,chr(135)=>556,chr(136)=>333,chr(137)=>1000,chr(138)=>667,chr(139)=>333,chr(140)=>1000,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>222,chr(146)=>222,chr(147)=>333,chr(148)=>333,chr(149)=>350,chr(150)=>556,chr(151)=>1000,chr(152)=>333,chr(153)=>1000,
chr(154)=>500,chr(155)=>333,chr(156)=>944,chr(157)=>350,chr(158)=>500,chr(159)=>667,chr(160)=>278,chr(161)=>333,chr(162)=>556,chr(163)=>556,chr(164)=>556,chr(165)=>556,chr(166)=>260,chr(167)=>556,chr(168)=>333,chr(169)=>737,chr(170)=>370,chr(171)=>556,chr(172)=>584,chr(173)=>333,chr(174)=>737,chr(175)=>333,
chr(176)=>400,chr(177)=>584,chr(178)=>333,chr(179)=>333,chr(180)=>333,chr(181)=>556,chr(182)=>537,chr(183)=>278,chr(184)=>333,chr(185)=>333,chr(186)=>365,chr(187)=>556,chr(188)=>834,chr(189)=>834,chr(190)=>834,chr(191)=>611,chr(192)=>667,chr(193)=>667,chr(194)=>667,chr(195)=>667,chr(196)=>667,chr(197)=>667,
chr(198)=>1000,chr(199)=>722,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>278,chr(205)=>278,chr(206)=>278,chr(207)=>278,chr(208)=>722,chr(209)=>722,chr(210)=>778,chr(211)=>778,chr(212)=>778,chr(213)=>778,chr(214)=>778,chr(215)=>584,chr(216)=>778,chr(217)=>722,chr(218)=>722,chr(219)=>722,
chr(220)=>722,chr(221)=>667,chr(222)=>667,chr(223)=>611,chr(224)=>556,chr(225)=>556,chr(226)=>556,chr(227)=>556,chr(228)=>556,chr(229)=>556,chr(230)=>889,chr(231)=>500,chr(232)=>556,chr(233)=>556,chr(234)=>556,chr(235)=>556,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>556,chr(241)=>556,
chr(242)=>556,chr(243)=>556,chr(244)=>556,chr(245)=>556,chr(246)=>556,chr(247)=>584,chr(248)=>611,chr(249)=>556,chr(250)=>556,chr(251)=>556,chr(252)=>556,chr(253)=>500,chr(254)=>556,chr(255)=>500);
$enc = 'cp1252';
$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96));
?>

View File

@@ -1,20 +0,0 @@
<?php
$type = 'Core';
$name = 'Symbol';
$up = -100;
$ut = 50;
$cw = array(
chr(0)=>250,chr(1)=>250,chr(2)=>250,chr(3)=>250,chr(4)=>250,chr(5)=>250,chr(6)=>250,chr(7)=>250,chr(8)=>250,chr(9)=>250,chr(10)=>250,chr(11)=>250,chr(12)=>250,chr(13)=>250,chr(14)=>250,chr(15)=>250,chr(16)=>250,chr(17)=>250,chr(18)=>250,chr(19)=>250,chr(20)=>250,chr(21)=>250,
chr(22)=>250,chr(23)=>250,chr(24)=>250,chr(25)=>250,chr(26)=>250,chr(27)=>250,chr(28)=>250,chr(29)=>250,chr(30)=>250,chr(31)=>250,' '=>250,'!'=>333,'"'=>713,'#'=>500,'$'=>549,'%'=>833,'&'=>778,'\''=>439,'('=>333,')'=>333,'*'=>500,'+'=>549,
','=>250,'-'=>549,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>278,';'=>278,'<'=>549,'='=>549,'>'=>549,'?'=>444,'@'=>549,'A'=>722,
'B'=>667,'C'=>722,'D'=>612,'E'=>611,'F'=>763,'G'=>603,'H'=>722,'I'=>333,'J'=>631,'K'=>722,'L'=>686,'M'=>889,'N'=>722,'O'=>722,'P'=>768,'Q'=>741,'R'=>556,'S'=>592,'T'=>611,'U'=>690,'V'=>439,'W'=>768,
'X'=>645,'Y'=>795,'Z'=>611,'['=>333,'\\'=>863,']'=>333,'^'=>658,'_'=>500,'`'=>500,'a'=>631,'b'=>549,'c'=>549,'d'=>494,'e'=>439,'f'=>521,'g'=>411,'h'=>603,'i'=>329,'j'=>603,'k'=>549,'l'=>549,'m'=>576,
'n'=>521,'o'=>549,'p'=>549,'q'=>521,'r'=>549,'s'=>603,'t'=>439,'u'=>576,'v'=>713,'w'=>686,'x'=>493,'y'=>686,'z'=>494,'{'=>480,'|'=>200,'}'=>480,'~'=>549,chr(127)=>0,chr(128)=>0,chr(129)=>0,chr(130)=>0,chr(131)=>0,
chr(132)=>0,chr(133)=>0,chr(134)=>0,chr(135)=>0,chr(136)=>0,chr(137)=>0,chr(138)=>0,chr(139)=>0,chr(140)=>0,chr(141)=>0,chr(142)=>0,chr(143)=>0,chr(144)=>0,chr(145)=>0,chr(146)=>0,chr(147)=>0,chr(148)=>0,chr(149)=>0,chr(150)=>0,chr(151)=>0,chr(152)=>0,chr(153)=>0,
chr(154)=>0,chr(155)=>0,chr(156)=>0,chr(157)=>0,chr(158)=>0,chr(159)=>0,chr(160)=>750,chr(161)=>620,chr(162)=>247,chr(163)=>549,chr(164)=>167,chr(165)=>713,chr(166)=>500,chr(167)=>753,chr(168)=>753,chr(169)=>753,chr(170)=>753,chr(171)=>1042,chr(172)=>987,chr(173)=>603,chr(174)=>987,chr(175)=>603,
chr(176)=>400,chr(177)=>549,chr(178)=>411,chr(179)=>549,chr(180)=>549,chr(181)=>713,chr(182)=>494,chr(183)=>460,chr(184)=>549,chr(185)=>549,chr(186)=>549,chr(187)=>549,chr(188)=>1000,chr(189)=>603,chr(190)=>1000,chr(191)=>658,chr(192)=>823,chr(193)=>686,chr(194)=>795,chr(195)=>987,chr(196)=>768,chr(197)=>768,
chr(198)=>823,chr(199)=>768,chr(200)=>768,chr(201)=>713,chr(202)=>713,chr(203)=>713,chr(204)=>713,chr(205)=>713,chr(206)=>713,chr(207)=>713,chr(208)=>768,chr(209)=>713,chr(210)=>790,chr(211)=>790,chr(212)=>890,chr(213)=>823,chr(214)=>549,chr(215)=>250,chr(216)=>713,chr(217)=>603,chr(218)=>603,chr(219)=>1042,
chr(220)=>987,chr(221)=>603,chr(222)=>987,chr(223)=>603,chr(224)=>494,chr(225)=>329,chr(226)=>790,chr(227)=>790,chr(228)=>786,chr(229)=>713,chr(230)=>384,chr(231)=>384,chr(232)=>384,chr(233)=>384,chr(234)=>384,chr(235)=>384,chr(236)=>494,chr(237)=>494,chr(238)=>494,chr(239)=>494,chr(240)=>0,chr(241)=>329,
chr(242)=>274,chr(243)=>686,chr(244)=>686,chr(245)=>686,chr(246)=>384,chr(247)=>384,chr(248)=>384,chr(249)=>384,chr(250)=>384,chr(251)=>384,chr(252)=>494,chr(253)=>494,chr(254)=>494,chr(255)=>0);
$uv = array(32=>160,33=>33,34=>8704,35=>35,36=>8707,37=>array(37,2),39=>8715,40=>array(40,2),42=>8727,43=>array(43,2),45=>8722,46=>array(46,18),64=>8773,65=>array(913,2),67=>935,68=>array(916,2),70=>934,71=>915,72=>919,73=>921,74=>977,75=>array(922,4),79=>array(927,2),81=>920,82=>929,83=>array(931,3),86=>962,87=>937,88=>926,89=>936,90=>918,91=>91,92=>8756,93=>93,94=>8869,95=>95,96=>63717,97=>array(945,2),99=>967,100=>array(948,2),102=>966,103=>947,104=>951,105=>953,106=>981,107=>array(954,4),111=>array(959,2),113=>952,114=>961,115=>array(963,3),118=>982,119=>969,120=>958,121=>968,122=>950,123=>array(123,3),126=>8764,160=>8364,161=>978,162=>8242,163=>8804,164=>8725,165=>8734,166=>402,167=>9827,168=>9830,169=>9829,170=>9824,171=>8596,172=>array(8592,4),176=>array(176,2),178=>8243,179=>8805,180=>215,181=>8733,182=>8706,183=>8226,184=>247,185=>array(8800,2),187=>8776,188=>8230,189=>array(63718,2),191=>8629,192=>8501,193=>8465,194=>8476,195=>8472,196=>8855,197=>8853,198=>8709,199=>array(8745,2),201=>8835,202=>8839,203=>8836,204=>8834,205=>8838,206=>array(8712,2),208=>8736,209=>8711,210=>63194,211=>63193,212=>63195,213=>8719,214=>8730,215=>8901,216=>172,217=>array(8743,2),219=>8660,220=>array(8656,4),224=>9674,225=>9001,226=>array(63720,3),229=>8721,230=>array(63723,10),241=>9002,242=>8747,243=>8992,244=>63733,245=>8993,246=>array(63734,9));
?>

View File

@@ -1,21 +0,0 @@
<?php
$type = 'Core';
$name = 'Times-Roman';
$up = -100;
$ut = 50;
$cw = array(
chr(0)=>250,chr(1)=>250,chr(2)=>250,chr(3)=>250,chr(4)=>250,chr(5)=>250,chr(6)=>250,chr(7)=>250,chr(8)=>250,chr(9)=>250,chr(10)=>250,chr(11)=>250,chr(12)=>250,chr(13)=>250,chr(14)=>250,chr(15)=>250,chr(16)=>250,chr(17)=>250,chr(18)=>250,chr(19)=>250,chr(20)=>250,chr(21)=>250,
chr(22)=>250,chr(23)=>250,chr(24)=>250,chr(25)=>250,chr(26)=>250,chr(27)=>250,chr(28)=>250,chr(29)=>250,chr(30)=>250,chr(31)=>250,' '=>250,'!'=>333,'"'=>408,'#'=>500,'$'=>500,'%'=>833,'&'=>778,'\''=>180,'('=>333,')'=>333,'*'=>500,'+'=>564,
','=>250,'-'=>333,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>278,';'=>278,'<'=>564,'='=>564,'>'=>564,'?'=>444,'@'=>921,'A'=>722,
'B'=>667,'C'=>667,'D'=>722,'E'=>611,'F'=>556,'G'=>722,'H'=>722,'I'=>333,'J'=>389,'K'=>722,'L'=>611,'M'=>889,'N'=>722,'O'=>722,'P'=>556,'Q'=>722,'R'=>667,'S'=>556,'T'=>611,'U'=>722,'V'=>722,'W'=>944,
'X'=>722,'Y'=>722,'Z'=>611,'['=>333,'\\'=>278,']'=>333,'^'=>469,'_'=>500,'`'=>333,'a'=>444,'b'=>500,'c'=>444,'d'=>500,'e'=>444,'f'=>333,'g'=>500,'h'=>500,'i'=>278,'j'=>278,'k'=>500,'l'=>278,'m'=>778,
'n'=>500,'o'=>500,'p'=>500,'q'=>500,'r'=>333,'s'=>389,'t'=>278,'u'=>500,'v'=>500,'w'=>722,'x'=>500,'y'=>500,'z'=>444,'{'=>480,'|'=>200,'}'=>480,'~'=>541,chr(127)=>350,chr(128)=>500,chr(129)=>350,chr(130)=>333,chr(131)=>500,
chr(132)=>444,chr(133)=>1000,chr(134)=>500,chr(135)=>500,chr(136)=>333,chr(137)=>1000,chr(138)=>556,chr(139)=>333,chr(140)=>889,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>333,chr(146)=>333,chr(147)=>444,chr(148)=>444,chr(149)=>350,chr(150)=>500,chr(151)=>1000,chr(152)=>333,chr(153)=>980,
chr(154)=>389,chr(155)=>333,chr(156)=>722,chr(157)=>350,chr(158)=>444,chr(159)=>722,chr(160)=>250,chr(161)=>333,chr(162)=>500,chr(163)=>500,chr(164)=>500,chr(165)=>500,chr(166)=>200,chr(167)=>500,chr(168)=>333,chr(169)=>760,chr(170)=>276,chr(171)=>500,chr(172)=>564,chr(173)=>333,chr(174)=>760,chr(175)=>333,
chr(176)=>400,chr(177)=>564,chr(178)=>300,chr(179)=>300,chr(180)=>333,chr(181)=>500,chr(182)=>453,chr(183)=>250,chr(184)=>333,chr(185)=>300,chr(186)=>310,chr(187)=>500,chr(188)=>750,chr(189)=>750,chr(190)=>750,chr(191)=>444,chr(192)=>722,chr(193)=>722,chr(194)=>722,chr(195)=>722,chr(196)=>722,chr(197)=>722,
chr(198)=>889,chr(199)=>667,chr(200)=>611,chr(201)=>611,chr(202)=>611,chr(203)=>611,chr(204)=>333,chr(205)=>333,chr(206)=>333,chr(207)=>333,chr(208)=>722,chr(209)=>722,chr(210)=>722,chr(211)=>722,chr(212)=>722,chr(213)=>722,chr(214)=>722,chr(215)=>564,chr(216)=>722,chr(217)=>722,chr(218)=>722,chr(219)=>722,
chr(220)=>722,chr(221)=>722,chr(222)=>556,chr(223)=>500,chr(224)=>444,chr(225)=>444,chr(226)=>444,chr(227)=>444,chr(228)=>444,chr(229)=>444,chr(230)=>667,chr(231)=>444,chr(232)=>444,chr(233)=>444,chr(234)=>444,chr(235)=>444,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>500,chr(241)=>500,
chr(242)=>500,chr(243)=>500,chr(244)=>500,chr(245)=>500,chr(246)=>500,chr(247)=>564,chr(248)=>500,chr(249)=>500,chr(250)=>500,chr(251)=>500,chr(252)=>500,chr(253)=>500,chr(254)=>500,chr(255)=>500);
$enc = 'cp1252';
$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96));
?>

View File

@@ -1,21 +0,0 @@
<?php
$type = 'Core';
$name = 'Times-Bold';
$up = -100;
$ut = 50;
$cw = array(
chr(0)=>250,chr(1)=>250,chr(2)=>250,chr(3)=>250,chr(4)=>250,chr(5)=>250,chr(6)=>250,chr(7)=>250,chr(8)=>250,chr(9)=>250,chr(10)=>250,chr(11)=>250,chr(12)=>250,chr(13)=>250,chr(14)=>250,chr(15)=>250,chr(16)=>250,chr(17)=>250,chr(18)=>250,chr(19)=>250,chr(20)=>250,chr(21)=>250,
chr(22)=>250,chr(23)=>250,chr(24)=>250,chr(25)=>250,chr(26)=>250,chr(27)=>250,chr(28)=>250,chr(29)=>250,chr(30)=>250,chr(31)=>250,' '=>250,'!'=>333,'"'=>555,'#'=>500,'$'=>500,'%'=>1000,'&'=>833,'\''=>278,'('=>333,')'=>333,'*'=>500,'+'=>570,
','=>250,'-'=>333,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>333,';'=>333,'<'=>570,'='=>570,'>'=>570,'?'=>500,'@'=>930,'A'=>722,
'B'=>667,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>778,'I'=>389,'J'=>500,'K'=>778,'L'=>667,'M'=>944,'N'=>722,'O'=>778,'P'=>611,'Q'=>778,'R'=>722,'S'=>556,'T'=>667,'U'=>722,'V'=>722,'W'=>1000,
'X'=>722,'Y'=>722,'Z'=>667,'['=>333,'\\'=>278,']'=>333,'^'=>581,'_'=>500,'`'=>333,'a'=>500,'b'=>556,'c'=>444,'d'=>556,'e'=>444,'f'=>333,'g'=>500,'h'=>556,'i'=>278,'j'=>333,'k'=>556,'l'=>278,'m'=>833,
'n'=>556,'o'=>500,'p'=>556,'q'=>556,'r'=>444,'s'=>389,'t'=>333,'u'=>556,'v'=>500,'w'=>722,'x'=>500,'y'=>500,'z'=>444,'{'=>394,'|'=>220,'}'=>394,'~'=>520,chr(127)=>350,chr(128)=>500,chr(129)=>350,chr(130)=>333,chr(131)=>500,
chr(132)=>500,chr(133)=>1000,chr(134)=>500,chr(135)=>500,chr(136)=>333,chr(137)=>1000,chr(138)=>556,chr(139)=>333,chr(140)=>1000,chr(141)=>350,chr(142)=>667,chr(143)=>350,chr(144)=>350,chr(145)=>333,chr(146)=>333,chr(147)=>500,chr(148)=>500,chr(149)=>350,chr(150)=>500,chr(151)=>1000,chr(152)=>333,chr(153)=>1000,
chr(154)=>389,chr(155)=>333,chr(156)=>722,chr(157)=>350,chr(158)=>444,chr(159)=>722,chr(160)=>250,chr(161)=>333,chr(162)=>500,chr(163)=>500,chr(164)=>500,chr(165)=>500,chr(166)=>220,chr(167)=>500,chr(168)=>333,chr(169)=>747,chr(170)=>300,chr(171)=>500,chr(172)=>570,chr(173)=>333,chr(174)=>747,chr(175)=>333,
chr(176)=>400,chr(177)=>570,chr(178)=>300,chr(179)=>300,chr(180)=>333,chr(181)=>556,chr(182)=>540,chr(183)=>250,chr(184)=>333,chr(185)=>300,chr(186)=>330,chr(187)=>500,chr(188)=>750,chr(189)=>750,chr(190)=>750,chr(191)=>500,chr(192)=>722,chr(193)=>722,chr(194)=>722,chr(195)=>722,chr(196)=>722,chr(197)=>722,
chr(198)=>1000,chr(199)=>722,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>389,chr(205)=>389,chr(206)=>389,chr(207)=>389,chr(208)=>722,chr(209)=>722,chr(210)=>778,chr(211)=>778,chr(212)=>778,chr(213)=>778,chr(214)=>778,chr(215)=>570,chr(216)=>778,chr(217)=>722,chr(218)=>722,chr(219)=>722,
chr(220)=>722,chr(221)=>722,chr(222)=>611,chr(223)=>556,chr(224)=>500,chr(225)=>500,chr(226)=>500,chr(227)=>500,chr(228)=>500,chr(229)=>500,chr(230)=>722,chr(231)=>444,chr(232)=>444,chr(233)=>444,chr(234)=>444,chr(235)=>444,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>500,chr(241)=>556,
chr(242)=>500,chr(243)=>500,chr(244)=>500,chr(245)=>500,chr(246)=>500,chr(247)=>570,chr(248)=>500,chr(249)=>556,chr(250)=>556,chr(251)=>556,chr(252)=>556,chr(253)=>500,chr(254)=>556,chr(255)=>500);
$enc = 'cp1252';
$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96));
?>

View File

@@ -1,21 +0,0 @@
<?php
$type = 'Core';
$name = 'Times-BoldItalic';
$up = -100;
$ut = 50;
$cw = array(
chr(0)=>250,chr(1)=>250,chr(2)=>250,chr(3)=>250,chr(4)=>250,chr(5)=>250,chr(6)=>250,chr(7)=>250,chr(8)=>250,chr(9)=>250,chr(10)=>250,chr(11)=>250,chr(12)=>250,chr(13)=>250,chr(14)=>250,chr(15)=>250,chr(16)=>250,chr(17)=>250,chr(18)=>250,chr(19)=>250,chr(20)=>250,chr(21)=>250,
chr(22)=>250,chr(23)=>250,chr(24)=>250,chr(25)=>250,chr(26)=>250,chr(27)=>250,chr(28)=>250,chr(29)=>250,chr(30)=>250,chr(31)=>250,' '=>250,'!'=>389,'"'=>555,'#'=>500,'$'=>500,'%'=>833,'&'=>778,'\''=>278,'('=>333,')'=>333,'*'=>500,'+'=>570,
','=>250,'-'=>333,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>333,';'=>333,'<'=>570,'='=>570,'>'=>570,'?'=>500,'@'=>832,'A'=>667,
'B'=>667,'C'=>667,'D'=>722,'E'=>667,'F'=>667,'G'=>722,'H'=>778,'I'=>389,'J'=>500,'K'=>667,'L'=>611,'M'=>889,'N'=>722,'O'=>722,'P'=>611,'Q'=>722,'R'=>667,'S'=>556,'T'=>611,'U'=>722,'V'=>667,'W'=>889,
'X'=>667,'Y'=>611,'Z'=>611,'['=>333,'\\'=>278,']'=>333,'^'=>570,'_'=>500,'`'=>333,'a'=>500,'b'=>500,'c'=>444,'d'=>500,'e'=>444,'f'=>333,'g'=>500,'h'=>556,'i'=>278,'j'=>278,'k'=>500,'l'=>278,'m'=>778,
'n'=>556,'o'=>500,'p'=>500,'q'=>500,'r'=>389,'s'=>389,'t'=>278,'u'=>556,'v'=>444,'w'=>667,'x'=>500,'y'=>444,'z'=>389,'{'=>348,'|'=>220,'}'=>348,'~'=>570,chr(127)=>350,chr(128)=>500,chr(129)=>350,chr(130)=>333,chr(131)=>500,
chr(132)=>500,chr(133)=>1000,chr(134)=>500,chr(135)=>500,chr(136)=>333,chr(137)=>1000,chr(138)=>556,chr(139)=>333,chr(140)=>944,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>333,chr(146)=>333,chr(147)=>500,chr(148)=>500,chr(149)=>350,chr(150)=>500,chr(151)=>1000,chr(152)=>333,chr(153)=>1000,
chr(154)=>389,chr(155)=>333,chr(156)=>722,chr(157)=>350,chr(158)=>389,chr(159)=>611,chr(160)=>250,chr(161)=>389,chr(162)=>500,chr(163)=>500,chr(164)=>500,chr(165)=>500,chr(166)=>220,chr(167)=>500,chr(168)=>333,chr(169)=>747,chr(170)=>266,chr(171)=>500,chr(172)=>606,chr(173)=>333,chr(174)=>747,chr(175)=>333,
chr(176)=>400,chr(177)=>570,chr(178)=>300,chr(179)=>300,chr(180)=>333,chr(181)=>576,chr(182)=>500,chr(183)=>250,chr(184)=>333,chr(185)=>300,chr(186)=>300,chr(187)=>500,chr(188)=>750,chr(189)=>750,chr(190)=>750,chr(191)=>500,chr(192)=>667,chr(193)=>667,chr(194)=>667,chr(195)=>667,chr(196)=>667,chr(197)=>667,
chr(198)=>944,chr(199)=>667,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>389,chr(205)=>389,chr(206)=>389,chr(207)=>389,chr(208)=>722,chr(209)=>722,chr(210)=>722,chr(211)=>722,chr(212)=>722,chr(213)=>722,chr(214)=>722,chr(215)=>570,chr(216)=>722,chr(217)=>722,chr(218)=>722,chr(219)=>722,
chr(220)=>722,chr(221)=>611,chr(222)=>611,chr(223)=>500,chr(224)=>500,chr(225)=>500,chr(226)=>500,chr(227)=>500,chr(228)=>500,chr(229)=>500,chr(230)=>722,chr(231)=>444,chr(232)=>444,chr(233)=>444,chr(234)=>444,chr(235)=>444,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>500,chr(241)=>556,
chr(242)=>500,chr(243)=>500,chr(244)=>500,chr(245)=>500,chr(246)=>500,chr(247)=>570,chr(248)=>500,chr(249)=>556,chr(250)=>556,chr(251)=>556,chr(252)=>556,chr(253)=>444,chr(254)=>500,chr(255)=>444);
$enc = 'cp1252';
$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96));
?>

View File

@@ -1,21 +0,0 @@
<?php
$type = 'Core';
$name = 'Times-Italic';
$up = -100;
$ut = 50;
$cw = array(
chr(0)=>250,chr(1)=>250,chr(2)=>250,chr(3)=>250,chr(4)=>250,chr(5)=>250,chr(6)=>250,chr(7)=>250,chr(8)=>250,chr(9)=>250,chr(10)=>250,chr(11)=>250,chr(12)=>250,chr(13)=>250,chr(14)=>250,chr(15)=>250,chr(16)=>250,chr(17)=>250,chr(18)=>250,chr(19)=>250,chr(20)=>250,chr(21)=>250,
chr(22)=>250,chr(23)=>250,chr(24)=>250,chr(25)=>250,chr(26)=>250,chr(27)=>250,chr(28)=>250,chr(29)=>250,chr(30)=>250,chr(31)=>250,' '=>250,'!'=>333,'"'=>420,'#'=>500,'$'=>500,'%'=>833,'&'=>778,'\''=>214,'('=>333,')'=>333,'*'=>500,'+'=>675,
','=>250,'-'=>333,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>333,';'=>333,'<'=>675,'='=>675,'>'=>675,'?'=>500,'@'=>920,'A'=>611,
'B'=>611,'C'=>667,'D'=>722,'E'=>611,'F'=>611,'G'=>722,'H'=>722,'I'=>333,'J'=>444,'K'=>667,'L'=>556,'M'=>833,'N'=>667,'O'=>722,'P'=>611,'Q'=>722,'R'=>611,'S'=>500,'T'=>556,'U'=>722,'V'=>611,'W'=>833,
'X'=>611,'Y'=>556,'Z'=>556,'['=>389,'\\'=>278,']'=>389,'^'=>422,'_'=>500,'`'=>333,'a'=>500,'b'=>500,'c'=>444,'d'=>500,'e'=>444,'f'=>278,'g'=>500,'h'=>500,'i'=>278,'j'=>278,'k'=>444,'l'=>278,'m'=>722,
'n'=>500,'o'=>500,'p'=>500,'q'=>500,'r'=>389,'s'=>389,'t'=>278,'u'=>500,'v'=>444,'w'=>667,'x'=>444,'y'=>444,'z'=>389,'{'=>400,'|'=>275,'}'=>400,'~'=>541,chr(127)=>350,chr(128)=>500,chr(129)=>350,chr(130)=>333,chr(131)=>500,
chr(132)=>556,chr(133)=>889,chr(134)=>500,chr(135)=>500,chr(136)=>333,chr(137)=>1000,chr(138)=>500,chr(139)=>333,chr(140)=>944,chr(141)=>350,chr(142)=>556,chr(143)=>350,chr(144)=>350,chr(145)=>333,chr(146)=>333,chr(147)=>556,chr(148)=>556,chr(149)=>350,chr(150)=>500,chr(151)=>889,chr(152)=>333,chr(153)=>980,
chr(154)=>389,chr(155)=>333,chr(156)=>667,chr(157)=>350,chr(158)=>389,chr(159)=>556,chr(160)=>250,chr(161)=>389,chr(162)=>500,chr(163)=>500,chr(164)=>500,chr(165)=>500,chr(166)=>275,chr(167)=>500,chr(168)=>333,chr(169)=>760,chr(170)=>276,chr(171)=>500,chr(172)=>675,chr(173)=>333,chr(174)=>760,chr(175)=>333,
chr(176)=>400,chr(177)=>675,chr(178)=>300,chr(179)=>300,chr(180)=>333,chr(181)=>500,chr(182)=>523,chr(183)=>250,chr(184)=>333,chr(185)=>300,chr(186)=>310,chr(187)=>500,chr(188)=>750,chr(189)=>750,chr(190)=>750,chr(191)=>500,chr(192)=>611,chr(193)=>611,chr(194)=>611,chr(195)=>611,chr(196)=>611,chr(197)=>611,
chr(198)=>889,chr(199)=>667,chr(200)=>611,chr(201)=>611,chr(202)=>611,chr(203)=>611,chr(204)=>333,chr(205)=>333,chr(206)=>333,chr(207)=>333,chr(208)=>722,chr(209)=>667,chr(210)=>722,chr(211)=>722,chr(212)=>722,chr(213)=>722,chr(214)=>722,chr(215)=>675,chr(216)=>722,chr(217)=>722,chr(218)=>722,chr(219)=>722,
chr(220)=>722,chr(221)=>556,chr(222)=>611,chr(223)=>500,chr(224)=>500,chr(225)=>500,chr(226)=>500,chr(227)=>500,chr(228)=>500,chr(229)=>500,chr(230)=>667,chr(231)=>444,chr(232)=>444,chr(233)=>444,chr(234)=>444,chr(235)=>444,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>500,chr(241)=>500,
chr(242)=>500,chr(243)=>500,chr(244)=>500,chr(245)=>500,chr(246)=>500,chr(247)=>675,chr(248)=>500,chr(249)=>500,chr(250)=>500,chr(251)=>500,chr(252)=>500,chr(253)=>444,chr(254)=>500,chr(255)=>444);
$enc = 'cp1252';
$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96));
?>

Some files were not shown because too many files have changed in this diff Show More