Files
MP-Manager/docs/casos/2026-05-30-incoherencia-canal-fuente-lead-digital.md
2026-05-30 20:16:12 -06:00

9.7 KiB
Raw Permalink Blame History


id: CASE-2026-05-30-incoherencia-canal-fuente-lead-digital fecha: 2026-05-30 categoria: custom_field, cascada_n8n, descuadre location_ids: [GbKkBpCmKu2QmloKFHy3 (Monte Providencia/Marca), KEZ7dAhgwzK4uZfMvZuj (Puebla), uJEn2iuUficuml9zxAnt (Cancún), uZnMH5bO6MXTHcgHeyq9 (Pilares), nF1uEaYB3mCK5em9bPn2 (Eugenia), jE41bVhhnb5T505BFm4F (Morelia 1), WCHyow6KpjLFYriQWdbJ (Tampico)] run_ids: [origen-fuente-3c50e43ec6a9, "n8n ddUEORBEtZLzsQF2 versionId 11c7184b→e8f6f33f (Patrón A)→37f780e1 (Patrón B)"] snapshots: [n8n/backup_fuente_reconcile_ddUEORBEtZLzsQF2_20260530_190108.json, n8n/backup_redes_sociales_ddUEORBEtZLzsQF2_20260530_192343.json] status: resuelto memorias: incoherencia_canal_fuente_lead_digital, super_script_fix_branch_user_origin, n8n_2004_canal_origen_complemento, createdby_only_in_individual_get playbooks: []

TRIGGERS

  • LEAD DIGITAL no cuadra con FORMULARIO + FACEBOOK, Recuento de Contactos por CANAL DE ORIGEN vs Fuente de prospecto
  • 929 vs 901, descuadre 28 LEAD DIGITAL, Canal=SUCURSAL pero Fuente=LEAD DIGITAL, viola AGENTS Cap.3
  • REDES SOCIALES fuente de prospecto (valor no canónico), Tampico 7 contactos
  • fix_branch_user_origin.py NO toca Fuente de Prospecto, n8n [2004] pone Canal=SUCURSAL a WEB_USER sin reconciliar Fuente
  • createdBy.source WEB_USER MOBILE_USER = captura manual sucursal; source de Marca (Formulario/Sucursal) lo estampa la replicación n8n y NO es fiable
  • scripts: audit_origen_fuente_incoherencia.py, fix_origen_fuente_incoherencia.py

SÍNTOMA

Panel de Marca (GbKkBpCmKu2QmloKFHy3, 1328 contactos). Dos widgets descuadran:

  • Recuento por CANAL DE ORIGEN: FORMULARIO 612, SUCURSAL 426, FACEBOOK 289 (digital = 901).
  • Fuente de prospecto: LEAD DIGITAL 929, SUCURSAL 374, PROSPECCIÓN 11, REDES SOCIALES 7, CLIENTE CONOCIDO 3, ALIANZA 2, GALLARDETES 1. Regla: LEAD DIGITAL debería = FORMULARIO + FACEBOOK. 929 ≠ 901 → descuadre +28. Además REDES SOCIALES sospechoso (canal digital mal clasificado).

DIAGNÓSTICO

Cross-tab Canal × Fuente desde la cache (generated/data/mp_manager.sqlite, contacts.custom_fields_json + object_schemas):

  • FUENTE=LEAD DIGITAL (929) → 612 FORMULARIO + 289 FACEBOOK + 28 SUCURSAL ← el descuadre.
  • FUENTE=REDES SOCIALES (7) → 7 canal=SUCURSAL.
  • PROSPECCIÓN/CLIENTE CONOCIDO/ALIANZA/GALLARDETES → todos canal=SUCURSAL (OK, fuentes de prospección manual válidas).

Global (todas las cuentas): los 28 incoherentes de Marca = 16 Puebla + 4 Cancún + 3 Pilares + 3 Eugenia + 2 Morelia (suma 28 → replica 1:1 a Marca). Los 7 REDES SOCIALES = todos Tampico. La incoherencia nace en sucursal, no es artefacto de replicación.

