How to Add Laravel Livewire Checkout to Product Booking System (Part 2)

Learn how to build a Laravel Livewire checkout system for product booking cart. Step-by-step guide with database, Livewire component, and order storage.

In Part 1, we built a complete Product Booking System with Cart using Laravel Livewire, where users could:

  • Select a product
  • Choose a booking date
  • Select quantity
  • Add multiple products to cart
  • Merge identical cart entries

Now in Part 2, we will extend that system and add Laravel Livewire Checkout Form to make it fully working, where:

✔ User enters billing details
✔ Cart items are validated
✔ Orders are saved in database
✔ Cart clears after successful checkout
✔ Ready for payment integration

Let’s build it step-by-step.


Step 1: Create Order Tables

When a user places an order, we must store:

  • Who placed the order
  • Their contact details
  • The total order amount

Instead of saving everything in one table, we follow proper e-commerce structure and create 2 tables as follows:

  • orders: To store contact details and order related information
  • order_items: To store multiple order items for the order

This keeps your database clean and scalable.

Use the following migration command to create orders table:

php artisan make:migration create_orders_table

It will create a migration file xxxx_xx_xx_xxxxxx_create_orders_table.php inside database/migrations folder. Open this file and add the following code:

Schema::create('orders', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email');
$table->string('phone');
$table->text('address');
$table->decimal('total_amount', 10, 2);
$table->timestamps();
});

Similarly, use the same artisan command to create order_items table as follows,

php artisan make:migration create_order_items_table

And copy the following code to the generated migration file xxxx_xx_xx_xxxxxx_create_order_items_table.php:

Schema::create('order_items', function (Blueprint $table) {
$table->id();
$table->foreignId('order_id')->constrained()->cascadeOnDelete();
$table->foreignId('product_id');
$table->date('booking_date');
$table->integer('quantity');
$table->decimal('price', 10, 2);
$table->decimal('total', 10, 2);
$table->timestamps();
});

After both migrations, run the below migrate command to execute created migrations:

php artisan migrate

Step 2: Create Checkout Livewire Component

Create a checkout form livewire component using the following artisan command:

php artisan make:livewire CheckoutForm

It will create 2 files for product booking,

  • Class File: app/Livewire/CheckoutForm.php
  • Blade File: resources/views/livewire/checkout-form.blade.php

Livewire Component Logic

Open app/Livewire/CheckoutForm.php file and copy the following component login in it.

namespace App\Livewire;

use App\Models\Order;
use App\Models\OrderItem;
use App\Services\CartService;
use Livewire\Component;

class CheckoutForm extends Component
{
    public $name, $email, $phone, $address;

    protected $rules = [
        'name'    => 'required|string|min:3',
        'email'   => 'required|email',
        'phone'   => 'required',
        'address' => 'required|min:10',
    ];

    public function placeOrder()
    {
        $this->validate();

        $cart = CartService::all();

        if (empty($cart)) {
            session()->flash('error', 'Cart is empty!');
            return;
        }

        $total = array_sum(array_column($cart, 'total'));

        $order = Order::create([
            'name'         => $this->name,
            'email'        => $this->email,
            'phone'        => $this->phone,
            'address'      => $this->address,
            'total_amount' => $total,
        ]);

        foreach ($cart as $item) {
            OrderItem::create([
                'order_id'     => $order->id,
                'product_id'   => $item['product_id'],
                'booking_date' => $item['date'],
                'quantity'     => $item['quantity'],
                'price'        => $item['price'],
                'total'        => $item['total'],
            ]);
        }

        CartService::clear();

        return redirect()->route('order.success');
    }

    public function render()
    {
        return view('livewire.checkout-form', [
            'cart' => CartService::all()
        ]);
    }
}

Blade View with Message

Add the following code to the resources/views/livewire/checkout-form.blade.php.

<div class="row">

    <div class="col-md-7">
        <h4>Billing Details</h4>

        <input type="text" wire:model="name" placeholder="Full Name" class="form-control mb-2">
        <input type="email" wire:model="email" placeholder="Email" class="form-control mb-2">
        <input type="text" wire:model="phone" placeholder="Phone" class="form-control mb-2">
        <textarea wire:model="address" placeholder="Address" class="form-control mb-3"></textarea>

        <button wire:click="placeOrder" class="btn btn-success w-100">
            Place Order
        </button>
    </div>

    <div class="col-md-5">
        <h4>Order Summary</h4>

        @foreach($cart as $item)
            <div class="border-bottom mb-2 pb-2">
                {{ $item['name'] }} <br>
                Date: {{ $item['date'] }} <br>
                Qty: {{ $item['quantity'] }} <br>
                ₹{{ $item['total'] }}
            </div>
        @endforeach

        <h5 class="mt-3">
            Total: ₹{{ array_sum(array_column($cart, 'total')) }}
        </h5>
    </div>

</div>

It contains user details form with Place Order button to complete the order and Cart Summary with all items and total amount to be payed.

Apply CSS according to your project requirements and you can also add more fields to the checkout form.


Step 3: Add Checkout Route

Add a route to routes/web.php file as follows and point to checkout view.

Route::get('/checkout', function () {
return view('checkout');
})->name('checkout');

Route is point to checkout view. So, create resources/views/checkout.blade.php file and copy the following content to it:

@extends('layouts.app')@section('content')
<div class="container py-5">
<livewire:checkout-form />
</div>
@endsection

Checkout form livewire component is attached in above view file.


What Happens Now?

When user clicks Place Order the following process is being done inside CheckoutForm.php

  1. It validates billing data and creates order record.
  2. It retrieves cart items from session and save them to order items table.
  3. It clears the cart and redirects the user to success page.

You now have a fully working product booking checkout system in Laravel Livewire.


Optional Enhancements

To make this production-ready, you can add:

  • Integrate Stripe / Razorpay payment gateway for actual payment
  • Send email confirmation to admin as well as user
  • Generate invoice on place order or after payment complete or after mark order completed from admin panel.
  • Create order panel using filament to list all orders
  • Order status management