Skip to main content
Orders represent customer purchases and are central to your e-commerce operations. Shopper provides a comprehensive order management system with support for items, addresses, shipping, refunds, and status tracking.

Models

Shopper uses five models to manage orders:
Shopper\Core\Models\Order          // The main order
Shopper\Core\Models\OrderItem      // Products in the order
Shopper\Core\Models\OrderAddress   // Billing and shipping addresses
Shopper\Core\Models\OrderShipping  // Shipping and tracking information
Shopper\Core\Models\OrderRefund    // Refund requests
use Shopper\Core\Models\Order;

// The model implements
- Shopper\Core\Models\Contracts\Order

// Uses traits
- SoftDeletes

Extending the Model

namespace App\Models;

use Shopper\Core\Models\Order as BaseOrder;

class Order extends BaseOrder
{
    // Add your customizations here
}
Update config/shopper/models.php:
return [
    'order' => \App\Models\Order::class,
];

Database Schema

Order Table

ColumnTypeNullableDefaultDescription
idbigintnoautoPrimary key
numberstring(32)no-Order number
price_amountintegeryesnullOrder price override (in cents)
statusstring(32)nonewOrder status enum
payment_statusstring(32)nopendingPayment status enum
shipping_statusstring(32)nounfulfilledShipping status enum
currency_codestringno-Currency code (USD, EUR, etc.)
notestextyesnullOrder notes
parent_order_idbigintyesnullFK to parent order
payment_method_idbigintyesnullFK to payment method
channel_idbigintyesnullFK to channel
customer_idbigintyesnullFK to user
zone_idbigintyesnullFK to zone
billing_address_idbigintyesnullFK to order address
shipping_address_idbigintyesnullFK to order address
shipping_option_idbigintyesnullFK to carrier option
cancelled_attimestampyesnullCancellation date
archived_attimestampyesnullArchive date
deleted_attimestampyesnullSoft delete timestamp
created_attimestampyesnullCreation timestamp
updated_attimestampyesnullLast update timestamp

OrderItem Table

ColumnTypeNullableDescription
idbigintnoPrimary key
namestringyesProduct name at time of purchase
skustringyesProduct SKU at time of purchase
quantityintegernoQuantity ordered
unit_price_amountintegernoUnit price (in cents)
product_idbigintnoPolymorphic relation ID
product_typestringnoPolymorphic relation type
order_idbigintnoFK to order
order_shipping_idbigintyesFK to order_shipping (shipment)
fulfillment_statusstringyesFulfillment status enum value

OrderAddress Table

ColumnTypeNullableDescription
idbigintnoPrimary key
customer_idbigintnoFK to user
first_namestringnoFirst name
last_namestringnoLast name
companystringyesCompany name
street_addressstringnoStreet address
street_address_plusstringyesAdditional address line
postal_codestringnoPostal/ZIP code
citystringnoCity
statestringyesState/province/region
phonestringyesPhone number
country_namestringyesCountry name

OrderShipping Table

ColumnTypeNullableDescription
idbigintnoPrimary key
statusstring(32)yesShipment status enum
shipped_atdatetimeyesShipment date
received_atdatetimeyesDelivery date
returned_atdatetimeyesReturn date
tracking_numberstringyesCarrier tracking number
tracking_urlstringyesTracking URL
voucherjsonyesShipping voucher data
order_idbigintnoFK to order
carrier_idbigintyesFK to carrier

OrderRefund Table

ColumnTypeNullableDescription
idbigintnoPrimary key
refund_reasonstringyesRefund reason
refund_amountintegeryesRefund amount (in cents)
statusstringnoRefund status enum
currencystringnoCurrency code
notesstringyesAdmin notes
order_idbigintnoFK to order
user_idbigintyesFK to user processing refund

Order Status

Every order tracks three independent statuses: order status, payment status, and shipping status. This separation allows each aspect of the order to progress independently — for example, an order can be paid before it’s shipped, or partially shipped while still processing.

Order Status

The OrderStatus enum tracks the overall lifecycle of the order:
use Shopper\Core\Enum\OrderStatus;

OrderStatus::New         // new (default)
OrderStatus::Processing  // processing
OrderStatus::Completed   // completed
OrderStatus::Cancelled   // cancelled
OrderStatus::Archived    // archived
StatusDatabase ValueColorDescription
NewnewinfoNewly placed order
ProcessingprocessingprimaryOrder is being prepared
CompletedcompletedtealOrder fulfilled and delivered
CancelledcancelleddangerOrder cancelled
ArchivedarchivedgrayRemoved from active list

