db->query("select database() as current_db")->result(); // print_r($cek); } public function __construct() { parent::__construct(); } public function search() { if (! $this->isLogin) { $this->sys_error("Invalid Token"); exit; } $prm = $this->sys_input; $search = '%' . $prm['search'] . '%'; $startDate = $prm['startDate']; $endDate = $prm['endDate']; $status = $prm['status']; $page = $prm['page']; $flag = $prm['flag']; $user = $this->sys_user; $regionalID = $user['S_RegionalID']; $branchCode = $user['M_BranchCode']; $loginType = $user['M_UserLocationFlag']; $userID = $user['M_UserID']; $approveLevelID = $user['M_UserM_ApproveLevelID']; $sqlBranch = ''; if ($loginType == 'B' || $loginType == 'RB') { $sqlBranch = "AND PurchaseRequestM_BranchCode = '{$branchCode}'"; } $sqlStatus = ''; if ($status != 'All') { $sqlStatus = "AND PurchaseRequestStatus = '{$status}'"; } $number_limit = 20; $number_offset = 0; if ($page > 0) { $number_offset = ($prm['page'] - 1) * $number_limit; } if ($approveLevelID == '1') { if ($flag == 'G') { $sqlStockRequest = " AND (PurchaseRequestVerifiedBy = 0 OR PurchaseRequestVerifiedBy IS NULL) "; } } else if ($approveLevelID == '2') { if ($flag == 'G') { $sqlStockRequest = " AND PurchaseRequestApprovedBy IS NULL"; } } $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; } $totalStart = $approvalLevel[0]['M_ApproveLevelStartTotal']; $totalEnd = $approvalLevel[0]['M_ApproveLevelEndTotal']; $sql = "SELECT COUNT(PurchaseRequestID) total FROM purchase_request JOIN s_regional ON PurchaseRequestS_RegionalID = S_RegionalID AND S_RegionalIsActive = 'Y' JOIN item_category ON PurchaseRequestItemCategoryID = ItemCategoryID AND ItemCategoryIsActive = 'Y' JOIN m_user b ON PurchaseRequestRequestedBy = b.M_UserID AND b.M_UserIsActive = 'Y' AND S_RegionalIsActive = 'Y' LEFT JOIN m_user a ON PurchaseRequestApprovedBy = a.M_UserID AND a.M_UserIsActive = 'Y' LEFT JOIN m_branch ON PurchaseRequestM_BranchCode = M_BranchCode WHERE PurchaseRequestIsActive = 'Y' AND PurchaseRequestItemCategoryID = 1 AND (PurchaseRequestNumber LIKE ? OR PurchaseRequestRefNumber LIKE ? OR PurchaseRequestRequestedBy LIKE ?) AND (PurchaseRequestDate BETWEEN ? AND ?) AND PurchaseRequestS_RegionalID = ? $sqlStockRequest $sqlBranch $sqlStatus"; $qry = $this->db->query($sql, [$search, $search, $search, $startDate, $endDate, $regionalID]); if (!$qry) { $this->sys_error_db("Error searching"); exit; } $total = $qry->row_array()['total']; $tot_page = ceil($total / $number_limit); $params = [$search, $search, $search, $startDate, $endDate, $regionalID]; $params[] = $number_limit; $params[] = $number_offset; $sql = "SELECT PurchaseRequestID prID, DATE_FORMAT(PurchaseRequestDate, '%d-%m-%Y') prDate, PurchaseRequestNumber prNumber, PurchaseRequestRefNumber prRefNumber, PurchaseRequestNote prNote, PurchaseRequestTotal prTotal, PurchaseRequestItemCategoryID prItemType, ItemCategoryName prItemTypeName, PurchaseRequestStatus prStatus, IFNULL(PurchaseRequestVerifiedBy, 0) AS PurchaseRequestVerifiedBy, DATE_FORMAT(PurchaseRequestApprovedDate, '%d-%m-%Y %H:%i') prApprovedDate, a.M_userUserName prApprovedBy, b.M_UserID prRequestedByID, b.M_userUserName prRequestedBy, b.M_UserM_BranchID prRequestedByFromBranch, S_RegionalName prRegionalName, M_BranchName prBranchName, IFNULL(`fn_getitemnamebyprid`(PurchaseRequestID), '') prItemName FROM purchase_request JOIN s_regional ON PurchaseRequestS_RegionalID = S_RegionalID AND S_RegionalIsActive = 'Y' JOIN item_category ON PurchaseRequestItemCategoryID = ItemCategoryID AND ItemCategoryIsActive = 'Y' JOIN m_user b ON PurchaseRequestRequestedBy = b.M_UserID AND b.M_UserIsActive = 'Y' LEFT JOIN m_user a ON PurchaseRequestApprovedBy = a.M_UserID AND a.M_UserIsActive = 'Y' LEFT JOIN m_branch ON PurchaseRequestM_BranchCode = M_BranchCode WHERE PurchaseRequestIsActive = 'Y' AND PurchaseRequestItemCategoryID = 1 AND (PurchaseRequestNumber LIKE ? OR PurchaseRequestRefNumber LIKE ? OR PurchaseRequestRequestedBy LIKE ?) AND (PurchaseRequestDate BETWEEN ? AND ?) AND PurchaseRequestS_RegionalID = ? $sqlStockRequest $sqlBranch $sqlStatus ORDER BY prDate,prNumber DESC LIMIT ? OFFSET ? "; $qry = $this->db->query($sql, $params); if (!$qry) { $this->sys_error_db("Error searching"); exit; } //echo $this->db->last_query(); //exit; $data = $qry->result_array(); $result = array( 'total' => $tot_page, 'records' => $data, // "qry" => $this->db->last_query() ); $this->sys_ok($result); } function getDetail() { if (! $this->isLogin) { $this->sys_error("Invalid Token"); exit; } $prm = $this->sys_input; $id = $prm['id']; $sql = "SELECT PurchaseRequestID as prDetailPrID, PurchaseRequestDetailID as prDetailID, PurchaseRequestDetailM_ItemID as prDetailItemID, M_ItemDesc as prDetailItemName, M_ItemCode as prDetailItemCode, PurchaseRequestDetailQty as prDetailItemQty, PurchaseRequestDetailPrice as prDetailItemPrice, PurchaseRequestDetailItemUnitID, ItemUnitName as prDetailItemUnitName, SUM(StockQty) AS CurrentStockQty FROM purchase_request JOIN purchase_request_detail ON PurchaseRequestDetailPurchaseRequestID = PurchaseRequestID AND PurchaseRequestDetailIsActive = 'Y' JOIN m_item ON M_ItemID = PurchaseRequestDetailM_ItemID JOIN itemunit ON ItemUnitID = PurchaseRequestDetailItemUnitID LEFT JOIN m_branch ON M_BranchCode = PurchaseRequestM_BranchCode JOIN warehouse ON WarehouseS_RegionalID = PurchaseRequestS_RegionalID AND WarehouseM_BranchID = COALESCE(M_BranchID, 0) AND WarehouseIsTransit = 'N' LEFT JOIN stock ON StockWarehouseID = WarehouseID AND StockItemID = PurchaseRequestDetailM_ItemID AND StockItemUnitID = PurchaseRequestDetailItemUnitID WHERE PurchaseRequestID = ? GROUP BY PurchaseRequestDetailID, PurchaseRequestDetailM_ItemID, PurchaseRequestDetailItemUnitID, M_ItemDesc, M_ItemCode, ItemUnitName"; $qry = $this->db->query($sql, [$id]); if (!$qry) { $this->sys_error_db("Error get detail"); exit; } $data = $qry->result_array(); $this->sys_ok($data); } function approve() { $this->db->trans_begin(); // $this->db->trans_rollback(); // $this->db->trans_commit(); if (! $this->isLogin) { $this->sys_error("Invalid Token"); exit; } $prm = $this->sys_input; $detail = $prm['detail']; $user = $this->sys_user; $userid = $user["M_UserID"]; $pr = $prm['pr']; $total = $prm['total']; $type = $prm['type']; // get user level approval $sqlevel = "SELECT M_UserM_ApproveLevelID FROM m_user WHERE M_UserIsActive = 'Y' AND M_UserID = ?"; $qulevel = $this->db->query($sqlevel, [$userid]); if (!$qulevel) { $this->sys_error_db("[Error] get approval level user"); exit; } $userlevel = $qulevel->row_array()['M_UserM_ApproveLevelID']; $datas_log = array(); $sql = "SELECT * FROM purchase_request WHERE PurchaseRequestID = ? AND PurchaseRequestIsActive = 'Y'"; $query = $this->db->query($sql, [$pr['prID']]); if (!$query) { $this->db->trans_rollback(); $this->sys_error_db("purchase request select", $this->db); exit; } $header = $query->row_array(); $datas_log['header'] = $header; $sql = "SELECT * FROM purchase_request_detail JOIN m_item ON M_ItemID = PurchaseRequestDetailM_ItemID AND M_ItemIsActive = 'Y' JOIN itemunit ON ItemUnitID = PurchaseRequestDetailItemUnitID AND ItemUnitIsActive = 'Y' WHERE PurchaseRequestDetailPurchaseRequestID = ? AND PurchaseRequestDetailIsActive = 'Y'"; $query = $this->db->query($sql, [$pr['prID']]); if (!$query) { $this->db->trans_rollback(); $this->sys_error_db("purchase request detail select", $this->db); exit; } $details = $query->result_array(); $datas_log['details'] = $details; if ($type == 'A') { // verifikasi jika manager if ($userlevel == '1') { $sql = "UPDATE purchase_request SET PurchaseRequestVerifiedBy = ?, PurchaseRequestVerifiedDate = NOW() WHERE PurchaseRequestID = ? AND PurchaseRequestStatus = 'Pending'"; $qry = $this->db->query($sql, [$userid, $pr['prID']]); if (!$qry) { $this->sys_error_db("Error verifikasi manager"); $this->db->trans_rollback(); exit; } $messages = "Purchase Request dengan kode " . $header['PurchaseRequestNumber'] . " telah di verifikasi"; $this->insert_act_log("PRP", "Verified", $messages, $pr['prID'], $this->safeJsonEncode($datas_log), $userid); } // approve jika kepala cabang / regional if ($userlevel == '2') { // -- PurchaseRequestTotal = ?, $sql = "UPDATE purchase_request SET PurchaseRequestStatus = ?, PurchaseRequestApprovedDate = NOW(), PurchaseRequestApprovedBy = ? WHERE PurchaseRequestID = ? AND PurchaseRequestStatus = 'Pending'"; $qry = $this->db->query($sql, ['Approved', $userid, $pr['prID']]); if (!$qry) { $this->sys_error_db("Error Approve"); $this->db->trans_rollback(); exit; } $sql = "UPDATE purchase_request_detail SET PurchaseRequestDetailStatus = ? WHERE PurchaseRequestDetailPurchaseRequestID = ?"; $qry = $this->db->query($sql, ['Approved', $pr['prID']]); if (!$qry) { $this->sys_error_db("Error update detail"); $this->db->trans_rollback(); exit; } $messages = "Purchase Request dengan kode " . $header['PurchaseRequestNumber'] . " telah di approved"; $this->insert_act_log("PRP", "Approved", $messages, $pr['prID'], $this->safeJsonEncode($datas_log), $userid); } } else if ($type == 'R') { $sql = "UPDATE purchase_request SET PurchaseRequestStatus = ?, PurchaseRequestApprovedDate = NOW(), PurchaseRequestApprovedBy = ? WHERE PurchaseRequestID = ? AND PurchaseRequestStatus = 'Pending'"; $qry = $this->db->query($sql, ['Rejected', $userid, $pr['prID']]); if (!$qry) { $this->sys_error_db("Error Approve"); $this->db->trans_rollback(); exit; } $sql = "UPDATE purchase_request_detail SET PurchaseRequestDetailStatus = ? WHERE PurchaseRequestDetailPurchaseRequestID = ?"; $qry = $this->db->query($sql, ['Rejected', $pr['prID']]); if (!$qry) { $this->sys_error_db("Error update detail"); $this->db->trans_rollback(); exit; } $messages = "Purchase Request dengan kode " . $header['PurchaseRequestNumber'] . " telah di reject"; $this->insert_act_log("PRP", "Rejected", $messages, $pr['prID'], $this->safeJsonEncode($datas_log), $userid); } else if ($type == 'U') { // un approve jika kepala cabang / regional if ($userlevel == '2') { // -- PurchaseRequestTotal = ?, $sql = "UPDATE purchase_request SET PurchaseRequestStatus = ?, PurchaseRequestApprovedDate = NULL, PurchaseRequestApprovedBy = NULL WHERE PurchaseRequestID = ? AND PurchaseRequestStatus = 'Approved'"; $qry = $this->db->query($sql, ['Pending', $userid, $pr['prID']]); if (!$qry) { $this->sys_error_db("Error Approve"); $this->db->trans_rollback(); exit; } $sql = "UPDATE purchase_request_detail SET PurchaseRequestDetailStatus = ? WHERE PurchaseRequestDetailPurchaseRequestID = ?"; $qry = $this->db->query($sql, ['Pending', $pr['prID']]); if (!$qry) { $this->sys_error_db("Error update detail"); $this->db->trans_rollback(); exit; } $messages = "Purchase Request dengan kode " . $header['PurchaseRequestNumber'] . " telah di unapproved"; $this->insert_act_log("PRP", "Unapproved", $messages, $pr['prID'], $this->safeJsonEncode($datas_log), $userid); } } // update notification $this->readNotif($type, $userlevel, $userid, $pr['prID']); $this->db->trans_commit(); $this->sys_ok('Berhasil'); } // read notification function readNotif($type, $userlevel, $userId, $refID) { $this->db->trans_begin(); // cari user penerima notifikasi if ($type == "U") { $sql_get = "SELECT PurchaseRequestID, M_UserID, M_UserUsername, NotificationID, NotificationDetailID, NotificationDetailStatus, NotificationDetailM_UserID, NotificationDetailM_ApproveLevelID FROM notification JOIN purchase_request ON NotificationRefID = PurchaseRequestID AND PurchaseRequestIsActive = 'Y' JOIN notification_detail ON NotificationID = NotificationDetailNotificationID JOIN m_user ON NotificationUserID = M_UserID WHERE PurchaseRequestID = ? AND NotificationDetailStatus = 'read'"; $qry = $this->db->query($sql_get, [$refID]); if (!$qry) { $this->sys_error_db("select user notification error", $this->db); exit; } $rowsuser = $qry->result_array(); } else { $sql_get = "SELECT PurchaseRequestID, M_UserID, M_UserUsername, NotificationID, NotificationDetailID, NotificationDetailStatus, NotificationDetailM_UserID, NotificationDetailM_ApproveLevelID FROM notification JOIN purchase_request ON NotificationRefID = PurchaseRequestID AND PurchaseRequestIsActive = 'Y' JOIN notification_detail ON NotificationID = NotificationDetailNotificationID JOIN m_user ON NotificationUserID = M_UserID WHERE PurchaseRequestID = ? AND NotificationDetailStatus = 'unread'"; $qry = $this->db->query($sql_get, [$refID]); if (!$qry) { $this->sys_error_db("select user notification error", $this->db); exit; } $rowsuser = $qry->result_array(); } foreach ($rowsuser as $user) { if ($type == "A") { if ($userlevel === '1') { // verifikasi manager $sql = "UPDATE notification_detail SET NotificationDetailStatus = 'read', NotificationDetailLastUpdated = NOW(), NotificationDetailUserID = ? WHERE NotificationDetailNotificationID = ? AND NotificationDetailM_ApproveLevelID = ?"; $qry = $this->db->query($sql, [$userId, $user["NotificationID"], $user["NotificationDetailM_ApproveLevelID"]]); if (!$qry) { $this->sys_error_db("update notification error", $this->db); exit; } } else if ($userlevel === '2') { // approve kepala cabang / regional $sql = "UPDATE notification_detail SET NotificationDetailStatus = 'read', NotificationDetailLastUpdated = NOW(), NotificationDetailUserID = ? WHERE NotificationDetailNotificationID = ? AND NotificationDetailM_ApproveLevelID = ?"; $qry = $this->db->query($sql, [$userId, $user["NotificationID"], $user["NotificationDetailM_ApproveLevelID"]]); if (!$qry) { $this->sys_error_db("update notification error", $this->db); exit; } } } else if ($type == "R") { $sql = "UPDATE notification_detail SET NotificationDetailStatus = 'read', NotificationDetailLastUpdated = NOW(), NotificationDetailUserID = ? WHERE NotificationDetailNotificationID = ?"; $qry = $this->db->query($sql, [$userId, $user["NotificationID"]]); if (!$qry) { $this->sys_error_db("update notification error", $this->db); exit; } } else if ($type == "U") { if ($userlevel === '2') { $sql = "UPDATE notification_detail SET NotificationDetailStatus = 'unread', NotificationDetailLastUpdated = NOW(), NotificationDetailUserID = ? WHERE NotificationDetailNotificationID = ? AND NotificationDetailM_ApproveLevelID = ?"; $qry = $this->db->query($sql, [$userId, $user["NotificationID"], $user["NotificationDetailM_ApproveLevelID"]]); if (!$qry) { $this->sys_error_db("update notification error", $this->db); exit; } } } } $this->db->trans_commit(); } function getUserApproveLevel() { if (!$this->isLogin) { $this->sys_error("Invalid Token"); exit; } $userId = $this->sys_user["M_UserID"]; $sqlevel = "SELECT M_UserM_ApproveLevelID FROM m_user WHERE M_UserIsActive = 'Y' AND M_UserID = ?"; $qulevel = $this->db->query($sqlevel, [$userId]); if (!$qulevel) { $this->sys_error_db("[Error] get approval level user"); exit; } $data = $qulevel->row_array(); $this->sys_ok($data); } function updateqty() { if (!$this->isLogin) { $this->sys_error("Invalid Token"); exit; } $this->db->trans_begin(); $userId = $this->sys_user["M_UserID"]; $prm = $this->sys_input; $arrItems = $prm["arrItems"]; if (count($arrItems) > 0) { foreach ($arrItems as $key => $value) { $sql = "UPDATE purchase_request_detail SET PurchaseRequestDetailQty = ?, PurchaseRequestDetailLastUpdated = NOW(), PurchaseRequestDetailLastUpdatedUserID = ? WHERE PurchaseRequestDetailID = ?"; $qry = $this->db->query($sql, [ $value['prDetailItemQty'], $userId, $value['prDetailID'] ]); if (!$qry) { $this->db->trans_rollback(); $this->sys_error_db("Failed update qty", $this->db); exit; } } } $this->db->trans_commit(); $this->sys_ok("Berhasil update qty"); } function insert_act_log($code, $status, $description, $refId, $data, $userId) { $sql = "INSERT INTO user_activity( UserActivityCode, UserActivityStatus, UserActivityDescription, UserActivityRefID, UserActivityData, UserActivityUserID, UserActivityCreated) VALUES (?,?,?,?,?,?,?)"; $query = $this->db->query($sql, [$code, $status, $description, $refId, $data, $userId, date("Y-m-d H:i:s")]); if (!$query) { $this->sys_error_db("user activity", $this->db); exit; } } private function safeJsonEncode($data) { // Coba encode data ke JSON $jsonData = json_encode($data); // Cek apakah terjadi error saat encode if (json_last_error() !== JSON_ERROR_NONE) { $errorMsg = json_last_error_msg(); error_log("JSON encode error: " . $errorMsg); // Lakukan sanitasi dan perbaikan data $fixedData = $this->fixJsonEncodeIssues($data, $errorMsg); // Coba encode lagi setelah diperbaiki $jsonData = json_encode($fixedData); // Jika masih error, log dan kembalikan objek kosong if (json_last_error() !== JSON_ERROR_NONE) { error_log("Failed to fix JSON encode issues: " . json_last_error_msg()); // Kembalikan objek kosong jika masih gagal return '{}'; } } return $jsonData; } // Fungsi untuk memperbaiki masalah encoding JSON private function fixJsonEncodeIssues($data, $errorMsg) { // Buat salinan data untuk dimodifikasi $fixedData = $data; // Tangani berbagai jenis error if (strpos($errorMsg, 'Malformed UTF-8') !== false) { // Perbaiki masalah karakter UTF-8 $fixedData = $this->fixUTF8Issues($fixedData); } else if (strpos($errorMsg, 'Inf and NaN cannot be JSON encoded') !== false) { // Perbaiki masalah nilai Infinity atau NaN $fixedData = $this->fixInfNanIssues($fixedData); } else { // Konversi semua nilai numerik menjadi string untuk menghindari masalah presisi $fixedData = $this->convertNumericValuesToStrings($fixedData); // Perbaiki masalah referensi recursif $fixedData = $this->fixRecursiveReferences($fixedData); } return $fixedData; } // Perbaiki masalah karakter UTF-8 private function fixUTF8Issues($data) { if (is_string($data)) { return mb_convert_encoding($data, 'UTF-8', 'UTF-8'); } else if (is_array($data)) { foreach ($data as $key => $value) { $data[$key] = $this->fixUTF8Issues($value); } } return $data; } // Perbaiki masalah nilai Infinity atau NaN private function fixInfNanIssues($data) { if (is_array($data)) { foreach ($data as $key => $value) { if (is_float($value) && (is_nan($value) || is_infinite($value))) { $data[$key] = (string)$value; // Konversi ke string } else if (is_array($value)) { $data[$key] = $this->fixInfNanIssues($value); } } } return $data; } // Perbaiki masalah referensi recursif private function fixRecursiveReferences($data, $depth = 0) { // Batasi kedalaman rekursi untuk menghindari infinite loop if ($depth > 50) { return "[MAX_DEPTH_REACHED]"; } if (is_array($data)) { $result = []; foreach ($data as $key => $value) { if (is_array($value)) { $result[$key] = $this->fixRecursiveReferences($value, $depth + 1); } else { $result[$key] = $value; } } return $result; } return $data; } // Cari dan konversi numerik ke string secara rekursif private function convertNumericValuesToStrings($data) { if (is_array($data)) { foreach ($data as $key => $value) { if (is_array($value)) { $data[$key] = $this->convertNumericValuesToStrings($value); } else if (is_numeric($value)) { $data[$key] = (string)$value; } else if (is_bool($value)) { $data[$key] = $value ? "true" : "false"; } } } return $data; } }