""" 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""