From ff3aafe82a9c7dd171d3fc05c4b53f86fda78b62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20G=C3=B3mez?= Date: Sat, 13 Jun 2026 23:14:32 +0200 Subject: [PATCH] Add monthly margin breakdown by vertical to Slack summary table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Compute monthly_verticals in run.py and send_slack_report.py using per-vertical CPL targets - Display vertical breakdown (spend, leads, CPL, target, margin) inside the monthly table block - Add alarmas vertical (CPL target 8€) to Baserow Co-Authored-By: Claude Sonnet 4.6 --- run.py | 6 ++++++ send_slack_report.py | 6 ++++++ slack_notifier.py | 14 ++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/run.py b/run.py index 9412c95..abce877 100644 --- a/run.py +++ b/run.py @@ -120,6 +120,7 @@ def run(): print(f"→ Fetching monthly daily totals for {config.META_CAMPAIGN_PREFIX}...") daily_rows = meta.get_monthly_daily_totals() _daily: dict = {} + monthly_verticals: dict = {} for row in daily_rows: v = _extract_vertical(row["campaign_name"]) target = vertical_cpls.get(v, config.META_TARGET_CPL) @@ -128,6 +129,10 @@ def run(): d["spend"] += row["spend"] d["leads"] += row["leads"] d["margin"] += margin + mv = monthly_verticals.setdefault(v, {"spend": 0.0, "leads": 0, "margin": 0.0, "target_cpl": target}) + mv["spend"] += row["spend"] + mv["leads"] += row["leads"] + mv["margin"] += margin daily_totals = [ { "date": date, @@ -373,6 +378,7 @@ def run(): mode="DRY_RUN" if config.DRY_RUN else "PRODUCTION", verticals=verticals, campaign_details=campaign_details, + monthly_verticals=monthly_verticals, ) except Exception as e: print(f" Warning: Slack notification failed: {e}") diff --git a/send_slack_report.py b/send_slack_report.py index 56f59e6..618d8d2 100644 --- a/send_slack_report.py +++ b/send_slack_report.py @@ -40,6 +40,7 @@ def main(): print("Obteniendo datos mensuales de Meta...") daily_rows = meta.get_monthly_daily_totals() _daily: dict = {} + monthly_verticals: dict = {} for row in daily_rows: v = _extract_vertical(row["campaign_name"]) target = vertical_cpls.get(v, config.META_TARGET_CPL) @@ -51,6 +52,10 @@ def main(): d["spend"] += row["spend"] d["leads"] += row["leads"] d["margin"] += margin + mv = monthly_verticals.setdefault(v, {"spend": 0.0, "leads": 0, "margin": 0.0, "target_cpl": target}) + mv["spend"] += row["spend"] + mv["leads"] += row["leads"] + mv["margin"] += margin daily_totals = [ { "date": date, @@ -163,6 +168,7 @@ def main(): mode="DRY_RUN", verticals=verticals, campaign_details=campaign_details, + monthly_verticals=monthly_verticals, ) if ts: print(f" ✓ Mensaje enviado (ts={ts})") diff --git a/slack_notifier.py b/slack_notifier.py index 9fee718..46b6850 100644 --- a/slack_notifier.py +++ b/slack_notifier.py @@ -153,6 +153,7 @@ def send_daily_report( mode: str = "DRY_RUN", verticals: dict = None, campaign_details: dict = None, + monthly_verticals: dict = None, ) -> str | None: """Envía el informe diario consolidado. Devuelve el ts del mensaje.""" now = datetime.now() @@ -192,6 +193,19 @@ def send_daily_report( lines.append( f"{'TOTAL':<5} {total_spend:>6.0f}€ {int(total_leads):>5} {total_cpl:>6.2f}€ {m_tot_sign:>8}" ) + # Margen mensual por vertical + if monthly_verticals: + mv_lines = ["", f"{'Vertical':<16} {'Gasto':>7} {'Leads':>5} {'CPL':>7} {'Obj':>5} {'Margen':>8}"] + mv_lines.append("─" * 54) + for v, mv in sorted(monthly_verticals.items(), key=lambda x: -x[1]["margin"]): + v_cpl = round(mv["spend"] / mv["leads"], 2) if mv["leads"] > 0 else 0.0 + m_sign = f"+{mv['margin']:.0f}€" if mv["margin"] >= 0 else f"{mv['margin']:.0f}€" + obj = mv.get("target_cpl", 0) + mv_lines.append( + f"{v:<16} {mv['spend']:>6.0f}€ {mv['leads']:>5} {v_cpl:>6.2f}€ {obj:>4.1f}€ {m_sign:>8}" + ) + lines += mv_lines + blocks.append({ "type": "section", "text": {