# -*- coding: utf-8 -*- """Test puntual del fallback post-UPDATE en workflow Marca->Sucursal V2. Escenario: - Crear contacto en SUCURSAL (con CF autoref). - Crear contacto en MARCA SIN CF, mismo phone. - Disparar webhook Marca->Sucursal. - El workflow va por cascada phone, encuentra contacto sucursal, UPDATE. - Tras UPDATE, el nuevo IF detecta cfValue vacio -> autoenlace. - Verificar: * CF en MARCA queda poblado con id del contacto sucursal. * CF en SUCURSAL queda con autoref. - Cleanup. """ import os import sys import time import datetime ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, ROOT_DIR) sys.path.insert(0, os.path.join(ROOT_DIR, "scripts")) from scripts import n8n_e2e_test as t def log(msg): ts = datetime.datetime.now().strftime("%H:%M:%S") print(f"[{ts}] {msg}", flush=True) def main(): cleanup = t.Cleanup() try: phone = "+5219991122334" email = "fbpost@e3.local" # 1) Resolver field_id CF en sucursal (varia por sucursal) cf_id_branch = t.resolve_cf_id_in_location(t.PINOTEPA_LOCATION_ID, t.CF_KEY) log(f"CF field_id en PINOTEPA: {cf_id_branch}") # 2) Crear contacto SUCURSAL con autoref CF payload_branch = t._new_contact_payload("FBPU", phone=phone, email=email) branch_id = t.create_contact(t.PINOTEPA_LOCATION_ID, payload_branch) cleanup.register(t.PINOTEPA_LOCATION_ID, branch_id, "fbpost branch") log(f"Branch creado: {branch_id}") # Poblar CF autoref en sucursal t.update_contact(t.PINOTEPA_LOCATION_ID, branch_id, { "customFields": [ {"id": cf_id_branch, "key": t.CF_KEY, "field_value": branch_id} ] }) # 2b) Esperar a que GHL indexe el email en sucursal (el workflow va por cascada mail) log("Esperando indexacion del email en sucursal...") suc_token = t.get_token(t.PINOTEPA_LOCATION_ID) import time as _t deadline = _t.time() + 30 indexed = False while _t.time() < deadline: try: r = t.gc._request("POST", "/contacts/search", suc_token, json={ "locationId": t.PINOTEPA_LOCATION_ID, "pageLimit": 5, "query": email }) if any(c.get("id") == branch_id for c in (r.get("contacts") or [])): indexed = True break except Exception: pass _t.sleep(2) log(f" email indexado: {indexed}") assert indexed, "El email no se indexo en sucursal a tiempo" # 3) Crear contacto MARCA SIN CF, mismo phone payload_brand = t._new_contact_payload("FBPU", phone=phone, email=email) brand_id = t.create_contact(t.BRAND_LOCATION_ID, payload_brand) cleanup.register(t.BRAND_LOCATION_ID, brand_id, "fbpost brand") log(f"Brand creado (sin CF): {brand_id}") # 4) Sanity: confirmar CF Marca vacio cm0 = t.get_contact(t.BRAND_LOCATION_ID, brand_id) cf_brand_0 = t.cf_value_of(cm0, t.CF_ID_BRAND) log(f"CF Marca pre-webhook: {cf_brand_0!r} (esperado: vacio)") assert not cf_brand_0, f"CF Marca deberia estar vacio, valor={cf_brand_0!r}" # 5) Disparar webhook Marca->Sucursal brand_obj = t.get_contact(t.BRAND_LOCATION_ID, brand_id) webhook_payload = t.build_webhook_payload_marca_to_suc(brand_obj) s, body = t.fire_webhook(t.WEBHOOK_URL_MARCA_TO_SUC, webhook_payload) log(f"Webhook status: {s} body: {body[:100]}") assert s == 200, f"Webhook fallo: {s}" log("Esperando 18s para que el workflow complete (cascada + UPDATE + autoenlace)...") time.sleep(18) # 6) Verificar: CF en MARCA ahora poblado con branch_id cm1 = t.get_contact(t.BRAND_LOCATION_ID, brand_id) cf_brand_1 = t.cf_value_of(cm1, t.CF_ID_BRAND) log(f"CF Marca post-webhook: {cf_brand_1!r}") if cf_brand_1 == branch_id: log("[OK] Fallback post-UPDATE: CF Marca quedo enlazado al branch_id.") else: log(f"[FAIL] CF Marca = {cf_brand_1!r}, esperaba {branch_id!r}") sys.exit(2) # 7) Verificar: CF en SUCURSAL sigue siendo autoref (era branch_id desde antes) cb1 = t.get_contact(t.PINOTEPA_LOCATION_ID, branch_id) cf_branch_1 = t.cf_value_of(cb1, cf_id_branch) log(f"CF Sucursal post-webhook: {cf_branch_1!r}") if cf_branch_1 == branch_id: log("[OK] CF Sucursal mantiene autoref.") else: log(f"[WARN] CF Sucursal cambio a {cf_branch_1!r}") finally: cleanup.run() if __name__ == "__main__": main()