FlotillasGPS - Sistema completo de monitoreo de flotillas GPS
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.
This commit is contained in:
130
backend/app/models/vehiculo.py
Normal file
130
backend/app/models/vehiculo.py
Normal file
@@ -0,0 +1,130 @@
|
||||
"""
|
||||
Modelo de Vehículo para gestión de la flota.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import (
|
||||
Boolean,
|
||||
DateTime,
|
||||
Float,
|
||||
ForeignKey,
|
||||
Integer,
|
||||
String,
|
||||
Text,
|
||||
)
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.core.database import Base
|
||||
from app.models.base import TimestampMixin
|
||||
|
||||
|
||||
class Vehiculo(Base, TimestampMixin):
|
||||
"""Modelo de vehículo de la flota."""
|
||||
|
||||
__tablename__ = "vehiculos"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
|
||||
# Identificación
|
||||
nombre: Mapped[str] = mapped_column(String(100), nullable=False)
|
||||
placa: Mapped[str] = mapped_column(String(20), unique=True, nullable=False, index=True)
|
||||
vin: Mapped[str | None] = mapped_column(String(17), unique=True, nullable=True) # Vehicle Identification Number
|
||||
numero_economico: Mapped[str | None] = mapped_column(String(50), nullable=True) # Número interno
|
||||
|
||||
# Características del vehículo
|
||||
marca: Mapped[str | None] = mapped_column(String(50), nullable=True)
|
||||
modelo: Mapped[str | None] = mapped_column(String(50), nullable=True)
|
||||
año: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
color: Mapped[str | None] = mapped_column(String(30), nullable=True)
|
||||
tipo: Mapped[str | None] = mapped_column(String(50), nullable=True) # Sedan, SUV, Camión, etc.
|
||||
|
||||
# Capacidades
|
||||
capacidad_carga_kg: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
capacidad_pasajeros: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
capacidad_combustible_litros: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
tipo_combustible: Mapped[str | None] = mapped_column(String(20), nullable=True) # Gasolina, Diesel, Eléctrico
|
||||
|
||||
# Odómetro
|
||||
odometro_inicial: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
|
||||
odometro_actual: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
|
||||
|
||||
# Visualización
|
||||
icono: Mapped[str | None] = mapped_column(String(50), nullable=True) # Nombre del icono en el mapa
|
||||
color_marcador: Mapped[str] = mapped_column(String(7), default="#3B82F6", nullable=False) # Hex color
|
||||
|
||||
# Relaciones
|
||||
conductor_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey("conductores.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
grupo_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey("grupos_vehiculos.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
|
||||
# Estado
|
||||
activo: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
||||
en_servicio: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
||||
notas: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
|
||||
# Última ubicación conocida (para consultas rápidas)
|
||||
ultima_lat: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
ultima_lng: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
ultima_velocidad: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
ultimo_rumbo: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
ultima_ubicacion_tiempo: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
motor_encendido: Mapped[bool | None] = mapped_column(Boolean, nullable=True)
|
||||
|
||||
# Relaciones ORM
|
||||
conductor: Mapped["Conductor | None"] = relationship(
|
||||
"Conductor",
|
||||
back_populates="vehiculos",
|
||||
lazy="selectin",
|
||||
)
|
||||
grupo: Mapped["GrupoVehiculos | None"] = relationship(
|
||||
"GrupoVehiculos",
|
||||
back_populates="vehiculos",
|
||||
lazy="selectin",
|
||||
)
|
||||
dispositivos: Mapped[list["Dispositivo"]] = relationship(
|
||||
"Dispositivo",
|
||||
back_populates="vehiculo",
|
||||
lazy="selectin",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
viajes: Mapped[list["Viaje"]] = relationship(
|
||||
"Viaje",
|
||||
back_populates="vehiculo",
|
||||
lazy="dynamic",
|
||||
)
|
||||
alertas: Mapped[list["Alerta"]] = relationship(
|
||||
"Alerta",
|
||||
back_populates="vehiculo",
|
||||
lazy="dynamic",
|
||||
)
|
||||
cargas_combustible: Mapped[list["CargaCombustible"]] = relationship(
|
||||
"CargaCombustible",
|
||||
back_populates="vehiculo",
|
||||
lazy="dynamic",
|
||||
)
|
||||
mantenimientos: Mapped[list["Mantenimiento"]] = relationship(
|
||||
"Mantenimiento",
|
||||
back_populates="vehiculo",
|
||||
lazy="dynamic",
|
||||
)
|
||||
camaras: Mapped[list["Camara"]] = relationship(
|
||||
"Camara",
|
||||
back_populates="vehiculo",
|
||||
lazy="selectin",
|
||||
)
|
||||
|
||||
@property
|
||||
def distancia_recorrida(self) -> float:
|
||||
"""Calcula la distancia total recorrida."""
|
||||
return self.odometro_actual - self.odometro_inicial
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<Vehiculo(id={self.id}, placa='{self.placa}', nombre='{self.nombre}')>"
|
||||
Reference in New Issue
Block a user