Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Order Laravel Package

vanilo/order

Vanilo Order provides the core order management layer for Laravel e-commerce applications built on Vanilo. It includes order and order item models, status handling, adjustments, totals, and the business logic needed to create, calculate, and process customer orders.

View on GitHub
Deep Wiki
Context7

Getting Started

vanilo/order is the order/order-item backbone of the Vanilo e-commerce stack. It does not ship a storefront or admin UI; it gives you the models, contracts, factories, status handling, number generation and events you build checkout/order management on top of.

Install:

composer require vanilo/order

The module registers via Laravel package discovery. Publish and run migrations before touching anything else:

php artisan vendor:publish --tag=vanilo-order-migrations
php artisan migrate

Also publish config/order.php if you plan to change model bindings or order-number behaviour (check vendor/vanilo/order/src/Providers/ModuleServiceProvider.php for the exact publish tags in your installed version).

Where to look first, in this order:

  1. src/Contracts/ — Order, OrderItem, OrderFactory, OrderStatus, OrderNumberGenerator. These define the public seam.
  2. src/Models/Order.php — the concrete implementation, its relations (items(), customer()), and total calculations.
  3. config/order.php — model swaps and the number-generator block.
  4. src/Events/ — OrderCreated, OrderUpdated, OrderStatusChanged, etc. These are your integration hooks.

First use case: turn a cart/cart-like object into an order.

The canonical flow is through the OrderFactory contract, not Order::create():

use Vanilo\Order\Contracts\OrderFactory;

$order = app(OrderFactory::class)->createFromPayable($cart);

Anything implementing the Payable contract (the Vanilo cart does) can be converted. From there:

$order->number;             // generated per config
$order->items;              // OrderItem collection
$order->total();            // Money object
$order->status;             // OrderStatus enum/instance

If you are not using Vanilo's cart, use createFromDataArray() with the shape the factory expects, or subclass the factory and bind your own.

Implementation Patterns

Checkout via the factory, then decorate. Don't build orders by hand in controllers. Let OrderFactory create the order and items from the payable, then layer your own domain data (payment method, shipping address, notes) onto the returned order before saving:

$order = app(OrderFactory::class)->createFromPayable($cart, [
    'payment_method' => 'stripe',
    'notes' => $request->input('notes'),
]);
$order->save();

Keeping creation inside the factory preserves numbering, item copying and event dispatch.

Status is a first-class concept, not a string. Cast/read $order->status through the OrderStatus contract. Transitioning should be explicit:

use Vanilo\Order\Contracts\OrderStatus;

$order->status = OrderStatus::PROCESSING;
$order->save(); // fires OrderStatusChanged

Build a small transition policy (pending → processing → completed/cancelled) in your app layer; the package deliberately does not enforce a state machine.

React to events rather than editing vendor code. Listen for OrderCreated to send confirmations, push to a fulfilment queue, or sync to an ERP. Listen for OrderStatusChanged for customer notifications. Register listeners in your own EventServiceProvider — nothing needs to be hacked into the module.

Swap models via config, not by patching. When you need extra columns or behaviour:

// config/order.php
'models' => [
    'order' => App\Models\Order::class,        // extends Vanilo\Order\Models\Order
    'order_item' => App\Models\OrderItem::class,
],

Always extend the base model so traits, casts and relations survive.

Number generation strategy. Defaults are typically a sequential generator; for high-volume or multi-node setups switch to the time-hash generator in the number_generator config block. Implement OrderNumberGenerator if you need invoice-style prefixes (INV-2024-000123).

Admin integration. If you use vanilo/admin (Orchid-based), the module's order screens light up automatically once installed. For custom back-office screens, query Order::with('items') and paginate — the module gives you no list controllers of its own.

Totals. Treat $order->total() as the source of truth and recompute after any item mutation; don't cache totals in your own column unless you also hook the update events.

Gotchas and Tips

  • Payable mismatch is the #1 failure. createFromPayable() expects an object implementing the contract with the right item/total accessors. If you roll your own cart, either implement Payable or use createFromDataArray(); do not Order::create() and hope.
  • Order number collisions. The sequential generator is not safe under concurrent checkouts without a DB unique constraint plus retry. Keep the number column unique and prefer the time-hash generator in production.
  • Status enum drift. Vanilo moved status representation across major versions (class constants → enums). Pin your vanilo/order version, and if you compare $order->status === 'pending', verify it — use $order->status->value or the enum cases instead of loose strings.
  • Mass assignment surprises. Order/OrderItem guard or fill specific attributes. Extra fields you add via a swapped model need to be added to $fillable on your subclass, or you'll silently drop them.
  • N+1 on order lists. $order->total() and item counts iterate items. Always Order::with('items') on index pages.
  • Money precision. Amounts are Money objects backed by integer minor units. Do not (float) cast totals for storage; convert only at the presentation boundary.
  • Missing module migrations. Installing order without vanilo/cart/vanilo/product leaves foreign keys or customer relations unbacked. Run migrations in dependency order and check order_items constraints.
  • Publish tags vary by version. If vendor:publish --tag=... fails, list providers with php artisan vendor:publish and pick the module's tag from the interactive menu.
  • Extension points to prefer: config model swaps, OrderNumberGenerator binding, OrderFactory binding, and event listeners. Avoid subclassing models and overriding relations unless the config swap is genuinely insufficient.
  • Testing tip. Use Event::fake() around factory calls and assert OrderCreated rather than inspecting DB rows; it keeps tests aligned with how the package is meant to be consumed.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console