Users - Analytics Service

Location: api/nextango/apps/users/analytics_service.py Last Updated: 2026-07-08

Overview

Provides aggregated customer and employee metrics for the analytics dashboard. Two service classes cover separate concerns: CustomerAnalyticsService for customer KPIs (acquisition, retention, lifetime value, loyalty) and EmployeeAnalyticsService for staff performance (sales totals, transaction counts, cash drawer activity). All methods use the replica database when USE_REPLICA_DATABASE=True and cache results for 5 minutes.


Class: CustomerAnalyticsService

Aggregation methods for customer analytics derived from Customer, User, and SaleTransaction records.


get_customer_summary()

Purpose: Returns headline customer KPIs: total and new customers, returning customers, average lifetime value, loyalty points and store credit outstanding, and marketing opt-in rate.

Parameters:

ParamTypeRequiredDescription
store_idstrNoFilter transaction-based metrics by store UUID or Sanity ID
start_datedateNoStart of period (inclusive)
end_datedateNoEnd of period (inclusive)

Returns:

{
    'total_customers': int,
    'new_customers': int,                        # Customers created within the date range
    'returning_customers': int,                  # Customers with 2+ transactions in period
    'average_lifetime_value': Decimal,           # All-time avg spend per customer
    'total_loyalty_points_outstanding': int,
    'total_store_credit_outstanding': Decimal,
    'marketing_opt_in_rate': float,              # Percentage (0–100)
}

Example:

from nextango.apps.users.analytics_service import CustomerAnalyticsService
from datetime import date

result = CustomerAnalyticsService.get_customer_summary(
    store_id='store-uuid',
    start_date=date(2026, 1, 1),
    end_date=date(2026, 1, 31),
)
print(f"New customers this month: {result['new_customers']}")

get_top_customers()

Purpose: Returns the top N customers by total spend in a period, with order count, average order value, and last purchase date.

Parameters:

ParamTypeRequiredDescription
store_idstrNoFilter by store UUID or Sanity ID
start_datedateNoStart of period
end_datedateNoEnd of period
limitintNoMax results (default: 10)

Returns:

{
    'data': [
        {
            'customer_id': UUID,
            'name': str,
            'email': str,
            'total_spent': Decimal,
            'order_count': int,
            'avg_order_value': Decimal,
            'last_purchase': str,    # ISO 8601 datetime string
        },
        ...
    ]
}

Rows are ordered by total_spent descending.

Example:

result = CustomerAnalyticsService.get_top_customers(limit=5)
for customer in result['data']:
    print(f"{customer['name']}: £{customer['total_spent']}")

Class: EmployeeAnalyticsService

Aggregation methods for employee performance derived from SaleTransaction and CashDrawerEvent records.


get_employee_performance()

Purpose: Returns per-employee sales totals, transaction counts, average transaction value, and items sold for completed transactions in a period.

Parameters:

ParamTypeRequiredDescription
store_idstrNoFilter by store UUID or Sanity ID
start_datedateNoStart of period
end_datedateNoEnd of period

Returns:

{
    'data': [
        {
            'employee_id': UUID,
            'name': str,
            'total_sales': Decimal,
            'transaction_count': int,
            'avg_transaction_value': Decimal,
            'items_sold': int,
        },
        ...
    ]
}

Rows are ordered by total_sales descending.

Example:

from nextango.apps.users.analytics_service import EmployeeAnalyticsService

result = EmployeeAnalyticsService.get_employee_performance(store_id='store-uuid')
for emp in result['data']:
    print(f"{emp['name']}: {emp['transaction_count']} transactions")

get_cash_drawer_summary()

Purpose: Returns per-employee cash drawer activity (open/close counts, total cash sales, deposits, no-sale events) for a period.

Parameters:

ParamTypeRequiredDescription
store_idstrNoFilter by store UUID or Sanity ID
start_datedateNoStart of period
end_datedateNoEnd of period

Returns:

{
    'data': [
        {
            'employee_name': str,
            'open_count': int,
            'close_count': int,
            'total_cash_sales': Decimal,
            'total_deposits': Decimal,
            'no_sale_count': int,
            'total_events': int,
        },
        ...
    ]
}

Rows are ordered by total_cash_sales descending.


get_rfm_scores()

Purpose: Scores all customers using the RFM model (Recency, Frequency, Monetary). Each dimension is ranked into quintiles (1–5), and the combined score ranks customers by overall value.

Parameters:

ParamTypeRequiredDescription
store_idstrNoFilter by store UUID or Sanity ID

Returns:

{
    'data': [
        {
            'customer_id': UUID,
            'r_score': int,           # 1–5, higher = more recent purchase
            'f_score': int,           # 1–5, higher = more frequent
            'm_score': int,           # 1–5, higher = more spend
            'rfm_score': int,         # r_score + f_score + m_score (3–15)
            'total_spend': float,
            'order_count': int,
            'days_since_last_purchase': int,
        },
        ...
    ]
}

Rows are ordered by rfm_score descending. Only customers with at least one completed transaction are included.

Scoring method: Values are sorted into quintiles using rank position. The lowest 20% of days-since-last-purchase (i.e., most recent) receives a recency score of 5. Frequency and monetary scores rank highest values highest.


get_cohort_retention()

Purpose: Builds a cohort retention matrix. Customers are grouped by the calendar month of their first completed transaction. Each cell shows the percentage of that cohort who made at least one additional purchase in that offset month.

Parameters:

ParamTypeRequiredDescription
store_idstrNoFilter by store UUID or Sanity ID

Returns:

{
    'cohorts': [
        {
            'cohort_month': str,       # 'YYYY-MM'
            'size': int,               # Total customers in this cohort
            'retention': {
                0: float,              # Month 0 (always 100%: acquisition month)
                1: float,              # % still active in month 1
                2: float,              # % still active in month 2
                # ...
            }
        },
        ...
    ]
}

Cohorts are ordered chronologically. Retention percentages are rounded to one decimal place. Months with no activity for a given cohort are absent from the retention dict (not zero).

Implementation note: Uses TruncMonth with UTC timezone to prevent off-by-one cohort assignment at month boundaries.


get_repeat_purchase_rate()

Purpose: Returns the percentage of customers with 2+ completed transactions in a period, plus supporting metrics.

Parameters:

ParamTypeRequiredDescription
store_idstrNoFilter by store UUID or Sanity ID
start_datedateNoStart of period (inclusive)
end_datedateNoEnd of period (inclusive)

Returns:

{
    'repeat_rate_pct': float,                  # Percentage of customers with 2+ orders
    'repeat_customers': int,                   # Count of customers with 2+ orders
    'total_customers_with_orders': int,        # All customers with at least 1 order in period
    'avg_orders_per_repeat_customer': float,   # Avg order count among repeat buyers only
}

Caching

Every method caches its result for 300 seconds (5 minutes), scoped per parameter set: two calls with the same arguments within that window return the cached result, and a call with different arguments computes fresh.


  • Models: User, Customer, Employee
  • Views: Analytics endpoints that call these services
  • Backends: CustomTokenAuthentication

Was this page helpful?