| <?php |
| require_once '../../db.php'; |
|
|
| class MainAccount { |
| private $conn; |
| private $mainAccountId = 1; |
|
|
| public function __construct() { |
| $database = new Database(); |
| $this->conn = $database->getConnection(); |
| $this->initializeMainAccount(); |
| } |
|
|
| |
| private function initializeMainAccount() { |
| $query = "SELECT COUNT(*) as count FROM main_account"; |
| $stmt = $this->conn->prepare($query); |
| $stmt->execute(); |
| $result = $stmt->fetch(PDO::FETCH_ASSOC); |
| |
| if ($result['count'] == 0) { |
| $query = "INSERT INTO main_account |
| (paybill_number, account_number, created_at) |
| VALUES ('542542', '00106664176150', NOW())"; |
| $this->conn->exec($query); |
| $this->mainAccountId = $this->conn->lastInsertId(); |
| } |
| } |
|
|
| |
| public function getMainAccount() { |
| $query = "SELECT * FROM main_account WHERE id = :id"; |
| $stmt = $this->conn->prepare($query); |
| $stmt->bindParam(":id", $this->mainAccountId); |
| $stmt->execute(); |
| return $stmt->fetch(PDO::FETCH_ASSOC); |
| } |
|
|
| |
| public function updateMainAccountBalance($amount, $type = 'deposit') { |
| try { |
| $this->conn->beginTransaction(); |
|
|
| |
| $amount = $this->validateAmount($amount); |
|
|
| |
| $mainAccount = $this->getMainAccount(); |
| $currentBalance = $mainAccount['total_balance']; |
| |
| if ($type === 'withdrawal' && $currentBalance < $amount) { |
| throw new Exception("Insufficient funds in main account"); |
| } |
|
|
| $newBalance = $type === 'deposit' |
| ? $currentBalance + $amount |
| : $currentBalance - $amount; |
|
|
| |
| $query = "UPDATE main_account SET |
| total_balance = :balance, |
| total_deposits = total_deposits + :deposits, |
| total_withdrawals = total_withdrawals + :withdrawals, |
| updated_at = NOW() |
| WHERE id = :id"; |
|
|
| $stmt = $this->conn->prepare($query); |
| $stmt->bindParam(":balance", $newBalance); |
| |
| $depositAmount = $type === 'deposit' ? $amount : 0; |
| $withdrawalAmount = $type === 'withdrawal' ? $amount : 0; |
| |
| $stmt->bindParam(":deposits", $depositAmount); |
| $stmt->bindParam(":withdrawals", $withdrawalAmount); |
| $stmt->bindParam(":id", $this->mainAccountId); |
| |
| $stmt->execute(); |
| $this->conn->commit(); |
| |
| |
| $this->logTransaction('main_account_update', [ |
| 'type' => $type, |
| 'amount' => $amount, |
| 'previous_balance' => $currentBalance, |
| 'new_balance' => $newBalance |
| ]); |
|
|
| return [ |
| 'success' => true, |
| 'previous_balance' => $currentBalance, |
| 'new_balance' => $newBalance |
| ]; |
| } catch (Exception $e) { |
| $this->conn->rollBack(); |
| return ['success' => false, 'error' => $e->getMessage()]; |
| } |
| } |
|
|
| |
| public function getUserAccount($userId) { |
| $this->validateUser($userId); |
| |
| $query = "SELECT * FROM user_accounts WHERE user_id = :user_id"; |
| $stmt = $this->conn->prepare($query); |
| $stmt->bindParam(":user_id", $userId); |
| $stmt->execute(); |
| |
| $account = $stmt->fetch(PDO::FETCH_ASSOC); |
| |
| |
| if (!$account) { |
| return $this->createUserAccount($userId); |
| } |
| |
| return $account; |
| } |
|
|
| |
| private function createUserAccount($userId) { |
| $virtualAccountNumber = 'JM' . str_pad($userId, 8, '0', STR_PAD_LEFT); |
| |
| $query = "INSERT INTO user_accounts (user_id, virtual_account_number) |
| VALUES (:user_id, :account_number)"; |
| $stmt = $this->conn->prepare($query); |
| $stmt->bindParam(":user_id", $userId); |
| $stmt->bindParam(":account_number", $virtualAccountNumber); |
| |
| if ($stmt->execute()) { |
| $this->logTransaction('user_account_created', [ |
| 'user_id' => $userId, |
| 'virtual_account' => $virtualAccountNumber |
| ], $userId); |
| |
| return $this->getUserAccount($userId); |
| } |
| |
| return false; |
| } |
|
|
| |
| public function updateUserAccount($userId, $amount, $type = 'deposit') { |
| try { |
| $this->conn->beginTransaction(); |
|
|
| $amount = $this->validateAmount($amount); |
| $userAccount = $this->getUserAccount($userId); |
| $currentBalance = $userAccount['current_balance']; |
| |
| if ($type === 'withdrawal' && $currentBalance < $amount) { |
| throw new Exception("Insufficient funds in user account"); |
| } |
|
|
| if ($type === 'deposit') { |
| $newBalance = $currentBalance + $amount; |
| $updateField = "total_invested = total_invested + :amount"; |
| } else { |
| $newBalance = $currentBalance - $amount; |
| $updateField = "total_withdrawn = total_withdrawn + :amount"; |
| } |
|
|
| $query = "UPDATE user_accounts SET |
| current_balance = :balance, |
| {$updateField}, |
| updated_at = NOW() |
| WHERE user_id = :user_id"; |
|
|
| $stmt = $this->conn->prepare($query); |
| $stmt->bindParam(":balance", $newBalance); |
| $stmt->bindParam(":amount", $amount); |
| $stmt->bindParam(":user_id", $userId); |
| |
| $stmt->execute(); |
| $this->conn->commit(); |
| |
| $this->logTransaction('user_account_update', [ |
| 'type' => $type, |
| 'amount' => $amount, |
| 'previous_balance' => $currentBalance, |
| 'new_balance' => $newBalance |
| ], $userId); |
| |
| return [ |
| 'success' => true, |
| 'previous_balance' => $currentBalance, |
| 'new_balance' => $newBalance, |
| 'virtual_account' => $userAccount['virtual_account_number'] |
| ]; |
| } catch (Exception $e) { |
| $this->conn->rollBack(); |
| return ['success' => false, 'error' => $e->getMessage()]; |
| } |
| } |
|
|
| |
| public function recordPendingTransaction($userID, $amount, $phoneNumber, $checkoutRequestID) { |
| try { |
| |
| if (!$this->checkRateLimit($userID, 'stk_push')) { |
| throw new Exception("Too many attempts. Please try again later."); |
| } |
|
|
| |
| if ($this->checkDuplicateTransaction($userID, $amount, $phoneNumber)) { |
| throw new Exception("Duplicate transaction detected. Please wait before retrying."); |
| } |
|
|
| $amount = $this->validateAmount($amount); |
| $this->validateUser($userID); |
|
|
| $transactionID = 'JM' . date('YmdHis') . rand(1000, 9999); |
| |
| |
| $query = "INSERT INTO recharge_transactions |
| (user_id, main_account_id, amount, phone_number, |
| transaction_id, checkout_request_id, status, payment_method) |
| VALUES |
| (:user_id, :main_account_id, :amount, :phone_number, |
| :transaction_id, :checkout_request_id, 'pending', 'M-Pesa STK Push')"; |
|
|
| $stmt = $this->conn->prepare($query); |
| $stmt->bindParam(":user_id", $userID); |
| $stmt->bindParam(":main_account_id", $this->mainAccountId); |
| $stmt->bindParam(":amount", $amount); |
| $stmt->bindParam(":phone_number", $phoneNumber); |
| $stmt->bindParam(":transaction_id", $transactionID); |
| $stmt->bindParam(":checkout_request_id", $checkoutRequestID); |
|
|
| if ($stmt->execute()) { |
| $this->logTransaction('pending_transaction_created', [ |
| 'amount' => $amount, |
| 'phone_number' => $phoneNumber, |
| 'checkout_request_id' => $checkoutRequestID, |
| 'transaction_id' => $transactionID |
| ], $userID); |
| |
| return $transactionID; |
| } |
| |
| return false; |
| } catch (Exception $e) { |
| error_log("Pending transaction error: " . $e->getMessage()); |
| return false; |
| } |
| } |
|
|
| |
| public function processDeposit($userId, $amount, $paymentData) { |
| try { |
| $this->conn->beginTransaction(); |
|
|
| $amount = $this->validateAmount($amount); |
| $this->validateUser($userId); |
|
|
| |
| $mainAccount = $this->getMainAccount(); |
| $userAccount = $this->getUserAccount($userId); |
|
|
| |
| $bonus = $this->calculateBonus($amount); |
| $totalAmount = $amount + $bonus; |
|
|
| |
| $mainUpdate = $this->updateMainAccountBalance($amount, 'deposit'); |
| if (!$mainUpdate['success']) { |
| throw new Exception("Failed to update main account: " . $mainUpdate['error']); |
| } |
|
|
| |
| $userUpdate = $this->updateUserAccount($userId, $totalAmount, 'deposit'); |
| if (!$userUpdate['success']) { |
| throw new Exception("Failed to update user account: " . $userUpdate['error']); |
| } |
|
|
| |
| $transactionId = $this->recordTransaction([ |
| 'user_id' => $userId, |
| 'amount' => $amount, |
| 'bonus_amount' => $bonus, |
| 'virtual_balance_before' => $userAccount['current_balance'], |
| 'virtual_balance_after' => $userUpdate['new_balance'], |
| 'main_balance_before' => $mainAccount['total_balance'], |
| 'main_balance_after' => $mainUpdate['new_balance'], |
| 'payment_method' => $paymentData['method'], |
| 'phone_number' => $paymentData['phone'], |
| 'mpesa_receipt' => $paymentData['receipt'] ?? null, |
| 'transaction_id' => $paymentData['transaction_id'] ?? null, |
| 'checkout_request_id' => $paymentData['checkout_request_id'] ?? null, |
| 'status' => 'completed' |
| ]); |
|
|
| $this->conn->commit(); |
|
|
| $this->logTransaction('deposit_processed', [ |
| 'amount' => $amount, |
| 'bonus' => $bonus, |
| 'total_amount' => $totalAmount, |
| 'transaction_id' => $transactionId |
| ], $userId); |
|
|
| return [ |
| 'success' => true, |
| 'transaction_id' => $transactionId, |
| 'user_balance' => $userUpdate['new_balance'], |
| 'bonus_received' => $bonus, |
| 'virtual_account' => $userUpdate['virtual_account'], |
| 'main_account_balance' => $mainUpdate['new_balance'] |
| ]; |
|
|
| } catch (Exception $e) { |
| $this->conn->rollBack(); |
| return ['success' => false, 'error' => $e->getMessage()]; |
| } |
| } |
|
|
| |
| private function recordTransaction($data) { |
| $query = "INSERT INTO recharge_transactions |
| (user_id, main_account_id, amount, bonus_amount, |
| virtual_balance_before, virtual_balance_after, |
| main_balance_before, main_balance_after, |
| payment_method, phone_number, mpesa_receipt, |
| transaction_id, checkout_request_id, paybill_number, account_number, status) |
| VALUES |
| (:user_id, :main_account_id, :amount, :bonus_amount, |
| :virtual_before, :virtual_after, |
| :main_before, :main_after, |
| :payment_method, :phone_number, :mpesa_receipt, |
| :transaction_id, :checkout_request_id, :paybill, :account, :status)"; |
|
|
| $stmt = $this->conn->prepare($query); |
| $stmt->bindParam(":user_id", $data['user_id']); |
| $stmt->bindParam(":main_account_id", $this->mainAccountId); |
| $stmt->bindParam(":amount", $data['amount']); |
| $stmt->bindParam(":bonus_amount", $data['bonus_amount']); |
| $stmt->bindParam(":virtual_before", $data['virtual_balance_before']); |
| $stmt->bindParam(":virtual_after", $data['virtual_balance_after']); |
| $stmt->bindParam(":main_before", $data['main_balance_before']); |
| $stmt->bindParam(":main_after", $data['main_balance_after']); |
| $stmt->bindParam(":payment_method", $data['payment_method']); |
| $stmt->bindParam(":phone_number", $data['phone_number']); |
| $stmt->bindParam(":mpesa_receipt", $data['mpesa_receipt']); |
| $stmt->bindParam(":transaction_id", $data['transaction_id']); |
| $stmt->bindParam(":checkout_request_id", $data['checkout_request_id'] ?? null); |
| $stmt->bindParam(":paybill", $data['paybill_number'] ?? '542542'); |
| $stmt->bindParam(":account", $data['account_number'] ?? '00106664176150'); |
| $stmt->bindParam(":status", $data['status']); |
|
|
| if ($stmt->execute()) { |
| return $this->conn->lastInsertId(); |
| } |
| |
| return false; |
| } |
|
|
| |
| private function calculateBonus($amount) { |
| $bonuses = [ |
| 500 => 5, |
| 1000 => 15, |
| 2000 => 40, |
| 5000 => 120, |
| 10000 => 300, |
| 20000 => 700, |
| 50000 => 2000, |
| 100000 => 5000 |
| ]; |
| |
| |
| $closestAmount = 0; |
| $minDifference = PHP_INT_MAX; |
| |
| foreach ($bonuses as $packageAmount => $bonus) { |
| $difference = abs($packageAmount - $amount); |
| if ($difference < $minDifference) { |
| $minDifference = $difference; |
| $closestAmount = $packageAmount; |
| } |
| } |
| |
| return $bonuses[$closestAmount] ?? 0; |
| } |
|
|
| |
| public function updateTransactionStatus($checkoutRequestID, $status, $mpesaReceipt = null) { |
| try { |
| $this->conn->beginTransaction(); |
|
|
| |
| $query = "SELECT * FROM recharge_transactions |
| WHERE checkout_request_id = :checkout_id AND status = 'pending'"; |
| $stmt = $this->conn->prepare($query); |
| $stmt->bindParam(":checkout_id", $checkoutRequestID); |
| $stmt->execute(); |
| $transaction = $stmt->fetch(PDO::FETCH_ASSOC); |
|
|
| if (!$transaction) { |
| throw new Exception("Transaction not found"); |
| } |
|
|
| |
| $updateQuery = "UPDATE recharge_transactions SET |
| status = :status, |
| mpesa_receipt = :receipt, |
| updated_at = NOW() |
| WHERE checkout_request_id = :checkout_id"; |
| |
| $updateStmt = $this->conn->prepare($updateQuery); |
| $updateStmt->bindParam(":status", $status); |
| $updateStmt->bindParam(":receipt", $mpesaReceipt); |
| $updateStmt->bindParam(":checkout_id", $checkoutRequestID); |
| $updateStmt->execute(); |
|
|
| |
| if ($status === 'completed') { |
| $paymentData = [ |
| 'method' => 'M-Pesa STK Push', |
| 'phone' => $transaction['phone_number'], |
| 'receipt' => $mpesaReceipt, |
| 'transaction_id' => $transaction['transaction_id'], |
| 'checkout_request_id' => $checkoutRequestID |
| ]; |
|
|
| $depositResult = $this->processDeposit($transaction['user_id'], $transaction['amount'], $paymentData); |
|
|
| if (!$depositResult['success']) { |
| throw new Exception($depositResult['error']); |
| } |
| } |
|
|
| $this->conn->commit(); |
|
|
| $this->logTransaction('transaction_status_updated', [ |
| 'checkout_request_id' => $checkoutRequestID, |
| 'status' => $status, |
| 'mpesa_receipt' => $mpesaReceipt |
| ], $transaction['user_id']); |
|
|
| return ['success' => true]; |
|
|
| } catch (Exception $e) { |
| $this->conn->rollBack(); |
| error_log("Error updating transaction status: " . $e->getMessage()); |
| return ['success' => false, 'error' => $e->getMessage()]; |
| } |
| } |
|
|
| |
| public function submitManualPayment($user_id, $amount, $phone_number, $mpesa_code, $screenshot) { |
| try { |
| $this->conn->beginTransaction(); |
|
|
| $amount = $this->validateAmount($amount); |
| $this->validateUser($user_id); |
|
|
| |
| $transactionId = $this->recordTransaction([ |
| 'user_id' => $user_id, |
| 'amount' => $amount, |
| 'bonus_amount' => 0, |
| 'virtual_balance_before' => 0, |
| 'virtual_balance_after' => 0, |
| 'main_balance_before' => 0, |
| 'main_balance_after' => 0, |
| 'payment_method' => 'Manual Verification', |
| 'phone_number' => $phone_number, |
| 'mpesa_receipt' => $mpesa_code, |
| 'transaction_id' => 'MANUAL_' . time() . '_' . $user_id, |
| 'status' => 'pending' |
| ]); |
|
|
| |
| $query = "INSERT INTO admin_payments |
| (user_id, amount, mpesa_code, phone_number, screenshot_path) |
| VALUES |
| (:user_id, :amount, :mpesa_code, :phone_number, :screenshot)"; |
|
|
| $stmt = $this->conn->prepare($query); |
| $stmt->bindParam(":user_id", $user_id); |
| $stmt->bindParam(":amount", $amount); |
| $stmt->bindParam(":mpesa_code", $mpesa_code); |
| $stmt->bindParam(":phone_number", $phone_number); |
| $stmt->bindParam(":screenshot", $screenshot); |
|
|
| if ($stmt->execute()) { |
| $this->conn->commit(); |
| |
| $this->logTransaction('manual_payment_submitted', [ |
| 'amount' => $amount, |
| 'mpesa_code' => $mpesa_code, |
| 'transaction_id' => $transactionId |
| ], $user_id); |
| |
| return [ |
| 'success' => true, |
| 'payment_id' => $this->conn->lastInsertId(), |
| 'transaction_id' => $transactionId |
| ]; |
| } else { |
| $this->conn->rollBack(); |
| return ['success' => false, 'error' => 'Failed to submit payment']; |
| } |
|
|
| } catch (Exception $e) { |
| $this->conn->rollBack(); |
| return ['success' => false, 'error' => $e->getMessage()]; |
| } |
| } |
|
|
| |
| public function verifyPayment($payment_id, $admin_id, $notes = '') { |
| try { |
| $this->conn->beginTransaction(); |
|
|
| |
| $query = "SELECT ap.*, rt.id as transaction_id |
| FROM admin_payments ap |
| LEFT JOIN recharge_transactions rt ON ap.user_id = rt.user_id |
| AND ap.amount = rt.amount |
| AND rt.status = 'pending' |
| WHERE ap.id = :payment_id"; |
| |
| $stmt = $this->conn->prepare($query); |
| $stmt->bindParam(":payment_id", $payment_id); |
| $stmt->execute(); |
| $payment = $stmt->fetch(PDO::FETCH_ASSOC); |
|
|
| if (!$payment) { |
| throw new Exception("Payment not found"); |
| } |
|
|
| |
| $paymentData = [ |
| 'method' => 'Manual Verification', |
| 'phone' => $payment['phone_number'], |
| 'receipt' => $payment['mpesa_code'], |
| 'transaction_id' => 'MANUAL_VERIFIED_' . $payment_id |
| ]; |
|
|
| $depositResult = $this->processDeposit($payment['user_id'], $payment['amount'], $paymentData); |
|
|
| if (!$depositResult['success']) { |
| throw new Exception($depositResult['error']); |
| } |
|
|
| |
| $updateQuery = "UPDATE admin_payments SET |
| status = 'verified', |
| verified_by = :admin_id, |
| verified_at = NOW(), |
| notes = :notes |
| WHERE id = :payment_id"; |
| |
| $updateStmt = $this->conn->prepare($updateQuery); |
| $updateStmt->bindParam(":admin_id", $admin_id); |
| $updateStmt->bindParam(":notes", $notes); |
| $updateStmt->bindParam(":payment_id", $payment_id); |
| $updateStmt->execute(); |
|
|
| |
| if ($payment['transaction_id']) { |
| $updateTxQuery = "UPDATE recharge_transactions SET status = 'completed' WHERE id = :tx_id"; |
| $updateTxStmt = $this->conn->prepare($updateTxQuery); |
| $updateTxStmt->bindParam(":tx_id", $payment['transaction_id']); |
| $updateTxStmt->execute(); |
| } |
|
|
| $this->conn->commit(); |
|
|
| $this->logTransaction('payment_verified', [ |
| 'payment_id' => $payment_id, |
| 'admin_id' => $admin_id, |
| 'amount' => $payment['amount'] |
| ], $payment['user_id']); |
|
|
| return [ |
| 'success' => true, |
| 'user_balance' => $depositResult['user_balance'], |
| 'bonus_received' => $depositResult['bonus_received'] |
| ]; |
|
|
| } catch (Exception $e) { |
| $this->conn->rollBack(); |
| return ['success' => false, 'error' => $e->getMessage()]; |
| } |
| } |
|
|
| |
| public function rejectPayment($payment_id, $admin_id, $notes = '') { |
| try { |
| $this->conn->beginTransaction(); |
|
|
| |
| $updateQuery = "UPDATE admin_payments SET |
| status = 'rejected', |
| verified_by = :admin_id, |
| verified_at = NOW(), |
| notes = :notes |
| WHERE id = :payment_id"; |
| |
| $updateStmt = $this->conn->prepare($updateQuery); |
| $updateStmt->bindParam(":admin_id", $admin_id); |
| $updateStmt->bindParam(":notes", $notes); |
| $updateStmt->bindParam(":payment_id", $payment_id); |
| $updateStmt->execute(); |
|
|
| |
| $txQuery = "UPDATE recharge_transactions SET status = 'failed' |
| WHERE user_id = (SELECT user_id FROM admin_payments WHERE id = :payment_id) |
| AND amount = (SELECT amount FROM admin_payments WHERE id = :payment_id) |
| AND status = 'pending'"; |
| |
| $txStmt = $this->conn->prepare($txQuery); |
| $txStmt->bindParam(":payment_id", $payment_id); |
| $txStmt->execute(); |
|
|
| $this->conn->commit(); |
|
|
| $payment = $this->getPaymentDetails($payment_id); |
| $this->logTransaction('payment_rejected', [ |
| 'payment_id' => $payment_id, |
| 'admin_id' => $admin_id, |
| 'notes' => $notes |
| ], $payment['user_id']); |
|
|
| return ['success' => true]; |
|
|
| } catch (Exception $e) { |
| $this->conn->rollBack(); |
| return ['success' => false, 'error' => $e->getMessage()]; |
| } |
| } |
|
|
| |
| public function getUserDashboardData($userId) { |
| $this->validateUser($userId); |
| |
| $userAccount = $this->getUserAccount($userId); |
| $mainAccount = $this->getMainAccount(); |
|
|
| |
| $query = "SELECT * FROM recharge_transactions |
| WHERE user_id = :user_id |
| ORDER BY created_at DESC |
| LIMIT 5"; |
| $stmt = $this->conn->prepare($query); |
| $stmt->bindParam(":user_id", $userId); |
| $stmt->execute(); |
| $recentTransactions = $stmt->fetchAll(PDO::FETCH_ASSOC); |
|
|
| return [ |
| 'virtual_account' => $userAccount['virtual_account_number'], |
| 'current_balance' => $userAccount['current_balance'], |
| 'total_invested' => $userAccount['total_invested'], |
| 'total_earnings' => $userAccount['total_earnings'], |
| 'total_withdrawn' => $userAccount['total_withdrawn'], |
| 'main_account_balance' => $mainAccount['total_balance'], |
| 'paybill_number' => $mainAccount['paybill_number'], |
| 'account_number' => $mainAccount['account_number'], |
| 'recent_transactions' => $recentTransactions |
| ]; |
| } |
|
|
| |
| public function getPendingPayments() { |
| $query = "SELECT ap.*, u.username, u.email |
| FROM admin_payments ap |
| JOIN users u ON ap.user_id = u.id |
| WHERE ap.status = 'pending' |
| ORDER BY ap.created_at DESC"; |
| |
| $stmt = $this->conn->prepare($query); |
| $stmt->execute(); |
| |
| return $stmt->fetchAll(PDO::FETCH_ASSOC); |
| } |
|
|
| |
| public function getUserPaymentHistory($user_id, $limit = 10) { |
| $this->validateUser($user_id); |
| |
| $query = "SELECT * FROM recharge_transactions |
| WHERE user_id = :user_id |
| ORDER BY created_at DESC |
| LIMIT :limit"; |
| |
| $stmt = $this->conn->prepare($query); |
| $stmt->bindParam(":user_id", $user_id); |
| $stmt->bindParam(":limit", $limit, PDO::PARAM_INT); |
| $stmt->execute(); |
| |
| return $stmt->fetchAll(PDO::FETCH_ASSOC); |
| } |
|
|
| |
| private function validateAmount($amount) { |
| if (!is_numeric($amount) || $amount <= 0) { |
| throw new Exception("Invalid amount specified"); |
| } |
| return floatval($amount); |
| } |
|
|
| private function validateUser($userId) { |
| $stmt = $this->conn->prepare("SELECT id FROM users WHERE id = ?"); |
| $stmt->execute([$userId]); |
| if (!$stmt->fetch()) { |
| throw new Exception("User not found"); |
| } |
| } |
|
|
| |
| public function checkRateLimit($userId, $action, $maxAttempts = 5, $timeFrame = 3600) { |
| $stmt = $this->conn->prepare(" |
| SELECT COUNT(*) as attempts FROM transaction_logs |
| WHERE user_id = ? AND action = ? AND created_at > DATE_SUB(NOW(), INTERVAL ? SECOND) |
| "); |
| $stmt->execute([$userId, $action, $timeFrame]); |
| $result = $stmt->fetch(PDO::FETCH_ASSOC); |
| |
| return $result['attempts'] < $maxAttempts; |
| } |
|
|
| public function checkDuplicateTransaction($userId, $amount, $phoneNumber, $timeFrame = 300) { |
| $stmt = $this->conn->prepare(" |
| SELECT id FROM recharge_transactions |
| WHERE user_id = ? AND amount = ? AND phone_number = ? |
| AND status = 'pending' AND created_at > DATE_SUB(NOW(), INTERVAL ? SECOND) |
| "); |
| $stmt->execute([$userId, $amount, $phoneNumber, $timeFrame]); |
| |
| return $stmt->fetch() !== false; |
| } |
|
|
| |
| private function logTransaction($action, $details, $userId = null) { |
| $stmt = $this->conn->prepare(" |
| INSERT INTO transaction_logs |
| (user_id, action, details, created_at) |
| VALUES (?, ?, ?, NOW()) |
| "); |
| $stmt->execute([$userId, $action, json_encode($details)]); |
| } |
|
|
| |
| private function getPaymentDetails($payment_id) { |
| $query = "SELECT * FROM admin_payments WHERE id = :id"; |
| $stmt = $this->conn->prepare($query); |
| $stmt->bindParam(":id", $payment_id); |
| $stmt->execute(); |
| return $stmt->fetch(PDO::FETCH_ASSOC); |
| } |
|
|
| |
| public function getMainAccountSummary() { |
| $mainAccount = $this->getMainAccount(); |
| |
| |
| $query = "SELECT COUNT(*) as today_count, COALESCE(SUM(amount), 0) as today_amount |
| FROM recharge_transactions |
| WHERE DATE(created_at) = CURDATE() AND status = 'completed'"; |
| $stmt = $this->conn->prepare($query); |
| $stmt->execute(); |
| $today = $stmt->fetch(PDO::FETCH_ASSOC); |
| |
| |
| $query = "SELECT COUNT(*) as pending_count FROM recharge_transactions WHERE status = 'pending'"; |
| $stmt = $this->conn->prepare($query); |
| $stmt->execute(); |
| $pending = $stmt->fetch(PDO::FETCH_ASSOC); |
| |
| return [ |
| 'main_account' => $mainAccount, |
| 'today_transactions' => $today, |
| 'pending_transactions' => $pending |
| ]; |
| } |
| } |
| ?> |