Payment Status

The PaymentStatus enum tracks whether payment has been collected. It is updated automatically by the PaymentProcessingService as transactions succeed.
use Shopper\Core\Enum\PaymentStatus;

PaymentStatus::Pending             // pending (default)
PaymentStatus::Authorized          // authorized
PaymentStatus::Paid                // paid
PaymentStatus::PartiallyRefunded   // partially_refunded
PaymentStatus::Refunded            // refunded
PaymentStatus::Voided              // voided
StatusDatabase ValueColorDescription
PendingpendingwarningAwaiting payment
AuthorizedauthorizedinfoFunds held, not yet captured
PaidpaidsuccessFunds collected
Partially Refundedpartially_refundedorangeSome amount refunded
RefundedrefundedgrayFull amount refunded
VoidedvoideddangerCancelled before capture
For the full payment lifecycle, capture strategies, and transaction recording, see the Payments page.

Shipping Status

The ShippingStatus enum tracks the overall shipping state at the order level. It reflects the combined state of all shipments on the order.
use Shopper\Core\Enum\ShippingStatus;

ShippingStatus::Unfulfilled        // unfulfilled (default)
ShippingStatus::PartiallyShipped   // partially_shipped
ShippingStatus::Shipped            // shipped
ShippingStatus::PartiallyDelivered // partially_delivered
ShippingStatus::Delivered          // delivered
ShippingStatus::PartiallyReturned  // partially_returned
ShippingStatus::Returned           // returned
StatusDatabase ValueColorDescription
UnfulfilledunfulfilledwarningNo items shipped yet
Partially Shippedpartially_shippedinfoSome items shipped
ShippedshippedindigoAll items shipped
Partially Deliveredpartially_deliveredprimarySome packages delivered
DelivereddeliveredsuccessAll packages delivered
Partially Returnedpartially_returnedorangeSome items returned
ReturnedreturnedgrayAll items returned
For shipment-level tracking (individual packages with carriers and tracking numbers), see the Fulfillment page.

Status Check Methods

$order->isNew();               // true if status is New
$order->isProcessing();        // true if status is Processing
$order->isCompleted();         // true if status is Completed
$order->isArchived();          // true if status is Archived
$order->isNotCancelled();      // true if status is NOT Cancelled
$order->canBeCancelled();      // true if not Cancelled/Archived and shipping is Unfulfilled

$order->isPaid();              // true if payment_status is Paid
$order->isPaymentPending();    // true if payment_status is Pending
$order->isPaymentAuthorized(); // true if payment_status is Authorized
$order->isRefunded();          // true if payment_status is Refunded

$order->isShipped();           // true if shipping_status is Shipped
$order->isShippingPending();   // true if shipping_status is Unfulfilled

Fulfillment Status

The FulfillmentStatus enum tracks individual item fulfillment, enabling partial shipments and multi-carrier delivery:
use Shopper\Core\Enum\FulfillmentStatus;

FulfillmentStatus::Pending              // pending
FulfillmentStatus::ForwardedToSupplier  // forwarded_to_supplier (dropshipping)
FulfillmentStatus::Processing           // processing
FulfillmentStatus::Shipped              // shipped
FulfillmentStatus::Delivered            // delivered
FulfillmentStatus::Cancelled            // cancelled
StatusDatabase ValueColorDescription
PendingpendingwarningAwaiting processing
Forwarded to Supplierforwarded_to_supplierinfoSent to external supplier (dropshipping)
ProcessingprocessingprimaryBeing prepared
ShippedshippedindigoIn transit
DelivereddeliveredsuccessReceived by customer
CancelledcancelleddangerFulfillment cancelled
FulfillmentStatus is applied per item, not per order. This allows partial fulfillment when items ship at different times or from different carriers. See the Fulfillment page for complete workflows.

Refund Status

The OrderRefundStatus enum defines refund states:
use Shopper\Core\Enum\OrderRefundStatus;

OrderRefundStatus::Pending        // pending (default)
OrderRefundStatus::Awaiting       // awaiting
OrderRefundStatus::Treatment      // treatment
OrderRefundStatus::Partial_Refund // partial_refund
OrderRefundStatus::Refunded       // refunded
OrderRefundStatus::Rejected       // rejected
OrderRefundStatus::Cancelled      // cancelled

