Add PMX attribution detection and ConvLeadsLakeMesGrupo field
- Detect Search+PMX companion campaigns by course number - Add PMX attribution warning to Log field for Search campaigns with active PMX - Add ConvLeadsLakeMesGrupo: for PMX with Search companion uses Search leads count Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a1aef8f58e
commit
9edd74b9ad
@ -360,12 +360,18 @@ class AirtableClient:
|
|||||||
|
|
||||||
def batch_update_gacampaignmes_final_leads(self, gcm_records: list[dict]) -> None:
|
def batch_update_gacampaignmes_final_leads(self, gcm_records: list[dict]) -> None:
|
||||||
"""
|
"""
|
||||||
Copia ConvLeadsLakeMes → ConvLeadsLakeMesFinal en GACampaignMes.
|
Actualiza ConvLeadsLakeMesFinal y ConvLeadsLakeMesGrupo en GACampaignMes.
|
||||||
Se llama una vez por ejecución diaria.
|
gcm_records: lista de dicts con:
|
||||||
gcm_records: lista de dicts con 'airtable_id' y 'conv_leads_lake_mes'
|
- 'airtable_id'
|
||||||
|
- 'conv_leads_lake_mes' → valor para ConvLeadsLakeMesFinal
|
||||||
|
- 'conv_leads_lake_mes_grupo' → valor para ConvLeadsLakeMesGrupo
|
||||||
|
(igual al anterior salvo en PMX con Search companion: usa leads del Search)
|
||||||
"""
|
"""
|
||||||
batch = [
|
batch = [
|
||||||
{"id": r["airtable_id"], "fields": {"ConvLeadsLakeMesFinal": r["conv_leads_lake_mes"]}}
|
{"id": r["airtable_id"], "fields": {
|
||||||
|
"ConvLeadsLakeMesFinal": r["conv_leads_lake_mes"],
|
||||||
|
"ConvLeadsLakeMesGrupo": r["conv_leads_lake_mes_grupo"],
|
||||||
|
}}
|
||||||
for r in gcm_records
|
for r in gcm_records
|
||||||
]
|
]
|
||||||
for i in range(0, len(batch), 10):
|
for i in range(0, len(batch), 10):
|
||||||
|
|||||||
48
run.py
48
run.py
@ -1,6 +1,7 @@
|
|||||||
import sys
|
import sys
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", line_buffering=True)
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", line_buffering=True)
|
||||||
|
|
||||||
from airtable_client import AirtableClient
|
from airtable_client import AirtableClient
|
||||||
@ -173,6 +174,23 @@ def run():
|
|||||||
# Ordenar: 0=críticas → 1=no críticas → 2=mantener
|
# Ordenar: 0=críticas → 1=no críticas → 2=mantener
|
||||||
collected.sort(key=_priority)
|
collected.sort(key=_priority)
|
||||||
|
|
||||||
|
# Detectar cursos con campaña Search Y PMX simultáneas (posible reatribución PMX)
|
||||||
|
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
|
||||||
|
|
||||||
|
course_types: dict[str, set] = {}
|
||||||
|
for item in collected:
|
||||||
|
name = item["campaign"]["curso"]
|
||||||
|
num = _course_num(name)
|
||||||
|
if num:
|
||||||
|
course_types.setdefault(num, set())
|
||||||
|
if "pmx" in name.lower():
|
||||||
|
course_types[num].add("pmx")
|
||||||
|
elif "search" in name.lower():
|
||||||
|
course_types[num].add("search")
|
||||||
|
courses_with_both = {num for num, types in course_types.items() if "pmx" in types and "search" in types}
|
||||||
|
|
||||||
# === SEGUNDA PASADA: imprimir en orden + aplicar decisiones ===
|
# === SEGUNDA PASADA: imprimir en orden + aplicar decisiones ===
|
||||||
resumen = []
|
resumen = []
|
||||||
advice_updates = [] # (gcm_record_id, consejo, criticidad) para batch update final
|
advice_updates = [] # (gcm_record_id, consejo, criticidad) para batch update final
|
||||||
@ -235,6 +253,11 @@ def run():
|
|||||||
else:
|
else:
|
||||||
log_text = f"OK: {leads} leads Airtable | {conv_google} conv Google Ads"
|
log_text = f"OK: {leads} leads Airtable | {conv_google} conv Google Ads"
|
||||||
|
|
||||||
|
# Nota de reatribución PMX para campañas Search con companion PMX del mismo curso
|
||||||
|
course_num = _course_num(campaign["curso"])
|
||||||
|
if "search" in campaign["curso"].lower() and course_num in courses_with_both:
|
||||||
|
log_text += " | ⚠️ PMX ATTRIBUTION: campaña Search con companion PMX activo — parte de las conversiones de Google pueden estar reatribuidas a la campaña PMX"
|
||||||
|
|
||||||
advice_updates.append((
|
advice_updates.append((
|
||||||
campaign["airtable_id"],
|
campaign["airtable_id"],
|
||||||
decision.get("consejo", ""),
|
decision.get("consejo", ""),
|
||||||
@ -262,12 +285,27 @@ def run():
|
|||||||
at.batch_update_gacampaignmes_advice(advice_updates)
|
at.batch_update_gacampaignmes_advice(advice_updates)
|
||||||
print(" ✓ Consejos y criticidad guardados.")
|
print(" ✓ Consejos y criticidad guardados.")
|
||||||
|
|
||||||
# Copiar ConvLeadsLakeMes → ConvLeadsLakeMesFinal (snapshot diario)
|
# Snapshot diario: ConvLeadsLakeMesFinal + ConvLeadsLakeMesGrupo
|
||||||
final_leads_data = [
|
# Para PMX con Search companion del mismo curso, Grupo = leads del Search
|
||||||
{"airtable_id": item["campaign"]["airtable_id"],
|
course_search_leads = {
|
||||||
"conv_leads_lake_mes": item["leads"]}
|
_course_num(item["campaign"]["curso"]): item["leads"]
|
||||||
for item in collected
|
for item in collected
|
||||||
]
|
if "search" in item["campaign"]["curso"].lower()
|
||||||
|
and _course_num(item["campaign"]["curso"])
|
||||||
|
}
|
||||||
|
final_leads_data = []
|
||||||
|
for item in collected:
|
||||||
|
name = item["campaign"]["curso"]
|
||||||
|
num = _course_num(name)
|
||||||
|
if num and "pmx" in name.lower() and num in courses_with_both:
|
||||||
|
grupo = course_search_leads.get(num, item["leads"])
|
||||||
|
else:
|
||||||
|
grupo = item["leads"]
|
||||||
|
final_leads_data.append({
|
||||||
|
"airtable_id": item["campaign"]["airtable_id"],
|
||||||
|
"conv_leads_lake_mes": item["leads"],
|
||||||
|
"conv_leads_lake_mes_grupo": grupo,
|
||||||
|
})
|
||||||
if final_leads_data:
|
if final_leads_data:
|
||||||
print(f"→ Actualizando ConvLeadsLakeMesFinal ({len(final_leads_data)} registros)...")
|
print(f"→ Actualizando ConvLeadsLakeMesFinal ({len(final_leads_data)} registros)...")
|
||||||
at.batch_update_gacampaignmes_final_leads(final_leads_data)
|
at.batch_update_gacampaignmes_final_leads(final_leads_data)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user