<?php
class Itemoutv3 extends MY_Controller
{
    var $db;
    public function index()
    {
        echo "Item Out/Requester API";
    }

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

    // jika jumlah item out sebagian maka status request item out menjadi partial
    // jika jumlah item out komplit maka status request item out menjadi completed
    public function saveRequest()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }
            $this->db->trans_begin();
            $prm = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];

            $date = isset($prm["date"]) ? $prm["date"] : "";
            if ($date == "" || $date == null) {
                $this->sys_error("Invalid Date Use");
                exit;
            }
            $warehouseID = isset($prm["warehouseID"]) ? $prm["warehouseID"] : "";
            if ($warehouseID == "" || $warehouseID == null) {
                $this->sys_error("Warehouse masih kosong");
                exit;
            }
            $note = "";
            if (isset($prm["note"])) {
                $note = trim($prm["note"]);
            }
            $divisionID = isset($prm["divisionID"]) ? $prm["divisionID"] : "";
            if ($divisionID == "" || $divisionID == null) {
                $this->sys_error("Division masih kosong");
                exit;
            }
            $items = isset($prm["items"]) ? $prm["items"] : [];
            if (count($items) == 0) {
                $this->sys_error("Items cannot be empty");
                exit;
            }


            $sqlnum = "SELECT `fn_numbering`('IO') as IOnumber";
            $qrynum = $this->db->query($sqlnum, []);
            $IOnumber = $qrynum->row()->IOnumber;

            $sqlIO = "INSERT INTO t_item_out (
                        T_ItemOutDate,
                        T_ItemOutNumber,
                        T_ItemOutWarehouseID,
                        T_ItemOutNote,
                        T_ItemOutDivisionID,
                        T_ItemOutStatus,
                        T_ItemOutIsActive,
                        T_ItemOutUserID,
                        T_ItemOutCreated,
                        T_ItemOutLastUpdated) VALUES(?,?,?,?,?,'Draft','Y',?,NOW(),NOW())";
            $qryIO = $this->db->query($sqlIO, [
                $date,
                $IOnumber,
                $warehouseID,
                $note,
                $divisionID,
                $userId
            ]);
            if (!$qryIO) {
                $this->db->trans_rollback();
                $this->sys_error_db("Failed to insert data table item out", $this->db);
            }

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

            // Kelompokkan item berdasarkan rioID
            $grouped = [];
            foreach ($items as $item) {
                $grouped[$item['rioID']][] = $item;
            }

            foreach ($grouped as $rioID => $itemGroup) {
                $statusHeader = 'Completed';

                foreach ($itemGroup as $item) {
                    $receiveQty = intval($item['rioDReceiveQty']);

                    // encode json list batch number
                    $jsonBatchNo = "[]";
                    if (isset($item['ItemRequest']) && is_array($item['ItemRequest'])) {
                        $batches = $item['ItemRequest'];
                        if (sizeof($batches) > 0) {
                            $jsonResult = json_encode($batches);
                            if ($jsonResult === false) {
                                throw new Exception("[Error] Failed to encode json batch number");
                            } else {
                                $jsonBatchNo = $jsonResult;
                            }
                        }
                    }

                    // transaksi insert item out detail
                    $sql = "INSERT INTO t_item_out_detail(
                            T_ItemOutDetailT_ItemOutID,
                            T_ItemOutDetailRequestItemOutID,
                            T_ItemOutDetailRequestItemOutDetailID,
                            T_ItemOutDetailM_ItemID,
                            T_ItemOutDetailItemUnitID,
                            T_ItemOutDetailItemBatchNo,
                            T_ItemOutDetailQty,
                            T_ItemOutDetailCreated,
                            T_ItemOutDetailUserID) VALUES(?, ?, ?, ?, ?, ?, ?, NOW(), ?)";
                    $qry = $this->db->query($sql, [
                        $ioId,
                        $item["rioID"],
                        $item["rioDID"],
                        $item["itemID"],
                        $item["unitID"],
                        $jsonBatchNo,
                        $receiveQty,
                        $userId
                    ]);
                    if (!$qry) {
                        $this->db->trans_rollback();
                        $this->sys_error_db("failed to insert data table item out detail", $this->db);
                        exit;
                    }

                    $isPartial = intval($receiveQty) < intval($item['rioDQty']);
                    $detailStatus = $isPartial ? 'Partial' : 'Completed';

                    if ($isPartial) {
                        $statusHeader = 'Partial'; // Jika ada satu saja partial, status header ikut partial
                    }

                    // Update request item out detail
                    $sqlDetail = "UPDATE request_item_out_detail SET
                                    RequestItemOutDetailStatus = ?,
                                    RequestItemOutDetailLastUpdated = NOW(),
                                    RequestItemOutDetailUserID = ?
                                  WHERE RequestItemOutDetailID = ?";
                    $queryDetail = $this->db->query($sqlDetail, [
                        $detailStatus,
                        $userId,
                        $item['rioDID']
                    ]);
                    if (!$queryDetail) {
                        $this->db->trans_rollback();
                        $this->sys_error_db("ERROR, update detail RIO", $this->db);
                        exit;
                    }
                }

                $sqlHeader = "UPDATE request_item_out SET
                                RequestItemOutStatus = ?,
                                RequestItemOutUserID = ?,
                                RequestItemOutLastUpdated = NOW()
                              WHERE RequestItemOutID = ?";
                $queryHeader = $this->db->query($sqlHeader, [
                    $statusHeader,
                    $userId,
                    $rioID
                ]);

                if (!$queryHeader) {
                    $this->db->trans_rollback();
                    $this->sys_error_db("ERROR, update header RIO", $this->db);
                    exit;
                }


                $userdesc = "Transaksi item out dengan kode " . $IOnumber . " telah di buat";
                $this->insertUserActivityIo($ioId, $userId, "DRAFT", $userdesc);
                // Insert user activity (log)
                $this->insertUserActivityRio($rioID, $userId, $statusHeader);
            }


            // transaksi pengurangan stockqty
            foreach ($items as $key => $item) {
                // array stock request per batch
                foreach ($item["ItemRequest"] as $k => $v) {
                    // update stock
                    $stockupd = "UPDATE stock 
                        SET StockQty = StockQty - ?
                        WHERE StockID = ? 
                        AND StockWarehouseID = ?";
                    $stockupd = $this->db->query($stockupd, [
                        intval($v["QtyReq"]),
                        $v["StockID"],
                        $v["WarehouseID"]
                    ]);
                    if (!$stockupd) {
                        $this->db->trans_rollback();
                        $this->sys_error_db("ERROR, update stock qty item out", $this->db);
                        exit;
                    }

                    $receiveQty = intval($v['QtyReq']);
                    $currentQty = intval($v['StockQty']);
                    $remainingQty = max(0, $currentQty - $receiveQty);

                    // insert stockcard
                    $sqlcard = "INSERT INTO stockcard (
                            StockCardWarehouseID,
                            StockCardDatetime,
                            StockCardItemID,
                            StockCardItemUnitID,
                            StockCardBatchNo,
                            StockCardED,
                            StockCardReffID,
                            StockCardStatus,
                            StockCardBefore,
                            StockCardIn,
                            StockCardOut,
                            StockCardAfter,
                            StockCardUserID
                        ) VALUES (?, NOW(), ?, ?, ?, ?, ?, 'IO', ?, 0, ?, ?, ?)";
                    $qrycard = $this->db->query($sqlcard, array(
                        $v["WarehouseID"],
                        $v["StockItemID"],
                        $v["StockItemUnitID"],
                        $v["StockBatchNo"],
                        $v["StockED"],
                        $v["StockID"],
                        $currentQty,
                        $receiveQty,
                        $remainingQty,
                        $userId
                    ));
                    if (!$qrycard) {
                        $this->db->trans_rollback();
                        $this->sys_error_db("Error insert stock card", $this->db);
                        exit;
                    }

                    // insert into stocklog
                    $sqllog = "INSERT INTO stocklog (
                            StockLogWarehouseID,
                            StockLogDateTime,
                            StockLogItemID,
                            StockLogItemUnitID,
                            StockLogStockNumber,
                            StockLogBatchNo,
                            StockLogED,
                            StockLogReffID,
                            StockLogStatus,
                            StockLogQty,
                            StockLogUserID
                        ) VALUES (?,NOW(),?,?,?,?,?,?,?,?,?)";
                    $qrylog = $this->db->query($sqllog, [
                        $v["WarehouseID"],
                        $v["StockItemID"],
                        $v["StockItemUnitID"],
                        $v["StockStockNumber"],
                        $v["StockBatchNo"],
                        $v["StockED"],
                        $v["StockID"],
                        'IO',
                        $receiveQty,
                        $userId,
                    ]);
                    if (!$qrylog) {
                        $this->db->trans_rollback();
                        $this->sys_error_db("Error insert stocklog", $this->db);
                        exit;
                    }
                }
            }

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

    public function getItemOuts()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
            }
            $this->db->trans_begin();

            $prm = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];
            $ioID = isset($prm["ioID"]) ? $prm["ioID"] : "";
            if ($ioID == "" || $ioID == null) {
                $this->sys_error("Invalid item out ID");
                exit;
            }
            $sql = "SELECT 
                T_ItemOutDetailID,
                T_ItemOutDetailT_ItemOutID,
                T_ItemOutDetailRequestItemOutID,
                T_ItemOutDetailRequestItemOutDetailID,
                T_ItemOutDetailM_ItemID,
                T_ItemOutDetailItemUnitID,
                T_ItemOutDetailItemBatchNo,
                T_ItemOutDetailQty,
                T_ItemOutID,
                T_ItemOutDate,
                T_ItemOutNumber,
                T_ItemOutNote,
                RequestItemOutDetailID,
                RequestItemOutDetailReceiveQty,
                RequestItemOutDetailQty,
                IFNULL(RequestItemOutDetailQty, 0) - IFNULL(T_ItemOutDetailQty, 0) as remainingRequestQty,
                M_ItemID,
                M_ItemDesc,
                ItemUnitID,
                ItemUnitCode,
                ItemUnitName,
                CASE
                    WHEN WarehouseType = 'B' THEN CONCAT(WarehouseCode,' ', WarehouseName, ' - ', M_BranchName) 
                    WHEN WarehouseType = 'R' THEN CONCAT(WarehouseCode,' ', WarehouseName, ' - ', S_RegionalName) 
                ELSE ''
                END WarehouseName,
                WarehouseID,
                StockID,
                StockWarehouseID,
                StockWarehouseAlmariID,
                StockWarehouseRackID,
                StockStockNumber,
                StockItemID,
                StockItemUnitID,
                StockItemPrice,
                StockBatchNo,
                StockED,
                StockLastUpdated,
                StockUserID,
                SUM(stock.StockQty) AS StockQty
            FROM t_item_out_detail
            JOIN t_item_out ON T_ItemOutDetailT_ItemOutID = T_ItemOutID
                AND T_ItemOutIsActive = 'Y'
            JOIN warehouse ON T_ItemOutWarehouseID = WarehouseID
            JOIN request_item_out_detail ON T_ItemOutDetailRequestItemOutDetailID = RequestItemOutDetailID
                AND RequestItemOutDetailIsActive = 'Y'
            JOIN m_item ON T_ItemOutDetailM_ItemID = M_ItemID
                AND M_ItemIsActive = 'Y'
            JOIN itemunit ON T_ItemOutDetailItemUnitID = ItemUnitID
                AND ItemUnitIsActive = 'Y'
            JOIN stock ON StockItemID = T_ItemOutDetailM_ItemID
                AND StockItemUnitID = T_ItemOutDetailItemUnitID
                AND StockWarehouseID = T_ItemOutWarehouseID
            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 T_ItemOutDetailIsActive = 'Y'
                AND T_ItemOutDetailT_ItemOutID = ?
            GROUP BY T_ItemOutDetailID
            ORDER BY T_ItemOutDetailID DESC";
            $qry = $this->db->query($sql, [$ioID]);
            if (!$qry) {
                $this->sys_error_db("ERROR, get detail item out data", $this->db);
                exit;
            }
            $rows = $qry->result_array();

            foreach ($rows as $key => $value) {
                $jsonStr = $value['T_ItemOutDetailItemBatchNo'];
                $batches = [];

                if (!empty($jsonStr)) {
                    $decode = json_decode($jsonStr);
                    if ($decode !== null && json_last_error() === JSON_ERROR_NONE) {
                        $batches = $decode;
                    } else {
                        $this->sys_error_db("[Error] decode json for batches number");
                        exit;
                    }
                }
                $rows[$key]['ItemRequest'] = $batches;
                unset($rows[$key]['T_ItemOutDetailItemBatchNo']);
            }

            $result = array(
                "records" => $rows
            );
            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }
    public function confirmIO()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }
            $this->db->trans_begin();
            $prm = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];

            $ioID = isset($prm["ioID"]) ? $prm["ioID"] : "";
            if ($ioID == "" || $ioID == null) {
                $this->sys_error("Item out ID not found");
                exit;
            }

            $sql_update = "UPDATE t_item_out SET
                T_ItemOutIsConfirmDate = NOW(),
                T_ItemOutIsConfirm = 'Y',
                T_ItemOutUserID = ?,
                T_ItemOutLastUpdated = NOW()
                WHERE T_ItemOutID = ?";
            $qry_update = $this->db->query($sql_update, [$userId, $ioID]);
            if (!$qry_update) {
                $this->db->trans_rollback();
                $this->sys_error_db("Gagal konfirmasi", $this->db);
                exit;
            }

            $sql = "SELECT t_item_out.* 
                    FROM t_item_out
                    WHERE T_ItemOutIsActive = 'Y'
                    AND T_ItemOutID = ?";
            $qry = $this->db->query($sql, [$ioID]);
            if (!$qry) {
                $this->sys_error_db("select item out error", $this->db);
                exit;
            }
            $row = $qry->row();

            $userdesc = "Transaksi item out dengan kode " . $row->T_ItemOutNumber . " telah di konfirmasi";
            $this->insertUserActivityIo($ioID, $userId, "CONFIRM", $userdesc);
            $this->db->trans_commit();
            $result = array(
                "total" => 1,
                "affected_rows" => $this->db->affected_rows()
            );
            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }
    public function approveIO()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }
            $this->db->trans_begin();
            $prm = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];

            $ioID = isset($prm["ioID"]) ? $prm["ioID"] : "";
            if ($ioID == "" || $ioID == null) {
                $this->sys_error("Item out ID not found");
                exit;
            }

            $sqlApp = "UPDATE t_item_out SET
                        T_ItemOutApproveDate = NOW(),
                        T_ItemOutApproveID = ?
                    WHERE T_ItemOutID = ?";
            $qryApp = $this->db->query($sqlApp, [
                $userId,
                $ioID
            ]);
            if (!$qryApp) {
                $this->db->trans_rollback();
                $this->sys_error_db("ERROR, update approve failed", $this->db);
                exit;
            }

            $sql = "SELECT t_item_out.* 
                    FROM t_item_out
                    WHERE T_ItemOutIsActive = 'Y'
                    AND T_ItemOutID = ?";
            $qry = $this->db->query($sql, [$ioID]);
            if (!$qry) {
                $this->sys_error_db("select item out error", $this->db);
                exit;
            }
            $row = $qry->row();

            $userdesc = "Transaksi item out dengan kode " . $row->T_ItemOutNumber . " telah di approve";
            $this->insertUserActivityIo($ioID, $userId, "Approve", $userdesc);

            $this->db->trans_commit();
            $result = array(
                "total" => 1,
                "affected_rows" => $this->db->affected_rows()
            );
            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }
    public function processIO()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }
            $this->db->trans_begin();
            $prm = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];

            $ioID = isset($prm["ioID"]) ? $prm["ioID"] : "";
            if ($ioID == "" || $ioID == null) {
                $this->sys_error("Item out ID not found");
                exit;
            }
            $items = isset($prm["items"]) ? $prm["items"] : [];
            if (count($items) == 0) {
                $this->sys_error("Items cannot be empty");
                exit;
            }

            $sqlApp = "UPDATE t_item_out SET
                        T_ItemOutStatus = 'Process',
                        T_ItemOutReceiveUserID = ?,
                        T_ItemOutLastUpdated = NOW()
                        WHERE T_ItemOutID = ?";
            $qryApp = $this->db->query($sqlApp, [
                $userId,
                $ioID
            ]);
            if (!$qryApp) {
                $this->db->trans_rollback();
                $this->sys_error_db("ERROR, update Process failed", $this->db);
                exit;
            }

            foreach ($items as $key => $item) {

                $sqlQty = "UPDATE request_item_out_detail SET 
                            RequestItemOutDetailQty = RequestItemOutDetailQty - ?,
                            RequestItemOutDetailLastUpdated = NOW(),
                            RequestItemOutDetailUserID = ?
                            WHERE RequestItemOutDetailID = ?";
                $qryQty = $this->db->query($sqlQty, [
                    intval($item["T_ItemOutDetailQty"]),
                    $userId,
                    $item["T_ItemOutDetailRequestItemOutDetailID"]
                ]);
                if (!$qryQty) {
                    $this->db->trans_rollback();
                    $this->sys_error_db("ERROR, update qty request failed", $this->db);
                    exit;
                }
            }
            $sql = "SELECT t_item_out.* 
                    FROM t_item_out
                    WHERE T_ItemOutIsActive = 'Y'
                    AND T_ItemOutID = ?";
            $qry = $this->db->query($sql, [$ioID]);
            if (!$qry) {
                $this->sys_error_db("select item out error", $this->db);
                exit;
            }
            $row = $qry->row();

            $userdesc = "Transaksi item out dengan kode " . $row->T_ItemOutNumber . " telah di approve";
            $this->insertUserActivityIo($ioID, $userId, "Process", $userdesc);

            // generate jurnal sudah tidak dipakai 22-08-2025
            // $this->generateJurnal($ioID);

            // Insert item usage
            $this->insertUsage($ioID, $userId);

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

    function insertUserActivityIo($ioID, $userId, $status, $userdesc)
    {
        try {
            // insert log
            $sql_json = "SELECT t_item_out.*, '' as detail
                        FROM t_item_out
                        WHERE T_ItemOutIsActive = 'Y'
                        AND T_ItemOutID = ?";
            $qry_json = $this->db->query($sql_json, [$ioID]);
            if (!$qry_json) {
                $this->db->trans_rollback();
                $this->sys_error_db("select json io error");
                exit;
            }
            $row_json = $qry_json->row_array();

            $sql_json_detail = "SELECT t_item_out_detail.* 
                            FROM t_item_out_detail
                            WHERE T_ItemOutDetailIsActive = 'Y'
                            AND T_ItemOutDetailT_ItemOutID = ?";
            $qry_json_detail = $this->db->query($sql_json_detail, [$ioID]);
            if ($qry_json_detail) {
                $row_json["detail"] = $qry_json_detail->result_array();
            } else {
                $this->sys_error_db("select detail io error", $this->db);
                exit;
            }

            $data_json = $row_json;

            $sql_log = "INSERT INTO user_activity(
                            UserActivityCode,
                            UserActivityStatus,
                            UserActivityDescription,
                            UserActivityRefID,
                            UserActivityData,
                            UserActivityUserID,
                            UserActivityCreated
                        ) VALUES('IO',?,?,?,?,?,NOW())";
            $qry_log = $this->db->query($sql_log, [
                $status,
                $userdesc,
                $ioID,
                json_encode($data_json),
                $userId
            ]);
            if (!$qry_log) {
                $this->db->trans_rollback();
                $this->sys_error_db("insert user activity error", $this->db);
                exit;
            }
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    function insertUserActivityRio($rioID, $userId, $status)
    {
        try {
            // insert log
            $sql_json = "SELECT request_item_out.*, '' as detail
                        FROM request_item_out
                        WHERE RequestItemOutIsActive = 'Y'
                        AND RequestItemOutID = ?";
            $qry_json = $this->db->query($sql_json, [$rioID]);
            if (!$qry_json) {
                $this->db->trans_rollback();
                $this->sys_error_db("select json rio error");
                exit;
            }
            $row_json = $qry_json->row_array();

            if ($status == "Partial") {
                $userdesc = "Request Item out dengan kode " . $row_json['RequestItemOutNumber'] . " telah di kirim sebagian";
            } else {
                $userdesc = "Request Item out dengan kode " . $row_json['RequestItemOutNumber'] . " telah komplit";
            }

            $sql_json_detail = "SELECT request_item_out_detail.* 
                            FROM request_item_out_detail
                            WHERE RequestItemOutDetailIsActive = 'Y'
                            AND RequestItemOutDetailRequestItemOutID = ?";
            $qry_json_detail = $this->db->query($sql_json_detail, [$rioID]);
            if ($qry_json_detail) {
                $row_json["detail"] = $qry_json_detail->result_array();
            } else {
                $this->sys_error_db("select detail rio error", $this->db);
                exit;
            }

            $data_json = $row_json;

            $sql_log = "INSERT INTO user_activity(
                            UserActivityCode,
                            UserActivityStatus,
                            UserActivityDescription,
                            UserActivityRefID,
                            UserActivityData,
                            UserActivityUserID,
                            UserActivityCreated
                        ) VALUES('RIO',?,?,?,?,?,NOW())";
            $qry_log = $this->db->query($sql_log, [
                $status,
                $userdesc,
                $rioID,
                json_encode($data_json),
                $userId
            ]);
            if (!$qry_log) {
                $this->db->trans_rollback();
                $this->sys_error_db("insert user activity error", $this->db);
                exit;
            }
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    function formatRupiah($angka)
    {
        // Ganti koma ke titik agar jadi desimal yang valid
        $angka = str_replace(',', '.', $angka);

        // Validasi input
        if (!is_numeric($angka)) {
            return 'Input tidak valid';
        }

        // Konversi ke float
        $angka = (float)$angka;

        // Bulatkan ke 3 angka desimal
        $angka = round($angka, 3);

        // Cek apakah angka desimalnya nol
        if (fmod($angka, 1) == 0.0) {
            // Tanpa desimal
            $formatted = number_format($angka, 0, ',', '.');
        } else {
            // Dengan 3 angka desimal
            $formatted = number_format($angka, 3, ',', '.');
        }

        return 'Rp ' . $formatted;
    }

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

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

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

            $status = $prm["status"];
            $filter = "";
            if ($status != 'All') {
                $filter .= " AND T_ItemOutStatus = '{$status}'";
            }

            $number_offset = 0;
            $number_limit = 10;
            if ($prm["current_page"] > 0) {
                $number_offset = ($prm["current_page"] - 1) * $number_limit;
            }

            $sqlCount = "SELECT count(*) as total
                    FROM t_item_out
                    JOIN warehouse ON T_ItemOutWarehouseID = WarehouseID
                        AND WarehouseIsActive = 'Y'
                    JOIN division ON T_ItemOutDivisionID = DivisionID
                        AND DivisionIsActive = 'Y'
                    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 T_ItemOutIsActive = 'Y'
                    AND (T_ItemOutDate BETWEEN ? AND ?)
                    AND (T_ItemOutNumber LIKE ?)
                    $filter
                    ORDER BY T_ItemOutNumber DESC";
            $qryCount = $this->db->query($sqlCount, [
                $startDate,
                $endDate,
                $search
            ]);

            $tot_count = 0;
            $tot_page = 0;
            if ($qryCount) {
                $tot_count = $qryCount->result_array()[0]["total"];
                $tot_page = ceil($tot_count / $number_limit);
            } else {
                $this->sys_error_db("item out count error", $this->db);
                exit;
            }

            $sql = "SELECT T_ItemOutID,
                    T_ItemOutDate,
                    T_ItemOutNumber,
                    T_ItemOutNote,
                    T_ItemOutReceiveUserID,
                    T_ItemOutStatus,
                    T_ItemOutApproveID,
                    T_ItemOutIsConfirm,
                    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,
                    DivisionID,
                    DivisionCode,
                    DivisionName
                    FROM t_item_out
                    JOIN warehouse ON T_ItemOutWarehouseID = WarehouseID
                        AND WarehouseIsActive = 'Y'
                    JOIN division ON T_ItemOutDivisionID = DivisionID
                        AND DivisionIsActive = 'Y'
                    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 T_ItemOutIsActive = 'Y'
                    AND (T_ItemOutDate BETWEEN ? AND ?)
                    AND (T_ItemOutNumber LIKE ?)
                    $filter
                    ORDER BY T_ItemOutNumber DESC
                    LIMIT ? OFFSET ?";
            $qry = $this->db->query($sql, [
                $startDate,
                $endDate,
                $search,
                $number_limit,
                $number_offset
            ]);
            // echo $this->db->last_query();
            // exit;
            if ($qry) {
                $rows = $qry->result_array();
            } else {
                $this->sys_error_db("get item out error", $this->db);
                exit;
            }

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

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

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

            $regionalID = $prm["regionalID"];
            $branchCode = $prm["branchCode"];
            $filterBranch = "";
            if (!$branchCode == "") {
                $filterBranch .= " AND M_BranchCode = '{$branchCode}'";
            }

            $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,
                    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 WarehouseIsActive = 'Y'
                    AND WarehouseIsTransit = 'N'
                    AND WarehouseS_RegionalID = ?
                    $filterBranch
                    ORDER BY WarehouseID ASC
                    ";
            $qry = $this->db->query($sql, [$regionalID]);
            if (!$qry) {
                $this->db->trans_rollback();
                $this->sys_error_db("get 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);
        }
    }

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

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

            $sql = "SELECT M_DepartmentID,
                    M_DepartmentCode,
                    M_DepartmentName
                    FROM m_department
                    WHERE M_DepartmentIsActive = 'Y'
                    ORDER BY M_DepartmentName ASC";
            $qry = $this->db->query($sql, []);
            if (!$qry) {
                $this->db->trans_rollback();
                $this->sys_error_db("get Department", $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);
        }
    }

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

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

            $rows = [];

            $query = "SELECT DISTINCT
                      DivisionID,
                      DivisionCode,
                      DivisionName
                      FROM division
                      WHERE DivisionIsActive = 'Y'
                      ORDER BY DivisionName ASC";
            $exec = $this->db->query($query);
            if ($exec) {
                $rows = $exec->result_array();
            } else {
                $this->db->trans_rollback();
                $this->sys_error_db("select division", $this->db);
                exit;
            }

            if ($prm["act"] == "edit") {
                $sql = "SELECT DISTINCT
                      DivisionID,
                      DivisionCode,
                      DivisionName
                    FROM division 
                    JOIN m_userdivision ON M_UserDivisionDivisionID = DivisionID
                    WHERE DivisionIsActive = 'Y'
                    AND DivisionID = ?
                    ORDER BY M_UserDivisionID DESC
                    LIMIT 1";
                $exec = $this->db->query($sql, [$prm["DivisionID"]]);
                if ($exec) {
                    $row = $exec->result_array();
                } else {
                    $this->sys_error_db("select division", $this->db);
                    exit;
                }
            } else {
                $sql = "SELECT DISTINCT
                      DivisionID,
                      DivisionCode,
                      DivisionName
                    FROM division 
                    JOIN m_userdivision ON M_UserDivisionDivisionID = DivisionID AND M_UserDivisionM_UserID = ?
                    WHERE DivisionIsActive = 'Y'
                    ORDER BY M_UserDivisionID DESC
                    LIMIT 1";
                $exec = $this->db->query($sql, [$userId]);
                if ($exec) {
                    $row = $exec->result_array();
                } else {
                    $this->sys_error_db("select division by user", $this->db);
                    exit;
                }
            }

            $result = array(
                "records" => $rows,
                "selected" => $row
            );

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

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

            $this->db->trans_begin();

            $prm = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];
            $itemoutID = isset($prm["itemoutID"]) ? $prm["itemoutID"] : "";
            if ($itemoutID == "" || $itemoutID == null) {
                $this->sys_error("Invalid item out ID");
                exit;
            }

            $sql = "SELECT 
                T_ItemOutDetailID as ioDetailID,
                T_ItemOutDetailT_ItemOutID as ioDetailioID,
                T_ItemOutDetailRequestItemOutID as ioDetailRequestioID,
                T_ItemOutDetailM_ItemID as ioDetailItemID,
                T_ItemOutDetailItemUnitID as ioDetailUnitID,
                T_ItemOutDetailItemBatchNo,
                IFNULL(T_ItemOutDetailQty, 0) as rioDReceiveQty,
                T_ItemOutID as ioID,
                T_ItemOutDate as ioDate,
                T_ItemOutNumber as ioNumber,
                T_ItemOutWarehouseID as ioWarehouseID,
                T_ItemOutNote as ioNote,
                T_ItemOutDivisionID as ioDivisionID,
                RequestItemOutID as rioID,
                RequestItemOutNumber as rioNumber,
                RequestItemOutDetailID as rioDID,
                RequestItemOutDetailM_ItemID as rioDItemID,
                RequestItemOutDetailItemUnitID as rioDItemUnitID,
                RequestItemOutDetailQty as rioDQty,
                M_ItemID as itemID,
                M_ItemCode as itemCode,
                M_ItemDesc as itemDesc,
                ItemUnitID as unitID,
                ItemUnitCode as unitCode,
                ItemUnitName as unitName,
                StockID,
                StockWarehouseID,
                StockWarehouseAlmariID,
                StockWarehouseRackID,
                StockStockNumber,
                StockItemID,
                StockItemUnitID,
                StockItemPrice,
                StockBatchNo,
                StockED,
                StockLastUpdated,
                StockUserID,
                SUM(stock.StockQty) as StockQty
            FROM t_item_out_detail
            JOIN t_item_out ON T_ItemOutDetailT_ItemOutID = T_ItemOutID
                AND T_ItemOutIsActive = 'Y'
            JOIN request_item_out ON T_ItemOutDetailRequestItemOutID = RequestItemOutID
                AND RequestItemOutIsActive = 'Y'
            JOIN request_item_out_detail ON RequestItemOutDetailRequestItemOutID = RequestItemOutID
                AND RequestItemOutDetailM_ItemID = T_ItemOutDetailM_ItemID
                AND RequestItemOutDetailItemUnitID = T_ItemOutDetailItemUnitID
                AND RequestItemOutDetailIsActive = 'Y'
            JOIN m_item ON T_ItemOutDetailM_ItemID = M_ItemID
                AND M_ItemIsActive = 'Y'
            JOIN itemunit ON T_ItemOutDetailItemUnitID = ItemUnitID
                AND ItemUnitIsActive = 'Y'
            JOIN stock ON StockItemID = T_ItemOutDetailM_ItemID
                AND StockItemUnitID = T_ItemOutDetailItemUnitID
                AND StockWarehouseID = T_ItemOutWarehouseID
            WHERE T_ItemOutDetailIsActive = 'Y'
                AND T_ItemOutDetailT_ItemOutID = ?
            GROUP BY T_ItemOutDetailID
            ORDER BY T_ItemOutDetailID DESC";
            $qry = $this->db->query($sql, [$itemoutID]);
            if (!$qry) {
                $this->sys_error_db('ERROR, get detail item out', $this->db);
                exit;
            }
            $rows = $qry->result_array();

            foreach ($rows as $key => $value) {
                $jsonStr = $value['T_ItemOutDetailItemBatchNo'];
                $batches = [];

                if (!empty($jsonStr)) {
                    $decode = json_decode($jsonStr);
                    if ($decode !== null && json_last_error() === JSON_ERROR_NONE) {
                        $batches = $decode;
                    } else {
                        $this->sys_error_db("[Error] decode json for batches number");
                        exit;
                    }
                }
                $rows[$key]['ItemRequest'] = $batches;
                unset($rows[$key]['T_ItemOutDetailItemBatchNo']);
            }

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

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

            $this->db->trans_begin();

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

            $date = isset($prm["date"]) ? $prm["date"] : "";
            if ($date == "" || $date == null) {
                $this->sys_error("Invalid Date Use");
                exit;
            }
            $warehouseID = isset($prm["warehouseID"]) ? $prm["warehouseID"] : "";
            if ($warehouseID == "" || $warehouseID == null) {
                $this->sys_error("Warehouse masih kosong");
                exit;
            }
            $note = "";
            if (isset($prm["note"])) {
                $note = trim($prm["note"]);
            }
            $divisionID = isset($prm["divisionID"]) ? $prm["divisionID"] : "";
            if ($divisionID == "" || $divisionID == null) {
                $this->sys_error("Division masih kosong");
                exit;
            }
            $IOID = isset($prm["IOID"]) ? $prm["IOID"] : "";
            if ($IOID == "" || $IOID == null) {
                $this->sys_error("item out ID masih kosong");
                exit;
            }

            $items = isset($prm["items"]) ? $prm["items"] : [];
            if (count($items) == 0) {
                $this->sys_error("Items cannot be empty");
                exit;
            }

            $sql = "UPDATE t_item_out SET 
                    T_ItemOutDate = ?,
                    T_ItemOutWarehouseID = ?,
                    T_ItemOutNote = ?,
                    T_ItemOutDivisionID = ?,
                    T_ItemOutUserID = ?,
                    T_ItemOutLastUpdated = NOW()
                    WHERE T_ItemOutID = ?";
            $qry = $this->db->query($sql, [
                $date,
                $warehouseID,
                $note,
                $divisionID,
                $userId,
                $IOID
            ]);
            if (!$qry) {
                $this->db->trans_rollback();
                $this->sys_error_db("Failed update item out", $this->db);
                exit;
            }

            $sql = "SELECT T_ItemOutDetailID
                FROM t_item_out_detail
                WHERE T_ItemOutDetailIsActive = 'Y'
                AND T_ItemOutDetailT_ItemOutID = ?";
            $qry = $this->db->query($sql, [$IOID]);
            if (!$qry) {
                $this->sys_error_db("select item out detail error", $this->db);
                exit;
            }
            $dbIoDetailIDs = array_column($qry->result_array(), 'T_ItemOutDetailID');

            // Buat array ioDetailID dari frontend
            $activeIoDetailIDs = [];
            foreach ($items as $item) {
                if (!empty($item["ioDetailID"])) {
                    $activeIoDetailIDs[] = $item["ioDetailID"];
                }
            }

            // Cari ID yang harus di-nonaktifkan (yang ada di database tapi tidak ada di frontend)
            $toDeactivateIDs = array_diff($dbIoDetailIDs, $activeIoDetailIDs);

            // Jika ada yang perlu di-deactivate
            if (!empty($toDeactivateIDs)) {
                $placeholders = implode(',', array_fill(0, count($toDeactivateIDs), '?'));
                $sql = "UPDATE t_item_out_detail SET
                T_ItemOutDetailIsActive = 'N',
                T_ItemOutDetailLastUpdated = NOW(),
                T_ItemOutDetailUserID = ?
                WHERE T_ItemOutDetailID IN ($placeholders)";
                $params = array_merge([$userId], $toDeactivateIDs);
                $qry = $this->db->query($sql, $params);
                if (!$qry) {
                    $this->db->trans_rollback();
                    $this->sys_error_db("ERROR, batch deactivate item out detail");
                    exit;
                }
            }

            // Sekarang update atau insert yang dikirim frontend
            foreach ($items as $item) {
                $ioupdetailID = $item["ioDetailID"];


                // encode json list batch number
                $jsonBatchNo = "[]";
                if (isset($item['ItemRequest']) && is_array($item['ItemRequest'])) {
                    $batches = $item['ItemRequest'];
                    if (sizeof($batches) > 0) {
                        $jsonResult = json_encode($batches);
                        if ($jsonResult === false) {
                            throw new Exception("[Error] Failed to encode json batch number");
                        } else {
                            $jsonBatchNo = $jsonResult;
                        }
                    }
                }

                if ($ioupdetailID) {
                    // UPDATE existing
                    $sql = "UPDATE t_item_out_detail SET
                            T_ItemOutDetailItemBatchNo = ?,
                            T_ItemOutDetailQty = ?,
                            T_ItemOutDetailLastUpdated = NOW(),
                            T_ItemOutDetailUserID = ?
                            WHERE T_ItemOutDetailID = ?";
                    $qry = $this->db->query($sql, [
                        $jsonBatchNo,
                        intval($item["rioDReceiveQty"]),
                        $userId,
                        $ioupdetailID
                    ]);
                    if (!$qry) {
                        $this->db->trans_rollback();
                        $this->sys_error_db("ERROR, update item out detail");
                        exit;
                    }
                } else {
                    // INSERT baru
                    $sql = "INSERT INTO t_item_out_detail(
                        T_ItemOutDetailT_ItemOutID,
                        T_ItemOutDetailRequestItemOutID,
                        T_ItemOutDetailRequestItemOutDetailID,
                        T_ItemOutDetailM_ItemID,
                        T_ItemOutDetailItemUnitID,
                        T_ItemOutDetailItemBatchNo,
                        T_ItemOutDetailQty,
                        T_ItemOutDetailCreated,
                        T_ItemOutDetailUserID) VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), ?)";
                    $qry = $this->db->query($sql, [
                        $IOID,
                        $item["rioID"],
                        $item["rioDID"],
                        $item["itemID"],
                        $item["unitID"],
                        $jsonBatchNo,
                        intval($item["rioDReceiveQty"]),
                        $userId
                    ]);
                    if (!$qry) {
                        $this->db->trans_rollback();
                        $this->sys_error_db("failed to insert data table item out detail", $this->db);
                        exit;
                    }
                }
            }
            $sql = "SELECT t_item_out.* 
                    FROM t_item_out
                    WHERE T_ItemOutIsActive = 'Y'
                    AND T_ItemOutID = ?";
            $qry = $this->db->query($sql, [$IOID]);
            if (!$qry) {
                $this->sys_error_db("select item out error", $this->db);
                exit;
            }
            $row = $qry->row();

            $userdesc = "Transaksi item out dengan kode " . $row->T_ItemOutNumber . " telah di edit";
            $this->insertUserActivityIo($IOID, $userId, "UPDATE", $userdesc);

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

    public function rejectRequest()
    {
        try {
            $this->db->trans_begin();

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

            $IOID = "";
            if (isset($prm["IOID"])) {
                $IOID = trim($prm["IOID"]);
            }

            $sql = "UPDATE t_item_out SET
                    T_ItemOutStatus = 'Rejected',
                    T_ItemOutUserID = ?,
                    T_ItemOutLastUpdated = NOW()
                    WHERE T_ItemOutID = ?";
            $qry = $this->db->query($sql, [
                $userId,
                $IOID
            ]);
            if (!$qry) {
                $this->db->trans_rollback();
                $this->sys_error_db("Failed delete item out", $this->db);
                exit;
            }

            $sql = "SELECT t_item_out.* 
                    FROM t_item_out
                    WHERE T_ItemOutIsActive = 'Y'
                    AND T_ItemOutID = ?";
            $qry = $this->db->query($sql, [$IOID]);
            if (!$qry) {
                $this->sys_error_db("select item out error", $this->db);
                exit;
            }
            $row = $qry->row();

            $userdesc = "Transaksi item out dengan kode " . $row->T_ItemOutNumber . " telah di reject";
            $this->insertUserActivityIo($IOID, $userId, "REJECTED", $userdesc);
            $this->db->trans_commit();
            $result = array(
                "total" => 1
            );
            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    public function deleteRequest()
    {
        try {
            $this->db->trans_begin();

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

            $IOID = "";
            if (isset($prm["IOID"])) {
                $IOID = trim($prm["IOID"]);
            }

            $sql = "UPDATE t_item_out SET
                    T_ItemOutIsActive = 'N',
                    T_ItemOutUserID = ?,
                    T_ItemOutLastUpdated = NOW()
                    WHERE T_ItemOutID = ?";
            $qry = $this->db->query($sql, [
                $userId,
                $IOID
            ]);
            if (!$qry) {
                $this->db->trans_rollback();
                $this->sys_error_db("Failed delete item out", $this->db);
                exit;
            }

            $sqldetail = "UPDATE t_item_out_detail SET
                        T_ItemOutDetailIsActive = 'N',
                        T_ItemOutDetailLastUpdated = NOW(),
                        T_ItemOutDetailUserID = ?
                        WHERE T_ItemOutDetailT_ItemOutID = ?";
            $qrydetail = $this->db->query($sqldetail, [
                $userId,
                $IOID
            ]);
            if (!$qrydetail) {
                $this->db->trans_rollback();
                $this->sys_error_db("Failed delete item out detail", $this->db);
                exit;
            }

            $sqlstatus = "UPDATE request_item_out SET 
                    RequestItemOutStatus = 'Process',
                    RequestItemOutUserID = ?,
                    RequestItemOutLastUpdated = NOW()
                    WHERE RequestItemOutID = ?";
            $qrystatus = $this->db->query($sqlstatus, [
                $userId,
                $prm["RIOID"]
            ]);
            if (!$qrystatus) {
                $this->db->trans_rollback();
                $this->sys_error_db("Failed update request item out status", $this->db);
                exit;
            }

            $sqlstatusdetail = "UPDATE request_item_out_detail SET 
                    RequestItemOutDetailStatus = 'Process',
                    RequestItemOutDetailLastUpdated = NOW(),
                    RequestItemOutDetailUserID = ?
                    WHERE RequestItemOutDetailID = ?";
            $qrystatusdetail = $this->db->query($sqlstatusdetail, [
                $userId,
                $prm["RIODID"]
            ]);
            if (!$qrystatusdetail) {
                $this->db->trans_rollback();
                $this->sys_error_db("Failed update request item out detail status", $this->db);
                exit;
            }

            $sql = "SELECT t_item_out.* 
                    FROM t_item_out
                    WHERE T_ItemOutIsActive = 'Y'
                    AND T_ItemOutID = ?";
            $qry = $this->db->query($sql, [$IOID]);
            if (!$qry) {
                $this->sys_error_db("select item out error", $this->db);
                exit;
            }
            $row = $qry->row();

            $userdesc = "Transaksi item out dengan kode " . $row->T_ItemOutNumber . " telah di hapus";
            $this->insertUserActivityIo($IOID, $userId, "DELETE", $userdesc);
            $this->db->trans_commit();
            $result = array(
                "total" => 1
            );
            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

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

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

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

            $IOID = "";
            if (isset($prm["IOID"])) {
                $IOID = trim($prm["IOID"]);
            }

            $number_offset = 0;
            $number_limit = 10;
            if ($prm["current_page"] > 0) {
                $number_offset = ($prm["current_page"] - 1) * $number_limit;
            }

            $sqlCount = "SELECT count(*) as total
                    FROM t_item_out_detail
                    JOIN m_item ON T_ItemOutDetailM_ItemID = M_ItemID
                    AND M_ItemIsActive = 'Y'
                    JOIN itemunit ON T_ItemOutDetailItemUnitID = ItemUnitID
                    AND ItemUnitIsActive = 'Y'
                    WHERE T_ItemOutDetailIsActive = 'Y'
                    AND T_ItemOutDetailT_ItemOutID = ?
                    ORDER BY T_ItemOutDetailID DESC";
            $qryCount = $this->db->query($sqlCount, [
                $IOID
            ]);

            $tot_count = 0;
            $tot_page = 0;
            if ($qryCount) {
                $tot_count = $qryCount->result_array()[0]["total"];
                $tot_page = ceil($tot_count / $number_limit);
            } else {
                $this->sys_error_db("item out detail count error", $this->db);
                exit;
            }

            $sql = "SELECT T_ItemOutDetailID,
                    T_ItemOutDetailT_ItemOutID,
                    T_ItemOutDetailM_ItemID,
                    T_ItemOutDetailQty,
                    M_ItemID,
                    M_ItemCode,
                    M_ItemDesc,
                    ItemUnitID,
                    ItemUnitCode,
                    ItemUnitName,
                    ROW_NUMBER() OVER(ORDER BY T_ItemOutDetailID) RowNumber
                    FROM t_item_out_detail
                    JOIN m_item ON T_ItemOutDetailM_ItemID = M_ItemID
                    AND M_ItemIsActive = 'Y'
                    JOIN itemunit ON T_ItemOutDetailItemUnitID = ItemUnitID
                    AND ItemUnitIsActive = 'Y'
                    WHERE T_ItemOutDetailIsActive = 'Y'
                    AND T_ItemOutDetailT_ItemOutID = ?
                    ORDER BY T_ItemOutDetailID DESC
                    LIMIT ? OFFSET ?";
            $qry = $this->db->query($sql, [
                $IOID,
                $number_limit,
                $number_offset
            ]);
            if ($qry) {
                $rows = $qry->result_array();
            } else {
                $this->sys_error_db("get item out detail error", $this->db);
                exit;
            }

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

    public function searchItem()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
            }
            $prm = $this->sys_input;

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

            $number_limit = 10;
            $sql = "SELECT 
                    M_ItemID,
                    M_ItemCode,
                    M_ItemDesc,
                    StockQty,
                    StockItemPrice,
                    StockBatchNo,
                    StockED,
                    StockWarehouseID
                    FROM stock
                    JOIN m_item ON M_ItemID = StockItemID
                    WHERE 
                    StockWarehouseID = ?
                    AND StockQty > 0
                    AND M_ItemIsActive = 'Y'
                    AND (M_ItemCode LIKE ? OR M_ItemDesc LIKE ?)";
            $qry = $this->db->query($sql, array($warehouseID, $search, $search));
            if ($qry) {
                $rows = $qry->result_array();
            } else {
                $this->db->trans_rollback();
                $this->sys_error_db("select item error", $this->db);
                exit;
            }

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

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

            $prm = $this->sys_input;
            $search = "";
            if (isset($prm["search"])) {
                $search = trim($prm["search"]);
                if ($search != "") {
                    $search = "%" . $prm["search"] . "%";
                } else {
                    $search = "%%";
                }
            }
            $itemID = $prm["itemID"];

            $sql = "SELECT 
                    ItemUnitID,
                    ItemUnitCode,
                    ItemUnitName,
                    ItemUnitCreated,
                    ItemUnitLastUpdated,
                    ItemUnitIsActive,
                    ItemUnitUserID,
                    ItemUnitMapM_ItemID,
                    ItemUnitMapIsPurchase,
                    ItemUnitMapIsReport,
                    ItemUnitMapIsBase
                    FROM itemunit 
                    JOIN itemunitmap ON ItemUnitMapItemUnitID = ItemUnitID AND ItemUnitMapIsActive ='Y'
                    AND ItemUnitMapM_ItemID = ?
                WHERE ItemUnitIsActive = 'Y'
                AND ItemUnitName LIKE ?
                ORDER BY ItemUnitName ASC";

            $query = $this->db->query($sql, [
                $itemID,
                $search
            ]);

            if (!$query) {
                $this->sys_error_db("item unit list", $this->db);
                exit;
            }

            $rows = $query->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);
        }
    }

    public function saveDetail()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }
            $this->db->trans_begin();
            $prm = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];

            $itemID = "";
            if (isset($prm["itemID"])) {
                $itemID = trim($prm["itemID"]);
            }
            $itemUnitID = "";
            if (isset($prm["itemUnitID"])) {
                $itemUnitID = trim($prm["itemUnitID"]);
            }
            $qty = "";
            if (isset($prm["qty"])) {
                $qty = trim($prm["qty"]);
            }
            $IOID = "";
            if (isset($prm["IOID"])) {
                $IOID = trim($prm["IOID"]);
            }

            $qryChek = "SELECT count(*) as exist
                        FROM t_item_out_detail
                        WHERE T_ItemOutDetailIsActive = 'Y'
                        AND T_ItemOutDetailT_ItemOutID = ?
                        AND T_ItemOutDetailM_ItemID = ?";
            $exist = $this->db->query($qryChek, [
                $IOID,
                $itemID
            ]);
            if ($exist) {
                $row = $exist->row()->exist;
            } else {
                $this->sys_error_db("exist error", $this->db);
                exit;
            }

            if ($row == 0) {
                $sql = "INSERT INTO t_item_out_detail(
                        T_ItemOutDetailT_ItemOutID,
                        T_ItemOutDetailM_ItemID,
                        T_ItemOutDetailItemUnitID,
                        T_ItemOutDetailQty,
                        T_ItemOutDetailIsActive,
                        T_ItemOutDetailCreated,
                        T_ItemOutDetailUserID) VALUES(?,?,?,?,'Y',NOW(),?)";
                $qry = $this->db->query($sql, [
                    $IOID,
                    $itemID,
                    $itemUnitID,
                    $qty,
                    $userId
                ]);
                if (!$qry) {
                    $this->db->trans_rollback();
                    $this->sys_error_db("Failed insert item out detail", $this->db);
                    exit;
                }

                $this->db->trans_commit();

                $result = array("total" => 1, "records" => array("xId" => 0));
                $this->sys_ok($result);
            } else {
                $errors = array();
                $qryItem = "SELECT M_ItemDesc FROM m_item WHERE M_ItemID = ?";
                $qryItem = $this->db->query($qryItem, [
                    $itemID
                ]);
                if ($qryItem) {
                    $rowItem = $qryItem->row()->M_ItemDesc;
                } else {
                    $this->db->trans_rollback();
                    $this->sys_error_db("Failed get item error", $this->db);
                    exit;
                }
                if ($row != 0) {
                    array_push($errors, array("msg" => "Data dengan item " . $rowItem . " sudah ada"));
                }
                $result = array("total" => -1, "errors" => $errors, "records" => array('status' => 'ERROR'));
                $this->sys_ok($result);
            }
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

    public function updateDetail()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }
            $this->db->trans_begin();
            $prm = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];

            $itemID = "";
            if (isset($prm["itemID"])) {
                $itemID = trim($prm["itemID"]);
            }
            $itemUnitID = "";
            if (isset($prm["itemUnitID"])) {
                $itemUnitID = trim($prm["itemUnitID"]);
            }
            $qty = "";
            if (isset($prm["qty"])) {
                $qty = trim($prm["qty"]);
            }
            $IOID = "";
            if (isset($prm["IOID"])) {
                $IOID = trim($prm["IOID"]);
            }
            $IODID = "";
            if (isset($prm["IODID"])) {
                $IODID = trim($prm["IODID"]);
            }

            $sqlCheck = "SELECT count(*) as exist
                        FROM t_item_out_detail
                        WHERE T_ItemOutDetailIsActive = 'Y'
                        AND T_ItemOutDetailT_ItemOutID = ?
                        AND T_ItemOutDetailM_ItemID = ?
                        AND T_ItemOutDetailItemUnitID = ?
                        AND T_ItemOutDetailID != ?";
            $qryCheck = $this->db->query($sqlCheck, [
                $IOID,
                $itemID,
                $itemUnitID,
                $IODID
            ]);
            if ($qryCheck && $qryCheck->result_array()[0]["exist"] > 0) {
                $this->sys_error("Item dan satuan sudah ada");
                exit;
            }

            $sql = "UPDATE t_item_out_detail SET
                    T_ItemOutDetailT_ItemOutID = ?,
                    T_ItemOutDetailM_ItemID = ?,
                    T_ItemOutDetailItemUnitID = ?,
                    T_ItemOutDetailQty = ?,
                    T_ItemOutDetailLastUpdated = NOW(),
                    T_ItemOutDetailUserID = ?
                    WHERE T_ItemOutDetailID = ?";
            $qry = $this->db->query($sql, [
                $IOID,
                $itemID,
                $itemUnitID,
                $qty,
                $userId,
                $IODID
            ]);
            if (!$qry) {
                $this->db->trans_rollback();
                $this->sys_error_db("Failed insert item out detail error", $this->db);
                exit;
            }

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

    public function deleteDetail()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }
            $this->db->trans_begin();
            $prm = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];

            $IODID = "";
            if (isset($prm["IODID"])) {
                $IODID = trim($prm["IODID"]);
            }

            $sql = "UPDATE t_item_out_detail SET
                    T_ItemOutDetailIsActive = 'N',
                    T_ItemOutDetailLastUpdated = NOW(),
                    T_ItemOutDetailUserID = ?
                    WHERE T_ItemOutDetailID = ?";
            $qry = $this->db->query($sql, [
                $userId,
                $IODID
            ]);
            if (!$qry) {
                $this->db->trans_rollback();
                $this->sys_error_db("Failed delete item out detail error", $this->db);
                exit;
            }

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

    public function orderConfirm()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }
            $this->db->trans_begin();
            $prm = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];

            $itemoutID = $prm["itemoutID"];

            $sqlDetail = "SELECT T_ItemOutDetailID,
                        T_ItemOutDetailT_ItemOutID,
                        T_ItemOutDetailM_ItemID,
                        T_ItemOutDetailItemUnitID,
                        T_ItemOutDetailQty
                        FROM t_item_out_detail
                        WHERE T_ItemOutDetailIsActive = 'Y'
                        AND T_ItemOutDetailT_ItemOutID = ?";
            $qryDetail = $this->db->query($sqlDetail, [$itemoutID]);
            if ($qryDetail) {
                $rows = $qryDetail->result_array();
            } else {
                $this->db->tans_rollback();
                $this->sys_error_db("select item out detail error", $this->db);
                exit;
            }

            // Ambil Warehouse ID
            $sqlHeader = "SELECT T_ItemOutWarehouseID FROM t_item_out WHERE T_ItemOutIsActive = 'Y' AND T_ItemOutID = ?";
            $qryHeader = $this->db->query($sqlHeader, [$itemoutID]);
            if (!$qryHeader || $qryHeader->num_rows() == 0) {
                $this->db->trans_rollback();
                $this->sys_error("Item Out tidak ditemukan");
                return;
            }
            $warehouseID = $qryHeader->row()->T_ItemOutWarehouseID;

            // loop detail
            foreach ($rows as $row) {
                $itemID = $row["T_ItemOutDetailM_ItemID"];
                $unitID = $row["T_ItemOutDetailItemUnitID"];
                $qtyNeeded = $row["T_ItemOutDetailQty"];

                // Ambil stok berdasarkan Warehouse, Item dan Unit
                $sqlStock = "SELECT StockID, StockQty 
                 FROM stock 
                 WHERE StockWarehouseID = ? 
                   AND StockItemID = ? 
                   AND StockItemUnitID = ? 
                   AND StockQty > 0
                 ORDER BY StockID ASC";
                $qryStock = $this->db->query($sqlStock, [$warehouseID, $itemID, $unitID]);
                if (!$qryStock) {
                    $this->db->trans_rollback();
                    $this->sys_error_db("select stock error", $this->db);
                    exit;
                }
                $stocks = $qryStock->result_array();

                foreach ($stocks as $stock) {
                    if ($qtyNeeded <= 0) break;

                    $stockID = $stock["StockID"];
                    $stockQty = $stock["StockQty"];

                    if ($stockQty >= $qtyNeeded) {
                        // Kurangi stok langsung dengan SQL
                        $sqlUpdate = "UPDATE stock 
                                      SET StockQty = StockQty - ? 
                                      WHERE StockID = ?";
                        $this->db->query($sqlUpdate, [$qtyNeeded, $stockID]);

                        $qtyNeeded = 0;
                    }
                }

                // Jika setelah looping qtyNeeded masih > 0, berarti stok tidak cukup
                if ($qtyNeeded > 0) {
                    $this->db->trans_rollback();
                    $this->sys_error("Stok tidak cukup untuk item ID: $itemID");
                    return;
                }
            }

            // update approved
            $sqlUpdate = "UPDATE t_item_out SET
                            T_ItemOutReceiveUserID= ?,
                            T_ItemOutStatus = 'Process',
                            T_ItemOutLastUpdated = NOW()
                            WHERE T_ItemOutID = ?";
            $qryUpdate = $this->db->query($sqlUpdate, [$userId, $itemoutID]);
            if (!$qryUpdate) {
                $this->db->trans_rollback();
                $this->sys_error_db("update item out error", $this->db);
                exit;
            }

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

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

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

            $startDate = $prm["startDate"];
            $endDate = $prm["endDate"];
            $search = isset($prm["search"]) ? $prm["search"] : "";
            $status = isset($prm["status"]) ? $prm["status"] : "";

            $number_offset = 0;
            $number_limit = 20;
            if ($prm["current_page"] > 0) {
                $number_offset = ($prm["current_page"] - 1) * $number_limit;
            }


            $sqlCount = "SELECT count(*) as total
            FROM request_item_out_detail
            JOIN request_item_out ON RequestItemOutDetailRequestItemOutID = RequestItemOutID
                AND RequestItemOutIsActive = 'Y'
                AND (RequestItemOutNumber  LIKE ? )
                AND (RequestItemOutStatus = ? OR ? = '' )
                AND RequestItemOutDate BETWEEN ? AND ?
            JOIN m_item ON RequestItemOutDetailM_ItemID = M_ItemID 
                AND M_ItemIsActive = 'Y'
            JOIN stock ON StockItemID = RequestItemOutDetailM_ItemID
                AND StockItemUnitID = RequestItemOutDetailItemUnitID
                AND StockWarehouseID = RequestItemOutWarehouseID
            WHERE RequestItemOutDetailIsActive = 'Y'
            GROUP BY RequestItemOutDetailID 
            ORDER BY RequestItemOutDetailID DESC";
            $qryCount = $this->db->query($sqlCount, ['%' . $search . '%', $status, $status, $startDate, $endDate]);

            $tot_count = 0;
            $tot_page = 0;
            if ($qryCount) {
                $tot_count = $qryCount->result_array()[0]["total"];
                $tot_page = ceil($tot_count / $number_limit);
            } else {
                $this->sys_error_db("request item out count error", $this->db);
                exit;
            }

            $sql = "SELECT RequestItemOutDetailID as rioDID,
                RequestItemOutDetailM_ItemID as rioDItemID,
                RequestItemOutDetailItemUnitID as rioDItemUnitID,
                RequestItemOutDetailQty as rioDQty,
                RequestItemOutDetailStatus as rioDStatus,
                RequestItemOutID as rioID,
                RequestItemOutDate as rioDate,
                RequestItemOutNumber as rioNumber,
                RequestItemOutNote as rioNote,
                RequestItemOutDivisionID as rioDivisionID,
                RequestItemOutStatus as rioStatus,
                M_ItemID,
                M_ItemCode,
                M_ItemDesc,
                StockID,
                StockItemPrice,
                SUM(StockQty) AS StockQty
            FROM request_item_out_detail
            JOIN request_item_out ON RequestItemOutDetailRequestItemOutID = RequestItemOutID
                AND RequestItemOutIsActive = 'Y'
                AND (RequestItemOutNumber  LIKE ?)
                AND (RequestItemOutStatus = ? OR ? = '' )
                AND RequestItemOutDate BETWEEN ? AND ?
            JOIN m_item ON RequestItemOutDetailM_ItemID = M_ItemID 
                AND M_ItemIsActive = 'Y'
            JOIN stock ON StockItemID = RequestItemOutDetailM_ItemID
                AND StockItemUnitID = RequestItemOutDetailItemUnitID
                AND StockWarehouseID = RequestItemOutWarehouseID
            WHERE RequestItemOutDetailIsActive = 'Y'
            GROUP BY RequestItemOutDetailID 
            ORDER BY RequestItemOutDetailID DESC
            LIMIT ? OFFSET ?";
            $qry = $this->db->query($sql, [
                '%' . $search . '%',
                $status,
                $status,
                $startDate,
                $endDate,
                $number_limit,
                $number_offset
            ]);
            // echo $this->db->last_query();
            // exit;
            if ($qry) {
                $rows = $qry->result_array();
            } else {
                $this->sys_error_db("request item out error", $this->db);
                exit;
            }

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

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

            $payload = $this->sys_input;
            $user = $this->sys_user;
            $regionalID = $user['S_RegionalID'];
            $branchCode = $user['M_BranchCode'];
            $loginType = $user['M_UserLocationFlag'];
            $userID = $user['M_UserID'];
            $sql = "SELECT M_UserDivisionID,
                        M_UserDivisionM_UserID,
                        M_UserDivisionDivisionID,
                        M_UserUsername,
                        DivisionName
                        FROM m_user  
                        JOIN m_userdivision ON M_UserID = M_UserDivisionM_UserID
                        AND M_UserDivisionIsActive = 'Y'
                        JOIN division ON M_UserDivisionDivisionID = DivisionID
                        AND DivisionIsActive = 'Y'
                        WHERE M_UserIsActive = 'Y'
                        AND M_UserDivisionM_UserID = ?";
            $qry = $this->db->query($sql, [$userID]);
            if (!$qry) {
                $this->sys_error_db("Error cek approval level");
                exit;
            }
            $approvalDivision = $qry->result_array();
            if (count($approvalDivision) == 0) {
                $result = array(
                    'total' => 0,
                    'records' => []
                );
                $this->sys_ok($result);
                exit;
            } else {
                $result = array(
                    "total" => 1,
                    "records" => $approvalDivision,
                    "sql" => $this->db->last_query()
                );

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

    public function approveRequest()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }
            $this->db->trans_begin();
            $prm = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];

            $arrRequest = $prm["arrRequest"];
            foreach ($arrRequest as $key => $value) {
                $sql = "UPDATE request_item_out SET
                        RequestItemOutStatus = 'Process',
                        RequestItemOutApprovedDate = NOW(),
                        RequestItemOutApprovedUserID = ?,
                        RequestItemOutLastUpdated = NOW()
                        WHERE RequestItemOutID = ?";
                $qry = $this->db->query($sql, [
                    $userId,
                    $value["rioID"]
                ]);
                if (!$qry) {
                    $this->db->trans_rollback();
                    $this->sys_error_db("update request item out error", $this->db);
                    exit;
                }

                $sqlDetail = "UPDATE request_item_out_detail SET
                        RequestItemOutDetailStatus = 'Process',
                        RequestItemOutDetailLastUpdated = NOW(),
                        RequestItemOutDetailUserID = ?
                        WHERE RequestItemOutDetailID = ?";
                $qryDetail = $this->db->query($sqlDetail, [
                    $userId,
                    $value["rioDID"]
                ]);
                if (!$qryDetail) {
                    $this->db->trans_rollback();
                    $this->sys_error_db("update request item out detail error", $this->db);
                    exit;
                }
            }

            // insert log
            $sql_json = "SELECT request_item_out.*, '' as detail
                    FROM request_item_out
                    WHERE RequestItemOutIsActive = 'Y'
                    AND RequestItemOutID = ?";
            $qry_json = $this->db->query($sql_json, [$value["rioID"]]);
            if (!$qry_json) {
                $this->db->trans_rollback();
                $this->sys_error_db("select json rio error");
                exit;
            }
            $row_json = $qry_json->row_array();

            $userdesc = "Request Item out dengan kode " . $row_json['RequestItemOutNumber'] . " telah di approve";

            $sql_json_detail = "SELECT request_item_out_detail.* 
                        FROM request_item_out_detail
                        WHERE RequestItemOutDetailIsActive = 'Y'
                        AND RequestItemOutDetailRequestItemOutID = ?";
            $qry_json_detail = $this->db->query($sql_json_detail, [$value["rioID"]]);
            if ($qry_json_detail) {
                $row_json["detail"] = $qry_json_detail->result_array();
            } else {
                $this->sys_error_db("select detail rio error", $this->db);
                exit;
            }

            $data_json = $row_json;

            $sql_log = "INSERT INTO user_activity(
                        UserActivityCode,
                        UserActivityStatus,
                        UserActivityDescription,
                        UserActivityRefID,
                        UserActivityData,
                        UserActivityUserID,
                        UserActivityCreated
                    ) VALUES('RIO','Process',?,?,?,?,NOW())";
            $qry_log = $this->db->query($sql_log, [
                $userdesc,
                $value["rioID"],
                json_encode($data_json),
                $userId
            ]);
            if (!$qry_log) {
                $this->db->trans_rollback();
                $this->sys_error_db("insert user activity error", $this->db);
                exit;
            }

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

    public function rejectedRequest()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }
            $this->db->trans_begin();
            $prm = $this->sys_input;
            $userId = $this->sys_user["M_UserID"];

            $arrRequest = $prm["arrRequest"];
            foreach ($arrRequest as $key => $value) {
                $sql = "UPDATE request_item_out SET
                        RequestItemOutStatus = 'Rejected',
                        RequestItemOutUserID = ?,
                        RequestItemOutLastUpdated = NOW()
                        WHERE RequestItemOutID = ?";
                $qry = $this->db->query($sql, [
                    $userId,
                    $value["rioID"]
                ]);
                if (!$qry) {
                    $this->db->trans_rollback();
                    $this->sys_error_db("update request item out error", $this->db);
                    exit;
                }

                $sqlDetail = "UPDATE request_item_out_detail SET
                        RequestItemOutDetailStatus = 'Rejected',
                        RequestItemOutDetailLastUpdated = NOW(),
                        RequestItemOutDetailUserID = ?
                        WHERE RequestItemOutDetailID = ?";
                $qryDetail = $this->db->query($sqlDetail, [
                    $userId,
                    $value["rioDID"]
                ]);
                if (!$qryDetail) {
                    $this->db->trans_rollback();
                    $this->sys_error_db("update request item out detail error", $this->db);
                    exit;
                }
            }

            // insert log
            $sql_json = "SELECT request_item_out.*, '' as detail
                    FROM request_item_out
                    WHERE RequestItemOutIsActive = 'Y'
                    AND RequestItemOutID = ?";
            $qry_json = $this->db->query($sql_json, [$value["rioID"]]);
            if (!$qry_json) {
                $this->db->trans_rollback();
                $this->sys_error_db("select json rio error");
                exit;
            }
            $row_json = $qry_json->row_array();

            $userdesc = "Request Item out dengan kode " . $row_json['RequestItemOutNumber'] . " telah di reject";

            $sql_json_detail = "SELECT request_item_out_detail.* 
                        FROM request_item_out_detail
                        WHERE RequestItemOutDetailIsActive = 'Y'
                        AND RequestItemOutDetailRequestItemOutID = ?";
            $qry_json_detail = $this->db->query($sql_json_detail, [$value["rioID"]]);
            if ($qry_json_detail) {
                $row_json["detail"] = $qry_json_detail->result_array();
            } else {
                $this->sys_error_db("select detail rio error", $this->db);
                exit;
            }

            $data_json = $row_json;

            $sql_log = "INSERT INTO user_activity(
                        UserActivityCode,
                        UserActivityStatus,
                        UserActivityDescription,
                        UserActivityRefID,
                        UserActivityData,
                        UserActivityUserID,
                        UserActivityCreated
                    ) VALUES('RIO','Rejected',?,?,?,?,NOW())";
            $qry_log = $this->db->query($sql_log, [
                $userdesc,
                $value["rioID"],
                json_encode($data_json),
                $userId
            ]);
            if (!$qry_log) {
                $this->db->trans_rollback();
                $this->sys_error_db("insert user activity error", $this->db);
                exit;
            }

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

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

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

            $warehouseID = isset($prm["warehouseID"]) ? $prm["warehouseID"] : "";
            $divisionID = isset($prm["divisionID"]) ? $prm["divisionID"] : "";
            $search = isset($prm["search"]) ? $prm["search"] : "";
            $currentPage = isset($prm["currentPage"]) ? $prm["currentPage"] : 1;

            $limit = 10;
            $offset = ($currentPage - 1) * $limit;

            $sqlCount = "SELECT COUNT(*) as total FROM (
            SELECT *
            FROM request_item_out_detail
            JOIN request_item_out ON RequestItemOutDetailRequestItemOutID = RequestItemOutID
                AND RequestItemOutIsActive = 'Y'
                AND (RequestItemOutStatus = 'Process' OR RequestItemOutStatus = 'Partial')
                AND RequestItemOutWarehouseID = ?
                AND RequestItemOutDivisionID = ?
            JOIN m_item ON RequestItemOutDetailM_ItemID = M_ItemID 
                AND M_ItemIsActive = 'Y'
                AND (M_ItemDesc LIKE ?)
            JOIN itemunit ON RequestItemOutDetailItemUnitID = ItemUnitID 
                AND ItemUnitIsActive = 'Y'
            JOIN stock ON StockItemID = M_ItemID
                AND StockItemUnitID = RequestItemOutDetailItemUnitID
                AND StockWarehouseID = RequestItemOutWarehouseID
            LEFT JOIN t_item_out_detail ON T_ItemOutDetailRequestItemOutID = RequestItemOutDetailRequestItemOutID
                AND T_ItemOutDetailM_ItemID = RequestItemOutDetailM_ItemID
                AND T_ItemOutDetailItemUnitID = RequestItemOutDetailItemUnitID
            WHERE RequestItemOutDetailIsActive = 'Y'
                AND (RequestItemOutDetailStatus = 'Process' OR RequestItemOutDetailStatus = 'Partial')
            GROUP BY RequestItemOutDetailID) x";
            $qryCount = $this->db->query($sqlCount, [$warehouseID, $divisionID, '%' . $search . '%']);
            if (!$qryCount) {
                $this->sys_error_db("count item list request error", $this->db);
                exit;
            }

            $rowsCount = $qryCount->result_array();
            $total = ceil($rowsCount[0]["total"] / $limit);

            $sql = "SELECT 
                RequestItemOutDetailID as rioDID,
                RequestItemOutDetailRequestItemOutID as rioDrioID,
                RequestItemOutDetailM_ItemID as rioDItemID,
                RequestItemOutDetailItemUnitID as rioDItemUnitID,
                IFNULL(RequestItemOutDetailQty, 0) as rioDQty,
                IFNULL(T_ItemOutDetailQty, 0) as rioDReceiveQty,
                RequestItemOutDetailStatus as rioDStatus,
                RequestItemOutID as rioID,
                RequestItemOutDate as rioDate,
                RequestItemOutNumber as rioNumber,
                RequestItemOutWarehouseID as rioWarehouseID,
                RequestItemOutS_RegionalID as rioRegionalID,
                RequestItemOutM_BranchCode as rioBranchCode,
                RequestItemOutNote as rioNote,
                RequestItemOutDivisionID as rioDivisionID,
                RequestItemOutStatus as rioStatus,
                M_ItemID as itemID,
                M_ItemCode as itemCode,
                M_ItemDesc as itemDesc,
                ItemUnitID as unitID,
                ItemUnitCode as unitCode,
                ItemUnitName as unitName,
                StockID,
                StockWarehouseID,
                StockWarehouseAlmariID,
                StockWarehouseRackID,
                StockStockNumber,
                StockItemID,
                StockItemUnitID,
                StockItemPrice,
                StockBatchNo,
                StockED,
                StockLastUpdated,
                StockUserID,
                -- GROUP_CONCAT(CONCAT(StockBatchNo, ' (', StockQty, ')')) AS stockFull,
                SUM(StockQty) AS StockQty
            FROM request_item_out_detail
            JOIN request_item_out ON RequestItemOutDetailRequestItemOutID = RequestItemOutID
                AND RequestItemOutIsActive = 'Y'
                AND (RequestItemOutStatus = 'Process' OR RequestItemOutStatus = 'Partial')
                AND RequestItemOutWarehouseID = ?
                AND RequestItemOutDivisionID = ?
            JOIN m_item ON RequestItemOutDetailM_ItemID = M_ItemID 
                AND M_ItemIsActive = 'Y'
                AND (M_ItemDesc LIKE ?)
            JOIN itemunit ON RequestItemOutDetailItemUnitID = ItemUnitID 
                AND ItemUnitIsActive = 'Y'
            JOIN stock ON StockItemID = M_ItemID
                AND StockItemUnitID = RequestItemOutDetailItemUnitID
                AND StockWarehouseID = RequestItemOutWarehouseID
            LEFT JOIN t_item_out_detail ON T_ItemOutDetailRequestItemOutID = RequestItemOutDetailRequestItemOutID
                AND T_ItemOutDetailM_ItemID = RequestItemOutDetailM_ItemID
                AND T_ItemOutDetailItemUnitID = RequestItemOutDetailItemUnitID
            WHERE RequestItemOutDetailIsActive = 'Y'
                AND (RequestItemOutDetailStatus = 'Process' OR RequestItemOutDetailStatus = 'Partial')
            GROUP BY RequestItemOutDetailID
            ORDER BY RequestItemOutNumber DESC
            LIMIT ? OFFSET ?";
            $qry = $this->db->query($sql, [$warehouseID, $divisionID, '%' . $search . '%', $limit, $offset]);
            if (!$qry) {
                $this->sys_error_db("select item request error", $this->db);
                exit;
            }

            // echo $this->db->last_query();
            // exit;

            $rows = $qry->result_array();

            foreach ($rows as $key => $value) {
                $rows[$key]['ItemRequest'] = [];
            }


            $result = array(
                "records" => $rows,
                "total" => $total
            );

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

    // dijagain itemid dan itemunit harus sama
    // agar di stock pemakaian tidak terjadi rancu jumlah stocknya karena berdasarkan itemunit
    public function insertUsage($ioID, $userID)
    {
        try {
            // 1. Ambil data dari t_item_out_detail
            $this->db->trans_begin();
            $sql_tio = "SELECT T_ItemOutID,
            T_ItemOutDate,
            T_ItemOutWarehouseID,
            T_ItemOutDivisionID,
            T_ItemOutDetailID,
            T_ItemOutDetailM_ItemID,
            T_ItemOutDetailItemUnitID,
            T_ItemOutDetailItemBatchNo,
            T_ItemOutDetailQty,
            RequestItemOutS_RegionalID,
            RequestItemOutM_BranchCode,
            M_ItemDesc
            FROM t_item_out_detail 
            JOIN t_item_out ON T_ItemOutDetailT_ItemOutID = T_ItemOutID
            AND T_ItemOutIsActive = 'Y'
            JOIN request_item_out ON T_ItemOutDetailRequestItemOutID = RequestItemOutID
            AND RequestItemOutIsActive = 'Y'
            JOIN m_item ON T_ItemOutDetailM_ItemID = M_ItemID
            AND M_ItemIsActive = 'Y'
            WHERE T_ItemOutDetailIsActive = 'Y'
            AND T_ItemOutDetailT_ItemOutID = ?";

            $qry_tio = $this->db->query($sql_tio, [$ioID]);
            if (!$qry_tio) {
                $this->sys_error_db("select t_item_out error", $this->db);
                exit;
            }
            $rows_tio = $qry_tio->result_array();
            if (count($rows_tio) == 0) {
                $this->sys_error("No data found in t_item_out_detail");
                exit;
            }

            // 2. Ambil data existing dari item_usage
            $sqlusage = "SELECT ItemUsageID,
                ItemUsageS_RegionalID,
                ItemUsageM_BranchCode,
                ItemUsageDivisionID,
                ItemUsageM_ItemID,
                ItemUsageItemUnitID,
                ItemUsageQty,
                ItemUsagePrice
                FROM item_usage WHERE ItemUsageIsActive = 'Y'";
            $qryusage = $this->db->query($sqlusage, []);
            if (!$qryusage) {
                $this->db->trans_rollback();
                $this->sys_error_db('get select usage error', $this->db);
                exit;
            }
            $rowsusage = $qryusage->result_array();

            // 3. Buat mapping untuk pencarian cepat (ItemID dan ItemUsageItemUnitID sebagai key)
            $usage_map = [];
            foreach ($rowsusage as $usage) {
                $key = $usage['ItemUsageM_ItemID'] . '_' . $usage['ItemUsageItemUnitID'];
                $usage_map[$key] = $usage;
            }
            // print_r($usage_map);
            // exit;

            // 4. Loop data t_item_out_detail
            foreach ($rows_tio as $key => $value) {
                // Decode batch JSON
                $jsonStr = $value["T_ItemOutDetailItemBatchNo"];
                $batches = [];

                if (!empty($jsonStr)) {
                    $decode = json_decode($jsonStr, true);
                    if ($decode !== null && json_last_error() === JSON_ERROR_NONE) {
                        $batches = $decode;
                    } else {
                        $this->sys_error_db("[Error] decode json for batches number");
                        exit;
                    }
                }

                // Buat key untuk pengecekan
                $check_key = $value["T_ItemOutDetailM_ItemID"] . '_' . $value["T_ItemOutDetailItemUnitID"];

                // Cek apakah sudah ada di item_usage
                if (isset($usage_map[$check_key])) {
                    // SUDAH ADA - Update qty dan proses detail
                    $existing_usage = $usage_map[$check_key];
                    $item_usage_id = $existing_usage['ItemUsageID'];

                    // Update qty di item_usage (opsional, sesuai kebutuhan)
                    $sql_update = "UPDATE item_usage 
                      SET ItemUsageQty = ItemUsageQty + ?,
                          ItemUsageUserID = ?,
                          ItemUsageLastUpdated = NOW()
                      WHERE ItemUsageID = ?";
                    $qry_update = $this->db->query($sql_update, [
                        $value["T_ItemOutDetailQty"],
                        $userID,
                        $item_usage_id
                    ]);
                    if (!$qry_update) {
                        $this->db->trans_rollback();
                        $this->sys_error_db("Failed update item usage", $this->db);
                        exit;
                    }
                } else {
                    // BELUM ADA - Insert baru
                    $sql = "INSERT INTO item_usage(
                            ItemUsageS_RegionalID,
                            ItemUsageM_BranchCode,
                            ItemUsageDivisionID,
                            ItemUsageM_ItemID,
                            ItemUsageItemUnitID,
                            ItemUsageQty,
                            ItemUsagePrice,
                            ItemUsageIsActive,
                            ItemUsageUserID,
                            ItemUsageCreated) VALUES(?,?,?,?,?,?,?,?,'Y',?,NOW())";
                    $qry = $this->db->query($sql, [
                        $value["RequestItemOutS_RegionalID"],
                        $value["RequestItemOutM_BranchCode"],
                        $value["T_ItemOutDivisionID"],
                        $value["T_ItemOutDetailM_ItemID"],
                        $value["T_ItemOutDetailItemUnitID"],
                        $value["T_ItemOutDetailQty"],
                        $batches[0]["StockItemPrice"], // Ambil dari batch pertama
                        $userID
                    ]);
                    if (!$qry) {
                        $this->db->trans_rollback();
                        $this->sys_error_db("Failed insert item usage", $this->db);
                        exit;
                    }

                    $item_usage_id = $this->db->insert_id();
                }

                // 5. Ambil existing detail untuk item_usage_id ini
                $sql_detail = "SELECT ItemUsageDetailID,
                   ItemUsageDetailStockBatchNo,
                   ItemUsageDetailQtyReq
                   FROM item_usage_detail 
                   WHERE ItemUsageDetailItemUsageID = ?";
                $qry_detail = $this->db->query($sql_detail, [$item_usage_id]);
                if (!$qry_detail) {
                    $this->db->trans_rollback();
                    $this->sys_error_db("Failed get item usage detail", $this->db);
                    exit;
                }
                $existing_details = $qry_detail->result_array();

                // Buat mapping batch no untuk pencarian cepat
                $detail_map = [];
                foreach ($existing_details as $detail) {
                    $detail_map[$detail['ItemUsageDetailStockBatchNo']] = $detail;
                }

                // 6. Proses setiap batch
                foreach ($batches as $k => $v) {
                    $batch_no = $v["StockBatchNo"];

                    // Cek apakah batch no sudah ada
                    if (isset($detail_map[$batch_no])) {
                        // BATCH SUDAH ADA - Update qty
                        $existing_detail = $detail_map[$batch_no];

                        $sql_update_detail = "UPDATE item_usage_detail 
                                 SET ItemUsageDetailQtyReq = ItemUsageDetailQtyReq + ?,
                                     ItemUsageDetailUserID = ?,
                                     ItemUsageDetailLastUpdated = NOW()
                                 WHERE ItemUsageDetailID = ?";
                        $qry_update_detail = $this->db->query($sql_update_detail, [
                            floatval($v["QtyReq"]),
                            $userID,
                            $existing_detail['ItemUsageDetailID']
                        ]);
                        if (!$qry_update_detail) {
                            $this->db->trans_rollback();
                            $this->sys_error_db("Failed update item usage detail", $this->db);
                            exit;
                        }
                    } else {
                        // BATCH BELUM ADA - Insert baru
                        $sql_insert_detail = "INSERT INTO item_usage_detail(
                                 ItemUsageDetailItemUsageID,
                                 ItemUsageDetailWarehouseID,
                                 ItemUsageDetailWarehouseName,
                                 ItemUsageDetailStockID,
                                 ItemUsageDetailStockNumber,
                                 ItemUsageDetailStockItemID,
                                 ItemUsageDetailStockItemUnitID,
                                 ItemUsageDetailItemUnitCode,
                                 ItemUsageDetailItemUnitName,
                                 ItemUsageDetailStockItemPrice,
                                 ItemUsageDetailStockBatchNo,
                                 ItemUsageDetailStockED,
                                 ItemUsageDetailStockQty,
                                 ItemUsageDetailQtyReq,
                                 ItemUsageDetailUserID,
                                 ItemUsageDetailCreated) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW())";
                        $qry_insert_detail = $this->db->query($sql_insert_detail, [
                            $item_usage_id,
                            $v["WarehouseID"],
                            $v["WarehouseName"],
                            $v["StockID"],
                            $v["StockStockNumber"],
                            $v["StockItemID"],
                            $v["StockItemUnitID"],
                            $v["ItemUnitCode"],
                            $v["ItemUnitName"],
                            $v["StockItemPrice"],
                            $v["StockBatchNo"],
                            $v["StockED"],
                            $v["StockQty"],
                            $v["QtyReq"],
                            $userID
                        ]);
                        if (!$qry_insert_detail) {
                            $this->db->trans_rollback();
                            $this->sys_error_db("Failed insert item usage detail", $this->db);
                            exit;
                        }
                    }
                }
            }

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

    public function insertItemUsage($ioID, $userID)
    {
        try {
            $this->db->trans_begin();
            $sql_tio = "SELECT T_ItemOutID,
                T_ItemOutDate,
                T_ItemOutWarehouseID,
                T_ItemOutDivisionID,
                T_ItemOutDetailID,
                T_ItemOutDetailM_ItemID,
                T_ItemOutDetailItemUnitID,
                T_ItemOutDetailItemBatchNo,
                T_ItemOutDetailQty,
                RequestItemOutS_RegionalID,
                RequestItemOutM_BranchCode,
                M_ItemDesc
                FROM t_item_out_detail 
                JOIN t_item_out ON T_ItemOutDetailT_ItemOutID = T_ItemOutID
                AND T_ItemOutIsActive = 'Y'
                JOIN request_item_out ON T_ItemOutDetailRequestItemOutID = RequestItemOutID
                AND RequestItemOutIsActive = 'Y'
                JOIN m_item ON T_ItemOutDetailM_ItemID = M_ItemID
                AND M_ItemIsActive = 'Y'
                WHERE T_ItemOutDetailIsActive = 'Y'
                AND T_ItemOutDetailT_ItemOutID = ?";
            $qry_tio = $this->db->query($sql_tio, [$ioID]);
            if (!$qry_tio) {
                $this->sys_error_db("select t_item_out error", $this->db);
                exit;
            }
            $rows_tio = $qry_tio->result_array();
            if (count($rows_tio) == 0) {
                $this->sys_error("No data found in t_item_out_detail");
                exit;
            }

            foreach ($rows_tio as $key => $value) {
                $jsonStr = $value["T_ItemOutDetailItemBatchNo"];
                $batches = [];

                if (!empty($jsonStr)) {
                    $decode = json_decode($jsonStr, true);
                    if ($decode !== null && json_last_error() === JSON_ERROR_NONE) {
                        $batches = $decode;
                    } else {
                        $this->sys_error_db("[Error] decode json for batches number");
                        exit;
                    }
                }

                // cari harga per item, 
                $sqlstock = "SELECT *
                    FROM stock
                    WHERE StockItemID = ?
                    AND StockItemUnitID = ?
                    AND StockWarehouseID = ?";
                $qrystock = $this->db->query($sqlstock, [
                    $value["T_ItemOutDetailM_ItemID"],
                    $value["T_ItemOutDetailItemUnitID"],
                    $value["T_ItemOutWarehouseID"]
                ]);
                if (!$qrystock) {
                    $this->sys_error_db("select stock error", $this->db);
                    exit;
                }
                $rowstock = $qrystock->row_array();
                if (!$rowstock) {
                    $this->sys_error("No stock found for item " . $value["M_ItemDesc"]);
                    exit;
                }

                $sql = "INSERT INTO item_usage(
                    ItemUsageS_RegionalID,
                    ItemUsageM_BranchCode,
                    ItemUsageDivisionID,
                    ItemUsageM_ItemID,
                    ItemUsageItemUnitID,
                    ItemUsageQty,
                    ItemUsagePrice,
                    ItemUsageIsActive,
                    ItemUsageUserID,
                    ItemUsageCreated) VALUES(?,?,?,?,?,?,?,?,'Y',?,NOW())";
                $qry = $this->db->query($sql, [
                    $value["RequestItemOutS_RegionalID"],
                    $value["RequestItemOutM_BranchCode"],
                    $value["T_ItemOutDivisionID"],
                    $value["T_ItemOutDetailM_ItemID"],
                    $value["T_ItemOutDetailItemUnitID"],
                    $value["T_ItemOutDetailQty"],
                    $rowstock["StockItemPrice"],
                    $userID
                ]);
                if (!$qry) {
                    $this->db->trans_rollback();
                    $this->sys_error_db("Failed insert item usage", $this->db);
                    exit;
                }

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

                foreach ($batches as $k => $v) {
                    $sql = "INSERT INTO item_usage_detail(
                        ItemUsageDetailItemUsageID,
                        ItemUsageDetailWarehouseID,
                        ItemUsageDetailWarehouseName,
                        ItemUsageDetailStockID,
                        ItemUsageDetailStockNumber,
                        ItemUsageDetailStockItemID,
                        ItemUsageDetailStockItemUnitID,
                        ItemUsageDetailItemUnitCode,
                        ItemUsageDetailItemUnitName,
                        ItemUsageDetailStockItemPrice,
                        ItemUsageDetailStockBatchNo,
                        ItemUsageDetailStockED,
                        ItemUsageDetailStockQty,
                        ItemUsageDetailQtyReq,
                        ItemUsageDetailUserID,
                        ItemUsageDetailCreated) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW())";
                    $qry = $this->db->query($sql, [
                        $last_id,
                        $v["WarehouseID"],
                        $v["WarehouseName"],
                        $v["StockID"],
                        $v["StockStockNumber"],
                        $v["StockItemID"],
                        $v["StockItemUnitID"],
                        $v["ItemUnitCode"],
                        $v["ItemUnitName"],
                        $v["StockItemPrice"],
                        $v["StockBatchNo"],
                        $v["StockED"],
                        $v["StockQty"],
                        $v["QtyReq"],
                        $userID
                    ]);
                    if (!$qry) {
                        $this->db->trans_rollback();
                        $this->sys_error_db("Failed insert item usage detail", $this->db);
                        exit;
                    }
                }
            }

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

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

            $prm = $this->sys_input;
            $batchNo = "%";
            if ($prm['batchno'] != '') {
                $batchNo = $prm['batchno'] . "%";
            }

            $sqlbatch = "SELECT 
                WarehouseID,
                WarehouseName,
                StockID,
                StockStockNumber,
                StockItemID,
                StockItemUnitID,
                ItemUnitCode,
                ItemUnitName,
                StockItemPrice,
                StockBatchNo,
                StockED,
                StockQty
            FROM warehouse
            JOIN stock ON StockWarehouseID = WarehouseID 
                AND StockQty > 0
            JOIN itemunit ON ItemUnitID = StockItemUnitID AND ItemUnitIsActive= 'Y'
            WHERE WarehouseIsActive = 'Y' AND WarehouseIsTransit = 'N' 
                AND WarehouseS_RegionalID = ?
                AND WarehouseM_BranchID = ?
                AND StockItemID = ?
                AND StockItemUnitID = ?
                AND StockBatchNo LIKE ?";
            $quebatch = $this->db->query($sqlbatch, [
                $prm['regionalid'],
                $prm['branchid'],
                $prm['itemid'],
                $prm['unitid'],
                $batchNo
            ]);
            if (!$quebatch) {
                $this->sys_error_db("error get data draft detail transfer");
                exit;
            }
            $batch = $quebatch->result_array();
            $result = array(
                'records' => $batch,
                'total' => sizeof($batch)
            );

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

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

            $payload = $this->sys_input;
            $user = $this->sys_user;
            $regionalID = $user['S_RegionalID'];
            $branchCode = $user['M_BranchCode'];
            $loginType = $user['M_UserLocationFlag'];
            $userID = $user['M_UserID'];
            $sql = "SELECT m_approve_level.* FROM m_user
                JOIN m_approve_level
                ON M_UserM_ApproveLevelID = M_ApproveLevelID
                WHERE M_UserID = ?";
            $qry = $this->db->query($sql, [$userID]);
            if (!$qry) {
                $this->sys_error_db("Error cek approval level");
                exit;
            }
            $approvalLevel = $qry->result_array();
            if (count($approvalLevel) == 0) {
                $result = array(
                    'total' => 0,
                    'records' => []
                );
                $this->sys_ok($result);
                exit;
            } else {
                $result = array(
                    "total" => 1,
                    "records" => $approvalLevel,
                    "sql" => $this->db->last_query()
                );

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