Actualizar backend/main.py

This commit is contained in:
2026-09-22 10:47:28 -05:00
parent 981a606cce
commit 143932158d

View File

@@ -4,7 +4,7 @@ API REST del Dashboard — FastAPI.
Reutiliza la lógica de negocio existente en modules/ y core/. Reutiliza la lógica de negocio existente en modules/ y core/.
Cada endpoint devuelve JSON; el frontend (React) lo consume. Cada endpoint devuelve JSON; el frontend (React) lo consume.
""" """
from fastapi import FastAPI, Query, HTTPException from fastapi import FastAPI, Query, HTTPException, Body
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from datetime import datetime from datetime import datetime
import uvicorn import uvicorn
@@ -34,7 +34,7 @@ def _startup():
except Exception as e: except Exception as e:
print(f"[startup] Precarga falló: {e}") print(f"[startup] Precarga falló: {e}")
# Refresco cada 4 min en segundo plano (TTL del caché es 5 min) # Refresco cada 4 min en segundo plano (TTL del caché es 5 min)
start_background_refresh(services.refrescar_todo, interval=1800) start_background_refresh(services.refrescar_todo, interval=1800) # 30 min (con horario)
# Historial de estado de asesores: revisa Chatwoot cada 5 min y guarda los # Historial de estado de asesores: revisa Chatwoot cada 5 min y guarda los
# cambios (ON/OFF) en historial_estado_asesor. Solo entre 05:00 y 23:59. # cambios (ON/OFF) en historial_estado_asesor. Solo entre 05:00 y 23:59.
@@ -44,13 +44,28 @@ def _startup():
while True: while True:
try: try:
h = _dt.now().hour h = _dt.now().hour
if 5 <= h <= 23: if 5 <= h <= 23: # 05:00 a 23:59 (fuera de eso NO revisa)
services.registrar_estado_asesores() services.registrar_estado_asesores()
except Exception as e: except Exception as e:
print(f"[historial asesores loop] {e}") print(f"[historial asesores loop] {e}")
_t.sleep(300) _t.sleep(300) # 5 minutos
threading.Thread(target=_loop_asesores, daemon=True).start() threading.Thread(target=_loop_asesores, daemon=True).start()
# Auto-offline diario: 1 vez al día entre 05:00 y 06:00, desactiva el
# auto_offline de todos los asesores que lo tengan activado.
def _loop_auto_offline():
ultimo_dia = None
while True:
try:
ahora = _dt.now()
if 5 <= ahora.hour < 6 and ultimo_dia != ahora.date():
services.desactivar_auto_offline_todos()
ultimo_dia = ahora.date()
except Exception as e:
print(f"[auto_offline loop] {e}")
_t.sleep(300) # revisa cada 5 min si ya es la hora
threading.Thread(target=_loop_auto_offline, daemon=True).start()
# ── Salud / utilidades ───────────────────────────────────────────────────── # ── Salud / utilidades ─────────────────────────────────────────────────────
@app.get("/api/health") @app.get("/api/health")
@@ -140,9 +155,10 @@ def get_ventas_detalle(
tipo: str = Query("Venta Inscritos"), tipo: str = Query("Venta Inscritos"),
sede: str = Query("TODOS"), sede: str = Query("TODOS"),
programa: str = Query("TODOS"), programa: str = Query("TODOS"),
excluir_ret: bool = Query(False),
): ):
try: try:
return services.ventas_detalle(vendedor, ano, mes, tipo, sede, programa) return services.ventas_detalle(vendedor, ano, mes, tipo, sede, programa, excluir_ret)
except Exception as e: except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
@@ -181,6 +197,36 @@ def get_cobranza_detalle(
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
# ── RETIROS ────────────────────────────────────────────────────────────────
@app.get("/api/retiros")
def get_retiros(ano: int = Query(2026), mes: int = Query(8)):
try:
return services.retiros(ano, mes)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/retiros/info/guardar")
def post_retiros_info(payload: dict = Body(...)):
try:
mat = payload.get("matricula", "")
ano = payload.get("ano")
mes = payload.get("mes")
campos = {k: v for k, v in payload.items()
if k not in ("matricula", "ano", "mes", "usuario")}
return services.retiros_info_guardar(mat, ano, mes, campos, payload.get("usuario"))
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/retiros/snapshot/guardar")
def post_retiros_snapshot(payload: dict = Body(...)):
try:
return services.retiros_snapshot_guardar(
payload.get("ano"), payload.get("mes"),
payload.get("filas", []), payload.get("usuario"))
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# ── RENTABILIDAD ─────────────────────────────────────────────────────────── # ── RENTABILIDAD ───────────────────────────────────────────────────────────
@app.get("/api/rentabilidad") @app.get("/api/rentabilidad")
def get_rentabilidad( def get_rentabilidad(
@@ -317,36 +363,6 @@ def get_cobranza_detalle_todos(ano: int, mes: int, sectorista: str = "TODOS"):
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
# ── RETIROS ────────────────────────────────────────────────────────────────
@app.get("/api/retiros")
def get_retiros(ano: int = Query(2026), mes: int = Query(8)):
try:
return services.retiros(ano, mes)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/retiros/info/guardar")
def post_retiros_info(payload: dict = Body(...)):
try:
mat = payload.get("matricula", "")
ano = payload.get("ano")
mes = payload.get("mes")
campos = {k: v for k, v in payload.items()
if k not in ("matricula", "ano", "mes", "usuario")}
return services.retiros_info_guardar(mat, ano, mes, campos, payload.get("usuario"))
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/retiros/snapshot/guardar")
def post_retiros_snapshot(payload: dict = Body(...)):
try:
return services.retiros_snapshot_guardar(
payload.get("ano"), payload.get("mes"),
payload.get("filas", []), payload.get("usuario"))
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# ── USUARIOS ─────────────────────────────────────────────────────────────── # ── USUARIOS ───────────────────────────────────────────────────────────────
@app.get("/api/alumno/estado") @app.get("/api/alumno/estado")
def get_alumno_estado(matricula: str, ano: int = Query(...), mes: int = Query(...)): def get_alumno_estado(matricula: str, ano: int = Query(...), mes: int = Query(...)):
@@ -567,7 +583,6 @@ def set_asesor_estado(agent_id: int = Query(...), online: bool = Query(...)):
except Exception as e: except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/asesores/historial") @app.get("/api/asesores/historial")
def get_asesor_historial(email: str = Query(...)): def get_asesor_historial(email: str = Query(...)):
try: try: