""" Internal API for triggering delivery tracking alerts. Used by demo session cloning to generate realistic late delivery alerts. Moved from orchestrator service to procurement service (domain ownership). URL Pattern: /api/v1/tenants/{tenant_id}/procurement/internal/delivery-tracking/trigger This follows the tenant-scoped pattern so gateway can proxy correctly. """ from fastapi import APIRouter, HTTPException, Request, Path from uuid import UUID import structlog logger = structlog.get_logger() router = APIRouter() # New URL pattern: tenant-scoped so gateway proxies to procurement service correctly @router.post("/api/v1/tenants/{tenant_id}/procurement/internal/delivery-tracking/trigger") async def trigger_delivery_tracking( tenant_id: UUID = Path(..., description="Tenant ID to check deliveries for"), request: Request = None ) -> dict: """ Trigger delivery tracking for a specific tenant (internal use only). This endpoint is called by the demo session cloning process after POs are seeded to generate realistic delivery alerts (arriving soon, overdue, etc.). Security: Protected by x-internal-service header check. Args: tenant_id: Tenant UUID to check deliveries for request: FastAPI request object Returns: { "success": true, "tenant_id": "uuid", "alerts_generated": 3, "breakdown": { "arriving_soon": 1, "overdue": 1, "receipt_incomplete": 1 } } """ try: # Verify internal service header if not request or request.headers.get("x-internal-service") not in ["demo-session", "internal"]: logger.warning("Unauthorized internal API call", tenant_id=str(tenant_id)) raise HTTPException( status_code=403, detail="This endpoint is for internal service use only" ) # Get delivery tracking service from app state delivery_tracking_service = getattr(request.app.state, 'delivery_tracking_service', None) if not delivery_tracking_service: logger.error("Delivery tracking service not initialized") raise HTTPException( status_code=500, detail="Delivery tracking service not available" ) # Trigger delivery tracking for this tenant logger.info("Triggering delivery tracking", tenant_id=str(tenant_id)) result = await delivery_tracking_service.check_expected_deliveries(tenant_id) logger.info( "Delivery tracking completed", tenant_id=str(tenant_id), alerts_generated=result.get("total_alerts", 0) ) return { "success": True, "tenant_id": str(tenant_id), "alerts_generated": result.get("total_alerts", 0), "breakdown": { "arriving_soon": result.get("arriving_soon", 0), "overdue": result.get("overdue", 0), "receipt_incomplete": result.get("receipt_incomplete", 0) } } except HTTPException: raise except Exception as e: logger.error( "Error triggering delivery tracking", tenant_id=str(tenant_id), error=str(e), exc_info=True ) raise HTTPException( status_code=500, detail=f"Failed to trigger delivery tracking: {str(e)}" )