client = new Client([ 'base_uri' => config('variables.cinetpay_api_url') ]); } /** * @OA\Get( * path="/cinetpay/methods", * summary="Afficher la liste des methodes de Cinetpay", * tags={"Cinetpay"}, * security={{"api_key":{}}}, * @OA\Response( * response=200, * description="OK", * @OA\JsonContent( * ref="#/components/schemas/ApiResponse", * example = { * "status" : 200, * "response" : {"hasWebview": true, "methods": { "MOBILE_MONEY": "Mobile Money", "CREDIT_CARD": "Carte de crédit" }}, * "error":null * } * ) * ) * ) */ public function getMethods() { $providers = [ // 'ALL', 'MOBILE_MONEY', 'CREDIT_CARD', ]; $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, ]); } // public function pay(Request $request) { $this->validate($request, [ 'aggregator_id' => 'required|integer', 'amount' => 'required|numeric|min:5', 'currency' => 'required|string|size:3', 'payment_method' => 'nullable|string|in:ALL,MOBILE_MONEY,CREDIT_CARD,WALLET', '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_city' => 'required_if:payment_method,CREDIT_CARD|string', 'customer_country' => 'required|string|size:2', 'customer_state' => 'required_if:payment_method,CREDIT_CARD|string|size:2', //Etat du pays dans lequel se trouve le client. Cette valeur est obligatoire si le client se trouve au États Unis d’Amérique (US) ou au Canada (CA) 'customer_zip_code' => 'required_if:payment_method,CREDIT_CARD|string|size:5', 'reason' => 'required|string' ]); $transaction_id = $this->getTransactionID(); $payment_method = $request->input('payment_method','ALL'); $amount = $request->input('amount'); $currency = $request->input('currency'); if ($currency != 'USD') { // Convertir en multiple de 5 $amount = $this->roundUpToAny($amount); } // Init payment $createResponse = $this->client->post('payment', [ 'json' => [ "api_key" => config('variables.cinetpay_api_key'), "site_id" => config('variables.cinetpay_site_id'), "transaction_id" => $transaction_id, "amount" => $amount, "currency" => $request->input('currency'), "description" => $request->input('reason'), "notify_url" => route('cinetpay.webhook'), "return_url" => route('cinetpay.webhook'), "channels" => $payment_method, 'lang' => app()->getLocale(), "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" => $request->input('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'), ], 'timeout' => $this->timeout ]); $responseData = json_decode($createResponse->getBody()->getContents()); $responseCode = $createResponse->getStatusCode(); if ($responseCode == 200) { PaymentTransaction::create([ 'aggregator_id' => $request->input('aggregator_id'), "currency" => $request->input('currency'), "transaction_id" => $transaction_id, "amount" => $amount, "payment_method" => $payment_method, "payment_token" => $responseData->data->payment_token, "payment_url" => $responseData->data->payment_url, 'status' => PaymentTransactionStatus::PENDING, "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" => $request->input('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' => $responseData->message, 'payment_url' => $responseData->data->payment_url ]); }else{ return $this->errorResponse($responseData->error ?? trans('errors.unexpected_error'),$responseCode); } } public function payOut(Request $request) { $this->validate($request, [ // 'aggregator_id' => 'required|integer', 'amount' => 'required|numeric|min:5', 'currency' => 'required|string|size:3', 'customer_id' => 'nullable', // 'payment_method' => 'required|string|in:WALLET', 'customer_email' => 'required|email', 'customer_name' => 'nullable|string', 'customer_surname' => 'required|string', 'customer_phone_number' => ['nullable','string',(new Phone())->country(['CI','SN','ML','CM','TG','BF','CD','GN','BJ'])], 'customer_address' => 'nullable|string', 'customer_city' => 'nullable|string', 'customer_country' => 'required|string|size:2|in:CI,SN,ML,CM,TG,BF,CD,GN,BJ', 'reason' => 'required|string' ]); $aggregator = PaymentAggregator::where('name','like','%cinetpay%')->firstOrFail(); try{ $customer_surname = $request->input('customer_surname'); $customer_name = $request->input('customer_name') ?? $customer_surname; $customer_email = $request->input('customer_email'); $country_code = $request->input('customer_country'); $phoneNumber = str_replace(' ','',$request->input('customer_phone_number')); $phone = new PhoneNumber($phoneNumber, $country_code); $phoneNumber = str_replace(' ','',$phone->formatInternational()); $nationalPhone = str_replace(' ','',$phone->formatNational()); $phonePrefix = substr($phoneNumber, 1, strlen($phoneNumber) - strlen($nationalPhone) - 1); $amount = $request->input('amount'); $payment_method = 'WALLET'; // if($amount < 500){ // return $this->errorResponse('Minimun amount is 500'); // } $client = new Client([ 'base_uri' => config('variables.cinetpay_transfert_url') ]); // Login $loginResponse = $client->post('auth/login', [ 'form_params' => [ "apikey" => config('variables.cinetpay_api_key'), "password" => config('variables.cinetpay_transfert_password'), ], 'timeout' => $this->timeout, 'http_errors' => false ]); $responseData = json_decode($loginResponse->getBody()->getContents()); $token = $responseData->data->token; $responseCode = $loginResponse->getStatusCode(); if ( $responseCode == 200 && !empty($token)) { // Add Contact $contactResponse = $client->post('transfer/contact', [ 'query' => [ 'token' => $token ], 'form_params' => [ "data" => json_encode( [ [ 'prefix' => $phonePrefix, 'phone' => $nationalPhone, 'name' => $customer_name, 'surname' => $customer_surname, 'email' => $customer_email ] ] ), ], 'timeout' => $this->timeout, 'http_errors' => false ]); $responseCode = $contactResponse->getStatusCode(); $responseData = json_decode($contactResponse->getBody()->getContents()); if ($responseCode == 200) { $transactionId = $this->getTransactionID(); $transaction = PaymentTransaction::create([ 'aggregator_id' => $aggregator->id, "currency" => $request->input('currency'), "transaction_id" => $transactionId, "amount" => $amount, "payment_method" => $payment_method, 'status' => PaymentTransactionStatus::INITIATED, "reason" => $request->input('reason'), "customer_id" => $request->input('customer_id'), "customer_name" => $customer_name, "customer_surname" => $customer_surname, "customer_email" => $customer_email, "customer_phone_number" => $phoneNumber, "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'), ]); // Transfert Fund $transfertResponse = $client->post('transfer/money/send/contact', [ 'query' => [ 'token' => $token ], 'form_params' => [ "data" => json_encode( [ [ 'client_transaction_id' => $transactionId, 'amount' => $amount, 'notify_url' => route('cinetpay.transfert.webhook'), 'prefix' => $phonePrefix, 'phone' => $nationalPhone, ] ] ), ], 'timeout' => $this->timeout, 'http_errors' => false ]); $responseData = json_decode($transfertResponse->getBody()->getContents()); $responseCode = $transfertResponse->getStatusCode(); Log::info("Pay out cinietpay"); Log::info(json_encode($responseData)); if ($responseCode == 200) { $transaction->update([ 'aggregator_payment_ref' => $responseData->data[0]?->transaction_id, 'status' => $responseData->data[0]?->treatment_status, ]); return $this->successResponse([ 'message' => 'Transfert is pending', 'transaction_id' => $transactionId, 'transaction_status' => $transaction->status ]); } } } $errorMessage = $responseData?->description ?? $responseData?->message; }catch (Throwable $e){ Log::error("Error CinetPay transfert payment"); $errorMessage = $e->getMessage(); Log::error($errorMessage); } return $this->errorResponse($errorMessage ?? __('errors.unexpected_error')); } public function captureTransfertResult(Request $request) { $this->validate($request, [ 'transaction_id' => 'nullable|string', 'client_transaction_id' => 'nullable|string|exists:payment_transactions,transaction_id' ]); if($request->has('transaction_id') && $request->has('client_transaction_id')){ $transaction = PaymentTransaction::where('transaction_id',$request->input('client_transaction_id'))->firstOrFail(); try { $client = new Client([ 'base_uri' => config('variables.cinetpay_transfert_url') ]); // Login $loginResponse = $client->post('auth/login', [ 'form_params' => [ "apikey" => config('variables.cinetpay_api_key'), "password" => config('variables.cinetpay_transfert_password'), ], 'timeout' => $this->timeout ]); $responseData = json_decode($loginResponse->getBody()->getContents()); $token = $responseData->data->token; $responseCode = $loginResponse->getStatusCode(); if ($responseCode == 200 && !empty($token)) { $response = $client->get('transfer/check/money', [ 'query' => [ 'token' => $token, 'transaction_id' => $request->input('transaction_id') ], ]); $responseData = json_decode($response->getBody()->getContents()); $responseCode = $response->getStatusCode(); Log::info("Pay out check result"); Log::info(json_encode($responseData)); if ($responseCode == 200) { $transaction->update([ 'aggregator_payment_ref' => $responseData->data[0]?->transaction_id, 'status' => $responseData->data[0]?->treatment_status, ]); } } } catch (Throwable $e) { Log::info("Get Cinetpay Transfert Status Error"); $errorMessage = $e->getMessage(); Log::info($errorMessage); $transaction->update([ 'status' => PaymentTransactionStatus::REFUSED ]); } return $this->errorResponse($errorMessage ?? __('errors.unexpected_error')); }else{ return response("OK"); } } public function capturePaymentResult(Request $request) { $this->validate($request, [ 'cpm_site_id' => 'nullable|string', 'cpm_trans_id' => 'nullable|string|exists:payment_transactions,transaction_id' ]); if($request->has('cpm_trans_id')) { $data = $request->input('cpm_site_id') . $request->input('cpm_trans_id') . $request->input('cpm_trans_date') . $request->input('cpm_amount') . $request->input('cpm_currency') . $request->input('signature') . $request->input('payment_method') . $request->input('cel_phone_num') . $request->input('cpm_phone_prefixe') . $request->input('cpm_language') . $request->input('cpm_version') . $request->input('cpm_payment_config') . $request->input('cpm_page_action') . $request->input('cpm_custom') . $request->input('cpm_designation') . $request->input('cpm_error_message'); $generated_token = hash_hmac('SHA256', $data, config('variables.cinetpay_secret_key')); $received_token = $request->header('x-token'); if(hash_equals($received_token, $generated_token)) { $transaction = PaymentTransaction::where('transaction_id',$request->input('cpm_trans_id'))->firstOrFail(); return $this->getPaymentStatus($transaction); }else{ return $this->errorResponse("Invalid token"); } }else if($request->has('transaction_id')){ $transaction = PaymentTransaction::where('transaction_id',$request->input('transaction_id'))->firstOrFail(); return $this->getPaymentStatus($transaction); }else{ return response("OK"); } } private function getPaymentStatus(PaymentTransaction $transaction) { try { $response = $this->client->post('payment/check', [ 'json' => [ "apikey" => config('variables.cinetpay_api_key'), "site_id" => config('variables.cinetpay_site_id'), 'transaction_id' => $transaction->transaction_id, ] ]); $responseData = json_decode($response->getBody()->getContents()); $responseCode = $response->getStatusCode(); if ($responseCode == 200) { $transaction->update([ 'status' => $responseData->data->status, 'payment_method_exact' => $responseData->data->payment_method ?? null, 'aggregator_payment_ref' => $responseData->data->operator_id ?? null, 'payment_date' => $responseData->data->payment_date ?? null, ]); } } catch (Throwable $e) { Log::info("Get Payment Status Error"); Log::info($e->getMessage()); $transaction->update([ 'status' => PaymentTransactionStatus::REFUSED ]); } if($transaction->status == PaymentTransactionStatus::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 ]); } } }