Files
bakery-ia/services/forecasting/app/api/enterprise_forecasting.py

108 lines
4.2 KiB
Python
Raw Normal View History

2025-11-30 09:12:40 +01:00
"""
Enterprise forecasting API endpoints
"""
from fastapi import APIRouter, Depends, HTTPException, Query
from typing import Optional
from datetime import date
import structlog
from app.services.enterprise_forecasting_service import EnterpriseForecastingService
from shared.auth.tenant_access import verify_tenant_permission_dep
from shared.clients import get_forecast_client, get_tenant_client
import shared.redis_utils
from app.core.config import settings
logger = structlog.get_logger()
router = APIRouter()
# Global Redis client
_redis_client = None
async def get_forecasting_redis_client():
"""Get or create Redis client"""
global _redis_client
try:
if _redis_client is None:
_redis_client = await shared.redis_utils.initialize_redis(settings.REDIS_URL)
logger.info("Redis client initialized for enterprise forecasting")
return _redis_client
except Exception as e:
logger.warning("Failed to initialize Redis client, enterprise forecasting will work with limited functionality", error=str(e))
return None
async def get_enterprise_forecasting_service(
redis_client = Depends(get_forecasting_redis_client)
) -> EnterpriseForecastingService:
"""Dependency injection for EnterpriseForecastingService"""
forecast_client = get_forecast_client(settings, "forecasting-service")
tenant_client = get_tenant_client(settings, "forecasting-service")
return EnterpriseForecastingService(
forecast_client=forecast_client,
tenant_client=tenant_client,
redis_client=redis_client
)
@router.get("/tenants/{tenant_id}/forecasting/enterprise/aggregated")
async def get_aggregated_forecast(
tenant_id: str,
start_date: date = Query(..., description="Start date for forecast aggregation"),
end_date: date = Query(..., description="End date for forecast aggregation"),
product_id: Optional[str] = Query(None, description="Optional product ID to filter by"),
enterprise_forecasting_service: EnterpriseForecastingService = Depends(get_enterprise_forecasting_service),
verified_tenant: str = Depends(verify_tenant_permission_dep)
):
"""
Get aggregated forecasts across parent and child tenants
"""
try:
# Check if this tenant is a parent tenant
tenant_info = await enterprise_forecasting_service.tenant_client.get_tenant(tenant_id)
if tenant_info.get('tenant_type') != 'parent':
raise HTTPException(
status_code=403,
detail="Only parent tenants can access aggregated enterprise forecasts"
)
result = await enterprise_forecasting_service.get_aggregated_forecast(
parent_tenant_id=tenant_id,
start_date=start_date,
end_date=end_date,
product_id=product_id
)
return result
except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to get aggregated forecast: {str(e)}")
@router.get("/tenants/{tenant_id}/forecasting/enterprise/network-performance")
async def get_network_performance_metrics(
tenant_id: str,
start_date: date = Query(..., description="Start date for metrics"),
end_date: date = Query(..., description="End date for metrics"),
enterprise_forecasting_service: EnterpriseForecastingService = Depends(get_enterprise_forecasting_service),
verified_tenant: str = Depends(verify_tenant_permission_dep)
):
"""
Get aggregated performance metrics across tenant network
"""
try:
# Check if this tenant is a parent tenant
tenant_info = await enterprise_forecasting_service.tenant_client.get_tenant(tenant_id)
if tenant_info.get('tenant_type') != 'parent':
raise HTTPException(
status_code=403,
detail="Only parent tenants can access network performance metrics"
)
result = await enterprise_forecasting_service.get_network_performance_metrics(
parent_tenant_id=tenant_id,
start_date=start_date,
end_date=end_date
)
return result
except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to get network performance: {str(e)}")