Orders Module
The Orders module is the central hub of Auto Commerce. All order creation β from Shopify, WooCommerce, manual entry, CSV import, or API β flows through a single Ingest Pipeline. The module provides a full order lifecycle: payments, fulfillment, returns, invoicing, analytics, notifications, outbound webhooks, and bulk operations.
Architecture
StoreShopify / StoreWooCommerce / Manual / CSV / API
β
Bus::call('Orders', 'orders.createOrUpdate', $normalized)
β
βββββββββββββββΌβββββββββββββββ
β OrderIngestService β
β β’ Validate & normalize β
β β’ Deduplicate (upsert) β
β β’ Create Order + Items β
β β’ Publish events β
βββββββββββββββ¬βββββββββββββββ
β
βββββββββββββββΌβββββββββββββββ¬βββββββββββββββ
β β β β
Workflows ResellerOrders Inventory Notifications
(triggers) (chain forward) (reserve) (SMS/WhatsApp)
Key Design Principles
- Single entry point: All order creation goes through
OrderIngestService, never directOrder::create() - Event-driven: 13 events published via Module Event Bus β other modules subscribe without coupling
- Idempotent upsert: Deduplication via
(source_module, external_id)constraint - PostgreSQL-optimized: JSONB columns, GIN indexes, BRIN indexes, partial indexes for hot statuses
Order Lifecycle
pending β confirmed β processing β ready_to_ship β shipped
β out_for_delivery β delivered
Alternate flows:
β rto_initiated β rto_received (Return to Origin)
β cancelled
β failed
Payment Statuses
pending β paid β refunded
β partial (partial payment received)
β failed
β cod (Cash on Delivery)
Data Model
Core Order Fields
| Field | Type | Description |
|---|---|---|
id |
UUID | Primary key |
external_id |
string | ID from source platform (Shopify, etc.) |
source_module |
string | Origin module (store-shopify, manual, etc.) |
order_number |
string | Auto-generated (ORD-YYYYMMDD-XXXX) |
status |
string | Order lifecycle status |
payment_status |
string | Payment status |
fulfillment_status |
string | Fulfillment status |
customer_id |
UUID | Customer reference |
subtotal |
decimal | Items subtotal |
tax |
decimal | Total tax |
discount |
decimal | Total discount |
shipping_cost |
decimal | Shipping charges |
total |
decimal | Grand total |
currency |
string | Currency code (default: INR) |
payment_method |
string | Payment method (razorpay, cod, etc.) |
notes |
text | Internal notes |
tags |
jsonb | Tags array |
custom_fields |
jsonb | Tenant-defined custom field values |
Related Models
| Model | Relationship | Description |
|---|---|---|
OrderItem |
HasMany | Line items with product, quantity, price |
OrderPayment |
HasMany | Payment records with provider, amount, status |
OrderRefund |
HasMany | Refund records linked to payments |
OrderReturn |
HasMany | Return requests with lifecycle |
OrderInvoice |
HasMany | Tax invoices and credit notes |
Shipment |
HasMany | Shipment tracking with carrier integration |
OrderStatusHistory |
HasMany | Audit trail of status changes |
OrderActivityLog |
HasMany | Rich activity log with changes JSONB |
OrderMetadata |
HasMany | Key-value metadata from any module |
Ingest Pipeline
The OrderIngestService is the single canonical entry point for all order creation.
Creating Orders via Bus
use App\Core\ModuleBus\ModuleApiBus;
$bus = app(ModuleApiBus::class);
// Simple create
$order = $bus->call('Orders', 'orders.create', [
'customer' => ['phone' => '+919876543210', 'first_name' => 'John'],
'items' => [
['name' => 'Widget', 'quantity' => 2, 'unit_price' => 999.00],
],
'total' => 1998.00,
'payment_method' => 'cod',
]);
// Idempotent upsert (for store integrations)
$order = $bus->call('Orders', 'orders.createOrUpdate', [
'source_module' => 'store-shopify',
'external_id' => 'shopify_12345',
'customer' => ['email' => 'john@example.com', 'first_name' => 'John'],
'items' => [...],
'status' => 'confirmed',
'payment_status' => 'paid',
'total' => 2999.00,
]);
// Batch ingest
$result = $bus->call('Orders', 'orders.batchIngest', [
'orders' => [$order1Data, $order2Data, ...],
'source' => 'csv-import',
]);
// Returns: { created: 50, updated: 3, skipped: 0, errors: [...] }
How Shopify Integration Uses It
// In ShopifyService::importOrder()
$bus->call('Orders', 'orders.createOrUpdate', [
'source_module' => 'store-shopify',
'external_id' => (string) $shopifyOrder['id'],
'order_number' => $shopifyOrder['name'],
'customer' => [
'email' => $shopifyOrder['email'],
'phone' => $shopifyOrder['phone'],
'first_name' => $shopifyOrder['customer']['first_name'] ?? 'Guest',
'last_name' => $shopifyOrder['customer']['last_name'] ?? '',
],
'items' => collect($shopifyOrder['line_items'])->map(fn($item) => [
'name' => $item['title'],
'sku' => $item['sku'],
'quantity' => $item['quantity'],
'unit_price' => $item['price'],
])->toArray(),
'total' => $shopifyOrder['total_price'],
'status' => $this->mapShopifyStatus($shopifyOrder),
'payment_status' => $shopifyOrder['financial_status'] === 'paid' ? 'paid' : 'pending',
]);
API Endpoints
Orders CRUD
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/orders |
List orders (paginated, filterable) |
POST |
/api/v1/orders |
Create order |
GET |
/api/v1/orders/{order} |
Get order details |
PATCH |
/api/v1/orders/{order} |
Update order |
DELETE |
/api/v1/orders/{order} |
Delete order |
PATCH |
/api/v1/orders/{order}/status |
Update status |
GET |
/api/v1/orders/stats/summary |
Order statistics |
Query Parameters for List:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by status |
payment_status |
string | Filter by payment status |
customer_id |
UUID | Filter by customer |
source_module |
string | Filter by source (shopify, manual, etc.) |
date_from / date_to |
date | Date range filter |
search |
string | Search order number, customer name/phone/email |
page / per_page |
int | Pagination |
Payments
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/orders/{order}/payments |
List payments |
POST |
/api/v1/orders/{order}/payments |
Record payment |
POST |
/api/v1/orders/{order}/payments/link |
Generate payment link |
POST |
/api/v1/orders/{order}/refund |
Process refund |
Record Payment Request:
{
"method": "razorpay",
"amount": 2999.00,
"external_payment_id": "pay_abc123",
"metadata": { "gateway_response": "..." }
}
Shipments
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/orders/{order}/ship |
Create shipment |
GET |
/api/v1/orders/{order}/shipments |
List shipments |
Create Shipment Request:
{
"carrier_module": "shipping-delhivery",
"awb_number": "DLV123456789",
"tracking_url": "https://track.delhivery.com/DLV123456789",
"estimated_delivery_at": "2026-03-15T00:00:00Z"
}
Returns
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/orders/{order}/returns |
List order returns |
POST |
/api/v1/orders/{order}/returns |
Request return |
PATCH |
/api/v1/returns/{return}/approve |
Approve return |
PATCH |
/api/v1/returns/{return}/reject |
Reject return |
PATCH |
/api/v1/returns/{return}/received |
Mark as received |
POST |
/api/v1/returns/{return}/refund |
Process refund for return |
Request Return:
{
"reason_category": "defective",
"reason_detail": "Screen cracked on arrival",
"items": [
{ "order_item_id": "uuid", "quantity": 1 }
]
}
Invoices
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/orders/{order}/invoices |
List invoices |
POST |
/api/v1/orders/{order}/invoices |
Generate invoice |
GET |
/api/v1/invoices/{invoice} |
Get invoice details |
Analytics
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/orders/analytics/dashboard |
Dashboard metrics |
GET |
/api/v1/orders/analytics/revenue |
Revenue time series |
GET |
/api/v1/orders/analytics/fulfillment |
Fulfillment metrics |
GET |
/api/v1/orders/analytics/sources |
Source breakdown |
GET |
/api/v1/orders/analytics/products |
Top products |
GET |
/api/v1/orders/analytics/cod-vs-prepaid |
COD vs Prepaid split |
Dashboard Response:
{
"total_orders": 1250,
"total_revenue": 3750000.00,
"avg_order_value": 3000.00,
"pending_orders": 45,
"orders_today": 28,
"revenue_today": 84000.00,
"fulfillment_rate": 0.89,
"cancellation_rate": 0.05,
"cod_percentage": 0.35,
"prepaid_percentage": 0.65
}
Bulk Operations
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/orders/bulk/import |
Import orders from CSV |
GET |
/api/v1/orders/bulk/import/{id} |
Import status |
POST |
/api/v1/orders/bulk/import/{id}/cancel |
Cancel import |
POST |
/api/v1/orders/bulk/export |
Export orders to CSV |
GET |
/api/v1/orders/bulk/export/{id}/download |
Download export |
POST |
/api/v1/orders/bulk/status |
Bulk update status |
POST |
/api/v1/orders/bulk/ship |
Bulk create shipments |
POST |
/api/v1/orders/bulk/cancel |
Bulk cancel orders |
Bulk Import:
// POST /api/v1/orders/bulk/import
// Content-Type: multipart/form-data
{
"file": "(csv file)",
"source": "csv-import"
}
// Response
{
"import_id": "uuid",
"status": "processing",
"total_rows": 500
}
Bulk Status Update:
{
"order_ids": ["uuid1", "uuid2", "uuid3"],
"status": "confirmed",
"reason": "Payment verified in batch"
}
Notification Rules
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/order-notification-rules |
List rules |
POST |
/api/v1/order-notification-rules |
Create rule |
GET |
/api/v1/order-notification-rules/{rule} |
Get rule |
PATCH |
/api/v1/order-notification-rules/{rule} |
Update rule |
DELETE |
/api/v1/order-notification-rules/{rule} |
Delete rule |
POST |
/api/v1/order-notification-rules/{rule}/test |
Send test notification |
Create Notification Rule:
{
"name": "Order Confirmed SMS",
"event": "order.status_changed",
"channel": "sms",
"recipient_type": "customer",
"template": "Hi {{customer_name}}, your order #{{order_number}} is confirmed! Total: βΉ{{total}}",
"conditions": { "new_status": "confirmed" },
"is_active": true
}
Outbound Webhooks
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/order-webhooks |
List webhook endpoints |
POST |
/api/v1/order-webhooks |
Create endpoint |
GET |
/api/v1/order-webhooks/{endpoint} |
Get endpoint |
PATCH |
/api/v1/order-webhooks/{endpoint} |
Update endpoint |
DELETE |
/api/v1/order-webhooks/{endpoint} |
Delete endpoint |
GET |
/api/v1/order-webhooks/{endpoint}/logs |
View delivery logs |
Create Webhook Endpoint:
{
"url": "https://yourapp.com/webhook/orders",
"secret": "whsec_abc123",
"events": ["order.created", "order.status_changed", "order.delivered"],
"is_active": true
}
Webhook Payload:
{
"event": "order.status_changed",
"payload": {
"order_id": "uuid",
"order_number": "ORD-20260305-A1B2",
"old_status": "pending",
"new_status": "confirmed"
},
"timestamp": "2026-03-05T10:30:00+00:00"
}
Webhooks include an X-Webhook-Signature header (HMAC-SHA256 of the body using the endpoint secret). Endpoints are automatically disabled after 10 consecutive failures.
Custom Fields
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/order-custom-fields |
List field definitions |
POST |
/api/v1/order-custom-fields |
Create field |
GET |
/api/v1/order-custom-fields/{field} |
Get field |
PATCH |
/api/v1/order-custom-fields/{field} |
Update field |
DELETE |
/api/v1/order-custom-fields/{field} |
Delete field |
Create Custom Field:
{
"field_key": "priority_level",
"field_label": "Priority Level",
"field_type": "select",
"options": ["low", "normal", "high", "urgent"],
"is_required": false,
"is_filterable": true,
"sort_order": 1
}
Custom field values are stored in the order's custom_fields JSONB column:
{
"priority_level": "high",
"gift_message": "Happy Birthday!"
}
Module API Bus Integration
The Orders module declares 10 bus endpoints and publishes 13 events. See Module API Bus for the bus architecture.
Provided Endpoints
| Method Alias | Description | Mode |
|---|---|---|
orders.create |
Create order via ingest pipeline | sync |
orders.createOrUpdate |
Idempotent upsert by source + external_id | sync |
orders.batchIngest |
Batch ingest multiple orders | async |
orders.get |
Get order by ID | sync |
orders.updateStatus |
Update order status | sync |
orders.getByExternalIds |
Find orders by source + external IDs | sync |
orders.getStats |
Get order statistics | sync |
orders.reserveInventory |
Publish inventory reservation event | sync |
orders.processReturn |
Process a return request | sync |
orders.processRefund |
Process a refund | sync |
Published Events
| Event | Trigger |
|---|---|
order.created |
New order created via ingest pipeline |
order.status_changed |
Order status updated |
order.cancelled |
Order cancelled |
order.fulfilled |
Order shipped or out for delivery |
order.delivered |
Order delivered to customer |
order.payment_updated |
Payment status changed |
order.refund_processed |
Refund completed |
order.return_requested |
Customer requested return |
order.return_approved |
Return request approved |
order.inventory_reserved |
Stock reserved for order |
order.inventory_released |
Stock reservation released |
order.shipment_created |
Shipment created with tracking |
order.import_completed |
Batch import finished |
Self-Subscriptions
The module subscribes to its own events for:
- Inventory reservation: On
order.createdβ reserves stock - Inventory release: On
order.cancelledβ releases reserved stock - Notifications: All order events β checks notification rules, sends alerts
- Outbound webhooks: All order events β dispatches to registered webhook endpoints
Tax & Invoicing
GST Calculation
The TaxService handles Indian GST rules automatically:
- Intra-state (same state): Split into CGST + SGST (half rate each)
- Inter-state (different states): Full IGST at combined rate
$tax = app(TaxService::class);
// Intra-state: βΉ1000 @ 18% β CGST βΉ90 + SGST βΉ90 = βΉ180
$result = $tax->calculateTax(1000, null, true, 18);
// Inter-state: βΉ1000 @ 18% β IGST βΉ180
$result = $tax->calculateTax(1000, null, false, 18);
Tax rates can be configured per HSN code via TaxConfiguration model.
Invoice Generation
Invoices are auto-numbered with the format INV-YYYYMM-NNNN:
POST /api/v1/orders/{order}/invoices
// Response
{
"invoice_number": "INV-202603-0001",
"type": "invoice",
"subtotal": 2500.00,
"tax_details": {
"cgst": 225,
"sgst": 225,
"rate": 18
},
"total_tax": 450.00,
"total": 2950.00,
"billing_name": "John Doe",
"billing_gstin": "27AAPFU0939F1ZV"
}
Database Optimizations
The module includes PostgreSQL-specific optimizations for large-scale order volumes:
| Optimization | Purpose |
|---|---|
| JSONB columns | GIN-indexable, supports @> containment queries |
GIN index on tags |
Fast tag filtering |
| Composite indexes | (status, created_at), (payment_status, created_at), (source_module, created_at) |
| Partial indexes | WHERE status = 'pending', WHERE status = 'ready_to_ship' for hot queries |
BRIN index on created_at |
Compact index for time-range scans on naturally ordered data |
Queue Workers
The module uses dedicated queues for background processing:
| Queue | Jobs |
|---|---|
default |
Notifications, webhooks, invoice PDF generation |
imports |
CSV order imports (chunked, cancellable) |
exports |
CSV/Excel order exports (cursor-based streaming) |
module-bus |
Async bus calls (batch ingest) |
Configure in Laravel Horizon for separate supervisor processes.
Order Metadata
Modules can attach arbitrary key-value metadata to orders:
// Set metadata
$order->setMeta('shopify_order_id', '12345', 'store-shopify');
$order->setMeta('delivery_notes', 'Ring doorbell twice', 'manual');
// Get metadata
$shopifyId = $order->getMeta('shopify_order_id');
Metadata is scoped by module_source to avoid conflicts between modules.
Navigation
Orders & Fulfillment
βββ All Orders
βββ Create Order
βββ Ready to Ship
βββ Shipped Orders
βββ Returns
βββ Analytics
βββ Import / Export
βββ Settings (Notification Rules, Webhooks, Custom Fields)
Related Documentation
- Complete Feature List β All features across 11 phases
- Payments & Refunds β Payment lifecycle, COD, refund processing
- Returns β Return request lifecycle
- Shipping & Fulfillment β Shipment tracking, partial fulfillment, NDR
- Tax & Invoicing β Indian GST calculation, invoice generation
- Analytics & Reporting β Dashboard metrics, materialized views
- Inventory Integration β Event-driven stock reservation
- Webhooks & Notifications β Outbound webhooks, notification rules, custom fields
- Bulk Operations β CSV import/export, batch processing
Other Modules
- Products Module β Manage your product catalog
- Customers Module β Customer relationship management
- Module API Bus β Inter-module communication
- Creating Modules β Extend order functionality