""" Modelo de Alerta para registrar eventos y notificaciones. """ from datetime import datetime from sqlalchemy import ( Boolean, DateTime, Float, ForeignKey, Index, String, Text, ) from sqlalchemy.orm import Mapped, mapped_column, relationship from app.core.database import Base from app.models.base import TimestampMixin class Alerta(Base, TimestampMixin): """Modelo de alerta/evento del sistema.""" __tablename__ = "alertas" id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) # Relaciones vehiculo_id: Mapped[int | None] = mapped_column( ForeignKey("vehiculos.id", ondelete="CASCADE"), nullable=True, index=True, ) conductor_id: Mapped[int | None] = mapped_column( ForeignKey("conductores.id", ondelete="SET NULL"), nullable=True, index=True, ) tipo_alerta_id: Mapped[int] = mapped_column( ForeignKey("tipos_alerta.id", ondelete="RESTRICT"), nullable=False, index=True, ) dispositivo_id: Mapped[int | None] = mapped_column( ForeignKey("dispositivos.id", ondelete="SET NULL"), nullable=True, ) # Severidad (puede sobrescribir la del tipo) severidad: Mapped[str] = mapped_column( String(20), default="media", nullable=False, ) # baja, media, alta, critica # Mensaje descriptivo mensaje: Mapped[str] = mapped_column(String(500), nullable=False) descripcion: Mapped[str | None] = mapped_column(Text, nullable=True) # Ubicación donde ocurrió lat: Mapped[float | None] = mapped_column(Float, nullable=True) lng: Mapped[float | None] = mapped_column(Float, nullable=True) direccion: Mapped[str | None] = mapped_column(String(255), nullable=True) # Datos adicionales velocidad: Mapped[float | None] = mapped_column(Float, nullable=True) valor: Mapped[float | None] = mapped_column(Float, nullable=True) # Valor que disparó la alerta umbral: Mapped[float | None] = mapped_column(Float, nullable=True) # Umbral configurado datos_extra: Mapped[str | None] = mapped_column(Text, nullable=True) # JSON con datos adicionales # Estado de atención atendida: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) atendida_por_id: Mapped[int | None] = mapped_column( ForeignKey("usuarios.id", ondelete="SET NULL"), nullable=True, ) atendida_en: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) notas_atencion: Mapped[str | None] = mapped_column(Text, nullable=True) # Notificaciones enviadas notificacion_email_enviada: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) notificacion_push_enviada: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) notificacion_sms_enviada: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) # Relaciones ORM vehiculo: Mapped["Vehiculo | None"] = relationship( "Vehiculo", back_populates="alertas", lazy="selectin", ) conductor: Mapped["Conductor | None"] = relationship( "Conductor", back_populates="alertas", lazy="selectin", ) tipo_alerta: Mapped["TipoAlerta"] = relationship( "TipoAlerta", back_populates="alertas", lazy="selectin", ) # Índices __table_args__ = ( Index("idx_alertas_vehiculo_creado", "vehiculo_id", "creado_en"), Index("idx_alertas_atendida", "atendida"), Index("idx_alertas_severidad", "severidad"), Index("idx_alertas_tipo_creado", "tipo_alerta_id", "creado_en"), ) @property def es_critica(self) -> bool: """Verifica si la alerta es crítica.""" return self.severidad == "critica" def __repr__(self) -> str: return f""