diff --git a/.gitignore b/.gitignore index 0f7df0f..ffea9a7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ /public/storage /storage/*.key /vendor +.DS_Store .env .env.backup .phpunit.result.cache diff --git a/app/Http/Controllers/AirtelMoneyMalawiController.php b/app/Http/Controllers/AirtelMoneyMalawiController.php new file mode 100644 index 0000000..53587f1 --- /dev/null +++ b/app/Http/Controllers/AirtelMoneyMalawiController.php @@ -0,0 +1,279 @@ +json(['code' => 1, 'data' => json_decode($request->all())]); + } + + + public function Collect(Requests\CollectPaymentsRequest $request){ + $current_date = date('Y-m-d'); + // $incoming=file_get_contents("php://input"); + // $data = json_decode($incoming, true); + $data = $request->only(['msisdn', 'country', 'currency']); + //country, currency, msisdn, + // $subscriber_country = $data['subscriber']['country']; + // $subscriber_currency = $data['subscriber']['currency']; + // $subscriber_msisdn = $data['subscriber']['msisdn']; + + // $transaction_amount = $data['transaction']['amount']; + // $transaction_country = $data['transaction']['country']; + // $transaction_currency = $data['transaction']['currency']; + // $transaction_id = $data['transaction']['id']; + + $authURL = "https://openapiuat.airtel.africa/auth/oauth2/token"; + + + //CONTINENTAL CAPITAL + $clientID = "9ff18a6d-331e-4ec5-9ecc-4e512e13747c"; + $clientSecret = "40f44254-10e7-4eb8-b161-38125117f4ba"; + + + $result = $this->authenticate($authURL, $clientID, $clientSecret); + if($result['success']){ + + $bearerToken = $result['token']; + + //send a ussd push + $retval = $this->sendUSSDPush($bearerToken, $data); + $result_data = json_decode($retval, true); + // dump($result_data); + // Check if the response has a status and success flag + if (isset($result_data['status']['success']) && $result_data['status']['success'] === true) { + // Success case + $transactionId = $result_data['data']['transaction']['id']; + $transactionStatus = $result_data['data']['transaction']['status']; + $message = $result_data['status']['message']; + + $msg = "✅ Transaction Successful!\n"; + $msg .= "Transaction ID: $transactionId\n"; + $msg .= "Status: $transactionStatus\n"; + $msg .= "Message: $message\n"; + return response()->json(['code' => 1, 'msg' => $msg]); + } else { + // Failure case + $errorCode = $result_data['status']['result_code'] ?? 'N/A'; + $errorMessage = $result_data['status']['message'] ?? 'Unknown error'; + + $msg = "❌ Transaction Failed!\n"; + $msg .= "Error Code: $errorCode\n"; + $msg .= "Message: $errorMessage\n"; + return response()->json(['code' => 3, 'msg' => $msg, 'responseRaw' => $result_data ]); + } + } + else{ + $msg = $result; + return response()->json(['code' => 5, 'msg' => $msg]); + exit(); + } + } + + + public function getProductIDs($product_name){ + $product = Models\Product::where('name', $product_name)->first(); + return $product; + } + + public function getProductIDsFirst($session_uuid){ + $params = [ + "request_reference" => 31000, + "session_uuid" => $session_uuid + ]; + $kazang = Config('kazang'); + $kaz_host = $kazang['test_base_url']; + + $url = "$kaz_host/apimanager/api_rest/v1/productList"; + $retval = $this->globalCurlPost($url, $params); + return $retval; + + } + public function sendUSSDPush($token, $data) { + // Endpoint + + + $url = "https://openapiuat.airtel.africa/merchant/v1/payments/"; + + // Initialize cURL + $ch = curl_init($url); + + // Set cURL options + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + "Authorization: Bearer " . $token, + "Content-Type: application/json", + "X-Country: MW", + "X-Currency: MWK" + ]); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); + + // Execute request + $response = curl_exec($ch); + + // Check for cURL errors + if (curl_errno($ch)) { + echo "cURL Error: " . curl_error($ch); + curl_close($ch); + return false; + } + + // Close connection + curl_close($ch); + + // Decode and return response + return $response; + } + + public function changePassword($baseURL, $token,$newPassword, $newPasswordConfirmation) { + // Endpoint URL + $url = rtrim($baseURL, "/") . "/password"; + + // Prepare data + $data = [ + "new_password" => $newPassword, + "new_password_confirmation" => $newPasswordConfirmation + ]; + + // Initialize cURL + $ch = curl_init($url); + + // Set cURL options + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH"); // PATCH request + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + "Authorization: Bearer " . $token, + "Content-Type: application/json" + ]); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); + + // Execute and capture response + $response = curl_exec($ch); + + // Check for errors + if (curl_errno($ch)) { + echo "cURL Error: " . curl_error($ch); + curl_close($ch); + return false; + } + + // Close connection + curl_close($ch); + + // Decode JSON response + return json_decode($response, true); + } + + public function validate_msisdn($baseURL, $msisdn, $bearerToken){ + // Ensure proper endpoint format + $url = rtrim($baseURL, '/') . '/payments/validate/' . urlencode($msisdn); + + // Initialize cURL + $ch = curl_init($url); + + // Set cURL options + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPGET, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Authorization: Bearer ' . $bearerToken, + 'Accept: application/json' + ]); + + // Execute the request + $response = curl_exec($ch); + + // Handle cURL error + if (curl_errno($ch)) { + curl_close($ch); + return [ + 'success' => false, + 'error' => 'Curl error: ' . curl_error($ch) + ]; + } + + // Get HTTP status code + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + // Decode JSON response + $result = json_decode($response, true); + + if ($httpCode === 200 && isset($result['data']['full_name'])) { + return [ + 'success' => true, + 'full_name' => $result['data']['full_name'] + ]; + } else { + return [ + 'success' => false, + 'error' => $result['message'] ?? 'Unknown error', + 'details' => $result['errors'] ?? [] + ]; + } + } + + + + public function authenticate($baseURL, $clientID, $clientSecret){ + // JSON payload + $postData = json_encode([ + 'client_id' => $clientID, + 'client_secret' => $clientSecret, + 'grant_type' => "client_credentials" + ]); + + // Initialize cURL + $ch = curl_init($baseURL); + + // Set cURL options + 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) + ]); + + // Execute the request + $response = curl_exec($ch); + + // Check for cURL errors + if (curl_errno($ch)) { + curl_close($ch); + return [ + 'success' => false, + 'error' => 'Curl error: ' . curl_error($ch) + ]; + } + + // 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'] ?? [] + ]; + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/ApiTokenController.php b/app/Http/Controllers/ApiTokenController.php new file mode 100644 index 0000000..e766b0b --- /dev/null +++ b/app/Http/Controllers/ApiTokenController.php @@ -0,0 +1,20 @@ +user()->forceFill([ + 'api_token' => hash('sha256', $token), + ])->save(); + return ['token' => $token]; + } +} diff --git a/app/Http/Controllers/ConfirmCollectionController.php b/app/Http/Controllers/ConfirmCollectionController.php new file mode 100644 index 0000000..f48a87c --- /dev/null +++ b/app/Http/Controllers/ConfirmCollectionController.php @@ -0,0 +1,124 @@ +log_query(); + $session_uuid = $this->KazangLogin(); + + $transaction = Models\KazangTransaction::where('routem_client_reference', $request->refID)->first(); + $request_reference = substr(time(), 0, 9); + #"supplier_transaction_id" => $request->supplier_transaction_id, + if ($transaction) { + $curl_params = [ + "session_uuid" => $session_uuid, + "request_reference" => $request_reference, + "product_id" => $transaction->product_id, + "confirmation_number" => $transaction->confirmation_number, + ]; + $url = "kaz_host/apimanager/api_rest/v1/airtelPayPaymentConfirm"; + + $retval = $this->globalCurlPost($url, $curl_params); + + return response()->json(['code' => 1, 'msg' => json_decode($retval)]); + } + else{ + return response()->json(['code' => 3, 'msg' => "Transaction not found"]); + } + # Airtel Params for approval + /* + { + "session_uuid": "{{kaz_session_uuid}}", + "request_reference": "{{kaz_request_reference}}", + "product_id": {{airtel_pay_payment_prod_id}}, + "confirmation_number": "{{airtel_pay_confirmation_number}}" + } + */ + # : MTN Params : supplier_transaction_id received in Pay 1 + # : + /* + { + "session_uuid": "6df64e35-0fa4-4c7e-86bc-eefd92255c2b", + "request_reference": "routem1008", + "product_id": {{mtn_momo_pay_fin_prod_id}}, + "wallet_msisdn": "+260981112134", + "amount": "50000", + "supplier_transaction_id": "{{mtn_cash_out_supplier_transaction_id}}", + "client_transaction_reference": "0987654321" + } + */ + + } + public function ConfirmAirtel(Requests\ConfirmPaymentsRequest $request) + { + $kazang = Config('kazang'); + $kaz_host = $kazang['test_base_url']; + $session_uuid = $this->KazangLogin(); + + $transaction = Models\KazangTransaction::where('routem_client_reference', $request->refID)->first(); + + return response()->json(['code' => 1, 'msg' => json_decode($transaction)]); + + $transaction = Models\KazangTransaction::where('request_reference', $request->refID)->first(); + $request_reference = substr(time(), 0, 9); + //Retrieve the last request from the transactions + + + if ($transaction) { + $curl_params = [ + "session_uuid" => $session_uuid, + "request_reference" => $request_reference, + "product_id" => $transaction->product_id, + "wallet_msisdn" => $transaction->msisdn, + "amount" => $transaction->amount, + "confirmation_number" => $transaction->confirmation_number, + "client_transaction_reference" => $transaction->request_reference + ]; + $url = "kaz_host/apimanager/api_rest/v1/mtnDebitApproval"; + + $retval = $this->globalCurlPost($url, $curl_params); + + return response()->json(['code' => 1, 'msg' => json_decode($retval)]); + } + else{ + return response()->json(['code' => 3, 'msg' => "Transaction not found"]); + } + # Response from RoutePay Collect + /* + { + "code": 1, + "msg": "success", + "data": { + "reference_id": "4393901145", + "confirmation_number": "333720", + "confirmation_message": "\nPlease confirm\nCust. Msisdn: +260978981953\nCust. First Name: Jean-Luc\nCust. Last name: Picard\nAmount: 0.05\n\n\n\n" + } + } + */ + # : MTN Params : supplier_transaction_id received in Pay 1 + # : + /* + { + "session_uuid": "6df64e35-0fa4-4c7e-86bc-eefd92255c2b", + "request_reference": "routem1008", + "product_id": {{mtn_momo_pay_fin_prod_id}}, + "wallet_msisdn": "+260981112134", + "amount": "50000", + "supplier_transaction_id": "{{mtn_cash_out_supplier_transaction_id}}", + "client_transaction_reference": "0987654321" + } + */ + + } +} diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index a0a2a8a..5914a3a 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -10,4 +10,46 @@ use Illuminate\Routing\Controller as BaseController; class Controller extends BaseController { use AuthorizesRequests, DispatchesJobs, ValidatesRequests; + + public function log_query() { + // , $binding, $timing 'bindings' => $binding) + \DB::listen(function ($sql) { + \Log::info('showing query', array('sql' => $sql)); + } + ); + } + public function globalCurlPost($url, $params){ + + $curl = curl_init(); + curl_setopt_array($curl, array( + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => '', + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 0, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => json_encode($params), + CURLOPT_HTTPHEADER => array( + 'Content-Type: application/json' + ), + )); + $response = curl_exec($curl); + curl_close($curl); + return $response; + } + public function KazangLogin(){ + $kaz_config = config('kazang'); + // $url = 'https://testapi.kazang.net/apimanager/api_rest/v1/authClient'; + $url = $kaz_config['test_base_url'] . '/apimanager/api_rest/v1/authClient'; + $postfields = [ + "username" => env('KAZ_USERNAME'), + "password" => env('KAZ_PASS'), + "channel" => env('KAZ_CHANNEL'), + ]; + $session_data = $this->globalCurlPost($url, $postfields); + $decoded = json_decode($session_data, true); + return $decoded['session_uuid']; + } } diff --git a/app/Http/Controllers/KazTestController.php b/app/Http/Controllers/KazTestController.php new file mode 100644 index 0000000..a2a79b2 --- /dev/null +++ b/app/Http/Controllers/KazTestController.php @@ -0,0 +1,16 @@ +json(['code' => 1, 'data' => json_decode($request->all())]); + } + public function CollectFirst(Requests\CollectPaymentsRequest $request, Kazang $kazang){ + $current_date = date('Y-m-d'); + // Todo : check network and call appropriate endpoint to initiate payment + //$session_uuid = $this->getSessionUuid($kazang); + $endpoint = $this->getEnpoint($request->product_name); + // dd($endpoint); + //TODO : find a way to dynamically retrieve Product ID from the list + #$product_list = $this->getProductIDs($session_uuid); - // { - // "msisdn", "amount", "refID", - // product_name - return response()->json(['code' => 1]); + // dd($product_list); + if ($endpoint !== false) { + $session_uuid = $this->getSessionUuid($kazang); + // send step 1 request here + $transaction_params = [ + 'session_uuid' => $session_uuid, + 'request_reference' => substr(time(), 0, 9), // add a reference from the transactions table + 'product_id' => $endpoint['productid'], + 'wallet_msisdn' => $request->msisdn, + 'routem_client_reference' => $request->refID, + 'amount' => $request->amount + ]; + + $saveTransaction = Models\KazangTransaction::create($transaction_params); + if ($saveTransaction == false) { + // code... return to sender + } + $curl_params = [ + 'session_uuid' => $session_uuid, + 'request_reference' => substr(time(), 0, 9), // add a reference from the transactions table + 'product_id' => $endpoint['productid'], + 'routem_client_reference' => $request->refID, + 'amount' => $request->amount + ]; + if ($request->product_name == 'zamtel_money') { + $curl_params['msisdn'] = $request->msisdn; + } + else{ + $curl_params['wallet_msisdn'] = $request->msisdn; + } + $retval = $this->globalCurlPost($endpoint['url'], $curl_params); + + $transaction = Models\KazangTransaction::find($saveTransaction->id); + // dd($retval); + // return response()->json(['code' => 1, 'msg' => 'success', 'data' => json_decode($retval)]); + $retval = json_decode($retval, true); + file_put_contents(public_path("logs/" . $current_date . "_api_response_logs.txt"), json_encode($retval) . PHP_EOL, FILE_APPEND); + + $transaction->response_code = $retval['response_code']; + $transaction->balance = $retval['balance']; + if (isset($retval['supplier_transaction_id'])) { + $transaction->supplier_transaction_id = $retval['supplier_transaction_id']; + } + if (isset($retval['confirmation_number'])) { + $transaction->confirmation_number = $retval['confirmation_number']; + } + if (isset($retval['confirmation_message'])) { + $transaction->confirmation_message = $retval['confirmation_message']; + } + + $transaction->save(); + if ($request->product_name == 'mtn_momo_zambia') { + //TODO : check response_code = "0" + if ($retval['response_code'] == "0") { + $data = ['reference_id' => $request->refID, 'supplier_transaction_id' => $retval['supplier_transaction_id'], 'response_message' => $retval['response_message']]; + return response()->json(['code' => 1, 'msg' => 'success', 'data' => $data]); + } + else{ + return response()->json(['code' => 3, 'msg' => $retval['response_message']]); + } + + } + else{ + if ($retval['response_code'] == "0") { + $data = ['reference_id' => $request->refID, 'confirmation_number' => $retval['confirmation_number'], 'confirmation_message' => $retval['confirmation_message']]; + return response()->json(['code' => 1, 'msg' => 'success', 'data' => $data]); + } + else{ + return response()->json(['code' => 3, 'msg' => $retval['$confirmation_message']]); + } + } + //Airtel : confirmation_number + /* + MTN + "data": { + "wallet_msisdn": "+260981112134", + "amount": "0.05", + "request_reference": "167079990", + "response_code": "0", + "balance": "20490.05", + "supplier_transaction_id": "52878", + "response_message": "\r\n********************************\r\n KAZANG \r\n********************************\r\n MOMO Pay Step 1 \r\n--------------------------------\r\n 2022-12-12 01:05 \r\n Pending Payment Created \r\n--------------------------------\r\n API V2 Test - Zambia \r\nVendor: 1000631438\r\nMTN Phone No.: 260981112134\r\nReference: 4458\r\n--------------------------------\r\n MTN Reference \r\n 5287 8 \n\r\n--------------------------------\r\nAmount: 0.05\r\n--------------------------------\r\n A pending transaction has been \ncreated. Please approve on your \nmobile device. Keep this receipt\n to prove payment to the vendor \n after approval. \r\n--------------------------------\r\n Thank you! " + } + Airtel + "data": { + "wallet_msisdn": "978981953", + "confirmation_number": "333366", + "request_reference": "167079973", + "customer_last_name": "Picard", + "response_code": "0", + "amount": "0.05", + "confirmation_message": "\nPlease confirm\nCust. Msisdn: +260978981953\nCust. First Name: Jean-Luc\nCust. Last name: Picard\nAmount: 0.05\n\n\n\n", + "customer_first_name": "Jean-Luc", + "balance": "20490.05" + } + Zamtel + "data": { + "customer_last_name": "killian", + "confirmation_number": "333360", + "request_reference": "167079058", + "msisdn": "+260981112134", + "response_code": "0", + "amount": "0.05", + "confirmation_message": "\nPlease confirm\nCust. Msisdn: +260981112134\nAmount: 0.05\n\nCustomer Details\nName: aaa\nSurname: killian\nID Number: 1234567\n\n\n\n\n\n", + "customer_first_name": "aaa", + "customer_id_number": "1234567", + "balance": "20490.05" + } + */ + return response()->json(['code' => 1, 'data' => json_decode($retval)]); + } + return response()->json(['code' => 3, 'msg' => 'Your request could not handled at this time']); } + + public function Collect(Requests\CollectPaymentsRequest $request){ + $current_date = date('Y-m-d'); + + // Todo : check network and call appropriate endpoint to initiate payment + // log request + // check broker + // check payment mode + // use payment mode pay logic to respond + + #$endpoint = $this->getEnpoint($request->product_name); + // dd($endpoint); + //TODO : find a way to dynamically retrieve Product ID from the list + #$product_list = $this->getProductIDs($request->product_name); + + return response()->json(['code' => 1, 'data' => json_decode($product_list)]); + + return response()->json(['code' => 3, 'msg' => 'Your request could not handled at this time', 'endpoint' => $endpoint]); + + } + public function getSessionUuid($kazang){ + $kas_session = Models\KazangSession::find(1); + if ($kas_session) { + $current_time = date('Y-m-d H:i:s'); + $to = Carbon::createFromFormat('Y-m-d H:s:i', $kas_session->updated_at); + $from = Carbon::createFromFormat('Y-m-d H:s:i', $current_time); + $diff_in_minutes = $to->diffInMinutes($from); + // dd($diff_in_hours); + + if ($diff_in_minutes <= 60) { + $session_uuid = $kas_session->session_uuid; + return $session_uuid; + } + else{ + $session_uuid = $kazang->login(); + $kas_session->session_uuid = $session_uuid; + $kas_session->save(); + return $session_uuid; + } + } + else { + $session_uuid = $kazang->login(); + $kas_session->session_uuid = $session_uuid; + $kas_session->save(); + return $session_uuid; + } + + } + public function getEnpoint($product_name){ + $kazang = Config('kazang'); + $kaz_host = $kazang['test_base_url']; + //TODO : remove the hardcoded productIDs + switch ($product_name) { + case 'airtel_money_zambia': + $productID = 1663; + $endpoint = "$kaz_host/apimanager/api_rest/v1/airtelPayPayment"; + break; + case 'mtn_momo_zambia': + $productID = 1612; + $endpoint = "$kaz_host/apimanager/api_rest/v1/mtnDebit"; + break; + case 'zamtel_money': + $productID = 1706; + $endpoint = "$kaz_host/apimanager/api_rest/v1/zamtelMoneyPay"; + break; + default: + return false; + break; + } + return ['productid' => $productID, 'url' => $endpoint]; + } + public function getProductIDs($product_name){ + $product = Models\Product::where('name', $product_name)->first(); + return $product; + } + + public function getProductIDsFirst($session_uuid){ + $params = [ + "request_reference" => 31000, + "session_uuid" => $session_uuid + ]; + $kazang = Config('kazang'); + $kaz_host = $kazang['test_base_url']; + + $url = "$kaz_host/apimanager/api_rest/v1/productList"; + $retval = $this->globalCurlPost($url, $params); + return $retval; + + } + } +//b1d7d86b-8906-4a24-bb8d-268b085d539c diff --git a/app/Http/Requests/CollectPaymentsRequest.php b/app/Http/Requests/CollectPaymentsRequest.php index 533de99..b4be172 100644 --- a/app/Http/Requests/CollectPaymentsRequest.php +++ b/app/Http/Requests/CollectPaymentsRequest.php @@ -18,7 +18,11 @@ class CollectPaymentsRequest extends FormRequest public function messages(){ return array( - 'product_name.required' => 'You need to specify the product name' + 'channel.required' => 'You need to specify the channel', + 'payment_mode.required' => 'You need to specify the payment mode', + 'broker_id.required' => 'You need to specify the borker', + 'refID.required' => 'No reference ID found', + // 'refID.unique' => 'Duplicate refID, check and try again' ); } public function responsenn(array $errors){ @@ -34,11 +38,14 @@ class CollectPaymentsRequest extends FormRequest public function rules() { return [ - 'msisdn' => 'required|regex:/^(0)[89]\d{8}$/', + 'msisdn' => 'required|regex:/\d{10}$/', 'amount' => 'required', - 'product_name' => 'required', + 'country' => 'required', + 'currency' => 'required', + 'channel' => 'required', //web, ussd, mobile app 'refID' => 'required', - 'country' => 'required' + 'payment_mode' => 'required', + 'broker_id' => 'required', ]; } } diff --git a/app/Http/Requests/ConfirmPaymentsRequest.php b/app/Http/Requests/ConfirmPaymentsRequest.php new file mode 100644 index 0000000..ea32ac0 --- /dev/null +++ b/app/Http/Requests/ConfirmPaymentsRequest.php @@ -0,0 +1,32 @@ + 'sometimes', + 'supplier_transaction_id' => 'sometimes', + 'refID' => 'required', + ]; + } +} diff --git a/app/Library/AirtelMoneyMw/AirtelPush.php b/app/Library/AirtelMoneyMw/AirtelPush.php new file mode 100644 index 0000000..ca7c114 --- /dev/null +++ b/app/Library/AirtelMoneyMw/AirtelPush.php @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/app/Library/AirtelMoneyMw/callback.php b/app/Library/AirtelMoneyMw/callback.php new file mode 100644 index 0000000..f55bd21 --- /dev/null +++ b/app/Library/AirtelMoneyMw/callback.php @@ -0,0 +1,50 @@ + "callback received"]); + +} else { + // Missing required fields + http_response_code(400); + echo json_encode(["error" => "Invalid callback payload"]); +} + +?> diff --git a/app/Library/AirtelMoneyMw/check_balance.php b/app/Library/AirtelMoneyMw/check_balance.php new file mode 100644 index 0000000..fb0b98d --- /dev/null +++ b/app/Library/AirtelMoneyMw/check_balance.php @@ -0,0 +1,170 @@ + $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => "", + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 30, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + CURLOPT_CUSTOMREQUEST => "GET", + CURLOPT_HTTPHEADER => [ + "Accept: application/json", + "X-Country: $country", + "X-Currency: $currency", + "Authorization: Bearer $token" + ], + ]); + + $response = curl_exec($curl); + + if (curl_errno($curl)) { + $error = curl_error($curl); + curl_close($curl); + return [ + "status" => "ERROR", + "message" => "cURL Error: $error" + ]; + } + + curl_close($curl); + + // Decode response + $result = json_decode($response, true); + + // Handle invalid JSON + if (!$result) { + return [ + "status" => "ERROR", + "message" => "Invalid JSON response from Airtel API" + ]; + } + + // Check for API structure + if (!isset($result["status"])) { + return [ + "status" => "ERROR", + "message" => "Unexpected API response format".print_r($result,true) + ]; + } + + $statusCode = $result["status"]["code"] ?? null; + $message = $result["status"]["message"] ?? "Unknown error"; + + // ✅ SUCCESS case + if ($statusCode == "200" && isset($result["data"])) { + return [ + "status" => "SUCCESS", + "balance" => $result["data"]["balance"] ?? "0", + "currency" => $result["data"]["currency"] ?? $currency, + "account_status" => $result["data"]["account_status"] ?? "Unknown" + ]; + } + + // ❌ ERROR case (e.g. "User not found", "Invalid token", etc.) + return [ + "status" => "ERROR", + "message" => $message, + "code" => $statusCode, + "responseCode" => $result["status"]["response_code"] ?? null, + "resultCode" => $result["status"]["result_code"] ?? null + ]; +} + +function authenticate($baseURL, $wallet, $password) +{ + // JSON payload + $postData = json_encode([ + 'client_id' => $wallet, + 'client_secret' => $password, + 'grant_type' => "client_credentials" + ]); + + // Initialize cURL + $ch = curl_init($baseURL); + + // Set cURL options + 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) + ]); + + // Execute the request + $response = curl_exec($ch); + + // Check for cURL errors + if (curl_errno($ch)) { + curl_close($ch); + return [ + 'success' => false, + 'error' => 'Curl error: ' . curl_error($ch) + ]; + } + + // 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'] ?? [] + ]; + } +} + + +?> diff --git a/app/Library/AirtelMoneyMw/testing.php b/app/Library/AirtelMoneyMw/testing.php new file mode 100644 index 0000000..98e8d07 --- /dev/null +++ b/app/Library/AirtelMoneyMw/testing.php @@ -0,0 +1,246 @@ + $newPassword, + "new_password_confirmation" => $newPasswordConfirmation + ]; + + // Initialize cURL + $ch = curl_init($url); + + // Set cURL options + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH"); // PATCH request + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + "Authorization: Bearer " . $token, + "Content-Type: application/json" + ]); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); + + // Execute and capture response + $response = curl_exec($ch); + + // Check for errors + if (curl_errno($ch)) { + echo "cURL Error: " . curl_error($ch); + curl_close($ch); + return false; + } + + // Close connection + curl_close($ch); + + // Decode JSON response + return json_decode($response, true); +} + +function validate_msisdn($baseURL, $msisdn, $bearerToken) +{ + // Ensure proper endpoint format + $url = rtrim($baseURL, '/') . '/payments/validate/' . urlencode($msisdn); + + // Initialize cURL + $ch = curl_init($url); + + // Set cURL options + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPGET, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Authorization: Bearer ' . $bearerToken, + 'Accept: application/json' + ]); + + // Execute the request + $response = curl_exec($ch); + + // Handle cURL error + if (curl_errno($ch)) { + curl_close($ch); + return [ + 'success' => false, + 'error' => 'Curl error: ' . curl_error($ch) + ]; + } + + // Get HTTP status code + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + // Decode JSON response + $result = json_decode($response, true); + + if ($httpCode === 200 && isset($result['data']['full_name'])) { + return [ + 'success' => true, + 'full_name' => $result['data']['full_name'] + ]; + } else { + return [ + 'success' => false, + 'error' => $result['message'] ?? 'Unknown error', + 'details' => $result['errors'] ?? [] + ]; + } +} + + + +function authenticate($baseURL, $wallet, $password) +{ + // JSON payload + $postData = json_encode([ + 'client_id' => $wallet, + 'client_secret' => $password, + 'grant_type' => "client_credentials" + ]); + + // Initialize cURL + $ch = curl_init($baseURL); + + // Set cURL options + 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) + ]); + + // Execute the request + $response = curl_exec($ch); + + // Check for cURL errors + if (curl_errno($ch)) { + curl_close($ch); + return [ + 'success' => false, + 'error' => 'Curl error: ' . curl_error($ch) + ]; + } + + // 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'] ?? [] + ]; + } +} + +?> diff --git a/app/Library/AirtelMoneyMw/trans_enquiry.php b/app/Library/AirtelMoneyMw/trans_enquiry.php new file mode 100644 index 0000000..fe7e88b --- /dev/null +++ b/app/Library/AirtelMoneyMw/trans_enquiry.php @@ -0,0 +1,142 @@ + $enqURL, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => '', + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 0, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_HTTPHEADER => array( + 'Authorization:'.$token, + 'Accept: */* ', + 'X-Country: MW', + 'X-Currency: MWK' + ), +)); + +$response = curl_exec($curl); + +curl_close($curl); +return $response; +} + +function authenticate($baseURL, $wallet, $password) +{ + // JSON payload + $postData = json_encode([ + 'client_id' => $wallet, + 'client_secret' => $password, + 'grant_type' => "client_credentials" + ]); + + // Initialize cURL + $ch = curl_init($baseURL); + + // Set cURL options + 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) + ]); + + // Execute the request + $response = curl_exec($ch); + + // Check for cURL errors + if (curl_errno($ch)) { + curl_close($ch); + return [ + 'success' => false, + 'error' => 'Curl error: ' . curl_error($ch) + ]; + } + + // 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'] ?? [] + ]; + } +} + + +?> diff --git a/app/Library/Kazang.php b/app/Library/Kazang.php new file mode 100644 index 0000000..13ab576 --- /dev/null +++ b/app/Library/Kazang.php @@ -0,0 +1,63 @@ + $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => '', + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 0, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => json_encode($postfields), + CURLOPT_HTTPHEADER => array( + 'Content-Type: application/json' + ), + )); + $response = curl_exec($curl); + curl_close($curl); + return $response; + } + public function Login(){ + $kaz_config = config('kazang'); + // $url = 'https://testapi.kazang.net/apimanager/api_rest/v1/authClient'; + $url = $kaz_config['test_base_url'] . '/apimanager/api_rest/v1/authClient'; + $postfields = [ + "username" => env('KAZ_USERNAME'), + "password" => env('KAZ_PASS'), + "channel" => env('KAZ_CHANNEL'), + ]; + $session_data = $this->HttpPost($url, $postfields); + $decoded = json_decode($session_data, true); + return $decoded['session_uuid']; + } + public function get_products($kaz_session_uuid){ + // $url = 'https://testapi.kazang.net/apimanager/api_rest/v1/productList'; + $url = $url = $kaz_config['test_base_url'] . '/apimanager/api_rest/v1/productList'; + $kaz_request_reference = uniqid("_route"); + $postfields = [ + "request_reference" => $kaz_request_reference, + "session_uuid" => $kaz_session_uuid + ]; + $products = $this->HttpPost($url, $postfields); + } + + + +} + + diff --git a/app/Library/MpambaTnm/MpambaPush.php b/app/Library/MpambaTnm/MpambaPush.php new file mode 100644 index 0000000..7eaea39 --- /dev/null +++ b/app/Library/MpambaTnm/MpambaPush.php @@ -0,0 +1,193 @@ + $invoiceNumber, + "amount" => (int)$amount, + "msisdn" => $msisdn, + "description" => $description + ]; + + // Initialize cURL + $ch = curl_init($url); + + // Set cURL options + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + "Authorization: Bearer " . $token, + "Content-Type: application/json" + ]); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); + + // Execute request + $response = curl_exec($ch); + + // Check for cURL errors + if (curl_errno($ch)) { + echo "cURL Error: " . curl_error($ch); + curl_close($ch); + return false; + } + + // Close connection + curl_close($ch); + + // Decode and return response + return json_decode($response, true); + } + + public function changePassword($baseURL, $token,$newPassword, $newPasswordConfirmation) { + // Endpoint URL + $url = rtrim($baseURL, "/") . "/password"; + + // Prepare data + $data = [ + "new_password" => $newPassword, + "new_password_confirmation" => $newPasswordConfirmation + ]; + + // Initialize cURL + $ch = curl_init($url); + + // Set cURL options + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH"); // PATCH request + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + "Authorization: Bearer " . $token, + "Content-Type: application/json" + ]); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); + + // Execute and capture response + $response = curl_exec($ch); + + // Check for errors + if (curl_errno($ch)) { + echo "cURL Error: " . curl_error($ch); + curl_close($ch); + return false; + } + + // Close connection + curl_close($ch); + + // Decode JSON response + return json_decode($response, true); + } + + public function validate_msisdn($baseURL, $msisdn, $bearerToken){ + // Ensure proper endpoint format + $url = rtrim($baseURL, '/') . '/payments/validate/' . urlencode($msisdn); + + // Initialize cURL + $ch = curl_init($url); + + // Set cURL options + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPGET, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Authorization: Bearer ' . $bearerToken, + 'Accept: application/json' + ]); + + // Execute the request + $response = curl_exec($ch); + + // Handle cURL error + if (curl_errno($ch)) { + curl_close($ch); + return [ + 'success' => false, + 'error' => 'Curl error: ' . curl_error($ch) + ]; + } + + // Get HTTP status code + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + // Decode JSON response + $result = json_decode($response, true); + + if ($httpCode === 200 && isset($result['data']['full_name'])) { + return [ + 'success' => true, + 'full_name' => $result['data']['full_name'] + ]; + } else { + return [ + 'success' => false, + 'error' => $result['message'] ?? 'Unknown error', + 'details' => $result['errors'] ?? [] + ]; + } + } + + public function authenticate($baseURL, $wallet, $password){ + // Endpoint URL + $url = rtrim($baseURL, '/') . '/authenticate'; + + // JSON payload + $postData = json_encode([ + 'wallet' => $wallet, + 'password' => $password + ]); + + // Initialize cURL + $ch = curl_init($url); + + // Set cURL options + 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) + ]); + + // Execute the request + $response = curl_exec($ch); + + // Check for cURL errors + if (curl_errno($ch)) { + curl_close($ch); + return [ + 'success' => false, + 'error' => 'Curl error: ' . curl_error($ch) + ]; + } + + // 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['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'] ?? [] + ]; + } + } + +} +?> \ No newline at end of file diff --git a/app/Library/MpambaTnm/callback.php b/app/Library/MpambaTnm/callback.php new file mode 100644 index 0000000..ee825e8 --- /dev/null +++ b/app/Library/MpambaTnm/callback.php @@ -0,0 +1,50 @@ + "callback received"]); + +} else { + // Missing required fields + http_response_code(400); + echo json_encode(["error" => "Invalid callback payload"]); +} + +?> diff --git a/app/Library/MpambaTnm/index.php b/app/Library/MpambaTnm/index.php new file mode 100644 index 0000000..3ca44d0 --- /dev/null +++ b/app/Library/MpambaTnm/index.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/app/Library/MpambaTnm/testing.php b/app/Library/MpambaTnm/testing.php new file mode 100644 index 0000000..ff9c2f7 --- /dev/null +++ b/app/Library/MpambaTnm/testing.php @@ -0,0 +1,214 @@ + $invoiceNumber, + "amount" => (int)$amount, + "msisdn" => $msisdn, + "description" => $description + ]; + + // Initialize cURL + $ch = curl_init($url); + + // Set cURL options + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + "Authorization: Bearer " . $token, + "Content-Type: application/json" + ]); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); + + // Execute request + $response = curl_exec($ch); + + // Check for cURL errors + if (curl_errno($ch)) { + echo "cURL Error: " . curl_error($ch); + curl_close($ch); + return false; + } + + // Close connection + curl_close($ch); + + // Decode and return response + return json_decode($response, true); +} + +function changePassword($baseURL, $token,$newPassword, $newPasswordConfirmation) { + // Endpoint URL + $url = rtrim($baseURL, "/") . "/password"; + + // Prepare data + $data = [ + "new_password" => $newPassword, + "new_password_confirmation" => $newPasswordConfirmation + ]; + + // Initialize cURL + $ch = curl_init($url); + + // Set cURL options + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH"); // PATCH request + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + "Authorization: Bearer " . $token, + "Content-Type: application/json" + ]); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); + + // Execute and capture response + $response = curl_exec($ch); + + // Check for errors + if (curl_errno($ch)) { + echo "cURL Error: " . curl_error($ch); + curl_close($ch); + return false; + } + + // Close connection + curl_close($ch); + + // Decode JSON response + return json_decode($response, true); +} + +function validate_msisdn($baseURL, $msisdn, $bearerToken) +{ + // Ensure proper endpoint format + $url = rtrim($baseURL, '/') . '/payments/validate/' . urlencode($msisdn); + + // Initialize cURL + $ch = curl_init($url); + + // Set cURL options + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPGET, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Authorization: Bearer ' . $bearerToken, + 'Accept: application/json' + ]); + + // Execute the request + $response = curl_exec($ch); + + // Handle cURL error + if (curl_errno($ch)) { + curl_close($ch); + return [ + 'success' => false, + 'error' => 'Curl error: ' . curl_error($ch) + ]; + } + + // Get HTTP status code + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + // Decode JSON response + $result = json_decode($response, true); + + if ($httpCode === 200 && isset($result['data']['full_name'])) { + return [ + 'success' => true, + 'full_name' => $result['data']['full_name'] + ]; + } else { + return [ + 'success' => false, + 'error' => $result['message'] ?? 'Unknown error', + 'details' => $result['errors'] ?? [] + ]; + } +} + + + +function authenticate($baseURL, $wallet, $password) +{ + // Endpoint URL + $url = rtrim($baseURL, '/') . '/authenticate'; + + // JSON payload + $postData = json_encode([ + 'wallet' => $wallet, + 'password' => $password + ]); + + // Initialize cURL + $ch = curl_init($url); + + // Set cURL options + 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) + ]); + + // Execute the request + $response = curl_exec($ch); + + // Check for cURL errors + if (curl_errno($ch)) { + curl_close($ch); + return [ + 'success' => false, + 'error' => 'Curl error: ' . curl_error($ch) + ]; + } + + // 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['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'] ?? [] + ]; + } +} + +?> diff --git a/app/Library/MpambaTnm/transaction_check.php b/app/Library/MpambaTnm/transaction_check.php new file mode 100644 index 0000000..edb14f6 --- /dev/null +++ b/app/Library/MpambaTnm/transaction_check.php @@ -0,0 +1,58 @@ + $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + "Authorization: Bearer " . $bearerToken, + "Accept: application/json" + ] + ]); + + // Execute the request + $response = curl_exec($ch); + + // Handle errors + if (curl_errno($ch)) { + echo "cURL Error: " . curl_error($ch); + curl_close($ch); + return null; + } + + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + // Check for successful response + if ($httpCode === 200 && $response) { + return json_decode($response, true); + } else { + echo "Request failed. HTTP Code: " . $httpCode . "\nResponse: " . $response; + return null; + } +} + +?> diff --git a/app/Models/KazangApi.php b/app/Models/KazangApi.php new file mode 100644 index 0000000..6ddcef1 --- /dev/null +++ b/app/Models/KazangApi.php @@ -0,0 +1,10 @@ + $org_id, - "msisdn" => $msisdn, - "reference_id" => $reference_id, - "amount" => $amount, - "product_name" => $product_name, - "result_code" => $result_code, - "ussd_push_result_code" => $result_code, - "last_updated_by" => 'clientRequest' + "org_id" => $org_id, + "msisdn" => $msisdn, + "reference_id" => $reference_id, + "amount" => $amount, + "product_name" => $product_name, + "result_code" => $result_code, + "ussd_push_result_code" => $result_code, + "last_updated_by" => 'clientRequest' ]; $result = Models\AirtelTransaction::create($bind); return ($result) ? 1 : 0; diff --git a/app/Models/User.php b/app/Models/User.php index e3d1687..7f05c69 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -9,7 +9,7 @@ use Illuminate\Notifications\Notifiable; class User extends Authenticatable { use Notifiable; - + public $table = 'auth_users'; /** * The attributes that are mass assignable. * diff --git a/config/airtelmoney.php b/config/airtelmoney.php new file mode 100644 index 0000000..41e0800 --- /dev/null +++ b/config/airtelmoney.php @@ -0,0 +1,16 @@ + "94351d4d-4909-4056-ad9d-8052a332d6b9", + "clientSecret" => "bf665590-2519-49af-8d1f-7cd0dce1dc7a", + 'payments_url' => "https://openapiuat.airtel.africa/merchant/v1/payments", + //CONTINENTAL CAPITAL + "clientID" => "9ff18a6d-331e-4ec5-9ecc-4e512e13747c", + "clientSecret" => "40f44254-10e7-4eb8-b161-38125117f4ba", + "authURL" => "https://openapiuat.airtel.africa/auth/oauth2/token", + + +] + + ?> \ No newline at end of file diff --git a/config/auth.php b/config/auth.php index ba1a4d8..d0e9c1a 100644 --- a/config/auth.php +++ b/config/auth.php @@ -14,7 +14,7 @@ return [ */ 'defaults' => [ - 'guard' => 'web', + 'guard' => 'api', 'passwords' => 'users', ], @@ -73,7 +73,7 @@ return [ // 'users' => [ // 'driver' => 'database', - // 'table' => 'users', + // 'table' => 'auth_users', // ], ], diff --git a/config/kazang.php b/config/kazang.php new file mode 100644 index 0000000..f70e42a --- /dev/null +++ b/config/kazang.php @@ -0,0 +1,8 @@ + 'https://testapi.kazang.net', + 'production_base_url' => 'https://testapi.kazang.net', +]; + + +?> \ No newline at end of file diff --git a/info.md b/info.md new file mode 100644 index 0000000..b46deb2 --- /dev/null +++ b/info.md @@ -0,0 +1,11 @@ +# Martha MTN +- +260963722831 + +# Test Numbers in Postman Collection +- airtel : 260978981953 +- mtn : 260981112134 +- zamtel test number : 260950003905 + +# New Tables +- kazang_sessions +- transactions_kazang \ No newline at end of file diff --git a/kazang_product_list.md b/kazang_product_list.md new file mode 100644 index 0000000..c62d85e --- /dev/null +++ b/kazang_product_list.md @@ -0,0 +1,674 @@ +{ + "product_list": [ + { + "product_id": 1478, + "product_category": "Airtime", + "product_description": "Airtel ZMW 10", + "method_name": "buyVoucher", + "product_value": 10.0, + "product_priority": 10, + "product_provider": "Airtel" + }, + { + "product_id": 1481, + "product_category": "Airtime", + "product_description": "Airtel ZMW 100", + "method_name": "buyVoucher", + "product_value": 100.0, + "product_priority": 10, + "product_provider": "Airtel" + }, + { + "product_id": 1479, + "product_category": "Airtime", + "product_description": "Airtel ZMW 20", + "method_name": "buyVoucher", + "product_value": 20.0, + "product_priority": 10, + "product_provider": "Airtel" + }, + { + "product_id": 1480, + "product_category": "Airtime", + "product_description": "Airtel ZMW 50", + "method_name": "buyVoucher", + "product_value": 50.0, + "product_priority": 10, + "product_provider": "Airtel" + }, + { + "product_id": 1490, + "product_category": "Airtime", + "product_description": "CellZ ZMW 10", + "method_name": "buyVoucher", + "product_value": 10.0, + "product_priority": 10, + "product_provider": "CellZ Zambia" + }, + { + "product_id": 1492, + "product_category": "Airtime", + "product_description": "CellZ ZMW 100", + "method_name": "buyVoucher", + "product_value": 100.0, + "product_priority": 10, + "product_provider": "CellZ Zambia" + }, + { + "product_id": 1491, + "product_category": "Airtime", + "product_description": "CellZ ZMW 50", + "method_name": "buyVoucher", + "product_value": 50.0, + "product_priority": 10, + "product_provider": "CellZ Zambia" + }, + { + "product_id": 1483, + "product_category": "Airtime", + "product_description": "MTN ZMW 10", + "method_name": "buyVoucher", + "product_value": 10.0, + "product_priority": 10, + "product_provider": "MTN Zambia" + }, + { + "product_id": 1486, + "product_category": "Airtime", + "product_description": "MTN ZMW 100", + "method_name": "buyVoucher", + "product_value": 100.0, + "product_priority": 10, + "product_provider": "MTN Zambia" + }, + { + "product_id": 1484, + "product_category": "Airtime", + "product_description": "MTN ZMW 20", + "method_name": "buyVoucher", + "product_value": 20.0, + "product_priority": 10, + "product_provider": "MTN Zambia" + }, + { + "product_id": 1487, + "product_category": "Airtime", + "product_description": "MTN ZMW 200", + "method_name": "buyVoucher", + "product_value": 200.0, + "product_priority": 10, + "product_provider": "MTN Zambia" + }, + { + "product_id": 1485, + "product_category": "Airtime", + "product_description": "MTN ZMW 50", + "method_name": "buyVoucher", + "product_value": 50.0, + "product_priority": 10, + "product_provider": "MTN Zambia" + }, + { + "product_id": 20004, + "product_category": "Electricity", + "product_description": "Buy Electricity", + "method_name": "buyElectricity", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "" + }, + { + "product_id": 20005, + "product_category": "Electricity", + "product_description": "Reissue", + "method_name": "reissueElectricity", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "" + }, + { + "product_id": 20007, + "product_category": "Electricity", + "product_description": "Reprint Last", + "method_name": "reprintElectricity", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "" + }, + { + "product_id": 20010, + "product_category": "Electricity", + "product_description": "Test Meter Number", + "method_name": "testElectricity", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "" + }, + { + "product_id": 20002, + "product_category": "Reports", + "product_description": "Query Bank Details", + "method_name": "query", + "product_value": 0.0, + "product_priority": 0, + "product_provider": "Banking" + }, + { + "product_id": 20000, + "product_category": "Reports", + "product_description": "Cashup Report", + "method_name": "report", + "product_value": 0.0, + "product_priority": 0, + "product_provider": "Cashup" + }, + { + "product_id": 20001, + "product_category": "Reports", + "product_description": "Cashup Reset", + "method_name": "report", + "product_value": 0.0, + "product_priority": 0, + "product_provider": "Cashup" + }, + { + "product_id": 20003, + "product_category": "Reports", + "product_description": "Query Balance", + "method_name": "query", + "product_value": 0.0, + "product_priority": 0, + "product_provider": "Client" + }, + { + "product_id": 20011, + "product_category": "Reports", + "product_description": "Transaction History", + "method_name": "transactionHistoryQuery", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Client" + }, + { + "product_id": 20016, + "product_category": "Reports", + "product_description": "Mini Statement Today", + "method_name": "query", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Mini Statements" + }, + { + "product_id": 20017, + "product_category": "Reports", + "product_description": "Mini Statement Yesterday", + "method_name": "query", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Mini Statements" + }, + { + "product_id": 20018, + "product_category": "Reports", + "product_description": "Mini Statement Month To Date", + "method_name": "query", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Mini Statements" + }, + { + "product_id": 20019, + "product_category": "Reports", + "product_description": "Mini Statement Previous Month", + "method_name": "query", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Mini Statements" + }, + { + "product_id": 1607, + "product_category": "Pinless Airtime", + "product_description": "Airtel Zambia Pinless Airtime", + "method_name": "directRechargeAirtime", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Airtel Zambia Pinless" + }, + { + "product_id": 1521, + "product_category": "Pinless Airtime", + "product_description": "MTN Zambia Pinless Airtime", + "method_name": "directRechargeAirtime", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "MTN Zambia Pinless" + }, + { + "product_id": 1648, + "product_category": "Agency Banking", + "product_description": "NFS Sim Deposit", + "method_name": "nfsCashIn", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "NFS Simulator" + }, + { + "product_id": 1647, + "product_category": "Agency Banking", + "product_description": "NFS Sim Transfer", + "method_name": "nfsTransfer", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "NFS Simulator" + }, + { + "product_id": 1649, + "product_category": "Agency Banking", + "product_description": "NFS Sim Withdraw", + "method_name": "nfsATMCashOut", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "NFS Simulator" + }, + { + "product_id": 1749, + "product_category": "Airtel Money", + "product_description": "Airtel Money Quick Step 2", + "method_name": "airtelPayQuickQuery", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Airtel Pay" + }, + { + "product_id": 1663, + "product_category": "Airtel Money", + "product_description": "Airtel Money Step 1", + "method_name": "airtelPayPayment", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Airtel Pay" + }, + { + "product_id": 1664, + "product_category": "Airtel Money", + "product_description": "Airtel Money Step 2", + "method_name": "airtelPayQuery", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Airtel Pay" + }, + { + "product_id": 1603, + "product_category": "Data", + "product_description": "MTN Zambia Bi - Monthly 100 GB", + "method_name": "directRechargeData", + "product_value": 1500.0, + "product_priority": 10, + "product_provider": "MTN Zambia Data" + }, + { + "product_id": 1599, + "product_category": "Data", + "product_description": "MTN Zambia Bi - Monthly 35 GB", + "method_name": "directRechargeData", + "product_value": 700.0, + "product_priority": 10, + "product_provider": "MTN Zambia Data" + }, + { + "product_id": 1601, + "product_category": "Data", + "product_description": "MTN Zambia Bi - Monthly 50 GB", + "method_name": "directRechargeData", + "product_value": 900.0, + "product_priority": 10, + "product_provider": "MTN Zambia Data" + }, + { + "product_id": 1581, + "product_category": "Data", + "product_description": "MTN Zambia Daily 20 MB", + "method_name": "directRechargeData", + "product_value": 2.0, + "product_priority": 10, + "product_provider": "MTN Zambia Data" + }, + { + "product_id": 1583, + "product_category": "Data", + "product_description": "MTN Zambia Daily 200 MB", + "method_name": "directRechargeData", + "product_value": 5.0, + "product_priority": 10, + "product_provider": "MTN Zambia Data" + }, + { + "product_id": 1585, + "product_category": "Data", + "product_description": "MTN Zambia Daily 350 MB", + "method_name": "directRechargeData", + "product_value": 7.0, + "product_priority": 10, + "product_provider": "MTN Zambia Data" + }, + { + "product_id": 1595, + "product_category": "Data", + "product_description": "MTN Zambia Monthly 12 GB", + "method_name": "directRechargeData", + "product_value": 200.0, + "product_priority": 10, + "product_provider": "MTN Zambia Data" + }, + { + "product_id": 1597, + "product_category": "Data", + "product_description": "MTN Zambia Monthly 25 GB", + "method_name": "directRechargeData", + "product_value": 400.0, + "product_priority": 10, + "product_provider": "MTN Zambia Data" + }, + { + "product_id": 1593, + "product_category": "Data", + "product_description": "MTN Zambia Monthly 5 GB", + "method_name": "directRechargeData", + "product_value": 100.0, + "product_priority": 10, + "product_provider": "MTN Zambia Data" + }, + { + "product_id": 1591, + "product_category": "Data", + "product_description": "MTN Zambia Weekly 10 GB", + "method_name": "directRechargeData", + "product_value": 150.0, + "product_priority": 10, + "product_provider": "MTN Zambia Data" + }, + { + "product_id": 1587, + "product_category": "Data", + "product_description": "MTN Zambia Weekly 2.5 GB", + "method_name": "directRechargeData", + "product_value": 50.0, + "product_priority": 10, + "product_provider": "MTN Zambia Data" + }, + { + "product_id": 1589, + "product_category": "Data", + "product_description": "MTN Zambia Weekly 6 GB", + "method_name": "directRechargeData", + "product_value": 100.0, + "product_priority": 10, + "product_provider": "MTN Zambia Data" + }, + { + "product_id": 1577, + "product_category": "Gaming", + "product_description": "Zambian Lotto Payout Ticket", + "method_name": "payoutLottoZambia", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Zambian Lotto" + }, + { + "product_id": 1571, + "product_category": "Gaming", + "product_description": "Zambian Lotto Quick Pick", + "method_name": "playLottoZambiaQuickPick", + "product_value": 5.0, + "product_priority": 10, + "product_provider": "Zambian Lotto" + }, + { + "product_id": 1573, + "product_category": "Gaming", + "product_description": "Zambian Lotto Self Pick", + "method_name": "playLottoZambiaSelfPick", + "product_value": 5.0, + "product_priority": 10, + "product_provider": "Zambian Lotto" + }, + { + "product_id": 1579, + "product_category": "Gaming", + "product_description": "Zambian Lotto View Draw Ticket", + "method_name": "viewDrawLottoZambia", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Zambian Lotto" + }, + { + "product_id": 1506, + "product_category": "Insurance", + "product_description": "Muende Bwino Travel Insurance", + "method_name": "buyTravelInsurance", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "PICZ" + }, + { + "product_id": 1612, + "product_category": "Mobile Money", + "product_description": "MOMO Pay Step 1", + "method_name": "mtnDebit", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "MOMO Pay" + }, + { + "product_id": 1609, + "product_category": "Mobile Money", + "product_description": "MTN Withdraw Step 1", + "method_name": "mtnCashOut", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "MTN Money" + }, + { + "product_id": 1610, + "product_category": "Mobile Money", + "product_description": "MTN Withdraw Step 2", + "method_name": "mtnCashOutApproval", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "MTN Money" + }, + { + "product_id": 1740, + "product_category": "Mobile Money", + "product_description": "SPENN Cashin", + "method_name": "spennDeposit", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "SPENN Cashin" + }, + { + "product_id": 1742, + "product_category": "Mobile Money", + "product_description": "SPENN Cashout Approval Zambia", + "method_name": "spennCashOutApproval", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "SPENN Cashout" + }, + { + "product_id": 1741, + "product_category": "Mobile Money", + "product_description": "SPENN Cashout Zambia", + "method_name": "spennCashOut", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "SPENN Cashout" + }, + { + "product_id": 1665, + "product_category": "Mobile Money", + "product_description": "Zamtel Kwacha Deposit", + "method_name": "zamtelMoneyCashIn", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Zamtel Kwacha" + }, + { + "product_id": 1666, + "product_category": "Mobile Money", + "product_description": "Zamtel Kwacha Withdraw", + "method_name": "zamtelMoneyCashOut", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Zamtel Kwacha" + }, + { + "product_id": 1427, + "product_category": "Money Transfer", + "product_description": "Money Receive", + "method_name": "receiveMoney", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Kazang Money Transfer" + }, + { + "product_id": 1426, + "product_category": "Money Transfer", + "product_description": "Money Send", + "method_name": "sendMoney", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Kazang Money Transfer" + }, + { + "product_id": 1563, + "product_category": "Money Transfer", + "product_description": "Cash Out Receive", + "method_name": "receiveMoney", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Kazang Money Transfer Cash Out" + }, + { + "product_id": 1561, + "product_category": "Money Transfer", + "product_description": "Cash Out Send", + "method_name": "sendMoney", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Kazang Money Transfer Cash Out" + }, + { + "product_id": 20036, + "product_category": "Payments", + "product_description": "Box Office Payment", + "method_name": "dstvVariableAmountPayment", + "product_value": 0.0, + "product_priority": 0, + "product_provider": "DSTV Zambia" + }, + { + "product_id": 20035, + "product_category": "Payments", + "product_description": "Pay Any Amount", + "method_name": "dstvVariableAmountPayment", + "product_value": 0.0, + "product_priority": 0, + "product_provider": "DSTV Zambia" + }, + { + "product_id": 1534, + "product_category": "Payments", + "product_description": "PayGo Power Tokens", + "method_name": "makeAzuriPayment", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Kazang Solar" + }, + { + "product_id": 1758, + "product_category": "Payments", + "product_description": "MOMO Pay Quick Step 2", + "method_name": "mtnDebitQuickApproval", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "MOMO Pay" + }, + { + "product_id": 1613, + "product_category": "Payments", + "product_description": "MOMO Pay Step 2", + "method_name": "mtnDebitApproval", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "MOMO Pay" + }, + { + "product_id": 1608, + "product_category": "Payments", + "product_description": "MTN Cash In Zambia", + "method_name": "mtnCashIn", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "MTN Money" + }, + { + "product_id": 1567, + "product_category": "Payments", + "product_description": "Topstar Zambia", + "method_name": "topstarPayment", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Topstar" + }, + { + "product_id": 1706, + "product_category": "Payments", + "product_description": "Zamtel Pay", + "method_name": "zamtelMoneyPay", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Zamtel Kwacha" + }, + { + "product_id": 1698, + "product_category": "Payments", + "product_description": "eLevy Payment", + "method_name": "elevyPayment", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "eLevy" + }, + { + "product_id": 1674, + "product_category": "Water", + "product_description": "Lusaka Water Payment Zambia", + "method_name": "lusakaWaterPayment", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Lusaka Water" + }, + { + "product_id": 1685, + "product_category": "Water", + "product_description": "Mulonga Water and Sanitation Company", + "method_name": "savannacomWaterPayment", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Savannacom Water" + }, + { + "product_id": 1681, + "product_category": "Water", + "product_description": "Nkana Water and Sanitation Company", + "method_name": "savannacomWaterPayment", + "product_value": 0.0, + "product_priority": 10, + "product_provider": "Savannacom Water" + } + ], + "response_code": "0", + "balance": "20000.00", + "request_reference": "23444", + "product_list_hash": "4b94bd115a87714f253e1da59dd22157bf1b44fc117" +} \ No newline at end of file diff --git a/public/logs/2022-12-16_api_response_logs.txt b/public/logs/2022-12-16_api_response_logs.txt new file mode 100644 index 0000000..e11c64a --- /dev/null +++ b/public/logs/2022-12-16_api_response_logs.txt @@ -0,0 +1 @@ +{"wallet_msisdn":"978981953","confirmation_number":"333720","request_reference":"167116923","customer_last_name":"Picard","response_code":"0","amount":"0.05","confirmation_message":"\nPlease confirm\nCust. Msisdn: +260978981953\nCust. First Name: Jean-Luc\nCust. Last name: Picard\nAmount: 0.05\n\n\n\n","customer_first_name":"Jean-Luc","balance":"20490.05"} diff --git a/resources/views/test.blade.php b/resources/views/test.blade.php new file mode 100644 index 0000000..303f0d8 --- /dev/null +++ b/resources/views/test.blade.php @@ -0,0 +1,90 @@ +@extends('layouts.master') + @section('page_title') + @if(isset($page_title)) + {{ $page_title }} + @endif + @endsection + +@section('content') + + +
+
+
+
+

