4 Commits

Author SHA1 Message Date
3e5727cc78 fix query insert t barcode barang -> add stock ID 2026-08-06 17:03:28 +07:00
796fa04a37 update readme 2026-07-22 14:15:44 +07:00
a008204865 update readme 2026-07-22 14:05:38 +07:00
5347d89acb fix insert date downpayment dan branchcode receive order asset 2026-07-22 13:37:35 +07:00
6 changed files with 225 additions and 114 deletions

104
README.md
View File

@@ -1,2 +1,106 @@
# be-accone
Backend service for Accone.
---
## Generate Monthly Installments (Cicilan Aset)
Automatically creates `supplier_installment` rows for all eligible active contracts every month. This is designed to be executed via **CRON daily at 1:00 AM**.
> **Note:** No journal entries are created here — that happens at cashier payment time. The contract's `InstallmentPaid` field is also **not** updated here — it's updated when payment is received.
### Endpoint
```
POST /one-api/mockup/scheduler/PurchaseInvoiceInstallment/GenerateMonthlyInvoices
```
### Request
| Field | Value |
|---------------|--------------------|
| **Method** | `POST` |
| **Content-Type** | `application/json` |
| **Body** | `{}` (optional `startDate` / `endDate`) |
```bash
curl -s -X POST "https://accone.aplikasi.web.id/one-api/mockup/scheduler/PurchaseInvoiceInstallment/GenerateMonthlyInvoices" \
-H "Content-Type: application/json" \
-d '{}'
```
**Optional body parameters:**
```json
{
"startDate": "2026-07-01",
"endDate": "2026-07-31"
}
```
If omitted, defaults to the current month (`startDate` = first day, `endDate` = last day).
### Eligibility Logic (Steps 15)
A contract is eligible for installment generation only if **all** of the following conditions are met:
| Step | Condition |
|------|-----------|
| **1** | Contract is **active** (`IsActive = 'Y'`), status is **"belum lunas"**, has a positive `InstallmentPayAmount`, `InstallmentPaid < InstallmentNumber`, falls within the date range, and the scheduled day of month has been reached |
| **2** | Associated **Purchase Order** is **Approved** and **Active** |
| **3** | Associated **Receive Order** is **Confirmed** and **Active** |
| **4** | A parent **Supplier Invoice** exists with `IsInstallment = 'Y'` |
| **5** | No `supplier_installment` record already exists for the same PO in the same month |
### Step 6 — Insert
For each eligible contract, a row is inserted into `supplier_installment` with:
- `SupplierInstallmentStatus` = `"Pending"`
- `SupplierInstallmentIsLunas` = `"N"`
- `SupplierInstallmentDate` = the contract's scheduled day of month (capped to the last day of the month)
- `SupplierInstallmentDueDate` = same as InstallmentDate, can be changed at payment instrutions manu
### Response
```json
{
"status": "OK",
"data": {
"startDate": "2026-07-01",
"endDate": "2026-07-31",
"totalEligible": 1,
"totalInserted": 1,
"created": [
{
"installmentID": 6,
"contractID": "11",
"purchaseOrderID": "20",
"parentInvoiceID": "16",
"parentInvoiceNumber": "PI-016/SDM-14/SM-1/VII/2026",
"amount": 5000000,
"installDate": "2026-07-22",
"dueDate": "2026-07-22"
}
]
}
}
```
| Field | Type | Description |
|-------|------|-------------|
| `status` | `string` | `"OK"` on success |
| `data.startDate` | `string` | Start of the billing period (`YYYY-MM-DD`) |
| `data.endDate` | `string` | End of the billing period (`YYYY-MM-DD`) |
| `data.totalEligible` | `number` | Total contracts that passed eligibility |
| `data.totalInserted` | `number` | Total installments successfully created |
| `data.created` | `array` | List of generated installment records |
| `data.created[].installmentID` | `number` | ID of the created `supplier_installment` row |
| `data.created[].contractID` | `string` | Associated contract ID (`PurchaseOrderAssetContract`) |
| `data.created[].purchaseOrderID` | `string` | Associated purchase order ID |
| `data.created[].parentInvoiceID` | `string` | Source supplier invoice ID |
| `data.created[].parentInvoiceNumber` | `string` | Source supplier invoice number |
| `data.created[].amount` | `number` | Installment amount (IDR) |
| `data.created[].installDate` | `string` | Date the installment is issued |
| `data.created[].dueDate` | `string` | Payment due date (`installDate + 7 days`) |

View File

