Skip to main content
The order system is extended by swapping action contracts in the container, registering pipeline steps for order creation, and binding a handful of dedicated registries for order-level preferences and notifications.

Overview

Lunar\Core\Models\Order exposes its operations as verb methods, each a one-line delegation to an action contract resolved from the container:
There is no ship() or fulfil() verb on Order itself — fulfilment shipping is a verb on the Fulfilment model created by createFulfilment() ($fulfilment->ship($tracking)).

Order action contracts

Lunar\Core\ActionServiceProvider’s $actions map is the canonical list of swappable action seams. The order-related entries, each a Lunar\Core\Contracts\Actions\Orders\* interface bound to its Lunar\Core\Actions\Orders\* default implementation: Creating an order from a cart is a cart-side operation: Cart::createOrder() delegates to Contracts\Carts\CreatesOrder. See Extending Carts. Rebind a contract from a consumer’s own service provider:

Order reference generation

Contracts\Orders\GeneratesOrderReference’s default implementation, Actions\Orders\GenerateOrderReference, formats a reference through whichever class implements Lunar\Core\Contracts\OrderReferenceGenerator:
That class is currently selected through config/lunar/orders.php, rather than a container binding:
Implement the interface and point the config key at the custom class:

Order creation pipeline

Creating an order runs it through an ordered list of pipeline steps, configured the same way, in config/lunar/orders.php:
Add a pipe by appending a class implementing handle(Order $order, Closure $next): mixed:
Pipes run in the order listed, top to bottom.

Order status

An order does not carry a single guarded status. It exposes two independently derived rollups, each a Spatie\ModelStates\State subclass recomputed from the order’s ledger rather than transitioned by hand:
  • payment_statusLunar\Core\States\Order\Payment\PaymentStatus (Pending, Authorized, PartiallyPaid, Paid, PartiallyRefunded, Refunded, Voided)
  • fulfilment_statusLunar\Core\States\Order\Fulfilment\FulfilmentStatus (Unfulfilled, PartiallyFulfilled, Fulfilled, PartiallyReturned, Returned)
Contracts\Orders\ResolvesPaymentStatus and Contracts\Orders\ResolvesFulfilmentStatus compute these values whenever the order’s transactions or fulfilments change; because any value can follow any other, extending order-level status logic means rebinding those two action contracts rather than editing a transition table. The order’s broader lifecycle — isOpen(), isClosed(), isCancelled(), lifecycleStatus() — is a plain computed method over cancelled_at and closed_at, not a state machine.
Fulfilments do have a guarded, extensible state machine: Lunar\Core\States\Fulfilment\FulfilmentState, governed by Lunar\Core\Contracts\FulfilmentStateConfig. Bind a custom implementation of that contract in a service provider’s register() to add states or reshape the transition table.

Order preferences and notifications

A handful of order-level concerns are container-bound registries rather than config, since they are expected to become per-store (channel) values:
  • Lunar\Core\Contracts\OrderSettingsautoClosesSettledOrders(Order $order): bool. Bind a custom implementation to change whether an order auto-closes once fully paid and fulfilled.
  • Lunar\Core\Contracts\OrderNotificationManifest — the catalogue of notifications sent about an order. register() and forget() entries from a service provider to add, replace, or remove a notification.
  • Lunar\Core\Contracts\CancelReasonManifest and Lunar\Core\Contracts\HoldReasonManifest — the reasons an order can be cancelled, and a fulfilment placed on hold. Both extend the shared Lunar\Core\Contracts\ReasonManifest registry.
Lunar\Core\Modifiers\OrderModifier and its OrderModifiers collection are registered in the container, but nothing in core currently runs an order through them. Do not rely on OrderModifier for order-total or order-creation hooks; use the creation pipeline or an action contract instead.