davidiwezulu/ecommerce

A flexible e-commerce package for Laravel

v1.0.0 2024-09-28 13:40 UTC

This package is auto-updated.

Last update: 2024-12-28 21:13:38 UTC


README

Latest Version on Packagist Tests License: MIT

Introduction

After letting this gem sit in a private repository for way too long, I decided it was time to dust it off, give it a serious makeover, and finally share it with everyone. What started as a personal side project has now evolved into a full-fledged e-commerce package 🚀.

Overview

An extensible Laravel package providing robust e-commerce functionalities, including cart management, order processing, admin operations, flexible tax calculations, and seamless payment gateway integration (Stripe and PayPal). Designed without a predefined UI to offer maximum flexibility, allowing integration with any Laravel backend, controllers, or views.

Laravel Version Compatibility

This package is compatible with the following Laravel versions:

Requirements

  • PHP: >= 8.0
  • Laravel: 8.x, 9.x, or 10.x
  • Database: MySQL, PostgreSQL, SQLite, or any Laravel-supported database.

Table of Contents

Features

  • Cart Management: Add, update, remove, and retrieve cart items with tax calculations.
  • Order Processing: Create, process, and manage orders with tax-inclusive totals.
  • Admin Operations: Create and manage products, update inventory, and set specific tax rates per product.
  • Payment Gateway Integration: Supports Stripe and PayPal, with options for customization.
  • Flexible Tax System: Configure default tax rates, specify per-product tax rates, and choose whether taxes are included in prices.
  • Currency Configuration: Define default currency symbol and code.
  • Model Customization: Extend and override default models through configuration.
  • Extensibility: Implement custom payment gateways by adhering to the provided interface.
  • Payment Status Handling: Handle successful and failed payments with appropriate responses.
  • Automatic Inventory Tracking: Automatically updates product inventory levels upon successful order placements.
  • Seamless Integration: Designed to integrate with any Laravel application without enforcing any specific frontend or UI.

Installation

Step 1: Install the Package

Use Composer to install the package into your Laravel application:

composer require davidiwezulu/ecommerce

Step 2: Publish Configuration and Migrations

Important: Before running migrations, ensure you have configured the package according to your application's needs. This includes setting up currency, tax settings, payment gateways, and customizing models if necessary.

Publish the package's configuration file and migrations:

php artisan vendor:publish --provider="Davidiwezulu\Ecommerce\EcommerceServiceProvider"

Step 3: Configure the Package

Edit the config/ecommerce.php file to suit your application's requirements. Ensure all configurations are set correctly before proceeding to migrations.

Step 4: Run Migrations

Run the migrations to create the necessary database tables:

php artisan migrate

Configuration

The package provides a configuration file located at config/ecommerce.php, allowing you to customize various aspects.

Important Note

Configure the package before running migrations. This ensures that your custom settings, such as table names and model classes, are correctly applied during the migration process.

Currency Settings

Set your application's default currency in the .env file:

CURRENCY_SYMBOL=£
CURRENCY_CODE=GBP

Or directly in config/ecommerce.php:

    'symbol' => env('CURRENCY_SYMBOL', '£'),
    'code'   => env('CURRENCY_CODE', 'GBP'),
],

Tax Settings

Configure tax settings in the .env file:

TAX_RATE=0.2  # 20% default tax rate
TAX_INCLUDED_IN_PRICES=false  # Are taxes included in product prices?

Or directly in config/ecommerce.php:

'tax' => [
    'default_rate' => env('TAX_RATE', 0.0),
    'included_in_prices' => env('TAX_INCLUDED_IN_PRICES', false),
],

Payment Gateways

Stripe Configuration

In your .env file:

STRIPE_SECRET_KEY=your-stripe-secret-key

In config/ecommerce.php:

'payment_gateways' => [
    'stripe' => [
        'class'      => \Davidiwezulu\Ecommerce\Payments\StripeGateway::class,
        'secret_key' => env('STRIPE_SECRET_KEY'),
    ],
    // ...
],

PayPal Configuration

In your .env file:

PAYPAL_CLIENT_ID=your-paypal-client-id
PAYPAL_SECRET=your-paypal-secret
PAYPAL_MODE=sandbox  # Use 'live' for production

In config/ecommerce.php:

