""" Modelo de POI (Punto de Interés) para marcar ubicaciones importantes. """ from sqlalchemy import Boolean, Float, Index, String, Text from sqlalchemy.orm import Mapped, mapped_column from app.core.database import Base from app.models.base import TimestampMixin class POI(Base, TimestampMixin): """ Modelo de Punto de Interés. Representa ubicaciones importantes como clientes, proveedores, estaciones de servicio, talleres, etc. """ __tablename__ = "pois" id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) # Identificación nombre: Mapped[str] = mapped_column(String(100), nullable=False) descripcion: Mapped[str | None] = mapped_column(Text, nullable=True) # Categoría categoria: Mapped[str] = mapped_column( String(50), default="otro", nullable=False, ) # cliente, proveedor, gasolinera, taller, oficina, almacen, otro # Ubicación lat: Mapped[float] = mapped_column(Float, nullable=False) lng: Mapped[float] = mapped_column(Float, nullable=False) direccion: Mapped[str | None] = mapped_column(String(255), nullable=True) ciudad: Mapped[str | None] = mapped_column(String(100), nullable=True) estado: Mapped[str | None] = mapped_column(String(100), nullable=True) codigo_postal: Mapped[str | None] = mapped_column(String(10), nullable=True) # Radio de proximidad (para detectar llegadas) radio_metros: Mapped[float] = mapped_column(Float, default=100.0, nullable=False) # Contacto telefono: Mapped[str | None] = mapped_column(String(20), nullable=True) email: Mapped[str | None] = mapped_column(String(255), nullable=True) contacto_nombre: Mapped[str | None] = mapped_column(String(100), nullable=True) # Horario (JSON) # Formato: {"lunes": {"apertura": "09:00", "cierre": "18:00"}, ...} horario_json: Mapped[str | None] = mapped_column(Text, nullable=True) # Visualización icono: Mapped[str | None] = mapped_column(String(50), nullable=True) color: Mapped[str] = mapped_column(String(7), default="#10B981", nullable=False) # Código externo (para integración con otros sistemas) codigo_externo: Mapped[str | None] = mapped_column(String(50), nullable=True, index=True) # Estado activo: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) # Notas notas: Mapped[str | None] = mapped_column(Text, nullable=True) # Índices __table_args__ = ( Index("idx_pois_coords", "lat", "lng"), Index("idx_pois_categoria", "categoria"), Index("idx_pois_activo", "activo"), ) def to_geojson(self) -> dict: """Convierte el POI a formato GeoJSON.""" return { "type": "Feature", "geometry": { "type": "Point", "coordinates": [self.lng, self.lat], }, "properties": { "id": self.id, "nombre": self.nombre, "categoria": self.categoria, "direccion": self.direccion, "telefono": self.telefono, "icono": self.icono, "color": self.color, }, } def __repr__(self) -> str: return f"" # Categorías predefinidas de POIs CATEGORIAS_POI = [ {"codigo": "cliente", "nombre": "Cliente", "icono": "building", "color": "#3B82F6"}, {"codigo": "proveedor", "nombre": "Proveedor", "icono": "truck", "color": "#8B5CF6"}, {"codigo": "gasolinera", "nombre": "Gasolinera", "icono": "fuel", "color": "#F59E0B"}, {"codigo": "taller", "nombre": "Taller", "icono": "wrench", "color": "#6B7280"}, {"codigo": "oficina", "nombre": "Oficina", "icono": "briefcase", "color": "#10B981"}, {"codigo": "almacen", "nombre": "Almacén", "icono": "warehouse", "color": "#EC4899"}, {"codigo": "estacionamiento", "nombre": "Estacionamiento", "icono": "parking", "color": "#06B6D4"}, {"codigo": "otro", "nombre": "Otro", "icono": "map-pin", "color": "#6B7280"}, ]