#!/usr/bin/env python3 # -*- coding: utf-8 -*- """Fase 3 — MARCA → SUCURSAL V2: autoenlace bidireccional post-CREATE. Tras `Crear Contacto - Cuenta Objetivo - MARCA` (nombre engañoso, crea en sucursal): 1) Code `Resolver fieldId y newContactId post-CREATE` — extrae el fieldId del CF en SUCURSAL desde `Conseguir Custom Cuenta objetivo - MARCA1` y el id del contacto recién creado. 2) HTTP PUT `Enlazar CF en SUCURSAL (autoref)` — pone CF=newContactId en sucursal. 3) HTTP PUT `Enlazar CF en MARCA` — pone CF=newContactId en el contacto Marca origen. Después seguimos al `Envio a tienda` original. """ import argparse import copy import json import os import sys import uuid ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, ROOT) sys.path.insert(0, os.path.join(ROOT, "scripts")) from n8n_workflow_lib import load_credentials, N8NClient # noqa: E402 WID = "4UMRwxJdHFfOGHBp" CF_ID_BRAND = "E6lI9ykWhqpj7Pmi7Qd3" CODE_RESOLVE = "Resolver fieldId y newContactId post-CREATE" PUT_SUC = "Enlazar CF en SUCURSAL (autoref)" PUT_MARCA = "Enlazar CF en MARCA" def code_resolve_node(): return { "parameters": { "jsCode": ( "var defs = $('Conseguir Custom Cuenta objetivo - MARCA1').first().json.customFields || [];\n" "var def = defs.find(function(d){ return d.fieldKey === 'contact.id_contacto_sucursal'; });\n" "var createdContact = ($('Crear Contacto - Cuenta Objetivo - MARCA').first().json || {}).contact || {};\n" "var newId = createdContact.id;\n" "return [{ json: { fieldId: def ? def.id : null, newContactId: newId || null } }];" ) }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [3920, 848], "id": str(uuid.uuid4()), "name": CODE_RESOLVE, "notes": "FASE 3. Extrae fieldId del CF en sucursal y el id del contacto recién creado.", } def put_sucursal_node(): return { "parameters": { "method": "PUT", "url": "=https://services.leadconnectorhq.com/contacts/{{ $json.newContactId }}", "sendHeaders": True, "headerParameters": { "parameters": [ {"name": "Accept", "value": "application/json"}, {"name": "Version", "value": "2021-07-28"}, {"name": "Authorization", "value": "=Bearer {{ $('Datos API Cuenta objetivo - SUCURSAL').item.json['Token/API'] }}"}, {"name": "Content-Type", "value": "application/json"}, ] }, "sendBody": True, "specifyBody": "json", "jsonBody": ( "={\n" " \"customFields\": [\n" " {\n" " \"id\": \"{{ $json.fieldId }}\",\n" " \"key\": \"contact.id_contacto_sucursal\",\n" " \"field_value\": \"{{ $json.newContactId }}\"\n" " }\n" " ]\n" "}" ), "options": {"redirect": {"redirect": {}}}, }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [4112, 848], "id": str(uuid.uuid4()), "name": PUT_SUC, "onError": "continueRegularOutput", "notes": "FASE 3. PUT al contacto sucursal recién creado: CF id_contacto_sucursal = su propio id.", } def put_marca_node(): return { "parameters": { "method": "PUT", "url": "=https://services.leadconnectorhq.com/contacts/{{ $('Webhook').item.json.body.contact_id }}", "sendHeaders": True, "headerParameters": { "parameters": [ {"name": "Accept", "value": "application/json"}, {"name": "Version", "value": "2021-07-28"}, {"name": "Authorization", "value": "=Bearer {{ $('Datos API Cuenta Origen').item.json['Token/API'] }}"}, {"name": "Content-Type", "value": "application/json"}, ] }, "sendBody": True, "specifyBody": "json", "jsonBody": ( "={\n" " \"customFields\": [\n" " {\n" " \"id\": \"" + CF_ID_BRAND + "\",\n" " \"key\": \"contact.id_contacto_sucursal\",\n" " \"field_value\": \"{{ $('" + CODE_RESOLVE + "').item.json.newContactId }}\"\n" " }\n" " ]\n" "}" ), "options": {"redirect": {"redirect": {}}}, }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [4304, 848], "id": str(uuid.uuid4()), "name": PUT_MARCA, "onError": "continueRegularOutput", "notes": "FASE 3. PUT al contacto Marca origen: CF id_contacto_sucursal = id del nuevo sucursal.", } def main(): parser = argparse.ArgumentParser() parser.add_argument("--apply", action="store_true") parser.add_argument("--activate", action="store_true") args = parser.parse_args() if hasattr(sys.stdout, "reconfigure"): sys.stdout.reconfigure(encoding="utf-8") client = N8NClient(*load_credentials()) wf, backup = client.backup_workflow(WID, label="fase3_pre") print(f"backup: {backup}") prev = wf.get("versionId") print(f"versionId pre: {prev} active: {wf.get('active')}") wfm = copy.deepcopy(wf) for name in (CODE_RESOLVE, PUT_SUC, PUT_MARCA): client.assert_idempotent(wfm, name) code_node = code_resolve_node() put_suc = put_sucursal_node() put_marca = put_marca_node() for n in (code_node, put_suc, put_marca): client.add_node(wfm, n) # Conexiones: Crear → Code → PUT suc → PUT Marca → Envio a tienda # antes: Crear → Envio a tienda client.set_connection(wfm, "Crear Contacto - Cuenta Objetivo - MARCA", CODE_RESOLVE) client.set_connection(wfm, CODE_RESOLVE, PUT_SUC) client.set_connection(wfm, PUT_SUC, PUT_MARCA) client.set_connection(wfm, PUT_MARCA, "Envio a tienda") print(f"nodes post: {len(wfm['nodes'])} (+{len(wfm['nodes'])-len(wf['nodes'])})") if not args.apply: res = client.put_workflow(WID, wfm, dry_run=True) print(f"DRY-RUN. {res['path']}") return client.put_workflow(WID, wfm, dry_run=False) wf2 = client.verify_post(WID, expected_node_names=[CODE_RESOLVE, PUT_SUC, PUT_MARCA], prev_version_id=prev) print(f"versionId nuevo: {wf2.get('versionId')} active: {wf2.get('active')}") if args.activate or not wf2.get("active"): client.activate(WID) print("activado") print("Fase 3 aplicada.") if __name__ == "__main__": main()