Promotions - Analytics Service

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

Overview

Provides aggregated promotional analytics for the dashboard: promo code performance, campaign summary, campaign lift (test vs. control revenue), and auto-apply promotion performance. The service reads from the replica database when USE_REPLICA_DATABASE=True and caches every method's result for 5 minutes. Called by the promotions analytics endpoints in Views.


Class: PromotionAnalyticsService

Aggregation methods for promotional campaign analytics.


Method Reference

get_promo_code_performance()

Purpose: Returns per-promo-code analytics from completed transactions: usage count, total discount granted, revenue from orders where the code was applied, and average order value for those orders. Also returns the percentage of all completed transactions that used a promo code and the total discount amount distributed.

Parameters:

ParamTypeRequiredDescription
store_idstrNoFilter by store UUID or Sanity ID
start_datedateNoFilter transactions on or after this date
end_datedateNoFilter transactions on or before this date

Returns:

{
    'data': [
        {
            'code': str,                       # PromoCode.code
            'code_name': str,                  # PromoCode.name
            'is_active': bool,
            'usage_count': int,                # Transactions using this code
            'total_discount_given': Decimal,   # Sum of orderLevelDiscount
            'revenue_from_promo_orders': Decimal,  # Sum of totalAmount
            'avg_order_with_promo': Decimal,
        },
        ...
    ],
    'total_promo_discount': Decimal,       # Total discount across all codes in period
    'orders_with_promo_pct': float,        # % of all completed orders that used a promo
}

Rows are ordered by revenue_from_promo_orders descending.

Example:

from nextango.apps.promotions.analytics_service import PromotionAnalyticsService
from datetime import date

result = PromotionAnalyticsService.get_promo_code_performance(
    start_date=date(2026, 1, 1),
    end_date=date(2026, 1, 31),
)
print(f"Total promo discount issued: £{result['total_promo_discount']}")
for code in result['data']:
    print(f"  {code['code']}: {code['usage_count']} uses, £{code['total_discount_given']} discounted")

get_campaign_summary()

Purpose: Returns a summary of all promotional campaigns with their type, active status, number of associated promo codes, and total usage across those codes.

Parameters: None

Returns:

{
    'data': [
        {
            'campaign_name': str,
            'campaign_type': str,             # e.g. 'seasonal_sale', 'flash_sale', 'clearance'
            'is_active': bool,
            'promo_codes_count': int,         # Number of PromoCode records linked
            'total_usage': int,               # Sum of current_usage_count across codes
            'performance_metrics': dict,      # PromotionalCampaign.performance_metrics JSON
        },
        ...
    ]
}

Example:

result = PromotionAnalyticsService.get_campaign_summary()
for campaign in result['data']:
    print(f"{campaign['campaign_name']}: {campaign['total_usage']} total uses")

get_campaign_lift(campaign_id)

Purpose: Compares revenue during a campaign's active window (test period) against an equal-length period immediately before it (control period), for transactions carrying one of the campaign's promo codes.

Parameters:

ParamTypeRequiredDescription
campaign_idstrYesPromotionalCampaign primary key

Returns:

{
    'campaign_id': str,
    'test_revenue': Decimal,      # Revenue from completed transactions using the campaign's codes, within date_range
    'control_revenue': Decimal,   # Revenue from all completed transactions in the equal-length prior window
    'lift_pct': float | None,     # Percentage change, None if control_revenue is 0
    'test_orders': int,
    'control_orders': int,
}

Returns an empty result (all zeros, lift_pct: None) if the campaign does not exist or has no date_range.


get_auto_promotion_performance()

Purpose: Aggregates performance for auto-apply Promotion records by grouping SaleTransactionAppliedPromotion snapshot rows, so historical performance is preserved even after a Promotion is deleted.

Parameters:

ParamTypeRequiredDescription
store_idstrNoFilter by store UUID
start_datedateNoFilter transactions on or after this date
end_datedateNoFilter transactions on or before this date

Returns:

{
    'data': [
        {
            'promotion_snapshot_id': str,
            'promotion_name': str,             # Snapshot name at time of sale
            'usage_count': int,
            'total_discount_given': float,
            'revenue_from_promo_orders': float,
            'avg_discount_per_use': float,
        },
        ...
    ]
}

Rows are ordered by usage_count descending.


Caching

All four methods use @cache_result with a 300-second (5-minute) TTL.

MethodCache Key PrefixVary On
get_promo_code_performancepromo_analytics_codesstore_id, start_date, end_date
get_campaign_summarypromo_analytics_campaignsnone, global
get_campaign_liftpromo_analytics_liftcampaign_id
get_auto_promotion_performancepromo_analytics_autostore_id, start_date, end_date

  • Models - PromotionalCampaign, PromoCode, ABTest, SaleTransactionAppliedPromotion
  • Views - Analytics endpoints that call this service
  • Services - Promo code validation and discount calculation

Was this page helpful?