# export_roas_excel.py # Genera un Excel de la tabla "Inversión por Sede" (ROAS) con el filtro # Año=2026, Mes=Marzo (3), Día=TODOS — igual que el dashboard. # Columnas: Sede | Programa | Conjunto | Importe Gastado | Resultados # Usa la MISMA función roas_dashboard() del dashboard (no reinventa la logica). # Ejecutar en backend/: python export_roas_excel.py import services as S from openpyxl import Workbook from openpyxl.styles import Font, PatternFill, Alignment, Border, Side ANO, MES, DIA = "2026", "3", "TODOS" # Marzo 2026 data = S.roas_dashboard(ANO, MES, DIA) filas = data.get("filas", []) # ── Aplanar a filas: Sede / Programa / Conjunto / Importe / Resultados ── rows = [] for f in filas: sede = f.get("sede", "") # nivel sede (total de la sede) rows.append([sede, "", "", f.get("importe", 0), f.get("resultados", 0), "sede"]) for p in (f.get("programas") or []): prog = p.get("programa", "") # nivel programa (total del programa) rows.append([sede, prog, "", p.get("importe", 0), p.get("resultados", 0), "prog"]) for c in (p.get("conjuntos") or []): rows.append([sede, prog, c.get("conjunto", ""), c.get("importe", 0), c.get("resultados", 0), "conj"]) # ── Excel ── wb = Workbook() ws = wb.active ws.title = "ROAS Marzo 2026" azul = PatternFill("solid", fgColor="1E3A5F") blanco = Font(bold=True, color="FFFFFF") fill_sede = PatternFill("solid", fgColor="DBEAFE") fill_prog = PatternFill("solid", fgColor="F1F5F9") bord = Border(*(Side(style="thin", color="D0D7E2"),)*4) cen = Alignment(horizontal="center", vertical="center") izq = Alignment(horizontal="left", vertical="center") cab = ["Sede", "Programa", "Conjunto", "Importe Gastado", "Resultados"] for j, t in enumerate(cab, 1): c = ws.cell(1, j, t) c.fill = azul; c.font = blanco; c.alignment = cen; c.border = bord r = 2 for sede, prog, conj, imp, res, nivel in rows: ws.cell(r, 1, sede) ws.cell(r, 2, prog) ws.cell(r, 3, conj) ci = ws.cell(r, 4, round(float(imp or 0), 2)); ci.number_format = '"$"#,##0.00' cr = ws.cell(r, 5, int(res or 0)); cr.number_format = '#,##0' for j in range(1, 6): cell = ws.cell(r, j); cell.border = bord cell.alignment = izq if j <= 3 else cen if nivel == "sede": cell.fill = fill_sede; cell.font = Font(bold=True) elif nivel == "prog": cell.fill = fill_prog; cell.font = Font(bold=True, color="475569") r += 1 # anchos for col, w in zip("ABCDE", [16, 14, 46, 16, 14]): ws.column_dimensions[col].width = w ws.freeze_panes = "A2" out = "ROAS_Marzo_2026.xlsx" wb.save(out) print(f"\nOK -> {out}") print(f"Filas totales: {len(rows)} (sedes: {len(filas)})") print("Columnas: Sede | Programa | Conjunto | Importe Gastado | Resultados")