<?php

class PurchaseOrderV2 extends MY_Controller
{
    var $db;

    public function index()
    {
        echo "Purchase Order API";
    }

    public function __construct()
    {
        parent::__construct();
    }

    function search()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
            }
            $payload = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];
            $approveLevelID = $this->sys_user['M_UserM_ApproveLevelID'];
            $flag = $payload['flag'];

            if ($approveLevelID == '1') {
                if ($flag == 'G') {
                    $sqlPurchaseOrder = " AND po.PurchaseOrderApprovedManagerUserID = 0";
                }
            } else if ($approveLevelID == '2') {
                if ($flag == 'G') {
                    $sqlPurchaseOrder = " AND po.PurchaseOrderApprovedUserID IS NULL";
                }
            }

            $query = "SELECT po.*,
            CASE 
                WHEN po.PurchaseOrderDiscountPercent = 0 THEN 'Absolute'
                WHEN po.PurchaseOrderDiscountAmount = 0 THEN 'Percentage'
                    ELSE '' 
                END AS DiscountType,
            CASE 
                WHEN po.PurchaseOrderDiscountPercent <> 0 THEN (po.PurchaseOrderDiscountPercent / 100) * PurchaseOrderSubTotal
                WHEN po.PurchaseOrderDiscountAmount <> 0 THEN PurchaseOrderDiscountAmount
                    ELSE '' 
                END AS DiscountAmount,
            PurchaseOrderTaxAmountPph + PurchaseOrderTaxAmountPpn AS TaxAmount,
            DATE_FORMAT(PurchaseOrderDate, '%d %M %Y') AS DisplayDate,
            SupplierCode,
            SupplierName,
            WarehouseCode,
            IFNULL(itemCategoryID, '') as itemCategoryID,
            IFNULL(itemCategoryName, '') as itemCategoryName,
            CASE
                WHEN WarehouseType = 'B' THEN CONCAT(WarehouseCode,' ', WarehouseName, ' - ', M_BranchName) 
                WHEN WarehouseType = 'R' THEN CONCAT(WarehouseCode,' ', WarehouseName, ' - ', S_RegionalName) 
                ELSE ''
            END as WarehouseName
            FROM purchase_order po
            JOIN item_category ON PurchaseOrderItemCategoryID = itemCategoryID 
                AND itemCategoryID = 1
            LEFT JOIN supplier ON SupplierID = PurchaseOrderSupplierID 
            LEFT JOIN warehouse ON WarehouseID = PurchaseOrderWarehouseID
            LEFT JOIN s_regional ON S_RegionalID = WarehouseS_RegionalID
            LEFT JOIN m_branch ON M_BranchID = WarehouseM_BranchID
            WHERE po.PurchaseOrderIsActive = 'Y'
            $sqlPurchaseOrder
            AND (PurchaseOrderNumber LIKE '%" . $payload["search"] . "%')";

            $queryCount = "SELECT count(*) as total
                FROM purchase_order po
                JOIN item_category ON PurchaseOrderItemCategoryID = itemCategoryID
                    AND itemCategoryID = 1
                WHERE PurchaseOrderIsActive = 'Y'
                    $sqlPurchaseOrder
                AND (PurchaseOrderNumber LIKE '%" . $payload["search"] . "%')";

            if ((isset($payload["startDate"]) && isset($payload["endDate"])) && (trim($payload["startDate"]) !== "" && trim($payload["endDate"]) !== "")) {
                $query .= " AND (PurchaseOrderDate BETWEEN '{$payload["startDate"]}' AND '{$payload["endDate"]}')";
                $queryCount .= " AND (PurchaseOrderDate BETWEEN '{$payload["startDate"]}' AND '{$payload["endDate"]}')";
            }

            if ($payload["status"] !== 'All') {
                $query .= " AND PurchaseOrderStatus = '{$payload["status"]}'";
                $queryCount .= " AND PurchaseOrderStatus = '{$payload["status"]}'";
            }

            $exec = $this->db->query($queryCount, []);

            $numberLimit = 20;
            $numberOffset = 0;
            if ($payload["currentPage"] > 0) {
                $numberOffset = ($payload["currentPage"] - 1) * $numberLimit;
            }

            $totalCount = 0;
            $totalPage = 0;

            if ($exec) {
                $totalCount = $exec->result_array()[0]["total"];
                $totalPage = ceil($totalCount / $numberLimit);
            } else {
                $this->db->trans_rollback();
                $this->sys_error_db("select purchase order", $this->db);
                exit;
            }

            $query .= " ORDER BY  PurchaseOrderDate DESC, PurchaseOrderNumber DESC
                       LIMIT {$numberLimit} OFFSET {$numberOffset}";
            $exec = $this->db->query($query, []);

            if ($exec) {
                $rows = $exec->result_array();
            } else {
                $this->db->trans_rollback();
                $this->sys_error_db("select purchase order", $this->db);
                exit;
            }

            // Untuk setiap baris tambahakan Total Real Price dan Total Diskon Per Item
            // Agar tidak misleading dengan Jurnal Penerimaan Barang dan Faktur
            foreach ($rows as $key => $row) {
                $rows[$key]['TotalRealPrice'] = 0;
                $rows[$key]['TotalDiskonPerItem'] = 0;

                // Hitung Total Real Price
                $sql = "SELECT PurchaseOrderSummaryPurchaseOrderID, 
                        SUM(PurchaseOrderSummaryQty * PurchaseOrderSummaryPrice) AS TotalRealPrice,
                        SUM(PurchaseOrderSummaryQty * PurchaseOrderSummaryDiscountAmount) AS TotalDiskonPerItem
                        FROM purchase_order_summary
                        WHERE PurchaseOrderSummaryPurchaseOrderID = ?";
                $qry = $this->db->query($sql, [$row['PurchaseOrderID']]);
                if ($qry) {
                    $summaryRow = $qry->row_array();
                    $rows[$key]['TotalRealPrice'] = floatval($summaryRow['TotalRealPrice']);
                    $rows[$key]['TotalDiskonPerItem'] = floatval($summaryRow['TotalDiskonPerItem']);
                } else {
                    $rows[$key]['TotalRealPrice'] = 0;
                    $rows[$key]['TotalDiskonPerItem'] = 0;
                    $this->db->trans_rollback();
                    $this->sys_error_db("select purchase order", $this->db);
                    exit;
                }
            }

            $result = array(
                "totalPage" => $totalPage,
                "totalFilter" => $totalCount,
                "records" => $rows,
                "sql" => $this->db->last_query()
            );

            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    function getSupplier()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }

            $payload = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];

            $search = '%%';
            if (isset($payload['search'])) {
                $search = trim($payload["search"]);
                if ($search != "") {
                    $search = '%' . $search . '%';
                } else {
                    $search = '%%';
                }
            }

            $sql = "SELECT SupplierID,
                    SupplierCode,
                    SupplierName
                    FROM supplier
                    WHERE SupplierIsActive = 'Y'
                    AND SupplierName LIKE '{$search}'
                    ORDER BY SupplierName ASC ";
            $qry = $this->db->query($sql, []);
            if (!$qry) {
                $this->db->trans_rollback();
                $this->sys_error_db("select supplier", $this->db);;
                exit;
            }

            $rows = $qry->result_array();

            $result = array(
                "records" => $rows,
                "sql" => $this->db->last_query()
            );

            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }
    function getItemCategory()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }

            $payload = $this->sys_input;


            $sql = "SELECT * FROM item_category 
            WHERE ItemCategoryIsActive = 'Y' AND itemCategoryID = '1'";
            $qry = $this->db->query($sql, []);
            if (!$qry) {
                $this->db->trans_rollback();
                $this->sys_error_db("select supplier", $this->db);;
                exit;
            }

            $rows = $qry->result_array();

            $result = array(
                "records" => $rows,
                "sql" => $this->db->last_query()
            );

            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    function getWarehouse()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }

            $payload = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];
            $regionalId = $payload["regionalId"];
            $categoryID = $payload['categoryID'];

            $search = '%%';
            if (isset($payload['search'])) {
                $search = trim($payload["search"]);
                if ($search != "") {
                    $search = '%' . $search . '%';
                } else {
                    $search = '%%';
                }
            }

            $isRegional = "X";
            if ($categoryID == '1') {
                $isRegional = 'R';
            }

            $sql = "SELECT 
                    WarehouseID,
                    WarehouseCode,
                    CASE
                        WHEN WarehouseType = 'B' THEN CONCAT(WarehouseCode,' ', WarehouseName, ' - ', M_BranchName) 
                        WHEN WarehouseType = 'R' THEN CONCAT(WarehouseCode,' ', WarehouseName, ' - ', S_RegionalName) 
                    ELSE ''
                    END WarehouseName,
                    WarehouseType,
                    WarehouseIsDefault,
                    WarehouseS_RegionalID,
                    WarehouseM_BranchID,
                    S_RegionalID,
                    S_RegionalName
                    FROM warehouse
                    JOIN s_regional ON WarehouseS_RegionalID = S_RegionalID AND S_RegionalIsActive = 'Y'
                    LEFT JOIN m_branch ON WarehouseM_BranchID = M_BranchID AND M_BranchIsActive = 'Y'
                    where WarehouseS_RegionalID = ?
                        AND WarehouseIsActive = 'Y'
                        AND WarehouseIsTransit = 'N'
                        AND (WarehouseType = ? OR ? = 'X')
                    ORDER BY WarehouseID ASC ";
            $qry = $this->db->query($sql, [$regionalId, $isRegional, $isRegional]);
            if (!$qry) {
                $this->db->trans_rollback();
                $this->sys_error_db("select warehouse", $this->db);;
                exit;
            }

            $rows = $qry->result_array();

            $result = array(
                "records" => $rows,
                "sql" => $this->db->last_query()
            );

            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    function getItem()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
            }

            $regionalId = $this->sys_user["S_RegionalID"];
            $payload = $this->sys_input;
            $itemCategoryID = $payload['itemCategoryID'];
            $supplierID = $payload['supplierID'];

            $search = '%%';
            if (isset($payload['search'])) {
                $search = trim($payload["search"]);
                if ($search != "") {
                    $search = '%' . $search . '%';
                } else {
                    $search = '%%';
                }
            }

            if (!isset($supplierID)) {
                $this->sys_error("Supplier ID is required");
                exit;
            }

            $numberLimit = 10;
            $numberOffset = 0;
            if (isset($payload["currentPage"]) && $payload["currentPage"] > 0) {
                $numberOffset = ($payload["currentPage"] - 1) * $numberLimit;
            }

            $countSql = "SELECT COUNT(*) as total
                FROM purchase_request_flag prf
                JOIN purchase_request_detail prd ON prf.PurchaseRequestFlagPurchaseRequestDetailID = prd.PurchaseRequestDetailID 
                JOIN m_item mi ON prd.PurchaseRequestDetailM_ItemID = mi.M_ItemID AND mi.M_ItemDesc LIKE ? AND mi.M_ItemItem_CategoryID = ?
                JOIN supplier_price sp ON mi.M_ItemID = sp.SupplierPriceM_ItemID AND sp.SupplierPriceSupplierID = ? AND sp.SupplierPriceIsActive = 'Y'
                WHERE prf.PurchaseRequestFlagStatus LIKE '%PO%'
                AND prf.PurchaseRequestFlagS_RegionalID = ?
                AND prf.PurchaseRequestFlagQtyRest > 0
                AND (prf.PurchaseRequestFlagQtyRest - prf.PurchaseRequestFlagQtyProses) > 0";

            $countQry = $this->db->query($countSql, [$search, $itemCategoryID, $supplierID, $regionalId]);

            if (!$countQry) {
                $this->db->trans_rollback();
                $this->sys_error_db("count items error", $this->db);
                exit;
            }

            $totalCount = $countQry->row()->total;
            $totalPage = ceil($totalCount / $numberLimit);

            $sql = "SELECT 
                    PurchaseRequestFlagID,
                    PurchaseRequestFlagM_BranchCode as BranchCode,
                    PurchaseRequestFlagQtyRest - PurchaseRequestFlagQtyProses as UnprocessFlagQty,
                    PurchaseRequestDetailID,
                    PurchaseRequestDetailPurchaseRequestID as PurchaseRequestID,
                    PurchaseRequestDetailQty as RequestQty,
                    M_ItemID,
                    M_ItemCode,
                    M_ItemDesc,
                    requnit.ItemUnitID as ReqItemUnitID,
                    requnit.ItemUnitName as ReqItemUnitName,
                    purunit.ItemUnitID as PoItemUnitID,
                    purunit.ItemUnitName as PoItemUnitName,
                    SupplierPricePrice as Price,
                    S_RegionalName,
                    S_RegionalID,
                    CASE
                        WHEN M_BranchID IS NULL OR M_BranchID = 0 THEN wr.WarehouseID
                        WHEN M_BranchID IS NOT NULL OR M_BranchID <> 0 THEN wb.WarehouseID
                    END as WarehouseID,
                    CASE
                        WHEN M_BranchID IS NULL OR M_BranchID = 0 THEN CONCAT(wr.WarehouseCode,' ', wr.WarehouseName, ' - ', S_RegionalName)
                        WHEN M_BranchID IS NOT NULL OR M_BranchID <> 0 THEN CONCAT(wb.WarehouseCode,' ', wb.WarehouseName, ' - ', M_BranchName)
                    END as WarehouseName,
                    M_BranchName,
                    M_BranchName as RequesterBranchName, -- Agar sama dengan getItemUpdate saja, tidak perlu edit FE
                    M_BranchID,
                    PurchaseRequestNumber,
                    0 as discount,
                    'R' as discountType
                    FROM purchase_request_flag
                    JOIN purchase_request_detail
                        ON PurchaseRequestFlagPurchaseRequestDetailID = PurchaseRequestDetailID
                        AND PurchaseRequestFlagStatus LIKE '%PO%'
                        AND PurchaseRequestFlagS_RegionalID = ?
                        AND PurchaseRequestFlagQtyRest > 0
                    JOIN purchase_request ON PurchaseRequestDetailPurchaseRequestID  = PurchaseRequestID
                    JOIN supplier_price ON 
                        PurchaseRequestDetailM_ItemID = SupplierPriceM_ItemID AND
                        SupplierPriceItemUnitID = PurchaseRequestDetailItemUnitID AND (
                        SupplierPriceFlagQty ='T' OR 
                        (
                            (SupplierPriceMinInclusive = 'Y' AND PurchaseRequestDetailQty >= SupplierPriceMinQty) OR 
                            (SupplierPriceMinInclusive = 'N' AND PurchaseRequestDetailQty > SupplierPriceMinQty)
                        ) AND
                        (
                            (SupplierPriceMaxInclusive = 'Y' AND PurchaseRequestDetailQty <= SupplierPriceMaxQty) OR 
                            (SupplierPriceMaxInclusive = 'N' AND PurchaseRequestDetailQty < SupplierPriceMaxQty))
                        ) 
                        AND SupplierPriceIsActive = 'Y'
                        AND SupplierPriceSupplierID = ?
                    JOIN m_item 
                        ON PurchaseRequestDetailM_ItemID = M_ItemID
                        AND M_ItemDesc LIKE ?
                        AND M_ItemItem_CategoryID = {$itemCategoryID} 
                    JOIN itemunit requnit
                        ON PurchaseRequestDetailItemUnitID = requnit.ItemUnitID
                    LEFT JOIN itemunitmap
                        ON PurchaseRequestDetailM_ItemID = ItemUnitMapM_ItemID
                        AND ItemUnitMapIsPurchase = 'Y'
                    LEFT JOIN itemunit purunit
                        ON ItemUnitMapItemUnitID = purunit.ItemUnitID
                    JOIN s_regional 
                        ON PurchaseRequestFlagS_RegionalID = S_RegionalID AND S_RegionalIsActive = 'Y'
                    JOIN warehouse wr 
                        ON S_RegionalID  = wr.WarehouseS_RegionalID
                        AND wr.WarehouseType = 'R'
                        AND wr.WarehouseIsActive = 'Y' 
                        AND wr.WarehouseIsDefault = 'Y'
                    LEFT JOIN m_branch 
                        ON PurchaseRequestFlagM_BranchCode = M_BranchCode 
                        AND M_BranchIsActive = 'Y'
                    LEFT JOIN warehouse wb 
                        ON S_RegionalID  = wb.WarehouseS_RegionalID
                        AND M_BranchID = wb.WarehouseM_BranchID
                        AND wb.WarehouseType = 'B'
                        AND wb.WarehouseIsActive = 'Y' 
                        AND wb.WarehouseIsDefault = 'Y'
                    LEFT JOIN purchase_order_detail
                        ON PurchaseRequestFlagID = PurchaseOrderDetailPurchaseRequestFlagID
                        AND PurchaseRequestDetailPurchaseRequestID = PurchaseOrderDetailPurchaseRequestID
                        AND PurchaseRequestDetailID = PurchaseOrderDetailPurchaseRequestDetailID
                        AND PurchaseOrderDetailIsActive = 'Y'
                    WHERE ((PurchaseRequestFlagQtyRest - PurchaseRequestFlagQtyProses) > 0)
                        AND PurchaseRequestFlagIsActive = 'Y'
                    ORDER BY M_ItemDesc ASC, PurchaseRequestNumber DESC
                    LIMIT {$numberLimit} OFFSET {$numberOffset}";

            $qry = $this->db->query($sql, [$payload['regionalId'], $supplierID, $search]);

            if (!$qry) {
                $this->db->trans_rollback();
                $this->sys_error_db("select items error", $this->db);
                exit;
            }

            $rows = $qry->result_array();

            foreach ($rows as &$row) {
                // Cek Unit Request dan Purchase sama atau tidak

                // TODO: Jika PurchaseItemUnitID == null maka jangan tampilkan item dan continue

                // Jika beda maka lakukan konversi rounding up ke unit purchase dan ganti PurchaseQty
                if ($row['ReqItemUnitID'] !== $row['PoItemUnitID']) {
                    // Lookup unitconvert
                    $sqlConvert = "SELECT UnitConvertAmount FROM unitconvert
                        WHERE UnitConvertFromItemUnitID = ?
                        AND UnitConvertToItemUnitID = ?
                        AND UnitConvertIsActive = 'Y'
                        ORDER BY UnitConvertID DESC LIMIT 1";
                    $qryConvert = $this->db->query($sqlConvert, [$row['PoItemUnitID'], $row['ReqItemUnitID']]);
                    if (!$qryConvert) {
                        $this->db->trans_rollback();
                        $this->sys_error_db("select items error", $this->db);
                        exit;
                    }

                    // Kalau tidak ditemukan konversi maka tambahkan flag 'UnitReqPoConvertStatus'
                    if ($qryConvert->num_rows() == 0) {
                        $row['PoQty'] = 0;
                        $row['UnitReqPoConvertStatus'] = 'failed';
                        $row['UnitReqPoConvertMsg'] = "Mapping konversi Req Unit {$row['ItemUnitName']} dengan PO Unit {$row['PoItemUnitName']} tidak ada";
                    } else {
                        // Kalau ada maka kalkulasi round up unit req ke unit purchase
                        $convertValue = $qryConvert->row()->UnitConvertAmount;

                        // RoundUpPoQty = Jumlah Request / Nilai Konversi lalu bulatkan ke atas integer
                        // Misal: jika hasil 0.1 -> 1, jika 1.6 -> 2
                        $roundUpPoQty = ceil($row['RequestQty'] / $convertValue);

                        $row['PoQty'] = $roundUpPoQty;
                        $row['UnitReqPoConvertStatus'] = 'success';
                        $row['UnitReqPoConvertMsg'] = "Berhasil mapping konversi Req {$row['RequestQty']} {$row['ItemUnitName']} ke PO {$roundUpPoQty} {$row['PoItemUnitName']}";
                    }
                }
                // Jika sama maka PoQty = RequestQty	
                else {
                    $row['PoQty'] = $row['RequestQty'];
                    $row['UnitReqPoConvertStatus'] = 'without';
                    $row['UnitReqPoConvertMsg'] = "Tidak perlu mapping konversi Req {$row['RequestQty']} {$row['ItemUnitName']} ke PO {$roundUpPoQty} {$row['PoItemUnitName']}";
                }

                $row['Total'] = floatval($row['Price']) * floatval($row['PoQty']);
                $row['keyID'] = "{$row['M_ItemID']}_{$row['PoItemUnitID']}";
                $row['DefaultPurchase'] = $this->getDefaultPurchase($supplierID, $row['M_ItemID'], $row['RequestQty']);
            }
            unset($row); // unset to prevent accidental modication

            $result = array(
                "totalRow" => $totalCount,
                "totalPage" => $totalPage,
                "records" => $rows
            );

            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    /** 
     * Refactored on 20 June 2025
     * Whats new:
     * > List Item PR dengan Item Unit yang berbeda dengan SupplierPrice tetap ditampilkan asal ada di unitconvert
     * > Kalau Unit Request dan Unit Convert berbeda, lakukan konversi dan rounding up request ke unit purchase
     * > Refactor SQL Count
     */
    function getItem_stable()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
            }

            $regionalId = $this->sys_user["S_RegionalID"];
            $payload = $this->sys_input;
            $itemCategoryID = $payload['itemCategoryID'];
            $supplierID = $payload['supplierID'];

            $search = '%%';
            if (isset($payload['search'])) {
                $search = trim($payload["search"]);
                if ($search != "") {
                    $search = '%' . $search . '%';
                } else {
                    $search = '%%';
                }
            }

            if (!isset($supplierID)) {
                $this->sys_error("Supplier ID is required");
                exit;
            }

            $numberLimit = 10;
            $numberOffset = 0;
            if (isset($payload["currentPage"]) && $payload["currentPage"] > 0) {
                $numberOffset = ($payload["currentPage"] - 1) * $numberLimit;
            }

            $countSql = "SELECT COUNT(*) as total
                FROM purchase_request_flag prf
                JOIN purchase_request_detail prd ON prf.PurchaseRequestFlagPurchaseRequestDetailID = prd.PurchaseRequestDetailID 
                JOIN m_item mi ON prd.PurchaseRequestDetailM_ItemID = mi.M_ItemID AND mi.M_ItemDesc LIKE ? AND mi.M_ItemItem_CategoryID = ?
                JOIN supplier_price sp ON mi.M_ItemID = sp.SupplierPriceM_ItemID AND sp.SupplierPriceSupplierID = ? AND sp.SupplierPriceIsActive = 'Y'
                WHERE prf.PurchaseRequestFlagStatus LIKE '%PO%'
                AND prf.PurchaseRequestFlagS_RegionalID = ?
                AND prf.PurchaseRequestFlagQtyRest > 0
                AND (prf.PurchaseRequestFlagQtyRest - prf.PurchaseRequestFlagQtyProses) > 0";

            $countQry = $this->db->query($countSql, [$search, $itemCategoryID, $supplierID, $regionalId]);

            if (!$countQry) {
                $this->db->trans_rollback();
                $this->sys_error_db("count items error", $this->db);
                exit;
            }

            $totalCount = $countQry->row()->total;
            $totalPage = ceil($totalCount / $numberLimit);

            $sql = "SELECT 
                    PurchaseRequestFlagID,
                    PurchaseRequestFlagM_BranchCode as BranchCode,
                    -- PurchaseRequestFlagQtyRest - PurchaseRequestFlagQtyProses as FlagQty,
                    PurchaseRequestDetailQty as FlagQty,
                    PurchaseRequestFlagQtyRest - PurchaseRequestFlagQtyProses as PoQty,
                    PurchaseRequestFlagQtyRest - PurchaseRequestFlagQtyProses as PoQtyBefore,
                    PurchaseRequestDetailID,
                    PurchaseRequestDetailPurchaseRequestID,
                    PurchaseRequestDetailQty as RequestQty,
                    PurchaseRequestDetailItemUnitID as RequestItemUnitID,
                    M_ItemID,
                    M_ItemCode,
                    M_ItemDesc,
                    M_ItemPurchaseUOM,
                    iu1.ItemUnitName,
                    iu1.ItemUnitID,
                    ItemUnitMapItemUnitID as PoItemUnitID,
                    iu2.ItemUnitName as PoItemUnitName,
                    SupplierPricePrice as Price,
                    S_RegionalName,
                    S_RegionalID,
                    CASE
                        WHEN M_BranchID IS NULL OR M_BranchID = 0 THEN wr.WarehouseID
                        WHEN M_BranchID IS NOT NULL OR M_BranchID <> 0 THEN wb.WarehouseID
                    END as WarehouseID,
                    CASE
                        WHEN M_BranchID IS NULL OR M_BranchID = 0 THEN CONCAT(wr.WarehouseCode,' ', wr.WarehouseName, ' - ', S_RegionalName)
                        WHEN M_BranchID IS NOT NULL OR M_BranchID <> 0 THEN CONCAT(wb.WarehouseCode,' ', wb.WarehouseName, ' - ', M_BranchName)
                    END as WarehouseName,
                    M_BranchName,
                    M_BranchID,
                    PurchaseRequestNumber,
                    0 as discount,
                    'R' as discountType
                    FROM purchase_request_flag
                    JOIN purchase_request_detail
                        ON PurchaseRequestFlagPurchaseRequestDetailID = PurchaseRequestDetailID
                        AND PurchaseRequestFlagStatus LIKE '%PO%'
                        AND PurchaseRequestFlagS_RegionalID = ?
                        AND PurchaseRequestFlagQtyRest > 0
                    JOIN m_item 
                        ON PurchaseRequestDetailM_ItemID = M_ItemID
                        AND M_ItemDesc LIKE ?
                        AND M_ItemItem_CategoryID = {$itemCategoryID}
                    JOIN supplier_price  
                        ON M_ItemID = SupplierPriceM_ItemID
                        AND SupplierPriceSupplierID = ?
                        -- AND PurchaseRequestDetailItemUnitID = SupplierPriceItemUnitID --Agar PR dengan Item yang belum ada di Supplier tetap bisa dilakukan PO
                        AND SupplierPriceIsActive = 'Y' 
                    JOIN itemunit iu1
                        ON PurchaseRequestDetailItemUnitID = iu1.ItemUnitID
                    LEFT JOIN itemunitmap
                        ON PurchaseRequestDetailM_ItemID = ItemUnitMapM_ItemID
                        AND ItemUnitMapIsPurchase = 'Y'
                    LEFT JOIN itemunit iu2
                        ON ItemUnitMapItemUnitID = iu2.ItemUnitID
                    JOIN s_regional 
                        ON PurchaseRequestFlagS_RegionalID = S_RegionalID AND S_RegionalIsActive = 'Y'
                    JOIN warehouse wr 
                        ON S_RegionalID  = wr.WarehouseS_RegionalID
                        AND wr.WarehouseType = 'R'
                        AND wr.WarehouseIsActive = 'Y' 
                        AND wr.WarehouseIsDefault = 'Y'
                    LEFT JOIN m_branch 
                        ON PurchaseRequestFlagM_BranchCode = M_BranchCode 
                        AND M_BranchIsActive = 'Y'
                    LEFT JOIN warehouse wb 
                        ON S_RegionalID  = wb.WarehouseS_RegionalID
                        AND M_BranchID = wb.WarehouseM_BranchID
                        AND wb.WarehouseType = 'B'
                        AND wb.WarehouseIsActive = 'Y' 
                        AND wb.WarehouseIsDefault = 'Y'
                    LEFT JOIN purchase_order_detail
                        ON PurchaseRequestFlagID = PurchaseOrderDetailPurchaseRequestFlagID
                        AND PurchaseRequestDetailPurchaseRequestID = PurchaseOrderDetailPurchaseRequestID
                        AND PurchaseRequestDetailID = PurchaseOrderDetailPurchaseRequestDetailID
                        AND PurchaseOrderDetailIsActive = 'Y'
                    LEFT JOIN purchase_request
                        ON PurchaseRequestDetailPurchaseRequestID = PurchaseRequestID
                    WHERE ((PurchaseRequestFlagQtyRest - PurchaseRequestFlagQtyProses) > 0)
                    ORDER BY M_ItemDesc ASC
                    LIMIT {$numberLimit} OFFSET {$numberOffset}";

            $qry = $this->db->query($sql, [$payload['regionalId'], $search, $supplierID]);

            if (!$qry) {
                $this->db->trans_rollback();
                $this->sys_error_db("select items error", $this->db);
                exit;
            }

            $rows = $qry->result_array();

            foreach ($rows as &$row) {
                // Cek Unit Request dan Purchase sama atau tidak

                // TODO: Jika PurchaseItemUnitID == null maka jangan tampilkan item dan continue

                // Jika beda maka lakukan konversi rounding up ke unit purchase dan ganti PurchaseQty
                if ($row['RequestItemUnitID'] !== $row['PoItemUnitID']) {
                    // Lookup unitconvert
                    $sqlConvert = "SELECT UnitConvertAmount FROM unitconvert
                        WHERE UnitConvertFromItemUnitID = ?
                        AND UnitConvertToItemUnitID = ?
                        AND UnitConvertIsActive = 'Y'
                        ORDER BY UnitConvertID DESC LIMIT 1";
                    $qryConvert = $this->db->query($sqlConvert, [$row['PoItemUnitID'], $row['RequestItemUnitID']]);
                    if (!$qryConvert) {
                        $this->db->trans_rollback();
                        $this->sys_error_db("select items error", $this->db);
                        exit;
                    }

                    // Kalau tidak ditemukan konversi maka tambahkan flag 'UnitReqPoConvertStatus'
                    if ($qryConvert->num_rows() == 0) {
                        $row['PoQty'] = 0;
                        $row['UnitReqPoConvertStatus'] = 'failed';
                        $row['UnitReqPoConvertMsg'] = "Mapping konversi Req Unit {$row['ItemUnitName']} dengan PO Unit {$row['PoItemUnitName']} tidak ada";
                    } else {
                        // Kalau ada maka kalkulasi round up unit req ke unit purchase
                        $convertValue = $qryConvert->row()->UnitConvertAmount;

                        // RoundUpPoQty = Jumlah Request / Nilai Konversi lalu bulatkan ke atas integer
                        // Misal: jika hasil 0.1 -> 1, jika 1.6 -> 2
                        $roundUpPoQty = ceil($row['RequestQty'] / $convertValue);

                        $row['PoQty'] = $roundUpPoQty;
                        $row['UnitReqPoConvertStatus'] = 'success';
                        $row['UnitReqPoConvertMsg'] = "Berhasil mapping konversi Req {$row['RequestQty']} {$row['ItemUnitName']} ke PO {$roundUpPoQty} {$row['PoItemUnitName']}";
                    }
                }
                // Jika sama maka PoQty = RequestQty	
                else {
                    $row['UnitReqPoConvertStatus'] = 'without';
                    $row['UnitReqPoConvertMsg'] = "Tidak perlu mapping konversi Req {$row['RequestQty']} {$row['ItemUnitName']} ke PO {$roundUpPoQty} {$row['PoItemUnitName']}";
                }

                $row['Total'] = floatval($row['Price']) * floatval($row['PoQty']);
                $row['keyID'] = "{$row['M_ItemID']}_{$row['ItemUnitID']}";
                // $row['DefaultPurchase'] = $this->getDefaultPurchase($row['M_ItemID'], $row['ItemUnitID']);
                $row['DefaultPurchase'] = $this->getDefaultPurchase($supplierID, $row['M_ItemID']);
            }
            unset($row); // unset to prevent accidental modication

            $result = array(
                "totalRow" => $totalCount,
                "totalPage" => $totalPage,
                // "sql" => $this->db->last_query(),
                "records" => $rows
            );

            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    function getItem_old()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
            }

            $payload = $this->sys_input;
            $itemCategoryID = $payload['itemCategoryID'];
            $regionalId = $this->sys_user["S_RegionalID"];

            $search = '%%';
            if (isset($payload['search'])) {
                $search = trim($payload["search"]);
                if ($search != "") {
                    $search = '%' . $search . '%';
                } else {
                    $search = '%%';
                }
            }

            if (!isset($payload['supplierID'])) {
                $this->sys_error("Supplier ID is required");
                exit;
            }

            $numberLimit = 10;
            $numberOffset = 0;
            if (isset($payload["currentPage"]) && $payload["currentPage"] > 0) {
                $numberOffset = ($payload["currentPage"] - 1) * $numberLimit;
            }

            $countSql = "SELECT 
                        COUNT(PurchaseRequestFlagID) as total
                    FROM purchase_request_flag
                    JOIN purchase_request_detail
                        ON PurchaseRequestFlagPurchaseRequestDetailID = PurchaseRequestDetailID
                        AND PurchaseRequestFlagStatus LIKE '%PO%'
                        AND PurchaseRequestFlagS_RegionalID = ?
                    JOIN m_item 
                        ON PurchaseRequestDetailM_ItemID =M_ItemID
                        AND M_ItemDesc LIKE ?
                        AND M_ItemItem_CategoryID = {$itemCategoryID}
                    JOIN supplier_price  
                        ON M_ItemID = SupplierPriceM_ItemID
                        AND SupplierPriceSupplierID = ?
                        AND PurchaseRequestDetailItemUnitID = SupplierPriceItemUnitID 
                        AND SupplierPriceIsActive = 'Y'
                    JOIN itemunit
                        ON PurchaseRequestDetailItemUnitID = ItemUnitID
                    JOIN s_regional 
                        ON PurchaseRequestFlagS_RegionalID = S_RegionalID AND S_RegionalIsActive = 'Y'
                    JOIN warehouse wr 
                        ON S_RegionalID  = wr.WarehouseS_RegionalID
                        AND wr.WarehouseType = 'R'
                        AND wr.WarehouseIsActive = 'Y' 
                        AND wr.WarehouseIsDefault = 'Y'
                    LEFT JOIN m_branch 
                        ON PurchaseRequestFlagM_BranchCode = M_BranchCode 
                        AND M_BranchIsActive = 'Y'
                    LEFT JOIN warehouse wb 
                        ON S_RegionalID  = wb.WarehouseS_RegionalID
                        AND M_BranchID = wb.WarehouseM_BranchID
                        AND wb.WarehouseType = 'B'
                        AND wb.WarehouseIsActive = 'Y' 
                        AND wb.WarehouseIsDefault = 'Y'
                    WHERE ((PurchaseRequestFlagQtyRest - PurchaseRequestFlagQtyProses) > 0)";

            $countQry = $this->db->query($countSql, [$payload['regionalId'],  $search, $payload['supplierID'],]);

            if (!$countQry) {
                $this->db->trans_rollback();
                $this->sys_error_db("count items error", $this->db);
                exit;
            }

            $totalCount = $countQry->row()->total;
            $totalPage = ceil($totalCount / $numberLimit);

            $sql = "SELECT 
                    PurchaseRequestFlagID,
                    PurchaseRequestDetailID,
                    PurchaseRequestDetailPurchaseRequestID,
                    M_ItemID,
                    M_ItemCode,
                    M_ItemDesc,
                    M_ItemPurchaseUOM,
                    ItemUnitName,
                    ItemUnitID,
                    SupplierPricePrice as Price,
                    PurchaseRequestDetailQty as RequestQty,
                    PurchaseRequestFlagM_BranchCode as BranchCode,
                    PurchaseRequestFlagQtyRest - PurchaseRequestFlagQtyProses as FlagQty,
                    PurchaseRequestFlagQtyRest - PurchaseRequestFlagQtyProses as PoQty,
                    S_RegionalName,
                    S_RegionalID,
                    M_BranchName,
                    M_BranchID,
                    PurchaseRequestNumber,
                    CASE
                    WHEN M_BranchID IS NULL OR M_BranchID = 0 THEN wr.WarehouseID
                    WHEN M_BranchID IS NOT NULL OR M_BranchID <> 0 THEN wb.WarehouseID
                    END as WarehouseID,
                    CASE
                    WHEN M_BranchID IS NULL OR M_BranchID = 0 THEN CONCAT(wr.WarehouseCode,' ', wr.WarehouseName, ' - ', S_RegionalName)
                    WHEN M_BranchID IS NOT NULL OR M_BranchID <> 0 THEN CONCAT(wb.WarehouseCode,' ', wb.WarehouseName, ' - ', M_BranchName)
                    END as WarehouseName ,
                    0 as discount,
                    'R' as discountType
                    FROM purchase_request_flag
                    JOIN purchase_request_detail
                        ON PurchaseRequestFlagPurchaseRequestDetailID = PurchaseRequestDetailID
                        AND PurchaseRequestFlagStatus LIKE '%PO%'
                        AND PurchaseRequestFlagS_RegionalID = ?
                        AND PurchaseRequestFlagQtyRest > 0
                    JOIN m_item 
                        ON PurchaseRequestDetailM_ItemID =M_ItemID
                        AND M_ItemDesc LIKE ?
                        AND M_ItemItem_CategoryID = {$itemCategoryID}
                    JOIN supplier_price  
                        ON M_ItemID = SupplierPriceM_ItemID
                        AND SupplierPriceSupplierID = ?
                        AND PurchaseRequestDetailItemUnitID = SupplierPriceItemUnitID
                        AND SupplierPriceIsActive = 'Y' 
                    JOIN itemunit
                        ON PurchaseRequestDetailItemUnitID = ItemUnitID
                    JOIN s_regional 
                        ON PurchaseRequestFlagS_RegionalID = S_RegionalID AND S_RegionalIsActive = 'Y'
                    JOIN warehouse wr 
                        ON S_RegionalID  = wr.WarehouseS_RegionalID
                        AND wr.WarehouseType = 'R'
                        AND wr.WarehouseIsActive = 'Y' 
                        AND wr.WarehouseIsDefault = 'Y'
                    LEFT JOIN m_branch 
                        ON PurchaseRequestFlagM_BranchCode = M_BranchCode 
                        AND M_BranchIsActive = 'Y'
                    LEFT JOIN warehouse wb 
                        ON S_RegionalID  = wb.WarehouseS_RegionalID
                        AND M_BranchID = wb.WarehouseM_BranchID
                        AND wb.WarehouseType = 'B'
                        AND wb.WarehouseIsActive = 'Y' 
                        AND wb.WarehouseIsDefault = 'Y'
                    LEFT JOIN purchase_order_detail
                        ON PurchaseRequestFlagID = PurchaseOrderDetailPurchaseRequestFlagID
                        AND PurchaseRequestDetailPurchaseRequestID = PurchaseOrderDetailPurchaseRequestID
                        AND PurchaseRequestDetailID = PurchaseOrderDetailPurchaseRequestDetailID
                        AND PurchaseOrderDetailIsActive = 'Y'
                    LEFT JOIN purchase_request
                        ON PurchaseRequestDetailPurchaseRequestID = PurchaseRequestID
                    WHERE ((PurchaseRequestFlagQtyRest - PurchaseRequestFlagQtyProses) > 0)
                    ORDER BY M_ItemDesc ASC
                    LIMIT {$numberLimit} OFFSET {$numberOffset}";

            $qry = $this->db->query($sql, [$payload['regionalId'], $search, $payload['supplierID']]);

            if (!$qry) {
                $this->db->trans_rollback();
                $this->sys_error_db("select items error", $this->db);
                exit;
            }

            $rows = $qry->result_array();

            foreach ($rows as $key => $row) {
                $rows[$key]['Total'] = floatval($row['Price']) * floatval($row['FlagQty']);
                $rows[$key]['keyID'] = "{$row['M_ItemID']}_{$row['ItemUnitID']}";
                $rows[$key]['DefaultPurchase'] = $this->getDefaultPurchase($row['M_ItemID'], $row['ItemUnitID']);
            }

            $result = array(
                "totalPage" => $totalPage,
                "records" => $rows,
                "sql" => $this->db->last_query()
            );

            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    function saveOrder()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
            }

            // Debugging
            // echo json_encode($this->sys_input, JSON_PRETTY_PRINT);
            // exit;

            $this->db->trans_begin(true); // Memulai transaksi

            $payload    = $this->sys_input;
            $user       = $this->sys_user;
            $userId     = $this->sys_user["M_UserID"];
            $regId      = $this->sys_user["S_RegionalID"];


            // $pdSql = "SELECT `fn_numbering`('PO') AS PO";
            // $exec = $this->db->query($pdSql, []);
            // $pd = "";

            // if (!$exec) {
            //     $this->sys_error_db("purchase order insert error", $this->db);
            //     $this->db->trans_rollback();
            //     exit;
            // } else {
            //     $pd = $exec->result_array()[0]["PO"];
            // }

            $areaid = $user['M_BranchID'];
            $areatype = 'B';
            if ($user['loginLevel'] == 'regional') {
                $areaid = $user['S_RegionalID'];
                $areatype = 'R';
            }

            $sqlusrdivisi = "SELECT M_UserDivisionDivisionID FROM m_userdivision 
                WHERE M_UserDivisionM_UserID = ? AND M_UserDivisionIsActive = 'Y'";
            $queusrdivisi = $this->db->query($sqlusrdivisi, [$userId]);
            if (!$queusrdivisi) {
                $this->db->trans_rollback();
                $this->sys_error_db("[Error] get user divisi", $this->db);
                exit;
            }
            $userDivID = $queusrdivisi->row_array()['M_UserDivisionDivisionID'];

            $sqlnum = "SELECT `fn_penomoran`(?, ?, ?, ?, ?, ?) AS numpd;";
            $quenum = $this->db->query($sqlnum, ['PO', $userDivID, $areatype, $areaid, 'SM', 'N']);
            if (!$quenum) {
                $this->db->trans_rollback();
                $this->sys_error_db("[Error] generate number doc", $this->db);
                exit;
            }
            $numpd = $quenum->row_array()['numpd'];

            // Step 1: Insert ke tabel purchase_order
            $sqlPurchaseOrder = "INSERT INTO purchase_order (
                PurchaseOrderNumber,
                PurchaseOrderItemCategoryID,
                PurchaseOrderDate,
                PurchaseOrderRefNumber,
                PurchaseOrderSupplierID,
                PurchaseOrderS_RegionalID,
                PurchaseOrderTaxPercentPph,
                PurchaseOrderTaxPercentPpn,
                PurchaseOrderPaymentTerm,
                PurchaseOrderDiscountPercent,
                PurchaseOrderDiscountAmount,
                PurchaseOrderWarehouseType,
                PurchaseOrderWarehouseID,
                PurchaseOrderNote,
                PurchaseOrderSubTotal,
                PurchaseOrderTaxAmountPph,
                PurchaseOrderTaxAmountPpn,
                PurchaseOrderGrandTotal,
                PurchaseOrderStatus,
                PurchaseOrderIsActive,
                PurchaseOrderUserID,
                PurchaseOrderCreated,
                PurchaseOrderLastUpdated,
                PurchaseOrderShippingCost,
                PurchaseOrderShippingCostStatus
            ) VALUES (
                ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW(), ?, ?
            )";

            $exec = $this->db->query($sqlPurchaseOrder, [
                $numpd,
                $payload['ItemCategoryID'],
                $payload['Date'],
                $payload['RefNumber'],
                $payload['SupplierID'],
                $regId,
                $payload['TaxPercentPph'],
                $payload['TaxPercentPpn'],
                $payload['PaymentTerm'],
                $payload['DiscountPercent'],
                $payload['DiscountAmount'],
                $payload['WarehouseType'],
                $payload['WarehouseID'],
                $payload['Note'],
                $payload['SubTotal'],
                $payload['TaxAmountPph'],
                $payload['TaxAmountPpn'],
                $payload['GrandTotal'],
                'Draft',
                'Y',
                $userId,
                $payload['ShippingCost'],
                $payload['ShippingCostStatus'] ? 'Y' : 'N'
            ]);


            if (!$exec) {
                $this->sys_error_db("purchase_order insert error", $this->db);
                $this->db->trans_rollback();
                exit;
            }
            $purchaseOrderId = $this->db->insert_id(); // Mendapatkan ID terakhir

            // Step 2: Insert ke tabel purchase_order_summary
            foreach ($payload['Summary'] as $summary) {
                $discountAmount = 0;
                if ($summary['discountType'] == 'R') $discountAmount = doubleval($summary['discount']);
                if ($summary['discountType'] == 'P') $discountAmount = (doubleval($summary['discount']) / 100) *  doubleval($summary['RealPrice']);
                $sqlSummary = "INSERT INTO purchase_order_summary (
                                    PurchaseOrderSummaryPurchaseOrderID,
                                    PurchaseOrderSummaryItemID,
                                    PurchaseOrderSummaryItemUnitID,
                                    PurchaseOrderSummaryQty,
                                    PurchaseOrderSummaryPrice,
                                    PurchaseOrderSummaryTotal,
                                    PurchaseOrderSummaryIsActive,
                                    PurchaseOrderSummaryCreatedUserID,
                                    PurchaseOrderSummaryCreated,
                                    PurchaseOrderSummaryDiscountRupiah,
                                    PurchaseOrderSummaryDiscountPercent,
                                    PurchaseOrderSummaryDiscountAmount,
                                    PurchaseOrderSummaryDiscountType                                    
                                ) VALUES (?,?,?,?,?,?,'Y',?,NOW(), ?,?,?,?)";

                $exec = $this->db->query($sqlSummary, [
                    $purchaseOrderId,
                    $summary['M_ItemID'],
                    $summary['PoItemUnitID'],
                    $summary['TotalPoQty'],
                    $summary['RealPrice'],
                    $summary['Total'],
                    $userId,
                    $summary['discountType'] == 'R' ? $summary['discount'] : 0,
                    $summary['discountType'] == 'P' ? $summary['discount'] : 0,
                    $discountAmount,
                    $summary['discountType']
                ]);


                if (!$exec) {
                    $this->sys_error_db("purchase_order_summary insert error", $this->db);
                    $this->db->trans_rollback();
                    exit;
                }
                $summaryId = $this->db->insert_id();

                // Step 3: Insert ke tabel purchase_order_detail
                foreach ($summary['Details'] as $detail) {
                    $sql = "SELECT * FROM purchase_request_flag
                            WHERE PurchaseRequestFlagID = {$detail['PurchaseRequestFlagID']}
                            AND PurchaseRequestFlagIsActive = 'Y'";
                    $qry = $this->db->query($sql);
                    if (!$qry) {
                        $this->sys_error_db("Error checking purchase_request_flag", $this->db);
                        $this->db->trans_rollback();
                        exit;
                    }

                    $row = $qry->row_array();
                    if (!$row) {
                        $this->sys_error("Data {$detail['M_ItemCode']} - {$detail['M_ItemDesc']} cabang {$detail['M_BranchName']} regional {$detail['S_RegionalName']} tidak ditemukan, silahkan refresh item");
                        $this->db->trans_rollback();
                        exit;
                    }

                    $qtyRest = floatval($row['PurchaseRequestFlagQtyRest']);
                    $qtyProses = floatval($row['PurchaseRequestFlagQtyProses']);

                    if (($qtyRest - $qtyProses) <= 0) {
                        $this->sys_error("Qty {$detail['M_ItemCode']} - {$detail['M_ItemDesc']} cabang {$detail['M_BranchName']} regional {$detail['S_RegionalName']} tidak mencukupi karena sisa qty sudah habis diproses, silahkan refresh item");
                        $this->db->trans_rollback();
                        exit;
                    }

                    $sqlDetail = "INSERT INTO purchase_order_detail (
                                    PurchaseOrderDetailPurchaseOrderID,
                                    PurchaseOrderDetailPurchaseSummaryID,
                                    PurchaseOrderDetailPurchaseRequestID,
                                    PurchaseOrderDetailPurchaseRequestDetailID,
                                    PurchaseOrderDetailPurchaseRequestFlagID,
                                    PurchaseOrderDetailItemID,
                                    PurchaseOrderDetailItemUnitID,
                                    PurchaseOrderDetailRequestQty,
                                    PurchaseOrderDetailQty,
                                    PurchaseOrderDetailPrice,
                                    PurchaseOrderDetailTotal,
                                    PurchaseOrderDetailWarehouseID,
                                    PurchaseOrderDetailIsActive,
                                    PurchaseOrderDetailUserID,
                                    PurchaseOrderDetailCreatedUserID,
                                    PurchaseOrderDetailCreated,
                                    PurchaseOrderDetailLastUpdated
                                ) VALUES (
                                    {$purchaseOrderId},
                                    {$summaryId},
                                    {$detail['PurchaseRequestID']},
                                    {$detail['PurchaseRequestDetailID']},
                                    {$detail['PurchaseRequestFlagID']},
                                    {$detail['M_ItemID']},
                                    {$detail['PoItemUnitID']},
                                    {$detail['PoQty']},
                                    {$detail['PoQty']},
                                    {$detail['Price']},
                                    {$detail['Total']},
                                    {$detail['warehouse']['WarehouseID']},
                                    'Y',
                                    {$userId},
                                    {$userId},
                                    NOW(),
                                    NOW()
                                )";

                    $exec = $this->db->query($sqlDetail);

                    if (!$exec) {
                        $this->sys_error_db("purchase_order_detail insert error", $this->db);
                        $this->db->trans_rollback();
                        exit;
                    }
                    // Step 4: Update tabel purchase_request_flag
                    $sqlUpdateFlag = "UPDATE purchase_request_flag
                                    SET PurchaseRequestFlagQtyProses = PurchaseRequestFlagQtyProses + {$detail['RequestQty']}
                                    WHERE PurchaseRequestFlagID = {$detail['PurchaseRequestFlagID']}";

                    $exec = $this->db->query($sqlUpdateFlag);

                    if (!$exec) {
                        $this->sys_error_db("purchase_request_flag update error", $this->db);
                        $this->db->trans_rollback();
                        exit;
                    }
                }
            }

            $poAfter = $this->getDataPo($purchaseOrderId);

            $this->insertLog(
                $purchaseOrderId,
                "ADD",
                $payload,
                [],
                $poAfter,
                $userId,
                "Add purchase order {$numpd}"
            );

            // Commit transaksi jika semua berhasil
            $this->db->trans_commit();

            $result = array(
                "total" => 1,
                "records" => array("PurchaseOrderID" => $purchaseOrderId)
            );
            $this->sys_ok($result);
        } catch (Exception $exc) {
            $this->db->trans_rollback(); // Rollback jika ada kesalahan
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    function deleteOrder()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
            }

            $this->db->trans_begin(); // Start transaction

            $payload = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];
            $purchaseOrderId = $payload["PurchaseOrderId"];

            // Get PO data before deletion for logging
            $poBefore = $this->getDataPo($purchaseOrderId);

            // Check if PO exists and is active
            $sqlCheckPO = "SELECT * FROM purchase_order 
                        WHERE PurchaseOrderID = ? 
                        AND PurchaseOrderIsActive = 'Y'";
            $execCheck = $this->db->query($sqlCheckPO, [$purchaseOrderId]);

            if (!$execCheck || $execCheck->num_rows() == 0) {
                $this->sys_error("Purchase order not found or already deleted");
                $this->db->trans_rollback();
                exit;
            }

            $po = $execCheck->row_array();

            // Only allow deletion of POs in 'Draft' status
            if ($po['PurchaseOrderStatus'] != 'Draft') {
                $this->sys_error("Cannot delete purchase order with status '{$po['PurchaseOrderStatus']}'. Only Draft orders can be deleted.");
                $this->db->trans_rollback();
                exit;
            }

            // Step 1: Get all purchase_order_detail records to update purchase_request_flag
            $sqlDetails = "SELECT * FROM purchase_order_detail 
                        LEFT JOIN purchase_request_detail
                        ON PurchaseOrderDetailPurchaseRequestDetailID = PurchaseRequestDetailID
                        WHERE PurchaseOrderDetailPurchaseOrderID = ? 
                        AND PurchaseOrderDetailIsActive = 'Y'";
            $execDetails = $this->db->query($sqlDetails, [$purchaseOrderId]);

            if (!$execDetails) {
                $this->sys_error_db("Error retrieving purchase order details", $this->db);
                $this->db->trans_rollback();
                exit;
            }

            $details = $execDetails->result_array();

            // Step 2: Update purchase_request_flag for each detail (decrement QtyProses)
            foreach ($details as $detail) {
                $sqlUpdateFlag = "UPDATE purchase_request_flag 
                                SET PurchaseRequestFlagQtyProses = PurchaseRequestFlagQtyProses - {$detail['PurchaseRequestDetailQty']} 
                                WHERE PurchaseRequestFlagID = {$detail['PurchaseOrderDetailPurchaseRequestFlagID']}";

                $execUpdateFlag = $this->db->query($sqlUpdateFlag);

                if (!$execUpdateFlag) {
                    $this->sys_error_db("Error updating purchase_request_flag", $this->db);
                    $this->db->trans_rollback();
                    exit;
                }
            }

            // Step 3: Soft delete purchase_order_detail
            $sqlDeleteDetail = "UPDATE purchase_order_detail 
                            SET PurchaseOrderDetailIsActive = 'N', 
                                PurchaseOrderDetailDeleted = NOW(),
                                PurchaseOrderDetailDeletedUserID = ? 
                            WHERE PurchaseOrderDetailPurchaseOrderID = ?";

            $execDeleteDetail = $this->db->query($sqlDeleteDetail, [$userId, $purchaseOrderId]);

            if (!$execDeleteDetail) {
                $this->sys_error_db("Error deleting purchase_order_detail", $this->db);
                $this->db->trans_rollback();
                exit;
            }

            // Step 4: Soft delete purchase_order_summary
            $sqlDeleteSummary = "UPDATE purchase_order_summary 
                                SET PurchaseOrderSummaryIsActive = 'N',
                                    PurchaseOrderSummaryDeleted = NOW(),
                                    PurchaseOrderSummaryDeletedUserID = ? 
                                WHERE PurchaseOrderSummaryPurchaseOrderID = ?";

            $execDeleteSummary = $this->db->query($sqlDeleteSummary, [$userId, $purchaseOrderId]);

            if (!$execDeleteSummary) {
                $this->sys_error_db("Error deleting purchase_order_summary", $this->db);
                $this->db->trans_rollback();
                exit;
            }

            // Step 5: Soft delete purchase_order
            $sqlDeletePO = "UPDATE purchase_order 
                        SET PurchaseOrderIsActive = 'N',
                            PurchaseOrderDeleted = NOW(),
                            PurchaseOrderDeletedUserID = ? 
                        WHERE PurchaseOrderID = ?";

            $execDeletePO = $this->db->query($sqlDeletePO, [$userId, $purchaseOrderId]);

            if (!$execDeletePO) {
                $this->sys_error_db("Error deleting purchase_order", $this->db);
                $this->db->trans_rollback();
                exit;
            }

            // Add log entry for the deletion
            $this->insertLog(
                $purchaseOrderId,
                "DELETE",
                $payload,
                $poBefore,
                [], // No after data since it's deleted
                $userId,
                "Delete purchase order {$po['PurchaseOrderNumber']}"
            );

            // Commit transaction if all operations succeed
            $this->db->trans_commit();

            $result = array(
                "success" => true,
                "message" => "Purchase order {$po['PurchaseOrderNumber']} has been deleted successfully"
            );
            $this->sys_ok($result);
        } catch (Exception $exc) {
            $this->db->trans_rollback(); // Rollback on any error
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    function getItemUpdate()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
            }

            $payload = $this->sys_input;
            $regionalId = $this->sys_user["S_RegionalID"];

            $sql = "SELECT * FROM purchase_order 
                    WHERE PurchaseOrderID = ?";
            $qry = $this->db->query($sql, [$payload['POID']]);

            if (!$qry) {
                $this->db->trans_rollback();
                $this->sys_error_db("select PO error", $this->db);
                exit;
            }
            $PO = $qry->row_array();
            $sql = "SELECT
                    PurchaseOrderID,
                    PurchaseOrderSupplierID,
                    PurchaseOrderSummaryID,
                    PurchaseOrderSummaryQty as TotalPoQty, 
                    PurchaseOrderSummaryPrice as SummaryPrice, 
                    PurchaseOrderSummaryTotal as SummaryTotal,
                    PurchaseOrderSummaryDiscountAmount summaryDiscountAmount,
                    PurchaseOrderSummaryDiscountType  as discountType,
                    CASE
                        WHEN PurchaseOrderSummaryDiscountType = 'R' THEN PurchaseOrderSummaryDiscountRupiah
                        WHEN  PurchaseOrderSummaryDiscountType = 'P' THEN PurchaseOrderSummaryDiscountPercent
                        ELSE 0
                    END as discount,

                    PurchaseOrderDetailID,
                    PurchaseOrderDetailPrice as Price,
                    PurchaseOrderDetailTotal as Total,
                    PurchaseOrderDetailQty as PoQty,

                    PurchaseRequestFlagID,
                    PurchaseRequestFlagM_BranchCode as BranchCode,
                    PurchaseRequestFlagQtyRest - PurchaseRequestFlagQtyProses as UnprocessFlagQty,

                    PurchaseRequestDetailID,
                    PurchaseRequestDetailPurchaseRequestID,
                    PurchaseRequestDetailQty as RequestQty,
                    unitreq.ItemUnitID as ReqItemUnitID,
                    unitreq.ItemUnitName as ReqItemUnitName,

                    itemdtl.M_ItemID,
                    itemdtl.M_ItemCode,
                    itemdtl.M_ItemDesc,
                    unitdtl.ItemUnitID as PoItemUnitID,
                    unitdtl.ItemUnitName as PoItemUnitName,
                    
                    unitsum.ItemUnitID summaryItemUnitID,
                    unitsum.ItemUnitName SummaryItemUnitName,
                    itemsum.M_ItemID SummaryItemID,
                    itemsum.M_ItemCode SummaryItemCode,
                    itemsum.M_ItemDesc SummaryItemDesc,

                    reqbranch.M_BranchName as RequesterBranchName,

                    S_RegionalName,
                    S_RegionalID,
                    warehouseBranch.M_BranchName,
                    warehouseBranch.M_BranchID,
                    WarehouseID,
                    PurchaseRequestNumber,
                    CASE
                        WHEN warehouseBranch.M_BranchID IS NULL OR warehouseBranch.M_BranchID = 0 THEN CONCAT(WarehouseCode,' ', WarehouseName, ' - ', S_RegionalName)
                        WHEN warehouseBranch.M_BranchID IS NOT NULL OR warehouseBranch.M_BranchID <> 0 THEN CONCAT(WarehouseCode,' ', WarehouseName, ' - ', warehouseBranch.M_BranchName)
                    END as WarehouseName
                    FROM purchase_order
                    JOIN purchase_order_summary
                        ON PurchaseOrderID = PurchaseOrderSummaryPurchaseOrderID 
                        AND PurchaseOrderIsActive = 'Y'
                        AND PurchaseOrderSummaryPurchaseOrderID = ?
                    JOIN purchase_order_detail
                        ON PurchaseOrderID = PurchaseOrderDetailPurchaseOrderID
                        AND PurchaseOrderSummaryID = PurchaseOrderDetailPurchaseSummaryID
                        AND PurchaseOrderDetailIsActive = 'Y'
                    JOIN purchase_request_flag
                        ON PurchaseOrderDetailPurchaseRequestFlagID = PurchaseRequestFlagID
                    JOIN purchase_request_detail
                        ON PurchaseRequestFlagPurchaseRequestDetailID = PurchaseRequestDetailID
                        AND PurchaseRequestFlagStatus LIKE '%PO%'
                    LEFT JOIN purchase_request
                        ON PurchaseRequestDetailPurchaseRequestID = PurchaseRequestID
                    JOIN m_item itemsum
                        ON PurchaseOrderSummaryItemID=itemsum.M_ItemID
                    JOIN m_item itemdtl
                        ON PurchaseRequestDetailM_ItemID =itemdtl.M_ItemID
                    JOIN supplier_price ON 
                        PurchaseRequestDetailM_ItemID = SupplierPriceM_ItemID 
                        AND PurchaseOrderSupplierID = SupplierPriceSupplierID
                        AND SupplierPriceItemUnitID = PurchaseRequestDetailItemUnitID 
                        AND (SupplierPriceFlagQty ='T' OR 
                            (
                                (SupplierPriceMinInclusive = 'Y' AND PurchaseRequestDetailQty >= SupplierPriceMinQty) OR 
                                (SupplierPriceMinInclusive = 'N' AND PurchaseRequestDetailQty > SupplierPriceMinQty)
                            ) AND
                            (
                                (SupplierPriceMaxInclusive = 'Y' AND PurchaseRequestDetailQty <= SupplierPriceMaxQty) OR 
                                (SupplierPriceMaxInclusive = 'N' AND PurchaseRequestDetailQty < SupplierPriceMaxQty)
                            )
                        ) 
                        AND SupplierPriceIsActive = 'Y'
                    JOIN itemunit unitsum
                        ON PurchaseOrderSummaryItemUnitID = unitsum.ItemUnitID -- Unit Purchase
                    JOIN itemunit unitdtl
                        ON PurchaseOrderDetailItemUnitID = unitdtl.ItemUnitID -- Unit Purchase
                    JOIN itemunit unitreq
                        ON PurchaseRequestDetailItemUnitID = unitreq.ItemUnitID -- Unit Request
                    JOIN s_regional
                        ON PurchaseRequestFlagS_RegionalID = S_RegionalID AND S_RegionalIsActive = 'Y'
                    JOIN warehouse 
                        ON PurchaseOrderDetailWarehouseID = WarehouseID
                    LEFT JOIN m_branch warehouseBranch
                        ON WarehouseM_BranchID = warehouseBranch. M_BranchID
                        AND M_BranchIsActive = 'Y'
                    LEFT JOIN m_branch reqbranch
                        ON PurchaseRequestFlagM_BranchCode = reqbranch.M_BranchCode 
                        AND reqbranch.M_BranchIsActive = 'Y'
                    ORDER BY M_ItemDesc ASC";

            $qry = $this->db->query($sql, [$payload['POID']]);

            if (!$qry) {
                $this->db->trans_rollback();
                $this->sys_error_db("select items error", $this->db);
                exit;
            }

            $rows = $qry->result_array();
            $tmpSummaryID = [];
            $summary = [];

            $totalRealPrice = 0;

            /** 
             * A little Note:
             * data.records diambil dari $rows original hasil query ($row) 
             * data.summary diambil dari $rows dengan unique PurchaseOrderSummaryID 
             * (gabungan  dari $rows)
             */

            // Compose header data.summary
            foreach ($rows as $key => $row) {
                $rows[$key]['keyID'] = "{$row['M_ItemID']}_{$row['PoItemUnitID']}";

                $row['M_ItemID'] = $row['SummaryItemID'];
                $row['M_ItemCode'] = $row['SummaryItemCode'];
                $row['M_ItemDesc'] = $row['SummaryItemDesc'];

                $rows[$key]['RealPrice'] = $row['SummaryPrice'];
                $row['Price'] = doubleval($row['SummaryPrice']) - doubleval($row['summaryDiscountAmount']);
                $row['RealPrice'] = $row['SummaryPrice'];

                $row['Total'] = $row['SummaryTotal'];

                $rows[$key]['warehouse'] = array(
                    "WarehouseID" => $row['WarehouseID'],
                    "WarehouseName" => $row['WarehouseName'],
                );
                $rows[$key]['DefaultPurchase'] = $this->getDefaultPurchase($row['PurchaseOrderSupplierID'], $row['M_ItemID'], $row['PoQty']);

                if (count($tmpSummaryID) == 0) {
                    $tmpSummaryID[] = $row['PurchaseOrderSummaryID'];
                    $summary[] = $row;
                } else {
                    if (!in_array($row['PurchaseOrderSummaryID'], $tmpSummaryID)) {
                        $tmpSummaryID[] = $row['PurchaseOrderSummaryID'];
                        $summary[] = $row;
                    }
                }
                $totalRealPrice += $row['SummaryPrice'] * $row['SummaryQty'];
            }

            // Compose data.summary.Detail
            foreach ($summary as $key => $sm) {
                $summary[$key]['keyID'] = "{$sm['M_ItemID']}_{$sm['PoItemUnitID']}";
                foreach ($rows as $key1 => $row) {
                    if ($row['PurchaseOrderSummaryID'] == $sm['PurchaseOrderSummaryID']) {
                        $summary[$key]['Details'][] = $row;
                    }
                }
            }

            // Sisipkan total real price ke $PO
            $PO['TotalRealPrice'] = $totalRealPrice;

            $result = array(
                "records" => $rows,
                "summary" => $summary,
                "po" => $PO,
                // "sql" => $this->db->last_query()
            );

            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    function updateOrder()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
            }

            $this->db->trans_begin();

            $payload = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];
            $purchaseOrderId = $payload['PO']["PurchaseOrderID"];
            $isApprovalEdit = $payload["IsApprovalEdit"] ?? false;
            $updatedDetail = [];

            $sql = "SELECT * FROM purchase_order
                WHERE PurchaseOrderID = ?;";
            $exec = $this->db->query($sql, [$purchaseOrderId]);
            $updateMsg = [];

            $po = [];
            if (!$exec) {
                $this->db->trans_rollback();
                $this->sys_error_db("select purchase order error", $this->db);
                exit;
            }
            $po = $exec->row_array();

            if ($po['PurchaseOrderStatus'] != 'Draft' && !$isApprovalEdit) {
                $this->sys_error("Status Form {$po['PurchaseOrderStatus']} tidak dapat di ubah karena statusnya sudah bukan draft");
                exit;
            }
            if ($po['PurchaseOrderIsActive'] != 'Y') {
                $this->sys_error("{$po['PurchaseOrderStatus']} tidak dapat di ubah karena data sudah terhapus");
                exit;
            }

            $poBefore = $this->getDataPo($purchaseOrderId);

            $shippingCostStatus = $payload['ShippingCostStatus'] ? 'Y' : 'N';

            // Step 1: Update purchase_order
            $sqlUpdatePO = "UPDATE purchase_order 
                    SET 
                        PurchaseOrderDate = ?,
                        PurchaseOrderItemCategoryID = ?,
                        PurchaseOrderRefNumber = ?,
                        PurchaseOrderSupplierID = ?,
                        PurchaseOrderTaxPercentPph = ?,
                        PurchaseOrderTaxPercentPpn = ?,
                        PurchaseOrderPaymentTerm = ?,
                        PurchaseOrderDiscountPercent = ?,
                        PurchaseOrderDiscountAmount = ?,
                        PurchaseOrderWarehouseType = ?,
                        PurchaseOrderWarehouseID = ?,
                        PurchaseOrderNote = ?,
                        PurchaseOrderSubTotal = ?,
                        PurchaseOrderTaxAmountPph = ?,
                        PurchaseOrderTaxAmountPpn = ?,
                        PurchaseOrderGrandTotal = ?,
                        PurchaseOrderLastUpdated = NOW(),
                        PurchaseOrderUserID = ?,
                        PurchaseOrderShippingCost = ?,
                        PurchaseOrderShippingCostStatus = ?
                    WHERE PurchaseOrderID = ?
                    AND PurchaseOrderIsActive = 'Y'";

            // And modify the query execution:
            $exec = $this->db->query($sqlUpdatePO, [
                $payload['Date'],
                $payload['ItemCategoryID'],
                $payload['RefNumber'],
                $payload['SupplierID'],
                $payload['TaxPercentPph'],
                $payload['TaxPercentPpn'],
                $payload['PaymentTerm'],
                $payload['DiscountPercent'],
                $payload['DiscountAmount'],
                $payload['WarehouseType'],
                $payload['WarehouseID'], // bisa null kalau warehouseType == single
                $payload['Note'],
                $payload['SubTotal'],
                $payload['TaxAmountPph'],
                $payload['TaxAmountPpn'],
                $payload['GrandTotal'],
                $userId,
                $payload['ShippingCost'],
                $shippingCostStatus,
                $purchaseOrderId
            ]);
            if (!$exec) {
                $this->db->trans_rollback();
                $this->sys_error_db("Error updating purchase_order", $this->db);
                return;
            }
            $updateMsg[] = "- Update data purchase order \n";

            // Step 2: Nonaktifkan semua purchase_order_summary dan purchase_order_detail
            $sqlDeactivateSummary = "UPDATE purchase_order_summary 
                SET PurchaseOrderSummaryIsActive = 'N' ,
                    PurchaseOrderSummaryDeletedUserID = ?,
                    PurchaseOrderSummaryDeleted = NOW()
                WHERE PurchaseOrderSummaryPurchaseOrderID = ?";

            $exec = $this->db->query($sqlDeactivateSummary, [$userId, $purchaseOrderId]);
            if (!$exec) {
                $this->db->trans_rollback();
                $this->sys_error_db("Error deactivating purchase_order_summary", $this->db);
                return;
            }

            $sqlDeactivateDetail = "UPDATE purchase_order_detail 
                SET PurchaseOrderDetailIsActive = 'N' ,
                    PurchaseOrderDetailLastUpdated = NOW()
                WHERE PurchaseOrderDetailPurchaseOrderID = ?";

            $exec = $this->db->query($sqlDeactivateDetail, [$purchaseOrderId]);
            if (!$exec) {
                $this->db->trans_rollback();
                $this->sys_error_db("Error deactivating purchase_order_detail", $this->db);
                return;
            }

            // Step 3: Insert/Update purchase_order_summary dan purchase_order_detail
            foreach ($payload['Summary'] as $summary) {
                // Insert baru untuk purchase_order_summary jika ada item tambahan saat edit
                if ($summary['PurchaseOrderID'] == 0 || $summary['PurchaseOrderSummaryID'] == 0) {
                    $discountAmount = 0;
                    if ($summary['discountType'] == 'R') $discountAmount = doubleval($summary['discount']);
                    if ($summary['discountType'] == 'P') $discountAmount = (doubleval($summary['discount']) / 100) *  doubleval($summary['RealPrice']);
                    $updateMsg[] =  "- Add data purchase order summary {$summary['M_ItemDesc']} {$summary['TotalPoQty']} {$summary['ItemUnitName']} \n";
                    $sqlInsertSummary = "INSERT INTO purchase_order_summary (
                        PurchaseOrderSummaryPurchaseOrderID,
                        PurchaseOrderSummaryItemID,
                        PurchaseOrderSummaryItemUnitID,
                        PurchaseOrderSummaryQty,
                        PurchaseOrderSummaryPrice,
                        PurchaseOrderSummaryTotal,
                        PurchaseOrderSummaryIsActive,
                        PurchaseOrderSummaryCreatedUserID,
                        PurchaseOrderSummaryCreated,
                        PurchaseOrderSummaryDiscountRupiah,
                        PurchaseOrderSummaryDiscountPercent,
                        PurchaseOrderSummaryDiscountAmount,
                        PurchaseOrderSummaryDiscountType
                    ) VALUES (?,?,?,?,?,?,'Y',?,NOW(),?,?,?,?)";

                    $exec = $this->db->query($sqlInsertSummary, [
                        $purchaseOrderId,
                        $summary['M_ItemID'],
                        $summary['PoItemUnitID'],
                        $summary['TotalPoQty'],
                        $summary['RealPrice'],
                        $summary['Total'],
                        $userId,
                        $summary['discountType'] == 'R' ? $summary['discount'] : 0,
                        $summary['discountType'] == 'P' ? $summary['discount'] : 0,
                        $discountAmount,
                        $summary['discountType']
                    ]);
                    if (!$exec) {
                        $this->db->trans_rollback();
                        $this->sys_error_db("Error inserting purchase_order_summary", $this->db);
                        return;
                    }

                    $summaryId = $this->db->insert_id();

                    // Insert baru untuk purchase_order_detail
                    foreach ($summary['Details'] as $detail) {
                        $sql = "SELECT * FROM purchase_request_flag
                            WHERE PurchaseRequestFlagID = ?
                            AND PurchaseRequestFlagIsActive = 'Y'";
                        $qry = $this->db->query($sql, [$detail['PurchaseRequestFlagID']]);
                        if (!$qry) {
                            $this->sys_error_db("Error checking purchase_request_flag", $this->db);
                            $this->db->trans_rollback();
                            exit;
                        }

                        $row = $qry->row_array();
                        if (!$row) {
                            $this->sys_error("Data {$detail['M_ItemCode']} - {$detail['M_ItemDesc']} cabang {$detail['M_BranchName']} regional {$detail['S_RegionalName']} tidak ditemukan, silahkan refresh item");
                            $this->db->trans_rollback();
                            exit;
                        }

                        $qtyRest = floatval($row['PurchaseRequestFlagQtyRest']);
                        $qtyProses = floatval($row['PurchaseRequestFlagQtyProses']);

                        if (($qtyRest - $qtyProses) <= 0) {
                            $this->sys_error("Qty {$detail['M_ItemCode']} - {$detail['M_ItemDesc']} cabang {$detail['M_BranchName']} regional {$detail['S_RegionalName']} tidak mencukupi karena sisa qty sudah habis diproses, silahkan refresh item");
                            $this->db->trans_rollback();
                            exit;
                        }
                        $updateMsg[] =  "- Add data purchase order detail summary {$summary['M_ItemDesc']} {$detail['PoQty']} {$detail['ItemUnitName']} \n";
                        $sqlInsertDetail = "INSERT INTO purchase_order_detail (
                            PurchaseOrderDetailPurchaseOrderID,
                            PurchaseOrderDetailPurchaseSummaryID,
                            PurchaseOrderDetailPurchaseRequestID,
                            PurchaseOrderDetailPurchaseRequestDetailID,
                            PurchaseOrderDetailPurchaseRequestFlagID,
                            PurchaseOrderDetailItemID,
                            PurchaseOrderDetailItemUnitID,
                            PurchaseOrderDetailRequestQty,
                            PurchaseOrderDetailQty,
                            PurchaseOrderDetailPrice,
                            PurchaseOrderDetailTotal,
                            PurchaseOrderDetailWarehouseID,
                            PurchaseOrderDetailIsActive,
                            PurchaseOrderDetailUserID,
                            PurchaseOrderDetailCreated,
                            PurchaseOrderDetailLastUpdated
                        ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW(),NOW())";

                        $exec = $this->db->query($sqlInsertDetail, [
                            $purchaseOrderId,
                            $summaryId,
                            $detail['PurchaseRequestID'],
                            $detail['PurchaseRequestDetailID'],
                            $detail['PurchaseRequestFlagID'],
                            $detail['M_ItemID'],
                            $detail['PoItemUnitID'],
                            $detail['RequestQty'],
                            $detail['PoQty'],
                            $detail['Price'],
                            $detail['Total'],
                            $detail['warehouse']['WarehouseID'],
                            'Y',
                            $userId,
                        ]);
                        if (!$exec) {
                            $this->db->trans_rollback();
                            $this->sys_error_db("Error inserting purchase_order_detail", $this->db);
                            return;
                        }
                        $sqlUpdateFlag = "UPDATE purchase_request_flag
                                    SET PurchaseRequestFlagQtyProses = PurchaseRequestFlagQtyProses + {$detail['RequestQty']}
                                    WHERE PurchaseRequestFlagID = {$detail['PurchaseRequestFlagID']}";

                        $exec = $this->db->query($sqlUpdateFlag);

                        if (!$exec) {
                            $this->sys_error_db("purchase_request_flag update error", $this->db);
                            $this->db->trans_rollback();
                            exit;
                        }
                    }
                } else {
                    // Update purchase_order_summary untuk item yang diedit
                    $updateMsg[] =  "- Update data purchase order summary {$summary['M_ItemDesc']} {$summary['TotalPoQty']} {$summary['ItemUnitName']} \n";

                    $discountAmount = 0;
                    if ($summary['discountType'] == 'R') $discountAmount = doubleval($summary['discount']);
                    if ($summary['discountType'] == 'P') $discountAmount = (doubleval($summary['discount']) / 100) *  doubleval($summary['RealPrice']);
                    $sqlUpdateSummary = "UPDATE purchase_order_summary 
                    SET 
                        PurchaseOrderSummaryQty = ?,
                        PurchaseOrderSummaryPrice = ?,
                        PurchaseOrderSummaryTotal = ?,
                        PurchaseOrderSummaryIsActive = 'Y',
                        PurchaseOrderSummaryUpdated = NOW(),
                        PurchaseOrderSummaryUpdatedUserID = ?,
                        PurchaseOrderSummaryDiscountRupiah = ?,
                        PurchaseOrderSummaryDiscountPercent = ?,
                        PurchaseOrderSummaryDiscountAmount = ?,
                        PurchaseOrderSummaryDiscountType = ?
                    WHERE PurchaseOrderSummaryID = ?
                ";

                    $exec = $this->db->query($sqlUpdateSummary, [
                        $summary['TotalPoQty'],
                        $summary['RealPrice'],
                        $summary['Total'],
                        $userId,
                        $summary['discountType'] == 'R' ? $summary['discount'] : 0,
                        $summary['discountType'] == 'P' ? $summary['discount'] : 0,
                        $discountAmount,
                        $summary['discountType'],
                        $summary['PurchaseOrderSummaryID'],
                    ]);
                    if (!$exec) {
                        $this->db->trans_rollback();
                        $this->sys_error_db("Error updating purchase_order_summary", $this->db);
                        return;
                    }
                    // Update purchase_order_detail
                    foreach ($summary['Details'] as $detail) {
                        if (
                            $detail['PurchaseOrderDetailID'] !== null && $detail['PurchaseOrderDetailID'] != 0
                            && $detail['PurchaseOrderDetailID'] != '0'
                        ) {
                            $updatedDetail[] = $detail['PurchaseOrderDetailID'];
                            // Update data yang sudah ada
                            $updateMsg[] =  "- Update data purchase order summary detail {$summary['M_ItemDesc']} {$detail['PoQty']} {$detail['ItemUnitName']} \n";

                            $sqlUpdateDetail = "UPDATE purchase_order_detail 
                            SET 
                                PurchaseOrderDetailRequestQty = {$detail['RequestQty']},
                                PurchaseOrderDetailQty = {$detail['PoQty']},
                                PurchaseOrderDetailPrice = {$detail['Price']},
                                PurchaseOrderDetailTotal = {$detail['Total']},
                                PurchaseOrderDetailWarehouseID = {$detail['warehouse']['WarehouseID']},
                                PurchaseOrderDetailIsActive = 'Y',
                                PurchaseOrderDetailLastUpdated = NOW()
                            WHERE PurchaseOrderDetailID = {$detail['PurchaseOrderDetailID']} ";

                            $exec = $this->db->query($sqlUpdateDetail);
                            if (!$exec) {
                                $this->db->trans_rollback();
                                $this->sys_error_db("Error updating purchase_order_detail", $this->db);
                                return;
                            }
                        } else {
                            $updateMsg[] =  "- Add data purchase order summary detail {$summary['M_ItemDesc']} {$detail['PoQty']} {$detail['ItemUnitName']} \n";

                            $sql = "SELECT * FROM purchase_request_flag
                                WHERE PurchaseRequestFlagID = ?
                                AND PurchaseRequestFlagIsActive = 'Y'";
                            $qry = $this->db->query($sql, $detail['PurchaseRequestFlagID']);
                            if (!$qry) {
                                $this->sys_error_db("Error checking purchase_request_flag", $this->db);
                                $this->db->trans_rollback();
                                exit;
                            }

                            $row = $qry->row_array();
                            if (!$row) {
                                $this->sys_error("Data {$detail['M_ItemCode']} - {$detail['M_ItemDesc']} cabang {$detail['M_BranchName']} regional {$detail['S_RegionalName']} tidak ditemukan, silahkan refresh item");
                                $this->db->trans_rollback();
                                exit;
                            }

                            $qtyRest = floatval($row['PurchaseRequestFlagQtyRest']);
                            $qtyProses = floatval($row['PurchaseRequestFlagQtyProses']);

                            if (($qtyRest - $qtyProses) <= 0) {
                                $this->sys_error("Qty {$detail['M_ItemCode']} - {$detail['M_ItemDesc']} cabang {$detail['M_BranchName']} regional {$detail['S_RegionalName']} tidak mencukupi karena sisa qty sudah habis diproses, silahkan refresh item");
                                $this->db->trans_rollback();
                                exit;
                            }

                            // Insert data baru
                            $sqlInsertDetail = "INSERT INTO purchase_order_detail (
                                PurchaseOrderDetailPurchaseOrderID,
                                PurchaseOrderDetailPurchaseSummaryID,
                                PurchaseOrderDetailPurchaseRequestID,
                                PurchaseOrderDetailPurchaseRequestDetailID,
                                PurchaseOrderDetailPurchaseRequestFlagID,
                                PurchaseOrderDetailItemID,
                                PurchaseOrderDetailItemUnitID,
                                PurchaseOrderDetailRequestQty,
                                PurchaseOrderDetailQty,
                                PurchaseOrderDetailPrice,
                                PurchaseOrderDetailTotal,
                                PurchaseOrderDetailWarehouseID,
                                PurchaseOrderDetailIsActive,
                                PurchaseOrderDetailUserID,
                                PurchaseOrderDetailCreated,
                                PurchaseOrderDetailLastUpdated
                            ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW(),NOW())";

                            $exec = $this->db->query($sqlInsertDetail, [
                                $purchaseOrderId,
                                $summary['PurchaseOrderSummaryID'],
                                $detail['PurchaseRequestID'],
                                $detail['PurchaseRequestDetailID'],
                                $detail['PurchaseRequestFlagID'],
                                $detail['M_ItemID'],
                                $detail['PoItemUnitID'],
                                $detail['RequestQty'],
                                $detail['PoQty'],
                                $detail['Price'],
                                $detail['Total'],
                                $detail['warehouse']['WarehouseID'],
                                'Y',
                                $userId,
                            ]);
                            if (!$exec) {
                                $this->db->trans_rollback();
                                $this->sys_error_db("Error inserting purchase_order_detail", $this->db);
                                return;
                            }
                            $sqlUpdateFlag = "UPDATE purchase_request_flag
                                    SET PurchaseRequestFlagQtyProses = PurchaseRequestFlagQtyProses + {$detail['RequestQty']}
                                    WHERE PurchaseRequestFlagID = {$detail['PurchaseRequestFlagID']}";

                            $exec = $this->db->query($sqlUpdateFlag);

                            if (!$exec) {
                                $this->sys_error_db("purchase_request_flag update error", $this->db);
                                $this->db->trans_rollback();
                                exit;
                            }
                        }
                    }
                }
            }
            //cari dari deleted item yang benar benar di deleted mana
            $deletedID = [];
            foreach ($payload['deletedItem'] as $key => $deleted) {
                if (!in_array($deleted['PurchaseOrderDetailID'], $updatedDetail)) {
                    $deletedID[] = $deleted;
                    $updateMsg[] =  "- Delete data purchase order detail {$deleted['M_ItemDesc']} {$deleted['PoQty']} {$deleted['ItemUnitName']} \n";

                    $sqlUpdateFlag = "UPDATE purchase_request_flag
                                    SET PurchaseRequestFlagQtyProses = PurchaseRequestFlagQtyProses - {$deleted['RequestQty']}
                                    WHERE PurchaseRequestFlagID = {$deleted['PurchaseRequestFlagID']}";

                    $exec = $this->db->query($sqlUpdateFlag);

                    if (!$exec) {
                        $this->sys_error_db("purchase_request_flag update error", $this->db);
                        $this->db->trans_rollback();
                        exit;
                    }
                }
            }
            $poAfter = $this->getDataPo($purchaseOrderId);

            $this->insertLog(
                $purchaseOrderId,
                "UPDATE",
                $payload,
                $poBefore,
                $poAfter,
                $userId,
                implode($updateMsg)
            );


            // Commit transaction jika semua berhasil
            if ($this->db->trans_status() === FALSE) {
                $this->db->trans_rollback();
                $this->sys_error_db("Error updating purchase order", $this->db);
            } else {
                $this->db->trans_commit();
                $this->sys_ok([
                    "Message" => "Success",
                    "Deleted" => $deletedID,
                ]);
            }
        } catch (Exception $exc) {
            $this->db->trans_rollback();
            $this->sys_error_db("Error updating purchase order", $exc);
        }
    }

    function requestOrder()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }

            $this->db->trans_begin();

            $payload = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];
            $poBefore = $this->getDataPo($payload["ID"]);
            $sql = "SELECT * FROM purchase_order
                WHERE PurchaseOrderID = ?;";
            $exec = $this->db->query($sql, [$payload["ID"]]);
            $branchId   = $this->sys_user['M_BranchID'];
            $regionalId = $this->sys_user['S_RegionalID'];

            $po = [];
            if (!$exec) {
                $this->db->trans_rollback();
                $this->sys_error_db("select purchase order error", $this->db);
                exit;
            }
            $po = $exec->row_array();

            if ($po['PurchaseOrderStatus'] != 'Draft') {
                $this->sys_error("{$po['PurchaseOrderStatus']} tidak dapat di ubah karena statusnya sudah bukan draft");
                exit;
            }
            if ($po['PurchaseOrderIsActive'] != 'Y') {
                $this->sys_error("{$po['PurchaseOrderStatus']} tidak dapat di ubah karena data sudah terhapus");
                exit;
            }

            $sql = "UPDATE purchase_order SET
                    PurchaseOrderStatus = 'Pending',
                    PurchaseOrderLastUpdated = NOW(),
                    PurchaseOrderUserID = {$userId}
                    WHERE PurchaseOrderID = {$payload["ID"]}
                    AND PurchaseOrderIsActive = 'Y'";
            $exec = $this->db->query($sql, []);

            if (!$exec) {
                $this->db->trans_rollback();
                $this->sys_error_db("update purchase order status error", $this->db);
                exit;
            }

            $sqlDetail = "UPDATE purchase_order_detail SET
                         PurchaseOrderDetailLastUpdated = NOW(),
                         PurchaseOrderDetailUserID = {$userId}
                         WHERE PurchaseOrderDetailPurchaseOrderID = {$payload["ID"]}
                         AND PurchaseOrderDetailIsActive = 'Y'";
            $exec = $this->db->query($sqlDetail, []);

            if (!$exec) {
                $this->db->trans_rollback();
                $this->sys_error_db("update purchase order detail error", $this->db);
                exit;
            }
            $poAfter = $this->getDataPo($payload["ID"]);

            $this->insertLog($payload["ID"], "REQUEST PO", $payload, $poBefore, $poAfter, $userId);

            $this->db->trans_commit();

            $sql = "SELECT *, 
                    ROW_NUMBER() OVER(ORDER BY PurchaseOrderNumber) RowNumber 
                    FROM purchase_order 
                    WHERE PurchaseOrderIsActive = 'Y' 
                    AND PurchaseOrderID = {$payload["ID"]}";
            $exec = $this->db->query($sql, []);

            $row = [];
            if (!$exec) {
                $this->db->trans_rollback();
                $this->sys_error_db("select purchase order error", $this->db);
                exit;
            } else {
                $row = $exec->result_array();
            }

            $number = $row[0]['PurchaseOrderNumber'];

            // notification
            $this->saveNotification($userId, $payload['Date'], $number, $payload["ID"], $branchId, $regionalId);

            $result = array("total" => 1, "records" => $row);
            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    function approvePOrder()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }

            $this->db->trans_begin();
            $payload = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];
            $approvelevel = $payload['approvelevel'];

            if ($approvelevel == '1') {
                $sql = "UPDATE purchase_order SET
                    PurchaseOrderApprovedManagerUserID = ?,
                    PurchaseOrderLastUpdated = NOW()
                    WHERE PurchaseOrderID = ?
                    AND PurchaseOrderIsActive = 'Y'";
                $exec = $this->db->query($sql, [$userId, $payload['poID']]);
                if (!$exec) {
                    $this->db->trans_rollback();
                    $this->sys_error_db("[Error] update approved by manager user id");
                    exit;
                }
            } else if ($approvelevel == '2') {
                $sql = "UPDATE purchase_order SET
                        PurchaseOrderStatus = 'Approved',
                        PurchaseOrderLastUpdated = NOW(),
                        PurchaseOrderApprovedUserID = ?
                        WHERE PurchaseOrderID = ?
                        AND PurchaseOrderIsActive = 'Y'";
                $exec = $this->db->query($sql, [$userId, $payload['poID']]);
                if (!$exec) {
                    $this->db->trans_rollback();
                    $this->sys_error_db("[Error] update status PO ke approved");
                    exit;
                }

                $sqlDetail = "UPDATE purchase_order_detail SET
                            PurchaseOrderDetailLastUpdated = NOW(),
                            PurchaseOrderDetailLastUpdatedUserID = ?
                            WHERE PurchaseOrderDetailPurchaseOrderID = ?
                            AND PurchaseOrderDetailIsActive = 'Y'";
                $exec = $this->db->query($sqlDetail, [$userId, $payload['poID']]);
                if (!$exec) {
                    $this->db->trans_rollback();
                    $this->sys_error_db("[Error] update status PO Detail ke approved");
                    exit;
                }

                $sqlSummary = "UPDATE purchase_order_summary SET
                            PurchaseOrderSummaryUpdated = NOW(),
                            PurchaseOrderSummaryUpdatedUserID = ?
                            WHERE PurchaseOrderSummaryPurchaseOrderID = ?
                            AND PurchaseOrderSummaryIsActive = 'Y'";
                $exec = $this->db->query($sqlSummary, [$userId, $payload['poID']]);
                if (!$exec) {
                    $this->db->trans_rollback();
                    $this->sys_error_db("[Error] update status PO Detail ke approved");
                    exit;
                }
            }

            $this->readNotif($approvelevel, $userId, $payload['poID']);

            $this->db->trans_commit();
            $this->sys_ok("[Success] success update status PO to Approved");
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    // read notification
    function readNotif($userlevel, $userId, $refID)
    {

        $this->db->trans_begin();

        // cari user penerima notifikasi
        $sql_get = "SELECT PurchaseOrderID,
                M_UserID,
                M_UserUsername,
                NotificationID,
                NotificationDetailID,
                NotificationDetailStatus,
                NotificationDetailM_UserID,
                NotificationDetailM_ApproveLevelID
                FROM purchase_order  
                JOIN notification ON PurchaseOrderID = NotificationRefID
                AND PurchaseOrderIsActive = 'Y'
                JOIN notification_detail ON NotificationID = NotificationDetailNotificationID
                JOIN m_user ON NotificationUserID = M_UserID
                WHERE PurchaseOrderID = ?
                AND NotificationDetailStatus = 'unread'";
        $qry = $this->db->query($sql_get, [$refID]);
        if (!$qry) {
            $this->sys_error_db("select user notification error", $this->db);
            exit;
        }
        $rowsuser = $qry->result_array();


        foreach ($rowsuser as $user) {


            if ($userlevel === '1') {
                // verifikasi manager
                $sql = "UPDATE notification_detail SET 
                        NotificationDetailStatus = 'read',
                        NotificationDetailLastUpdated = NOW(),
                        NotificationDetailUserID = ?
                        WHERE NotificationDetailNotificationID = ?
                        AND NotificationDetailM_ApproveLevelID = ?";
                $qry = $this->db->query($sql, [$userId, $user["NotificationID"], $user["NotificationDetailM_ApproveLevelID"]]);
                if (!$qry) {
                    $this->sys_error_db("update notification error", $this->db);
                    exit;
                }
            } else if ($userlevel === '2') {
                // approve kepala cabang / regional
                $sql = "UPDATE notification_detail SET 
                        NotificationDetailStatus = 'read',
                        NotificationDetailLastUpdated = NOW(),
                        NotificationDetailUserID = ?
                        WHERE NotificationDetailNotificationID = ?
                        AND NotificationDetailM_ApproveLevelID = ?";
                $qry = $this->db->query($sql, [$userId, $user["NotificationID"], $user["NotificationDetailM_ApproveLevelID"]]);
                if (!$qry) {
                    $this->sys_error_db("update notification error", $this->db);
                    exit;
                }
            }
        }

        $this->db->trans_commit();
    }

    /** 
     * Function untuk mengecek:
     * Apakah selectedItem dari FE boleh multiple gudang atau tidak
     * 
     * @param: array PurchaseRequestDetailID 
     * @return: boolean true jika boleh multiple, false jika tidak
     * Author: Mario
     * Date: 24 Juni 2025
     */
    function isValidMultipleWarehouse()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }

            $prm = $this->sys_input;
            if (!isset($prm['PurchaseRequestDetailIDs']) || empty($prm['PurchaseRequestDetailIDs'])) {
                $this->sys_error("PurchaseRequestDetailIDs tidak boleh kosong");
                exit;
            }
            $arrPrDetailID = $prm['PurchaseRequestDetailIDs'];

            $placeholders_1 = implode(',', array_fill(0, count($arrPrDetailID), '?'));

            $sqlPurchase = "SELECT 
                PurchaseRequestDetailID,
                PurchaseRequestNumber as PRNumber,
                PurchaseRequestDetailM_ItemID,
                PurchaseRequestDetailItemUnitID as RequestItemUnitID,
                PurchaseRequestDetailQty as RequestQty,
                ItemUnitMapItemUnitID as PurchaseItemUnitID,
                ItemUnitMapIsPurchase,
                M_ItemDesc as ItemName
                FROM purchase_request_detail
                JOIN purchase_request
                    ON PurchaseRequestID = PurchaseRequestDetailPurchaseRequestID
                LEFT JOIN itemunitmap
                    ON ItemUnitMapM_ItemID = PurchaseRequestDetailM_ItemID
                    AND ItemUnitMapItemUnitID = PurchaseRequestDetailItemUnitID
                    AND ItemUnitMapIsActive = 'Y'
                    AND ItemUnitMapIsPurchase = 'Y'
                LEFT JOIN m_item
                    ON M_ItemID = PurchaseRequestDetailM_ItemID
                WHERE PurchaseRequestDetailID IN ($placeholders_1)";
            $qryPurchase = $this->db->query($sqlPurchase, $arrPrDetailID);
            if (!$qryPurchase) {
                $this->sys_error_db("Gagal query sqlPurchase di isValidMultipleWarehouse()");
                exit;
            }

            $rstPurchases = $qryPurchase->result_array();

            if (!empty($rstPurchases)) {
                // Cek Apakah semua ItemUnitMapIsPurchase = 'Y'
                // Jika ada != 'Y' maka masukkan ke $nonPurchaseItemIDs
                $nonPurchaseItemIDs = array_reduce($rstPurchases, function ($result, $item) {
                    if ($item['ItemUnitMapIsPurchase'] !== 'Y') {
                        $result[] = $item['PurchaseRequestDetailID'];
                    }
                    return $result;
                }, []);

                // Jika semua ItemUnitMapIsPurchase = 'Y' maka return true boleh multiple
                if (empty($nonPurchaseItemIDs)) {
                    $this->sys_ok([
                        'status' => true,
                        'message' => 'Bisa multiple gudang karena semua Unit Item Request = Purchase'
                    ]);
                    exit;
                }

                // Jika tidak, maka lanjut query unitconvert untuk PrID yang ada di $nonPurchaseItemIDs
                $placeholders_2 = implode(',', array_fill(0, count($nonPurchaseItemIDs), '?'));

                $sqlConvert = "SELECT 
                    PurchaseRequestDetailID,
                    PurchaseRequestDetailM_ItemID,
                    PurchaseRequestDetailItemUnitID as RequestItemUnitID,
                    PurchaseRequestDetailQty as RequestQty,
                    PurchaseRequestNumber as PRNumber,
                    M_ItemDesc as ItemName,
                    ItemUnitMapItemUnitID as PurchaseItemUnitID,
                    ItemUnitMapIsPurchase,
                    UnitConvertAmount,
                    reqUnit.ItemUnitName as RequestItemUnitName,
                    purUnit.ItemUnitName as PurchaseItemUnitName
                    FROM purchase_request_detail
                    JOIN purchase_request
                        ON PurchaseRequestID = PurchaseRequestDetailPurchaseRequestID
                    JOIN m_item
                        ON M_ItemID = PurchaseRequestDetailM_ItemID
                    LEFT JOIN itemunitmap
                        ON ItemUnitMapM_ItemID = PurchaseRequestDetailM_ItemID
                        AND ItemUnitMapIsPurchase = 'Y'
                        AND ItemUnitMapIsActive = 'Y'
                    LEFT JOIN unitconvert
                        ON UnitConvertFromItemUnitID = ItemUnitMapItemUnitID
                        AND UnitConvertToItemUnitID = PurchaseRequestDetailItemUnitID
                        AND UnitConvertIsActive = 'Y'
                    LEFT JOIN itemunit reqUnit
                        ON reqUnit.ItemUnitID = PurchaseRequestDetailItemUnitID
                    LEFT JOIN itemunit purUnit
                        ON purUnit.ItemUnitID = ItemUnitMapItemUnitID
                    WHERE PurchaseRequestDetailID IN ($placeholders_2)";
                $qryConvert = $this->db->query($sqlConvert, $nonPurchaseItemIDs);

                if (!$qryConvert) {
                    $this->sys_error_db("Gagal query sqlConvert di isValidMultipleWarehouse()");
                    exit;
                }
                if ($qryConvert->num_rows() == 0) {
                    $this->sys_ok([
                        'status' => false,
                        'message' => "Tidak bisa Multiple Gudang karena tidak ada mapping Konversi Unit Item untuk PurchaseRequestDetailID: " . implode(', ', $nonPurchaseItemIDs)
                    ]);
                    exit;
                }

                $rstConvert = $qryConvert->result_array();

                foreach ($rstConvert as $cvt) {
                    if (!$cvt['UnitConvertAmount'] || $cvt['UnitConvertAmount'] == null) {
                        $this->sys_ok([
                            'status' => false,
                            'message' => "Tidak bisa Multiple Gudang karena tidak ada Konversi Unit dari Unit {$cvt['PurchaseItemUnitName']} (Purchase) ke Unit {$cvt['RequestItemUnitName']} (Request) untuk Item {$cvt['ItemName']} (PR Number: {$cvt['PRNumber']})"
                        ]);
                        exit;
                    }

                    if ($cvt['RequestQty'] % $cvt['UnitConvertAmount'] != 0) {
                        $this->sys_ok([
                            'status' => false,
                            'message' => "Tidak bisa Multiple Gudang. Jumlah Item Request: {$cvt['ItemName']} (PR Number: {$cvt['PRNumber']}) minimal {$cvt['UnitConvertAmount']} {$cvt['RequestItemUnitName']} per {$cvt['PurchaseItemUnitName']} atau kelipatannya. Request saat ini: {$cvt['RequestQty']} {$cvt['RequestItemUnitName']}.",
                        ]);
                        exit;
                    }
                };

                // Kalau semuanya habis dibagi maka return true bisa multiple
                $this->sys_ok([
                    'status' => true,
                    'message' => 'Bisa multiple gudang karena ada Unit Convert yang valid untuk semua Item Unit Request'
                ]);
                exit;
            } else {
                $this->sys_ok([
                    'status' => false,
                    'message' => 'Tidak bisa multiple karena tidak menemukan PurchaseRequestDetailID: ' . implode(', ', $arrPrDetailID)
                ]);
            }
        } catch (Exception $e) {
            $message = $e->getMessage();
            $this->sys_error($message);
        }
    }

    function getDefaultPurchase_old($itemID, $unitTo)
    {
        try {
            $sql = "SELECT 
                ItemUnitID,
                ItemUnitCode,
                ItemUnitName,
                ItemUnitMapIsPurchase,
                ItemUnitMapMin,
                ItemUnitMapM_ItemID ,
                1 as UnitConvertAmount,
                SupplierPricePrice,
                'Y' isPurchased
                    FROM itemunitmap
                    JOIN m_item
                    ON ItemUnitMapM_ItemID  = M_itemID
                    JOIN itemunit
                    ON ItemUnitMapItemUnitID  = ItemUnitID
                    JOIN supplier_price 
                    ON ItemUnitMapM_ItemID  = SupplierPriceM_ItemID
                    AND ItemUnitMapItemUnitID  = SupplierPriceItemUnitID
                    WHERE ItemUnitMapM_ItemID = ?
                    AND ItemUnitMapItemUnitID = ?
                    AND ItemUnitMapIsPurchase = 'Y'; ";
            $exec = $this->db->query($sql, [$itemID, $unitTo]);

            if (!$exec) {
                $this->sys_error_db("Error get default purchase", $this->db);
                exit;
            }
            $rowDefault = $exec->row_array();

            if (!empty($rowDefault)) {
                return $rowDefault;
            }


            $sql = "SELECT 
                    ItemUnitID,
                    ItemUnitCode,
                    ItemUnitName,
                    ItemUnitMapIsPurchase,
                    ItemUnitMapMin,
                    ItemUnitMapM_ItemID ,
                    UnitConvertAmount,
                    SupplierPricePrice,
                    'N' isPurchased
                    FROM itemunitmap
                    JOIN itemunit
                    ON ItemUnitMapItemUnitID = ItemUnitID
                    JOIN unitconvert
                    ON ItemUnitID = UnitConvertFromItemUnitID  
                    AND UnitConvertToItemUnitID  = ?
                    AND UnitConvertIsActive = 'Y'
                    JOIN supplier_price
                    ON UnitConvertFromItemUnitID = SupplierPriceItemUnitID
                    AND SupplierPriceM_ItemID = ? 
                    WHERE ItemUnitMapIsPurchase = 'Y'
                    AND ItemUnitMapIsActive = 'Y'
                    AND ItemUnitMapM_ItemID = ?";
            $exec = $this->db->query($sql, [$unitTo, $itemID, $itemID]);

            if (!$exec) {
                $this->sys_error_db("Error get default purchase", $this->db);
                exit;
            }
            $row = $exec->result_array();

            $retVal = new stdClass(); // Menggunakan object kosong
            if (count($row) > 0) {
                $retVal = $row[0];
            }
            return $retVal;
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    function getDefaultPurchase($supplierID, $itemID, $qty)
    {
        try {
            $sql = "SELECT 
                ItemUnitID,
                ItemUnitCode,
                ItemUnitName,
                ItemUnitMapIsPurchase,
                ItemUnitMapMin,
                ItemUnitMapM_ItemID ,
                COALESCE(UnitConvertAmount, 1) as UnitConvertAmount,
                SupplierPricePrice,
                'Y' isPurchased
                FROM supplier_price
                JOIN m_item
                    ON M_ItemID  = SupplierPriceM_ItemID
                JOIN itemunitmap
                    ON ItemUnitMapM_ItemID = SupplierPriceM_ItemID
                    AND ItemUnitMapIsPurchase = 'Y'
                JOIN itemunit
                    ON ItemUnitID = ItemUnitMapItemUnitID
                LEFT JOIN unitconvert
                    -- Unit From pakai Unit Purchase 
                    ON UnitConvertFromItemUnitID = ItemUnitMapItemUnitID
                WHERE SupplierPriceSupplierID = ?
                AND SupplierPriceM_ItemID = ? 
                AND SupplierPriceIsActive = 'Y'
                AND (
                    SupplierPriceFlagQty = 'T'
                    OR (
                        (
                            (SupplierPriceMinInclusive = 'Y' AND $qty >= SupplierPriceMinQty)
                            OR
                            (SupplierPriceMinInclusive = 'N' AND $qty > SupplierPriceMinQty)
                        )
                        AND
                        (
                            (SupplierPriceMaxInclusive = 'Y' AND $qty <= SupplierPriceMaxQty)
                            OR
                            (SupplierPriceMaxInclusive = 'N' AND $qty < SupplierPriceMaxQty)
                        )
                    )
                )";
            $exec = $this->db->query($sql, [$supplierID, $itemID]);

            if (!$exec) {
                $this->sys_error_db("Error get default purchase", $this->db);
                exit;
            }
            $rowDefault = $exec->row_array();

            if (empty($rowDefault)) {
                return new stdClass(); // Return an empty object
            }

            return $rowDefault;
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    function getDefaultSupplierPrice()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }

            $prm = $this->sys_input;
            $supplierID = $prm['supplierID'];
            $itemID = $prm['itemID'];
            $qty = $prm['qty'];

            $sql = "SELECT 
                SupplierPricePrice
                FROM supplier_price
                JOIN m_item
                    ON M_ItemID  = SupplierPriceM_ItemID
                WHERE SupplierPriceSupplierID = ?
                AND SupplierPriceM_ItemID = ? 
                AND SupplierPriceIsActive = 'Y'
                AND (
                    SupplierPriceFlagQty = 'T'
                    OR (
                        (
                            (SupplierPriceMinInclusive = 'Y' AND $qty >= SupplierPriceMinQty)
                            OR
                            (SupplierPriceMinInclusive = 'N' AND $qty > SupplierPriceMinQty)
                        )
                        AND
                        (
                            (SupplierPriceMaxInclusive = 'Y' AND $qty <= SupplierPriceMaxQty)
                            OR
                            (SupplierPriceMaxInclusive = 'N' AND $qty < SupplierPriceMaxQty)
                        )
                    )
                )";
            $exec = $this->db->query($sql, [$supplierID, $itemID]);

            if (!$exec) {
                $this->sys_error_db("Error get default purchase", $this->db);
                exit;
            }
            $rowDefault = $exec->row_array();

            $result = array(
                "records" => $rowDefault
            );

            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    function getDataPo($poID)
    {
        $sql = "SELECT * FROM purchase_order
                WHERE PurchaseOrderID = ?;";
        $exec = $this->db->query($sql, [$poID]);

        $po = [];
        if (!$exec) {
            $this->db->trans_rollback();
            $this->sys_error_db("select purchase order error", $this->db);
            exit;
        }
        $po = $exec->row_array();
        $sql = "SELECT * FROM purchase_order_summary
                WHERE PurchaseOrderSummaryPurchaseOrderID = ?
                AND PurchaseOrderSummaryIsActive = 'Y';";
        $exec = $this->db->query($sql, [$poID]);

        $pos = [];
        if (!$exec) {
            $this->db->trans_rollback();
            $this->sys_error_db("select purchase order summary error", $this->db);
            exit;
        }
        $pos = $exec->result_array();

        $sql = "SELECT * FROM purchase_order_detail
                WHERE PurchaseOrderDetailPurchaseOrderID = ?
                AND PurchaseOrderDetailIsActive = 'Y';";
        $exec = $this->db->query($sql, [$poID]);

        $pod = [];
        if (!$exec) {
            $this->db->trans_rollback();
            $this->sys_error_db("select purchase order summary error", $this->db);
            exit;
        }
        $pod = $exec->result_array();
        $po['Summary'] = $pos;
        $po['Details'] = $pod;
        return $po;
    }

    function getPoBySupplier()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }

            $prm = $this->sys_input;
            $supplierID = $prm["supplierID"];

            $sql = "SELECT po.*,
                CASE 
                    WHEN po.PurchaseOrderDiscountPercent = 0 THEN 'Absolute'
                    WHEN po.PurchaseOrderDiscountAmount = 0 THEN 'Percentage'
                        ELSE '' 
                    END AS DiscountType,
                CASE 
                    WHEN po.PurchaseOrderDiscountPercent <> 0 THEN (po.PurchaseOrderDiscountPercent / 100) * PurchaseOrderSubTotal
                    WHEN po.PurchaseOrderDiscountAmount <> 0 THEN PurchaseOrderDiscountAmount
                        ELSE '' 
                    END AS DiscountAmount,
                PurchaseOrderTaxAmountPph + PurchaseOrderTaxAmountPpn AS TaxAmount,
                DATE_FORMAT(PurchaseOrderDate, '%d %M %Y') AS DisplayDate,
                SupplierCode,
                SupplierName,
                WarehouseCode,
                IFNULL(itemCategoryID, '') as itemCategoryID,
                IFNULL(itemCategoryName, '') as itemCategoryName,
                CASE
                    WHEN WarehouseType = 'B' THEN CONCAT(WarehouseCode,' ', WarehouseName, ' - ', M_BranchName) 
                    WHEN WarehouseType = 'R' THEN CONCAT(WarehouseCode,' ', WarehouseName, ' - ', S_RegionalName) 
                    ELSE ''
                END as WarehouseName
                FROM purchase_order po
                JOIN supplier ON SupplierID = PurchaseOrderSupplierID 
                LEFT JOIN item_category ON PurchaseOrderItemCategoryID = itemCategoryID 
                LEFT JOIN warehouse ON WarehouseID = PurchaseOrderWarehouseID
                LEFT JOIN s_regional ON S_RegionalID = WarehouseS_RegionalID
                LEFT JOIN m_branch ON M_BranchID = WarehouseM_BranchID
                WHERE po.PurchaseOrderIsActive = 'Y'
                AND po.PurchaseOrderSupplierID = ?";

            $queryCount = "SELECT count(*) as total
                          FROM purchase_order po
                          WHERE PurchaseOrderIsActive = 'Y'
                          AND PurchaseOrderSupplierID = ?";

            $qryCount = $this->db->query($queryCount, [$supplierID]);

            $numberLimit = 20;
            $numberOffset = 0;
            if ($prm["currentPage"] > 0) {
                $numberOffset = ($prm["currentPage"] - 1) * $numberLimit;
            }


            if ($qryCount) {
                $totalCount = $qryCount->result_array()[0]["total"];
                $totalPage = ceil($totalCount / $numberLimit);
            } else {
                $this->db->trans_rollback();
                $this->sys_error_db("get listing count po by supplier error", $this->db);
                exit;
            }

            $sql .= " ORDER BY PurchaseOrderCreated DESC
                    LIMIT ? OFFSET ?";
            $exec = $this->db->query($sql, [
                $supplierID,
                $numberLimit,
                $numberOffset
            ]);
            if ($exec) {
                $rows = $exec->result_array();
            } else {
                $this->db->trans_rollback();
                $this->sys_error_db("select purchase order", $this->db);
                exit;
            }

            foreach ($rows as $key => $row) {
                $rows[$key]['TotalRealPrice'] = 0;
                $rows[$key]['TotalDiskonPerItem'] = 0;

                // Hitung Total Real Price
                $sql = "SELECT PurchaseOrderSummaryPurchaseOrderID, 
                        SUM(PurchaseOrderSummaryQty * PurchaseOrderSummaryPrice) AS TotalRealPrice,
                        SUM(PurchaseOrderSummaryQty * PurchaseOrderSummaryDiscountAmount) AS TotalDiskonPerItem
                        FROM purchase_order_summary
                        WHERE PurchaseOrderSummaryPurchaseOrderID = ?";
                $qry = $this->db->query($sql, [$row['PurchaseOrderID']]);
                if ($qry) {
                    $summaryRow = $qry->row_array();
                    $rows[$key]['TotalRealPrice'] = floatval($summaryRow['TotalRealPrice']);
                    $rows[$key]['TotalDiskonPerItem'] = floatval($summaryRow['TotalDiskonPerItem']);
                } else {
                    $rows[$key]['TotalRealPrice'] = 0;
                    $rows[$key]['TotalDiskonPerItem'] = 0;
                    $this->db->trans_rollback();
                    $this->sys_error_db("select purchase order", $this->db);
                    exit;
                }
            }

            $result = array(
                "totalPage" => $totalPage,
                "totalFilter" => $totalCount,
                "records" => $rows
            );
            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    function insertLog($poID, $type, $prm, $dataBefore, $dataAfter, $userID, $desc = '')
    {
        // Query untuk menyisipkan log ke dalam tabel purchase_order_log
        $sql = "INSERT INTO acc_one_log.purchase_order_log (
                    PurchaseOrderLogPurchaseOrderID,
                    PurchaseOrderLogType,
                    PurchaseOrderLogPrm,
                    PurchaseOrderLogJSONBefore,
                    PurchaseOrderLogJSONAfter,
                    PurchaseOrderLogCreated,
                    PurchaseOrderLogUserID,
                    PurchaseOrderLogTypeDesc
                ) VALUES (
                    ?, ?, ?, ?, ?, NOW(), ?, ?
                )";

        // Eksekusi query dengan parameter yang diberikan
        $exec = $this->db->query($sql, [
            $poID,
            $type, // PurchaseOrderLogType
            json_encode($prm), // PurchaseOrderLogPurchaseOrderID
            json_encode($dataBefore), // PurchaseOrderLogJSONBefore
            json_encode($dataAfter), // PurchaseOrderLogJSONAfter
            $userID, // PurchaseOrderLogUserID
            $desc
        ]);

        // Jika query gagal, lempar error
        if (!$exec) {
            $this->sys_error_db("Error inserting log into purchase_order_log", $this->db);
            $this->db->trans_rollback();
            exit;
        }
    }

    function getApproveLevel()
    {
        if (!$this->isLogin) {
            $this->sys_error("Invalid Token");
            exit;
        }
        $userId = $this->sys_user["M_UserID"];

        $sqlevel = "SELECT M_UserM_ApproveLevelID FROM m_user WHERE M_UserIsActive = 'Y' AND M_UserID = ? ";
        $qulevel = $this->db->query($sqlevel, [$userId]);
        if (!$qulevel) {
            $this->sys_error_db("[Error] get approval level user");
            exit;
        }
        $data = $qulevel->row_array();

        $this->sys_ok($data);
    }

    // notifications
    function saveNotification($userId, $dateRequest, $number, $refID, $branchId, $regionalId)
    {
        try {
            $this->db->trans_begin();

            $xdate = date('d-m-Y');

            $sql_user = "SELECT M_UserID, M_UserUsername
                FROM m_user
                WHERE M_UserIsActive = 'Y'
                AND M_UserID = ?";
            $qry_user = $this->db->query($sql_user, [$userId]);
            if ($qry_user) {
                $username = $qry_user->row_array();
            } else {
                $this->sys_error_db("select user error", $this->db);
                exit;
            }

            $description = "Pembuatan <strong>PURCHASE ORDER</strong> pada tanggal <strong>" . $xdate . "</strong> oleh <strong>" . $username['M_UserUsername'] . "</strong> dengan nomor <strong>" . $number . "</strong>";

            $sql_menu = "SELECT S_MenuID,
                S_MenuName,
                S_MenuUrl,
                S_MenuLevel
                FROM s_menu
                WHERE S_MenuID = 82";
            $qry_menu = $this->db->query($sql_menu, []);
            if ($qry_menu) {
                $rowurl = $qry_menu->row_array();
            } else {
                $this->sys_error_db("select menu error", $this->db);
                exit;
            }

            $url = $rowurl['S_MenuUrl'] . "?flag=N&status=Pending&startdate=" . $dateRequest . "&search=" . $number;

            // cari user penerima notifikasi
            if ($branchId != 0) {
                // user cabang
                $sql_receive_user = "SELECT * FROM m_user
                JOIN m_branch ON  M_UserM_BranchID = M_BranchID
                AND M_BranchIsActive = 'Y'
                AND M_BranchID = ?
                WHERE M_UserIsActive = 'Y'
                AND M_UserM_ApproveLevelID IN (1,2)";
                $qry_receive_user = $this->db->query($sql_receive_user, [$branchId]);
                if ($qry_receive_user) {
                    $rowsuser = $qry_receive_user->result_array();
                } else {
                    $this->sys_error_db("select receive user error", $this->db);
                    exit;
                }
            } else if ($branchId == 0) {
                // user regional
                $sql_receive_user = "SELECT * FROM m_user
                JOIN s_regional ON M_UserS_RegionalID = S_RegionalID
                AND S_RegionalIsActive = 'Y'
                AND S_RegionalID = ?
                WHERE M_UserIsActive = 'Y'
                AND M_UserM_BranchID = 0
                AND M_UserM_ApproveLevelID IN (1,2)";
                $qry_receive_user = $this->db->query($sql_receive_user, [$regionalId]);
                if ($qry_receive_user) {
                    $rowsuser = $qry_receive_user->result_array();
                } else {
                    $this->sys_error_db("select receive user error", $this->db);
                    exit;
                }
            }

            $sql = "INSERT INTO notification(
                NotificationRefID,
                NotificationType,
                NotificationDescription,
                NotificationUrl,
                NotificationUserID,
                NotificationCreated) VALUES(?,?,?,?,?,NOW())";
            $qry = $this->db->query($sql, [
                $refID,
                'Purchase Order',
                $description,
                $url,
                $userId
            ]);
            if (!$qry) {
                $this->db->trans_rollback();
                $this->sys_error_db("insert notification error", $this->db);
                exit;
            }

            $lastid = $this->db->insert_id();

            // insert ke detail notification
            foreach ($rowsuser as $row) {
                $sql_detail = "INSERT INTO notification_detail(
                    NotificationDetailNotificationID,
                    NotificationDetailM_UserID,
                    NotificationDetailM_ApproveLevelID,
                    NotificationDetailStatus,
                    NotificationDetailCreated,
                    NotificationDetailUserID) VALUES(?,?,?,?,NOW(),?)";
                $qry_detail = $this->db->query($sql_detail, [
                    $lastid,
                    $row['M_UserID'], // user penerima notifikasi
                    $row['M_UserM_ApproveLevelID'],
                    'unread',
                    $userId
                ]);
                if (!$qry_detail) {
                    $this->db->trans_rollback();
                    $this->sys_error_db("insert notification detail error", $this->db);
                    exit;
                }
            }

            $this->db->trans_commit();
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }
}