'payment_gateways' => [
    'paypal' => [
        'class'     => \Davidiwezulu\Ecommerce\Payments\PayPalGateway::class,
        'client_id' => env('PAYPAL_CLIENT_ID'),
        'secret'    => env('PAYPAL_SECRET'),
        'mode'      => env('PAYPAL_MODE', 'sandbox'),
    ],
    // ...
],

Custom Models

You can override the default models used by the package in config/ecommerce.php:

'models' => [
    'product'     => App\Models\Product::class,
    'inventory'   => App\Models\Inventory::class,
    'order'       => App\Models\Order::class,
    'order_item'  => App\Models\OrderItem::class,
    'cart_item'   => App\Models\CartItem::class,
],

Database Migrations

The package provides migrations for creating necessary database tables. If you've customized table names or models, ensure that these are correctly set in the configuration before running migrations.

Important: Always back up your database before running new migrations, especially in production environments.

Usage

Cart Management

Manage cart items using the Cart facade.

Adding or Updating Cart Items

use Davidiwezulu\Ecommerce\Facades\Cart;

Cart::addOrUpdate($productId, $quantity);

Removing Cart Items

Cart::remove($productId);

Retrieving Cart Items

$items = Cart::items();

foreach ($items as $item) {
    echo 'Product: ' . $item->product->name . PHP_EOL;
    echo 'Price: ' . $item->price . PHP_EOL;
    echo 'Tax Amount: ' . $item->tax_amount . PHP_EOL;
    echo 'Quantity: ' . $item->quantity . PHP_EOL;
    echo 'Total Price: ' . $item->total_price . PHP_EOL; // Uses getTotalPriceAttribute()
    echo '---' . PHP_EOL;
}

Clearing the Cart

Cart::clear();

Admin Operations

Admins can manage products and inventory using the Admin facade.

Adding a New Product with Tax Rate

use Davidiwezulu\Ecommerce\Facades\Admin;

$productData = [
    'name'        => 'Product Name',
    'price'       => 100.00,
    'tax_rate'    => 0.15, // 15% tax rate
    'description' => 'Product Description',
    'sku'         => 'SKU001',
];

$product = Admin::addProduct($productData);

Updating an Existing Product

$productData = [
    'name'        => 'Updated Product Name',
    'price'       => 120.00,
    'tax_rate'    => 0.18, // Updated tax rate
    'description' => 'Updated Description',
];

$product = Admin::updateProduct($productId, $productData);

Updating Inventory

$quantity = 50; // New stock quantity
Admin::updateInventory($productId, $quantity);

Order Processing

Use the Order facade to create orders and process payments.

Stripe Payment Example

use Davidiwezulu\Ecommerce\Facades\Order;
use Illuminate\Support\Facades\Auth;
use Davidiwezulu\Ecommerce\Facades\Cart;

$paymentDetails = [
    'gateway' => 'stripe',
    'token'   => 'stripe-token', // Token from Stripe.js or Checkout
];

$cartItems = Cart::items()->toArray();

try {
    $order = Order::create(Auth::id(), $cartItems, $paymentDetails);
    Cart::clear();
    return redirect()->route('order.success')->with('message', 'Order created successfully!');
} catch (\Exception $e) {
    return redirect()->route('order.failed')->with('error', 'Payment failed: ' . $e->getMessage());
}

PayPal Payment Example

Step 1: Initiate PayPal Payment

use Davidiwezulu\Ecommerce\Facades\Order;
use Illuminate\Support\Facades\Auth;

$paymentDetails = [
    'gateway'    => 'paypal',
    'return_url' => route('paypal.return'),
    'cancel_url' => route('paypal.cancel'),
];

$cartItems = Cart::items()->toArray();

try {
    // This will redirect the user to PayPal for payment approval
    return Order::create(Auth::id(), $cartItems, $paymentDetails);
} catch (\Exception $e) {
    return redirect()->route('order.failed')->with('error', 'Payment initiation failed: ' . $e->getMessage());
}

Step 2: Handle PayPal Return (After User Approval)

Create routes in your web.php:

Route::get('/paypal/return', [PaymentController::class, 'handlePayPalReturn'])->name('paypal.return');
Route::get('/paypal/cancel', [PaymentController::class, 'handlePayPalCancel'])->name('paypal.cancel');

Implement the controller methods:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Davidiwezulu\Ecommerce\Services\OrderService;
use Davidiwezulu\Ecommerce\Facades\Cart;

