Open source
Shops for Laravel
composer require roundly-consulting/shops-for-laravelOverview
A production-grade e-commerce foundation for Laravel: shops as real tenants, products with options, variants and SKUs, a race-safe inventory ledger, a persistent cart with one-call order placement, a guarded order state machine and exact gross or net tax pricing on arbitrary-precision money. Payments and shipping are driver contracts, so you plug in your own providers. Everything runs through one Shops facade — or an injected manager, or plain action classes — with a recording fake for your tests. It is a building block, not a storefront — MIT-licensed and built only on Laravel and sibling Roundly packages (money, coupons, credits, media, reviews, attributes, addresses, slugs), with no other third-party runtime libraries.
What you get
Shops & tenancy
A real Shop tenant with its own currency and tax rates. Run one store or many, with a current-shop binding that fills ownership automatically.
Products, variants & options
Options compose sellable variants with their own SKU, price, tax class and stock; simple products get a default variant automatically.
Race-safe inventory
An auditable stock ledger with row-locked adjustments, reservations when an order is placed and low-stock events.
Exact money & tax
Arbitrary-precision Money in every amount, gross or net pricing, per-shop and per-country rates in basis points and a per-rate tax summary.
Cart to order, guarded lifecycle
A persistent cart, a one-call transactional checkout that snapshots lines, tax, discount and addresses, and a state machine from New to Refunded.
Facade, DI or actions
Shops::cart(), order() and inventory() handles, the same API on an injected ShopsManager or as action classes — and Shops::fake() records every change.
Pluggable drivers
Payment, shipping, tax, discount, order-number and verified-purchase contracts with zero-config defaults — no vendor SDK.
Documentation
Installation
Install via Composer, publish the fourteen migrations plus the provider packages’ tables, and decide key type and locales before migrating.
Configuration
Every config key and its default — tenant model, pricing, tax, inventory, media, reviews, slugs, payment, shipping, discounts and order numbers.
Quick start
From product to fulfilled order in a dozen lines with the Shops facade and the package’s zero-config defaults.
The Shops facade
Shops::cart(), order() and inventory() handles plus coupons(), current() and addresses() — the whole shop API in one facade, every method listed.
DI and actions
Inject ShopsManager for the same API without static calls, or run the public action classes in jobs and your own actions — with the full action map.
Shops & tenancy
The Shop tenant model, the CurrentShop binding that auto-fills shop_id, the forShop() scope, and swapping in your own tenant model.
Products & categories
Create products and categories, attach categories, schedule publishing and store names and descriptions in several languages.
Slugs & URLs
Per-locale slugs for shops, products and categories — database-enforced uniqueness, locale-aware route binding and opt-in 301 slug history.
Variants, SKUs & options
Sellable variants with their own SKU, price, currency, tax class and stock; options that compose them; and the automatic default variant.
Inventory & stock
An auditable, row-locked stock ledger — adjustments by reason, automatic reservations for orders, and stock and low-stock events.
Money & currencies
Every amount is an exact money-for-laravel Money — casts and decimal(38,0) columns, currency safety, and orders that remember their own currency.
Tax rates
Per-shop, per-country tax rates in basis points, the resolver fallback chain, TaxRateValue, config-only tax and custom resolvers.
Cart
A persistent cart for customers or guests — add variants, price it with or without a coupon, update lines and validate quantities.
Placing orders
Turn a cart into an order in one transaction — lines, stock, coupon, shipping, addresses and buyer — and fill addresses from the address book.
Orders & pricing
The Price DTO — subtotal, discount, net, tax, shipping and final total — with placement snapshots, exact per-line tax and a per-rate summary.
Order status & lifecycle
A guarded state machine — New, InProgress, Paid, Fulfilled, Canceled, Refunded — with timestamps, stock settlement, events and order numbers.
Coupons & discounts
Coupons from coupons-for-laravel — preview codes, price carts, redeem once at place-order with a locked-in discount, or plug in your own resolver.
Pay with store credit
Let buyers pay all or part of an order from a currency-denominated credits bucket, and refund orders back as store credit.
Payments & shipping
Payment and shipping driver contracts with zero-config defaults — implement a gateway, charge orders, refund on your terms and quote shipping.
Product media
Featured and gallery images for products, per-variant images and category banners — public by default, with responsive widths.
Reviews & ratings
Product reviews and rating aggregates via reviews-for-laravel, with verified-purchase flagging from paid and fulfilled orders.
Spec sheet (attributes)
Typed, validated, filterable product attributes via attributes-for-laravel — define them in config, then filter and sort the catalogue.
Extending, events & exceptions
The six swappable drivers, traits for your own models, service classes, every event the package fires and every exception it throws.
Testing
Shops::fake() records every cart change, checkout, charge, transition and stock write for assertions; model factories with states build the data.
Requirements
PHP 8.4+ with ext-bcmath, Laravel 12 or 13, and the sibling Roundly packages Composer installs automatically.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.