client = new Client([ 'base_uri' => $this->baseURL, 'timeout' => $this->timeout, 'http_errors' => false, 'verify' => false, // Disable SSL Certification verification ]); } /** * @OA\Get( * path="/ynote/methods", * summary="Afficher la liste des methodes de paiment de Ynote", * tags={"Ynote"}, * security={{"api_key":{}}}, * @OA\Response( * response=200, * description="OK", * @OA\JsonContent( * ref="#/components/schemas/ApiResponse", * example = { * "status" : 200, * "response" : {"hasWebview": true, "methods": {"Orange": "Orange"}}, * "error":null * } * ) * ) * ) */ public function getMethods() { return $this->successResponse([ 'hasWebview' => true, 'methods' => [ 'Orange' => 'Orange' ] ] ); } /* * Init payment and provide iLink World checkout page to handle payment */ public function initPay(Request $request) { $this->validate($request, [ // 'aggregator_id' => 'required|integer|exists:payment_aggregators,id', 'amount' => 'required|numeric|min:5', 'currency' => 'required|string|size:3', 'customer_id' => 'required|integer', 'customer_email' => 'required|email', 'customer_name' => 'nullable|string', 'customer_surname' => 'required|string', 'customer_phone_number' => 'required|string', 'customer_address' => 'required|string', 'customer_country' => 'required|string|size:2', 'reason' => 'required|string', ]); $aggregator = PaymentAggregator::where('name','like','%ynote%')->firstOrFail(); $transaction_id = $this->getTransactionID(); $payment_method = 'Orange'; $customer_phone_number = $request->input('customer_phone_number'); if(str_contains($customer_phone_number,'+237')){ $customer_phone_number = substr($customer_phone_number,4); } do{ $payment_token = Str::random(64); }while(PaymentTransaction::where('payment_token', $payment_token)->exists()); $payment_url = route('checkout',['payment_token' => $payment_token]); PaymentTransaction::create([ 'aggregator_id' => $aggregator->id, "currency" => $request->input('currency'), "transaction_id" => $transaction_id, "amount" => $request->input('amount'), "payment_method" => $payment_method, "payment_url" => $payment_url, 'payment_token' => $payment_token, 'status' => PaymentTransactionStatus::INITIATED, "reason" => $request->input('reason'), "customer_id" => $request->input('customer_id'), "customer_name" => $request->input('customer_name'), "customer_surname" => $request->input('customer_surname'), "customer_email" => $request->input('customer_email'), "customer_phone_number" => $customer_phone_number, "customer_address" => $request->input('customer_address'), "customer_city" => $request->input('customer_city'), "customer_country" => $request->input('customer_country'), "customer_state" => $request->input('customer_state'), "customer_zip_code" => $request->input('customer_zip_code'), "payment_endpoint" => route('ynote.checkoutPay'), "payment_verify_endpoint" => route('ynote.status'), ]); return $this->successResponse([ 'message' => 'Payment initiated', 'payment_url' => $payment_url ]); } public function checkoutPay(Request $request) { $this->validate($request, [ 'payment_token' => 'required|string|exists:payment_transactions,payment_token', 'phone_number' => 'required|string', ]); $token = $request->input('payment_token'); $transaction = PaymentTransaction::where('payment_token', $token) ->where('status', PaymentTransactionStatus::INITIATED)->firstOrFail(); $customer_phone_number = $request->input('phone_number'); if(str_contains($customer_phone_number,'+237')){ $customer_phone_number = substr($customer_phone_number,4); } // Get Access Token $accessTokenResponse = $this->client->post('/token', [ 'headers' => [ 'Authorization' => 'Basic '.base64_encode($this->username.':'.$this->password), ], 'form_params' => [ 'grant_type' => 'client_credentials', ] ]); $responseBody = json_decode($accessTokenResponse->getBody()->getContents()); if ($accessTokenResponse->getStatusCode() == 200) { $accessToken = $responseBody->access_token; // Init Payment $initResponse = $this->client->post('/omcoreapis/1.0.2/mp/init', [ 'headers' => [ 'Authorization' => 'Bearer '.$accessToken, 'X-AUTH-TOKEN' => $this->X_AUTH_TOKEN ], ]); $responseBody = json_decode($initResponse->getBody()->getContents()); if ($initResponse->getStatusCode() == 200) { $payToken = $responseBody->data->payToken; // Make Payment $makeResponse = $this->client->post('/omcoreapis/1.0.2/mp/pay', [ 'headers' => [ 'Authorization' => 'Bearer ' . $accessToken, 'X-AUTH-TOKEN' => $this->X_AUTH_TOKEN ], 'json' => [ 'notifUrl' => 'http://28f8-102-244-222-34.ngrok-free.app/ynote/webhook' ,// route('ynote.webhook'), 'channelUserMsisdn' => $this->channelUserMsisdn, 'pin' => $this->PIN, 'amount' => ''.intval(ceil(floatval($transaction->amount))), 'subscriberMsisdn' => $customer_phone_number, 'orderId' => $transaction->transaction_id, 'description' => $transaction->reason, 'payToken' => $payToken ] ]); $responseBody = json_decode($makeResponse->getBody()->getContents()); if ($makeResponse->getStatusCode() == 200) { $transaction->update([ 'aggregator_payment_ref' => $responseBody->data->txnid, 'aggregator_payment_token' => $payToken, 'status' => strtoupper($responseBody->data->status), "customer_phone_number" => $customer_phone_number, ]); return redirect()->route('checkout',['payment_token' => $token]); }else{ //If error regenerate transaction id to avoid 'Numero de commande deja utilisé' $transaction->update([ 'transaction_id' => $this->getTransactionID() ]); } } } if(!empty($responseBody->error)){ //Convert into single line session()->flash('error',str_replace(array("\n", "\r"), '',$responseBody->error_description)); return redirect()->route('checkout',['payment_token' => $token]); } Log::error(json_encode($responseBody)); session()->flash('error',__('errors.unexpected_error')); return redirect()->route('checkout',['payment_token' => $token]); } public function capturePaymentResult(Request $request) { Log::info("capture"); Log::warning(json_encode($request->all())); $this->validate($request, [ 'txnid' => 'required|string' ]); $transaction = PaymentTransaction::where('aggregator_payment_ref',$request->input('txnid'))->first(); return $this->getPaymentStatus($transaction); } public function getPaymentStatus(Request $request) { $this->validate($request, [ 'transaction_id' => 'required|string|exists:payment_transactions,transaction_id', 'verify_btn' => 'nullable|boolean' ]); $transaction = PaymentTransaction::where('transaction_id',$request->input('transaction_id'))->first(); $verify_btn = $request->input('verify_btn'); try { // Si le paiement fait plus de 5 min on l'annule if($transaction->status == PaymentTransactionStatus::PENDING && $transaction->created_at->diffInMinutes(Carbon::now()) > 5){ $transaction->update([ 'status' => PaymentTransactionStatus::CANCELLED ]); } // Get Access Token $accessTokenResponse = $this->client->post('/token', [ 'headers' => [ 'Authorization' => 'Basic '.base64_encode($this->username.':'.$this->password), ], 'form_params' => [ 'grant_type' => 'client_credentials', ] ]); $responseBody = json_decode($accessTokenResponse->getBody()->getContents()); if ($accessTokenResponse->getStatusCode() == 200) { $accessToken = $responseBody->access_token; $response = $this->client->get('/omcoreapis/1.0.2/mp/paymentstatus/'.$transaction->aggregator_payment_token, [ 'headers' => [ 'Authorization' => 'Bearer '.$accessToken, 'X-AUTH-TOKEN' => $this->X_AUTH_TOKEN ], ]); $responseData = json_decode($response->getBody()->getContents()); $responseCode = $response->getStatusCode(); Log::info(json_encode($responseData)); Log::info(json_encode($responseCode)); Log::info(json_encode([ 'Authorization' => 'Bearer '.$accessToken, 'X-AUTH-TOKEN' => $this->X_AUTH_TOKEN ])); Log::info(json_encode($transaction->aggregator_payment_token)); Log::info("Veriication de paement"); if ($responseCode == 200) { $status = strtoupper($responseData->data->status); if(str_contains($status,'SUCCESS')){ $status = PaymentTransactionStatus::ACCEPTED; } $transaction->update([ 'status' => $status, 'payment_date' => $responseData->data->transaction_date ?? null, ]); } } } catch (Throwable $e) { Log::info("Get Ynote Payment Status Error"); Log::info($e); $transaction->update([ 'status' => PaymentTransactionStatus::REFUSED ]); } if($verify_btn){ return redirect()->route('checkout',['payment_token' => $transaction->payment_token]); }else { Log::warning($transaction->status); if ($transaction->status == PaymentTransactionStatus::ACCEPTED) { return [ 'message' => "Payment accepted", 'status' => 1, 'refresh' => true, ]; } else { return [ 'message' => "Payment failed", 'status' => 0, 'refresh' => $transaction->status == PaymentTransactionStatus::PENDING ]; } } } }