@@ -786,8 +786,8 @@ class PurchaseOrderAset extends MY_Controller {
$PurchaseOrderID,
$para['supplierID'],
$summary_downpayment ?: 0.00,
$para['contractStart'],
$para['contractStart'],
$para['contractDate'],
$para['contractDate'],
'Draft',
$user['M_UserID'],
$user['M_UserID']

View File

@@ -791,26 +791,28 @@ class ReceiveItemPOAsset extends MY_Controller
// insert table ro #
$sqlInsRO = 'INSERT INTO receive_order_po (
ReceiveOrderPoNumber,
ReceiveOrderPoSupplierID,
ReceiveOrderPoIDate,
ReceiveOrderPoWarehouseID,
ReceiveOrderPoM_BranchCode,
ReceiveOrderPoS_RegionalID,
ReceiveOrderShippingCostAmount,
ReceiveOrderShippingCostIsPaid,
ReceiveOrderPoNote,
ReceiveOrderPoRefNumber,
ReceiveOrderPoDONumber,
ReceiveOrderPoTypePurchase,
ReceiveOrderPoCreatedUserID
) VALUE (?,?,?,?,?,?,?,?,?,?,?,?,?)';
ReceiveOrderPoNumber,
ReceiveOrderPoSupplierID,
ReceiveOrderPoIDate,
ReceiveOrderPoWarehouseID,
ReceiveOrderPoM_BranchCode,
ReceiveOrderPoS_RegionalID,
ReceiveOrderShippingCostAmount,
ReceiveOrderShippingCostIsPaid,
ReceiveOrderPoNote,
ReceiveOrderPoRefNumber,
ReceiveOrderPoDONumber,
ReceiveOrderPoTypePurchase,
ReceiveOrderPoCreatedUserID
)
SELECT ?, ?, ?, ?, b.M_BranchCode, ?, ?, ?, ?, ?, ?, ?, ?
FROM m_branch b
WHERE b.M_BranchID = ?';
$queInsRO = $this->db->query($sqlInsRO, [
$numGR,
$param['supplier'],
$param['date'],
$param['gudangID'],
$user['M_BranchCode'],
$user['S_RegionalID'],
$param['shipping'],
$param['shippingIsPaid'],
@@ -819,6 +821,7 @@ class ReceiveItemPOAsset extends MY_Controller
$param['reference'],
'aset',
$user['M_UserID'],
$param['branchID']
]);
if (!$queInsRO) {
$this->db->trans_rollback();
@@ -958,26 +961,28 @@ class ReceiveItemPOAsset extends MY_Controller
$roID = $param['ReceiveOrderPoID'];
// update receive order header #
$sqlHeader = "UPDATE receive_order_po SET
ReceiveOrderPoNumber = ?,
ReceiveOrderPoSupplierID = ?,
ReceiveOrderPoIDate = ?,
ReceiveOrderPoWarehouseID = ?,
ReceiveOrderPoM_BranchCode = ?,
ReceiveOrderPoS_RegionalID = ?,
ReceiveOrderShippingCostAmount = ?,
ReceiveOrderShippingCostIsPaid = ?,
ReceiveOrderPoNote = ?,
ReceiveOrderPoRefNumber = ?,
ReceiveOrderPoDONumber = ?
WHERE ReceiveOrderPoID = ?
AND ReceiveOrderPoIsActive = 'Y'";
$sqlHeader = "UPDATE receive_order_po r
JOIN m_branch b ON b.M_BranchID = ?
SET
r.ReceiveOrderPoNumber = ?,
r.ReceiveOrderPoSupplierID = ?,
r.ReceiveOrderPoIDate = ?,
r.ReceiveOrderPoWarehouseID = ?,
r.ReceiveOrderPoM_BranchCode = b.M_BranchCode,
r.ReceiveOrderPoS_RegionalID = ?,
r.ReceiveOrderShippingCostAmount = ?,
r.ReceiveOrderShippingCostIsPaid = ?,
r.ReceiveOrderPoNote = ?,
r.ReceiveOrderPoRefNumber = ?,
r.ReceiveOrderPoDONumber = ?
WHERE r.ReceiveOrderPoID = ?
AND r.ReceiveOrderPoIsActive = 'Y'";
$queHeader = $this->db->query($sqlHeader, [
$param['branchID'],
$param['ReceiveOrderPoNumber'],
$param['supplier'],
$param['date'],
$param['gudangID'],
$user['M_BranchCode'],
$user['S_RegionalID'],
$param['shipping'],
$param['shippingIsPaid'],
@@ -1460,7 +1465,7 @@ class ReceiveItemPOAsset extends MY_Controller
$diskon_proratapo = $besarDiskonPO / doubleval($data_po['totalAllPricePO']);
$ratioQty = (intval($elem['ReceiveOrderPoDetailQty']) / intval($elem['QtyAllPO']));
$diskon_prorata_item = round($ratioQty * $diskon_proratapo,2);
$diskon_prorata_item = round($ratioQty * $diskon_proratapo, 2);
$total_diskonpo = round($total_diskonpo + $diskon_prorata_item, 2);
$input_diskon = [$diskon, $diskon_prorata_item];
@@ -1918,33 +1923,6 @@ class ReceiveItemPOAsset extends MY_Controller
'BNP',
$item['ReceiveOrderPoItemID']
);
$sql_insert_barcode = "INSERT INTO t_barcode_barang(
T_BarcodeBarangReceiveOrderPoID,
T_BarcodeBarangReceiveOrderPoDetailID,
T_BarcodeBarangRefType,
T_BarcodeBarangM_ItemID,
T_BarcodeBarangItemUnitID,
T_BarcodeBarangNumber,
T_BarcodeBarangM_RuanganID,
T_BarcodeBarangM_BranchID,
T_BarcodeBarangIsActive,
T_BarcodeBarangUserID,
T_BarcodeBarangCreated
) VALUES(?,?,'PO',?,?,?,?,?,'Y',?,NOW())";
$que_insert_barcode = $this->db->query($sql_insert_barcode, [
$param['receiveOrderPoID'],
$item['ReceiveOrderPoDetailID'],
$item['ReceiveOrderPoItemID'],
$item['ReceiveOrderPoItemUnitID'],
$noBarcode,
$param['ruanganID'],
$user['M_BranchID'],
$user['M_UserID'],
]);
if (!$que_insert_barcode) {
throw new Exception('failed insert into t barcode barang', 1);
}
$barcodeID = $this->db->insert_id();
// check if item already in stock #
$sql_cekstock = "SELECT StockID
@@ -1964,6 +1942,36 @@ class ReceiveItemPOAsset extends MY_Controller
}
$stockID = $que_cekstock->row_array()['StockID'];
$sql_insert_barcode = "INSERT INTO t_barcode_barang(
T_BarcodeBarangStockID,
T_BarcodeBarangReceiveOrderPoID,
T_BarcodeBarangReceiveOrderPoDetailID,
T_BarcodeBarangRefType,
T_BarcodeBarangM_ItemID,
T_BarcodeBarangItemUnitID,
T_BarcodeBarangNumber,
T_BarcodeBarangM_RuanganID,
T_BarcodeBarangM_BranchID,
T_BarcodeBarangIsActive,
T_BarcodeBarangUserID,
T_BarcodeBarangCreated
) VALUES(?,?,?,'PO',?,?,?,?,?,'Y',?,NOW())";
$que_insert_barcode = $this->db->query($sql_insert_barcode, [
$stockID,
$param['receiveOrderPoID'],
$item['ReceiveOrderPoDetailID'],
$item['ReceiveOrderPoItemID'],
$item['ReceiveOrderPoItemUnitID'],
$noBarcode,
$param['ruanganID'],
$user['M_BranchID'],
$user['M_UserID'],
]);
if (!$que_insert_barcode) {
throw new Exception('failed insert into t barcode barang', 1);
}
$barcodeID = $this->db->insert_id();
/* insert into table stock asset */
$sql_stockasset = 'INSERT INTO stock_asset (
StockAssetStockID,