Callejón descartado: el source de los contactos en Marca decía 19 "Sucursal" / 9 "Formulario", sugiriendo partir los 28 en dos. PERO el source del lado sucursal era 26 null + 2 Formulario (no coincide). Verificación en vivo con createdBy.source (GET individual, audit_origen_fuente_incoherencia.py --all): los 28 son WEB_USER/MOBILE_USER (captura manual sucursal), incluidos los 9 que en Marca figuraban "Formulario". El source de Marca lo estampa la replicación n8n y NO es fiable; createdBy.source es el gold standard.

CAUSA RAÍZ

  1. Workflow n8n [2004] (ddUEORBEtZLzsQF2) y su gemelo Python fix_branch_user_origin.py ponen Canal de Origen=SUCURSAL a los contactos creados por empleado (WEB_USER/MOBILE_USER) pero deliberadamente NO tocan "Fuente de Prospecto" (fix_branch_user_origin.py:27-29,234) para no pisar ALIANZA/PROSPECCIÓN. Efecto colateral: cuando voltean canal a SUCURSAL dejan el LEAD DIGITAL viejo huérfano → los 28 (Patrón A).
  2. En Tampico se usó el valor no canónico REDES SOCIALES como Fuente de Prospecto en 7 contactos digitales (social), que quedaron con canal=SUCURSAL (Patrón B).

ACCIÓN

Decisión del usuario (2 rondas AskUserQuestion): Patrón A → todos a SUCURSAL (createdBy manda sobre source de Marca); Patrón B → FACEBOOK + LEAD DIGITAL.

Script nuevo scripts/fix_origen_fuente_incoherencia.py (idempotente, detecta por estado actual, dry-run default, script_audit reversible, resuelve field ids por FIELD_ALIASES). Plan por patrón:

  • A: contacto Fuente→SUCURSAL; opps: Canal de Origen de la Oportunidad→Sucursal, Fuente→SUCURSAL.
  • B: contacto Canal→FACEBOOK + Fuente→LEAD DIGITAL; opps: Canal Opp→Facebook, Tipo de Lead→Lead digital, Fuente→LEAD DIGITAL.

Secuencia (RUN_ID origen-fuente-3c50e43ec6a9):

# dry-run (las 7 cuentas)            -> A=28, B=7, 35 opps
# piloto Tampico (Patrón B)
python scripts/fix_origen_fuente_incoherencia.py --location WCHyow6KpjLFYriQWdbJ --apply --run-id origen-fuente-3c50e43ec6a9
# verificación live 7/7 OK -> batch resto:
for LOC in GbKkBpCmKu2QmloKFHy3 KEZ7dAhgwzK4uZfMvZuj uJEn2iuUficuml9zxAnt uZnMH5bO6MXTHcgHeyq9 nF1uEaYB3mCK5em9bPn2 jE41bVhhnb5T505BFm4F; do
  python scripts/fix_origen_fuente_incoherencia.py --location $LOC --apply --run-id origen-fuente-3c50e43ec6a9; done

Marca en el batch reportó B=1 (no 7): los otros 6 REDES SOCIALES de Marca ya se habían corregido solos por replicación n8n desde Tampico. 0 errores en todas.

VERIFICACIÓN

Cross-tab en vivo en Marca (re-GET de 1328+ contactos vía API, no cache):

  • LEAD DIGITAL = 908 = FORMULARIO 612 + FACEBOOK 296 → COHERENTE (antes 929 vs 901).
  • canal=SUCURSAL & fuente=LEAD DIGITAL: 0 (antes 28).
  • REDES SOCIALES: 0 (antes 7).
  • Canal SUCURSAL 419 (antes 426; 7 que pasaron a FACEBOOK). Piloto Tampico verificado 7/7 (canal=FACEBOOK, fuente=LEAD DIGITAL sostenido; n8n [2004] no revirtió en el momento).

