""" 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 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_names = {t["name"] for t in existing.json().get("tables", [])} if "Meta Ads Campaigns" in existing_names or "MetaCampaignMes" in existing_names: print("Error: 'Meta Ads Campaigns' or 'MetaCampaignMes' already exist in this base. Aborting.") sys.exit(1) print(f"Creando tablas en la base {BASE_ID}...") 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}}, ]) 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} """)