""" Production Service - Sustainability API Exposes production-specific sustainability metrics following microservices principles Each service owns its domain data """ from datetime import datetime, timedelta from typing import Optional from uuid import UUID from fastapi import APIRouter, Depends, Path, Query, Request import structlog from shared.auth.decorators import get_current_user_dep from app.services.production_service import ProductionService from shared.routing import RouteBuilder logger = structlog.get_logger() # Create route builder for consistent URL structure route_builder = RouteBuilder('production') router = APIRouter(tags=["production-sustainability"]) def get_production_service(request: Request) -> ProductionService: """Dependency injection for production service""" from app.core.database import database_manager from app.core.config import settings notification_service = getattr(request.app.state, 'notification_service', None) return ProductionService(database_manager, settings, notification_service) @router.get( "/api/v1/tenants/{tenant_id}/production/sustainability/waste-metrics", response_model=dict, summary="Get production waste metrics", description=""" Returns production-specific waste metrics for sustainability tracking. This endpoint is part of the microservices architecture where each service owns its domain data. Frontend aggregates data from multiple services. Metrics include: - Total production waste from batches (waste_quantity + defect_quantity) - Production volumes (planned vs actual) - Waste breakdown by defect type - AI-assisted batch tracking """ ) async def get_production_waste_metrics( tenant_id: UUID = Path(..., description="Tenant ID"), start_date: Optional[datetime] = Query(None, description="Start date for metrics (default: 30 days ago)"), end_date: Optional[datetime] = Query(None, description="End date for metrics (default: now)"), current_user: dict = Depends(get_current_user_dep), production_service: ProductionService = Depends(get_production_service) ): """ Get production waste metrics for sustainability dashboard Returns production-specific metrics that frontend will aggregate with inventory metrics for complete sustainability picture. """ try: # Set default dates if not end_date: end_date = datetime.now() if not start_date: start_date = end_date - timedelta(days=30) # Get waste analytics from production service waste_data = await production_service.get_waste_analytics( tenant_id=tenant_id, start_date=start_date, end_date=end_date ) # Enrich with metadata response = { **waste_data, "service": "production", "period": { "start_date": start_date.isoformat(), "end_date": end_date.isoformat(), "days": (end_date - start_date).days }, "metadata": { "data_source": "production_batches", "calculation_method": "SUM(waste_quantity + defect_quantity)", "filters_applied": { "status": ["COMPLETED", "QUALITY_CHECK"], "date_range": f"{start_date.date()} to {end_date.date()}" } } } logger.info( "Production waste metrics retrieved", tenant_id=str(tenant_id), total_waste_kg=waste_data.get('total_production_waste', 0), period_days=(end_date - start_date).days, user_id=current_user.get('user_id') ) return response except Exception as e: logger.error( "Error getting production waste metrics", tenant_id=str(tenant_id), error=str(e) ) raise @router.get( "/api/v1/tenants/{tenant_id}/production/sustainability/baseline", response_model=dict, summary="Get production baseline metrics", description=""" Returns baseline production metrics from the first 90 days of operation. Used by frontend to calculate SDG 12.3 compliance (waste reduction targets). If tenant has less than 90 days of data, returns industry average baseline. """ ) async def get_production_baseline( tenant_id: UUID = Path(..., description="Tenant ID"), current_user: dict = Depends(get_current_user_dep), production_service: ProductionService = Depends(get_production_service) ): """ Get baseline production metrics for SDG compliance calculations Frontend uses this to calculate: - Waste reduction percentage vs baseline - Progress toward SDG 12.3 targets - Grant eligibility based on improvement """ try: baseline_data = await production_service.get_baseline_metrics(tenant_id) # Add metadata response = { **baseline_data, "service": "production", "metadata": { "baseline_period_days": 90, "calculation_method": "First 90 days of production data", "fallback": "Industry average (25%) if insufficient data" } } logger.info( "Production baseline metrics retrieved", tenant_id=str(tenant_id), has_baseline=baseline_data.get('has_baseline', False), baseline_waste_pct=baseline_data.get('waste_percentage'), user_id=current_user.get('user_id') ) return response except Exception as e: logger.error( "Error getting production baseline", tenant_id=str(tenant_id), error=str(e) ) raise @router.get( "/api/v1/tenants/{tenant_id}/production/sustainability/ai-impact", response_model=dict, summary="Get AI waste reduction impact", description=""" Analyzes the impact of AI-assisted production on waste reduction. Compares waste rates between: - AI-assisted batches (with is_ai_assisted=true) - Manual batches (is_ai_assisted=false) Shows ROI of AI features for sustainability. """ ) async def get_ai_waste_impact( tenant_id: UUID = Path(..., description="Tenant ID"), start_date: Optional[datetime] = Query(None, description="Start date (default: 30 days ago)"), end_date: Optional[datetime] = Query(None, description="End date (default: now)"), current_user: dict = Depends(get_current_user_dep), production_service: ProductionService = Depends(get_production_service) ): """ Get AI impact on waste reduction Frontend uses this to showcase: - Value proposition of AI features - Waste avoided through AI assistance - Financial ROI of AI investment """ try: # Set default dates if not end_date: end_date = datetime.now() if not start_date: start_date = end_date - timedelta(days=30) # Get AI impact analytics (we'll implement this) ai_impact = await production_service.get_ai_waste_impact( tenant_id=tenant_id, start_date=start_date, end_date=end_date ) logger.info( "AI waste impact retrieved", tenant_id=str(tenant_id), ai_waste_reduction_pct=ai_impact.get('waste_reduction_percentage'), user_id=current_user.get('user_id') ) return ai_impact except Exception as e: logger.error( "Error getting AI waste impact", tenant_id=str(tenant_id), error=str(e) ) raise @router.get( "/api/v1/tenants/{tenant_id}/production/sustainability/summary", response_model=dict, summary="Get production sustainability summary", description=""" Quick summary endpoint combining all production sustainability metrics. Useful for dashboard widgets that need overview data without multiple calls. """ ) async def get_production_sustainability_summary( tenant_id: UUID = Path(..., description="Tenant ID"), days: int = Query(30, ge=7, le=365, description="Number of days to analyze"), current_user: dict = Depends(get_current_user_dep), production_service: ProductionService = Depends(get_production_service) ): """ Get comprehensive production sustainability summary Combines waste metrics, baseline, and AI impact in one response. Optimized for dashboard widgets. """ try: end_date = datetime.now() start_date = end_date - timedelta(days=days) # Get all metrics in parallel (within service) waste_data = await production_service.get_waste_analytics(tenant_id, start_date, end_date) baseline_data = await production_service.get_baseline_metrics(tenant_id) # Try to get AI impact (may not be available for all tenants) try: ai_impact = await production_service.get_ai_waste_impact(tenant_id, start_date, end_date) except: ai_impact = {"available": False} summary = { "service": "production", "period_days": days, "waste_metrics": waste_data, "baseline": baseline_data, "ai_impact": ai_impact, "last_updated": datetime.now().isoformat() } logger.info( "Production sustainability summary retrieved", tenant_id=str(tenant_id), period_days=days, user_id=current_user.get('user_id') ) return summary except Exception as e: logger.error( "Error getting production sustainability summary", tenant_id=str(tenant_id), error=str(e) ) raise