Analytics - Services Documentation

Location: api/nextango/apps/analytics/services/ Last Updated: 2026-03-14

Overview

The Analytics domain owns two services: ActiveOperationsService surfaces live operational queues (pending pickups, in-transit shipments, pending transactions, open returns), and InfrastructureService aggregates sync pipeline health and system component status.

All other analytics data is retrieved by delegating to domain-owned services in transactions, products, users, promotions, and procurement. See the domain overview for the full mapping.


ActiveOperationsService

Location: api/nextango/apps/analytics/services/active_operations.py

Surfaces live operational queues for a single store. Each method returns a list of plain dicts so callers can serialize results without ORM awareness.

Constructor

service = ActiveOperationsService(store_id="uuid-or-sanity-id")

store_id accepts either the store's Django UUID primary key or its Sanity document ID. All queries use a combined Q(store__id=s) | Q(store__sanity_id=s) filter.


get_pending_pickups()

Returns PickupSchedule rows with status pending or ready for the store, ordered by scheduled_time.

Store is reached via: fulfillment → transaction → store.

Returns: list[dict]

[
    {
        "id": "uuid",
        "status": "pending",
        "scheduled_time": "2026-03-06T15:00:00Z",
        "ready_at": null,
        "customer_notified_at": null,
        "preparation_notes": "Handle with care",
        "fulfillment_id": "uuid",
        "transaction_id": "uuid"
    }
]

get_in_transit_shipments()

Returns Shipment rows with status shipped or in_transit, ordered by created_at descending.

Store is reached via: fulfillment → transaction → store.

Returns: list[dict]

[
    {
        "id": "uuid",
        "status": "in_transit",
        "carrier_name": "FedEx",
        "tracking_number": "7489234908",
        "shipped_at": "2026-03-05T10:00:00Z",
        "fulfillment_id": "uuid"
    }
]

get_pending_transactions()

Returns SaleTransaction rows with status pending or partially_paid, ordered by timestamp descending.

Includes expires_at so the dashboard can surface expiry warnings for layaway and pay-at-pickup orders.

Returns: list[dict]

[
    {
        "id": "uuid",
        "transaction_id": "TXN-001",
        "status": "pending",
        "total_amount": "49.99",
        "expires_at": "2026-03-06T14:00:00Z",
        "timestamp": "2026-03-06T13:45:00Z"
    }
]

expires_at is null for counter-sale transactions.


get_open_returns()

Returns Return rows with status pending, ordered by timestamp descending.

Store is reached via: originalSaleId → store.

Returns: list[dict]

[
    {
        "id": "uuid",
        "return_id": "RTN-001",
        "status": "pending",
        "reason": "Defective item",
        "timestamp": "2026-03-06T11:00:00Z",
        "original_transaction_id": "uuid"
    }
]

InfrastructureService

Location: api/nextango/apps/analytics/services/infrastructure.py

Aggregates sync pipeline stats and system health. All methods are safe to call — exceptions are caught and logged internally, never raised to the caller.

Used by GET /api/analytics/system/infrastructure/.

get_all(days=30)

Assembles the full infrastructure payload by calling all sub-methods. The days parameter controls the lookback window for all stats (minimum 7, maximum 365).

service = InfrastructureService()
data = service.get_all(days=30)

get_webhook_stats(days=30)

Aggregates WebhookEvent counts for the last N days. Covers inbound Sanity→Django traffic only.

Returns:

{
    "total_received": 1240,
    "processed": 1228,
    "failed": 12,
    "retrying": 0,
    "avg_processing_ms": 145.3
}

avg_processing_ms is null when no completed events exist in the window.


get_sync_audit_stats(days=30)

Aggregates SyncAuditLog counts for the last N days. Covers both inbound (Sanity→Django) and outbound (Django→Sanity) sync operations.

Returns:

{
    "inbound": {"total": 1240, "completed": 1228, "failed": 12},
    "outbound": {"total": 320, "completed": 318, "failed": 2},
    "combined": {"total": 1560, "failed": 14}
}

get_daily_throughput(days=30)

Daily sync volume for the last N days, merging WebhookEvent (inbound) and SyncAuditLog outbound rows by date.

Returns: list of {hour, inbound, outbound, failed} dicts, one per day that had any activity. Days with no activity do not appear.

The hour key holds a YYYY-MM-DD date string (named hour for frontend chart compatibility).


get_db_health()

Pings the PostgreSQL connection.

Returns: {"status": "ok"} or {"status": "error", "detail": "..."}


get_redis_health()

Checks Redis via Django's cache layer (cache.get('_health')).

Returns: {"status": "ok"} or {"status": "error", "detail": "..."}


get_celery_health()

Checks Celery worker availability via inspect.stats() with a 0.5-second timeout.

Returns:

{"status": "ok", "worker_count": 2}
# or
{"status": "unknown", "worker_count": null}
# or
{"status": "error", "detail": "..."}

Returns "unknown" (not "error") when the inspect call times out or returns no workers — this is normal for staging environments with no active workers.



CustomerAnalyticsService

Location: api/nextango/apps/users/analytics_service.py (delegated via analytics domain)

All methods accept store_id and date range (start_date, end_date) unless noted.

get_cohort_retention()

Monthly cohort retention table. Groups customers by their first-purchase month and tracks repurchase rates across subsequent months.

Returns: list of cohort objects

[
    {
        "cohort_month": "2026-01",
        "cohort_size": 142,
        "periods": [
            {"period": 0, "retained": 142, "rate": 100.0},
            {"period": 1, "retained": 61, "rate": 43.0},
            {"period": 2, "retained": 38, "rate": 26.8}
        ]
    }
]

Period 0 is always 100%. Subsequent periods reflect the percentage of the original cohort that made at least one additional purchase in that month offset.


get_repeat_purchase_rate()

Ratio of customers who made more than one transaction in the period.

Returns:

{
    "total_customers": 890,
    "repeat_customers": 312,
    "repeat_purchase_rate": 35.06
}

get_rfm_scores()

Rank-based quintile scoring (1–5) across recency, frequency, and monetary dimensions per customer. Store-isolated. Higher scores are better across all three dimensions.

Returns: list of per-customer score rows

[
    {
        "customer_id": "uuid",
        "recency_score": 5,
        "frequency_score": 3,
        "monetary_score": 4,
        "rfm_total": 12
    }
]

ProcurementAnalyticsService

Location: api/nextango/apps/procurement/analytics_service.py (delegated via analytics domain)

get_supplier_lead_time_variance()

Actual vs expected lead time per supplier across purchase orders for the period.

Returns: list of per-supplier aggregates

[
    {
        "supplier_id": "uuid",
        "supplier_name": "Acme Co.",
        "avg_actual_lead_days": 8.4,
        "avg_expected_lead_days": 7.0,
        "variance_days": 1.4,
        "order_count": 12
    }
]

PromotionAnalyticsService — campaign lift

Location: api/nextango/apps/promotions/analytics_service.py (delegated via analytics domain)

get_campaign_lift(campaign_id)

Compares promo-code revenue during a campaign's test window against an equal-duration control window immediately preceding it.

Returns:

{
    "test_revenue": "12480.00",
    "control_revenue": "9310.00",
    "test_order_count": 248,
    "control_order_count": 194,
    "lift_pct": 34.05
}

A positive lift_pct indicates the campaign period outperformed the equivalent prior window. lift_pct is null when control_revenue is zero.


Was this page helpful?