View File

@@ -2693,36 +2693,6 @@ class ReceiveItemPoInventaris extends MY_Controller
# generate barcode number each inventory item #
$noBarcode = $this->generateNoBarcode($user, $param['ruanganID'], 'BNP', $item['ReceiveOrderPoItemID']);
$sql_insert_barcode = "INSERT INTO t_barcode_barang(
T_BarcodeBarangReceiveOrderPoID,
T_BarcodeBarangReceiveOrderPoDetailID,
T_BarcodeBarangRefType,
T_BarcodeBarangM_ItemID,
T_BarcodeBarangItemUnitID,
T_BarcodeBarangNumber,
T_BarcodeBarangM_RuanganID,
T_BarcodeBarangM_BranchID,
T_BarcodeBarangIsActive,
T_BarcodeBarangUserID,
T_BarcodeBarangCreated
) VALUES(?,?,'PO',?,?,?,?,?,'Y',?,NOW())";
$que_insert_barcode = $this->db->query($sql_insert_barcode, [
$param['receiveOrderPoID'],
$item['ReceiveOrderPoDetailID'],
$item['ReceiveOrderPoItemID'],
$item['ReceiveOrderPoItemUnitID'],
$noBarcode,
$param['ruanganID'],
$user['M_BranchID'],
$user['M_UserID']
]);
if (!$que_insert_barcode) {
$this->db->trans_rollback();
$this->sys_error_db("[Error] insert no barcode invetaris");
exit;
}
$barcodeID = $this->db->insert_id();
# check if item already in stock #
$sql_cekstock = "SELECT StockID
@@ -2744,6 +2714,39 @@ class ReceiveItemPoInventaris extends MY_Controller
}
$stockID = $que_cekstock->row_array()['StockID'];
$sql_insert_barcode = "INSERT INTO t_barcode_barang(
T_BarcodeBarangStockID,
T_BarcodeBarangReceiveOrderPoID,
T_BarcodeBarangReceiveOrderPoDetailID,
T_BarcodeBarangRefType,
T_BarcodeBarangM_ItemID,
T_BarcodeBarangItemUnitID,
T_BarcodeBarangNumber,
T_BarcodeBarangM_RuanganID,
T_BarcodeBarangM_BranchID,
T_BarcodeBarangIsActive,
T_BarcodeBarangUserID,
T_BarcodeBarangCreated
) VALUES(?,?,?,'PO',?,?,?,?,?,'Y',?,NOW())";
$que_insert_barcode = $this->db->query($sql_insert_barcode, [
$stockID,
$param['receiveOrderPoID'],
$item['ReceiveOrderPoDetailID'],
$item['ReceiveOrderPoItemID'],
$item['ReceiveOrderPoItemUnitID'],
$noBarcode,
$param['ruanganID'],
$user['M_BranchID'],
$user['M_UserID']
]);
if (!$que_insert_barcode) {
$this->db->trans_rollback();
$this->sys_error_db("[Error] insert no barcode invetaris");
exit;
}
$barcodeID = $this->db->insert_id();
# insert stock inventaris #
$sql_stockinventaris = "INSERT INTO stock_inventory (
StockInventoryStockID,

