KPI Total Sales Widget API
Overview
This document describes the KPI (Key Performance Indicator) Total Sales Widget API implementation in the Analytics and Notification Service (ANS). The API provides endpoints for retrieving sales analytics data with daily, weekly, and monthly granularity.
Architecture
The implementation follows the TMS (Transaction Management Service) coding style with a clean separation of concerns:
app/
βββ schemas/
β βββ kpi_schema.py # Pydantic models for request/response
βββ repositories/
β βββ kpi_repository.py # Data access layer (SQL queries)
βββ services/
β βββ kpi_service.py # Business logic layer
βββ routers/
β βββ kpi_router.py # API endpoints
βββ utils/
βββ request_id_utils.py # Request correlation utilities
API Endpoints
Base URL
/api/v1/kpi
1. Get Total Sales KPI (POST)
Endpoint: POST /api/v1/kpi/total-sales
Description: Retrieve total sales KPI data with specified time granularity.
Authentication: Required (Bearer token)
Permissions: view_analytics
Request Body:
{
"merchant_id": "MERCH123",
"branch_id": "BRANCH001",
"metric_type": "total_sales",
"granularity": "daily",
"start_date": "2024-01-01T00:00:00Z",
"end_date": "2024-01-31T23:59:59Z"
}
Request Parameters:
merchant_id(string, required): Merchant identifierbranch_id(string, optional): Branch/Store identifier for filteringmetric_type(string, required): Type of KPI metric (currently supports "total_sales")granularity(string, required): Time granularity - "daily", "weekly", or "monthly"start_date(datetime, required): Start date for KPI calculationend_date(datetime, required): End date for KPI calculation
Response:
{
"status": "success",
"data": {
"merchant_id": "MERCH123",
"branch_id": "BRANCH001",
"metric_type": "total_sales",
"granularity": "daily",
"start_date": "2024-01-01T00:00:00Z",
"end_date": "2024-01-31T23:59:59Z",
"data_points": [
{
"period": "2024-01-01",
"value": 15000.50,
"transaction_count": 45,
"period_start": "2024-01-01T00:00:00Z",
"period_end": "2024-01-01T23:59:59Z"
},
{
"period": "2024-01-02",
"value": 18500.75,
"transaction_count": 52,
"period_start": "2024-01-02T00:00:00Z",
"period_end": "2024-01-02T23:59:59Z"
}
],
"summary": {
"total": 465000.00,
"average": 15000.00,
"min_value": 8500.00,
"max_value": 22000.00,
"period_count": 31,
"total_transactions": 1350
},
"generated_at": "2024-02-01T10:30:00Z"
},
"message": "Total sales KPI retrieved successfully",
"correlation_id": "550e8400-e29b-41d4-a716-446655440000"
}
2. Get Total Sales KPI (GET)
Endpoint: GET /api/v1/kpi/total-sales
Description: Alternative endpoint using query parameters instead of request body.
Authentication: Required (Bearer token)
Permissions: view_analytics
Query Parameters:
granularity(string, required): Time granularity - "daily", "weekly", or "monthly"start_date(datetime, required): Start date for KPI calculationend_date(datetime, required): End date for KPI calculationbranch_id(string, optional): Branch/Store ID filter
Example Request:
GET /api/v1/kpi/total-sales?granularity=daily&start_date=2024-01-01T00:00:00Z&end_date=2024-01-31T23:59:59Z&branch_id=BRANCH001
Response: Same as POST endpoint
3. Get Widget KPI
Endpoint: POST /api/v1/kpi/widget/{widget_id}
Description: Get KPI data for a specific dashboard widget with automatic date range calculation.
Authentication: Required (Bearer token)
Permissions: view_analytics
Path Parameters:
widget_id(string, required): Widget identifier
Request Body:
{
"widget_id": "widget_123",
"granularity": "weekly",
"start_date": "2024-01-01T00:00:00Z",
"end_date": "2024-03-31T23:59:59Z"
}
Request Parameters:
widget_id(string, required): Widget identifiergranularity(string, required): Time granularity - "daily", "weekly", or "monthly"start_date(datetime, optional): Start date (defaults based on granularity)end_date(datetime, optional): End date (defaults to now)
Default Date Ranges:
- Daily: Last 30 days
- Weekly: Last 12 weeks
- Monthly: Last 12 months
Response:
{
"status": "success",
"data": {
"widget_id": "widget_123",
"kpi_data": {
"merchant_id": "MERCH123",
"branch_id": "BRANCH001",
"metric_type": "total_sales",
"granularity": "weekly",
"data_points": [...],
"summary": {...},
"generated_at": "2024-02-01T10:30:00Z"
}
},
"message": "Widget KPI retrieved successfully",
"correlation_id": "550e8400-e29b-41d4-a716-446655440000"
}
4. Health Check
Endpoint: GET /api/v1/kpi/health
Description: Health check endpoint for KPI service.
Authentication: Not required
Response:
{
"status": "healthy",
"service": "kpi",
"timestamp": "2024-02-01T10:30:00Z"
}
Data Models
KPIRequest
{
"merchant_id": str, # Merchant identifier
"branch_id": str | None, # Optional branch identifier
"metric_type": str, # "total_sales", "transaction_count", "average_order_value"
"granularity": str, # "daily", "weekly", "monthly"
"start_date": datetime, # Start date for calculation
"end_date": datetime # End date for calculation
}
KPIDataPoint
{
"period": str, # Period label (e.g., "2024-01-15", "2024-W03", "2024-01")
"value": float, # Metric value for the period
"transaction_count": int, # Number of transactions in period
"period_start": datetime, # Period start timestamp
"period_end": datetime # Period end timestamp
}
KPISummary
{
"total": float, # Total value across all periods
"average": float, # Average value per period
"min_value": float, # Minimum value in any period
"max_value": float, # Maximum value in any period
"period_count": int, # Number of periods
"total_transactions": int # Total number of transactions
}
KPIResponse
{
"merchant_id": str,
"branch_id": str | None,
"metric_type": str,
"granularity": str,
"start_date": datetime,
"end_date": datetime,
"data_points": List[KPIDataPoint],
"summary": KPISummary,
"generated_at": datetime
}
Time Granularity
Daily
- Aggregates sales by calendar day
- Period format:
YYYY-MM-DD(e.g., "2024-01-15") - Best for: Short-term analysis (last 30-90 days)
Weekly
- Aggregates sales by ISO week (Monday to Sunday)
- Period format:
YYYY-WNN(e.g., "2024-W03") - Best for: Medium-term trends (last 12-26 weeks)
Monthly
- Aggregates sales by calendar month
- Period format:
YYYY-MM(e.g., "2024-01") - Best for: Long-term trends (last 12-24 months)
Database Schema
The KPI API queries the sales_trans table from the TMS database:
SELECT
DATE_TRUNC(:granularity, transaction_date) as period_start,
SUM(total_amount) as total_sales,
COUNT(*) as transaction_count,
AVG(total_amount) as avg_order_value
FROM sales_trans
WHERE merchant_id = :merchant_id
AND transaction_date >= :start_date
AND transaction_date <= :end_date
AND status = 'completed'
AND (:branch_id IS NULL OR branch_id = :branch_id)
GROUP BY DATE_TRUNC(:granularity, transaction_date)
ORDER BY period_start ASC
Error Handling
Validation Errors (400)
{
"status": "error",
"message": "Validation error message",
"correlation_id": "550e8400-e29b-41d4-a716-446655440000"
}
Authentication Errors (401)
{
"detail": "Invalid authentication credentials"
}
Permission Errors (403)
{
"detail": "Forbidden"
}
Internal Errors (500)
{
"status": "error",
"message": "Failed to retrieve total sales KPI",
"correlation_id": "550e8400-e29b-41d4-a716-446655440000"
}
Metrics and Monitoring
The API tracks the following metrics using the insightfy_utils telemetry:
kpi_total_sales_requests- Counter for total sales KPI requestskpi_widget_requests- Counter for widget KPI requestskpi_validation_errors- Counter for validation errorskpi_errors- Counter for internal errorskpi_calculation_duration- Histogram of KPI calculation durationkpi_widget_duration- Histogram of widget KPI durationkpi_total_sales_value- Histogram of total sales values
Logging
All operations are logged with structured logging including:
- Merchant ID
- Branch ID
- Granularity
- Duration
- Correlation ID
- Error details (when applicable)
Authentication
All endpoints (except health check) require:
- Valid JWT token in Authorization header:
Bearer <token> - Token must contain:
merchant_idassociate_idbranch_idrole_id
Permissions
The API uses role-based access control (RBAC):
view_analytics- Required for all KPI endpoints
Usage Examples
cURL Examples
Get Daily Sales KPI
curl -X POST "http://localhost:8000/api/v1/kpi/total-sales" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"merchant_id": "MERCH123",
"branch_id": "BRANCH001",
"metric_type": "total_sales",
"granularity": "daily",
"start_date": "2024-01-01T00:00:00Z",
"end_date": "2024-01-31T23:59:59Z"
}'
Get Weekly Sales KPI (Query Parameters)
curl -X GET "http://localhost:8000/api/v1/kpi/total-sales?granularity=weekly&start_date=2024-01-01T00:00:00Z&end_date=2024-03-31T23:59:59Z" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
Get Widget KPI
curl -X POST "http://localhost:8000/api/v1/kpi/widget/widget_123" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"widget_id": "widget_123",
"granularity": "monthly"
}'
Python Examples
import requests
from datetime import datetime, timedelta
# Configuration
BASE_URL = "http://localhost:8000/api/v1/kpi"
TOKEN = "YOUR_JWT_TOKEN"
HEADERS = {
"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json"
}
# Get daily sales for last 30 days
end_date = datetime.utcnow()
start_date = end_date - timedelta(days=30)
payload = {
"merchant_id": "MERCH123",
"branch_id": "BRANCH001",
"metric_type": "total_sales",
"granularity": "daily",
"start_date": start_date.isoformat() + "Z",
"end_date": end_date.isoformat() + "Z"
}
response = requests.post(
f"{BASE_URL}/total-sales",
headers=HEADERS,
json=payload
)
if response.status_code == 200:
data = response.json()
kpi_data = data["data"]
print(f"Total Sales: ${kpi_data['summary']['total']:,.2f}")
print(f"Average: ${kpi_data['summary']['average']:,.2f}")
print(f"Transactions: {kpi_data['summary']['total_transactions']}")
else:
print(f"Error: {response.status_code} - {response.text}")
JavaScript/TypeScript Examples
interface KPIRequest {
merchant_id: string;
branch_id?: string;
metric_type: 'total_sales';
granularity: 'daily' | 'weekly' | 'monthly';
start_date: string;
end_date: string;
}
async function getTotalSalesKPI(
token: string,
request: KPIRequest
): Promise<any> {
const response = await fetch(
'http://localhost:8000/api/v1/kpi/total-sales',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
}
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
}
// Usage
const kpiData = await getTotalSalesKPI('YOUR_JWT_TOKEN', {
merchant_id: 'MERCH123',
branch_id: 'BRANCH001',
metric_type: 'total_sales',
granularity: 'daily',
start_date: '2024-01-01T00:00:00Z',
end_date: '2024-01-31T23:59:59Z'
});
console.log('Total Sales:', kpiData.data.summary.total);
Performance Considerations
- Query Optimization: The repository uses PostgreSQL's
DATE_TRUNCfunction for efficient date aggregation - Index Recommendations: Ensure indexes on:
merchant_idbranch_idtransaction_datestatus
- Caching: Consider implementing Redis caching for frequently accessed KPI data
- Pagination: For large date ranges, consider implementing pagination or limiting the maximum date range
Future Enhancements
Additional Metrics:
- Transaction count KPI
- Average order value KPI
- Customer acquisition metrics
- Product performance metrics
Advanced Features:
- Comparison with previous periods
- Trend analysis and forecasting
- Real-time KPI updates
- Export to CSV/Excel
- Scheduled KPI reports
Optimization:
- Materialized views for faster queries
- Background job for pre-calculating KPIs
- WebSocket support for real-time updates
Testing
Run the service and test the endpoints:
# Start the service
cd insightfy-bloom-ms-ans
uvicorn app.main:app --reload --port 8000
# Test health check
curl http://localhost:8000/api/v1/kpi/health
# Test KPI endpoint (requires valid token)
curl -X POST http://localhost:8000/api/v1/kpi/total-sales \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d @test_kpi_request.json
Support
For issues or questions:
- Check logs in the ANS service
- Review correlation_id in error responses for debugging
- Contact the development team
Version History
- v1.0.0 (2024-02-01): Initial implementation
- Total sales KPI with daily, weekly, monthly granularity
- Widget-specific KPI endpoints
- Authentication and authorization
- Metrics and logging