diff --git a/airtable_client.py b/airtable_client.py index d8ef43d..d37f219 100644 --- a/airtable_client.py +++ b/airtable_client.py @@ -11,17 +11,19 @@ class AirtableClient: def get_active_campaigns(self) -> list[dict]: """Lee todas las campañas activas desde 'Google Ads Campaigns'.""" - records = self.campaigns.all(formula="{Activa}=TRUE()") + records = self.campaigns.all(formula="{Status}='Activa'") result = [] for r in records: f = r["fields"] result.append({ "airtable_id": r["id"], "curso": f.get("Campaign Name", "Sin nombre"), + "cursoid_text": str(f.get("CursoID Text", "")).strip(), "google_campaign_id": str(f.get("CampaignID", "")).strip(), "ppl": float(f.get("PPL", 0)), "capping_mensual": int(f.get("CapTotalMes", 0)), - "cpa_maximo": float(f.get("CPAMaximo", 0)), + "cpa_maximo": float(f.get("CPAMax", 0)), + "margen_objetivo": float(f.get("MargenObjetivo", 0)), }) return [c for c in result if c["google_campaign_id"]] # descartar sin ID @@ -50,7 +52,7 @@ class AirtableClient: self.campaigns.create({ "Campaign Name": gc["name"], "CampaignID": int(gid), - "Activa": False, + "Status": "Pausada", }) created.append(gc["name"]) else: @@ -63,18 +65,18 @@ class AirtableClient: return {"created": created, "updated": updated} - def get_leads_this_month(self, google_campaign_id: str) -> int: + def get_leads_this_month(self, cursoid_text: str) -> int: """ - Cuenta todos los leads del mes actual para una campaña. - Todos los leads en Airtable están validados, sin filtro de estado. + Cuenta todos los leads validados del mes actual para un curso. + Filtra por attr_cursoid (que coincide con CursoID Text de la campaña). """ now = datetime.now() mes_inicio = f"{now.year}-{now.month:02d}-01" formula = ( f"AND(" - f"{{GoogleCampaignID}}='{google_campaign_id}'," - f"{{Fecha}}>='{mes_inicio}'" + f"{{attr_cursoid}}='{cursoid_text}'," + f"{{creado}}>='{mes_inicio}'" f")" ) records = self.leads.all(formula=formula) diff --git a/analyzer.py b/analyzer.py index 32f036d..247d203 100644 --- a/analyzer.py +++ b/analyzer.py @@ -11,6 +11,7 @@ def analyze(campaign_config: dict, leads_entregados: int, ads_metrics: dict) -> capping = campaign_config["capping_mensual"] ppl = campaign_config["ppl"] cpa_max = campaign_config["cpa_maximo"] + margen_objetivo = campaign_config.get("margen_objetivo", 0) gasto = ads_metrics.get("cost", 0) conversiones_google = ads_metrics.get("conversions", 0) @@ -42,6 +43,8 @@ def analyze(campaign_config: dict, leads_entregados: int, ads_metrics: dict) -> "campaign_id": campaign_config["google_campaign_id"], "ppl": ppl, "cpa_maximo": cpa_max, + "margen_objetivo": margen_objetivo, + "margen_ok": margen >= margen_objetivo if margen_objetivo > 0 else True, "capping": capping, "leads_entregados": leads_entregados, "leads_restantes": leads_restantes, diff --git a/config.py b/config.py index c189aa4..3cd5d81 100644 --- a/config.py +++ b/config.py @@ -20,5 +20,4 @@ GOOGLE_ADS_LOGIN_CUSTOMER_ID = os.environ["GOOGLE_ADS_LOGIN_CUSTOMER_ID"] ANTHROPIC_API_KEY = os.environ["ANTHROPIC_API_KEY"] # Operación -DRY_RUN = True # True = solo sugiere, no aplica cambios en Google Ads -MARGEN_MINIMO = 0.40 # 40% mínimo de margen sobre PPL +DRY_RUN = True # True = solo sugiere, no aplica cambios en Google Ads diff --git a/run.py b/run.py index e04b2e2..b135e78 100644 --- a/run.py +++ b/run.py @@ -53,7 +53,7 @@ def run(): print(f" Campaign ID: {cid} | PPL: {campaign['ppl']}€ | Cap: {campaign['capping_mensual']} leads") # 1. Leads reales desde Airtable - leads = at.get_leads_this_month(cid) + leads = at.get_leads_this_month(campaign["cursoid_text"]) # 2. Métricas de Google Ads metrics = gads.get_campaign_metrics(cid)