leads-optimizer/backfill_leadform_jun8_10.py
José Manuel Gómez 4848253c49 Fix leadform double-attribution and Slack message truncation
- airtable_client: restrict leadform cursoid path (path 5) to PMX-only
  campaigns, preventing triple-attribution to search+pmx+leadform companion
- slack_reporter: derive margen from ingreso-coste instead of stale MetricasDiarias
  field; split monthly rankings from fields to separate section blocks; add
  _trunc() helper to clamp all text blocks under Slack's 3000-char limit
- agent: increase portfolio_daily_analysis max_tokens 500→800
- backfill: extend to June 11

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 23:04:40 +02:00

98 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Recalcula leads_lake en MetricasDiarias para días 8-10 de junio 2026
añadiendo la atribución de leadforms via cursoid + UserAgent.
También actualiza ConvLeadsLakeMes, Leads Lake y ConvLeadsLakeMesFinal.
"""
import json
import re
from datetime import datetime
from airtable_client import AirtableClient
DAYS = ["2026-06-08", "2026-06-09", "2026-06-10", "2026-06-11"]
def _course_num(name: str) -> str | None:
m = re.search(r'fco_(?:search|pmx)_(\d+)', name, re.IGNORECASE)
return m.group(1) if m else None
def run():
at = AirtableClient()
campaigns = at.get_active_gacampaignmes()
print(f"{len(campaigns)} campañas activas este mes\n")
# Mapping cursoid → PMX campaign_id para leadforms diarios
cursoid_to_campaign: dict[str, str] = {}
for c in campaigns:
num = _course_num(c["curso"])
if num and "pmx" in c["curso"].lower() and "_leadform" not in c["curso"].lower():
cursoid_to_campaign[num] = c["google_campaign_id"]
print(f"→ Mapping cursoid→campaign: {len(cursoid_to_campaign)} entradas")
# Obtener leads por campaña para cada día (una llamada bulk por día)
daily_counts: dict[str, dict[str, int]] = {}
for date_str in DAYS:
daily_counts[date_str] = at.get_leads_by_campaign_on_date(date_str, cursoid_to_campaign)
total = sum(daily_counts[date_str].values())
print(f" {date_str}: {total} leads totales encontrados")
print()
# Actualizar MetricasDiarias para cada campaña
metricas_updates = []
for campaign in campaigns:
cid = campaign["google_campaign_id"]
try:
md = json.loads(campaign["metricas_diarias"])
except (json.JSONDecodeError, TypeError):
md = {}
changed = False
for date_str in DAYS:
day_key = date_str[8:10]
if day_key not in md:
continue
new_count = daily_counts[date_str].get(cid, 0)
old_count = md[day_key].get("leads_lake", 0)
if old_count != new_count:
print(f" {campaign['curso'][:45]} día {day_key}: leads_lake {old_count}{new_count}")
md[day_key]["leads_lake"] = new_count
# Recalcular ingreso_lxp para el día (leads_lake × PPL)
md[day_key]["ingreso"] = round(new_count * campaign["ppl"], 2)
changed = True
if changed:
metricas_updates.append({
"airtable_id": campaign["airtable_id"],
"metricas_json": json.dumps(md, ensure_ascii=False),
})
if metricas_updates:
print(f"\n→ Actualizando MetricasDiarias ({len(metricas_updates)} registros)...")
at.batch_update_metricas_diarias(metricas_updates)
print(" ✓ MetricasDiarias actualizado.")
else:
print(" ✓ MetricasDiarias sin cambios.")
# Recalcular totales mensuales con la nueva atribución
print("\n→ Recalculando totales mensuales (leads_lake acumulado del mes)...")
final_leads_data = []
for campaign in campaigns:
cid = campaign["google_campaign_id"]
leads, lead_ids = at.get_leads_this_month_gads(cid, campaign["curso"])
at.update_gacampaignmes_leads_lake(campaign["airtable_id"], lead_ids)
final_leads_data.append({
"airtable_id": campaign["airtable_id"],
"conv_leads_lake_mes": leads,
"conv_leads_lake_mes_grupo": leads,
})
if leads > 0:
print(f" {campaign['curso'][:45]}: {leads} leads")
at.batch_update_gacampaignmes_final_leads(final_leads_data)
print(" ✓ ConvLeadsLakeMesFinal actualizado.")
if __name__ == "__main__":
run()