v1.7.0 - Fix: Corregido error 500 en SLA Dashboard
- Fix error de sintaxis SQL en cálculo de tickets 'at risk' - Fix error de timezone (offset-naive vs offset-aware datetimes) - Implementado sistema completo de SLA Management - Agregados endpoints: /sla/dashboard, /sla/violations, /sla/at-risk - Creadas vistas frontend para dashboard, violaciones y tickets en riesgo - Actualizado sistema de Celery para monitoreo automático de SLAs - Mejorada configuración de categorías con tiempos SLA personalizables - Corregidos problemas de proxy en configuración de Vite - Agregado troubleshooting guide en README Archivos principales modificados: - backend/app/api/v1/endpoints/sla.py (nuevo) - backend/app/api/schemas/sla.py (nuevo) - frontend-internal/src/routes/sla/ (nuevo módulo completo) - workers/app/tasks/sla_tasks.py (queries async mejoradas) Documentación: docs/changelog-2026-02-17.md
This commit is contained in:
253
backend/app/api/schemas/sla.py
Normal file
253
backend/app/api/schemas/sla.py
Normal file
@@ -0,0 +1,253 @@
|
||||
"""
|
||||
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]
|
||||
Reference in New Issue
Block a user