# -*- coding: utf-8 -*- """Agrega al workflow n8n de oportunidades un nodo HTTP PUT que, antes de 'Buscar Oportunidad - SUCURSAL', setea el campo 'ID Oportunidad Sucursal' de la opp de sucursal = su propio id nativo (del webhook). Reordena la rama sucursal para que 'Conseguir Custom Fields - Opportunity - SUCURSAL' vaya antes (necesario para resolver el field_id, que varia por sucursal). Hace backup y verifica. """ import requests, json, datetime, uuid api_key = base = None with open('n8n/n8n credencials.txt', encoding='utf-8') as f: for line in f: if line.startswith('API:'): api_key = line.split('API:', 1)[1].strip() if line.startswith('URL:'): base = line.split('URL:', 1)[1].strip().rstrip('/') H = {'X-N8N-API-KEY': api_key, 'Accept': 'application/json', 'Content-Type': 'application/json'} WID = 'Cfgwp0bOtDW8zuKW' wf = requests.get(f'{base}/api/v1/workflows/{WID}', headers=H, timeout=30).json() print('versionId previo:', wf.get('versionId')) ts = datetime.datetime.now().strftime('%Y%m%d_%H%M%S') bpath = f'n8n/backup_workflow_pre_automap_{ts}.json' open(bpath, 'w', encoding='utf-8').write(json.dumps(wf, ensure_ascii=False, indent=2)) print('backup:', bpath) nodes = wf['nodes']; conns = wf['connections'] NEW_NAME = 'Mapear ID Oportunidad Sucursal - SUCURSAL' if any(n.get('name') == NEW_NAME for n in nodes): print('El nodo ya existe; abortando para no duplicar.'); raise SystemExit jsonBody = ("={{ JSON.stringify({ customFields: [ { " "id: $('Conseguir Custom Fields - Opportunity - SUCURSAL').item.json.customFields" ".find(f => f.fieldKey === 'opportunity.id_oportunidad_sucursal')?.id, " "key: 'opportunity.id_oportunidad_sucursal', " "field_value: $('Datos de Lead').item.json.Oportunidad.opportunity_id } ] }) }}") new_node = { "parameters": { "method": "PUT", "url": "=https://services.leadconnectorhq.com/opportunities/{{ $('Datos de Lead').item.json.Oportunidad.opportunity_id }}", "sendHeaders": True, "headerParameters": {"parameters": [ {"name": "Accept", "value": "application/json"}, {"name": "Version", "value": "2021-07-28"}, {"name": "Authorization", "value": "=Bearer {{ $('DATOS API - SUCURSAL').item.json['Token/API'] }}"}, {"name": "Content-Type", "value": "application/json"}, ]}, "sendBody": True, "specifyBody": "json", "jsonBody": jsonBody, "options": {}, }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [1448, 176], "id": str(uuid.uuid4()), "name": NEW_NAME, "onError": "continueRegularOutput", "notes": ("Auto-mapeo de seguridad: setea 'ID Oportunidad Sucursal' = id nativo " "de la propia opp de sucursal (del webhook) antes de procesar. " "onError=continue para no romper el sync si falla."), } nodes.append(new_node) def setconn(src, dst): conns[src] = {'main': [[{'node': dst, 'type': 'main', 'index': 0}]]} # Rama sucursal reordenada: DATOS API - SUCURSAL -> Conseguir CF -> [PUT] -> Buscar Opp -> Obtener info setconn('DATOS API - SUCURSAL', 'Conseguir Custom Fields - Opportunity - SUCURSAL') setconn('Conseguir Custom Fields - Opportunity - SUCURSAL', NEW_NAME) setconn(NEW_NAME, 'Buscar Oportunidad - SUCURSAL') setconn('Buscar Oportunidad - SUCURSAL', 'Obtener info de Oportunidad - SUCURSAL') ALLOWED = {'saveExecutionProgress', 'saveManualExecutions', 'saveDataErrorExecution', 'saveDataSuccessExecution', 'executionTimeout', 'errorWorkflow', 'timezone', 'executionOrder'} settings = {k: v for k, v in (wf.get('settings') or {}).items() if k in ALLOWED} payload = {'name': wf['name'], 'nodes': nodes, 'connections': conns, 'settings': settings} r = requests.put(f'{base}/api/v1/workflows/{WID}', headers=H, data=json.dumps(payload), timeout=60) print('PUT status:', r.status_code) if r.status_code != 200: print(r.text[:600]); raise SystemExit('PUT fallo') wf2 = requests.get(f'{base}/api/v1/workflows/{WID}', headers=H, timeout=30).json() print('versionId nuevo:', wf2.get('versionId')) print('active:', wf2.get('active')) print('total nodos:', len(wf2['nodes'])) print('nodo agregado:', any(n.get('name') == NEW_NAME for n in wf2['nodes'])) c = wf2['connections'] def tgt(s): return [x['node'] for o in c.get(s, {}).get('main', []) for x in (o or [])] print('DATOS API - SUCURSAL ->', tgt('DATOS API - SUCURSAL')) print('Conseguir CF SUCURSAL ->', tgt('Conseguir Custom Fields - Opportunity - SUCURSAL')) print(NEW_NAME, '->', tgt(NEW_NAME)) print('Buscar Oportunidad - SUCURSAL ->', tgt('Buscar Oportunidad - SUCURSAL'))