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
|
||||
Content-Type: application/json
|
||||
# =============================================================================
|
||||
# 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
|
||||
# =============================================================================
|
||||
|
||||
{
|
||||
"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
|
||||
POST {{host}}/mockup/scheduler/JurnalPiCicilanOrderAset/ListEligiblePurchaseOrderAssetContracts
|
||||
### 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}}",
|
||||
"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)
|
||||
* - Referensi ke jurnalID header
|
||||
* - COA (Chart of Account) dan deskripsinya:
|
||||
* * Sisi hutang cicilan → nilai DEBIT
|
||||
* * Sisi pembayaran cicilan → nilai KREDIT
|
||||
* * 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: "PICICIL"), addonValue, mItemID
|
||||
* - Berisi: addonCode (default: "PIINSTALMENT"), addonValue, mItemID
|
||||
*
|
||||
* Endpoint:
|
||||
* POST /mockup/scheduler/JurnalPiCicilanOrderAset/CreateJournal
|
||||
* POST /mockup/scheduler/JurnalPiCicilanOrderAset/CreatePiInstallmentJournal
|
||||
* POST /mockup/scheduler/JurnalPiCicilanOrderAset/GenerateJournalsFromContracts
|
||||
* GET /mockup/scheduler/JurnalPiCicilanOrderAset/ListEligiblePurchaseOrderAssetContracts
|
||||
*/
|
||||
class JurnalPiCicilanOrderAset extends MY_Controller
|
||||
@@ -74,7 +74,7 @@ class JurnalPiCicilanOrderAset extends MY_Controller
|
||||
* 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: "PICICIL")
|
||||
* - jurnalAddOnCode : kode addon (default: "PIINSTALMENT")
|
||||
* - jurnalAddOnValue : nilai tambahan (misal: nomor PI/kontrak)
|
||||
* - jurnalAddOnM_ItemID : ID item aset yang terkait
|
||||
*
|
||||
@@ -90,7 +90,7 @@ class JurnalPiCicilanOrderAset extends MY_Controller
|
||||
* - credit : Nilai kredit (pembayaran cicilan).
|
||||
* - addonValue : (opsional) Nilai addon, misal nomor PI.
|
||||
* - 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.
|
||||
* - regionalID : (opsional) ID regional. 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.");
|
||||
}
|
||||
|
||||
$userID = isset($para["userID"]) ? (int) $para["userID"] : 0;
|
||||
$jurnalNo = $this->generateJournalNumber();
|
||||
if ($jurnalNo === false || $jurnalNo == "") {
|
||||
throw new Exception("Gagal generate nomor jurnal.");
|
||||
}
|
||||
$userID = 0;
|
||||
|
||||
// Validasi balance: total debit harus sama dengan total credit
|
||||
$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) {
|
||||
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,
|
||||
$result = $this->insertJournal(
|
||||
$date,
|
||||
$branchCode,
|
||||
$periodeID,
|
||||
$jurnalNo,
|
||||
$title,
|
||||
$description,
|
||||
$date,
|
||||
$details,
|
||||
$periodeID,
|
||||
$regionalID,
|
||||
$branchCompanyID,
|
||||
$jurnalTypeID,
|
||||
$userID
|
||||
]);
|
||||
if (!$qryHeader) {
|
||||
$this->db->trans_rollback();
|
||||
$this->sys_error_db("Gagal insert jurnal header.");
|
||||
);
|
||||
|
||||
if ($result === false) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$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));
|
||||
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
|
||||
]);
|
||||
$this->sys_ok($result);
|
||||
} catch (Exception $exc) {
|
||||
$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
|
||||
* pembuatan jurnal PI cicilan order aset. Memanggil CreateJournal secara langsung.
|
||||
* Fungsi ini mengintegrasikan data dari getEligiblePurchaseOrderAssetContracts()
|
||||
* 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
|
||||
* yang memenuhi syarat untuk dibuatkan jurnal PI cicilan pada periode tertentu.
|
||||
@@ -390,6 +463,195 @@ class JurnalPiCicilanOrderAset extends MY_Controller
|
||||
// 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.
|
||||
*
|
||||
@@ -553,9 +815,12 @@ class JurnalPiCicilanOrderAset extends MY_Controller
|
||||
mi.M_ItemFa_ClassID,
|
||||
fc.Fa_ClassID AS ItemFaClassID,
|
||||
fc.Fa_ClassName AS ItemFaClassName,
|
||||
fc.Fa_ClassCoaID AS ItemCoaID,
|
||||
fc.Fa_ClassCoaAccountNo AS ItemCoaAccountNo,
|
||||
fc.Fa_ClassCoaDesc AS ItemCoaDesc,
|
||||
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,
|
||||
@@ -625,6 +890,14 @@ class JurnalPiCicilanOrderAset extends MY_Controller
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user