fix query get cicilan dan insert supplier invoice
This commit is contained in:
@@ -1,17 +1,7 @@
|
|||||||
@host = accone.aplikasi.web.id/one-api/mockup
|
@host = https://accone.aplikasi.web.id/one-api/
|
||||||
|
|
||||||
### Generate PI cicilan langsung
|
### Generate PI cicilan langsung
|
||||||
POST https://{{host}}/scheduler/PurchaseInvoiceInstallment/GenerateMonthlyInvoices
|
POST {{host}}/mockup/scheduler/PurchaseInvoiceInstallment/GenerateMonthlyInvoices
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"startDate": "2026-07-01",
|
|
||||||
"endDate": "2026-07-31",
|
|
||||||
"dryRun": "Y"
|
|
||||||
}
|
|
||||||
|
|
||||||
### List kontrak eligible yang belum diproses
|
|
||||||
POST https://{{host}}/scheduler/PurchaseInvoiceInstallment/ListEligibleContracts
|
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -19,38 +9,32 @@ Content-Type: application/json
|
|||||||
"endDate": "2026-07-31"
|
"endDate": "2026-07-31"
|
||||||
}
|
}
|
||||||
|
|
||||||
### Generate PI cicilan untuk 1 kontrak
|
### List kontrak eligible yang belum diproses
|
||||||
POST https://{{host}}/scheduler/PurchaseInvoiceInstallment/GenerateMonthlyInvoices
|
POST https://accone.aplikasi.web.id/one-api/mockup/scheduler/PurchaseInvoiceInstallment/ListEligibleContracts
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
{
|
{
|
||||||
"startDate": "2026-07-01",
|
"startDate": "2026-07-01",
|
||||||
"endDate": "2026-07-31",
|
"endDate": "2026-07-31"
|
||||||
"contractID": 123,
|
|
||||||
"dryRun": "Y"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
### Panggil endpoint generate via cURL internal
|
### Insert supplier_invoice lewat controller terpisah
|
||||||
POST https://{{host}}/scheduler/PurchaseInvoiceInstallment/CurlGenerateMonthlyInvoices
|
POST {{host}}/mockup/scheduler/PurchaseInvoiceInstallmentInsert/InsertSupplierInvoice
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
{
|
{
|
||||||
"baseUrl": "https://accone.aplikasi.web.id/one-api/index.php",
|
"nomorPI": "PI-INS-20260712120000-000123-00456-00000",
|
||||||
"startDate": "2026-07-01",
|
"tanggalPI": "2026-07-31",
|
||||||
"endDate": "2026-07-31",
|
"tanggalJatuhTempo": "2026-08-14",
|
||||||
"userID": 1,
|
"jumlahCicilan": 15000000,
|
||||||
"dryRun": "Y"
|
"catatan": "PI Cicilan Otomatis",
|
||||||
}
|
"deskripsi": "Cicilan Kontrak Aset",
|
||||||
|
"userID": 0,
|
||||||
### Panggil endpoint generate via cURL internal untuk kontrak tertentu
|
"purchaseOrderAssetContractID": 123,
|
||||||
POST https://{{host}}/scheduler/PurchaseInvoiceInstallment/CurlGenerateMonthlyInvoices
|
"purchaseOrderID": 456,
|
||||||
Content-Type: application/json
|
"receiveOrderPoID": 789,
|
||||||
|
"supplierID": 12,
|
||||||
{
|
"purchaseOrderSummaryID": 111,
|
||||||
"baseUrl": "https://accone.aplikasi.web.id/one-api/index.php",
|
"purchaseOrderSummaryItemID": 222,
|
||||||
"startDate": "2026-07-01",
|
"purchaseOrderSummaryItemUnitID": 333
|
||||||
"endDate": "2026-07-31",
|
|
||||||
"userID": 1,
|
|
||||||
"contractID": 123,
|
|
||||||
"dryRun": "N"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
class PurchaseInvoiceInstallment extends MY_Controller
|
class PurchaseInvoiceInstallment extends MY_Controller
|
||||||
{
|
{
|
||||||
var $db;
|
var $db;
|
||||||
|
var $baseUrl = "https://accone.aplikasi.web.id/one-api/";
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
echo "Purchase Invoice Installment — Auto Generate PI Cicilan Aset";
|
echo "Purchase Invoice Installment — Auto Generate PI Cicilan Aset";
|
||||||
@@ -22,7 +22,6 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
$baseUrl = "devone.aplikasi.web.id";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,26 +33,23 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
* Parameter (POST JSON):
|
* Parameter (POST JSON):
|
||||||
* - startDate : Tanggal awal periode (format YYYY-MM-DD). Default: awal bulan ini.
|
* - startDate : Tanggal awal periode (format YYYY-MM-DD). Default: awal bulan ini.
|
||||||
* - endDate : Tanggal akhir periode (format YYYY-MM-DD). Default: akhir bulan ini.
|
* - endDate : Tanggal akhir periode (format YYYY-MM-DD). Default: akhir bulan ini.
|
||||||
* - dryRun : "Y" = simulasi tanpa menyimpan data. Default: "N".
|
|
||||||
* - contractID : (opsional) Filter hanya 1 kontrak tertentu.
|
|
||||||
*
|
|
||||||
* userID diambil otomatis dari token (sys_user["M_UserID"]).
|
* userID diambil otomatis dari token (sys_user["M_UserID"]).
|
||||||
* Jika CRON berjalan tanpa token, fallback ke user ID 1 (user sistem).
|
* Jika CRON berjalan tanpa token, fallback ke user ID 0.
|
||||||
*
|
*
|
||||||
* Syarat kontrak diproses:
|
* Syarat kontrak diproses:
|
||||||
* 1. Kontrak aktif dan berstatus "belum lunas"
|
* 1. Kontrak aktif dan berstatus "belum lunas"
|
||||||
* 2. Nilai cicilan > 0
|
* 2. Nilai cicilan > 0
|
||||||
* 3. Jumlah cicilan terbayar < total cicilan
|
* 3. Jumlah cicilan terbayar < total cicilan
|
||||||
* 4. Tanggal kontrak masuk dalam bulan yang dituju
|
* 4. Tanggal kontrak masuk dalam bulan yang dituju
|
||||||
* 5. Invoice dasar (tukar faktur) sudah ada untuk PO tersebut
|
* 5. RO sudah confirmed
|
||||||
* 6. PO sudah berstatus Approved
|
* 6. PO sudah berstatus Approved
|
||||||
*/
|
*/
|
||||||
public function GenerateMonthlyInvoices()
|
public function GenerateMonthlyInvoices()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$para = $this->sys_input;
|
$para = $this->sys_input;
|
||||||
// Ambil userID dari token JWT (sys_user). Fallback ke 1 jika CRON berjalan tanpa token.
|
// Ambil userID dari token JWT (sys_user). Fallback ke 0 jika CRON berjalan tanpa token.
|
||||||
$userID = !empty($this->sys_user["M_UserID"]) ? (int) $this->sys_user["M_UserID"] : 1;
|
$userID = !empty($this->sys_user["M_UserID"]) ? (int) $this->sys_user["M_UserID"] : 0;
|
||||||
$user = $this->getCronUser($userID);
|
$user = $this->getCronUser($userID);
|
||||||
|
|
||||||
$startDate = isset($para["startDate"]) && $para["startDate"] != ""
|
$startDate = isset($para["startDate"]) && $para["startDate"] != ""
|
||||||
@@ -62,8 +58,6 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
$endDate = isset($para["endDate"]) && $para["endDate"] != ""
|
$endDate = isset($para["endDate"]) && $para["endDate"] != ""
|
||||||
? $para["endDate"]
|
? $para["endDate"]
|
||||||
: (isset($para["date"]) && $para["date"] != "" ? date("Y-m-t", strtotime($para["date"])) : date("Y-m-t"));
|
: (isset($para["date"]) && $para["date"] != "" ? date("Y-m-t", strtotime($para["date"])) : date("Y-m-t"));
|
||||||
$dryRun = isset($para["dryRun"]) && ($para["dryRun"] === true || $para["dryRun"] == "Y" || $para["dryRun"] == "1");
|
|
||||||
|
|
||||||
// Validasi format tanggal
|
// Validasi format tanggal
|
||||||
if (!$this->isValidDate($startDate) || !$this->isValidDate($endDate)) {
|
if (!$this->isValidDate($startDate) || !$this->isValidDate($endDate)) {
|
||||||
throw new Exception("Format tanggal tidak valid. Gunakan format YYYY-MM-DD, contoh: 2025-07-01");
|
throw new Exception("Format tanggal tidak valid. Gunakan format YYYY-MM-DD, contoh: 2025-07-01");
|
||||||
@@ -84,7 +78,7 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
$sqlKontrak = "SELECT
|
$sqlKontrak = "SELECT
|
||||||
c.PurchaseOrderAssetContractID,
|
c.PurchaseOrderAssetContractID,
|
||||||
c.PurchaseOrderAssetContractPurchaseOrderID,
|
c.PurchaseOrderAssetContractPurchaseOrderID,
|
||||||
c.PurchaseOrderAssetContractReceiveOrderPoID,
|
ro.ReceiveOrderPoID AS PurchaseOrderAssetContractReceiveOrderPoID,
|
||||||
c.PurchaseOrderAssetContractName,
|
c.PurchaseOrderAssetContractName,
|
||||||
c.PurchaseOrderAssetContractStartDate,
|
c.PurchaseOrderAssetContractStartDate,
|
||||||
c.PurchaseOrderAssetContractEndDate,
|
c.PurchaseOrderAssetContractEndDate,
|
||||||
@@ -98,9 +92,7 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
po.PurchaseOrderPaymentTerm,
|
po.PurchaseOrderPaymentTerm,
|
||||||
po.PurchaseOrderWarehouseType,
|
po.PurchaseOrderWarehouseType,
|
||||||
po.PurchaseOrderWarehouseID,
|
po.PurchaseOrderWarehouseID,
|
||||||
ro.ReceiveOrderPoID,
|
ro.ReceiveOrderPoConfirmed,
|
||||||
si_base.SupplierInvoiceID AS BaseSupplierInvoiceID,
|
|
||||||
si_base.SupplierInvoiceNumber AS BaseSupplierInvoiceNumber,
|
|
||||||
ps.PurchaseOrderSummaryID,
|
ps.PurchaseOrderSummaryID,
|
||||||
ps.PurchaseOrderSummaryItemID,
|
ps.PurchaseOrderSummaryItemID,
|
||||||
ps.PurchaseOrderSummaryItemUnitID
|
ps.PurchaseOrderSummaryItemUnitID
|
||||||
@@ -112,27 +104,20 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
AND po.PurchaseOrderIsActive = 'Y'
|
AND po.PurchaseOrderIsActive = 'Y'
|
||||||
AND po.PurchaseOrderStatus = 'Approved'
|
AND po.PurchaseOrderStatus = 'Approved'
|
||||||
|
|
||||||
JOIN receive_order_po ro
|
JOIN (
|
||||||
ON ro.ReceiveOrderPoID = c.PurchaseOrderAssetContractReceiveOrderPoID
|
SELECT
|
||||||
AND ro.ReceiveOrderPoIsActive = 'Y'
|
rd.ReceiveOrderPoDetailPurchaseOrderID,
|
||||||
|
MIN(ro0.ReceiveOrderPoID) AS ReceiveOrderPoID,
|
||||||
-- Pastikan tukar faktur (invoice dasar) sudah ada untuk PO ini
|
MAX(ro0.ReceiveOrderPoConfirmed) AS ReceiveOrderPoConfirmed
|
||||||
JOIN supplier_invoice si_base
|
FROM receive_order_po ro0
|
||||||
ON si_base.SupplierInvoiceID = (
|
JOIN receive_order_po_detail rd
|
||||||
SELECT MIN(si0.SupplierInvoiceID)
|
ON rd.ReceiveOrderPoDetailReceiveOrderPoID = ro0.ReceiveOrderPoID
|
||||||
FROM supplier_invoice si0
|
AND rd.ReceiveOrderPoDetailIsActive = 'Y'
|
||||||
WHERE si0.SupplierInvoiceIsActive = 'Y'
|
WHERE ro0.ReceiveOrderPoIsActive = 'Y'
|
||||||
AND (
|
AND ro0.ReceiveOrderPoConfirmed = 'Y'
|
||||||
si0.SupplierInvoiceReceiveOrderPoID = c.PurchaseOrderAssetContractReceiveOrderPoID
|
GROUP BY rd.ReceiveOrderPoDetailPurchaseOrderID
|
||||||
OR EXISTS (
|
) ro
|
||||||
SELECT 1
|
ON ro.ReceiveOrderPoDetailPurchaseOrderID = po.PurchaseOrderID
|
||||||
FROM supplier_invoice_detail sid0
|
|
||||||
WHERE sid0.SupplierInvoiceDetailSupplierInvoiceID = si0.SupplierInvoiceID
|
|
||||||
AND sid0.SupplierInvoiceDetailReceiveOrderPoID = c.PurchaseOrderAssetContractReceiveOrderPoID
|
|
||||||
AND sid0.SupplierInvoiceDetailIsActive = 'Y'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
-- Ambil 1 item PO pertama sebagai referensi baris detail PI
|
-- Ambil 1 item PO pertama sebagai referensi baris detail PI
|
||||||
LEFT JOIN (
|
LEFT JOIN (
|
||||||
@@ -163,17 +148,10 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
c.PurchaseOrderAssetContractEndDate IS NULL
|
c.PurchaseOrderAssetContractEndDate IS NULL
|
||||||
OR DATE(c.PurchaseOrderAssetContractEndDate) >= DATE(?)
|
OR DATE(c.PurchaseOrderAssetContractEndDate) >= DATE(?)
|
||||||
)
|
)
|
||||||
AND c.PurchaseOrderAssetContractReceiveOrderPoID > 0
|
|
||||||
-- Tanggal jatuh tempo cicilan sudah melewati atau sama dengan hari ini
|
-- Tanggal jatuh tempo cicilan sudah melewati atau sama dengan hari ini
|
||||||
AND IFNULL(c.PurchaseOrderAssetContractInstallmentDate, 1) <= ?";
|
AND IFNULL(c.PurchaseOrderAssetContractInstallmentDate, 1) <= ?";
|
||||||
|
|
||||||
// Filter kontrak tertentu jika diminta
|
$params = [$monthEnd, $monthStart, $dayOfMonth];
|
||||||
if (isset($para["contractID"]) && (int) $para["contractID"] > 0) {
|
|
||||||
$sqlKontrak .= " AND c.PurchaseOrderAssetContractID = ?";
|
|
||||||
$params = [$monthEnd, $monthStart, $dayOfMonth, (int) $para["contractID"]];
|
|
||||||
} else {
|
|
||||||
$params = [$monthEnd, $monthStart, $dayOfMonth];
|
|
||||||
}
|
|
||||||
|
|
||||||
$qryKontrak = $this->db->query($sqlKontrak, $params);
|
$qryKontrak = $this->db->query($sqlKontrak, $params);
|
||||||
if (!$qryKontrak) {
|
if (!$qryKontrak) {
|
||||||
@@ -188,8 +166,6 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
// Proses tiap kontrak satu per satu
|
// Proses tiap kontrak satu per satu
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
$kontraks = $qryKontrak->result_array();
|
$kontraks = $qryKontrak->result_array();
|
||||||
print_r($kontraks);
|
|
||||||
exit;
|
|
||||||
foreach ($kontraks as $kontrak) {
|
foreach ($kontraks as $kontrak) {
|
||||||
|
|
||||||
// Lewati jika item/satuan PO tidak ditemukan (tidak bisa buat baris detail)
|
// Lewati jika item/satuan PO tidak ditemukan (tidak bisa buat baris detail)
|
||||||
@@ -248,35 +224,14 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------
|
|
||||||
// Mode simulasi (dryRun): catat tanpa simpan ke database
|
|
||||||
// -------------------------------------------------------
|
|
||||||
if ($dryRun) {
|
|
||||||
$berhasil[] = [
|
|
||||||
"kontrakID" => $kontrak["PurchaseOrderAssetContractID"],
|
|
||||||
"purchaseOrderID" => $kontrak["PurchaseOrderID"],
|
|
||||||
"receiveOrderPoID" => $kontrak["PurchaseOrderAssetContractReceiveOrderPoID"],
|
|
||||||
"jumlahCicilan" => (float) $kontrak["PurchaseOrderAssetContractInstallmentPayAmount"],
|
|
||||||
"keterangan" => "Mode simulasi (dryRun), data tidak disimpan ke database."
|
|
||||||
];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------
|
|
||||||
// Mulai transaksi database
|
|
||||||
// -------------------------------------------------------
|
|
||||||
$this->db->trans_begin();
|
|
||||||
|
|
||||||
// Generate nomor PI otomatis via stored function fn_penomoran
|
// Generate nomor PI otomatis via stored function fn_penomoran
|
||||||
$nomorPI = $this->generateNomorPI($kontrak, $user);
|
$nomorPI = $this->generateNomorPI($kontrak, $user);
|
||||||
if ($nomorPI === false) {
|
|
||||||
$this->db->trans_rollback();
|
|
||||||
$this->sys_error_db("Gagal generate nomor Purchase Invoice untuk kontrak ID " . $kontrak["PurchaseOrderAssetContractID"] . ". Pastikan divisi user sudah diatur.");
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$jumlahCicilan = (float) $kontrak["PurchaseOrderAssetContractInstallmentPayAmount"];
|
$jumlahCicilan = (float) $kontrak["PurchaseOrderAssetContractInstallmentPayAmount"];
|
||||||
$tanggalJatuhTempo = $this->hitungJatuhTempo($endDate, $kontrak["PurchaseOrderPaymentTerm"]);
|
$paymentTerm = isset($kontrak["PurchaseOrderPaymentTerm"]) && $kontrak["PurchaseOrderPaymentTerm"] !== null
|
||||||
|
? (int) $kontrak["PurchaseOrderPaymentTerm"]
|
||||||
|
: 0;
|
||||||
|
$tanggalJatuhTempo = $this->hitungJatuhTempo($endDate, $paymentTerm);
|
||||||
$catatan = "PI Cicilan Otomatis — Kontrak Aset ID " . $kontrak["PurchaseOrderAssetContractID"] . " periode " . date("Y-m", strtotime($startDate));
|
$catatan = "PI Cicilan Otomatis — Kontrak Aset ID " . $kontrak["PurchaseOrderAssetContractID"] . " periode " . date("Y-m", strtotime($startDate));
|
||||||
|
|
||||||
// -------------------------------------------------------
|
// -------------------------------------------------------
|
||||||
@@ -287,39 +242,63 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
: "Cicilan Kontrak Aset ID " . $kontrak["PurchaseOrderAssetContractID"];
|
: "Cicilan Kontrak Aset ID " . $kontrak["PurchaseOrderAssetContractID"];
|
||||||
$deskripsi .= " periode " . date("Y-m", strtotime($startDate));
|
$deskripsi .= " periode " . date("Y-m", strtotime($startDate));
|
||||||
|
|
||||||
$supplierInvoiceID = $this->insertPurchaseInvoice(
|
$payloadInsert = [
|
||||||
$nomorPI,
|
"nomorPI" => $nomorPI,
|
||||||
$kontrak,
|
"tanggalPI" => $endDate,
|
||||||
$endDate,
|
"tanggalJatuhTempo" => $tanggalJatuhTempo,
|
||||||
$tanggalJatuhTempo,
|
"jumlahCicilan" => $jumlahCicilan,
|
||||||
$jumlahCicilan,
|
"catatan" => $catatan,
|
||||||
$catatan,
|
"deskripsi" => $deskripsi,
|
||||||
$deskripsi,
|
"userID" => $userID,
|
||||||
$userID
|
"purchaseOrderAssetContractID" => $kontrak["PurchaseOrderAssetContractID"],
|
||||||
);
|
"purchaseOrderID" => $kontrak["PurchaseOrderID"],
|
||||||
|
"receiveOrderPoID" => $kontrak["PurchaseOrderAssetContractReceiveOrderPoID"],
|
||||||
|
"supplierID" => $kontrak["PurchaseOrderSupplierID"],
|
||||||
|
"purchaseOrderSummaryID" => $kontrak["PurchaseOrderSummaryID"],
|
||||||
|
"purchaseOrderSummaryItemID" => $kontrak["PurchaseOrderSummaryItemID"],
|
||||||
|
"purchaseOrderSummaryItemUnitID" => $kontrak["PurchaseOrderSummaryItemUnitID"]
|
||||||
|
];
|
||||||
|
|
||||||
if ($supplierInvoiceID === false) {
|
$hasilInsert = $this->curlInsertSupplierInvoice($payloadInsert);
|
||||||
$this->db->trans_rollback();
|
if ($hasilInsert === false) {
|
||||||
$this->sys_error_db("Gagal menyimpan Purchase Invoice cicilan untuk kontrak ID " . $kontrak["PurchaseOrderAssetContractID"] . ".");
|
$this->sys_error_db("Gagal menyimpan Purchase Invoice cicilan untuk kontrak ID " . $kontrak["PurchaseOrderAssetContractID"] . ".");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($hasilInsert["duplicate"])) {
|
||||||
|
$dilewati[] = [
|
||||||
|
"kontrakID" => $kontrak["PurchaseOrderAssetContractID"],
|
||||||
|
"purchaseOrderID" => $kontrak["PurchaseOrderID"],
|
||||||
|
"receiveOrderPoID" => $kontrak["PurchaseOrderAssetContractReceiveOrderPoID"],
|
||||||
|
"supplierInvoiceID" => $hasilInsert["supplierInvoiceID"],
|
||||||
|
"nomorInvoice" => $hasilInsert["supplierInvoiceNumber"],
|
||||||
|
"alasan" => "PI cicilan untuk bulan ini sudah dibuat sebelumnya, tidak perlu dibuat ulang."
|
||||||
|
];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$supplierInvoiceID = $hasilInsert["supplierInvoiceID"];
|
||||||
|
|
||||||
// -------------------------------------------------------
|
// -------------------------------------------------------
|
||||||
// UPDATE jumlah cicilan terbayar pada kontrak
|
// UPDATE jumlah cicilan terbayar pada kontrak
|
||||||
// -------------------------------------------------------
|
// -------------------------------------------------------
|
||||||
|
$this->db->trans_begin();
|
||||||
|
|
||||||
$cicilanTerbayarBaru = ((int) $kontrak["PurchaseOrderAssetContractInstallmentPaid"]) + 1;
|
$cicilanTerbayarBaru = ((int) $kontrak["PurchaseOrderAssetContractInstallmentPaid"]) + 1;
|
||||||
$statusKontrakBaru = $cicilanTerbayarBaru >= (int) $kontrak["PurchaseOrderAssetContractInstallmentNumber"]
|
$statusKontrakBaru = $cicilanTerbayarBaru >= (int) $kontrak["PurchaseOrderAssetContractInstallmentNumber"]
|
||||||
? "lunas"
|
? "lunas"
|
||||||
: "belum lunas";
|
: "belum lunas";
|
||||||
|
|
||||||
$sqlUpdateKontrak = "UPDATE purchase_order_asset_contract
|
$sqlUpdateKontrak = "UPDATE purchase_order_asset_contract
|
||||||
SET PurchaseOrderAssetContractInstallmentPaid = ?,
|
SET PurchaseOrderAssetContractReceiveOrderPoID = ?,
|
||||||
|
PurchaseOrderAssetContractInstallmentPaid = ?,
|
||||||
PurchaseOrderAssetContractStatus = ?,
|
PurchaseOrderAssetContractStatus = ?,
|
||||||
PurchaseOrderAssetContractLastUpdated = NOW()
|
PurchaseOrderAssetContractLastUpdated = NOW()
|
||||||
WHERE PurchaseOrderAssetContractID = ?
|
WHERE PurchaseOrderAssetContractID = ?
|
||||||
AND PurchaseOrderAssetContractIsActive = 'Y'";
|
AND PurchaseOrderAssetContractIsActive = 'Y'";
|
||||||
|
|
||||||
$qryUpdateKontrak = $this->db->query($sqlUpdateKontrak, [
|
$qryUpdateKontrak = $this->db->query($sqlUpdateKontrak, [
|
||||||
|
$kontrak["PurchaseOrderAssetContractReceiveOrderPoID"],
|
||||||
$cicilanTerbayarBaru,
|
$cicilanTerbayarBaru,
|
||||||
$statusKontrakBaru,
|
$statusKontrakBaru,
|
||||||
$kontrak["PurchaseOrderAssetContractID"]
|
$kontrak["PurchaseOrderAssetContractID"]
|
||||||
@@ -371,6 +350,60 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kirim payload insert supplier_invoice ke controller terpisah via cURL.
|
||||||
|
*
|
||||||
|
* @param array $payload
|
||||||
|
* @return array|false
|
||||||
|
*/
|
||||||
|
private function curlInsertSupplierInvoice($payload)
|
||||||
|
{
|
||||||
|
$endpoint = rtrim($this->baseUrl, "/") . "/mockup/scheduler/PurchaseInvoiceInstallmentInsert/InsertSupplierInvoice";
|
||||||
|
|
||||||
|
$ch = curl_init($endpoint);
|
||||||
|
curl_setopt_array($ch, [
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
CURLOPT_POST => true,
|
||||||
|
CURLOPT_HTTPHEADER => [
|
||||||
|
"Content-Type: application/json",
|
||||||
|
"Accept: application/json"
|
||||||
|
],
|
||||||
|
CURLOPT_POSTFIELDS => json_encode($payload),
|
||||||
|
CURLOPT_CONNECTTIMEOUT => 15,
|
||||||
|
CURLOPT_TIMEOUT => 120
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
if (curl_errno($ch)) {
|
||||||
|
$pesanError = curl_error($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
$this->sys_error("Gagal menghubungi endpoint insert supplier_invoice. Detail: " . $pesanError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($httpCode < 200 || $httpCode >= 300) {
|
||||||
|
$this->sys_error("Endpoint insert supplier_invoice mengembalikan HTTP " . $httpCode . ".");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$decoded = json_decode($response, true);
|
||||||
|
if (!is_array($decoded)) {
|
||||||
|
$this->sys_error("Response insert supplier_invoice tidak valid JSON.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($decoded["status"]) || strtoupper($decoded["status"]) !== "OK") {
|
||||||
|
$pesan = isset($decoded["message"]) ? $decoded["message"] : "Insert supplier_invoice gagal.";
|
||||||
|
$this->sys_error($pesan);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isset($decoded["data"]) && is_array($decoded["data"]) ? $decoded["data"] : $decoded;
|
||||||
|
}
|
||||||
|
|
||||||
public function ListEligibleContracts()
|
public function ListEligibleContracts()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -397,7 +430,7 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
$sqlKontrak = "SELECT
|
$sqlKontrak = "SELECT
|
||||||
c.PurchaseOrderAssetContractID,
|
c.PurchaseOrderAssetContractID,
|
||||||
c.PurchaseOrderAssetContractPurchaseOrderID,
|
c.PurchaseOrderAssetContractPurchaseOrderID,
|
||||||
c.PurchaseOrderAssetContractReceiveOrderPoID,
|
ro.ReceiveOrderPoID AS PurchaseOrderAssetContractReceiveOrderPoID,
|
||||||
c.PurchaseOrderAssetContractName,
|
c.PurchaseOrderAssetContractName,
|
||||||
c.PurchaseOrderAssetContractStartDate,
|
c.PurchaseOrderAssetContractStartDate,
|
||||||
c.PurchaseOrderAssetContractEndDate,
|
c.PurchaseOrderAssetContractEndDate,
|
||||||
@@ -411,9 +444,7 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
po.PurchaseOrderPaymentTerm,
|
po.PurchaseOrderPaymentTerm,
|
||||||
po.PurchaseOrderWarehouseType,
|
po.PurchaseOrderWarehouseType,
|
||||||
po.PurchaseOrderWarehouseID,
|
po.PurchaseOrderWarehouseID,
|
||||||
ro.ReceiveOrderPoID,
|
ro.ReceiveOrderPoConfirmed,
|
||||||
si_base.SupplierInvoiceID AS BaseSupplierInvoiceID,
|
|
||||||
si_base.SupplierInvoiceNumber AS BaseSupplierInvoiceNumber,
|
|
||||||
ps.PurchaseOrderSummaryID,
|
ps.PurchaseOrderSummaryID,
|
||||||
ps.PurchaseOrderSummaryItemID,
|
ps.PurchaseOrderSummaryItemID,
|
||||||
ps.PurchaseOrderSummaryItemUnitID
|
ps.PurchaseOrderSummaryItemUnitID
|
||||||
@@ -423,26 +454,21 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
AND po.PurchaseOrderIsActive = 'Y'
|
AND po.PurchaseOrderIsActive = 'Y'
|
||||||
AND po.PurchaseOrderStatus = 'Approved'
|
AND po.PurchaseOrderStatus = 'Approved'
|
||||||
|
|
||||||
JOIN receive_order_po ro
|
JOIN (
|
||||||
ON ro.ReceiveOrderPoID = c.PurchaseOrderAssetContractReceiveOrderPoID
|
SELECT
|
||||||
AND ro.ReceiveOrderPoIsActive = 'Y'
|
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
|
||||||
|
|
||||||
JOIN supplier_invoice si_base
|
|
||||||
ON si_base.SupplierInvoiceID = (
|
|
||||||
SELECT MIN(si0.SupplierInvoiceID)
|
|
||||||
FROM supplier_invoice si0
|
|
||||||
WHERE si0.SupplierInvoiceIsActive = 'Y'
|
|
||||||
AND (
|
|
||||||
si0.SupplierInvoiceReceiveOrderPoID = c.PurchaseOrderAssetContractReceiveOrderPoID
|
|
||||||
OR EXISTS (
|
|
||||||
SELECT 1
|
|
||||||
FROM supplier_invoice_detail sid0
|
|
||||||
WHERE sid0.SupplierInvoiceDetailSupplierInvoiceID = si0.SupplierInvoiceID
|
|
||||||
AND sid0.SupplierInvoiceDetailReceiveOrderPoID = c.PurchaseOrderAssetContractReceiveOrderPoID
|
|
||||||
AND sid0.SupplierInvoiceDetailIsActive = 'Y'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
LEFT JOIN (
|
LEFT JOIN (
|
||||||
SELECT ps0.*
|
SELECT ps0.*
|
||||||
FROM purchase_order_summary ps0
|
FROM purchase_order_summary ps0
|
||||||
@@ -466,7 +492,6 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
c.PurchaseOrderAssetContractEndDate IS NULL
|
c.PurchaseOrderAssetContractEndDate IS NULL
|
||||||
OR DATE(c.PurchaseOrderAssetContractEndDate) >= DATE(?)
|
OR DATE(c.PurchaseOrderAssetContractEndDate) >= DATE(?)
|
||||||
)
|
)
|
||||||
AND c.PurchaseOrderAssetContractReceiveOrderPoID > 0
|
|
||||||
AND IFNULL(c.PurchaseOrderAssetContractInstallmentDate, 1) <= ?
|
AND IFNULL(c.PurchaseOrderAssetContractInstallmentDate, 1) <= ?
|
||||||
ORDER BY c.PurchaseOrderAssetContractID ASC";
|
ORDER BY c.PurchaseOrderAssetContractID ASC";
|
||||||
|
|
||||||
@@ -499,254 +524,33 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
* - baseUrl : Base URL server tujuan. Default: URL server ini sendiri.
|
* - baseUrl : Base URL server tujuan. Default: URL server ini sendiri.
|
||||||
* - startDate : Tanggal awal periode (YYYY-MM-DD). Default: awal bulan ini.
|
* - startDate : Tanggal awal periode (YYYY-MM-DD). Default: awal bulan ini.
|
||||||
* - endDate : Tanggal akhir periode (YYYY-MM-DD). Default: akhir bulan ini.
|
* - endDate : Tanggal akhir periode (YYYY-MM-DD). Default: akhir bulan ini.
|
||||||
* - userID : ID user yang menjalankan. Default: 1.
|
* - userID : ID user yang menjalankan. Default: 0.
|
||||||
* - dryRun : "Y" untuk simulasi. Default: "N".
|
|
||||||
* - contractID : (opsional) Filter 1 kontrak tertentu.
|
|
||||||
*/
|
*/
|
||||||
public function CurlGenerateMonthlyInvoices()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$para = $this->sys_input;
|
|
||||||
$baseUrl = isset($para["baseUrl"]) && $para["baseUrl"] != "" ? rtrim($para["baseUrl"], "/") : $this->getBaseUrl();
|
|
||||||
$startDate = isset($para["startDate"]) && $para["startDate"] != "" ? $para["startDate"] : (isset($para["date"]) && $para["date"] != "" ? date("Y-m-01", strtotime($para["date"])) : date("Y-m-01"));
|
|
||||||
$endDate = isset($para["endDate"]) && $para["endDate"] != "" ? $para["endDate"] : (isset($para["date"]) && $para["date"] != "" ? date("Y-m-t", strtotime($para["date"])) : date("Y-m-t"));
|
|
||||||
$userID = isset($para["userID"]) && (int) $para["userID"] > 0 ? (int) $para["userID"] : 1;
|
|
||||||
$dryRun = isset($para["dryRun"]) ? $para["dryRun"] : "N";
|
|
||||||
$contractID = isset($para["contractID"]) && (int) $para["contractID"] > 0 ? (int) $para["contractID"] : null;
|
|
||||||
|
|
||||||
$endpoint = $baseUrl . "/tools/PurchaseInvoiceInstallment/GenerateMonthlyInvoices";
|
|
||||||
|
|
||||||
$payload = [
|
|
||||||
"startDate" => $startDate,
|
|
||||||
"endDate" => $endDate,
|
|
||||||
"userID" => $userID,
|
|
||||||
"dryRun" => $dryRun
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($contractID !== null) {
|
|
||||||
$payload["contractID"] = $contractID;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kirim request ke endpoint GenerateMonthlyInvoices
|
|
||||||
$ch = curl_init($endpoint);
|
|
||||||
curl_setopt_array($ch, [
|
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
|
||||||
CURLOPT_POST => true,
|
|
||||||
CURLOPT_HTTPHEADER => [
|
|
||||||
"Content-Type: application/json",
|
|
||||||
"Accept: application/json"
|
|
||||||
],
|
|
||||||
CURLOPT_POSTFIELDS => json_encode($payload),
|
|
||||||
CURLOPT_CONNECTTIMEOUT => 15, // timeout koneksi: 15 detik
|
|
||||||
CURLOPT_TIMEOUT => 120 // timeout proses: 2 menit
|
|
||||||
]);
|
|
||||||
|
|
||||||
$response = curl_exec($ch);
|
|
||||||
|
|
||||||
if (curl_errno($ch)) {
|
|
||||||
$pesanError = curl_error($ch);
|
|
||||||
curl_close($ch);
|
|
||||||
$this->sys_error("Gagal menghubungi endpoint generate PI cicilan. Detail: " . $pesanError);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
||||||
curl_close($ch);
|
|
||||||
|
|
||||||
$this->sys_ok([
|
|
||||||
"endpoint" => $endpoint,
|
|
||||||
"httpStatus" => $httpCode,
|
|
||||||
"response" => $response
|
|
||||||
]);
|
|
||||||
} catch (Exception $exc) {
|
|
||||||
$this->sys_error($exc->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// FUNGSI PRIVATE / HELPER
|
// FUNGSI PRIVATE / HELPER
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* insertPurchaseInvoice
|
* Generate nomor Purchase Invoice default untuk proses sementara.
|
||||||
*
|
|
||||||
* Menyimpan header Purchase Invoice (supplier_invoice) sekaligus
|
|
||||||
* 1 baris detail-nya (supplier_invoice_detail) dalam satu fungsi.
|
|
||||||
*
|
|
||||||
* Fungsi ini TIDAK mengelola transaksi DB — begin/commit/rollback
|
|
||||||
* tetap menjadi tanggung jawab pemanggil (GenerateMonthlyInvoices).
|
|
||||||
*
|
|
||||||
* @param string $nomorPI Nomor PI yang sudah di-generate
|
|
||||||
* @param array $kontrak Data baris kontrak dari query
|
|
||||||
* @param string $tanggal Tanggal PI (format YYYY-MM-DD)
|
|
||||||
* @param string $tanggalJatuhTempo Tanggal jatuh tempo pembayaran (format YYYY-MM-DD)
|
|
||||||
* @param float $jumlahCicilan Nilai cicilan yang harus dibayar bulan ini
|
|
||||||
* @param string $catatan Catatan / keterangan pada header PI
|
|
||||||
* @param string $deskripsi Deskripsi baris detail PI
|
|
||||||
* @param int $userID ID user yang membuat PI
|
|
||||||
*
|
|
||||||
* @return int|false ID supplier_invoice yang baru dibuat, atau false jika salah satu INSERT gagal
|
|
||||||
*/
|
|
||||||
private function insertPurchaseInvoice($nomorPI, $kontrak, $tanggal, $tanggalJatuhTempo, $jumlahCicilan, $catatan, $deskripsi, $userID)
|
|
||||||
{
|
|
||||||
// -----------------------------------------------------------------
|
|
||||||
// 1. INSERT header ke supplier_invoice
|
|
||||||
// -----------------------------------------------------------------
|
|
||||||
$sqlHeader = "INSERT INTO supplier_invoice (
|
|
||||||
SupplierInvoiceNumber,
|
|
||||||
SupplierInvoicePurchaseOrderID,
|
|
||||||
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, [
|
|
||||||
$nomorPI,
|
|
||||||
$kontrak["PurchaseOrderID"],
|
|
||||||
$kontrak["PurchaseOrderAssetContractReceiveOrderPoID"],
|
|
||||||
$tanggal,
|
|
||||||
$tanggalJatuhTempo,
|
|
||||||
$tanggal, // draft payment date = tanggal PI
|
|
||||||
$kontrak["PurchaseOrderSupplierID"],
|
|
||||||
$kontrak["BaseSupplierInvoiceNumber"], // nomor faktur dasar (tukar faktur)
|
|
||||||
$tanggal, // tanggal faktur supplier = tanggal PI
|
|
||||||
$jumlahCicilan, // subtotal
|
|
||||||
0, // diskon persen
|
|
||||||
0, // diskon rupiah
|
|
||||||
0, // PPh persen
|
|
||||||
0, // PPh nominal
|
|
||||||
0, // PPN persen
|
|
||||||
0, // PPN nominal
|
|
||||||
0, // ongkos kirim
|
|
||||||
0, // penyesuaian
|
|
||||||
null, // catatan penyesuaian
|
|
||||||
$jumlahCicilan, // grand total
|
|
||||||
$jumlahCicilan, // sisa belum terbayar
|
|
||||||
$catatan,
|
|
||||||
"Draft",
|
|
||||||
$userID
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!$qryHeader) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$supplierInvoiceID = $this->db->insert_id();
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------
|
|
||||||
// 2. INSERT 1 baris detail ke supplier_invoice_detail
|
|
||||||
// -----------------------------------------------------------------
|
|
||||||
$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,
|
|
||||||
$kontrak["PurchaseOrderID"],
|
|
||||||
$kontrak["PurchaseOrderAssetContractReceiveOrderPoID"],
|
|
||||||
$kontrak["PurchaseOrderSummaryID"],
|
|
||||||
$kontrak["PurchaseOrderSummaryItemID"],
|
|
||||||
$kontrak["PurchaseOrderSummaryItemUnitID"],
|
|
||||||
$deskripsi,
|
|
||||||
1, // qty = 1 (1 periode cicilan)
|
|
||||||
$jumlahCicilan, // harga satuan = nilai cicilan
|
|
||||||
0, // diskon persen
|
|
||||||
0, // diskon rupiah
|
|
||||||
"R", // tipe diskon: Rupiah
|
|
||||||
0, // prorata PO
|
|
||||||
0, // total diskon
|
|
||||||
$jumlahCicilan, // total baris
|
|
||||||
$jumlahCicilan, // sisa belum terbayar
|
|
||||||
$userID
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!$qryDetail) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $supplierInvoiceID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate nomor Purchase Invoice otomatis menggunakan stored function fn_penomoran.
|
|
||||||
* Nomor PI ditentukan berdasarkan tipe dokumen, divisi user, dan area (branch/regional).
|
|
||||||
*
|
*
|
||||||
* @param array $kontrak Data baris kontrak dari query
|
* @param array $kontrak Data baris kontrak dari query
|
||||||
* @param array $user Data user CRON
|
* @param array $user Data user CRON
|
||||||
* @return string|false Nomor PI yang dihasilkan, atau false jika gagal
|
* @return string Nomor PI yang dihasilkan
|
||||||
*/
|
*/
|
||||||
private function generateNomorPI($kontrak, $user)
|
private function generateNomorPI($kontrak, $user)
|
||||||
{
|
{
|
||||||
// Tentukan tipe area: Regional (R) atau Branch (B)
|
$contractID = isset($kontrak["PurchaseOrderAssetContractID"]) ? (int) $kontrak["PurchaseOrderAssetContractID"] : 0;
|
||||||
$tipeArea = $kontrak["PurchaseOrderWarehouseType"] == "R" ? "R" : "B";
|
$poID = isset($kontrak["PurchaseOrderID"]) ? (int) $kontrak["PurchaseOrderID"] : 0;
|
||||||
$areaID = (int) $kontrak["PurchaseOrderWarehouseID"];
|
$userID = isset($user["M_UserID"]) ? (int) $user["M_UserID"] : 0;
|
||||||
|
|
||||||
// Fallback ke area user jika warehouse PO tidak terisi
|
return sprintf(
|
||||||
if ($areaID <= 0) {
|
"PI-INS-%s-%06d-%05d-%05d",
|
||||||
$areaID = isset($user["M_BranchID"]) ? (int) $user["M_BranchID"] : 0;
|
date("YmdHis"),
|
||||||
if (isset($user["loginLevel"]) && $user["loginLevel"] == "regional") {
|
$contractID,
|
||||||
$tipeArea = "R";
|
$poID,
|
||||||
$areaID = (int) $user["S_RegionalID"];
|
$userID
|
||||||
}
|
);
|
||||||
}
|
|
||||||
|
|
||||||
// Ambil divisi user untuk keperluan penomoran
|
|
||||||
$sqlDivisi = "SELECT M_UserDivisionDivisionID
|
|
||||||
FROM m_userdivision
|
|
||||||
WHERE M_UserDivisionM_UserID = ?
|
|
||||||
AND M_UserDivisionIsActive = 'Y'
|
|
||||||
LIMIT 1";
|
|
||||||
|
|
||||||
$qryDivisi = $this->db->query($sqlDivisi, [$user["M_UserID"]]);
|
|
||||||
if (!$qryDivisi || $qryDivisi->num_rows() == 0) {
|
|
||||||
return false; // User tidak memiliki divisi, nomor PI tidak bisa dibuat
|
|
||||||
}
|
|
||||||
|
|
||||||
$divisiID = $qryDivisi->row_array()["M_UserDivisionDivisionID"];
|
|
||||||
|
|
||||||
// Panggil stored function penomoran untuk mendapatkan nomor PI berikutnya
|
|
||||||
$sqlNomor = "SELECT `fn_penomoran`(?, ?, ?, ?, ?, ?) AS nomorPI";
|
|
||||||
$qryNomor = $this->db->query($sqlNomor, ["PI", $divisiID, $tipeArea, $areaID, "SM", "Y"]);
|
|
||||||
if (!$qryNomor || $qryNomor->num_rows() == 0) {
|
|
||||||
return false; // Stored function tidak mengembalikan hasil
|
|
||||||
}
|
|
||||||
|
|
||||||
return $qryNomor->row_array()["nomorPI"];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -791,7 +595,7 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
*/
|
*/
|
||||||
private function hitungJatuhTempo($tanggal, $term)
|
private function hitungJatuhTempo($tanggal, $term)
|
||||||
{
|
{
|
||||||
$hari = (int) $term;
|
$hari = is_numeric($term) ? (int) $term : 0;
|
||||||
if ($hari < 0) {
|
if ($hari < 0) {
|
||||||
$hari = 0;
|
$hari = 0;
|
||||||
}
|
}
|
||||||
@@ -810,27 +614,4 @@ class PurchaseInvoiceInstallment extends MY_Controller
|
|||||||
$d = DateTime::createFromFormat("Y-m-d", $tanggal);
|
$d = DateTime::createFromFormat("Y-m-d", $tanggal);
|
||||||
return $d && $d->format("Y-m-d") === $tanggal;
|
return $d && $d->format("Y-m-d") === $tanggal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Deteksi base URL server saat ini secara otomatis (HTTP/HTTPS).
|
|
||||||
* Digunakan sebagai fallback pada CurlGenerateMonthlyInvoices.
|
|
||||||
*
|
|
||||||
* @return string Base URL lengkap termasuk path index.php
|
|
||||||
*/
|
|
||||||
private function getBaseUrl()
|
|
||||||
{
|
|
||||||
$scheme = "http";
|
|
||||||
if (
|
|
||||||
(isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] !== "off") ||
|
|
||||||
(isset($_SERVER["SERVER_PORT"]) && (int) $_SERVER["SERVER_PORT"] === 443)
|
|
||||||
) {
|
|
||||||
$scheme = "https";
|
|
||||||
}
|
|
||||||
|
|
||||||
$host = isset($_SERVER["HTTP_HOST"]) && $_SERVER["HTTP_HOST"] != "" ? $_SERVER["HTTP_HOST"] : "localhost";
|
|
||||||
$scriptName = isset($_SERVER["SCRIPT_NAME"]) ? $_SERVER["SCRIPT_NAME"] : "/index.php";
|
|
||||||
$basePath = rtrim(str_replace("/index.php", "", $scriptName), "/");
|
|
||||||
|
|
||||||
return $scheme . "://" . $host . $basePath . "/index.php";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,220 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user