leads-optimizer/airtable_client.py
Claude d68f9f5659
Sync Google Ads campaigns to Airtable before analysis
Before each run, fetch all non-removed campaigns from Google Ads
and upsert them into the Airtable campaigns table: new campaigns
are created (Activa=False, pending manual PPL/Cap/CPA setup) and
existing ones get their name updated if it changed.

https://claude.ai/code/session_01WEcdWPxGWZKk8FGwBRLGR2
2026-04-17 11:33:37 +00:00

82 lines
3.0 KiB
Python

from pyairtable import Api
from datetime import datetime
import config
class AirtableClient:
def __init__(self):
self.api = Api(config.AIRTABLE_TOKEN)
self.leads = self.api.table(config.AIRTABLE_BASE_ID, config.LEADS_TABLE)
self.campaigns = self.api.table(config.AIRTABLE_BASE_ID, config.CAMPAIGNS_TABLE)
def get_active_campaigns(self) -> list[dict]:
"""Lee todas las campañas activas desde 'Google Ads Campaigns'."""
records = self.campaigns.all(formula="{Activa}=TRUE()")
result = []
for r in records:
f = r["fields"]
result.append({
"airtable_id": r["id"],
"curso": f.get("Campaign Name", "Sin nombre"),
"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)),
})
return [c for c in result if c["google_campaign_id"]] # descartar sin ID
def sync_campaigns_from_google_ads(self, google_campaigns: list[dict]) -> dict:
"""
Sincroniza campañas de Google Ads → Airtable.
- Crea las campañas nuevas (Activa=False, requiere configuración manual de PPL/Cap/CPA).
- Actualiza el nombre si ha cambiado.
Devuelve un resumen con listas de campañas creadas y actualizadas.
"""
all_records = self.campaigns.all()
at_by_gid = {
str(r["fields"].get("CampaignID", "")).strip(): r
for r in all_records
if r["fields"].get("CampaignID")
}
created = []
updated = []
for gc in google_campaigns:
gid = gc["id"]
at_record = at_by_gid.get(gid)
if at_record is None:
self.campaigns.create({
"Campaign Name": gc["name"],
"CampaignID": int(gid),
"Activa": False,
})
created.append(gc["name"])
else:
changes = {}
if at_record["fields"].get("Campaign Name") != gc["name"]:
changes["Campaign Name"] = gc["name"]
if changes:
self.campaigns.update(at_record["id"], changes)
updated.append(gc["name"])
return {"created": created, "updated": updated}
def get_leads_this_month(self, google_campaign_id: 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.
"""
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")"
)
records = self.leads.all(formula=formula)
return len(records)