Co-authored-by: MENDOZA BALLARDO GAEL RICARDO <gael-meb123@users.noreply.github.com>

Co-authored-by: Azareth-Tr <Azareth-Tr@users.noreply.githu

b.com>

correcion de errores en llenado de tablas, primeras vistas frontend
This commit is contained in:
shinra32
2026-05-22 20:17:04 -06:00
parent fc28333e3f
commit 21a73162df
14 changed files with 600 additions and 95 deletions

View File

@@ -1,40 +1,54 @@
from fastapi import APIRouter, HTTPException
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException
from app.services import simulation
from app.core.deps import get_current_user
from app.core.supabase_client import supabase_admin
router = APIRouter()
router = APIRouter(tags=["eta"])
@router.get("/eta")
def get_eta(colonia: Optional[str] = None, routeId: Optional[str] = None):
# Resolver routeId a partir de colonia si es necesario
if routeId is None:
if colonia is None:
raise HTTPException(status_code=400, detail="colonia or routeId required")
mapping = simulation.get_colonias()
match = next((c for c in mapping if c.get("colonia","").lower() == colonia.lower()), None)
if not match:
raise HTTPException(status_code=404, detail="colonia not found")
routeId = match["routeId"]
def get_eta(
address_id: str,
current_user: dict = Depends(get_current_user),
):
"""
ETA para el ciudadano.
- Recibe `address_id` (domicilio del usuario autenticado).
- Valida que el domicilio pertenezca al usuario (túnel de privacidad).
- Devuelve SOLO texto: nunca coordenadas ni routeId completo.
"""
result = (
supabase_admin.table("addresses")
.select("route_id, user_id")
.eq("id", address_id)
.maybe_single()
.execute()
)
if not result.data:
raise HTTPException(status_code=404, detail="Domicilio no encontrado")
address = result.data
# Túnel: ciudadano solo puede consultar sus propios domicilios
if current_user["role"] != "admin" and address["user_id"] != current_user["user_id"]:
raise HTTPException(status_code=403, detail="No tienes acceso a este domicilio")
route_id = address["route_id"]
pos = simulation.get_route_position(route_id)
status = simulation.get_route_status(route_id)
pos = simulation.get_route_position(routeId)
status = simulation.get_route_status(routeId)
if pos is None:
raise HTTPException(status_code=404, detail="route not found")
raise HTTPException(status_code=503, detail="Simulación no disponible")
if pos < 4:
mensaje = "El camión va en camino a tu sector"
elif pos == 4:
mensaje = "Llega en aproximadamente 15 minutos"
mensaje = "Llega en aproximadamente 15 minutos — saca tus bolsas"
elif pos < 8:
mensaje = "Está atendiendo tu zona; saca tus bolsas"
mensaje = "Está atendiendo tu zona; prepara tus bolsas"
else:
mensaje = "Servicio del día finalizado"
mensaje = "Servicio del día finalizado. Mañana continuamos"
return {"mensaje": mensaje, "status": status, "routeId": routeId}
@router.post("/simulate/tick")
def simulate_tick():
events = simulation.tick()
return {"events": events}
# ⚠️ Nunca devolver coordenadas ni el routeId al ciudadano
return {"mensaje": mensaje, "status": status}

View File

@@ -0,0 +1,64 @@
from fastapi import APIRouter, Depends
from app.services import simulation
from app.core.deps import require_role
router = APIRouter(prefix="/simulation", tags=["simulation"])
# Solo admin puede ver el estado real de la simulación (incluye routeId y posición)
_require_admin = require_role("admin")
@router.get("/state")
def get_state(_: dict = Depends(_require_admin)):
"""
Estado actual de la simulación: positionId y status de cada ruta.
⚠️ No devuelve coordenadas — solo el índice (18) y el status de texto.
"""
colonias = simulation.get_colonias()
route_ids = {c["routeId"] for c in colonias}
state = []
for route_id in sorted(route_ids):
pos = simulation.get_route_position(route_id)
status = simulation.get_route_status(route_id)
# Derivar mensaje ETA sin coordenadas
if pos is None:
mensaje = "Ruta no cargada"
elif pos < 4:
mensaje = "En camino al sector"
elif pos == 4:
mensaje = "Llega en ~15 min"
elif pos < 8:
mensaje = "Atendiendo la zona"
else:
mensaje = "Servicio finalizado"
state.append({
"routeId": route_id,
"positionId": pos,
"status": status,
"etaMensaje": mensaje,
})
return {"routes": state, "totalRoutes": len(state)}
@router.post("/tick")
def manual_tick(_: dict = Depends(_require_admin)):
"""Avanza manualmente un tick en todas las rutas (útil para la demo)."""
events = simulation.tick()
return {"events": events, "total": len(events)}
@router.post("/reset")
def reset_simulation(_: dict = Depends(_require_admin)):
"""Reinicia todas las rutas a positionId=1 (para repetir la demo)."""
simulation.start_simulation_state()
return {"message": "Simulación reiniciada. Todas las rutas están en posición 1."}
@router.get("/events")
def get_events(_: dict = Depends(_require_admin)):
"""Últimos 20 eventos disparados por la simulación."""
return {"events": simulation.get_last_events()}