""" Schemas Pydantic para Viaje y Parada. """ from datetime import datetime from typing import List, Optional from pydantic import Field from app.schemas.base import BaseSchema, TimestampSchema class ViajeBase(BaseSchema): """Schema base de viaje.""" vehiculo_id: int conductor_id: Optional[int] = None proposito: Optional[str] = Field(None, max_length=100) notas: Optional[str] = None class ViajeCreate(ViajeBase): """Schema para crear viaje manualmente.""" inicio_tiempo: datetime inicio_lat: float inicio_lng: float inicio_direccion: Optional[str] = None class ViajeUpdate(BaseSchema): """Schema para actualizar viaje.""" conductor_id: Optional[int] = None proposito: Optional[str] = Field(None, max_length=100) notas: Optional[str] = None estado: Optional[str] = Field(None, pattern="^(en_curso|completado|cancelado)$") class ViajeResponse(ViajeBase, TimestampSchema): """Schema de respuesta de viaje.""" id: int inicio_tiempo: datetime fin_tiempo: Optional[datetime] = None inicio_lat: float inicio_lng: float inicio_direccion: Optional[str] = None fin_lat: Optional[float] = None fin_lng: Optional[float] = None fin_direccion: Optional[str] = None distancia_km: Optional[float] = None duracion_segundos: Optional[int] = None tiempo_movimiento_segundos: Optional[int] = None tiempo_parado_segundos: Optional[int] = None velocidad_promedio: Optional[float] = None velocidad_maxima: Optional[float] = None combustible_usado: Optional[float] = None rendimiento: Optional[float] = None odometro_inicio: Optional[float] = None odometro_fin: Optional[float] = None estado: str puntos_gps: int # Calculados duracion_formateada: str en_curso: bool class ViajeResumen(BaseSchema): """Schema resumido de viaje para listas.""" id: int vehiculo_id: int vehiculo_nombre: Optional[str] = None vehiculo_placa: Optional[str] = None conductor_nombre: Optional[str] = None inicio_tiempo: datetime fin_tiempo: Optional[datetime] = None inicio_direccion: Optional[str] = None fin_direccion: Optional[str] = None distancia_km: Optional[float] = None duracion_formateada: str estado: str class ViajeConParadas(ViajeResponse): """Schema de viaje con lista de paradas.""" paradas: List["ParadaResponse"] = [] class ViajeReplayData(BaseSchema): """Schema para datos de replay de viaje.""" viaje: ViajeResponse ubicaciones: List["UbicacionResponse"] paradas: List["ParadaResponse"] # ============================================================================ # Schemas de Parada # ============================================================================ class ParadaBase(BaseSchema): """Schema base de parada.""" lat: float = Field(..., ge=-90, le=90) lng: float = Field(..., ge=-180, le=180) tipo: str = Field(default="desconocido", max_length=50) notas: Optional[str] = None class ParadaCreate(ParadaBase): """Schema para crear parada manualmente.""" viaje_id: Optional[int] = None vehiculo_id: int inicio_tiempo: datetime fin_tiempo: Optional[datetime] = None direccion: Optional[str] = Field(None, max_length=255) motor_apagado: Optional[bool] = None class ParadaUpdate(BaseSchema): """Schema para actualizar parada.""" tipo: Optional[str] = Field(None, max_length=50) direccion: Optional[str] = Field(None, max_length=255) notas: Optional[str] = None motor_apagado: Optional[bool] = None class ParadaResponse(ParadaBase): """Schema de respuesta de parada.""" id: int viaje_id: Optional[int] = None vehiculo_id: int inicio_tiempo: datetime fin_tiempo: Optional[datetime] = None duracion_segundos: Optional[int] = None direccion: Optional[str] = None motor_apagado: Optional[bool] = None poi_id: Optional[int] = None geocerca_id: Optional[int] = None en_curso: bool # Calculado duracion_formateada: str class ParadaResumen(BaseSchema): """Schema resumido de parada.""" id: int vehiculo_id: int inicio_tiempo: datetime duracion_formateada: str tipo: str direccion: Optional[str] = None # Import fix from app.schemas.ubicacion import UbicacionResponse # noqa: E402 ViajeReplayData.model_rebuild()