client = new StripeClient(config('variables.stripe_secret')); } public function getMethods() { $data = $this->client->paymentMethods->all()->toArray(); return $this->successResponse([ 'hasWebview' => true, 'methods' => $data, ]); } public function getCheckout($payment_token) { $transaction = PaymentTransaction::where('payment_token', $payment_token)->first(); if(empty($transaction)){ return $this->errorResponse(__('errors.model_not_found', ['model' => 'transaction']), Response::HTTP_NOT_FOUND); } $amount = $transaction->amount; $receiver = config('variables.receiver_name'); $receiver_logo = asset('assets/images/logo.jpeg'); return view('stripe-checkout', compact('amount','receiver','receiver_logo','payment_token')); } // Formulaire de paiement public function pay(Request $request) { try { $this->validate($request, [ 'aggregator_id' => 'required|integer', 'amount' => 'required|numeric', 'currency' => 'required|string|size:3', 'customer_id' => 'nullable', 'payment_method' => 'nullable|string', 'customer_email' => 'required|email', 'customer_name' => 'nullable|string', 'customer_surname' => 'required|string', 'customer_phone_number' => 'nullable|string', 'customer_address' => 'required|string', 'customer_city' => 'required_if:payment_method,CARD|string', 'customer_country' => 'required|string|size:2', 'customer_state' => 'required_if:payment_method,CARD|string', //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,CARD|string|size:5', 'reason' => 'required|string' ]); $transaction_id = $this->getTransactionID(); $payment_method = $request->input('payment_method','CARD'); $amount = $request->input('amount'); $currency = $request->input('currency'); if($amount <= 0 || $this->toMoneyAmount($amount, $currency , 'USD') < 1 ){ return $this->errorResponse(__('errors.minimum_amount_required')); } $payment_token = $this->getTransactionToken(); $payment_url = route('stripe.checkout',['payment_token' =>$payment_token]); PaymentTransaction::create([ 'aggregator_id' => $request->input('aggregator_id'), "currency" => $request->input('currency'), "transaction_id" => $transaction_id, "amount" => $amount, "payment_method" => $payment_method, "payment_token" => $payment_token, "payment_url" => $payment_url, '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" => $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' => 'Payment initiated', 'payment_url' => $payment_url ]); }catch (Throwable $e){ Log::error($e->getMessage()); } return $this->errorResponse(trans('errors.unexpected_error')); } public function post(Request $request) { $this->validate($request, [ 'payment_token' => 'required|string|exists:payment_transactions,payment_token', 'stripeToken' => 'required|string', ]); $token = $request->input('payment_token'); $transaction = PaymentTransaction::where('payment_token', $token)->where('status', PaymentTransactionStatus::INITIATED)->firstOrFail(); // Init payment $charge = $this->client->charges->create([ "amount" => stripeFormatCurrency(round($transaction->amount,2), $transaction->currency), "currency" => $transaction->currency, "description" => $transaction->reason, // "customer" => 15, "source" => $request->input('stripeToken'), "receipt_email" => $transaction->customer_email, "metadata" => [ "transaction_id" => $transaction->transaction_id, 'lang' => app()->getLocale(), "customer_id" => $transaction->customer_id, "customer_name" => $transaction->customer_name, "customer_surname" => $transaction->customer_surname, "customer_email" => $transaction->customer_email, "customer_phone_number" => $transaction->customer_phone_number, "customer_address" => $transaction->customer_address, "customer_city" => $transaction->customer_city, "customer_country" => $transaction->customer_country, "customer_state" => $transaction->customer_state, "customer_zip_code" => $transaction->customer_zip_code, ], ]); if($charge){ $transaction->update([ 'aggregator_payment_ref' => $charge->id, 'payment_date' => date('Y-m-d H:i:s', $charge->created), 'status' => PaymentTransactionStatus::ACCEPTED, 'payment_method_exact' => $request->input('card_number') ]); return redirect()->route('checkout',['payment_token' => $token]); } session()->flash('error',__('errors.unexpected_error')); return redirect()->to(route('stripe.checkout',['payment_token' => $token])); } private function getTransactionToken() { do { $code = 'STP-'.Str::random(64); $result = collect(DB::select('SELECT * FROM payment_transactions WHERE payment_token = :code', ['code' => $code])); $codeCorrect = sizeof($result) < 0; } while ($codeCorrect); return $code; } public function refund(Request $request) { $this->validate($request, [ 'transaction_id' => 'required|string|exists:payment_transactions,transaction_id', 'reason' => 'nullable|string|in:duplicate,fraudulent,requested_by_customer' ]); $transaction = PaymentTransaction::where('transaction_id', $request->input('transaction_id'))->where('status', PaymentTransactionStatus::ACCEPTED)->firstOrFail(); $reason = $request->input('reason','requested_by_customer'); $reference = $transaction->aggregator_payment_ref; $twoFirstChars = substr($reference,0,2); $keyToRefund = $twoFirstChars == 'ch' ? 'charge' : 'payment_intent'; $refund = $this->client->refunds->create([ $keyToRefund => $reference, 'reason' => $reason ]); if(!empty($refund)){ PaymentRefund::create([ 'refund_id' => $this->getTransactionID('payment_refunds'), 'transaction_id' => $transaction->id, "currency" => strtoupper($refund->currency), "amount" => $refund->amount, "reason" => $reason, 'date' => date('Y-m-d H:i:s', $refund->created), 'status' => strtoupper($refund->status) ]); return $this->successResponse("Payment refunded successfully"); } return $this->errorResponse(__('errors.unexpected_error')); } // Encaissement de l'argent des clients public function payIn(Request $request) { $this->validate($request, [ 'card_no' => 'required', 'exp_month' => 'required', 'exp_year' => 'required', 'cvc' => 'required', // 'aggregator_id' => 'required|integer', 'amount' => 'required|numeric', 'currency' => 'required|string|size:3', 'customer_id' => 'nullable', // 'payment_method' => 'nullable|string', // Actuallu it's only CARD 'customer_email' => 'required|email', 'customer_name' => 'nullable|string', 'customer_surname' => 'required|string', 'customer_phone_number' => 'nullable|string', 'customer_address' => 'required|string', 'customer_city' => 'required|string', 'customer_country' => 'required|string|size:2', 'customer_state' => 'nullable|string', //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' => 'nullable|string|size:5', 'reason' => 'required|string' ]); $aggregator = PaymentAggregator::where('name','like','%stripe%')->firstOrFail(); $amount = $request->input('amount'); $currency = $request->input('currency'); if($amount <= 0 || $this->toMoneyAmount($amount, $currency , 'USD') < 1 ){ return $this->errorResponse(__('errors.minimum_amount_required')); } $transaction = PaymentTransaction::create([ 'aggregator_id' => $aggregator->id, "currency" => $request->input('currency'), "transaction_id" => $this->getTransactionID(), "amount" => $amount, "payment_method" => 'CARD', '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" => $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'), ]); // Create payment method in Stripe // https://stripe.com/docs/api/payment_methods/create $method = $this->client->paymentMethods->create([ 'type' => 'card', 'card' => [ 'number' => $request->input('card_no'), 'exp_month' => $request->input('exp_month'), 'exp_year' => $request->input('exp_year'), 'cvc' => $request->input('cvc'), ] ]); if($method){ $transaction->update([ 'payment_method_exact' => $method->id ]); // Create payment intent // https://stripe.com/docs/api/payment_intents/create $paymentIntent = $this->client->paymentIntents->create([ "amount" => stripeFormatCurrency($amount, $request->input('currency')), "currency" => $request->input('currency'), "description" => $request->input('reason'), 'payment_method_types' => ['card'], 'payment_method' => $method->id, 'confirm' => 'true', 'capture_method' => 'automatic', 'return_url' => route('stripe.webhook',['transaction_id' => $transaction->transaction_id]), // Redirect url if 3d secure required 'payment_method_options' => [ 'card' => [ 'request_three_d_secure' => 'automatic' ] ], ]); if($paymentIntent){ $transaction->update([ 'payment_date' => date('Y-m-d H:i:s', $paymentIntent->created), 'aggregator_payment_ref' => $paymentIntent->id ]); if(!empty($paymentIntent->next_action->redirect_to_url->url)){ return $this->successResponse([ 'message' => '3D secure redirect', 'payment_url' => $paymentIntent->next_action->redirect_to_url->url ], ResponseAlias::HTTP_MOVED_PERMANENTLY); } return $this->handlePaymentIntentResult($transaction, $paymentIntent, false); } } return $this->errorResponse(__('errors.unexpected_error')); } // Recharge des comptes clients public function payOut(Request $request) { $this->validate($request, [ 'card_no' => 'required_if:payment_method,CARD', 'exp_month' => 'required_if:payment_method,CARD', 'exp_year' => 'required_if:payment_method,CARD', // 'cvc' => 'required_if:payment_method,CARD', 'bank_country' => 'required_if:payment_method,BANK|string|size:2', 'bank_currency' => 'required_if:payment_method,BANK|string|size:3', 'bank_account_number' => 'required_if:payment_method,BANK|string', // 'aggregator_id' => 'required|integer', 'amount' => 'required|numeric', 'currency' => 'required|string|size:3', 'customer_id' => 'nullable', 'payment_method' => 'required|string|in:CARD,BANK', 'customer_email' => 'required|email', 'customer_name' => 'nullable|string', 'customer_surname' => 'required|string', 'customer_phone_number' => 'nullable|string', 'customer_address' => 'required|string', 'customer_city' => 'required|string', 'customer_country' => 'required|string|size:2', 'customer_state' => 'nullable|string', //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' => 'nullable|string|size:5', 'reason' => 'required|string' ]); $aggregator = PaymentAggregator::where('name','like','%stripe%')->firstOrFail(); $amount = $request->input('amount'); $currency = $request->input('currency'); $payment_method = $request->input('payment_method'); if($amount <= 0 || $this->toMoneyAmount($amount, $currency , 'USD') < 1 ){ return $this->errorResponse(__('errors.minimum_amount_required')); } $transaction = PaymentTransaction::create([ 'aggregator_id' => $aggregator->id, "currency" => $request->input('currency'), "transaction_id" => $this->getTransactionID(), "amount" => $amount, "payment_method" => $payment_method, '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" => $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'), ]); // Create destination account in Stripe if($payment_method == 'CARD'){ //https://stripe.com/docs/api/external_account_cards/create $destination = $this->client->accounts->createExternalAccount( config('variables.stripe_account'), [ 'external_account' => [ 'object' => 'card', 'number' => $request->input('card_no'), 'exp_month' => $request->input('exp_month'), 'exp_year' => $request->input('exp_year'), // 'cvc' => $request->input('cvc'), ] ] ); }else{ //https://stripe.com/docs/api/external_account_bank_accounts/create#account_create_bank_account $destination = $this->client->accounts->createExternalAccount( config('variables.stripe_account'), [ 'external_account' => [ 'object' => 'bank_account', 'country' => $request->input('bank_country'), 'currency' => $request->input('bank_currency'), 'account_number' => $request->input('bank_account_number'), ] ] ); } if($destination){ $transaction->update([ 'payment_method_exact' => $destination->id ]); // Create payout in Stripe // https://stripe.com/docs/api/payouts/create $payout = $this->client->payouts->create([ "amount" => stripeFormatCurrency($amount, $currency), "currency" => $currency, 'description' => $request->input('reason'), "destination" => $destination->id, "method" => $payment_method == 'CARD' ? 'instant' : 'standard' ]); if($payout) { $transaction->update([ 'payment_date' => date('Y-m-d H:i:s', $payout->arrival_date), 'aggregator_payment_ref' => $payout->id, 'status' => strtolower($payout->status) ]); return $this->successResponse([ 'transaction_id' => $transaction->transaction_id, 'status' => $transaction->status ]); } } return $this->errorResponse(__('errors.unexpected_error')); } public function capturePaymentResult(Request $request) { $this->validate($request, [ 'payment_intent' => 'nullable|string', 'transaction_id' => 'required|string|exists:payment_transactions,transaction_id', ]); $transaction = PaymentTransaction::where('transaction_id',$request->input('transaction_id'))->firstOrFail(); if($request->has('payment_intent')) { $paymentIntent = $this->client->paymentIntents->retrieve($request->input('payment_intent')); return $this->handlePaymentIntentResult($transaction, $paymentIntent); } return $this->errorResponse(__('errors.unexpected_error')); } private function handlePaymentIntentResult(PaymentTransaction $transaction, PaymentIntent $intent , bool $returnView = true){ if($intent->status == 'succeeded'){ $transaction->update([ 'status' => PaymentTransactionStatus::ACCEPTED ]); $data = [ 'message' => 'Payment Accepted', 'transaction_id' => $transaction->transaction_id, 'status' => 1 ]; if($returnView){ return redirect()->route('paymentResult',$data); }else{ return $this->successResponse($data); } }else{ $transaction->update([ 'status' => strtolower($intent->status) ]); $data = [ 'message' => "Payment ".$transaction->status, 'status' => 0 ]; if($returnView){ return redirect()->route('paymentResult', $data); }else{ return $this->errorResponse($data); } } } }