EDGE-CASES / TRAMPAS

  • NO confiar en contact.source de Marca para clasificar origen: la replicación n8n lo estampa (Formulario/Sucursal) y diverge del lado sucursal. Usar createdBy.source en vivo (GET individual).
  • Tampico tiene los campos con capitalización distinta (CANAL DE ORIGEN): resolver field ids case-insensitive / por FIELD_ALIASES, nunca por nombre exacto.
  • Falso positivo en verificación: match difuso de nombre ("edgar") atrapó "edgar alejandro pozos" y "edgard radiadores" (PROSPECCIÓN/SUCURSAL, no eran target). Filtrar por id, no por substring de nombre.
  • Riesgo de reversión del Patrón B: los 7 de Tampico son WEB_USER y n8n [2004] re-pone canal=SUCURSAL a WEB_USER. Si se re-editan, podrían revertir. Pendiente endurecer [2004].

REUTILIZABLE

  • python scripts/audit_origen_fuente_incoherencia.py --all → clasifica incoherentes con createdBy en vivo (read-only).
  • python scripts/fix_origen_fuente_incoherencia.py --all (dry-run) / --apply --run-id <uuid> → corrige + propaga a opps. Idempotente: re-correr no re-toca.
  • Rollback: dashboard → run origen-fuente-3c50e43ec6a9.

CAUSA RAÍZ — CIERRE EN TIEMPO REAL (2026-05-30)

Endurecido el workflow n8n [2004] (ddUEORBEtZLzsQF2) con n8n/_add_fuente_reconcile.py (backup→dry-run→apply→verify→E2E). En la rama "Creado por usuario" (esUsuario=true), tras Tag- facebook-ads se añadió: IF fuenteEsLeadDigital → PUT Fuente de Prospecto=SUCURSAL. El Code node se extendió para resolver el field contact.fuente_de_prospecto y leer su VALOR ACTUAL del GET del contacto (contact.customFields[].value), exponiendo fuente/fuenteActual/fuenteEsLeadDigital. Solo reconcilia si vale exactamente LEAD DIGITAL → preserva ALIANZA/PROSPECCIÓN/etc. versionId 11c7184be8f6f33f, 19→21 nodos. Backup n8n/backup_fuente_reconcile_ddUEORBEtZLzsQF2_20260530_190108.json.

E2E en vivo (Cancún, esau sotelo do3ClHt57hfHj0hw4tKk, WEB_USER): (1) ensuciado FORMULARIO/LEAD DIGITAL → webhook 8d574598 → SUCURSAL/SUCURSAL ✓. (2) ensuciado FORMULARIO/PROSPECCIÓN → webhook → SUCURSAL/PROSPECCIÓN intacta ✓ (preservación). Contacto restaurado a su estado real SUCURSAL/SUCURSAL.

CAUSA RAÍZ PATRÓN B — CIERRE EN TIEMPO REAL (2026-05-30)

Cerrado con n8n/_add_redes_sociales_branch.py. En la rama esUsuario, ANTES del PUT canal=SUCURSAL, se intercaló IF "Fuente es REDES SOCIALES": [true]→PUT Canal=FACEBOOK→PUT Fuente=LEAD DIGITAL (camino digital, igual que el fix de datos Patrón B); [false]→PUT Canal=SUCURSAL (camino existente intacto). Code node expone fuenteEsRedesSociales. versionId e8f6f33f37f780e1, 21→24 nodos. Backup n8n/backup_redes_sociales_ddUEORBEtZLzsQF2_20260530_192343.json. E2E vivo (Cancún, esau): T1 SUCURSAL/REDES SOCIALES→FACEBOOK/LEAD DIGITAL ✓; T2 regresión FORMULARIO/LEAD DIGITAL→SUCURSAL/SUCURSAL ✓ (la rama Patrón A sigue intacta por el false branch). Restaurado.

PENDIENTES

  1. [HECHO 2026-05-30] Causa raíz Patrón A cerrada en [2004] (_add_fuente_reconcile.py). Nota: fix_branch_user_origin.py (batch) sigue sin reconciliar Fuente, pero fix_origen_fuente_incoherencia.py cubre el backlog y [2004] cubre lo nuevo en tiempo real.
  2. [HECHO 2026-05-30] Causa raíz Patrón B (REDES SOCIALES) cerrada en [2004] (_add_redes_sociales_branch.py, ver sección arriba).
  3. Re-sync de la cache local de las 7 cuentas (el panel GHL ya está bien; la cache SQLite quedó stale para los 35 contactos).

ENLACES