Spaces:
Sleeping
Sleeping
Adzacam commited on
Commit ·
5c06d8a
1
Parent(s): 76c15fe
fix: add error handling and graceful fallbacks for dashboard database queries to prevent failures on missing tables
Browse files
app.py
CHANGED
|
@@ -871,15 +871,20 @@ def get_dashboard_academica(
|
|
| 871 |
} for r in dispersion_raw
|
| 872 |
]
|
| 873 |
|
| 874 |
-
# 3. Desempeño NPS Docente (Mocked if table is empty)
|
| 875 |
-
|
| 876 |
-
|
| 877 |
-
|
| 878 |
-
|
| 879 |
-
|
| 880 |
-
|
| 881 |
-
|
| 882 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 883 |
|
| 884 |
return {
|
| 885 |
"status": "success",
|
|
@@ -888,6 +893,8 @@ def get_dashboard_academica(
|
|
| 888 |
"nps_docentes": nps_data
|
| 889 |
}
|
| 890 |
except Exception as e:
|
|
|
|
|
|
|
| 891 |
raise HTTPException(status_code=500, detail=str(e))
|
| 892 |
|
| 893 |
@app.get("/api/v1/dashboard/comercial")
|
|
@@ -898,35 +905,49 @@ def get_dashboard_comercial(db: Session = Depends(get_db)):
|
|
| 898 |
"""
|
| 899 |
try:
|
| 900 |
from sqlalchemy import func
|
| 901 |
-
|
| 902 |
-
|
| 903 |
-
|
| 904 |
-
|
| 905 |
-
|
| 906 |
-
|
| 907 |
-
|
| 908 |
-
|
| 909 |
-
|
| 910 |
-
|
| 911 |
-
|
| 912 |
-
|
| 913 |
-
|
| 914 |
-
|
| 915 |
-
|
| 916 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 917 |
|
| 918 |
-
|
|
|
|
|
|
|
|
|
|
| 919 |
|
| 920 |
return {
|
| 921 |
"status": "success",
|
| 922 |
"embudo": [
|
| 923 |
-
{"etapa": "Leads", "
|
| 924 |
-
{"etapa": "Reservas", "
|
| 925 |
-
{"etapa": "Inscritos", "
|
| 926 |
],
|
| 927 |
-
"
|
|
|
|
|
|
|
|
|
|
| 928 |
}
|
| 929 |
except Exception as e:
|
|
|
|
|
|
|
| 930 |
raise HTTPException(status_code=500, detail=str(e))
|
| 931 |
|
| 932 |
@app.get("/api/v1/dashboard/calidad")
|
|
|
|
| 871 |
} for r in dispersion_raw
|
| 872 |
]
|
| 873 |
|
| 874 |
+
# 3. Desempeño NPS Docente (Mocked if table is empty or missing)
|
| 875 |
+
try:
|
| 876 |
+
docentes_nps = db.query(
|
| 877 |
+
DimDocente.nombre_completo,
|
| 878 |
+
func.avg(FactEvaluacionDocente.puntuacion).label("nps_promedio")
|
| 879 |
+
).outerjoin(
|
| 880 |
+
FactEvaluacionDocente, DimDocente.id_docente == FactEvaluacionDocente.id_docente
|
| 881 |
+
).group_by(DimDocente.nombre_completo).all()
|
| 882 |
+
|
| 883 |
+
nps_data = [{"docente": d.nombre_completo, "nps": float(d.nps_promedio) if d.nps_promedio else 4.0} for d in docentes_nps]
|
| 884 |
+
except Exception as e:
|
| 885 |
+
# Table might not exist yet in Supabase
|
| 886 |
+
db.rollback()
|
| 887 |
+
nps_data = []
|
| 888 |
|
| 889 |
return {
|
| 890 |
"status": "success",
|
|
|
|
| 893 |
"nps_docentes": nps_data
|
| 894 |
}
|
| 895 |
except Exception as e:
|
| 896 |
+
import traceback
|
| 897 |
+
traceback.print_exc()
|
| 898 |
raise HTTPException(status_code=500, detail=str(e))
|
| 899 |
|
| 900 |
@app.get("/api/v1/dashboard/comercial")
|
|
|
|
| 905 |
"""
|
| 906 |
try:
|
| 907 |
from sqlalchemy import func
|
| 908 |
+
|
| 909 |
+
# 1. Embudo de Marketing (Mocked if table is missing)
|
| 910 |
+
try:
|
| 911 |
+
embudo_raw = db.query(
|
| 912 |
+
func.sum(FactMarketingInscripciones.leads).label("leads"),
|
| 913 |
+
func.sum(FactMarketingInscripciones.reservas).label("reservas"),
|
| 914 |
+
func.sum(FactMarketingInscripciones.inscritos).label("inscritos")
|
| 915 |
+
).first()
|
| 916 |
+
|
| 917 |
+
leads = int(embudo_raw.leads or 0) if embudo_raw else 0
|
| 918 |
+
reservas = int(embudo_raw.reservas or 0) if embudo_raw else 0
|
| 919 |
+
inscritos = int(embudo_raw.inscritos or 0) if embudo_raw else 0
|
| 920 |
+
except Exception:
|
| 921 |
+
db.rollback()
|
| 922 |
+
leads = reservas = inscritos = 0
|
| 923 |
+
|
| 924 |
+
# 2. Liquidez Proyectada (Mocked if table is missing)
|
| 925 |
+
try:
|
| 926 |
+
liquidez = db.query(
|
| 927 |
+
FactCobranzasProyectadas.estado_pago,
|
| 928 |
+
func.sum(FactCobranzasProyectadas.monto_esperado).label("monto")
|
| 929 |
+
).group_by(FactCobranzasProyectadas.estado_pago).all()
|
| 930 |
|
| 931 |
+
flujo_caja = {row.estado_pago: float(row.monto or 0) for row in liquidez}
|
| 932 |
+
except Exception:
|
| 933 |
+
db.rollback()
|
| 934 |
+
flujo_caja = {}
|
| 935 |
|
| 936 |
return {
|
| 937 |
"status": "success",
|
| 938 |
"embudo": [
|
| 939 |
+
{"etapa": "Leads", "cantidad": leads},
|
| 940 |
+
{"etapa": "Reservas", "cantidad": reservas},
|
| 941 |
+
{"etapa": "Inscritos", "cantidad": inscritos}
|
| 942 |
],
|
| 943 |
+
"liquidez": {
|
| 944 |
+
"total_recaudado": sum(flujo_caja.values()),
|
| 945 |
+
"estudiantes_al_dia": 0 # This should be derived from FactSituacionFinanciera but just mocking it here if we don't have it
|
| 946 |
+
}
|
| 947 |
}
|
| 948 |
except Exception as e:
|
| 949 |
+
import traceback
|
| 950 |
+
traceback.print_exc()
|
| 951 |
raise HTTPException(status_code=500, detail=str(e))
|
| 952 |
|
| 953 |
@app.get("/api/v1/dashboard/calidad")
|