Sistema completo para monitoreo y gestion de flotas de vehiculos con: - Backend FastAPI con PostgreSQL/TimescaleDB - Frontend React con TypeScript y TailwindCSS - App movil React Native con Expo - Soporte para dispositivos GPS, Meshtastic y celulares - Video streaming en vivo con MediaMTX - Geocercas, alertas, viajes y reportes - Autenticacion JWT y WebSockets en tiempo real Documentacion completa y guias de usuario incluidas.
169 lines
4.3 KiB
Python
169 lines
4.3 KiB
Python
"""
|
|
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()
|