Files
bakery-ia/services/distribution/app/api/routes.py

149 lines
5.3 KiB
Python
Raw Normal View History

2025-11-30 09:12:40 +01:00
"""
API Routes for Distribution Service
"""
from fastapi import APIRouter, Depends, HTTPException, Query, Header
from typing import List, Optional, Dict, Any
from datetime import date, timedelta
import structlog
import os
from app.api.dependencies import get_distribution_service
2025-12-05 20:07:01 +01:00
from shared.auth.tenant_access import verify_tenant_access_dep
from shared.routing.route_builder import RouteBuilder
2025-11-30 09:12:40 +01:00
from app.core.config import settings
logger = structlog.get_logger()
2025-12-05 20:07:01 +01:00
# Initialize route builder for distribution service
route_builder = RouteBuilder('distribution')
2025-11-30 09:12:40 +01:00
async def verify_internal_api_key(x_internal_api_key: str = Header(None)):
"""Verify internal API key for service-to-service communication"""
required_key = settings.INTERNAL_API_KEY
if x_internal_api_key != required_key:
logger.warning("Unauthorized internal API access attempted")
raise HTTPException(status_code=403, detail="Invalid internal API key")
return True
router = APIRouter()
2025-12-05 20:07:01 +01:00
@router.post(route_builder.build_base_route("plans/generate"))
2025-11-30 09:12:40 +01:00
async def generate_daily_distribution_plan(
tenant_id: str,
target_date: date = Query(..., description="Date for which to generate distribution plan"),
vehicle_capacity_kg: float = Query(1000.0, description="Vehicle capacity in kg"),
distribution_service: object = Depends(get_distribution_service),
2025-12-05 20:07:01 +01:00
verified_tenant: str = Depends(verify_tenant_access_dep)
2025-11-30 09:12:40 +01:00
):
"""
Generate daily distribution plan for internal transfers
**Enterprise Tier Feature**: Distribution and routing require Enterprise subscription.
"""
try:
# Validate subscription tier for distribution features
from shared.subscription.plans import PlanFeatures
from shared.clients import get_tenant_client
tenant_client = get_tenant_client(config=settings, service_name="distribution-service")
subscription = await tenant_client.get_tenant_subscription(tenant_id)
if not subscription:
raise HTTPException(
status_code=403,
detail="No active subscription found. Distribution routing requires Enterprise tier."
)
# Check if tier has distribution feature (enterprise only)
tier = subscription.get("plan", "starter")
if not PlanFeatures.has_feature(tier, "distribution_management"):
raise HTTPException(
status_code=403,
detail=f"Distribution routing requires Enterprise tier. Current tier: {tier}"
)
result = await distribution_service.generate_daily_distribution_plan(
parent_tenant_id=tenant_id,
target_date=target_date,
vehicle_capacity_kg=vehicle_capacity_kg
)
return result
except HTTPException:
raise
except Exception as e:
logger.error("Error generating distribution plan", error=str(e), exc_info=True)
raise HTTPException(status_code=500, detail=f"Failed to generate distribution plan: {str(e)}")
2025-12-05 20:07:01 +01:00
@router.get(route_builder.build_base_route("routes"))
2025-11-30 09:12:40 +01:00
async def get_delivery_routes(
tenant_id: str,
date_from: Optional[date] = Query(None, description="Start date for route filtering"),
date_to: Optional[date] = Query(None, description="End date for route filtering"),
status: Optional[str] = Query(None, description="Filter by route status"),
distribution_service: object = Depends(get_distribution_service),
2025-12-05 20:07:01 +01:00
verified_tenant: str = Depends(verify_tenant_access_dep)
2025-11-30 09:12:40 +01:00
):
"""
Get delivery routes with optional filtering
"""
try:
# If no date range specified, default to today
if not date_from and not date_to:
date_from = date.today()
date_to = date.today()
elif not date_to:
date_to = date_from
routes = []
current_date = date_from
while current_date <= date_to:
daily_routes = await distribution_service.get_delivery_routes_for_date(tenant_id, current_date)
routes.extend(daily_routes)
current_date = current_date + timedelta(days=1)
if status:
routes = [r for r in routes if r.get('status') == status]
return {"routes": routes}
except Exception as e:
logger.error("Error getting delivery routes", error=str(e), exc_info=True)
raise HTTPException(status_code=500, detail=f"Failed to get delivery routes: {str(e)}")
2025-12-05 20:07:01 +01:00
@router.get(route_builder.build_base_route("routes/{route_id}"))
2025-11-30 09:12:40 +01:00
async def get_route_detail(
tenant_id: str,
route_id: str,
distribution_service: object = Depends(get_distribution_service),
2025-12-05 20:07:01 +01:00
verified_tenant: str = Depends(verify_tenant_access_dep)
2025-11-30 09:12:40 +01:00
):
"""
Get delivery route details
"""
try:
# Implementation would fetch detailed route information
# For now, return a simple response
routes = await distribution_service.get_delivery_routes_for_date(tenant_id, date.today())
route = next((r for r in routes if r.get('id') == route_id), None)
if not route:
raise HTTPException(status_code=404, detail="Route not found")
return route
except HTTPException:
raise
except Exception as e:
logger.error("Error getting route detail", error=str(e), exc_info=True)
raise HTTPException(status_code=500, detail=f"Failed to get route detail: {str(e)}")