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:
FlotillasGPS Developer
2026-01-21 08:18:00 +00:00
commit 51d78bacf4
248 changed files with 50171 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
"""
Modelo de Conductor para gestión de operadores de vehículos.
"""
from datetime import date, datetime
from sqlalchemy import Boolean, Date, DateTime, String, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.core.database import Base
from app.models.base import TimestampMixin
class Conductor(Base, TimestampMixin):
"""Modelo de conductor/operador de vehículo."""
__tablename__ = "conductores"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
nombre: Mapped[str] = mapped_column(String(100), nullable=False)
apellido: Mapped[str] = mapped_column(String(100), nullable=False)
telefono: Mapped[str | None] = mapped_column(String(20), nullable=True)
email: Mapped[str | None] = mapped_column(String(255), nullable=True, index=True)
# Documento de identidad
documento_tipo: Mapped[str | None] = mapped_column(String(20), nullable=True) # DNI, INE, etc.
documento_numero: Mapped[str | None] = mapped_column(String(50), nullable=True)
# Licencia de conducir
licencia_numero: Mapped[str | None] = mapped_column(String(50), nullable=True, unique=True)
licencia_tipo: Mapped[str | None] = mapped_column(String(20), nullable=True) # A, B, C, D, E
licencia_vencimiento: Mapped[date | None] = mapped_column(Date, nullable=True)
# Información personal
foto_url: Mapped[str | None] = mapped_column(Text, nullable=True)
fecha_nacimiento: Mapped[date | None] = mapped_column(Date, nullable=True)
direccion: Mapped[str | None] = mapped_column(Text, nullable=True)
contacto_emergencia: Mapped[str | None] = mapped_column(String(100), nullable=True)
telefono_emergencia: Mapped[str | None] = mapped_column(String(20), nullable=True)
# Información laboral
fecha_contratacion: Mapped[date | None] = mapped_column(Date, nullable=True)
numero_empleado: Mapped[str | None] = mapped_column(String(50), nullable=True)
# Estado
activo: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
notas: Mapped[str | None] = mapped_column(Text, nullable=True)
# Relaciones
vehiculos: Mapped[list["Vehiculo"]] = relationship(
"Vehiculo",
back_populates="conductor",
lazy="selectin",
)
viajes: Mapped[list["Viaje"]] = relationship(
"Viaje",
back_populates="conductor",
lazy="dynamic",
)
alertas: Mapped[list["Alerta"]] = relationship(
"Alerta",
back_populates="conductor",
lazy="dynamic",
)
cargas_combustible: Mapped[list["CargaCombustible"]] = relationship(
"CargaCombustible",
back_populates="conductor",
lazy="dynamic",
)
mensajes: Mapped[list["Mensaje"]] = relationship(
"Mensaje",
back_populates="conductor",
lazy="dynamic",
)
@property
def nombre_completo(self) -> str:
"""Retorna el nombre completo del conductor."""
return f"{self.nombre} {self.apellido}"
@property
def licencia_vigente(self) -> bool:
"""Verifica si la licencia está vigente."""
if not self.licencia_vencimiento:
return False
return self.licencia_vencimiento >= date.today()
def __repr__(self) -> str:
return f"<Conductor(id={self.id}, nombre='{self.nombre_completo}')>"