error("API Authentication failed token : " . $token); return $this->json([ "status" => "failed", "message" => "Unauthorised Access", ]); } $log_data = json_encode($user); $logger->info("User $log_data successfully authenticated from " . $_SERVER['REMOTE_ADDR']); $payload = json_decode(file_get_contents("php://input") , true); if (json_last_error() !== JSON_ERROR_NONE) { // echo "JSON Error: " . json_last_error_msg(); http_response_code(400); return $this->json([ "status" => "failed", "message" => "Bad Request. Invalid JSON Object", ]); } $requested_keys = ['transaction_id', 'reference_id', 'mobile_number', 'amount']; foreach ($requested_keys as $key) { if (!isset($payload[$key]) || trim($payload[$key]) === '') { http_response_code(400); return $this->json([ "status" => "failed", "message" => "Validation Error: Missing or empty field : {$key}", ]); } } if (!preg_match('/^[a-zA-Z0-9]+$/', $payload['transaction_id'])) { http_response_code(400); return $this->json([ "status" => "failed", "message" => "Validation Error: Malformed Transaction ID", ]); } if (!preg_match('/^[a-zA-Z0-9]+$/', $payload['reference_id'])) { return $this->json([ "status" => "failed", "message" => "Validation Error: Malformed Reference ID", ]); } if (!preg_match('/^[0-9]{9,12}$/', $payload['mobile_number'])) { return $this->json([ "status" => "failed", "message" => "Validation Error: Invalid Mobile Number format", ]); } $amount = filter_var($payload['amount'], FILTER_VALIDATE_FLOAT); if ($amount === false || $amount <= 0) { return $this->json([ "status" => "failed", "message" => "Validation Error: Amount must be a positive number", ]); } $logger->info("Disbursement check request : " . json_encode($payload)); $transaction_details = Disbursement::varifyTransaction($payload['transaction_id'], $payload['reference_id']); if ($transaction_details == false) { return $this->json([ 'status' => 'fail', 'data' => 'Transaction not found', ]); } $network = $this->getNetwork($payload['mobile_number']); //pull this away into the ENV file $pin = "IGbCqXwRoiqsHTIIjxfo6vWyzPMKg6iF3+pNQK6gTXbOyJgOd1bbPuIstTcMwSAiRXOgQrkRC0+sQU5wHF33aha+AL0TevBntLzVyGl8002ZXy6Ux4Pu+zymRdlw7J6H/PXRC2kXhbR2GIHLHlqHC49gu65OzpJ8fvpnscg1yjE="; if ($network == 'airtel') { $broker_details = AirtelBroker::find($transaction_details[0]['wallet_id']); $authURL = $_ENV['AIRTEL_MONEY_AUTH_URL']; $auth_result = $this->authenticateAirtel($authURL, $broker_details['client_id'], $broker_details['client_secret']); if ($auth_result['success'] == false) { $logger->info("Airtel Money authentication failed " . json_encode($auth_result)); return $this->json([ 'status' => 'fail', 'data' => 'Your request could not be handled at this time. Try again', ]); } $airtel_array = [ "accessToken" => $auth_result['token'], "msisdn" => $transaction_details[0]['msisdn'], "amount" => $amount, "reference" => $transaction_details[0]['infotech_transaction_id'], "pin" => $pin, "transactionId" => $transaction_details[0]['transaction_id'], "country" => "MW", "currency" => "MWK" ]; $retval = $this->airtelDisbursement($airtel_array); var_dump($retval); $disbursement_update_data = [ 'response_message' => $disbursement_retval['response'], 'confirmed' => 1, 'confirmed_at' => date('Y-m-d H:i:s'), 'status' => 'successful' ]; $logger->info('Disbursement Update data : ' . json_encode($disbursement_update_data)); $update_result = Disbursement::updateById($transaction_details[0]['id'], $disbursement_update_data); $logger->info('Airtel Disbursement Update Result : ' . $update_result); } elseif($network == 'tnm'){ //code $broker_details = MpambaBroker::getBroker($transaction_details[0]['wallet_id']); $auth_result = $this->authenticateMpamba($transaction_details[0]['wallet_id'], $broker_details[0]['password']); $params = [ "msisdn" => $transaction_details[0]['msisdn'], "amount" => $transaction_details[0]['amount'], "transaction_id" => $transaction_details[0]['transaction_id'], "narration" => "Testing", //$transaction_details[0]['description'] "token" => $auth_result['token'] ]; $disbursement_retval = $this->mpambaDisbursement($params); var_dump($disbursement_retval); $disbursement_update_data = [ 'response_message' => $disbursement_retval['raw'], 'confirmed' => 1, 'confirmed_at' => date('Y-m-d H:i:s'), 'status' => 'successful' ]; $logger->info('Disbursement Update data : ' . json_encode($disbursement_update_data)); $update_result = Disbursement::updateById($transaction_details[0]['id'], $disbursement_update_data); $logger->info('Mpamba Disbursement Update Result : ' . $update_result); } else{ return $this->json([ 'status' => 'fail', 'data' => 'Invalid phone number', ]); } } public function show($id) { $user = User::find($id); if (!$user) { return $this->json(['message' => 'User not found'], 404); } return $this->json($user); } public function testUpdate(){ $disbursement_update_data = [ 'response_message' => 'in heere', 'confirmed' => 1, 'confirmed_at' => date('Y-m-d H:i:s'), 'status' => 'successful' ]; $update_result = Disbursement::updateById('3', $disbursement_update_data); var_dump($update_result); } public function airtelDisbursement($params) { $timeout = 30; $logger = new Logger(); $url = $_ENV['AIRTEL_MONEY_DISBURSEMENT_URL']; $payload = [ "payee" => [ "msisdn" => $params['msisdn'] ], "reference" => $params['reference'], "pin" => $params['pin'], "transaction" => [ "amount" => $params['amount'], "id" => $params['transactionId'] ] ]; $log_data = json_encode($payload); $logger->info("Disbursement Requests to Airtel MW : " . $log_data ); $headers = [ 'Content-Type: application/json', 'Accept: */*', 'X-Country: ' . $params['country'], 'X-Currency: ' . $params['currency'], 'Authorization: Bearer ' . $params['accessToken'] ]; $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_HTTPHEADER => $headers, CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => $timeout, CURLOPT_SSL_VERIFYPEER => true ]); $response = curl_exec($ch); $error = curl_error($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($error) { return [ 'success' => false, 'error' => 'CURL_ERROR', 'message' => $error ]; } $logger->info("Disbursement Response from Airtel MW : " . $response); return [ 'success' => ($code === 200), 'http_code' => $code, 'response' => json_decode($response, true), 'raw' => $response ]; } public function authenticateAirtel($baseURL, $wallet, $password){ // JSON payload $postData = json_encode([ "client_id" => $wallet, "client_secret" => $password, "grant_type" => "client_credentials" ]); if (json_last_error() !== JSON_ERROR_NONE) { return [ "status" => "failed", "message" => "Bad Request. Invalid JSON Object" . json_last_error_msg(), ]; } $ch = curl_init($baseURL); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Content-Length: ' . strlen($postData) ]); $response = curl_exec($ch); if (curl_errno($ch)) { $curl_error = curl_error($ch); curl_close($ch); return [ 'success' => false, 'error' => 'Curl error: ' . $curl_error ]; } // Get HTTP status code $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); // Decode JSON response $result = json_decode($response, true); // Check if token is present if ($httpCode === 200 && isset($result['access_token'])) { return [ 'success' => true, 'token' => $result['access_token'] ]; } else { return [ 'success' => false, 'error' => $result['error_description'] ?? 'Unknown error', 'details' => $result['error'] ?? [] ]; } } #Mpamba Scripts public function authenticateMpamba($wallet, $password){ $logger = new Logger(); $url = rtrim($_ENV['MPAMBA_BASE_URL'], '/') . '/authenticate'; // JSON payload $postData = json_encode([ 'wallet' => $wallet, 'password' => $password ]); $logger->info("Mpamba Authentication Requests : " . $postData ); $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Return the response curl_setopt($ch, CURLOPT_POST, true); // Use POST method curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);// Set the request body curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Content-Length: ' . strlen($postData) ]); $response = curl_exec($ch); if (curl_errno($ch)) { $curl_error = curl_error($ch); $logger->info("Mpamba Authentication Error : " . $curl_error ); curl_close($ch); return [ 'success' => false, 'error' => 'Error: ' . $curl_error ]; } $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); // Decode JSON response $result = json_decode($response, true); // Check if token is present $logger->info("Mpamba Authentication Response : " . json_encode($result)); if ($httpCode === 200 && isset($result['data']['token'])) { return [ 'success' => true, 'token' => $result['data']['token'], 'expires_at' => $result['data']['expires_at'] ]; } else { return [ 'success' => false, 'error' => $result['message'] ?? 'Unknown error', 'details' => $result['errors'] ?? [] ]; } } public function mpambaDisbursement($params){ $logger = new Logger(); $url = $_ENV['MPAMBA_BASE_URL'] . "/payments"; $payload = array( "msisdn" => $params['msisdn'], "amount" => (int)$params['amount'], "transaction_id" => $params['transaction_id'], "narration" => $params['narration'] ); $logger->info("Mpamba Disbursement Requests : " . json_encode($payload)); $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); curl_setopt($ch, CURLOPT_HTTPHEADER, array( "Content-Type: application/json", "Authorization: Bearer " . $params['token'] )); curl_setopt($ch, CURLOPT_TIMEOUT, 30); $response = curl_exec($ch); if ($response === false) { $error = curl_error($ch); $logger->info("Mpamba Disbursement Response Error : " . $error); curl_close($ch); return array( "status" => "ERROR", "message" => "Error: " . $error ); } $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $logger->info("Mpamba Disbursement Response : " . $response); $responseData = json_decode($response, true); return array( "http_code" => $httpCode, "response" => $responseData ); } } ?>