Windows console encoding crashed the script right after creating the first table; make it re-runnable by skipping tables that already exist instead of aborting entirely.
103 lines
4.0 KiB
Python
103 lines
4.0 KiB
Python
"""
|
|
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}
|
|
""")
|