DEV Community

alamriku
alamriku

Posted on

How to Integrate PayPal Payment Gateway in Laravel 8.x

On my current datetime of writing this blog post I have shown the images of paypal dashboard. It may change on future. Paypal have changed many things on past.

Paypalcheckout
      Above image give us the idea how PayPal work on behind

Step 1 : Create a PayPal account.

select business on account creation.

Step 2 : got to developer dashboard from your business dashboard. See The Below Images.

PayPal Business Dashboard

Step 3 : now we are on developer dashboard
Developer dashboard
Step 3.1 : now create a rest API App buy clicking on My App and credential. see the image below.
App creation
APP creation page

when app is created PayPal also created two sandox account for us. Step-4 can be skip if we want use the default accounts

Step 4 : create sandbox account
menusandbox
Sandox1

Step: 5 accessing the accounts

After creating sandbox account we will have two user email

1 business email

2 personal email

we will use the business email to login to our PayPal merchant account.
And personal email to do purchase, order from our Laravel application.

          watch the below images
accounts
        from here we get the email pass. The modal open when we click the edit button on .... I have shown on above image see click here
emailpassword

Going to the PayPal sandbox dasboard. which will give a real look of PayPal merchant Dashboard.
www.sandbox.paypal.com

sandboxpage
login

        Marchent/Seller Dashboard
SellerDashboard

payer/buyer/personal account

        Buyer/Payer/Personal Dashboard
Buyer/Payer/Personal Dashboard

Hurray we have completed all the PayPal account procedure and sandbox Utilities. Congratulations
https://developer.paypal.com/docs/business/get-started/

Note :
When we create our  PayPal Rest Api App from the My app and Credential menu.
 By Default PayPal give us two accounts One personal,
 second business.
Enter fullscreen mode Exit fullscreen mode

Now lets jump to the business logic and other essentials.

  • Step-6 : get the CLIENT_ID and CLIENT_SECRET from our created on
    click the My Apps & Credentials menu on you dashboad and then click to the created app which will redirect to the below image pages
    clientIdAndSecre

  • step-7 : puth the CLIENT_ID and CLIENT_SECRET on your laravel .env file

PAYPAL_MODE=sandbox
PAYPAL_SANDBOX_CLIENT_ID=
PAYPAL_SANDBOX_CLIENT_SECRET=

Enter fullscreen mode Exit fullscreen mode

composer require srmklive/paypal

which a wrapper on PayPal SDK
https://github.com/paypal/Checkout-PHP-SDK

  • step-9 : now publish the config of our srmklive/laravel-paypal
php artisan vendor:publish --provider "Srmklive\PayPal\Providers\PayPalServiceProvider"
Enter fullscreen mode Exit fullscreen mode
  • step-10 : go to app config folder on paypal.php file
    config/paypal.php
    config

  • Step-11 : add client_id, secret to paypal.php file

'mode'    => env('PAYPAL_MODE', 'sandbox'), // Can only be 'sandbox' Or 'live'. If empty or invalid, 'live' will be used.
    'sandbox' => [
        'client_id'         => env('PAYPAL_SANDBOX_CLIENT_ID'),
        'client_secret'    =>env('PAYPAL_SANDBOX_CLIENT_SECRET',),
    ],
Enter fullscreen mode Exit fullscreen mode
  • Step-11.1 : create route on api.php file

    we will be sending api request to our server side laravel app from our javascript paypal sdk. That's why we create route on api.php. benefit of doing these we don't need to send CSRF token to our laravel app when we make the fetch post request to our laravel server side application. In laravel api.php route don't work with session.so we will can not use the session() on this route. we can also write route on web.php file then we have to send csrf token with our post from our javascript.

  • step-11.2 : creating route on api.php

Route::group(['prefix'=>'paypal'], function(){
    Route::post('/order/create',[\App\Http\Controllers\Front\PaypalPaymentController::class,'create']);
    Route::post('/order/capture/',[\App\Http\Controllers\Front\PaypalPaymentController::class,'capture']);
});
Enter fullscreen mode Exit fullscreen mode
  • Step-11.2.1 : add the PayPal Javascript SDK on your blade file/page. where usually user want to pay. Example checkout page of our product. PayPal Javascript SDK
