15 Commits

Author SHA1 Message Date
f6f897adeb Include campaign status in analysis and fix agent reactivation advice
- analyzer.py: add status_google (ENABLED/PAUSED) to analysis dict
- agent.py: instruct agent never to recommend reactivating an ENABLED campaign;
  mention reactivation in consejo only when campaign is PAUSED

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 13:01:41 +02:00
a5ce85ed32 Add GACampaignMes sync and use it as optimization source
- New GACampaignMes table tracks monthly state of campaigns with activity
  (ENABLED status or cost > 0 this month)
- sync_gacampaignmes(): creates/updates records with PPL, CPAMax, CosteMes,
  ConvMes, CapTotalMes, Status for current month (numeric Mes: 1-12)
- get_active_gacampaignmes(): reads GACampaignMes as source for optimization loop
- get_leads_this_month_gads(): filters leads by GoogleCampaignID + utm_source
  (pmx/google) + utm_medium (paid_search) instead of attr_cursoid
- update_gacampaignmes_leads_lake(): links leads to GACampaignMes Leads Lake field
- batch_update_gacampaignmes_consejos(): saves agent advice to Consejo field
- Google Ads Campaigns table simplified to catalog only (name, status, PPL)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 13:00:34 +02:00
7344cc0c52 Order campaign output by priority and add direct Google Ads links
- Campaigns now shown in three sections:
  1. ACCIONES CRÍTICAS (urgencia PAUSAR/SPRINT)
  2. ACCIONES NO CRÍTICAS (other budget changes)
  3. SIN CAMBIOS (MANTENER)
- First pass collects all data, then sorts before printing
- Each campaign shows direct Google Ads link with account ID
- Summary table also grouped by section with links

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 18:27:51 +02:00
b0f0ad394b Recalculate PPL weighted by centro invalidation rate and sync CapTotalMes from CursoMes
- PPL = sum(PPL_centrocurso × % invalidación_centro) for ABIERTO records
  (% invalidación stored as decimal 0-1, not percentage)
- CapTotalMes synced from CursoMes.Caping Admitido for current month/year
  (0 if no record found in CursoMes)
- Table reference fixed: CENTROCURSO → CentroCurso
- Added CursoMes table client in AirtableClient.__init__

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 16:41:48 +02:00
2191a498d7 Link Leads Lake records to campaign on each run
- get_leads_this_month() now returns (count, [record_ids])
- update_campaign_leads_lake() updates the multipleRecordLinks
  field 'Leads Lake' in Google Ads Campaigns with the lead IDs
  found for that course this month
- run.py calls the update after fetching leads per campaign

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 10:21:30 +02:00
ec3802eccf Auto-calculate PPL and CPAMax from CENTROCURSO on sync
- Add build_ppl_lookup(): loads Cursos + CENTROCURSO ABIERTO in 2
  bulk calls, returns {cursoid_text: sum_ppl} for all courses
- sync_campaigns_from_google_ads() now accepts ppl_lookup and
  updates PPL = sum(CENTROCURSO.PPL where Estado ROI=ABIERTO)
  and CPAMax = PPL * 70% for each campaign
- run.py builds the lookup before sync and passes it in

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 12:35:49 +02:00
952fabe4ca Sync ConvMes and CosteMes to Airtable on each run
- Add get_monthly_metrics_all() in GoogleAdsClient: fetches
  conversions and cost for all campaigns in one query
- sync_campaigns_from_google_ads() now accepts monthly_metrics
  and updates ConvMes and CosteMes fields in Airtable
- run.py fetches monthly metrics before sync and passes them

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 21:12:05 +02:00
e4362c6ad9 Add sync detail and per-campaign advice
- Sync shows campaign ID, name and status for new campaigns,
  and field-level changes (before/after) for updated ones
- Agent now returns a 'consejo' field with a specific actionable
  recommendation per campaign
- Summary table includes leads, margin and consejo per campaign

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 16:16:43 +02:00
2f88eb119d Add execution logging to logs/ directory
Each run saves a timestamped log file (logs/YYYYMMDD_HHMMSS.log)
with full output. logs/ is gitignored.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 16:13:43 +02:00
f954b7ee38 Fix encoding, batch sync and field mapping
- Force UTF-8 stdout with line buffering to fix Windows encoding error
- Use batch_create/batch_update in Airtable sync (10x faster)
- Fix CampaignID field type (string, not int)
- Fix FechaEntrada → Fecha in leads query

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 16:10:56 +02:00
ef7d494aeb
Merge pull request #1 from jmgomezroi/claude/help-project-setup-t4hyw
Claude/help project setup t4hyw
2026-04-17 14:02:45 +02:00
Claude
67d5104dca
Sync campaign Status from Google Ads (ENABLED→Activa, PAUSED→Pausada)
Both on create and update, mirror the real Google Ads status instead
of defaulting to Pausada.

https://claude.ai/code/session_01WEcdWPxGWZKk8FGwBRLGR2
2026-04-17 11:52:38 +00:00
Claude
905ad3bcd2
Align field names with actual Airtable schema
- Campaigns: Status='Activa' filter (was Activa=TRUE), CPAMax (was
  CPAMaximo), add MargenObjetivo and CursoID Text per campaign
- Leads: filter by attr_cursoid + creado (was GoogleCampaignID + Fecha)
- analyzer: expose margen_objetivo and margen_ok per campaign
- config: remove global MARGEN_MINIMO, now per-campaign via Airtable
- sync: new campaigns created with Status='Pausada'

https://claude.ai/code/session_01WEcdWPxGWZKk8FGwBRLGR2
2026-04-17 11:48:52 +00:00
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
f0d7f65c1a Initial commit 2026-04-17 12:53:25 +02:00