<?php

class TransferRequestNP extends MY_Controller
{
    var $db;
    public function index()
    {
        echo "Transfer Request/Requester Non Persediaan API";
    }

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

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

            $prm = $this->sys_input;
            $regID = $prm["S_RegionalID"];

            $sql = "SELECT M_BranchID, M_BranchCode, M_BranchName
                    FROM m_branch
                    WHERE M_BranchIsActive = 'Y'
                    AND M_BranchS_RegionalID = ?";
            $qry = $this->db->query($sql, [$regID]);
            if (!$qry) {
                $this->sys_error_db("Failed to get Branches from RegionalID: {$regID}", $this->db);
                exit;
            }
            $rst = $qry->result_array();

            $this->sys_ok(["records" => $rst]);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

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

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

            $startDate = $payload["startDate"];
            $endDate = $payload["endDate"];

            $search = $payload['search'];
            if ($search == "") {
                $search = "%";
            }

            $status = $payload["StatusName"];
            if (strtolower($status) == 'all') {
                $status = "%";
            }

            $cabangcode = $payload["M_BranchCode"];
            if (strtolower($cabangcode) == 'all') {
                $cabangcode = "%";
            }

            $offset = 0;
            $limit = 10;
            if ($payload["currentPage"] > 0) {
                $offset = ($payload["currentPage"] - 1) * $limit;
            }

            $sql = "SELECT
                t_goods_transfer.*,
                M_BranchID,
                M_BranchCode,
                M_BranchName,
                DivisionCode,
                DivisionName
            FROM t_goods_transfer
            JOIN m_branch ON T_GoodsTransferToM_BranchCode = M_BranchCode 
                AND M_BranchIsActive = 'Y'
            JOIN division ON DivisionID = T_GoodsTransferDivisionID 
                AND DivisionIsActive = 'Y'
            WHERE T_GoodsTransferIsActive = 'Y'
                AND T_GoodsTransferFromS_RegionalID = ?
                AND T_GoodsTransferNum LIKE ?
                AND T_GoodsTransferToM_BranchCode LIKE ?
                AND T_GoodsTransferType = 'NP'
                AND T_GoodsTransferStatus LIKE ?
                AND T_GoodsTransferDate BETWEEN DATE(?) AND DATE(?)
            ORDER BY T_GoodsTransferDate DESC";

            $sqldata = $sql . " LIMIT ? OFFSET ?";

            $quedata = $this->db->query($sqldata, [
                $regionalID,
                $search,
                $cabangcode,
                $status,
                $startDate,
                $endDate,
                $limit,
                $offset
            ]);
            if (!$quedata) {
                $this->sys_error_db("[Error] get data");
                exit;
            }
            $data = $quedata->result_array();

            $sqltotal = "SELECT COUNT(*) AS total FROM ($sql) as x";
            $quetotal = $this->db->query($sqltotal, [
                $regionalID,
                $search,
                $cabangcode,
                $status,
                $startDate,
                $endDate
            ]);
            if (!$quetotal) {
                $this->sys_error_db("[Error] get total data");
                exit;
            }
            $total = $quetotal->result_array()[0]['total'];

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

    public function getDivision()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("invalid token");
                exit;
            }

            $sqldiv = "SELECT 
                DivisionID,
                DivisionCode,
                DivisionName
            FROM division 
            WHERE DivisionIsActive = 'Y'";
            $quediv = $this->db->query($sqldiv, []);
            if (!$quediv) {
                $this->sys_error_db("[Error] get listing data divisi");
                exit;
            }
            $result = $quediv->result_array();
            $this->sys_ok($result);
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

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

            $prm = $this->sys_input;
            $regionalid = $prm['regionalid'];
            $branchIDOrigin = $prm['branchIDorigin'];
            $branchCodeDestin = $prm['branchcodedestin'];
            $divisionID = $prm['divisionID'];
            $currpage = $prm['currpage'];

            $page = 0;
            $limit = 5;
            if ($currpage > 0) {
                $page = ($currpage - 1) * $limit;
            }

            $sql = "SELECT
                PurchaseRequestDate,
                PurchaseRequestNumber,
                PurchaseRequestDetailM_ItemID,
                PurchaseRequestDetailItemUnitID,
                M_ItemDesc,
                ItemUnitName,
                PurchaseRequestFlagID,
                PurchaseRequestFlagQty,
                PurchaseRequestFlagQtyRest,
                COALESCE(SUM(CASE WHEN WarehouseID IS NOT NULL AND StockItemId IS NOT NULL THEN StockQty ELSE 0 END), 0) as StockGudang,
                PurchaseRequestFlagStatus
            FROM purchase_request_flag 
            JOIN purchase_request_detail ON PurchaseRequestDetailID = PurchaseRequestFlagPurchaseRequestDetailID
                AND PurchaseRequestDetailIsActive = 'Y'
            JOIN purchase_request ON PurchaseRequestID = PurchaseRequestDetailPurchaseRequestID 
                AND PurchaseRequestIsActive = 'Y' 
            JOIN m_item ON M_ItemID = PurchaseRequestDetailM_ItemID 
                AND M_ItemIsActive = 'Y'
                AND M_ItemItem_CategoryID != 1
            JOIN itemunit ON ItemUnitID = PurchaseRequestDetailItemUnitID
                AND ItemUnitIsActive = 'Y'
            JOIN m_itemdivision ON M_ItemDivisionM_ItemID = M_ItemID
                AND M_ItemDivisionIsActive = 'Y'
                AND M_ItemDivisionDivisionID = ?
            JOIN warehouse ON WarehouseS_RegionalID = PurchaseRequestS_RegionalID 
                AND WarehouseIsTransit = 'N'
                AND WarehouseM_BranchID = 0 
                AND WarehouseIsActive = 'Y' 
            LEFT JOIN stock ON StockItemId = M_ItemID AND StockWarehouseID = WarehouseID 
            WHERE PurchaseRequestFlagIsActive = 'Y' 
                AND FIND_IN_SET('TF', PurchaseRequestFlagStatus) 
                AND PurchaseRequestDetailStatus = 'Read' 
                AND PurchaseRequestFlagIsClosed = 'N' 
                AND PurchaseRequestS_RegionalID = ? 
                AND PurchaseRequestM_BranchCode = ? 
                AND NOT EXISTS (
                    SELECT 1 
                    FROM t_goods_transfer 
                    JOIN t_goods_transfer_detail ON T_GoodsTransferDetailIDT_GoodsTransferID = T_GoodsTransferID 
                        AND T_GoodsTransferDetailIsActive = 'Y' 
                    WHERE T_GoodsTransferDetailT_PurchaseRequestFlagID = PurchaseRequestFlagID
                        AND T_GoodsTransferFromS_RegionalID = ? 
                        AND T_GoodsTransferToM_BranchCode = ? 
                )
            GROUP BY PurchaseRequestFlagID, PurchaseRequestNumber";

            $sqllist = $sql . " LIMIT ? OFFSET ?";
            $quelist = $this->db->query($sqllist, [
                $divisionID,
                $regionalid,
                $branchCodeDestin,
                $regionalid,
                $branchCodeDestin,
                $limit,
                $page
            ]);
            if (!$quelist) {
                $this->db->sys_error_db("[Error] get data list tf request non persediaan");
                exit;
            }
            $data = $quelist->result_array();

            $sqltotal = "SELECT COUNT(*) AS total FROM ($sql) as x";
            $quetotal = $this->db->query($sqltotal, [
                $divisionID,
                $regionalid,
                $branchCodeDestin,
                $regionalid,
                $branchCodeDestin
            ]);
            if (!$quetotal) {
                $this->db->sys_error_db("[Error] get data list tf request non persediaan");
                exit;
            }
            $total = $quetotal->result_array()[0]['total'];

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

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

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

            $prm = $this->sys_input;

            $sql = "SELECT 
                WarehouseID,
                WarehouseName,
                StockID,
                StockStockNumber,
                StockWarehouseID,
                StockItemID,
                StockItemUnitID,
                StockItemPrice,
                ItemUnitName,
                StockQty
            FROM warehouse
            JOIN stock ON StockWarehouseID = WarehouseID 
                AND WarehouseIsActive = 'Y' AND WarehouseIsTransit = 'N'
            JOIN itemunit ON ItemUnitID = StockItemUnitID AND ItemUnitIsActive= 'Y'
            WHERE WarehouseS_RegionalID = ?
                AND WarehouseM_BranchID = 0
                AND StockItemID = ?
                AND StockItemUnitID = ?";
            $que = $this->db->query($sql, [$prm['regionalid'], $prm['itemid'], $prm['unitid']]);
            if (!$que) {
                $this->db->sys_error_db("[Error] list stock item");
                exit;
            }
            $data = $que->result_array();

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

    public function getDraftDetail()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
                exit;
            }
            $prm = $this->sys_input;
            $goodTfID = $prm['goodTfID'];

            $sql = "SELECT
                PurchaseRequestDate,
                PurchaseRequestNumber,
                PurchaseRequestDetailM_ItemID,
                PurchaseRequestDetailItemUnitID,
                M_ItemDesc,
                ItemUnitName,
                COALESCE(SUM(CASE WHEN WarehouseID IS NOT NULL AND StockItemId IS NOT NULL THEN StockQty ELSE 0 END), 0) as StockGudang,
                PurchaseRequestFlagID,
                T_GoodsTransferDetailQty as PurchaseRequestFlagQty,
                T_GoodsTransferDetailQtyTF as PurchaseRequestFlagQtyRest,
                T_GoodsTransferDetailItemBarNote,
                PurchaseRequestFlagStatus
            FROM t_goods_transfer 
            LEFT JOIN t_goods_transfer_detail ON T_GoodsTransferDetailIDT_GoodsTransferID = T_GoodsTransferID 
                AND T_GoodsTransferDetailIsActive = 'Y' 
            JOIN purchase_request_flag ON PurchaseRequestFlagID = T_GoodsTransferDetailT_PurchaseRequestFlagID 
                AND PurchaseRequestFlagIsActive = 'Y' 
            JOIN purchase_request_detail ON PurchaseRequestDetailID = PurchaseRequestFlagPurchaseRequestDetailID
                AND PurchaseRequestDetailIsActive = 'Y' 
            JOIN purchase_request ON PurchaseRequestID = PurchaseRequestDetailPurchaseRequestID
                AND PurchaseRequestIsActive = 'Y' 
            JOIN m_item ON M_ItemID = PurchaseRequestDetailM_ItemID 
                AND M_ItemItem_CategoryID != 1 
                AND M_ItemIsActive = 'Y'
            JOIN itemunit ON ItemUnitID = PurchaseRequestDetailItemUnitID
                AND ItemUnitIsActive = 'Y'
            JOIN m_branch ON M_BranchCode = PurchaseRequestM_BranchCode 
                AND M_BranchIsActive = 'Y' 
            JOIN warehouse ON WarehouseS_RegionalID = PurchaseRequestS_RegionalID 
                AND WarehouseIsTransit = 'N'
                AND WarehouseM_BranchID = 0
                AND WarehouseIsActive = 'Y' 
            LEFT JOIN stock ON StockItemId = M_ItemID
                AND StockWarehouseID = WarehouseID 
            WHERE PurchaseRequestFlagIsActive = 'Y' 
                AND T_GoodsTransferID = ? 
                AND T_GoodsTransferIsActive = 'Y'
            GROUP BY PurchaseRequestNumber, PurchaseRequestFlagID";
            $qry = $this->db->query($sql, [$goodTfID]);
            if (!$qry) {
                $this->sys_error_db("[Error] get detail transfer request non persediaan");
                exit;
            }
            $detail = $qry->result_array();

            foreach ($detail as $key => $value) {
                $jsonStr = $value['T_GoodsTransferDetailItemBarNote'];
                $barnote = [];

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

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

    public function createTfRequest()
    {
        try {
            if (!$this->isLogin) {
                throw new Exception("Invalid Token");
            }

            $user = $this->sys_user;
            $userID = $this->sys_user["M_UserID"];
            $data = $this->sys_input;
            $datadetail = $data['detail'];

            $this->db->trans_begin();

            // generate tf number
            // $sqlnum = "SELECT `fn_numbering`('TR') AS GoodsTfNum";
            // $quenum = $this->db->query($sqlnum, []);
            // if (!$quenum) {
            //     throw new Exception("[Error] Failed to generate transfer request number. " . json_encode($this->db->error()));
            // }
            // $GoodsTfNum = $quenum->row()->GoodsTfNum;

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

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

            $sqlnum = "SELECT `fn_penomoran`(?, ?, ?, ?, ?, ?) AS numpd;";
            $quenum = $this->db->query($sqlnum, ['ST', $userDivID, $areatype, $areaid, 'SM', 'Y']);
            if (!$quenum) {
                throw new Exception("[Error] Failed to generate number for TF request NP. " . json_encode($this->db->error()));
            }
            $GoodsTfNum = $quenum->row_array()['numpd'];

            $sqlTrf = "INSERT INTO t_goods_transfer (
                T_GoodsTransferFromS_RegionalID,
                T_GoodsTransferToM_BranchCode,
                T_GoodsTransferDivisionID,
                T_GoodsTransferNum,
                T_GoodsTransferNotes,
                T_GoodsTransferDate,
                T_GoodsTransferType,
                T_GoodsTransferStatus,
                T_GoodsTransferCreatedAt,
                T_GoodsTransferM_UserID
            ) VALUES (?,?,?,?,?,?,'NP',?,NOW(),?)";
            $queTrf = $this->db->query($sqlTrf, [
                $data["S_RegionalID"],
                $data["M_BranchCode"],
                $data["DivisionID"],
                $GoodsTfNum,
                $data["GoodsTfNotes"],
                $data["GoodsTfDate"],
                $data["GoodsTfStatus"],
                $userID
            ]);
            if (!$queTrf) {
                throw new Exception("[Error] Failed to insert into table t_goods_transfer. " . json_encode($this->db->error()));
            }
            $TGoodsTrfID = $this->db->insert_id();

            // insert detail item tf into t_goods_transfer_detail
            foreach ($datadetail as $key => $value) {
                $flagID = $value['PurchaseRequestFlagID'];
                $itemID = $value['PurchaseRequestDetailM_ItemID'];
                $unitID = $value['PurchaseRequestDetailItemUnitID'];
                $QtyStart = intval($value['PurchaseRequestFlagQty']);
                $QtyTfRes = intval($value['PurchaseRequestFlagQtyRest']);

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

                $sqlTfDtl = "INSERT INTO t_goods_transfer_detail (
                    T_GoodsTransferDetailIDT_GoodsTransferID,
                    T_GoodsTransferDetailT_PurchaseRequestFlagID,
                    T_GoodsTransferDetailM_ItemID,
                    T_GoodsTransferDetailItemUnitID,
                    T_GoodsTransferDetailItemBarNote,
                    T_GoodsTransferDetailQty,
                    T_GoodsTransferDetailQtyTF,
                    T_GoodsTransferDetailCreatedAt,
                    T_GoodsTransferDetailM_UserID 
                ) VALUES (?,?,?,?,?,?,?,NOW(),?)";
                $queTfDtl = $this->db->query($sqlTfDtl, [
                    $TGoodsTrfID,
                    $flagID,
                    $itemID,
                    $unitID,
                    $jsonBarnote,
                    $QtyStart,
                    $QtyTfRes,
                    $userID
                ]);
                if (!$queTfDtl) {
                    throw new Exception("[Error] Failed to insert detail tf data into t_goods_transfer_detail. " . json_encode($this->db->error()));
                }
                $TGoodsTFDetailID = $this->db->insert_id();
                $datadetail[$key]['TGoodsTFDetailID'] = $TGoodsTFDetailID;

                // update flag jika status verified
                if ($data['GoodsTfStatus'] == 'Verified') {

                    $this->moveStockToTransit($value, $data['S_RegionalID'], $userID, $TGoodsTFDetailID);

                    $sqlUpdateFlag = "UPDATE purchase_request_flag 
                    SET PurchaseRequestFlagQtyRest = ?,
                        PurchaseRequestFlagQtyProses = PurchaseRequestFlagQtyProses + ?
                    WHERE PurchaseRequestFlagID = ? 
                        AND PurchaseRequestFlagIsActive = 'Y'";
                    $qflag = $this->db->query($sqlUpdateFlag, [$QtyTfRes, $QtyTfRes, $flagID]);
                    if (!$qflag) {
                        throw new Exception("[Error] Failed updating purchase request flag quantities. " . json_encode($this->db->error()));
                    }
                }
            }

            // get last inserted data
            $sqltfgood = "SELECT * FROM t_goods_transfer WHERE T_GoodsTransferIsActive = 'Y' AND T_GoodsTransferID = ?";
            $quetfgood = $this->db->query($sqltfgood, [$TGoodsTrfID]);
            if (!$quetfgood) {
                throw new Exception("[Error] Failed to get last data inserted. " . json_encode($this->db->error()));
            }
            $lastTFData = $quetfgood->row_array();

            $sqltfdetail = "SELECT * FROM t_goods_transfer_detail WHERE T_GoodsTransferDetailIsActive = 'Y' AND T_GoodsTransferDetailIDT_GoodsTransferID = ?";
            $quetfdetail = $this->db->query($sqltfdetail, [$TGoodsTrfID]);
            if (!$quetfdetail) {
                throw new Exception("[Error] Failed to get last data detail inserted. " . json_encode($this->db->error()));
            }
            $lastTFDetail = $quetfdetail->result_array();
            $lastTFData['detail'] = $lastTFDetail;

            // insert log user activity
            $msg = "Transfer Request nomor: {$lastTFData['T_GoodsTransferNum']}, tanggal: {$lastTFData['T_GoodsTransferDate']}, type: {$lastTFData['T_GoodsTransferType']}";
            $this->insertUserActivty($TGoodsTrfID, "CREATE", $userID, $msg, json_encode($lastTFData));

            $this->db->trans_commit();

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

    public function updateTfRequest()
    {
        try {
            if (!$this->isLogin) {
                throw new Exception("Invalid Token");
            }
            $user = $this->sys_user;
            $userID = $this->sys_user["M_UserID"];
            $data = $this->sys_input;

            // print_r($data['actverif']);
            // print_r($data['editqty']);
            // print_r(json_encode($data['detail']));
            // exit;

            $this->db->trans_begin();

            // update table header t_goods_transfer
            $sqlTrf = "UPDATE t_goods_transfer SET 
                T_GoodsTransferFromS_RegionalID = ?,
                T_GoodsTransferToM_BranchCode = ?,
                T_GoodsTransferDivisionID = ?,
                T_GoodsTransferNum = ?,
                T_GoodsTransferNotes = ?,
                T_GoodsTransferDate = ?,
                T_GoodsTransferStatus = ?,
                T_GoodsTransferLastUpdated = NOW(),
                T_GoodsTransferM_UserID = ?
            WHERE T_GoodsTransferID = ? 
                AND T_GoodsTransferIsActive = 'Y'";
            $queTrf = $this->db->query($sqlTrf, [
                $data["S_RegionalID"],
                $data["M_BranchCode"],
                $data["DivisionID"],
                $data["GoodsTfNum"],
                $data["GoodsTfNotes"],
                $data["GoodsTfDate"],
                $data["GoodsTfStatus"],
                $userID,
                $data["GoodsTfID"]
            ]);
            if (!$queTrf) {
                throw new Exception("[Error] Failed to update table t_goods_transfer. " . json_encode($this->db->error()));
            }

            // approve or verif tf request
            if (($data["GoodsTfStatus"] == 'Verified' && $data['actverif'] == 'V') || $data["GoodsTfStatus"] == 'Approved') {
                $this->toVerifOrApprove($data["GoodsTfID"], $user);
            }

            // update detail t_goods status to N
            $sqlTFdtltoN = "UPDATE t_goods_transfer_detail SET T_GoodsTransferDetailIsActive = 'N' WHERE T_GoodsTransferDetailIDT_GoodsTransferID = ?";
            $qeuTFdtltoN = $this->db->query($sqlTFdtltoN, [$data["GoodsTfID"]]);
            if (!$qeuTFdtltoN) {
                throw new Exception("[Error] Failed to update all detail to N. " . json_encode($this->db->error()));
            }

            // update detail table t_goods_transfer_detail
            $datadetail = $data['detail'];
            foreach ($datadetail as $key => $value) {
                $flagID = $value['PurchaseRequestFlagID'];
                $itemID = $value['PurchaseRequestDetailM_ItemID'];
                $unitID = $value['PurchaseRequestDetailItemUnitID'];
                $QtyStart = intval($value['PurchaseRequestFlagQty']);
                $QtyTfRes = intval($value['PurchaseRequestFlagQtyRest']);

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

                $sqlTfDtl = "INSERT INTO t_goods_transfer_detail (
                    T_GoodsTransferDetailIDT_GoodsTransferID,
                    T_GoodsTransferDetailT_PurchaseRequestFlagID,
                    T_GoodsTransferDetailM_ItemID,
                    T_GoodsTransferDetailItemUnitID,
                    T_GoodsTransferDetailItemBarNote,
                    T_GoodsTransferDetailQty,
                    T_GoodsTransferDetailQtyTF,
                    T_GoodsTransferDetailCreatedAt,
                    T_GoodsTransferDetailM_UserID 
                ) VALUES (?,?,?,?,?,?,?,NOW(),?)";
                $queTfDtl = $this->db->query($sqlTfDtl, [
                    $data["GoodsTfID"],
                    $flagID,
                    $itemID,
                    $unitID,
                    $jsonBarnote,
                    $QtyStart,
                    $QtyTfRes,
                    $userID
                ]);
                if (!$queTfDtl) {
                    throw new Exception("[Error] Failed to insert detail tf data into t_goods_transfer_detail. " . json_encode($this->db->error()));
                }
                $TGoodsTFDetailID = $this->db->insert_id();
                $datadetail[$key]['TGoodsTFDetailID'] = $TGoodsTFDetailID;

                // update flag jika status verified
                if ($data['GoodsTfStatus'] == 'Verified' && $data['actverif'] == 'V') {

                    $this->moveStockToTransit($value, $data['S_RegionalID'], $userID, $TGoodsTFDetailID);

                    $sqlUpdateFlag = "UPDATE purchase_request_flag 
                                    SET PurchaseRequestFlagQtyRest = ?,
                                        PurchaseRequestFlagQtyProses = PurchaseRequestFlagQtyProses + ?
                                    WHERE PurchaseRequestFlagID = ? 
                                        AND PurchaseRequestFlagIsActive = 'Y'";
                    $qflag = $this->db->query($sqlUpdateFlag, [$QtyTfRes, $QtyTfRes, $flagID]);
                    if (!$qflag) {
                        throw new Exception("[Error] Failed updating purchase request flag quantities. " . json_encode($this->db->error()));
                    }
                }
            }

            // get last inserted data
            $sqltfgood = "SELECT * FROM t_goods_transfer WHERE T_GoodsTransferIsActive = 'Y' AND T_GoodsTransferID = ?";
            $quetfgood = $this->db->query($sqltfgood, [$data["GoodsTfID"]]);
            if (!$quetfgood) {
                throw new Exception("[Error] Failed to get last data inserted. " . json_encode($this->db->error()));
            }
            $lastTFData = $quetfgood->row_array();

            $sqltfdetail = "SELECT * FROM t_goods_transfer_detail WHERE T_GoodsTransferDetailIsActive = 'Y' AND T_GoodsTransferDetailIDT_GoodsTransferID = ?";
            $quetfdetail = $this->db->query($sqltfdetail, [$data["GoodsTfID"]]);
            if (!$quetfdetail) {
                throw new Exception("[Error] Failed to get last data detail inserted. " . json_encode($this->db->error()));
            }
            $lastTFDetail = $quetfdetail->result_array();
            $lastTFData['detail'] = $lastTFDetail;

            // insert log user activity
            $msg = "Transfer Request nomor: {$lastTFData['T_GoodsTransferNum']}, tanggal: {$lastTFData['T_GoodsTransferDate']}, type: {$lastTFData['T_GoodsTransferType']}";
            $this->insertUserActivty($data["GoodsTfID"], "UPDATE", $userID, $msg, json_encode($lastTFData));

            $this->db->trans_commit();

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

    /**
     *  Pindah Stock ke WH Transit jika Verified 
     * @param array $detailTf - The detail of the transfer with ItemRequest info
     * @param int $regionalID - The regional ID to find the appropriate transit warehouse
     * @param int $userID - The user ID performing the operation
     * @param int $TGoodsTFDetailID - The ID of the transfer detail
     * @return void
     * @throws Exception if any validation or database operation fails
     */
    private function moveStockToTransit($detailTf, $regionalID, $userID, $TGoodsTFDetailID)
    {
        //* Validasi StockQty bisa memenuhi
        foreach ($detailTf['ItemRequest'] as $itemRequest) {
            $stockID    = $itemRequest['StockID'];
            $qtyReq     = intval($itemRequest['QtyReq']);

            $sqlCheck   = "SELECT StockQty FROM stock WHERE StockID = ?";
            $qryCheck   = $this->db->query($sqlCheck, [$stockID]);

            if (!$qryCheck || $qryCheck->num_rows() === 0) {
                $err = json_encode($this->db->error());
                throw new Exception($err);
            }

            if ($qryCheck->row()->StockQty < $qtyReq) {
                $sqlItem    = "SELECT M_ItemDesc, ItemUnitName 
                        FROM stock 
                        JOIN m_item ON M_ItemID = StockItemID 
                        JOIN itemunit ON ItemUnitID = StockItemUnitID 
                        WHERE StockID = ?";
                $qryItem    = $this->db->query($sqlItem, [$stockID]);
                $itemInfo   = $qryItem->row_array();

                throw new Exception("Err: Perhatikan Qty Stock dan Request. Tidak bisa verifikasi karena Stock Item {$itemInfo['M_ItemDesc']} 
                tersisa " . ($qryCheck ? $qryCheck->row()->StockQty : 0) . " {$itemInfo['ItemUnitName']}, 
                sedangkan request {$qtyReq} {$itemInfo['ItemUnitName']}");
            }
        }

        //* Query Warehouse Transit where WHRegionalID == $data[S_RegionalID]
        $sqlWh = "SELECT WarehouseID FROM warehouse WHERE WarehouseS_RegionalID = ? 
                AND WarehouseIsTransit = 'Y' AND WarehouseIsActive = 'Y' 
                AND WarehouseType = 'R' ORDER BY WarehouseID DESC LIMIT 1";
        $qryWh = $this->db->query($sqlWh, [$regionalID]);
        if (!$qryWh || $qryWh->num_rows() === 0) {
            throw new Exception("Transit warehouse not found for Regional ID: {$regionalID}");
        }
        $transitWhId = $qryWh->row()->WarehouseID;

        foreach ($detailTf['ItemRequest'] as $itemReq) {
            $stockID        = $itemReq['StockID'];
            $qtyReq         = intval($itemReq['QtyReq']);
            $stockNumber    = $itemReq['StockStockNumber'];
            $batchNo        = $itemReq['StockBatchNo'] ?? '';
            $itemID         = $itemReq['StockItemID'];
            $unitID         = $itemReq['StockItemUnitID'];
            $itemPrice      = $itemReq['StockItemPrice'];
            $expDate        = $itemReq['StockED'];
            $warehouseID    = $itemReq['WarehouseID'];

            //* Update Kurangi Existing Stock Qty
            $sqlUpdt = "UPDATE stock SET StockQty = StockQty - ?, 
                        StockLastUpdated = NOW(), StockUserID = ?
                        WHERE StockID = ?";
            $qryUpdt = $this->db->query($sqlUpdt, [$qtyReq, $userID, $stockID]);
            if (!$qryUpdt) {
                throw new Exception("Failed to update source stock quantity (ID: {$stockID})");
            }

            //* Create / Update Transit Stock
            $sqlCekTransit = "SELECT StockID FROM stock 
                        WHERE StockWarehouseID = ? 
                        AND StockItemID = ?  AND StockItemUnitID = ? ORDER BY StockID DESC LIMIT 1";
            $qryCekTransit = $this->db->query($sqlCekTransit, [
                $transitWhId,
                $itemID,
                $unitID
            ]);
            if (!$qryCekTransit) {
                $err = json_encode($this->db->error());
                throw new Exception("Failed to cek stock on warehouseId (ID: {$transitWhId}). DB Error: $err");
            }

            if ($qryCekTransit->num_rows() > 0) {
                $transitStockID = $qryCekTransit->row()->StockID;

                $sqlUpdTransit  = "UPDATE stock SET StockQty = StockQty + ?,
                        StockLastUpdated = NOW(), StockUserID = ?
                        WHERE StockID = ?";
                $qryUpdTransit  = $this->db->query($sqlUpdTransit, [
                    $qtyReq,
                    $userID,
                    $transitStockID
                ]);
                if (!$qryUpdTransit) {
                    throw new Exception("Failed to update transit stock quantity (ID: {$transitStockID})");
                }
            } else {
                $sqlInsTransit = "INSERT INTO stock (
                StockWarehouseID, StockItemID, StockItemUnitID, 
                StockBatchNo, StockQty, StockStockNumber, 
                StockItemPrice, StockED, 
                StockLastUpdated, StockUserID
            ) VALUES (?, ?, ?, ?, ?, fn_numbering('SN'), ?, ?, NOW(), ?)";
                $qryInsTransit = $this->db->query($sqlInsTransit, [
                    $transitWhId,
                    $itemID,
                    $unitID,
                    $batchNo,
                    $qtyReq,
                    $itemPrice,
                    $expDate,
                    $userID
                ]);
                if (!$qryInsTransit) {
                    throw new Exception("Failed to insert new transit stock for Item ID: {$itemID}");
                }

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

            //* Log Stock Movement (WTT - Warehouse To Transit)
            // Log hanya dari sumber ke transit
            $sqlLog = "INSERT INTO stocklog (
                    StockLogWarehouseID, StockLogDateTime, StockLogItemID,
                    StockLogItemUnitID, StockLogStockNumber, StockLogBatchNo,
                    StockLogED, StockLogReffID, StockLogStatus, StockLogQty, StockLogUserID)
                    VALUES (?, NOW(), ?, ?, ?, ?, ?, ?, 'WTT', ?, ?)";
            $qryLog = $this->db->query($sqlLog, [
                $warehouseID,
                $itemID,
                $unitID,
                $stockNumber,
                $batchNo,
                $expDate,
                $TGoodsTFDetailID,
                $qtyReq,
                $userID
            ]);
            if (!$qryLog) {
                throw new Exception("Failed to log source warehouse movement");
            }

            // * Query Stockcard where StockCardReffID == $stockID ORDER BY StockCardID DESC LIMIT 1
            // * Insert Stockcard WH Sumber ke Transit (OUT)
            // StockCardBefore = Previous StockCardAfter, StockCardIn=0, StockCardOut= qtyReg, StockCardAfter = PreviousCardAfter - qtyReq
            $sqlLastSourceCard = "SELECT StockCardAfter FROM stockcard 
                    WHERE StockCardReffID = ? ORDER BY StockCardID DESC LIMIT 1";
            $qryLastSourceCard = $this->db->query($sqlLastSourceCard, [$stockID]);
            if (!$qryLastSourceCard) {
                throw new Exception("Failed to query last stockcard entry for source stock ID: {$stockID}");
            }

            $beforeQty = 0;
            if ($qryLastSourceCard->num_rows() > 0) {
                $beforeQty = $qryLastSourceCard->row()->StockCardAfter;
            } else {
                $beforeQty = $lastSourceStockQty;
            }

            $afterQty = $beforeQty - $qtyReq;

            // Insert Stockcard for source warehouse (OUT)
            $sqlInsSourceCard = "INSERT INTO stockcard (
                StockCardWarehouseID, StockCardDatetime, StockCardItemID, 
                StockCardItemUnitID, StockCardBatchNo, StockCardED, 
                StockCardReffID, StockCardStatus, 
                StockCardBefore, StockCardIn, StockCardOut, StockCardAfter, 
                StockCardUserID
            ) VALUES (?, NOW(), ?, ?, ?, ?, ?, 'MWT', ?, 0, ?, ?, ?)";

            $qryInsSourceCard = $this->db->query($sqlInsSourceCard, [
                $warehouseID,
                $itemID,
                $unitID,
                $batchNo,
                $expDate,
                $stockID,
                $beforeQty,
                $qtyReq,
                $afterQty,
                $userID
            ]);

            if (!$qryInsSourceCard) {
                throw new Exception("Failed to insert stockcard for source warehouse ID: {$warehouseID}");
            }

            // * Query Stockcard where StockCardReffID == $transitStockID ORDER BY StockCardID DESC LIMIT 1
            // * Insert Stockcard WH Transit (IN)
            // New row with StockReffID = $transitStockID, StockCardIn = qtyReq, StockCardOut = 0, StockCardAfter = PreviousCardAfter + qtyReq
            $sqlLastTransitCard = "SELECT StockCardAfter FROM stockcard 
                    WHERE StockCardReffID = ? ORDER BY StockCardID DESC LIMIT 1";
            $qryLastTransitCard = $this->db->query($sqlLastTransitCard, [$transitStockID]);
            if (!$qryLastTransitCard) {
                throw new Exception("Failed to query last stockcard entry for transit stock ID: {$transitStockID}");
            }

            $transitBeforeQty = 0;
            if ($qryLastTransitCard->num_rows() > 0) {
                $transitBeforeQty = $qryLastTransitCard->row()->StockCardAfter;
            } else {
                $sqlTransitQty = "SELECT StockQty FROM stock WHERE StockID = ?";
                $qryTransitQty = $this->db->query($sqlTransitQty, [$transitStockID]);
                if (!$qryTransitQty || $qryTransitQty->num_rows() === 0) {
                    throw new Exception("Failed to get current stock quantity for transit stock ID: {$transitStockID}");
                }
                $transitBeforeQty = $qryTransitQty->row()->StockQty - $qtyReq; // Subtract qtyReq since we've already added it
            }

            $transitAfterQty = $transitBeforeQty + $qtyReq;

            // Insert Stockcard for transit warehouse (IN)
            $sqlInsTransitCard = "INSERT INTO stockcard (
                StockCardWarehouseID, StockCardDatetime, StockCardItemID, 
                StockCardItemUnitID, StockCardBatchNo, StockCardED, 
                StockCardReffID, StockCardStatus, 
                StockCardBefore, StockCardIn, StockCardOut, StockCardAfter, StockCardUserID
            ) VALUES (?, NOW(), ?, ?, ?, ?, ?, 'MWF', ?, ?, 0, ?, ?)";

            $qryInsTransitCard = $this->db->query($sqlInsTransitCard, [
                $transitWhId,
                $itemID,
                $unitID,
                $batchNo,
                $expDate,
                $transitStockID,
                $transitBeforeQty,
                $qtyReq,
                $transitAfterQty,
                $userID
            ]);

            if (!$qryInsTransitCard) {
                throw new Exception("Failed to insert stockcard for transit warehouse ID: {$transitWhId}");
            }
        }

        // Return true to indicate success
        return true;
    }

    public function deleteTfRequest()
    {
        try {
            if (!$this->isLogin) {
                $this->sys_error("Invalid Token");
            }
            $userID = $this->sys_user["M_UserID"];
            $goodsTfID = $this->sys_input["GoodsTfID"];

            $this->db->trans_begin();

            // update tf header status
            $sqlTrf = "UPDATE t_goods_transfer SET 
                T_GoodsTransferIsActive = 'N',
                T_GoodsTransferDeleted = NOW(),
                T_GoodsTransferM_UserID = ?
            WHERE T_GoodsTransferID = ? AND T_GoodsTransferIsActive = 'Y'";
            $queTrf = $this->db->query($sqlTrf, [$userID, $goodsTfID]);
            if (!$queTrf) {
                $this->db->trans_rollback();
                $this->sys_error_db("[Error] update TF status to N");
                exit;
            }

            // update tf detail status
            $sqlTrfDtl = "UPDATE t_goods_transfer_detail SET 
                T_GoodsTransferDetailIsActive = 'N',
                T_GoodsTransferDetailDeletedAt = NOW(),
                T_GoodsTransferDetailM_UserID = ? 
            WHERE T_GoodsTransferDetailIDT_GoodsTransferID = ? AND T_GoodsTransferDetailIsActive = 'Y'";
            $queTrfDtl = $this->db->query($sqlTrfDtl, [$userID, $goodsTfID]);
            if (!$queTrfDtl) {
                $this->db->trans_rollback();
                $this->sys_error_db("[Error] update status TF detail to N");
                exit;
            }

            // get last inserted data
            $sqltfgood = "SELECT * FROM t_goods_transfer WHERE T_GoodsTransferIsActive = 'Y' AND T_GoodsTransferID = ?";
            $quetfgood = $this->db->query($sqltfgood, [$goodsTfID]);
            if (!$quetfgood) {
                $this->db->trans_rollback();
                $this->sys_error_db("[Error] get last data inserted");
                exit;
            }
            $lastTFData = $quetfgood->row_array();

            // insert log user activity
            $msg = "Transfer Request nomor: {$lastTFData['T_GoodsTransferNum']}, tanggal: {$lastTFData['T_GoodsTransferDate']}, type: {$lastTFData['T_GoodsTransferType']}";
            $this->insertUserActivty($goodsTfID, "DELETE", $userID, $msg, json_encode($lastTFData));

            $this->db->trans_commit();
            $this->sys_ok("[Success] Delete TF Request number: {$lastTFData['T_GoodsTransferNum']}");
        } catch (Exception $exc) {
            $message = $exc->getMessage();
            $this->sys_error($message);
        }
    }

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

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

        $this->sys_ok($data);
    }

    function insertUserActivty($tfid, $type, $userid, $desc = '', $data = '')
    {
        $sql = "INSERT INTO user_activity (
            UserActivityCode,
            UserActivityStatus,
            UserActivityDescription,
            UserActivityRefID,
            UserActivityData,
            UserActivityUserID,
            UserActivityCreated
        ) VALUES (?,?,?,?,?,?,NOW())";
        $que = $this->db->query($sql, ['TR', $type, $desc, $tfid, $data, $userid]);
        if (!$que) {
            $this->db->trans_rollback();
            $this->sys_error_db("[Error] insert into table user activity");
            exit;
        }
    }

    function toVerifOrApprove($id, $user)
    {
        $sqlevl = "SELECT * FROM m_user WHERE M_UserIsActive = 'Y' AND M_UserID = ?";
        $quelvl = $this->db->query($sqlevl, [$user['M_UserID']]);
        if (!$quelvl) {
            $this->db->trans_rollback();
            $this->sys_error_db("[Error] get user level");
            exit;
        }

        $level = $quelvl->row_array()['M_UserM_ApproveLevelID'];

        if ($level == '1') {
            $sql = "UPDATE t_goods_transfer SET
                T_GoodsTransferVerifiedBy = ?,
                T_GoodsTransferVerifiedDate = NOW(),
                T_GoodsTransferLastUpdated = NOW()
            WHERE T_GoodsTransferID = ? 
                AND T_GoodsTransferIsActive = 'Y'";

            $que = $this->db->query($sql, [$user['M_UserID'], $id]);
            if (!$que) {
                $this->db->trans_rollback();
                $this->sys_error_db("[Error] update verified by manager");
                exit;
            }
        } elseif ($level == '2') {
            $sql = "UPDATE t_goods_transfer SET
                T_GoodsTransferApprovedBy = ?,
                T_GoodsTransferApprovedDate = NOW(),
                T_GoodsTransferLastUpdated = NOW()
            WHERE T_GoodsTransferID = ? 
                AND T_GoodsTransferIsActive = 'Y'";

            $que = $this->db->query($sql, [$user['M_UserID'], $id]);
            if (!$que) {
                $this->db->trans_rollback();
                $this->sys_error_db("[Error] update approve kareg");
                exit;
            }
        }
    }
}