<body>
    <!-- Set up a container element for the button -->
    <div id="paypal-button-container"></div>

    <!-- Include the PayPal JavaScript SDK -->
    <script src="https://www.paypal.com/sdk/js?client-id=test&currency=USD"></script>

    <script>
        // Render the PayPal button into #paypal-button-container
        paypal.Buttons({
 // Call your server to set up the transaction
             createOrder: function(data, actions) {
                return fetch('/api/paypal/order/create', {
                    method: 'POST',
                    body:JSON.stringify({
                        'course_id': "{{$course->id}}",
                        'user_id' : "{{auth()->user()->id}}",
                        'amount' : $("#paypalAmount").val(),
                    })
                }).then(function(res) {
                    //res.json();
                    return res.json();
                }).then(function(orderData) {
                    //console.log(orderData);
                    return orderData.id;
                });
            },

            // Call your server to finalize the transaction
            onApprove: function(data, actions) {
                return fetch('/api/paypal/order/capture' , {
                    method: 'POST',
                    body :JSON.stringify({
                        orderId : data.orderID,
                        payment_gateway_id: $("#payapalId").val(),
                        user_id: "{{ auth()->user()->id }}",
                    })
                }).then(function(res) {
                   // console.log(res.json());
                    return res.json();
                }).then(function(orderData) {

                    // Successful capture! For demo purposes:
                  //  console.log('Capture result', orderData, JSON.stringify(orderData, null, 2));
                    var transaction = orderData.purchase_units[0].payments.captures[0];
                    iziToast.success({
                        title: 'Success',
                        message: 'Payment completed',
                        position: 'topRight'
                    });
                });
            }

        }).render('#paypal-button-container');
    </script>
</body>
Enter fullscreen mode Exit fullscreen mode

checkoutPage

  • Step-11.2.2 : when we importing the paypal javascirpt sdk at the bottom of our body tag replace client_id=test with client-id=<?php echo config('services.paypal.client_id') ?>

    <script src="https://www.paypal.com/sdk/js?client-id=test&currency=USD"></script>
Enter fullscreen mode Exit fullscreen mode
client-id={{config('services.paypal.client_id')}}
Enter fullscreen mode Exit fullscreen mode
  • step-11.2 on Javascript SDK at createOrder we write /api/paypal/order/create url which send a post request to our larave app.