Relationships

Customer

// Get the customer who placed the order
$order->customer; // Returns User model

// Query orders by customer
Order::query()
    ->where('customer_id', $userId)
    ->get();

Items

// Get all items in the order
$order->items; // Collection of OrderItem models

// Add an item
$order->items()->create([
    'name' => $product->name,
    'sku' => $product->sku,
    'quantity' => 2,
    'unit_price_amount' => $product->price_amount,
    'product_id' => $product->id,
    'product_type' => get_class($product),
]);

// Get item total (computed)
$item->total; // unit_price_amount * quantity

Addresses

// Get shipping address
$order->shippingAddress; // OrderAddress model

// Get billing address
$order->billingAddress; // OrderAddress model

// Access full name
$order->shippingAddress->full_name; // "John Doe"

Shipping

// Get the shipping option selected at checkout
$order->shippingOption; // CarrierOption model

// Get all shipments for an order
$order->shippings; // Collection of OrderShipping models

// Create a shipment
$shipment = $order->shippings()->create([
    'carrier_id' => $carrierId,
    'shipped_at' => now(),
    'tracking_number' => 'TRACK123456',
    'tracking_url' => 'https://carrier.com/track/TRACK123456',
]);

// Link items to the shipment
$order->items()
    ->whereIn('id', [$itemId1, $itemId2])
    ->update([
        'order_shipping_id' => $shipment->id,
        'fulfillment_status' => FulfillmentStatus::Shipped,
    ]);

Item Shipment

// Get the shipment for a specific item
$item->shipment; // OrderShipping model (nullable)

// Get the carrier for an item's shipment
$item->shipment?->carrier; // Carrier model

// Get all items in a shipment
$shipment->items; // Collection of OrderItem models
For complete multi-shipment and dropshipping workflows, see the Fulfillment page.

Refund

// Get order refund
$order->refund; // OrderRefund model (HasOne)

// Create a refund
$order->refund()->create([
    'refund_reason' => 'Product damaged',
    'refund_amount' => $order->total(),
    'currency' => $order->currency_code,
    'status' => OrderRefundStatus::Pending,
]);

Channel and Zone

// Get sales channel
$order->channel; // Channel model

// Get zone (market)
$order->zone; // Zone model

Parent/Child Orders

// Get parent order (for split orders)
$order->parent; // Order model

// Get child orders
$order->children; // Collection of Order models

Computed Values

Order Total

// Get order total from items
$order->total(); // Sum of all item totals (in cents)

// Get total as Price object
$order->total_amount; // Price object with formatting

Events

Order lifecycle events are dispatched automatically throughout the order lifecycle:
use Shopper\Core\Events\Orders\OrderCreated;
use Shopper\Core\Events\Orders\OrderPaid;
use Shopper\Core\Events\Orders\OrderShipped;
use Shopper\Core\Events\Orders\OrderCompleted;
use Shopper\Core\Events\Orders\OrderCancel;
use Shopper\Core\Events\Orders\OrderArchived;
use Shopper\Core\Events\Orders\OrderDeleted;
use Shopper\Core\Events\Orders\OrderShipmentCreated;
use Shopper\Core\Events\Orders\OrderShipmentDelivered;
use Shopper\Core\Events\Orders\AddNoteToOrder;
For the full events reference including shipment events, payload details, and usage examples, see the Events page.

Creating Orders

Basic Order

use Shopper\Core\Models\Order;
use Shopper\Core\Enum\OrderStatus;

$order = Order::query()->create([
    'number' => generate_number(),
    'customer_id' => auth()->id(),
    'currency_code' => current_currency(),
    'channel_id' => $channelId,
    'status' => OrderStatus::New,
]);

Complete Order with Items and Addresses

// Create addresses
$shippingAddress = OrderAddress::query()->create([
    'customer_id' => auth()->id(),
    'first_name' => 'John',
    'last_name' => 'Doe',
    'street_address' => '123 Main St',
    'city' => 'New York',
    'postal_code' => '10001',
    'country_name' => 'United States',
    'phone' => '+1234567890',
]);

