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:
config/lunar/orders.php, rather than a container binding:
Order creation pipeline
Creating an order runs it through an ordered list of pipeline steps, configured the same way, inconfig/lunar/orders.php:
handle(Order $order, Closure $next): mixed:
Order status
An order does not carry a single guarded status. It exposes two independently derived rollups, each aSpatie\ModelStates\State subclass recomputed from the order’s ledger rather than transitioned by hand:
payment_status—Lunar\Core\States\Order\Payment\PaymentStatus(Pending,Authorized,PartiallyPaid,Paid,PartiallyRefunded,Refunded,Voided)fulfilment_status—Lunar\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\OrderSettings—autoClosesSettledOrders(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()andforget()entries from a service provider to add, replace, or remove a notification.Lunar\Core\Contracts\CancelReasonManifestandLunar\Core\Contracts\HoldReasonManifest— the reasons an order can be cancelled, and a fulfilment placed on hold. Both extend the sharedLunar\Core\Contracts\ReasonManifestregistry.