# -*- coding: utf-8 -*- """Segundo fix del nodo `Buscar Contacto Objetivo - SUCURSAL(mail)` del workflow Marca->Sucursal V2 (4UMRwxJdHFfOGHBp). El primer fix (`_fix_cascada_token_mail.py`) corrigio el header Authorization para usar la referencia explicita a 'Datos API Cuenta objetivo - SUCURSAL'. Pero el body sigue con el mismo bug: usa `$json['ID LOCATION BUCEFALO']` (implicito), que resuelve a undefined porque el $json llega del IF `¿cfValue presente?` y no contiene ese campo. Resultado: 422 "locationId can't be undefined". Patron correcto (usado por `Retry telefono` y `Retry nombre`): \"locationId\": \"{{ $('Datos API Cuenta objetivo - SUCURSAL').item.json['ID LOCATION BUCEFALO'] }}\" Cambio neto: 1 expression en el jsonBody del nodo. Total nodos sin cambios. """ import argparse import os import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from scripts.n8n_workflow_lib import load_credentials, N8NClient WID = "4UMRwxJdHFfOGHBp" TARGET_NODE = "Buscar Contacto Objetivo - SUCURSAL(mail)" BUGGY_FRAGMENT = '"locationId": "{{ $json[\'ID LOCATION BUCEFALO\'] }}"' FIXED_FRAGMENT = ( '"locationId": "{{ ' "$('Datos API Cuenta objetivo - SUCURSAL').item.json['ID LOCATION BUCEFALO']" ' }}"' ) def parse_args(): ap = argparse.ArgumentParser() ap.add_argument("--apply", action="store_true", help="Aplicar PUT real (default: dry-run a n8n/dryrun_*.json)") return ap.parse_args() def main(): args = parse_args() api_key, base_url = load_credentials() client = N8NClient(api_key, base_url) print(f"[1/6] GET workflow {WID}") wf = client.get_workflow(WID) prev_version = wf.get("versionId") print(f" versionId previo: {prev_version}") print(f" active : {wf.get('active')}") print(f" total nodos : {len(wf.get('nodes') or [])}") target = next((n for n in wf["nodes"] if n.get("name") == TARGET_NODE), None) if not target: print(f"\nERROR: nodo {TARGET_NODE!r} no existe. Abortando.") sys.exit(2) current_body = (target.get("parameters") or {}).get("jsonBody", "") print(f"\n[2/6] Verificar body actual") print(f" actual: {current_body}") if FIXED_FRAGMENT in current_body: print(f"\n [SKIP] El body ya esta arreglado.") return if BUGGY_FRAGMENT not in current_body: print(f"\nERROR: el body no contiene el fragmento buggy esperado.") print(f" buggy esperado: {BUGGY_FRAGMENT}") sys.exit(2) print(f"\n[3/6] Backup fresco") _, bpath = client.backup_workflow(WID, label="pre_fix_cascada_locationid_mail") print(f" backup -> {bpath}") print(f"\n[4/6] Aplicar cambio en memoria") new_body = current_body.replace(BUGGY_FRAGMENT, FIXED_FRAGMENT) target["parameters"]["jsonBody"] = new_body print(f" nuevo: {new_body}") print(f"\n[5/6] {'APPLY' if args.apply else 'DRY-RUN'} put_workflow") result = client.put_workflow(WID, wf, dry_run=not args.apply) if not args.apply: print(f" dry-run dump -> {result}") print("\nLISTO. Revisa el JSON. Si todo bien, corre con --apply.") return print(f"\n[6/6] Verificar y reactivar") new_wf = client.verify_post(WID, prev_version_id=prev_version) target_post = next((n for n in new_wf["nodes"] if n.get("name") == TARGET_NODE), None) body_post = (target_post.get("parameters") or {}).get("jsonBody", "") print(f" versionId nuevo : {new_wf.get('versionId')}") print(f" total nodos : {len(new_wf.get('nodes') or [])}") print(f" body coincide : {FIXED_FRAGMENT in body_post}") if not new_wf.get("active"): print(" workflow inactivo; reactivando...") client.activate(WID) new_wf = client.get_workflow(WID) print(f" active final : {new_wf.get('active')}") print("\nOK.") if __name__ == "__main__": main()