Get Appointment

Blog Single

A Step-by-Step Guide to Integrating Razorpay Payment Gateway in Laravel

  • Vfix Technology
  • 23 Dec 2023
  • Laravel
  • 376 Views

In the fast-paced world of e-commerce, providing a seamless and secure payment experience for users is crucial. One popular choice for handling online transactions is Razorpay, a robust payment gateway that facilitates smooth transactions. In this blog post, we'll walk you through the process of integrating the Razorpay payment gateway into your Laravel application, ensuring a hassle-free payment experience for your users.

Prerequisites

Before we dive into the integration process, make sure you have the following prerequisites in place:

  1.  Laravel Installed: Ensure that you have a Laravel application up and running.
  2. Razorpay Account: Create an account on the Razorpay platform and obtain your API key and secret key.

Here we are going to take an example of the booking 

Step 1: Install laravel

composer create-project --prefer-dist laravel/laravel your-project-name

Step 2: Create the blade file in the resource/views

<!DOCTYPE html>
<html lang="en">

<head>
    <!-- Required meta tags -->
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
        integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous" />
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <!-- Include jQuery -->
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>

    <title>Book Appointment</title>
    <style>
        #second,
        #third,
        #forth,
        #fifth {
            display: none;
        }

        .time-slot {
            padding: 5px;
            border: 1px solid #ccc;
            margin-bottom: 5px;
            width: 100px;
        }


        .fancy-btn {
            background: #000;
            color: white;
            padding: 10px 20px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            margin: 5px;
            font-weight: bold;
            transition: background 0.3s ease-in-out;
        }

        .fancy-btn:hover {
            background: l #004db2;
            filter: brightness(1.1);
        }


        .time-slot-btn {
            background-color: white;
            color: #252424;
            border: 1px solid gray;
            padding: 10px 20px;
            border-radius: 5px;
            cursor: pointer;
            margin: 5px;
            font-weight: bold;
            transition: background 0.3s ease-in-out;
        }

        .time-slot-btn:hover {
            background-color: #007bff;
            color: white;
            filter: brightness(1.1);
        }


        .booked-slot {
            background-color: #f4acac;
            color: #868282;
            cursor: not-allowed;
        }

        .booked-slot:hover {
            background-color: #f4acac;
            color: #868282;
            cursor: not-allowed;
        }

        input[type="date"]:disabled {
            background-color: #f0f0f0;
            color: #888888;
            cursor: not-allowed;
        }

        .highlighted {
            background-color: #007bff;
            color: white;
            /* Change to the highlight color you prefer */
        }

        .highlighted:hover {
            background-color: #2178DA;
            color: white;
            /* Change to the highlight color you prefer */
        }
    </style>
</head>

<body>
    <section class="bg-gray">
        <div class="container">
            <div class="row d-flex justify-content-center">
                <div class="col-md-8 pt-5">
                    <h1>Book an Appointment</h1>
                    {{-- @if (count($errors) > 0)
                        <div class="row">
                            <div class="col-md-12">
                                <div class="alert alert-danger">
                                    @foreach ($errors->all() as $error)
                                        <div>{{ $error }}</div>
                                    @endforeach
                                </div>
                            </div>
                        </div>
                    @endif --}}
                    @if (session()->has('success'))
                        <div class="alert alert-dismissable alert-success">
                            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                                <span aria-hidden="true">&times;</span>
                            </button>
                            <strong>
                                {!! session()->get('success') !!}
                            </strong>
                        </div>
                    @endif
                    <div class="progress mb-3" style="height: 40px">
                        <div class="progress-bar bg-success rounded border" role="progressbar" style="width: 20%"
                            id="progressBar">
                            <b class="lead fw-bold" id="progressText">Step - 1</b>
                        </div>
                    </div>
                    <div class="card bg-white p-3">
                        <form action="{{ route('create.appointment') }}" method="post">
                            @csrf
                                <h4 class="bg-primary text-center p-1 rounded text-light">
                                    Personal Information
                                </h4>
                                    <div class="mb-3">
                                        <label for="">Name</label>
                                        <input type="text" name="name" id="name" class="form-control"
                                            placeholder="Enter your name">
                                        <span class="form-text text-danger" id="nameError"></span>
                                       @error('name')
                                           <span class="text-danger">{{ $message }}</span>
                                       @enderror
                                    </div>
                                   
                                    <div class="mb-3">
                                        <label for="">Email</label>
                                        <input type="email" id="email" class="form-control" name="email"
                                            placeholder="Enter your email">
                                        <span class="form-text text-danger" id="emailError"></span>
                                        @error('email')
                                            <span class="text-danger">{{ $message }}</span>
                                        @enderror
                                    </div>
