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
This commit is contained in:
Claude 2026-04-17 11:33:37 +00:00
parent f0d7f65c1a
commit d68f9f5659
No known key found for this signature in database
3 changed files with 80 additions and 0 deletions

View File

@ -25,6 +25,44 @@ class AirtableClient:
})
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.

View File

@ -15,6 +15,32 @@ class GoogleAdsClient:
})
self.customer_id = config.GOOGLE_ADS_LOGIN_CUSTOMER_ID
def get_all_campaigns(self) -> list[dict]:
"""Obtiene todas las campañas no eliminadas de la cuenta."""
ga_service = self.client.get_service("GoogleAdsService")
query = """
SELECT
campaign.id,
campaign.name,
campaign.status
FROM campaign
WHERE campaign.status != 'REMOVED'
ORDER BY campaign.name
"""
try:
response = ga_service.search(customer_id=self.customer_id, query=query)
return [
{
"id": str(row.campaign.id),
"name": row.campaign.name,
"status": row.campaign.status.name,
}
for row in response
]
except GoogleAdsException as e:
print(f" ❌ Error obteniendo campañas de Google Ads: {e}")
return []
def get_campaign_metrics(self, campaign_id: str) -> dict:
"""Métricas del mes en curso para una campaña concreta."""
ga_service = self.client.get_service("GoogleAdsService")

16
run.py
View File

@ -25,6 +25,22 @@ def run():
at = AirtableClient()
gads = GoogleAdsClient()
# Sincronizar catálogo de campañas desde Google Ads → Airtable
print("→ Sincronizando campañas desde Google Ads...")
google_campaigns = gads.get_all_campaigns()
sync_result = at.sync_campaigns_from_google_ads(google_campaigns)
if sync_result["created"]:
print(f" ✅ Campañas nuevas importadas ({len(sync_result['created'])}):")
for name in sync_result["created"]:
print(f" + {name}")
if sync_result["updated"]:
print(f" 🔄 Campañas con nombre actualizado ({len(sync_result['updated'])}):")
for name in sync_result["updated"]:
print(f" ~ {name}")
if not sync_result["created"] and not sync_result["updated"]:
print(" ✓ Sin cambios en el catálogo.")
print()
campaigns = at.get_active_campaigns()
print(f"{len(campaigns)} campañas activas encontradas\n")