View File

@@ -98,7 +98,7 @@ class PurchaseInvoiceInstallment extends MY_Controller
$row["SupplierInvoiceID"],
$amount,
$installDate,
$dueDate,
$installDate,
$createdBy
]);

View File

@@ -361,25 +361,25 @@ class PaymentV2 extends MY_Controller
// GET data bayar #
$sql_databayar = "SELECT
CONCAT('Jurnal Payment Invoice Nomor : ',
SupplierPaymentNumber, DATE_FORMAT(now(),
', Tanggal : %d-%m-%Y ')
) AS jurnaltitle,
CONCAT('Nomor pembayaran kasir : ',
SupplierPaymentCashierNumber,
' dan Nomor grup pembayaran : ',
SupplierPaymentGroupNumber
) AS jurnaldesc,
SupplierPaymentNumber AS no_payinv,
SupplierPaymentCashierNumber AS addonvalue,
SupplierPaymentCoaID AS coaID,
coaDescription,
SupplierPaymentAmount AS amount,
SupplierPaymentRounding AS rounding,
(SupplierPaymentAmount + SupplierPaymentRounding) AS bayar
FROM supplier_payment
JOIN coa ON coaID = SupplierPaymentCoaID
WHERE SupplierPaymentID = ?";
CONCAT('Jurnal Payment Invoice Nomor : ',
SupplierPaymentNumber, DATE_FORMAT(now(),
', Tanggal : %d-%m-%Y ')
) AS jurnaltitle,
CONCAT('Nomor pembayaran kasir : ',
SupplierPaymentCashierNumber,
' dan Nomor grup pembayaran : ',
SupplierPaymentGroupNumber
) AS jurnaldesc,
SupplierPaymentNumber AS no_payinv,
SupplierPaymentCashierNumber AS addonvalue,
SupplierPaymentCoaID AS coaID,
coaDescription,
SupplierPaymentAmount AS amount,
SupplierPaymentRounding AS rounding,
(SupplierPaymentAmount + SupplierPaymentRounding) AS bayar
FROM supplier_payment
JOIN coa ON coaID = SupplierPaymentCoaID
WHERE SupplierPaymentID = ?";
$que_databayar = $this->db->query($sql_databayar, [$param['orderid']]);
if (!$que_databayar) {
$this->db->trans_rollback();
@@ -441,10 +441,6 @@ class PaymentV2 extends MY_Controller
];
}
// "PI Cicilan Aset - {$invoiceNumber}";
$description = '';
// "Jurnal cicilan ke-{$cicilanKe} dari {$totalCicilan} | {$namaKontrak} | PO: {$nomorPO} | Periode {$periode}";
switch ($param['type']) {
case 'DP':
$data_bayar['jurnaltitle'] .= " | Pembayaran Uang Muka Aset - {$param['dpkode']}";