$billingAddress = OrderAddress::query()->create([
    'customer_id' => auth()->id(),
    'first_name' => 'John',
    'last_name' => 'Doe',
    'street_address' => '123 Main St',
    'city' => 'New York',
    'postal_code' => '10001',
    'country_name' => 'United States',
]);

// Create order
$order = Order::query()->create([
    'number' => generate_number(),
    'customer_id' => auth()->id(),
    'currency_code' => 'USD',
    'shipping_address_id' => $shippingAddress->id,
    'billing_address_id' => $billingAddress->id,
    'shipping_option_id' => $carrierOptionId,
    'zone_id' => $zoneId,
]);

// Add items from cart
foreach ($cart->items as $cartItem) {
    $order->items()->create([
        'name' => $cartItem->product->name,
        'sku' => $cartItem->product->sku,
        'quantity' => $cartItem->quantity,
        'unit_price_amount' => $cartItem->product->price_amount,
        'product_id' => $cartItem->product->id,
        'product_type' => get_class($cartItem->product),
    ]);
}

Retrieving Orders

use Shopper\Core\Models\Order;

// Get all orders with relationships
$orders = Order::query()
    ->with(['customer', 'items', 'shippingAddress'])
    ->latest()
    ->get();

// Get orders by status
$newOrders = Order::query()
    ->where('status', OrderStatus::New)
    ->get();

// Get customer's orders
$customerOrders = Order::query()
    ->where('customer_id', $customerId)
    ->with('items.product')
    ->latest()
    ->paginate(10);

// Get order by number
$order = Order::query()
    ->where('number', $orderNumber)
    ->with(['items', 'shippingAddress', 'billingAddress', 'refund'])
    ->firstOrFail();

// Get orders for a channel
$channelOrders = Order::query()
    ->where('channel_id', $channelId)
    ->get();

// Get orders for a zone
$zoneOrders = Order::query()
    ->where('zone_id', $zoneId)
    ->get();

Order Number Generation

Use the generate_number() helper to create unique order numbers:
$orderNumber = generate_number();
// Returns something like: "ORD-20240115-001234"

Components

php artisan shopper:component:publish order
Creates config/shopper/components/order.php:
use Shopper\Livewire;

return [
    'pages' => [
        'order-index' => Livewire\Pages\Order\Index::class,
        'order-detail' => Livewire\Pages\Order\Detail::class,
    ],
    'components' => [
        //
    ],
];

Storefront Example

namespace App\Http\Controllers;

use Shopper\Core\Models\Order;
use Shopper\Core\Models\OrderAddress;
use Shopper\Core\Enum\OrderStatus;

class CheckoutController extends Controller
{
    public function store(Request $request)
    {
        $validated = $request->validate([
            'shipping.first_name' => 'required|string',
            'shipping.last_name' => 'required|string',
            'shipping.street_address' => 'required|string',
            'shipping.city' => 'required|string',
            'shipping.postal_code' => 'required|string',
            'shipping_option_id' => 'required|exists:carrier_options,id',
        ]);

        // Create shipping address
        $shippingAddress = OrderAddress::query()->create([
            'customer_id' => auth()->id(),
            ...$validated['shipping'],
        ]);

        // Create order
        $order = Order::query()->create([
            'number' => generate_number(),
            'customer_id' => auth()->id(),
            'currency_code' => current_currency(),
            'shipping_address_id' => $shippingAddress->id,
            'billing_address_id' => $shippingAddress->id,
            'shipping_option_id' => $validated['shipping_option_id'],
            'channel_id' => current_channel()->id,
        ]);

        // Add cart items
        foreach (Cart::items() as $item) {
            $order->items()->create([
                'name' => $item->product->name,
                'sku' => $item->product->sku,
                'quantity' => $item->quantity,
                'unit_price_amount' => $item->product->price_amount,
                'product_id' => $item->product->id,
                'product_type' => get_class($item->product),
            ]);
        }

        Cart::clear();

        return redirect()->route('orders.show', $order);
    }

    public function show(Order $order)
    {
        abort_unless($order->customer_id === auth()->id(), 403);

        return view('orders.show', [
            'order' => $order->load(['items.product', 'shippingAddress']),
        ]);
    }
}

Order Status Flow

From StatusPossible Transitions
NewProcessing, Cancelled, Archived
ProcessingCompleted, Cancelled
CompletedArchived
Cancelled(terminal state)
Archived(terminal state)