selli / commerce
A headless, catalog-agnostic commerce domain engine for Laravel: cart, order lifecycle, deterministic pricing pipeline, tax and inventory — multi-tenant, multi-currency, audited and ACL-protected.
Fund package maintenance!
Requires
- php: ^8.3
- brick/money: ^0.10 || ^0.11
- illuminate/contracts: ^11.0 || ^12.0 || ^13.0
- spatie/laravel-model-states: ^2.7 || ^3.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.8
- orchestra/testbench: ^9.0 || ^10.0 || ^11.0
- pestphp/pest: ^3.0 || ^4.0
- pestphp/pest-plugin-arch: ^3.0 || ^4.0
- pestphp/pest-plugin-laravel: ^3.0 || ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
Suggests
- spatie/laravel-event-sourcing: Required to run the Order aggregate as an event-sourced aggregate (Audit level 2).
- spatie/laravel-multitenancy: Adapter available to resolve the current tenant from spatie/laravel-multitenancy.
- spatie/laravel-permission: Required for granular role/permission ACL beyond native Gate/Policy.
- stancl/tenancy: Adapter available to resolve the current tenant from stancl/tenancy.
This package is auto-updated.
Last update: 2026-06-28 10:45:51 UTC
README
Laravel Commerce
A headless, catalog-agnostic commerce domain engine for Laravel: cart, order lifecycle, a deterministic pricing pipeline, multi-tenancy, multi-currency, an immutable audit trail and ACL — the transactional heart you build stores, checkouts, booking systems and quote flows on top of.
It is not a turnkey store. It owns the parts of commerce that are hard to get right and identical
across projects — money, order states, the calculation pipeline — and nothing else. Your catalogue
stays yours: anything implementing the Purchasable contract becomes sellable.
📚 Full documentation: https://laravel-commerce.selli.io
Why
Every commercial app re-writes cart, totals, discounts, VAT and order states — and re-introduces the same bugs (rounding, inclusive/exclusive tax, stock race conditions) project after project. Laravel Commerce is one engine, tested to the bone, reused across N projects.
Highlights
- Catalog-agnostic — binds to your models via the
Purchasablecontract; freezes an immutable order snapshot so history never changes when your catalogue does. - Headless & unopinionated — no routes, controllers or templates imposed. Pure service layer + events.
- Money correct by construction —
brick/moneyin minor units, never a float; centralised, per-currency rounding. - Deterministic calculation pipeline — an explainable, line-by-line breakdown; reorderable and extensible without touching the core.
- Order state machine —
spatie/laravel-model-states; illegal transitions are impossible by construction, authorised by policy and logged append-only. - Multi-tenant & multi-currency —
tenant_id+ global scope on every table; one engine serves single-tenant and SaaS alike. - Audited — every domain event persisted append-only; optional event sourcing for the Order aggregate.
- Optional modules — toggle each independently: Pricing (price books, coupons, promotions, gift cards), Tax (per-line jurisdictions, inclusive/exclusive, EU exemption & reverse charge) and Inventory (per-warehouse stock, TTL reservations, oversell prevention under a lock).
Requirements
- PHP 8.3+ (8.3 / 8.4 / 8.5)
- Laravel 12 or 13
Installation
composer require selli/commerce
php artisan vendor:publish --tag="commerce-migrations"
php artisan migrate
Quick start
use Selli\Commerce\Cart\CartManager; use Selli\Commerce\Order\Actions\PlaceOrder; use Selli\Commerce\Order\Actions\TransitionOrderState; use Selli\Commerce\Order\States\Confirmed; $carts = app(CartManager::class); $cart = $carts->forOwner('user', (string) $user->id, 'EUR'); $carts->add($cart, $product, quantity: 2, options: ['size' => 'L']); $calculation = $carts->calculate($cart); // deterministic, explainable $calculation->grandTotal(); // Brick\Money\Money $calculation->breakdown(); // subtotal, discounts, tax, lines $order = app(PlaceOrder::class)->handle($cart); // transactional, emits OrderPlaced $order->state; // Pending app(TransitionOrderState::class)->handle($order, Confirmed::class, by: $agent, reason: 'payment ok');
See the Quick Start guide for the
full walkthrough, including implementing Purchasable on your model.
Documentation
The documentation site is built with docmd:
npm install npm run docs:build # outputs to ./site npm run docs:dev # local preview
Testing
composer test # Pest suite composer test-coverage # with 90% minimum coverage gate composer analyse # PHPStan (max level) composer format # Pint
Roadmap
The core (cart, order, calculation pipeline, multi-tenancy, multi-currency, audit, ACL) and the Pricing & Promotions, Tax and Inventory modules have shipped. Next on the roadmap: Payments orchestration, Fulfillment and optional REST/GraphQL/Filament surfaces.
License
The MIT License (MIT). See License File.
