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; } } } }