# check_choque_campania.py # Revisa si una campaña NUEVA chocaría (duplicaría leads) contra las existentes. # Regla de choque (igual que el JOIN LIKE del dashboard): # - una frase es sub-cadena de la otra (contención de texto), Y # - los rangos de fecha se solapan. # Un mensaje que caiga en ambas frases + ambas fechas => 2 filas => lead duplicado. # # Edita NUEVA abajo y ejecuta: python check_choque_campania.py import os, requests from datetime import date from dotenv import load_dotenv load_dotenv() # ── CAMPAÑA NUEVA A PROBAR (edita aquí) ── NUEVA = { "frase": "🎟️ Me interesa el programa de Aire Acondicionado", "inicio": "2026-08-10", "fin": "2026-10-10", } # ───────────────────────────────────────── URL = os.getenv("CARTERA_URL") or os.getenv("SUPABASE_PAUTA_URL", "") KEY = os.getenv("CARTERA_KEY") or os.getenv("SUPABASE_PAUTA_KEY", "") TABLA = os.getenv("SUPABASE_TABLA_CAMPANIAS", "campanias") HEAD = {"apikey": KEY, "Authorization": f"Bearer {KEY}"} assert URL and KEY, "Falta CARTERA_URL / CARTERA_KEY en .env" def traer_todo(): filas, paso, desde = [], 1000, 0 while True: hdr = dict(HEAD); hdr["Range-Unit"] = "items"; hdr["Range"] = f"{desde}-{desde+paso-1}" r = requests.get(f"{URL}/rest/v1/{TABLA}", params={"select": "*", "order": "id"}, headers=hdr, timeout=60) r.raise_for_status() data = r.json() if not data: break filas.extend(data); desde += len(data) if len(data) < paso: break return filas def _d(s): try: return date.fromisoformat(str(s)[:10]) except Exception: return None def _solapan(i1, f1, i2, f2): if not (i1 and f1 and i2 and f2): return False return i1 <= f2 and i2 <= f1 # rangos [i1,f1] y [i2,f2] se cruzan def _norm(t): return " ".join(str(t or "").lower().split()) filas = traer_todo() ni, nf = _norm(NUEVA["frase"]), None n_ini, n_fin = _d(NUEVA["inicio"]), _d(NUEVA["fin"]) print("\n" + "="*90) print(f"CAMPAÑA NUEVA: \"{NUEVA['frase']}\"") print(f"FECHAS: {NUEVA['inicio']} → {NUEVA['fin']}") print("="*90) choques = [] for f in filas: fr = _norm(f.get("frase_busqueda")) if not fr: continue ei, ef = _d(f.get("fecha_inicio")), _d(f.get("fecha_fin")) contiene = (fr in ni) or (ni in fr) # una es sub-cadena de la otra fechas = _solapan(n_ini, n_fin, ei, ef) if contiene and fechas: choques.append((f, fr)) if not choques: print("\n✅ SIN CHOQUES. Ninguna campaña existente comparte texto contenido") print(" y fechas solapadas. Tu campaña NO duplicaría leads.\n") else: print(f"\n⚠️ {len(choques)} CHOQUE(S) DETECTADO(S) — estas campañas duplicarían leads:\n") for f, fr in choques: rel = "existente ⊂ nueva" if fr in ni else "nueva ⊂ existente" print(f" id {f.get('id')} cod {f.get('codigo')} [{rel}]") print(f" frase: \"{f.get('frase_busqueda')}\"") print(f" fechas: {str(f.get('fecha_inicio'))[:10]} → {str(f.get('fecha_fin'))[:10]}") print() print(" Un mensaje que contenga ambas frases dentro de estas fechas se") print(" contaría 2 veces (2 códigos de pauta para el mismo lead).\n") print("="*90)