100 lines
3.4 KiB
Python
100 lines
3.4 KiB
Python
# services/sales/app/api/analytics.py
|
|
"""
|
|
Sales Analytics API - Reporting, statistics, and insights
|
|
"""
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query, Path
|
|
from typing import Optional, Dict, Any
|
|
from uuid import UUID
|
|
from datetime import datetime
|
|
import structlog
|
|
|
|
from app.services.sales_service import SalesService
|
|
from shared.routing import RouteBuilder
|
|
from shared.auth.access_control import analytics_tier_required
|
|
from shared.auth.decorators import get_current_user_dep
|
|
|
|
route_builder = RouteBuilder('sales')
|
|
router = APIRouter(tags=["sales-analytics"])
|
|
logger = structlog.get_logger()
|
|
|
|
|
|
def get_sales_service():
|
|
"""Dependency injection for SalesService"""
|
|
return SalesService()
|
|
|
|
|
|
@router.get(
|
|
route_builder.build_analytics_route("summary")
|
|
)
|
|
@analytics_tier_required
|
|
async def get_sales_analytics(
|
|
tenant_id: UUID = Path(..., description="Tenant ID"),
|
|
start_date: Optional[datetime] = Query(None, description="Start date filter"),
|
|
end_date: Optional[datetime] = Query(None, description="End date filter"),
|
|
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
|
sales_service: SalesService = Depends(get_sales_service)
|
|
):
|
|
"""Get sales analytics summary for a tenant (Professional+ tier required)"""
|
|
try:
|
|
analytics = await sales_service.get_sales_analytics(tenant_id, start_date, end_date)
|
|
|
|
logger.info("Retrieved sales analytics", tenant_id=tenant_id)
|
|
return analytics
|
|
|
|
except Exception as e:
|
|
logger.error("Failed to get sales analytics", error=str(e), tenant_id=tenant_id)
|
|
raise HTTPException(status_code=500, detail=f"Failed to get sales analytics: {str(e)}")
|
|
|
|
|
|
@router.get(
|
|
route_builder.build_analytics_route("products/{product_id}/demand-patterns")
|
|
)
|
|
@analytics_tier_required
|
|
async def get_product_demand_patterns(
|
|
tenant_id: UUID = Path(..., description="Tenant ID"),
|
|
product_id: UUID = Path(..., description="Product ID (inventory_product_id)"),
|
|
start_date: Optional[datetime] = Query(None, description="Start date for analysis"),
|
|
end_date: Optional[datetime] = Query(None, description="End date for analysis"),
|
|
min_history_days: int = Query(90, description="Minimum days of history required", ge=30, le=365),
|
|
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
|
sales_service: SalesService = Depends(get_sales_service)
|
|
):
|
|
"""
|
|
Analyze demand patterns for a specific product (Professional+ tier required).
|
|
|
|
Returns:
|
|
- Demand trends (increasing/decreasing/stable)
|
|
- Volatility metrics (coefficient of variation)
|
|
- Weekly seasonal patterns
|
|
- Peak/low demand days
|
|
- Statistical summaries
|
|
"""
|
|
try:
|
|
patterns = await sales_service.analyze_product_demand_patterns(
|
|
tenant_id=tenant_id,
|
|
inventory_product_id=product_id,
|
|
start_date=start_date,
|
|
end_date=end_date,
|
|
min_history_days=min_history_days
|
|
)
|
|
|
|
logger.info(
|
|
"Retrieved product demand patterns",
|
|
tenant_id=tenant_id,
|
|
product_id=product_id
|
|
)
|
|
return patterns
|
|
|
|
except Exception as e:
|
|
logger.error(
|
|
"Failed to get product demand patterns",
|
|
error=str(e),
|
|
tenant_id=tenant_id,
|
|
product_id=product_id
|
|
)
|
|
raise HTTPException(
|
|
status_code=500,
|
|
detail=f"Failed to analyze demand patterns: {str(e)}"
|
|
)
|