Analytics, Bulk Operations & Webhooks

Advanced Orders features for reporting, high-volume operations, and external integrations.

Analytics

The OrderAnalyticsService provides real-time metrics with PostgreSQL materialized views for performance at scale.

All analytics endpoints accept from and to query parameters for date range filtering.

Dashboard Metrics

GET /api/v1/orders/analytics/dashboard?from=2026-03-01&to=2026-03-31

Returns total orders, revenue, average order value, unique customers, and breakdowns by status and payment status.

Revenue Time Series

GET /api/v1/orders/analytics/revenue?from=2026-03-01&to=2026-03-31

Returns daily order counts and revenue.

Other Analytics Endpoints

Method Endpoint Description
GET /api/v1/orders/analytics/fulfillment Delivery, cancellation, and RTO rates
GET /api/v1/orders/analytics/sources Orders and revenue by source module
GET /api/v1/orders/analytics/products Top products by quantity and revenue
GET /api/v1/orders/analytics/cod-vs-prepaid COD vs prepaid count and revenue split

Service Usage

use Modules\Orders\App\Services\OrderAnalyticsService;

$analytics = app(OrderAnalyticsService::class);
$from = '2026-03-01';
$to = '2026-03-31';

$metrics = $analytics->getDashboardMetrics($from, $to);
$series = $analytics->getRevenueTimeSeries($from, $to);
$sources = $analytics->getSourceBreakdown($from, $to);
$fulfillment = $analytics->getFulfillmentMetrics($from, $to);
$split = $analytics->getCodVsPrepaid($from, $to);
$products = $analytics->getTopProducts($from, $to, 10);

Materialized Views

For high-traffic tenants, pre-computed analytics are refreshed every 15 minutes via RefreshAnalyticsViewsJob:

View Purpose
mv_daily_order_stats Pre-aggregated daily metrics (orders, revenue, AOV, COD/prepaid split)
mv_order_source_stats Per-source daily metrics

Views use REFRESH MATERIALIZED VIEW CONCURRENTLY with unique indexes for non-blocking reads during refresh.


Bulk Operations

High-volume operations with queued processing and progress tracking.

CSV Import

POST /api/v1/orders/bulk/import
Content-Type: multipart/form-data

file: orders.csv
source: csv-import

CSV columns: order_number, customer_phone (required*), customer_email (required*), customer_first_name, customer_last_name, item_name (required), item_quantity (required), item_price (required), item_sku, total, payment_status, status, notes. *Phone or email required.

Processing details:

  • Parsed in 500-row chunks via Bus::batch()
  • Uses PostgreSQL INSERT ... ON CONFLICT DO UPDATE for idempotent upserts
  • Real-time progress via Laravel Reverb WebSockets
  • Cancellable between chunks

Check Import Status

GET /api/v1/orders/bulk/import/{importId}

CSV Export

POST /api/v1/orders/bulk/export

{
  "filters": { "status": "delivered", "date_from": "2026-01-01", "date_to": "2026-03-01" },
  "columns": ["order_number", "customer_name", "total", "status", "created_at"]
}

Uses cursor-based streaming for memory efficiency.

Bulk Actions

Method Endpoint Description
POST /api/v1/orders/bulk/status Update status for multiple orders
POST /api/v1/orders/bulk/ship Create shipments from tracking data
POST /api/v1/orders/bulk/cancel Cancel multiple orders with reason

Queue Configuration

Add dedicated supervisors in config/horizon.php:

'supervisor-imports' => [
    'connection' => 'redis',
    'queue' => ['imports'],
    'maxProcesses' => 2,
    'timeout' => 600,
],
'supervisor-exports' => [
    'connection' => 'redis',
    'queue' => ['exports'],
    'maxProcesses' => 2,
    'timeout' => 300,
],

Outbound Webhooks

Register HTTP endpoints to receive real-time order event notifications.

Creating an Endpoint

POST /api/v1/order-webhooks

{
  "url": "https://yourapp.com/webhook/orders",
  "secret": "whsec_your_signing_secret",
  "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"
}

Signature Verification

Requests include an X-Webhook-Signature header (HMAC-SHA256 of the body using the endpoint secret). Verify in your receiver:

import hmac, hashlib

signature = request.headers['X-Webhook-Signature']
expected = hmac.new(secret.encode(), request.body, hashlib.sha256).hexdigest()
assert hmac.compare_digest(signature, expected)

Failure Handling

  • Failed deliveries retry 3 times with 60-second backoff
  • Auto-disabled after 10 consecutive failures
  • All deliveries logged with response status and duration

Notification Rules

Configure automatic notifications triggered by order events.

POST /api/v1/order-notification-rules

{
  "name": "Order Shipped SMS",
  "event": "order.fulfilled",
  "channel": "sms",
  "recipient_type": "customer",
  "template": "Hi {{customer_name}}, your order #{{order_number}} has been shipped! Track: {{tracking_url}}",
  "conditions": {},
  "is_active": true
}

Supported Channels

Channel Delivery
sms Via SMS provider module
whatsapp Via WhatsApp channel module
email Via email service
in_app Via NotificationService

Template Placeholders

{{order_number}}, {{customer_name}}, {{total}}, {{status}}, {{tracking_url}}, {{return_number}}

Test Send

POST /api/v1/order-notification-rules/{rule}/test

Custom Fields

Define tenant-specific fields that appear on orders.

Type Description
text Free text input
number Numeric input
select Dropdown with predefined options
boolean Toggle (yes/no)
date Date picker
POST /api/v1/order-custom-fields

{
  "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
}

Values are stored in the order's custom_fields JSONB column. Fields marked is_filterable can be used in order list queries.