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:
108
backend/app/models/poi.py
Normal file
108
backend/app/models/poi.py
Normal file
@@ -0,0 +1,108 @@
|
||||
"""
|
||||
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"<POI(id={self.id}, nombre='{self.nombre}', categoria='{self.categoria}')>"
|
||||
|
||||
|
||||
# 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"},
|
||||
]
|
||||
Reference in New Issue
Block a user