<div class="mb-3">
                                        <label for="">Phone</label>
                                        <input type="tel" id="phone" class="form-control" name="email"
                                            placeholder="Enter your email">
                                        <span class="form-text text-danger" id="phoneError"></span>
                                        @error('email')
                                            <span class="text-danger">{{ $message }}</span>
                                        @enderror
                                    </div>
                                    
                                <input type="hidden" id="paymentMethod" name="payment_method"
                                    value="Cash on delivery">
                                    <div class="form-check">
                                        <input class="form-check-input" type="radio" name="payment_method"
                                            id="cash_on_delivery" value="Cash on delivery">
                                        <label class="form-check-label" for="cash_on_delivery">
                                            Cash On Delivery
                                        </label>
                                    </div>
                                    <div class="form-check">
                                        <input class="form-check-input" type="radio" name="payment_method"
                                            id="razorpay" value="Razorpay">
                                        <label class="form-check-label" for="razorpay">
                                            Razorpay
                                        </label>
                                    </div>
                                <div class="form-group d-flex justify-content-between pt-3">
                                    <a href="javascript:void(0);" class="btn btn-danger" id="prev-5">Previous</a>
                                    <button id="submit" type="submit" class="btn btn-success" disabled>
                                        Submit
                                    </button>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </section>
</body>

</html>

This is the blade code to book the appointment on two options first on cash on delivery and second on the razorpay

Step 3: Create and set up model and migration and controller to store the data of the appointment

php artisan make:model Booking -mcr

This command will create the model Booking and along with model it will create migration, controller and resource

now let set up migration

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('appointments', function (Blueprint $table) {
            $table->id();
            $table->string('name')->nullable();
            $table->string('email')->nullable();
            $table->string('phone')->nullable();
            $table->string('payment_method')->nullable();
            $table->json('payment')->nullable();
            $table->enum('payment_status')->default(0);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('appointments');
    }
};

Now let set up model and controller

App\Models\Booking.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Booking extends Model
{
    use HasFactory, SoftDeletes;

    protected $fillable = [
        'phone',
        'email',
        'payment',
        'amount',
        'payment_method',
        'payment_status',
        'order_id',
        'price'
    ];

    protected $casts = [
        'payment' => 'json'
    ];
}

Now controller 

App\Http\Controllers\BookingController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Carbon\Carbon;
use App\Models\Booking;



class BookingController extends Controller
{ 
public function createAppointment(Request $request)
    {

        $data = $this->validate($request ,[
            'name' => 'required|string|max:45',
            'order_id' => 'nullable|string|max:6',
            'email' => 'required|email:rfc,dns|max:45',
            'phone' => 'required|string|max:20',
            'payment' => 'nullable|json',
            'payment_status' => 'nullable|boolean',
            'payment_method' => 'nullable|string|max:50',
            'price'  => 'required|string|max:50'
        ]);

        $appointment = Appointment::create($data);

        Session::put('appointment',$appointment);

        if($appointment->payment_method == 'Razorpay')
        {
            return redirect()->route('razorpay');

        }else{
            Session::put('data',$appointment);

            return redirect()->route('thanks');
        }
    }
}

So here we are using the two method one cash on delivery which is simply going to be on thanks page after submission and if the user will select the razorpay the user will go to the other thanks page to pay the amount

Step 4: Now to work with razorpay payment gateway install the razorpay package

composer require razorpay/razorpay

Step 5: Add the secret and site key in the .evn file

RAZORPAY_KEY=rzp_test_XXXXXXXXX
RAZORPAY_SECRET=XXXXXXXXXXXXXXXX

Step 6: Create a blade to send the user to the payment page after successfully creating of the appointment razorpay.blade.php

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>Laravel - Razorpay Payment Gateway Integration</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" crossorigin="anonymous"></script>

    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>

