""" One-time script: adds "Meta Ads Campaigns" and "MetaCampaignMes" tables to the EXISTING Airtable base shared with leads-optimizer (AIRTABLE_BASE_ID), next to "Google Ads Campaigns" / "GACampaignMes". ⚠️ This mutates a shared, already-in-production Airtable base used by leads-optimizer. Run it deliberately, not as part of routine deploys. Requires an Airtable Personal Access Token with the `schema.bases:write` scope over that base (AIRTABLE_TOKEN in .env). Usage: python setup_airtable_meta_tables.py """ import os import sys import requests from dotenv import load_dotenv sys.stdout.reconfigure(encoding="utf-8", errors="replace") load_dotenv() TOKEN = os.environ.get("AIRTABLE_TOKEN", "") BASE_ID = os.environ.get("AIRTABLE_BASE_ID", "") if not TOKEN or not BASE_ID: print("Error: AIRTABLE_TOKEN and AIRTABLE_BASE_ID must be set in your .env file.") sys.exit(1) HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"} META_URL = f"https://api.airtable.com/v0/meta/bases/{BASE_ID}/tables" def create_table(name: str, fields: list) -> dict: resp = requests.post(META_URL, headers=HEADERS, json={"name": name, "fields": fields}, timeout=15) if not resp.ok: print(f" API error {resp.status_code}: {resp.text[:500]}") resp.raise_for_status() data = resp.json() print(f" ✓ Table '{name}' created (id={data['id']})") return data existing = requests.get(META_URL, headers=HEADERS, timeout=15) existing.raise_for_status() existing_tables = {t["name"]: t for t in existing.json().get("tables", [])} print(f"Creando tablas en la base {BASE_ID}...") if "Meta Ads Campaigns" in existing_tables: campaigns_table = existing_tables["Meta Ads Campaigns"] print(f" = Table 'Meta Ads Campaigns' already exists (id={campaigns_table['id']}), skipping") else: campaigns_table = create_table("Meta Ads Campaigns", [ {"name": "Campaign Name", "type": "singleLineText"}, {"name": "CampaignID", "type": "singleLineText"}, {"name": "CursoID Text", "type": "singleLineText"}, { "name": "Status", "type": "singleSelect", "options": {"choices": [{"name": "Activa"}, {"name": "Pausada"}]}, }, {"name": "PPL", "type": "number", "options": {"precision": 2}}, ]) if "MetaCampaignMes" in existing_tables: print(f" = Table 'MetaCampaignMes' already exists (id={existing_tables['MetaCampaignMes']['id']}), skipping") print(""" """ + "="*55 + "\n Nada que hacer: ambas tablas ya existen.\n" + "="*55) sys.exit(0) metacampaignmes_table = create_table("MetaCampaignMes", [ {"name": "Mes", "type": "singleLineText"}, {"name": "Año", "type": "singleLineText"}, { "name": "CampaignID", "type": "multipleRecordLinks", "options": {"linkedTableId": campaigns_table["id"]}, }, {"name": "PPL", "type": "number", "options": {"precision": 2}}, {"name": "CPAMax", "type": "number", "options": {"precision": 2}}, {"name": "CapTotalMes", "type": "number", "options": {"precision": 0}}, {"name": "CosteMes", "type": "number", "options": {"precision": 2}}, {"name": "ConvMes", "type": "number", "options": {"precision": 2}}, { "name": "Status", "type": "singleSelect", "options": {"choices": [{"name": "Activa"}, {"name": "Pausada"}]}, }, {"name": "Consejo", "type": "multilineText"}, { "name": "Criticidad", "type": "singleSelect", "options": {"choices": [{"name": "Crítico"}, {"name": "Peligro"}, {"name": "Mantener"}]}, }, {"name": "Log", "type": "multilineText"}, {"name": "ConvLeadsLakeMesFinal", "type": "number", "options": {"precision": 0}}, ]) print(f""" {'='*55} Listo. En Airtable ya existen 'Meta Ads Campaigns' y 'MetaCampaignMes'. No hace falta añadir nada a .env: AIRTABLE_TOKEN / AIRTABLE_BASE_ID ya son los mismos que usa leads-optimizer. {'='*55} """)