Laravel 12 E-Commerce Project Tutorial

Implementing Coupon Functionality on the Shopping Cart

Hi everyone, welcome back to the Laravel E-Commerce Project Tutorial. In this section, we will integrate the coupon system into the shopping cart to apply discounts based on valid coupon codes.

  1. Coupon Application and Discount Calculation Logic (CartController)

    Open your CartController and add two new public methods: apply_coupon_code and calculateDiscounts.

    1. apply_coupon_code(Request $request)

    This method handles the coupon submission. It validates the code against three conditions: it must exist in the database, it must not be expired (expiry_date >= Carbon::today()), and the cart subtotal must meet the minimum purchase requirement (cart_value <= Cart::instance("cart")->subtotal()).

    use CarbonCarbon; // Ensure you include Carbon at the top
    public function apply_coupon_code(Request $request)
    {
    $coupon_code = $request->coupon_code;

    if (empty($coupon_code)) {
    return back()->with("error", "Please enter a coupon code.");
    }
    $coupon = Coupon::where("code", $coupon_code)
    ->where("expiry_date", ">=", Carbon::today())
    ->where("cart_value", "<=", Cart::instance("cart")->subtotal())
    ->first();
    if (!$coupon) {
    return back()->with("error", "Invalid or ineligible coupon code!");
    }
    // Store coupon details in the session
    session()->put("coupon", [
    "code" => $coupon->code,
    "type" => $coupon->type,
    "value" => $coupon->value,
    "cart_value" => $coupon->cart_value
    ]);
    // Calculate and store the new totals
    $this->calculateDiscounts();
    return back()->with("status", "Coupon has been applied successfully!");
    }

    2. calculateDiscounts()

    This helper method computes the discount amount, calculates the new subtotal, tax, and total, and updates the discounts array in the session.

    public function calculateDiscounts()
    {
    $discount = 0;
    $cartSubtotal = Cart::instance("cart")->subtotal();
    if (session()->has("coupon")) {
    $couponData = session()->get("coupon");

    if ($couponData["type"] == "fixed") {
    $discount = $couponData["value"];
    } else {
    // Calculate percentage discount
    $discount = ($cartSubtotal * $couponData["value"]) / 100;
    }
    }
    $subtotalAfterDiscount = $cartSubtotal - $discount;

    // Ensure the tax calculation uses the discounted subtotal
    $taxRate = config("cart.tax");
    $taxAfterDiscount = ($subtotalAfterDiscount * $taxRate) / 100;

    $totalAfterDiscount = $subtotalAfterDiscount + $taxAfterDiscount;
    session()->put("discounts", [
    // Format all values to two decimal places
    "discount" => number_format(floatval($discount), 2, ".", ""),
    "subtotal" => number_format(floatval($subtotalAfterDiscount), 2, ".", ""),
    "tax" => number_format(floatval($taxAfterDiscount), 2, ".", ""),
    "total" => number_format(floatval($totalAfterDiscount), 2, ".", ""),
    ]);
    }

    3. Coupon Removal Logic (remove_coupon_code())

    Add a method to remove the coupon and reset the cart totals to their default state.

    public function remove_coupon_code()
    {
    session()->forget("coupon");
    session()->forget("discounts");
    return back()->with("status", "Coupon has been removed!");
    }
  2. Define the Routes

    Add the following routes to your web.php file (or relevant frontend route file):

    // Assuming these routes are within your authenticated or web middleware group
    Route::post("/cart/coupon/apply",[CartController::class,"apply_coupon_code"])->name("cart.coupon.apply");
    Route::delete("/cart/coupon/remove",[CartController::class,"remove_coupon_code"])->name("cart.coupon.remove");
  3. Update the Cart View (cart.blade.php)

    We need to update two parts of the cart view: the coupon form area and the cart totals summary.

    1. Conditional Coupon Form

    Replace the static coupon input form with conditional logic to show either the Apply Coupon form or the Remove Coupon button, based on the session:

    <div class="cart-form">
    <!-- Display flash messages for status or error -->
    @if(Session::has("status"))
    <p class="alert alert-success">{{Session::get("status")}}</p>
    @endif
    @if(Session::has("error"))
    <p class="alert alert-danger">{{Session::get("error")}}</p>
    @endif
    @if(Session::has("coupon"))
    <form action="{{ route("cart.coupon.remove") }}" method="POST">
    @csrf
    @method("DELETE")
    <input class="form-control" type="text" name="coupon_code" placeholder="Coupon Code" value="{{ Session::get("coupon")["code"] }} Applied!" readonly>
    <button class="btn btn-danger btn-hover-primary mt-3" type="submit">Remove Coupon</button>
    </form>
    @else
    <form action="{{ route("cart.coupon.apply") }}" method="POST">
    @csrf
    <input class="form-control" type="text" name="coupon_code" placeholder="Coupon Code" value="">
    <button class="btn btn-dark btn-hover-primary mt-3" type="submit">Apply Coupon</button>
    </form>
    @endif
    </div>

    2. Conditional Cart Totals

    Modify the cart totals table to check if the discounts session exists. If it does, display the discounted totals; otherwise, show the standard cart totals.

    <div class="cart-total-table">
    @if(Session::has("discounts"))
    <table class="table">
    <tbody>
    <tr>
    <td class="value">Subtotal (Original)</td>
    <td class="price">${{ Cart::instance("cart")->subtotal() }}</td>
    </tr>
    <tr>
    <td class="value">Discount</td>
    <td class="price">${{ Session::get("discounts")["discount"] }}</td>
    </tr>
    <tr>
    <td class="value">Subtotal After Discount</td>
    <td class="price">${{ Session::get("discounts")["subtotal"] }}</td>
    </tr>
    <tr>
    <td class="value">Shipping</td>
    <td class="price">Free</td>
    </tr>
    <tr>
    <td class="value">VAT</td>
    <td class="price">${{ Session::get("discounts")["tax"] }}</td>
    </tr>
    <tr>
    <td class="value"><strong>Total</strong></td>
    <td class="price"><strong>${{ Session::get("discounts")["total"] }}</strong></td>
    </tr>
    </tbody>
    </table>
    @else
    <table class="table">
    <tbody>
    <tr>
    <td class="value">Subtotal</td>
    <td class="price">${{ Cart::instance("cart")->subtotal() }}</td>
    </tr>
    <tr>
    <td class="value">Shipping</td>
    <td class="price">Free</td>
    </tr>
    <tr>
    <td class="value">VAT</td>
    <td class="price">${{ Cart::instance("cart")->tax() }}</td>
    </tr>
    <tr>
    <td class="value"><strong>Total</strong></td>
    <td class="price"><strong>${{ Cart::instance("cart")->total() }}</strong></td>
    </tr>
    </tbody>
    </table>
    @endif
    </div>
    <div class="cart-total-btn">
    <a href="{{ route("cart.checkout") }}" class="btn btn-dark btn-hover-primary btn-block">Proceed To Checkout</a>
    </div>

Verification and Testing ✨

Add a product to your cart and navigate to the cart page. Enter a valid coupon code, such as OFF10, into the form and click Apply Coupon. You should see the following changes:

  • A success message indicating the coupon has been applied.
  • The coupon form should be replaced by the Remove Coupon button.
  • The Cart Totals table will update to show the Discount, Subtotal After Discount, Tax, and the final discounted Total.

This successfully implements the coupon functionality on the shopping cart.