Orders Module — Complete Feature List
This document catalogs every feature built in the Orders module across 11 implementation phases, covering the full order lifecycle from ingest to delivery.
Phase 1: Foundation & Ingest Pipeline
The canonical entry point for all order creation. Every source (Shopify, WooCommerce, manual, CSV, API) flows through a single pipeline.
Services
- OrderIngestService —
ingest(),upsert()(idempotent bysource_module + external_id),ingestBatch()with chunking - OrderEventPublisher — typed wrapper publishing 8 event types via Module Event Bus
- OrderBusHandler — exposes 10 Module API Bus endpoints for cross-module communication
DTOs
- IngestOrderDTO — readonly typed DTO with
fromArray()factory, numeric casting, andtoArray()roundtrip - IngestResult — mutable accumulator tracking
created,updated,skipped,errors,orderIds
Models Added
OrderStatusHistory— tracks who changed what status and whenOrderMetadata— key-value metadata scoped by module (avoids cross-module conflicts)ShipmentEvent— carrier tracking events with raw webhook dataNdrCase— non-delivery report tracking per shipment
Customer Resolution
Orders can reference customers by:
- Customer UUID (
customer.id) - Phone number (
customer.phone) — find-or-create - Email (
customer.email) — find-or-create - Creates guest customer if none matched
Bus Integration (10 endpoints)
| Method | Description |
|---|---|
orders.create |
Create via ingest pipeline |
orders.createOrUpdate |
Idempotent upsert |
orders.batchIngest |
Batch ingest |
orders.get |
Get by ID |
orders.updateStatus |
Update status |
orders.getByExternalIds |
Find by source + external IDs |
orders.getStats |
Statistics |
orders.reserveInventory |
Publish reservation event |
orders.processReturn |
Process return |
orders.processRefund |
Process refund |
Events Published (13 total)
order.created, order.status_changed, order.cancelled, order.fulfilled, order.delivered, order.payment_updated, order.refund_processed, order.return_requested, order.return_approved, order.inventory_reserved, order.inventory_released, order.shipment_created, order.import_completed
Phase 2: Database Optimization (PostgreSQL)
PostgreSQL-specific optimizations for large-scale order volumes.
Schema Changes
- JSON to JSONB conversion on
orders.tags,order_items.properties,shipment_events.raw_data,shipments.dimensions - Added missing
payment_methodcolumn (varchar 50) - Added
ordered_attimestamp
Indexes
- GIN index on
orders.tags— fast@>containment queries - Composite indexes:
(status, created_at),(payment_status, created_at),(source_module, created_at),(customer_id, created_at) - Partial indexes:
WHERE status = 'pending',WHERE status = 'ready_to_ship'— smaller, faster for hot status queries - BRIN index on
created_at— 100x smaller than B-tree for naturally ordered data
New Tables
order_activity_log—order_id,actor_type,actor_id,action,description,changes(jsonb),metadata(jsonb)order_imports— tracks bulk import jobs withtotal_rows,processed_rows,error_count,errors(jsonb)
Models
OrderActivityLogOrderImport
Phase 3: Payment Lifecycle
Full payment tracking with multiple providers, partial payments, reconciliation, and refunds.
Tables
order_payments— UUID,provider_module,external_payment_id,method,status,amount,payment_link_url,payment_link_expires_at,metadata(jsonb),paid_atorder_refunds— UUID,payment_id,external_refund_id,amount,reason,status,processed_at
PaymentService
recordPayment()— records payment and auto-reconciles order statuscreatePaymentLink()— generates shareable payment link via provider moduleprocessRefund()— creates refund record, updates payment statusrecordCodCollection()— records cash collected on deliveryreconcilePaymentStatus()— auto-sets order topaid,partial, orrefundedbased on payment sums
Order Accessors
$order->total_paid— sum of completed payments$order->balance_due—total - total_paid
Reconciliation Logic
- Total paid >= order total → status becomes
paid - Total paid > 0 but < total → status becomes
partial - Total refunded >= total paid → status becomes
refunded
Phase 4: Fulfillment & Shipping
Shipment lifecycle with partial fulfillment, tracking, and carrier integration.
Schema Enhancements
order_item_ids(jsonb) on shipments — tracks which items are in which packagelabel_url,pickup_token,estimated_delivery_at,tracking_url,ndr_count
ShippingService
createShipment()— creates shipment record, updates order statuscancelShipment()— cancels shipment with carrier- Rate comparison stubs for multi-carrier support
Partial Fulfillment
- Orders can have multiple shipments (changed from
HasOnetoHasMany) - Each shipment tracks which
order_item_idsit contains - Order status reflects overall fulfillment state
Tracking
SyncTrackingStatusJob— polls in-transit shipments every 30 minutesShipmentWebhookController— receives carrier push updatesShipmentEventmodel stores tracking history with raw webhook data
Phase 5: Returns & Refunds
Complete return lifecycle with auto-generated return numbers and integrated refund processing.
Return Lifecycle
requested → approved → received → refunded
→ rejected
ReturnService
requestReturn()— creates return with auto-generatedRET-YYYYMMDD-XXXXnumberapproveReturn()— sets approved status, records approver and refund amountrejectReturn()— sets rejected status with admin notesmarkReceived()— marks items as received backprocessRefundForReturn()— callsPaymentService::processRefund()and marks return as refunded
Return Model Fields
return_number(auto-generated)reason_category,reason_detail,customer_notes,admin_notesitems(jsonb) — which items being returnedrefund_amount,refund_methodapproved_by,approved_at,received_at,refunded_at
Phase 6: Inventory Integration
Event-driven stock management with graceful degradation.
Pattern
- On order created → publishes
order.inventory_reservedwith item SKUs/quantities - On order cancelled → publishes
order.inventory_released - On shipment created → converts reservation to permanent decrement
Graceful Degradation
- Works without any inventory module installed
- Events are published regardless — no subscribers means no action
- Adding/removing inventory modules doesn't break orders
Listeners
OnOrderCreatedReserveStock— self-subscribes toorder.createdOnOrderCancelledReleaseStock— self-subscribes toorder.cancelled
Phase 7: Tax & Invoicing
Indian GST-compliant tax calculation and sequential invoice generation.
TaxService
- Intra-state: Splits into CGST + SGST (half rate each)
- Inter-state: Full IGST at combined rate
- Rate lookup by HSN code via
TaxConfigurationmodel - Supports standard GST rates: 0%, 5%, 12%, 18%, 28%
- Default fallback: 18%
InvoiceService
generateInvoice()— auto-populates from order items, calculates tax, generates sequential numbergenerateCreditNote()— creates credit note for refunds- Sequential numbering:
INV-YYYYMM-NNNN,CN-YYYYMM-NNNN,PI-YYYYMM-NNNN
Invoice Types
- Invoice (
INV-) — standard tax invoice - Credit Note (
CN-) — issued for refunds/returns - Proforma (
PI-) — pre-payment invoice
Phase 8: Notifications & Automation
Configurable notification rules triggered by order events.
OrderNotificationService
processEvent()— finds all active rules matching the eventmatchesConditions()— evaluates rule conditions against event payloadrenderTemplate()— replaces{{placeholder}}tokens, preserves unmatched ones
Supported Channels
- SMS (via provider module)
- WhatsApp (via channel module)
- Email (via email service)
- In-app notifications
Template Placeholders
{{order_number}}, {{customer_name}}, {{total}}, {{status}}, {{tracking_url}}, {{return_number}}
Conditional Rules
Rules can filter by event payload fields:
{ "conditions": { "new_status": "confirmed", "payment_status": "cod" } }
Phase 9: Bulk Operations
High-volume operations with queued processing and progress tracking.
CSV Import
- Parse and validate CSV files
- Process in 500-row chunks via
Bus::batch() - PostgreSQL
INSERT ... ON CONFLICT DO UPDATEfor idempotent upserts - Real-time progress via Laravel Reverb WebSockets
- Cancellable — job checks status between chunks
CSV Export
- Cursor-based streaming for memory efficiency
- Configurable column selection
- Filter by status, date range, etc.
Bulk Operations
- Bulk status update — single SQL
UPDATE ... WHERE id IN (...) - Bulk ship — create shipments from tracking CSV
- Bulk cancel — cancel multiple orders with reason
Queue Configuration
importsqueue — dedicated supervisor, 600s timeoutexportsqueue — dedicated supervisor, 300s timeout
Phase 10: Analytics & Reporting
Real-time analytics with PostgreSQL materialized views for performance.
OrderAnalyticsService
getDashboardMetrics()— total orders, revenue, AOV, unique customers, status/payment breakdownsgetRevenueTimeSeries()— daily order counts and revenuegetSourceBreakdown()— orders and revenue by source modulegetFulfillmentMetrics()— delivery rate, cancellation rate, RTO rategetCodVsPrepaid()— COD vs prepaid count and revenue splitgetTopProducts()— products ranked by quantity and revenue
Materialized Views
mv_daily_order_stats— pre-aggregated daily metricsmv_order_source_stats— per-source daily metrics- Refreshed every 15 minutes via
REFRESH MATERIALIZED VIEW CONCURRENTLY - Uses unique indexes for non-blocking concurrent refresh
Phase 11: Advanced Features
Outbound webhooks, order amendments, and tenant-definable custom fields.
Outbound Webhooks
- Register HTTP endpoints to receive order events
- HMAC-SHA256 signature verification via
X-Webhook-Signatureheader - 3 retries with 60-second backoff
- Auto-disable after 10 consecutive failures
- Full delivery logging with response status, body, and duration
Order Amendments
amendItems()— replace order items, recalculate totals, log activityamendAddress()— update shipping/billing address, log activitysyncBackToSource()— push changes back to source store (Shopify, etc.) via bus
Custom Fields
- Tenant-definable fields stored in
custom_fieldsJSONB column - Field types:
text,number,select,boolean,date - Fields can be marked as
is_requiredandis_filterable - CRUD API for field definitions
Infrastructure Summary
| Metric | Count |
|---|---|
| API routes | 70+ |
| Services | 14 |
| Models (new/modified) | 12 |
| Migrations | 10 |
| Controllers | 10 |
| Jobs | 6 |
| Listeners | 4 |
| DTOs | 2 |
| Bus endpoints (provides) | 10 |
| Events published | 13 |
| Tests | 129 (68 unit + 61 feature) |
Test Coverage
| Category | Tests | What's Covered |
|---|---|---|
| Order Model | 14 | Status/payment constants, fillable, casts, canShip/canCancel |
| IngestOrderDTO | 7 | Creation, defaults, roundtrip, type casting, readonly |
| IngestResult | 8 | Counters, error tracking, structure |
| TaxService | 7 | CGST/SGST split, IGST, rate variations, rounding |
| NotificationService | 5 | Template rendering with placeholders |
| OutboundWebhookService | 4 | Failure threshold disabling |
| OrderEventPublisher | 8 | All lifecycle event publishing |
| OrderBusHandler | 3 | Format structure, stub responses |
| OrderReturn Model | 6 | Constants, number generation, casts |
| OrderInvoice Model | 6 | Type/status constants, casts |
| OrderIngestService | 9 | Ingest, upsert, batch, customer resolution |
| PaymentService | 10 | Record, reconcile, refund, COD, payment links |
| ReturnService | 8 | Full lifecycle (request to refund) |
| InvoiceService | 9 | Generation, numbering, credit notes |
| OrderAnalyticsService | 10 | Metrics, revenue, fulfillment, COD/prepaid |
| OrderService | 7 | Create, update, bulk status, statistics |
| Order API | 8 | HTTP endpoints (CRUD, status, stats) |
Related Documentation
- Orders Module (main) — Architecture, data model, API reference
- Payments & Refunds — Payment lifecycle and refund processing
- Returns — Return request lifecycle
- Shipping & Fulfillment — Shipment tracking and carrier integration
- Tax & Invoicing — GST calculation and invoice generation
- Analytics & Reporting — Dashboard metrics and materialized views
- Inventory Integration — Event-driven stock management
- Webhooks & Notifications — Outbound webhooks and notification rules
- Bulk Operations — CSV import/export and batch processing