# ================================================================ # services/suppliers/app/schemas/performance.py # ================================================================ """ Performance Tracking and Alert Schemas for Suppliers Service """ from datetime import datetime from typing import List, Optional, Dict, Any from uuid import UUID from pydantic import BaseModel, Field, validator from decimal import Decimal from app.models.performance import ( AlertSeverity, AlertType, AlertStatus, PerformanceMetricType, PerformancePeriod ) # ===== Base Schemas ===== class PerformanceMetricBase(BaseModel): """Base schema for performance metrics""" metric_type: PerformanceMetricType period: PerformancePeriod period_start: datetime period_end: datetime metric_value: float = Field(ge=0, le=100) target_value: Optional[float] = None total_orders: int = Field(ge=0, default=0) total_deliveries: int = Field(ge=0, default=0) on_time_deliveries: int = Field(ge=0, default=0) late_deliveries: int = Field(ge=0, default=0) quality_issues: int = Field(ge=0, default=0) total_amount: Decimal = Field(ge=0, default=0) notes: Optional[str] = None class PerformanceMetricCreate(PerformanceMetricBase): """Schema for creating performance metrics""" supplier_id: UUID metrics_data: Optional[Dict[str, Any]] = None external_factors: Optional[Dict[str, Any]] = None class PerformanceMetricUpdate(BaseModel): """Schema for updating performance metrics""" metric_value: Optional[float] = Field(None, ge=0, le=100) target_value: Optional[float] = None notes: Optional[str] = None metrics_data: Optional[Dict[str, Any]] = None external_factors: Optional[Dict[str, Any]] = None class PerformanceMetric(PerformanceMetricBase): """Complete performance metric schema""" id: UUID tenant_id: UUID supplier_id: UUID previous_value: Optional[float] = None trend_direction: Optional[str] = None trend_percentage: Optional[float] = None metrics_data: Optional[Dict[str, Any]] = None external_factors: Optional[Dict[str, Any]] = None calculated_at: datetime class Config: orm_mode = True # ===== Alert Schemas ===== class AlertBase(BaseModel): """Base schema for alerts""" alert_type: AlertType severity: AlertSeverity title: str = Field(max_length=255) message: str description: Optional[str] = None trigger_value: Optional[float] = None threshold_value: Optional[float] = None metric_type: Optional[PerformanceMetricType] = None recommended_actions: Optional[List[Dict[str, Any]]] = None auto_resolve: bool = False class AlertCreate(AlertBase): """Schema for creating alerts""" supplier_id: UUID purchase_order_id: Optional[UUID] = None delivery_id: Optional[UUID] = None performance_metric_id: Optional[UUID] = None priority_score: int = Field(ge=1, le=100, default=50) business_impact: Optional[str] = None tags: Optional[List[str]] = None class AlertUpdate(BaseModel): """Schema for updating alerts""" status: Optional[AlertStatus] = None actions_taken: Optional[List[Dict[str, Any]]] = None resolution_notes: Optional[str] = None escalated: Optional[bool] = None class Alert(AlertBase): """Complete alert schema""" id: UUID tenant_id: UUID supplier_id: UUID status: AlertStatus purchase_order_id: Optional[UUID] = None delivery_id: Optional[UUID] = None performance_metric_id: Optional[UUID] = None triggered_at: datetime acknowledged_at: Optional[datetime] = None acknowledged_by: Optional[UUID] = None resolved_at: Optional[datetime] = None resolved_by: Optional[UUID] = None actions_taken: Optional[List[Dict[str, Any]]] = None resolution_notes: Optional[str] = None escalated: bool = False escalated_at: Optional[datetime] = None notification_sent: bool = False priority_score: int business_impact: Optional[str] = None tags: Optional[List[str]] = None created_at: datetime class Config: orm_mode = True # ===== Scorecard Schemas ===== class ScorecardBase(BaseModel): """Base schema for supplier scorecards""" scorecard_name: str = Field(max_length=255) period: PerformancePeriod period_start: datetime period_end: datetime overall_score: float = Field(ge=0, le=100) quality_score: float = Field(ge=0, le=100) delivery_score: float = Field(ge=0, le=100) cost_score: float = Field(ge=0, le=100) service_score: float = Field(ge=0, le=100) on_time_delivery_rate: float = Field(ge=0, le=100) quality_rejection_rate: float = Field(ge=0, le=100) order_accuracy_rate: float = Field(ge=0, le=100) response_time_hours: float = Field(ge=0) cost_variance_percentage: float total_orders_processed: int = Field(ge=0, default=0) total_amount_processed: Decimal = Field(ge=0, default=0) average_order_value: Decimal = Field(ge=0, default=0) cost_savings_achieved: Decimal = Field(default=0) class ScorecardCreate(ScorecardBase): """Schema for creating scorecards""" supplier_id: UUID strengths: Optional[List[str]] = None improvement_areas: Optional[List[str]] = None recommended_actions: Optional[List[Dict[str, Any]]] = None notes: Optional[str] = None class ScorecardUpdate(BaseModel): """Schema for updating scorecards""" overall_score: Optional[float] = Field(None, ge=0, le=100) quality_score: Optional[float] = Field(None, ge=0, le=100) delivery_score: Optional[float] = Field(None, ge=0, le=100) cost_score: Optional[float] = Field(None, ge=0, le=100) service_score: Optional[float] = Field(None, ge=0, le=100) strengths: Optional[List[str]] = None improvement_areas: Optional[List[str]] = None recommended_actions: Optional[List[Dict[str, Any]]] = None notes: Optional[str] = None is_final: Optional[bool] = None class Scorecard(ScorecardBase): """Complete scorecard schema""" id: UUID tenant_id: UUID supplier_id: UUID overall_rank: Optional[int] = None category_rank: Optional[int] = None total_suppliers_evaluated: Optional[int] = None score_trend: Optional[str] = None score_change_percentage: Optional[float] = None strengths: Optional[List[str]] = None improvement_areas: Optional[List[str]] = None recommended_actions: Optional[List[Dict[str, Any]]] = None is_final: bool = False approved_by: Optional[UUID] = None approved_at: Optional[datetime] = None notes: Optional[str] = None attachments: Optional[List[Dict[str, Any]]] = None generated_at: datetime generated_by: UUID class Config: orm_mode = True # ===== Dashboard Schemas ===== class PerformanceDashboardSummary(BaseModel): """Performance dashboard summary schema""" total_suppliers: int active_suppliers: int suppliers_above_threshold: int suppliers_below_threshold: int average_overall_score: float average_delivery_rate: float average_quality_rate: float total_active_alerts: int critical_alerts: int high_priority_alerts: int recent_scorecards_generated: int cost_savings_this_month: Decimal # Performance trends performance_trend: str # improving, declining, stable delivery_trend: str quality_trend: str # Business model insights detected_business_model: str # individual_bakery, central_bakery, hybrid model_confidence: float business_model_metrics: Dict[str, Any] class SupplierPerformanceInsights(BaseModel): """Supplier performance insights schema""" supplier_id: UUID supplier_name: str current_overall_score: float previous_score: Optional[float] = None score_change_percentage: Optional[float] = None performance_rank: Optional[int] = None # Key performance indicators delivery_performance: float quality_performance: float cost_performance: float service_performance: float # Recent metrics orders_last_30_days: int average_delivery_time: float quality_issues_count: int cost_variance: float # Alert summary active_alerts: int resolved_alerts_last_30_days: int alert_trend: str # Performance categorization performance_category: str # excellent, good, acceptable, needs_improvement, poor risk_level: str # low, medium, high, critical # Recommendations top_strengths: List[str] improvement_priorities: List[str] recommended_actions: List[Dict[str, Any]] class PerformanceAnalytics(BaseModel): """Advanced performance analytics schema""" period_start: datetime period_end: datetime total_suppliers_analyzed: int # Performance distribution performance_distribution: Dict[str, int] # excellent, good, etc. score_ranges: Dict[str, List[float]] # min, max, avg per range # Trend analysis overall_trend: Dict[str, float] # month-over-month changes delivery_trends: Dict[str, float] quality_trends: Dict[str, float] cost_trends: Dict[str, float] # Comparative analysis top_performers: List[SupplierPerformanceInsights] underperformers: List[SupplierPerformanceInsights] most_improved: List[SupplierPerformanceInsights] biggest_declines: List[SupplierPerformanceInsights] # Risk analysis high_risk_suppliers: List[Dict[str, Any]] contract_renewals_due: List[Dict[str, Any]] certification_expiries: List[Dict[str, Any]] # Financial impact total_procurement_value: Decimal cost_savings_achieved: Decimal cost_avoidance: Decimal financial_risk_exposure: Decimal class AlertSummary(BaseModel): """Alert summary schema""" alert_type: AlertType severity: AlertSeverity count: int avg_resolution_time_hours: Optional[float] = None oldest_alert_age_hours: Optional[float] = None trend_percentage: Optional[float] = None class DashboardFilter(BaseModel): """Dashboard filter schema""" supplier_ids: Optional[List[UUID]] = None supplier_categories: Optional[List[str]] = None performance_categories: Optional[List[str]] = None date_from: Optional[datetime] = None date_to: Optional[datetime] = None include_inactive: bool = False class AlertFilter(BaseModel): """Alert filter schema""" alert_types: Optional[List[AlertType]] = None severities: Optional[List[AlertSeverity]] = None statuses: Optional[List[AlertStatus]] = None supplier_ids: Optional[List[UUID]] = None date_from: Optional[datetime] = None date_to: Optional[datetime] = None metric_types: Optional[List[PerformanceMetricType]] = None # ===== Business Model Detection ===== class BusinessModelInsights(BaseModel): """Business model detection and insights schema""" detected_model: str # individual_bakery, central_bakery, hybrid confidence_score: float model_characteristics: Dict[str, Any] # Model-specific metrics supplier_diversity_score: float procurement_volume_patterns: Dict[str, Any] delivery_frequency_patterns: Dict[str, Any] order_size_patterns: Dict[str, Any] # Recommendations optimization_opportunities: List[Dict[str, Any]] recommended_supplier_mix: Dict[str, Any] cost_optimization_potential: Decimal risk_mitigation_suggestions: List[str] # Benchmarking industry_comparison: Dict[str, float] peer_comparison: Optional[Dict[str, float]] = None # ===== Export and Reporting ===== class PerformanceReportRequest(BaseModel): """Performance report generation request""" report_type: str # scorecard, analytics, alerts, comprehensive format: str = Field(pattern="^(pdf|excel|csv|json)$") period: PerformancePeriod date_from: datetime date_to: datetime supplier_ids: Optional[List[UUID]] = None include_charts: bool = True include_recommendations: bool = True include_benchmarks: bool = True custom_metrics: Optional[List[str]] = None class ExportDataResponse(BaseModel): """Export data response schema""" export_id: UUID format: str file_url: Optional[str] = None file_size_bytes: Optional[int] = None generated_at: datetime expires_at: datetime status: str # generating, ready, expired, failed error_message: Optional[str] = None