gabungkan fungsi get data dengan create jurnal
This commit is contained in:
@@ -1,42 +1,92 @@
|
|||||||
@host = https://accone.aplikasi.web.id/one-api/
|
@host = https://accone.aplikasi.web.id/one-api
|
||||||
|
@date = 2026-07-14
|
||||||
|
@coaBayarID = 1110100001
|
||||||
|
@coaHutangID = 2110100030
|
||||||
|
|
||||||
### Create jurnal PI cicilan order aset
|
# =============================================================================
|
||||||
POST {{host}}/mockup/scheduler/JurnalPiCicilanOrderAset/CreateJournal
|
# JurnalPiCicilanOrderAset — Contoh Pemanggilan Endpoint
|
||||||
Content-Type: application/json
|
# =============================================================================
|
||||||
|
# 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
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
{
|
|
||||||
"date": "2026-07-14",
|
|
||||||
"branchCode": "BA",
|
|
||||||
"regionalID": 8,
|
|
||||||
"branchCompanyID": 1,
|
|
||||||
"jurnalTypeID": 11,
|
|
||||||
"title": "Jurnal PI Cicilan Order Aset",
|
|
||||||
"description": "Pembuatan jurnal PI cicilan order aset",
|
|
||||||
"userID": 0,
|
|
||||||
"details": [
|
|
||||||
{
|
|
||||||
"coaID": 2110100030,
|
|
||||||
"description": "Hutang cicilan",
|
|
||||||
"debit": 15000000,
|
|
||||||
"credit": 0,
|
|
||||||
"addonCode": "PICICIL",
|
|
||||||
"addonValue": "PI-INS-202607140001",
|
|
||||||
"mItemID": 123
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"coaID": 1110100001,
|
|
||||||
"description": "Cicilan",
|
|
||||||
"debit": 0,
|
|
||||||
"credit": 15000000
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
### List eligible purchase order asset contracts
|
### 1. Lihat kontrak aset yang eligible untuk dibuatkan jurnal bulan ini
|
||||||
POST {{host}}/mockup/scheduler/JurnalPiCicilanOrderAset/ListEligiblePurchaseOrderAssetContracts
|
GET {{host}}/index.php/mockup/scheduler/JurnalPiCicilanOrderAset/ListEligiblePurchaseOrderAssetContracts
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
{
|
{
|
||||||
"startDate": "2026-07-01",
|
"startDate": "2026-07-01",
|
||||||
"endDate": "2026-07-31"
|
"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}}",
|
||||||
|
"coaBayarID" : {{coaBayarID}},
|
||||||
|
"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}}",
|
||||||
|
"coaBayarID" : {{coaBayarID}},
|
||||||
|
"dryRun" : "N",
|
||||||
|
"contractID" : 99
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
### 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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,15 +15,15 @@
|
|||||||
* 3. Insert baris transaksi ke tabel `jurnal_tx` (untuk setiap baris cicilan)
|
* 3. Insert baris transaksi ke tabel `jurnal_tx` (untuk setiap baris cicilan)
|
||||||
* - Referensi ke jurnalID header
|
* - Referensi ke jurnalID header
|
||||||
* - COA (Chart of Account) dan deskripsinya:
|
* - COA (Chart of Account) dan deskripsinya:
|
||||||
* * Sisi hutang cicilan → nilai DEBIT
|
* * Sisi hutang cicilan → nilai DEBIT (diambil dari HutangCoaID di fa_class)
|
||||||
* * Sisi pembayaran cicilan → nilai KREDIT
|
* * Sisi pembayaran cicilan → nilai KREDIT (diambil dari ItemCoaID di fa_class)
|
||||||
* 4. Insert data tambahan ke tabel `jurnal_addon` (jika ada addonValue atau mItemID)
|
* 4. Insert data tambahan ke tabel `jurnal_addon` (jika ada addonValue atau mItemID)
|
||||||
* - Referensi ke jurnalID dan jurnalTxID
|
* - Referensi ke jurnalID dan jurnalTxID
|
||||||
* - Berisi: addonCode (default: "PICICIL"), addonValue, mItemID
|
* - Berisi: addonCode (default: "PIINSTALMENT"), addonValue, mItemID
|
||||||
*
|
*
|
||||||
* Endpoint:
|
* Endpoint:
|
||||||
* POST /mockup/scheduler/JurnalPiCicilanOrderAset/CreateJournal
|
* POST /mockup/scheduler/JurnalPiCicilanOrderAset/CreateJournal
|
||||||
* POST /mockup/scheduler/JurnalPiCicilanOrderAset/CreatePiInstallmentJournal
|
* POST /mockup/scheduler/JurnalPiCicilanOrderAset/GenerateJournalsFromContracts
|
||||||
* GET /mockup/scheduler/JurnalPiCicilanOrderAset/ListEligiblePurchaseOrderAssetContracts
|
* GET /mockup/scheduler/JurnalPiCicilanOrderAset/ListEligiblePurchaseOrderAssetContracts
|
||||||
*/
|
*/
|
||||||
class JurnalPiCicilanOrderAset extends MY_Controller
|
class JurnalPiCicilanOrderAset extends MY_Controller
|
||||||
@@ -74,7 +74,7 @@ class JurnalPiCicilanOrderAset extends MY_Controller
|
|||||||
* 10. Jika ada addonValue atau mItemID, INSERT ke `jurnal_addon`:
|
* 10. Jika ada addonValue atau mItemID, INSERT ke `jurnal_addon`:
|
||||||
* - jurnalAddOnJurnalID : referensi ke header jurnal
|
* - jurnalAddOnJurnalID : referensi ke header jurnal
|
||||||
* - jurnalAddOnJurnalTxID: referensi ke baris jurnal_tx
|
* - jurnalAddOnJurnalTxID: referensi ke baris jurnal_tx
|
||||||
* - jurnalAddOnCode : kode addon (default: "PICICIL")
|
* - jurnalAddOnCode : kode addon (default: "PIINSTALMENT")
|
||||||
* - jurnalAddOnValue : nilai tambahan (misal: nomor PI/kontrak)
|
* - jurnalAddOnValue : nilai tambahan (misal: nomor PI/kontrak)
|
||||||
* - jurnalAddOnM_ItemID : ID item aset yang terkait
|
* - jurnalAddOnM_ItemID : ID item aset yang terkait
|
||||||
*
|
*
|
||||||
@@ -90,7 +90,7 @@ class JurnalPiCicilanOrderAset extends MY_Controller
|
|||||||
* - credit : Nilai kredit (pembayaran cicilan).
|
* - credit : Nilai kredit (pembayaran cicilan).
|
||||||
* - addonValue : (opsional) Nilai addon, misal nomor PI.
|
* - addonValue : (opsional) Nilai addon, misal nomor PI.
|
||||||
* - mItemID : (opsional) ID item aset.
|
* - mItemID : (opsional) ID item aset.
|
||||||
* - addonCode : (opsional) Kode addon. Default: "PICICIL".
|
* - addonCode : (opsional) Kode addon. Default: "PIINSTALMENT".
|
||||||
* - periodeID : (opsional) ID periode. Default: diambil dari tanggal.
|
* - periodeID : (opsional) ID periode. Default: diambil dari tanggal.
|
||||||
* - regionalID : (opsional) ID regional. Default: diambil dari branchCode.
|
* - regionalID : (opsional) ID regional. Default: diambil dari branchCode.
|
||||||
* - branchCompanyID: (opsional) ID branch company. Default: diambil dari branchCode.
|
* - branchCompanyID: (opsional) ID branch company. Default: diambil dari branchCode.
|
||||||
@@ -158,180 +158,253 @@ class JurnalPiCicilanOrderAset extends MY_Controller
|
|||||||
throw new Exception("jurnalTypeID / jurnalTypeCode tidak valid.");
|
throw new Exception("jurnalTypeID / jurnalTypeCode tidak valid.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$userID = isset($para["userID"]) ? (int) $para["userID"] : 0;
|
$userID = 0;
|
||||||
$jurnalNo = $this->generateJournalNumber();
|
|
||||||
if ($jurnalNo === false || $jurnalNo == "") {
|
|
||||||
throw new Exception("Gagal generate nomor jurnal.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validasi balance: total debit harus sama dengan total credit
|
$result = $this->insertJournal(
|
||||||
$totalDebit = 0;
|
$date,
|
||||||
$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) {
|
|
||||||
throw new Exception("Nilai debit/credit tidak boleh negatif pada detail ke-" . ($idx + 1));
|
|
||||||
}
|
|
||||||
$totalDebit += $debit;
|
|
||||||
$totalCredit += $credit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (round($totalDebit, 2) !== round($totalCredit, 2)) {
|
|
||||||
throw new Exception("Total debit dan credit harus sama. Debit={$totalDebit}, Credit={$totalCredit}");
|
|
||||||
}
|
|
||||||
|
|
||||||
$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,
|
$branchCode,
|
||||||
$periodeID,
|
|
||||||
$jurnalNo,
|
|
||||||
$title,
|
$title,
|
||||||
$description,
|
$description,
|
||||||
$date,
|
$details,
|
||||||
|
$periodeID,
|
||||||
|
$regionalID,
|
||||||
|
$branchCompanyID,
|
||||||
$jurnalTypeID,
|
$jurnalTypeID,
|
||||||
$userID
|
$userID
|
||||||
]);
|
);
|
||||||
if (!$qryHeader) {
|
|
||||||
$this->db->trans_rollback();
|
if ($result === false) {
|
||||||
$this->sys_error_db("Gagal insert jurnal header.");
|
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$jurnalID = $this->db->insert_id();
|
$this->sys_ok($result);
|
||||||
$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));
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sisi debit = hutang cicilan (COA hutang)
|
|
||||||
// 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));
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$jurnalTxID = $this->db->insert_id();
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------
|
|
||||||
// INSERT data tambahan ke tabel `jurnal_addon` (jika ada)
|
|
||||||
// Diisi jika ada addonValue (misal nomor PI) atau mItemID (ID aset)
|
|
||||||
// -----------------------------------------------------------------
|
|
||||||
$addonValue = isset($detail["addonValue"]) ? trim($detail["addonValue"]) : "";
|
|
||||||
$mItemID = isset($detail["mItemID"]) ? (int) $detail["mItemID"] : 0;
|
|
||||||
$addonCode = isset($detail["addonCode"]) && $detail["addonCode"] != "" ? trim($detail["addonCode"]) : "PICICIL";
|
|
||||||
|
|
||||||
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));
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
$createdAddonCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->db->trans_status() === false) {
|
|
||||||
$this->db->trans_rollback();
|
|
||||||
$this->sys_error_db("Transaksi jurnal gagal.");
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->db->trans_commit();
|
|
||||||
|
|
||||||
$this->sys_ok([
|
|
||||||
"jurnalID" => $jurnalID,
|
|
||||||
"jurnalNo" => $jurnalNo,
|
|
||||||
"detailCount" => count($details),
|
|
||||||
"addonCount" => $createdAddonCount
|
|
||||||
]);
|
|
||||||
} catch (Exception $exc) {
|
} catch (Exception $exc) {
|
||||||
$this->sys_error($exc->getMessage());
|
$this->sys_error($exc->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CreatePiInstallmentJournal — Alias dari CreateJournal.
|
* GenerateJournalsFromContracts — Generate jurnal otomatis dari seluruh kontrak aset eligible.
|
||||||
*
|
*
|
||||||
* Endpoint alternatif dengan nama yang lebih spesifik untuk konteks
|
* Fungsi ini mengintegrasikan data dari getEligiblePurchaseOrderAssetContracts()
|
||||||
* pembuatan jurnal PI cicilan order aset. Memanggil CreateJournal secara langsung.
|
* dengan proses pembuatan jurnal (insertJournal()) secara otomatis.
|
||||||
*
|
*
|
||||||
* @see CreateJournal()
|
* 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 CreatePiInstallmentJournal()
|
public function GenerateJournalsFromContracts()
|
||||||
{
|
{
|
||||||
$this->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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$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));
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
"jumlah" => $jumlah,
|
||||||
|
"coaHutangID" => $coaHutangID,
|
||||||
|
"coaBayarID" => $coaBayarID,
|
||||||
|
"keterangan" => "Mode simulasi (dryRun), data tidak disimpan."
|
||||||
|
];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Susun title dan description jurnal
|
||||||
|
$title = "PI Cicilan Aset - {$nomorPO}";
|
||||||
|
$description = "Jurnal cicilan ke-{$cicilanKe} dari {$totalCicilan} | {$namaKontrak} | 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("PAYMENT");
|
||||||
|
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" => (string) $contractID,
|
||||||
|
"mItemID" => $itemID,
|
||||||
|
"addonCode" => "PIINSTALMENT"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"coaID" => $coaBayarID,
|
||||||
|
"description" => $descBayar,
|
||||||
|
"debit" => 0,
|
||||||
|
"credit" => $jumlah,
|
||||||
|
"addonValue" => (string) $contractID,
|
||||||
|
"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
|
* ListEligiblePurchaseOrderAssetContracts — Menampilkan daftar kontrak aset
|
||||||
* yang memenuhi syarat untuk dibuatkan jurnal PI cicilan pada periode tertentu.
|
* yang memenuhi syarat untuk dibuatkan jurnal PI cicilan pada periode tertentu.
|
||||||
@@ -390,6 +463,195 @@ class JurnalPiCicilanOrderAset extends MY_Controller
|
|||||||
// FUNGSI PRIVATE / HELPER
|
// 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.
|
* generateJournalNumber — Generate nomor jurnal otomatis.
|
||||||
*
|
*
|
||||||
@@ -553,9 +815,12 @@ class JurnalPiCicilanOrderAset extends MY_Controller
|
|||||||
mi.M_ItemFa_ClassID,
|
mi.M_ItemFa_ClassID,
|
||||||
fc.Fa_ClassID AS ItemFaClassID,
|
fc.Fa_ClassID AS ItemFaClassID,
|
||||||
fc.Fa_ClassName AS ItemFaClassName,
|
fc.Fa_ClassName AS ItemFaClassName,
|
||||||
fc.Fa_ClassCoaID AS ItemCoaID,
|
coa_bayar.coaID AS ItemCoaID,
|
||||||
fc.Fa_ClassCoaAccountNo AS ItemCoaAccountNo,
|
coa_bayar.coaAccountNo AS ItemCoaAccountNo,
|
||||||
fc.Fa_ClassCoaDesc AS ItemCoaDesc,
|
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_BranchCode,
|
||||||
m_branch.M_BranchName,
|
m_branch.M_BranchName,
|
||||||
m_branch.M_BranchS_RegionalID,
|
m_branch.M_BranchS_RegionalID,
|
||||||
@@ -625,6 +890,14 @@ class JurnalPiCicilanOrderAset extends MY_Controller
|
|||||||
ON fc.Fa_ClassID = mi.M_ItemFa_ClassID
|
ON fc.Fa_ClassID = mi.M_ItemFa_ClassID
|
||||||
AND fc.Fa_ClassIsActive = 'Y'
|
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'
|
WHERE c.PurchaseOrderAssetContractIsActive = 'Y'
|
||||||
AND c.PurchaseOrderAssetContractStatus = 'belum lunas'
|
AND c.PurchaseOrderAssetContractStatus = 'belum lunas'
|
||||||
-- Hanya kontrak yang ada nilai cicilannya
|
-- Hanya kontrak yang ada nilai cicilannya
|
||||||
|
|||||||
Reference in New Issue
Block a user