<body>
    <div class="vh-100 d-flex justify-content-center align-items-center">
        @if ($message = Session::get('error'))
            <div class="alert alert-danger alert-dismissible fade in" role="alert">
                <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                    <span aria-hidden="true">×</span>
                </button>
                <strong>Error!</strong> {{ $message }}
            </div>
        @endif
        {!! Session::forget('error') !!}
        @if ($message = Session::get('success'))
            <div class="alert alert-info alert-dismissible fade in" role="alert">
                <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                    <span aria-hidden="true">×</span>
                </button>
                <strong>Success!</strong> {{ $message }}
            </div>
        @endif
        {!! Session::forget('success') !!}
        <div class="card col-md-4 bg-white shadow-md p-5">
            <div class="mb-4 text-center">
                <svg xmlns="http://www.w3.org/2000/svg" class="text-success" width="75" height="75"
                    fill="currentColor" class="bi bi-check-circle" viewBox="0 0 16 16">
                    <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
                    <path
                        d="M10.97 4.97a.235.235 0 0 0-.02.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-1.071-1.05z" />
                </svg>
            </div>
            <div class="text-center">
                <div class="text-center pb-3">
                    <form action="{{ route('payment') }}" method="POST" id="paymentForm">
                        @csrf
                        <script src="https://checkout.razorpay.com/v1/checkout.js" data-key="{{ env('RAZORPAY_KEY') }}"
                            data-amount="{{ $appointment->amount * 100 }}" data-buttontext="Pay {{ $appointment->amount }} INR"
                            data-name="Vfixtechnology" data-description="Razorpay"
                            data-image="https://www.itsolutionstuff.com/frontTheme/images/logo.png"
                            data-prefill.name="{{ $appointment->user->name }}" data-prefill.email="{{ $appointment->email }}"
                            data-prefill.contact="{{ $appointment->phone }}" data-theme.color="#ff7529"
                            data.order_id="{{ $appointment->order_id }}"></script>
                    </form>
                </div>
                <p>We've sent the link to your inbox. Lorem ipsum dolor sit, lorem lorem </p>
                {{-- <button class="btn btn-outline-success">Back Home</button> --}}
            </div>
        </div>
    </div>
</body>

</html>

now when the user will click on the pay now button payment of the amount will be visible and user can proceed to payment

Now after the payment has been done we have to save the response like the transaction id methods and many details which razor pay send us as a response so to save that thing in the table we have to update the table by matching the order_id as it is unique in the table you can use id too but using order_id is better and proffectional so use it.

Step 6: Now make controller RazorpayPaymentController

php artisan make:controller RazorpayPaymentController

Now add this code in the controller

<?php

namespace App\Http\Controllers\Payment;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Appointment;
use Razorpay\Api\Api;
use Session;
use Exception;


class RazorpayPaymentController extends Controller
{

    public function index()
    {
        $appointment = Session::get('appointment');

        Session::put('appointment',$appointment);

        return view('razorpay',compact('appointment'));
    }

    public function store(Request $request, Appointment $appointment)
    {
        $app = Session::get('appointment');

        $input = $request->all();

        // dd($input);

        $api = new Api(env('RAZORPAY_KEY'), env('RAZORPAY_SECRET'));

        $payment = $api->payment->fetch($input['razorpay_payment_id']);

        // dd($payment);

        if (count($input) && !empty($input['razorpay_payment_id'])) {
            try {
                $response = $api->payment->fetch($input['razorpay_payment_id'])->capture([
                    'amount' => $payment['amount']
                ]);
                $orderId = $app->order_id;
                $data = Appointment::where('order_id',$orderId)->firstOrFail();

                $data->payment_status = 1;
                $data->payment = (array)$response;

                $data->save();
            } catch (Exception $e) {
                Log::info($e->getMessage());
                return back()->withError($e->getMessage());
            }
        }

        Session::put($data,'data');
        return redirect()->back();
    }
}

Now create a route

Route::get('/razorpay',[RazorpayPaymentController::class, 'index'])->name('razorpay');
Route::post('/razorpay-amount', [RazorpayPaymentController::class, 'store'])->name('payment');

here in index method we are getting the details of the created appointment in through the session and we are passing the data in the razorpay blade so the user can make payment and can get the required proper response 

In the store method first we are taking the appointment details through session in $app and in try  we are getting the response and in try we are matching the order_id and and storing it in the $data now if the order id will match we are updating the payment_status from 0 to 1 that means payment has been done successfully and after updating the payment_status we are taking all the response in the array format and saving it in the payment column in the appointment table. 
After storing the data in the payment column you can get and use the required details.



+91 8447 525 204 Request Estimate