> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lunarphp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Extending Orders

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:

```php theme={null}
public function cancel(?string $reason = null, ?string $note = null, bool $notify = true): Order
{
    return app(CancelsOrder::class)->execute($this, $reason, $note, $notify);
}
```

| Verb                                                                                    | Delegates to        |
| --------------------------------------------------------------------------------------- | ------------------- |
| `createFulfilment(array $lines, array $attributes = [])`                                | `CreatesFulfilment` |
| `cancel(?string $reason = null, ?string $note = null, bool $notify = true)`             | `CancelsOrder`      |
| `notifyCustomer(string $notification, ?string $message = null, array $recipients = [])` | `NotifiesCustomer`  |
| `close()`                                                                               | `ClosesOrder`       |
| `reopen()`                                                                              | `ReopensOrder`      |
| `capture(int\|string $transactionId, float\|int\|string $amount)`                       | `CapturesOrder`     |
| `refund(RefundRequest $request)`                                                        | `RefundsOrder`      |

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:

| Contract                   | Default implementation    |
| -------------------------- | ------------------------- |
| `CancelsOrder`             | `CancelOrder`             |
| `CapturesOrder`            | `CaptureOrder`            |
| `ClosesOrder`              | `CloseOrder`              |
| `GeneratesOrderReference`  | `GenerateOrderReference`  |
| `NotifiesCustomer`         | `NotifyCustomer`          |
| `RecomputesOrderStatus`    | `RecomputeOrderStatus`    |
| `RefundsOrder`             | `RefundOrder`             |
| `ReopensOrder`             | `ReopenOrder`             |
| `ResolvesFulfilmentStatus` | `ResolveFulfilmentStatus` |
| `ResolvesPaymentStatus`    | `ResolvePaymentStatus`    |

Creating an order from a cart is a cart-side operation: `Cart::createOrder()` delegates to `Contracts\Carts\CreatesOrder`. See [Extending Carts](/2.x/extending/carts).

Rebind a contract from a consumer's own service provider:

```php theme={null}
use Lunar\Core\Contracts\Actions\Orders\CancelsOrder;

public function register(): void
{
    $this->app->bind(CancelsOrder::class, MyCancelsOrder::class);
}
```

## Order reference generation

`Contracts\Orders\GeneratesOrderReference`'s default implementation, `Actions\Orders\GenerateOrderReference`, formats a reference through whichever class implements `Lunar\Core\Contracts\OrderReferenceGenerator`:

```php theme={null}
namespace Lunar\Core\Contracts;

interface OrderReferenceGenerator
{
    public function generate(Order $order): string;
}
```

That class is currently selected through `config/lunar/orders.php`, rather than a container binding:

```php theme={null}
'reference_generator' => Lunar\Core\Orders\ReferenceGenerator::class,

'reference_format' => [
    'prefix' => null,
    'padding_direction' => STR_PAD_LEFT,
    'padding_character' => '0',
    'length' => 8,
],
```

Implement the interface and point the config key at the custom class:

```php theme={null}
<?php

namespace App\Orders;

use Lunar\Core\Contracts\OrderReferenceGenerator;
use Lunar\Core\Models\Order;

class MyReferenceGenerator implements OrderReferenceGenerator
{
    public function generate(Order $order): string
    {
        return 'ORD-'.$order->id;
    }
}
```

```php theme={null}
'reference_generator' => App\Orders\MyReferenceGenerator::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`:

```php theme={null}
'pipelines' => [
    'creation' => [
        Lunar\Core\Pipelines\Order\Creation\FillOrderFromCart::class,
        Lunar\Core\Pipelines\Order\Creation\CreateOrderLines::class,
        Lunar\Core\Pipelines\Order\Creation\CreateOrderAddresses::class,
        Lunar\Core\Pipelines\Order\Creation\CreateShippingLine::class,
        Lunar\Core\Pipelines\Order\Creation\CleanUpOrderLines::class,
        Lunar\Core\Pipelines\Order\Creation\MapDiscountBreakdown::class,
    ],
],
```

Add a pipe by appending a class implementing `handle(Order $order, Closure $next): mixed`:

```php theme={null}
<?php

namespace App\Pipelines\Orders;

use Closure;
use Lunar\Core\Models\Order;

class CustomOrderPipeline
{
    public function handle(Order $order, Closure $next): mixed
    {
        // ...

        return $next($order);
    }
}
```

```php theme={null}
'pipelines' => [
    'creation' => [
        // ...
        App\Pipelines\Orders\CustomOrderPipeline::class,
    ],
],
```

<Tip>
  Pipes run in the order listed, top to bottom.
</Tip>

## 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_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.

<Info>
  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.
</Info>

## 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()` 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.

```php theme={null}
use Lunar\Core\Contracts\OrderSettings;

public function register(): void
{
    $this->app->singleton(OrderSettings::class, MyOrderSettings::class);
}
```

<Warning>
  `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.
</Warning>