class PaymentController extends Controller
{
    public function handlePayPalReturn(Request $request)
    {
        $paymentId = $request->get('paymentId');
        $payerId   = $request->get('PayerID');
        $userId    = Auth::id();
        $cartItems = Cart::items()->toArray();

        try {
            $orderService = new OrderService();
            $order = $orderService->executePayPalPayment($paymentId, $payerId, $userId, $cartItems);
            Cart::clear();
            return redirect()->route('order.success')->with('message', 'Order created successfully!');
        } catch (\Exception $e) {
            return redirect()->route('order.failed')->with('error', 'Payment failed: ' . $e->getMessage());
        }
    }

    public function handlePayPalCancel()
    {
        return redirect()->route('order.cancelled')->with('message', 'Payment was cancelled.');
    }
}

Tax Calculations

The package supports flexible tax calculations, including per-product tax rates and configurable default tax rates.

Adding a Product with a Specific Tax Rate

use Davidiwezulu\Ecommerce\Facades\Admin;

$productData = [
    'name'        => 'Taxed Product',
    'price'       => 200.00,
    'tax_rate'    => 0.10, // 10% tax rate
    'description' => 'A product with a specific tax rate',
    'sku'         => 'TP-002',
];

$product = Admin::addProduct($productData);

Calculating Tax in Cart Items

When you add or update items in the cart, the tax amount is automatically calculated based on the product's tax rate or the default tax rate.

use Davidiwezulu\Ecommerce\Facades\Cart;

// Add product to cart
Cart::addOrUpdate($productId, $quantity);

// Retrieve cart items with tax details
$items = Cart::items();

foreach ($items as $item) {
    echo 'Product: ' . $item->product->name . PHP_EOL;
    echo 'Price: ' . $item->price . PHP_EOL;
    echo 'Tax Amount: ' . $item->tax_amount . PHP_EOL;
    echo 'Total Price (incl. Tax): ' . $item->total_price . PHP_EOL;
}

Extending the Package

Custom Models

Benefit of Custom Models: Defining models in the configuration allows you to override or extend the default models provided by the package with your own custom models. This provides flexibility to add custom methods, relationships, and business logic specific to your application.

Extend Package Models (Optional)

You can extend the package's default models if you want to retain the base functionality while adding your customizations.

Example:

namespace App\Models;

use Davidiwezulu\Ecommerce\Models\Product as BaseProduct;

class Product extends BaseProduct
{
    // Add your customizations here

    /**
     * Example of adding a new relationship.
     */
    public function categories()
    {
        return $this->belongsToMany(Category::class);
    }

    /**
     * Example of adding a custom method.
     */
    public function calculateDiscountedPrice()
    {
        // Implement your discount logic here
    }
}

Update Configuration:

In config/ecommerce.php:

'models' => [
    'product' => App\Models\Product::class,
    // Other models...
],

Explanation:

By extending BaseProduct, you retain all the original functionality provided by the package. You can add new relationships, methods, accessors, and mutators in your custom Product model. The package will use your custom model throughout its operations.

Adding Custom Payment Gateways

You can add new payment gateways by implementing the PaymentGatewayInterface.

Create a Custom Gateway Class

namespace App\Payments;

use Davidiwezulu\Ecommerce\Payments\PaymentGatewayInterface;

class CustomGateway implements PaymentGatewayInterface
{
    public function charge($amount, $paymentDetails)
    {
        // Implement charge logic
    }

    public function execute($paymentId, $payerId)
    {
        // Implement execute logic (if needed)
    }

    public function refund($transactionId)
    {
        // Implement refund logic
    }
}

Register the Custom Gateway

In config/ecommerce.php:

'payment_gateways' => [
    // Existing gateways...
    'custom_gateway' => [
        'class' => \App\Payments\CustomGateway::class,
        // Additional configuration...
    ],
],

License

This package is open-sourced software licensed under the MIT license.

Conclusion

The Laravel E-commerce package provides a comprehensive solution for implementing e-commerce functionality in your Laravel application. With features like flexible tax calculations, seamless payment gateway integration, and customizable models, it offers a solid foundation for building robust online stores.

Important: Remember to configure the package appropriately before running migrations to ensure a smooth integration with your application.

For any questions or contributions, feel free to open an issue or submit a pull request on GitHub.

Thank you for choosing the Laravel E-commerce package!