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/.
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 datetime import datetime
import uvicorn
@@ -34,7 +34,7 @@ def _startup():
except Exception as e:
print(f"[startup] Precarga falló: {e}")
# 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
# cambios (ON/OFF) en historial_estado_asesor. Solo entre 05:00 y 23:59.
@@ -44,13 +44,28 @@ def _startup():
while True:
try:
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()
except Exception as e:
print(f"[historial asesores loop] {e}")
_t.sleep(300)
_t.sleep(300) # 5 minutos
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 ─────────────────────────────────────────────────────
@app.get("/api/health")
@@ -140,9 +155,10 @@ def get_ventas_detalle(
tipo: str = Query("Venta Inscritos"),
sede: str = Query("TODOS"),
programa: str = Query("TODOS"),
excluir_ret: bool = Query(False),
):
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:
raise HTTPException(status_code=500, detail=str(e))
@@ -181,6 +197,36 @@ def get_cobranza_detalle(
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 ───────────────────────────────────────────────────────────
@app.get("/api/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))
# ── 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 ───────────────────────────────────────────────────────────────
@app.get("/api/alumno/estado")
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:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/asesores/historial")
def get_asesor_historial(email: str = Query(...)):
try: