client = new Client([ 'base_uri' => config('variables.yoomee_api_v2_url'), 'timeout' => $this->timeout, 'http_errors' => false ]); } /** * @OA\Get( * path="/yoomee/v2/methods", * summary="Afficher la liste des methodes de paiment de Yoomee", * tags={"Yoomee"}, * security={{"api_key":{}}}, * @OA\Response( * response=200, * description="OK", * @OA\JsonContent( * ref="#/components/schemas/ApiResponse", * example = { * "status" : 200, * "response" : {"hasWebview": true, "methods": {"Yoomee": "Yoomee", "MTN": "MTN" , "Orange": "Orange", "EU" : "EU"}}, * "error":null * } * ) * ) * ) */ public function getMethods() { $response = $this->client->get('providers/v1'); $providers = json_decode($response->getBody()->getContents()); // $providers = ["Yoomee","MTN","Orange","EU"]; $methods = []; foreach ($providers as $provider){ $key = 'providers.'.$provider; $method['title'] = Lang::has($key) ? __($key) : $provider; $method['value'] = $provider; $methods[] = $method; } return $this->successResponse([ 'hasWebview' => true, 'methods' => $methods ] ); } /* * 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', 'payment_method' => 'required|string', 'customer_id' => 'required|integer', 'customer_email' => 'required|email', 'customer_name' => 'required|string', 'customer_surname' => 'required|string', 'customer_phone_number' => 'required|string', 'customer_address' => 'required|string', 'customer_country' => 'required|string|size:2', 'reason' => 'required|string', ]); $transaction_id = $this->getTransactionID(); $payment_method = $request->input('payment_method'); $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' => $request->input('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, 'state' => PaymentTransactionState::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'), ]); 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('state', PaymentTransactionState::INITIATED)->firstOrFail(); $customer_phone_number = $request->input('phone_number'); if(str_contains($customer_phone_number,'+237')){ $customer_phone_number = substr($customer_phone_number,4); } // Create passport payment $createResponse = $this->client->post('start/v1', [ 'json' => [ 'order_merchant' => config('variables.yoomee_username'), 'order_merchant_password' => config('variables.yoomee_password'), 'order_type' => 'MemberAccount.merchantPaymentWithoutFees', 'order_payer' => $customer_phone_number, 'order_method' => $transaction->payment_method, 'order_app_id' => config('variables.yoomee_app_id'), 'order_ext_id' => $transaction->transaction_id, "order_base_amount" => $transaction->amount, "order_currency" => $transaction->currency, "order_description" => $transaction->reason, "order_wait_final_status" => $this->isSyncRequest ] ]); if ($createResponse->getStatusCode() == 400) { $createResponse = json_decode($createResponse->getBody()->getContents()); if(!empty($createResponse->error)){ //If error regenerate transaction id to avoid 'Numero de commande deja utilisé' $transaction->update([ 'transaction_id' => $this->getTransactionID() ]); //Convert into single line session()->flash('error',str_replace(array("\n", "\r"), '',$createResponse->error_description)); return redirect()->route('checkout',['payment_token' => $token]); } $transaction->update([ 'aggregator_payment_ref' => $createResponse->transaction_number, 'payment_date' => $createResponse->transaction_date, 'state' => strtoupper($createResponse->transaction_status), "customer_phone_number" => $customer_phone_number, ]); redirect()->route('checkout',['payment_token' => $token]); } session()->flash('error',__('errors.unexpected_error')); return redirect()->route('checkout',['payment_token' => $token]); } public function pay(Request $request) { $this->validate($request, [ 'aggregator_id' => 'required|integer|exists:payment_aggregators,id', 'amount' => 'required|numeric|min:5', 'currency' => 'required|string|size:3', 'payment_method' => 'required|string', 'customer_id' => 'required|integer', 'customer_email' => 'required|email', 'customer_name' => 'required|string', 'customer_surname' => 'required|string', 'customer_phone_number' => 'required|string', 'customer_address' => 'required|string', 'customer_country' => 'required|string|size:2', 'reason' => 'required|string', ]); $transaction_id = $this->getTransactionID(); $payment_method = $request->input('payment_method'); $customer_phone_number = $request->input('customer_phone_number'); if(str_contains($customer_phone_number,'+237')){ $customer_phone_number = substr($customer_phone_number,4); } // Create passport payment $createResponse = $this->client->post('start/v1', [ 'json' => [ 'order_merchant' => config('variables.yoomee_username'), 'order_merchant_password' => config('variables.yoomee_password'), 'order_type' => 'MemberAccount.merchantPaymentWithoutFees', 'order_payer' => $customer_phone_number, 'order_method' => $payment_method, 'order_app_id' => config('variables.yoomee_app_id'), 'order_ext_id' => $transaction_id, "order_base_amount" => $request->input('amount'), "order_currency" => $request->input('currency'), "order_description" => $request->input('reason'), "order_wait_final_status" => $this->isSyncRequest ] ]); if ($createResponse->getStatusCode() == 400) { $createResponse = json_decode($createResponse->getBody()->getContents()); if(!empty($createResponse->error)){ return $this->errorResponse($createResponse->error_description); } $transaction = PaymentTransaction::create([ 'aggregator_id' => $request->input('aggregator_id'), "currency" => $request->input('currency'), 'aggregator_payment_ref' => $createResponse->transaction_number, "transaction_id" => $transaction_id, "amount" => $createResponse->transaction_amount, 'payment_date' => $createResponse->transaction_date, "payment_method" => $payment_method, 'payment_token' => Str::random(64), 'state' => strtoupper($createResponse->transaction_status), "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'), ]); if($transaction->state == PaymentTransactionState::PENDING){ return $this->successResponse([ 'verification_url' => route('yoomee.v2.webhook',['transaction_id' => $transaction_id]) ]); }else{ return $this->successResponse([ 'transaction_id' => $transaction_id, 'token' => $transaction->payment_token ]); } } return $this->errorResponse(__('errors.unexpected_error')); } public function capturePaymentResult(Request $request) { $this->validate($request, [ 'transaction_id' => 'required|string|exists:payment_transactions,transaction_id' ]); $transaction = PaymentTransaction::where('transaction_id',$request->input('transaction_id'))->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->state == PaymentTransactionState::PENDING && $transaction->created_at->diffInMinutes(Carbon::now()) > 5){ $transaction->update([ 'state' => PaymentTransactionState::CANCELLED ]); } $response = $this->client->post('status/v1', [ 'json' => [ 'order_merchant' => config('variables.yoomee_username'), 'order_merchant_password' => config('variables.yoomee_password'), 'order_method' => $transaction->payment_method, 'order_app_id' => config('variables.yoomee_app_id'), 'order_ext_id' => $transaction->transaction_id, "order_wait_final_status" => $this->isSyncRequest ] ]); $responseData = json_decode($response->getBody()->getContents()); $responseCode = $response->getStatusCode(); if ($responseCode == 400) { $state = strtoupper($responseData->transaction_status); if($state == 'SUCCESS'){ $state = PaymentTransactionState::ACCEPTED; }else{ if(str_starts_with($state,'C')){ $state = PaymentTransactionState::REFUSED; } } $transaction->update([ 'state' => $state, 'payment_date' => $responseData->transaction_date ?? null, ]); } } catch (Throwable $e) { Log::info("Get Yoomee Payment Status Error"); Log::info($e->getMessage()); $transaction->update([ 'state' => PaymentTransactionState::REFUSED ]); } if($verify_btn){ return redirect()->route('checkout',['payment_token' => $transaction->payment_token]); }else { if ($transaction->state == PaymentTransactionState::ACCEPTED) { return [ 'message' => "Payment accepted", 'status' => 1, 'refresh' => 1, ]; } else { return [ 'message' => "Payment failed", 'status' => 0 ]; } } } public function merchantRedirect(Request $request) { $this->validate($request, [ 'transaction_id' => 'required|string|exists:payment_transactions,transaction_id' ]); $transaction = PaymentTransaction::where('transaction_id',$request->input('transaction_id'))->first(); if ($transaction->state == PaymentTransactionState::ACCEPTED) { return redirect()->route('paymentResult', [ 'transaction_id' => $transaction->transaction_id, 'token' => $transaction->payment_token, 'status' => 1 ]); } else { return redirect()->route('paymentResult', [ 'message' => "Payment failed", 'status' => 0 ]); } } }