Architecture
The fulfillment system connects four models:- Order has many shipments (
OrderShipping) and tracks overallshipping_status - Each shipment has its own
status(ShipmentStatus) and a timeline of events (OrderShippingEvent) - Each item tracks its own fulfillment status independently
Database Schema
OrderShipping Table
| Column | Type | Nullable | Description |
|---|---|---|---|
id | bigint | no | Primary key |
order_id | bigint | no | FK to order |
carrier_id | bigint | yes | FK to carrier |
status | string(32) | yes | Shipment status enum |
shipped_at | datetime | yes | When the shipment was dispatched |
received_at | datetime | yes | When the customer received it |
returned_at | datetime | yes | If the shipment was returned |
tracking_number | string | yes | Carrier tracking number |
tracking_url | string | yes | URL for customer tracking |
voucher | json | yes | Shipping label/voucher data |
OrderShippingEvent Table
| Column | Type | Nullable | Description |
|---|---|---|---|
id | bigint | no | Primary key |
order_shipping_id | bigint | no | FK to shipment |
status | string(32) | no | Shipment status at this event |
description | text | yes | Event description |
location | string | yes | Location name |
latitude | decimal(10,7) | yes | GPS latitude |
longitude | decimal(10,7) | yes | GPS longitude |
occurred_at | datetime | yes | When the event occurred |
metadata | json | yes | Additional event data |
OrderItem Fulfillment Columns
| Column | Type | Nullable | Description |
|---|---|---|---|
order_shipping_id | bigint | yes | FK to the shipment this item belongs to |
fulfillment_status | string | yes | Current fulfillment state of this item |
Fulfillment Status
TheFulfillmentStatus enum defines the lifecycle of each item:
Status Flow
| From | Possible Transitions |
|---|---|
| Pending | Processing, ForwardedToSupplier, Cancelled |
| ForwardedToSupplier | Processing, Shipped, Cancelled |
| Processing | Shipped, Cancelled |
| Shipped | Delivered |
| Delivered | (terminal state) |
| Cancelled | (terminal state) |
Shipping Status (Order Level)
TheShippingStatus enum lives on the Order model and reflects the combined state of all its shipments. It answers “has this order been shipped/delivered?”.
Shipment Status (Package Level)
TheShipmentStatus enum lives on the OrderShipping model and tracks the delivery progress of a single package. Each shipment goes through this lifecycle independently.
Shipment Transitions
TheHasFulfillmentTransitions trait on OrderShipping enforces valid state transitions:
| From | Possible Transitions |
|---|---|
| Pending | PickedUp, Returned |
| PickedUp | InTransit, DeliveryFailed, Returned |
| InTransit | AtSortingCenter, OutForDelivery, DeliveryFailed, Returned |
| AtSortingCenter | InTransit, OutForDelivery, DeliveryFailed, Returned |
| OutForDelivery | Delivered, DeliveryFailed, Returned |
| Delivered | Returned |
| DeliveryFailed | InTransit, OutForDelivery, Returned |
| Returned | (terminal state) |
Transitioning Shipment Status
UsetransitionTo() to update the shipment status. It validates the transition and automatically logs a tracking event:
OrderShippingEvent record with the status, timestamp, and optional location data.
Tracking Events
Each shipment has a timeline of events that record its journey:Relationships
Order → Shipments
OrderShipping → Items & Events
OrderItem → Shipment
Creating Shipments
Single Shipment (All Items Together)
When all items ship in one package:Partial Shipment (Split Across Packages)
When items ship in multiple packages with different carriers:Marking as Delivered
Dropshipping Workflow
For external products sourced from suppliers, the fulfillment flow includes an additional step where the order is forwarded to the supplier who ships directly to the customer.Dropshipping requires the Supplier feature to be enabled. External products must be linked to a supplier.
Complete Dropshipping Flow
Mixed Orders (Own Products + Supplier Products)
An order can contain both your own products and dropshipped products:Querying Fulfillment Data
Items by Status
Orders Needing Attention
Shipment History
Handling Returns
Storefront Example
Order Tracking Page
Best Practices
| Practice | Description |
|---|---|
| Update statuses atomically | Always update order_shipping_id and fulfillment_status together when shipping |
| Complete orders automatically | Check if all items are delivered and update the order status accordingly |
| Group items by carrier | Items from the same supplier or warehouse should share a shipment |
| Store tracking URLs | Always provide tracking_url so customers can track packages directly |
| Handle mixed orders | Process your own products and supplier products as separate shipments |