""" SLA Schemas - ServiceManagerWeb Schemas para el sistema de gestión de SLAs """ from pydantic import BaseModel, ConfigDict from typing import Optional, List, Dict, Any from datetime import datetime from enum import Enum import uuid class SLATypeEnum(str, Enum): """Tipos de SLA""" RESPONSE = "response" RESOLUTION = "resolution" class SLAStatusEnum(str, Enum): """Estados de cumplimiento SLA""" MET = "met" # Cumplido VIOLATED = "violated" # Violado AT_RISK = "at_risk" # En riesgo (80%+ del tiempo) PENDING = "pending" # Pendiente (ticket aún abierto) # =================================== # DASHBOARD SCHEMAS # =================================== class SLAComplianceMetrics(BaseModel): """Métricas de cumplimiento SLA""" target_hours: int met_count: int violated_count: int at_risk_count: int total_count: int compliance_percentage: float avg_time_hours: Optional[float] = None class SLADashboardResponse(BaseModel): """Response del dashboard principal de SLA""" tenant_id: uuid.UUID period_start: datetime period_end: datetime generated_at: datetime # Métricas generales response_sla: SLAComplianceMetrics resolution_sla: SLAComplianceMetrics # Contadores rápidos active_violations: int at_risk_tickets: int total_tickets_period: int # Breakdown por categoría (top 5) by_category: List[Dict[str, Any]] # Breakdown por prioridad by_priority: Dict[str, Dict[str, float]] # Tendencias (comparación con período anterior) trends: Dict[str, str] model_config = ConfigDict(from_attributes=True) # =================================== # VIOLATIONS SCHEMAS # =================================== class TicketBasicInfo(BaseModel): """Información básica del ticket""" id: uuid.UUID ticket_number: str subject: str priority: str status: str class UserBasicInfo(BaseModel): """Información básica del usuario""" id: uuid.UUID first_name: str last_name: str email: str class CategoryBasicInfo(BaseModel): """Información básica de categoría""" id: uuid.UUID name: str sla_response_hours: int sla_resolution_hours: int class SLAViolationResponse(BaseModel): """Detalle de una violación SLA""" ticket: TicketBasicInfo category: Optional[CategoryBasicInfo] = None created_by: UserBasicInfo assigned_to: Optional[UserBasicInfo] = None sla_type: SLATypeEnum sla_due_at: datetime violated_at: datetime hours_overdue: float # Contexto adicional first_response_at: Optional[datetime] = None resolved_at: Optional[datetime] = None model_config = ConfigDict(from_attributes=True) class SLAViolationsListResponse(BaseModel): """Lista paginada de violaciones""" violations: List[SLAViolationResponse] total: int page: int per_page: int total_pages: int # =================================== # TICKETS AT RISK # =================================== class SLATicketAtRisk(BaseModel): """Ticket que está en riesgo de violar SLA""" ticket: TicketBasicInfo category: Optional[CategoryBasicInfo] = None assigned_to: Optional[UserBasicInfo] = None sla_type: SLATypeEnum sla_due_at: datetime time_remaining_hours: float risk_percentage: float # 0-100, qué % del tiempo ha pasado model_config = ConfigDict(from_attributes=True) class SLAAtRiskListResponse(BaseModel): """Lista de tickets en riesgo""" tickets: List[SLATicketAtRisk] total: int # =================================== # METRICS & REPORTS SCHEMAS # =================================== class SLAMetricsByCategory(BaseModel): """Métricas SLA por categoría""" category_id: uuid.UUID category_name: str response_sla_compliance: float resolution_sla_compliance: float total_tickets: int response_violations: int resolution_violations: int avg_response_time_hours: Optional[float] avg_resolution_time_hours: Optional[float] class SLAMetricsByAgent(BaseModel): """Métricas SLA por agente""" agent_id: uuid.UUID agent_name: str tickets_assigned: int response_sla_met: int resolution_sla_met: int response_compliance: float resolution_compliance: float avg_response_time_hours: Optional[float] avg_resolution_time_hours: Optional[float] class SLAMetricsByPriority(BaseModel): """Métricas SLA por prioridad""" priority: str total_tickets: int response_sla_compliance: float resolution_sla_compliance: float avg_response_time_hours: Optional[float] avg_resolution_time_hours: Optional[float] class SLADetailedMetricsResponse(BaseModel): """Response de métricas detalladas""" tenant_id: uuid.UUID date_from: datetime date_to: datetime group_by: str # 'category', 'agent', 'priority' by_category: Optional[List[SLAMetricsByCategory]] = None by_agent: Optional[List[SLAMetricsByAgent]] = None by_priority: Optional[List[SLAMetricsByPriority]] = None generated_at: datetime model_config = ConfigDict(from_attributes=True) # =================================== # HISTORICAL TRENDS # =================================== class SLADailyTrend(BaseModel): """Tendencia diaria de SLA""" date: str # YYYY-MM-DD response_compliance: float resolution_compliance: float total_tickets: int violations: int class SLATrendsResponse(BaseModel): """Response de tendencias históricas""" tenant_id: uuid.UUID days: int daily_trends: List[SLADailyTrend] # Promedios del período avg_response_compliance: float avg_resolution_compliance: float total_tickets: int total_violations: int model_config = ConfigDict(from_attributes=True) # =================================== # CONFIGURATION # =================================== class SLAConfigByCategoryResponse(BaseModel): """Configuración SLA por categoría""" category_id: uuid.UUID category_name: str sla_response_hours: int sla_resolution_hours: int warning_threshold_percentage: int # % del tiempo para alertar is_active: bool class SLAConfigListResponse(BaseModel): """Lista de configuraciones SLA""" tenant_id: uuid.UUID categories: List[SLAConfigByCategoryResponse]