Default Table

+
Using the most basic table markup, here’s how .table-based tables look in Bootstrap. All table styles are inherited in Bootstrap 4, meaning any nested tables will be styled in the same manner as the parent.
+
Table With Outside Padding
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#FirstLastHandle
1MarkOtto@mdo
2JacobThornton@fat
3Larrythe Bird@twitter
+
+
Table Without Outside Padding
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#FirstLastHandle
1MarkOtto@mdo
2JacobThornton@fat
3Larrythe Bird@twitter
+
+
+
+@endsection + +@section('javascript') + +@endsection diff --git a/routes/api.php b/routes/api.php index 88c6405..46b8699 100644 --- a/routes/api.php +++ b/routes/api.php @@ -18,5 +18,16 @@ Route::middleware('auth:api')->get('/user', function (Request $request) { }); Route::group(['middleware' =>['auth:api']], function(){ - Route::post('collect', 'MoneyCollectionController@collect')->name('collect'); -}); \ No newline at end of file + + Route::post('collect/airtel', 'AirtelMoneyMalawiController@collect'); + + // Route::post('test', 'MoneyCollectionController@collect'); + // Route::post('collect', 'MoneyCollectionController@collect')->name('collect'); + // Route::post('confirm', 'ConfirmCollectionController@confirm')->name('confirm'); + + + +}); + + +// Can we also test MTN via Zamtel 260967080547 \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index a493fa8..c0b1b3a 100644 --- a/routes/web.php +++ b/routes/web.php @@ -21,3 +21,5 @@ Auth::routes(['register' => false]); Route::get('/home', 'HomeController@index')->name('home'); +Route::get('tester', 'KazTestController@main'); +Route::get('collect-web', 'MoneyCollectionController@collect')->name('collect'); \ No newline at end of file