createOrder: function(data, actions) {
                return fetch('/api/paypal/order/create', {
                    method: 'POST',
                    body:JSON.stringify({
                        'course_id': "{{$course->id}}",
                        'user_id' : "{{auth()->user()->id}}",
                        'amount' : $("#paypalAmount").val(),
                    })
                }).then
Enter fullscreen mode Exit fullscreen mode
  • step-11.3 : create the PaypalPaymentController php artisan make:controller PaypalPaymentController
  • step-11.4 : writhe the create method on PaypalPaymentController

  • Step-11.5 : write logic and make request to paypal using the package we are using

  public function create(Request $request)
    {
        $data = json_decode($request->getContent(), true);

        $this->paypalClient->setApiCredentials(config('paypal'));
        $token = $this->paypalClient->getAccessToken();
        $this->paypalClient->setAccessToken($token);
        $order = $this->paypalClient->createOrder([
            "intent"=> "CAPTURE",
            "purchase_units"=> [
                 [
                    "amount"=> [
                        "currency_code"=> "USD",
                        "value"=> $data['amount']
                    ],
                     'description' => 'test'
                ]
            ],
        ]);
        $mergeData = array_merge($data,['status' => TransactionStatus::PENDING, 'vendor_order_id' => $order['id']]);
        DB::beginTransaction();
        Order::create($mergeData);
        DB::commit();
        return response()->json($order);


        //return redirect($order['links'][1]['href'])->send();
       // echo('Create working');
    }
Enter fullscreen mode Exit fullscreen mode

below code snippet setup the config and send a post request to paypal to get the access token

$this->paypalClient->setApiCredentials(config('paypal'));
        $token = $this->paypalClient->getAccessToken();
        $this->paypalClient->setAccessToken($token);
Enter fullscreen mode Exit fullscreen mode

below code create a order on paypal on paypal gives us the order object which have a id order id

$order = $this->paypalClient->createOrder([
            "intent"=> "CAPTURE",
            "purchase_units"=> [
                 [
                    "amount"=> [
                        "currency_code"=> "USD",
                        "value"=> $data['amount']
                    ],
                     'description' => 'test'
                ]
            ],
        ]);
Enter fullscreen mode Exit fullscreen mode

saving the order with the paypal order id on our database

$mergeData = array_merge($data,['status' => TransactionStatus::PENDING, 'vendor_order_id' => $order['id']]);
        DB::beginTransaction();
        Order::create($mergeData);
        DB::commit();
        return response()->json($order);
Enter fullscreen mode Exit fullscreen mode

after creating the order a paypal payment modal open up.login as personal then paypal payment form will appear.

loignasPersonal
Transaction

When we click on the paypment button on the paypal form model.
The javascript Paypal Sdk at onApprove we make a post request to our laravel app with the order which was provided by our laravel app from paypal on create order process.

 onApprove: function(data, actions) {
                return fetch('/api/paypal/order/capture' , {
                    method: 'POST',
                    body :JSON.stringify({
                        orderId : data.orderID,
                        payment_gateway_id: $("#payapalId").val(),
                        user_id: "{{ auth()->user()->id }}",
                    })
                }).
Enter fullscreen mode Exit fullscreen mode

the post goes to api/paypal/order/capture which lead to create us new method on PayPalPaymentController
public function capture(Request $request)

on that method we write our business logic


public function capture(Request $request)
    {
        $data = json_decode($request->getContent(), true);
        $orderId = $data['orderId'];
        $this->paypalClient->setApiCredentials(config('paypal'));
        $token = $this->paypalClient->getAccessToken();
        $this->paypalClient->setAccessToken($token);
        $result = $this->paypalClient->capturePaymentOrder($orderId);

//            $result = $result->purchase_units[0]->payments->captures[0];
        try {
            DB::beginTransaction();
            if($result['status'] === "COMPLETED"){
                $transaction = new Transaction;
                $transaction->vendor_payment_id = $orderId;
                $transaction->payment_gateway_id  = $data['payment_gateway_id'];
                $transaction->user_id   = $data['user_id'];
                $transaction->status   = TransactionStatus::COMPLETED;
                $transaction->save();
                $order = Order::where('vendor_order_id', $orderId)->first();
                $order->transaction_id = $transaction->id;
                $order->status = TransactionStatus::COMPLETED;
                $order->save();
                DB::commit();
            }
        } catch (Exception $e) {
            DB::rollBack();
            dd($e);
        }
        return response()->json($result);
    }

Enter fullscreen mode Exit fullscreen mode

Again we make a post request to paypal to get the access token using the below snippet

 $data = json_decode($request->getContent(), true);
        $orderId = $data['orderId'];
        $this->paypalClient->setApiCredentials(config('paypal'));
        $token = $this->paypalClient->getAccessToken();
        $this->paypalClient->setAccessToken($token);
Enter fullscreen mode Exit fullscreen mode

then we make our payment using capturePaymentOrder()

$result = $this->paypalClient->capturePaymentOrder($orderId);

then do our database saving stuff

 DB::beginTransaction();
            if($result['status'] === "COMPLETED"){
                $transaction = new Transaction;
                $transaction->vendor_payment_id = $orderId;
                $transaction->payment_gateway_id  = $data['payment_gateway_id'];
                $transaction->user_id   = $data['user_id'];
                $transaction->status   = TransactionStatus::COMPLETED;
                $transaction->save();
                $order = Order::where('vendor_order_id', $orderId)->first();
                $order->transaction_id = $transaction->id;
                $order->status = TransactionStatus::COMPLETED;
                $order->save();
                DB::commit();
Enter fullscreen mode Exit fullscreen mode

Happy coding. Thank you to read my post. Leave a comment for a feedback. Give a unicorn.

Reference
developer.paypal.com/docs/business/checkout/set-up-standard-payments
https://developer.paypal.com/docs/business/checkout/set-up-standard-payments/#1-add-payment-buttons
https://github.com/paypal/Checkout-PHP-SDK#code
https://github.com/srmklive/laravel-paypal/issues/407#issuecomment-864521831
https://www.youtube.com/watch?v=_7YBIRQfSN0&ab_channel=AndreMadarang

Discussion (0)