{ "updatedAt": "2026-05-30T15:55:46.487Z", "createdAt": "2026-03-02T01:12:56.387Z", "id": "Cfgwp0bOtDW8zuKW", "name": "Sincronizar Oportunidad - Nodos Nuevos (Create/Update)", "description": null, "active": true, "isArchived": false, "nodes": [ { "parameters": { "httpMethod": "POST", "path": "3eecb45a-e24c-49ac-aef7-99843f485819", "options": {} }, "type": "n8n-nodes-base.webhook", "typeVersion": 2.1, "position": [ -336, -16 ], "id": "dd424583-8295-4013-96ba-c7e29ea944c6", "name": "Webhook", "webhookId": "3eecb45a-e24c-49ac-aef7-99843f485819" }, { "parameters": { "assignments": { "assignments": [ { "id": "8a998fd4-2de6-4895-ab3d-e052e823d1b8", "name": "Cliente.Fuente Posible Cliente", "value": "={{ $json.body['Fuente de Posible cliente'] }}", "type": "string" }, { "id": "938c6fec-ae16-4e7a-ba2a-f450794fa40d", "name": "Cliente.Fecha de creación", "value": "={{ $json.body.date_created }}", "type": "string" }, { "id": "b56a1939-2608-47c8-85ad-b60b557d2a27", "name": "Cliente.Sucursal.Sucursal", "value": "={{ $json.body.Sucursal }}", "type": "string" }, { "id": "0d07b9c9-4450-497b-ab81-3baa441787fb", "name": "Vehiculo.Versión.Versión", "value": "={{ $json.body['Version del Vehiculo'] }}", "type": "string" }, { "id": "75e3f337-00d1-429d-8d5b-85ec18e6c5e4", "name": "Vehiculo.Marca.Marca", "value": "={{ $json.body['Marca del Vehiculo'] }}", "type": "string" }, { "id": "cb09c536-fe84-4598-aaae-aa79f2eda61b", "name": "Vehiculo.Marca.fieldKey", "value": "=contact.marca_del_vehiculo", "type": "string" }, { "id": "17d36409-4c54-48dd-8100-f7f667fd2415", "name": "Vehiculo.Año.Año", "value": "={{ $json.body['Año del Vehículo'] }}", "type": "string" }, { "id": "a1886afc-b0af-4950-9752-f8bfff594896", "name": "Vehiculo.Modalidad.Modalidad", "value": "={{ $json.body['¿Qué modalidad prefieres?'] }}", "type": "string" }, { "id": "33b2c28a-1ad3-4c74-917f-3cd718a3a709", "name": "Cliente.Nombre", "value": "={{ $json.body['Información Adicional'] }}", "type": "string" }, { "id": "b36131ac-2d88-41f8-8f0f-7640cdb02b57", "name": "Cliente.Apellido", "value": "={{ $json.body.first_name }}", "type": "string" }, { "id": "ae252c8f-f0a1-41d9-a21d-04ca949f01c8", "name": "Cliente.Nombre Completo", "value": "={{ $json.body.full_name }}", "type": "string" }, { "id": "342a9377-0ded-4f23-b93b-1f76e57c0cbd", "name": "Cliente.Email", "value": "={{ $json.body.email }}", "type": "string" }, { "id": "cf1b7058-96c2-4c73-9250-719a88b68673", "name": "Cliente.Telefono", "value": "={{ $json.body.phone }}", "type": "string" }, { "id": "0b916193-15e8-4a91-9ff2-0a6f262b3c38", "name": "Cliente.Contact ID", "value": "={{ $json.body.contact_id }}", "type": "string" }, { "id": "67eeaa9b-f703-4521-82af-9d2797131edc", "name": "Cliente.Sucursal.fieldKey", "value": "contact.sucursal", "type": "string" }, { "id": "b05ea7bb-bbaa-467b-8247-eabb162ff029", "name": "Vehiculo.Versión.fieldKey", "value": "contact.version_del_vehiculo", "type": "string" }, { "id": "9891b919-ef4c-46bd-8414-6d916565d896", "name": "Vehiculo.Año.fieldKey", "value": "contact.ano_del_vehiculo", "type": "string" }, { "id": "0b6bf582-49c1-41de-9c2e-6ae85c4e41e8", "name": "Vehiculo.Modalidad.fieldKey", "value": "contact.que_modalidad_prefieres", "type": "string" }, { "id": "b02bc821-6121-452d-a042-623fac6e443c", "name": "Oportunidad.opportunity_name", "value": "={{ $json.body.opportunity_name }}", "type": "string" }, { "id": "898817a2-7926-4ddf-b785-cac8e28afc58", "name": "Oportunidad.pipleline_stage (new)", "value": "={{ $json.body.pipleline_stage }}", "type": "string" }, { "id": "opp-id-sucursal-capture", "name": "Oportunidad.opportunity_id", "value": "={{ $json.body.id }}", "type": "string" } ] }, "options": {} }, "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [ -96, -16 ], "id": "2b3ec130-27ce-4988-82db-46e4f12c3f7d", "name": "Datos de Lead" }, { "parameters": { "content": "# OBTENER DATOS DE SUCURSAL", "height": 352, "width": 1152 }, "type": "n8n-nodes-base.stickyNote", "position": [ 1072, -144 ], "typeVersion": 1, "id": "19023e33-a9f1-4c60-b87c-957e751e3dc2", "name": "Sticky Note" }, { "parameters": { "content": "# OBTENER DATOS DE MARCA", "height": 208, "width": 1188, "color": 7 }, "type": "n8n-nodes-base.stickyNote", "position": [ 2240, -80 ], "typeVersion": 1, "id": "3a3d4f18-1a08-4dbc-a00b-7ae6bc4d49d1", "name": "Sticky Note1" }, { "parameters": { "assignments": { "assignments": [ { "id": "55ff7d12-17b9-4bec-a324-e633020b131d", "name": "Name Location", "value": "={{ $json.Nombre }}", "type": "string" }, { "id": "d877c8cd-db32-4c16-96dd-4eeb2dc48efe", "name": "Location ID", "value": "={{ $json.Location_ID }}", "type": "string" }, { "id": "7698f395-5db8-415b-919e-3ad61c6566f8", "name": "Token/API", "value": "={{ $json.API_token }}", "type": "string" } ] }, "options": {} }, "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [ 2480, -32 ], "id": "a46df506-6a9a-420d-9cdd-6fc51d1a691e", "name": "DATOS API" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 }, "conditions": [ { "id": "44d54b9e-d192-4b54-bf0c-156b79afc6e2", "leftValue": "={{ $json.Cliente.Email }}", "rightValue": "@ezcorp.com", "operator": { "type": "string", "operation": "notContains" } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ 80, -16 ], "id": "25db982f-7bc7-4318-a7b0-e94326abc437", "name": "Omitir @ezcorp.com" }, { "parameters": { "method": "PUT", "url": "=https://services.leadconnectorhq.com/opportunities/{{ $json.opportunityId }}", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={{ $json.body }}", "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 3952, -32 ], "id": "2320b102-816e-4a0c-ae9c-e305d25df6df", "name": "Actualizar Oportunidad - MARCA2", "notes": "El código mapea los custom fields de una oportunidad de una sucursal hacia los IDs equivalentes de una marca. Toma tres fuentes: los metadatos de campos de la sucursal, los valores reales de esos campos en la oportunidad, y los metadatos de campos de la marca. Para cada campo con valor en la oportunidad, primero busca su `fieldKey` en los metadatos de la sucursal usando el `id`, luego usa ese `fieldKey` para encontrar el campo equivalente en la marca, y construye un array con el `id` y `key` de la marca pero con el valor original de la sucursal. Finalmente arma el body de una petición para crear/actualizar una oportunidad en la marca, reutilizando pipeline, nombre, stage y valor monetario de otros nodos, con los custom fields ya traducidos al contexto de la marca." }, { "parameters": { "method": "POST", "url": "https://services.leadconnectorhq.com/opportunities/search", "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'] }}" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"locationId\": \"{{ $('DATOS API - SUCURSAL').item.json['Location ID'] }}\",\n \"query\": \"{{ $('Datos de Lead').item.json.Oportunidad.opportunity_name }}\",\n \"limit\": 1,\n \"page\": 0\n}", "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 1536, -32 ], "id": "4e89658b-7ffd-4a3b-b91e-9ed3223a1a73", "name": "Buscar Oportunidad - SUCURSAL", "notes": "NECESITA MEJORAS\n\nActualmente solo hace busqueda con base al NOMBRE DE OPORTUNIDAD.\n\nSe puede optimizar la busqueda futura añadiendo más parametros como valor de oportunidad o datos que sean 100% seguros e inmutables." }, { "parameters": { "assignments": { "assignments": [ { "id": "55ff7d12-17b9-4bec-a324-e633020b131d", "name": "Name Location", "value": "={{ $json.Nombre }}", "type": "string" }, { "id": "d877c8cd-db32-4c16-96dd-4eeb2dc48efe", "name": "Location ID", "value": "={{ $json.Location_ID }}", "type": "string" }, { "id": "7698f395-5db8-415b-919e-3ad61c6566f8", "name": "Token/API", "value": "={{ $json.API_token }}", "type": "string" } ] }, "options": {} }, "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [ 528, -32 ], "id": "b721a65d-bcbb-44ab-bb7f-8f200b34fcdd", "name": "DATOS API - SUCURSAL" }, { "parameters": { "url": "=https://services.leadconnectorhq.com/locations/{{ $('DATOS API - SUCURSAL').item.json['Location ID'] }}/customFields", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "model", "value": "opportunity" } ] }, "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'] }}" } ] }, "options": { "redirect": { "redirect": { "maxRedirects": 90 } } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 1136, -32 ], "id": "39ef9dcc-ac20-4ba2-b891-2a2baa6ea4f5", "name": "Conseguir Custom Fields - Opportunity - SUCURSAL" }, { "parameters": { "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'] }}" } ] }, "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 1712, -32 ], "id": "fbd46ae4-792b-451b-b99e-9816dc175d52", "name": "Obtener info de Oportunidad - SUCURSAL" }, { "parameters": { "content": "# ACTUALIZAR OPORTUNIDAD - MARCA", "height": 352, "width": 928 }, "type": "n8n-nodes-base.stickyNote", "position": [ 3456, -144 ], "typeVersion": 1, "id": "f3ca1cfe-08e2-485b-b238-9240f5753809", "name": "Sticky Note2" }, { "parameters": { "content": "", "height": 208, "width": 992, "color": 3 }, "type": "n8n-nodes-base.stickyNote", "position": [ 2768, -64 ], "typeVersion": 1, "id": "45066721-8404-48ed-94c1-c88edf48bca5", "name": "Sticky Note5" }, { "parameters": { "content": "", "height": 192, "width": 928, "color": 3 }, "type": "n8n-nodes-base.stickyNote", "position": [ 1104, -64 ], "typeVersion": 1, "id": "b1646bb4-8b64-4bf4-b380-189cc7902741", "name": "Sticky Note7" }, { "parameters": { "databaseId": 63, "tableId": 749, "limit": 1, "additionalOptions": { "filters": { "fields": [ { "field": 7235, "value": "={{ $('Webhook').item.json.body.location.name }}" } ] } } }, "type": "n8n-nodes-base.baserow", "typeVersion": 1.1, "position": [ 320, -32 ], "id": "12088f29-8bb4-475d-ae0e-2cbdf8033138", "name": "API de Sucursal", "credentials": { "baserowApi": { "id": "LZztQ3WMpzXjSTIH", "name": "Baserow account" } } }, { "parameters": { "databaseId": 63, "tableId": 749, "limit": 1, "additionalOptions": { "filters": { "fields": [ { "field": 7235, "value": "=Monte Providencia" } ] } } }, "type": "n8n-nodes-base.baserow", "typeVersion": 1.1, "position": [ 2288, -32 ], "id": "8c8fa238-6ce4-4adf-8926-b603987a55cf", "name": "API de MARCA", "credentials": { "baserowApi": { "id": "LZztQ3WMpzXjSTIH", "name": "Baserow account" } } }, { "parameters": { "jsCode": "const opportunityData = $('Obtener info de Oportunidad - SUCURSAL').first().json;\nconst opportunity = opportunityData.opportunity;\nconst customFieldsDefs = $('Conseguir Custom Fields - Opportunity - SUCURSAL').first().json.customFields;\nconst pipelines = $input.first().json.pipelines;\n\n// Map custom fields: id -> { fieldKey, name }\nconst fieldMap = {};\nfor (const def of customFieldsDefs) {\n fieldMap[def.id] = { fieldKey: def.fieldKey, name: def.name };\n}\n\n// Map pipelines: id -> name, stages: id -> { name, position, stageWinProbability }\nconst pipelineMap = {};\nconst stageMap = {};\nfor (const pipeline of pipelines) {\n pipelineMap[pipeline.id] = pipeline.name;\n for (const stage of pipeline.stages) {\n stageMap[stage.id] = {\n name: stage.name,\n position: stage.position,\n stageWinProbability: stage.stageWinProbability,\n color: stage.color || null\n };\n }\n}\n\n// Enrich custom fields with fieldKey and name\nconst enrichedCustomFields = opportunity.customFields.map(cf => ({\n id: cf.id,\n name: fieldMap[cf.id]?.name || null,\n fieldKey: fieldMap[cf.id]?.fieldKey || null,\n fieldValue: cf.fieldValue\n}));\n\n// Resolve pipeline and stage info\nconst stageInfo = stageMap[opportunity.pipelineStageId] || {};\n\n// Build enriched opportunity\nconst enrichedOpportunity = {\n ...opportunity,\n pipelineName: pipelineMap[opportunity.pipelineId] || null,\n pipelineStageName: stageInfo.name || null,\n pipelineStagePosition: stageInfo.position ?? null,\n pipelineStageWinProbability: stageInfo.stageWinProbability ?? null,\n pipelineStageColor: stageInfo.color || null,\n customFields: enrichedCustomFields\n};\n\nreturn [{ json: { opportunity: enrichedOpportunity, traceId: opportunityData.traceId } }];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 2080, -32 ], "id": "d9609dd9-9493-4f3d-b356-99438cedada6", "name": "Mapeo completo oportunidad origen - SUCURSAL" }, { "parameters": { "url": "https://services.leadconnectorhq.com/opportunities/pipelines", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "locationId", "value": "={{ $('Webhook').item.json.body.location.id }}" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('API de Sucursal').item.json.API_token }}" } ] }, "sendBody": true, "bodyParameters": { "parameters": [ {} ] }, "options": {} }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 1872, -32 ], "id": "2d799ae3-b6b1-4e4f-8774-714ebe4f009f", "name": "Obtener Pipelines - SUCURSAL" }, { "parameters": { "url": "=https://services.leadconnectorhq.com/opportunities/{{ $('Buscar Oportunidad - MARCA').item.json.opportunities[0].id }}", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 3216, -32 ], "id": "1eee43d2-c6a8-414b-bebf-4b31d6fb34d7", "name": "Obtener info de Oportunidad - MARCA" }, { "parameters": { "url": "https://services.leadconnectorhq.com/opportunities/pipelines", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "locationId", "value": "={{ $('API de MARCA').item.json.Location_ID }}" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('API de MARCA').item.json.API_token }}" } ] }, "sendBody": true, "bodyParameters": { "parameters": [ {} ] }, "options": {} }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 3424, -32 ], "id": "20a1a288-2cd8-471b-9203-5ba88770edb0", "name": "Obtener Pipelines - MARCA" }, { "parameters": { "method": "POST", "url": "https://services.leadconnectorhq.com/opportunities/search", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $json['Token/API'] }}" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"locationId\": \"{{ $json['Location ID'] }}\",\n \"query\": \"{{ $('Datos de Lead').item.json.Oportunidad.opportunity_name }}\",\n \"limit\": 1,\n \"page\": 0\n}", "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 2800, -32 ], "id": "798a7e51-b8ed-4364-947a-7396fab47940", "name": "Buscar Oportunidad - MARCA", "notes": "NECESITA MEJORAS\n\nActualmente solo hace busqueda con base al NOMBRE DE OPORTUNIDAD.\n\nSe puede optimizar la busqueda futura añadiendo más parametros como valor de oportunidad o datos que sean 100% seguros e inmutables." }, { "parameters": { "url": "=https://services.leadconnectorhq.com/locations/{{ $('DATOS API').item.json['Location ID'] }}/customFields", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "model", "value": "opportunity" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "options": { "redirect": { "redirect": { "maxRedirects": 90 } } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 3008, -32 ], "id": "cc37ea9b-0a9f-44ce-8ce2-ee2444822ecf", "name": "Conseguir Custom Fields - Opportunity - MARCA" }, { "parameters": { "jsCode": "// ── DATOS MARCA ──────────────────────────────────────────────────────────────\nconst marcaOppData = $('Obtener info de Oportunidad - MARCA').first().json;\nconst marcaOpp = marcaOppData.opportunity;\nconst marcaCustomFieldsDefs = $('Conseguir Custom Fields - Opportunity - MARCA').first().json.customFields;\nconst marcaPipelines = $input.first().json.pipelines;\n\n// ── DATOS SUCURSAL (ya enriquecidos) ─────────────────────────────────────────\nconst sucursalOpp = $('Mapeo completo oportunidad origen - SUCURSAL').first().json.opportunity;\n\n// ── MAP PIPELINES MARCA: name -> { id, stages } ───────────────────────────────\nconst marcaPipelineByName = {};\nconst marcaStageByName = {};\nfor (const pipeline of marcaPipelines) {\n marcaPipelineByName[pipeline.name.trim()] = pipeline.id;\n for (const stage of pipeline.stages) {\n marcaStageByName[stage.name.trim()] = stage.id;\n }\n}\n\n// ── RESOLVER PIPELINE Y STAGE POR NAME DESDE SUCURSAL ────────────────────────\nconst resolvedPipelineId = marcaPipelineByName[sucursalOpp.pipelineName?.trim()] || marcaOpp.pipelineId;\nconst resolvedStageId = marcaStageByName[sucursalOpp.pipelineStageName?.trim()] || marcaOpp.pipelineStageId;\n\n// ── MAP CUSTOM FIELDS SUCURSAL: name -> fieldValue ────────────────────────────\nconst sucursalValueByName = {};\nfor (const cf of sucursalOpp.customFields) {\n if (cf.name) {\n sucursalValueByName[cf.name.trim()] = cf.fieldValue;\n }\n}\n\n// ── CONSTRUIR CUSTOM FIELDS PARA EL BODY ─────────────────────────────────────\nconst customFields = [];\nfor (const def of marcaCustomFieldsDefs) {\n const nameKey = def.name.trim();\n const sucursalValue = sucursalValueByName[nameKey];\n const marcaOriginal = marcaOpp.customFields?.find(cf => cf.id === def.id);\n const fieldValue = sucursalValue !== undefined ? sucursalValue : (marcaOriginal?.fieldValue ?? null);\n\n if (fieldValue === null) continue;\n\n customFields.push({\n id: def.id,\n key: def.fieldKey,\n field_value: fieldValue\n });\n}\n\n// ── CONSTRUIR BODY VÁLIDO PARA UPDATE OPPORTUNITY ────────────────────────────\nconst body = {\n pipelineId: resolvedPipelineId,\n name: sucursalOpp.name,\n pipelineStageId: resolvedStageId,\n status: sucursalOpp.status,\n monetaryValue: sucursalOpp.monetaryValue,\n source: sucursalOpp.source,\n customFields: customFields\n};\n\nreturn [{ json: {\n opportunityId: marcaOpp.id,\n body: JSON.stringify(body)\n} }];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 3632, -32 ], "id": "3b547c2a-a541-4b48-8d97-ea2d5df52010", "name": "Code in JavaScript" }, { "parameters": { "method": "POST", "url": "https://services.leadconnectorhq.com/contacts/search", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"locationId\": \"{{ $('DATOS API').item.json['Location ID'] }}\",\n \"pageLimit\": 10,\n \"query\": \"{{ $('Datos de Lead').item.json.Cliente.Telefono || $('Datos de Lead').item.json.Cliente.Email }}\"\n}", "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 3360, 960 ], "id": "02cd0fd6-6bb8-4faa-b85f-5d42663fba29", "name": "Buscar Contacto en MARCA", "notes": "Busca contacto en la location de marca por email.\nSi no encuentra, la siguiente IF deriva a creación." }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 }, "conditions": [ { "id": "exist-contact-check", "leftValue": "={{ $json.contacts ? $json.contacts.length : 0 }}", "rightValue": 0, "operator": { "type": "number", "operation": "gt" } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ 3600, 960 ], "id": "aa2644dc-34b4-4159-8afb-89147b12f5ee", "name": "¿Existe contacto en MARCA?" }, { "parameters": { "method": "POST", "url": "https://services.leadconnectorhq.com/contacts/upsert", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" }, { "name": "Content-Type", "value": "application/json" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"locationId\": \"{{ $('DATOS API').item.json['Location ID'] }}\",\n \"firstName\": \"{{ $('Datos de Lead').item.json.Cliente.Apellido }}\",\n \"name\": \"{{ $('Datos de Lead').item.json.Cliente['Nombre Completo'] }}\",\n \"email\": \"{{ $('Datos de Lead').item.json.Cliente.Email }}\",\n \"phone\": \"{{ $('Datos de Lead').item.json.Cliente.Telefono }}\",\n \"source\": \"Sincronización Sucursal\",\n \"tags\": [\"sincronizado-sucursal\"]\n}", "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 3840, 1104 ], "id": "f6c75352-3b9e-4fc9-b8e4-063c2792d190", "name": "Crear Contacto en MARCA", "notes": "Crea contacto en la marca solo si no existía.\nIMPORTANTE: revisa el mapeo de Nombre/Apellido, en el workflow original están invertidos." }, { "parameters": { "assignments": { "assignments": [ { "id": "contact-id-resolved", "name": "contactId", "value": "={{ $json.contact ? $json.contact.id : $json.contacts[0].id }}", "type": "string" } ] }, "options": {} }, "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [ 4080, 960 ], "id": "2a49d01e-6679-4584-9d9b-5778dfc4431e", "name": "Set Contact ID Resuelto", "notes": "Unifica el contactId tanto si vino de la búsqueda (contacts[0].id) como de la creación (contact.id)." }, { "parameters": { "url": "https://services.leadconnectorhq.com/opportunities/search", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "location_id", "value": "={{ $('DATOS API').item.json['Location ID'] }}" }, { "name": "contact_id", "value": "={{ $('Set Contact ID Resuelto').item.json.contactId }}" }, { "name": "limit", "value": "100" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "options": {} }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 4320, 960 ], "id": "8e25f660-3ed2-4597-9c2a-7480ac7d150f", "name": "Buscar Oportunidades del Contacto - MARCA", "notes": "Busca TODAS las oportunidades del contacto en la marca.\nDespués el Code de decisión elige cuál (o crea nueva)." }, { "parameters": { "jsCode": "// DECISION (Create vs Update) con idempotencia GLOBAL via mapeo Baserow (tabla 754).\n// (1) Si el mapeo id_opp_sucursal -> id_opp_marca existe -> UPDATE esa opp de Marca,\n// independiente del contacto resuelto (evita duplicados por contacto ambiguo).\n// (2) Si no hay mapeo, match por CF entre las opps del contacto resuelto.\n// (3) Si nada -> CREATE.\nconst result = $input.first().json;\nconst opportunities = result.opportunities || [];\nconst sucursalOppId = $('Datos de Lead').first().json.Oportunidad.opportunity_id;\n\nlet action = 'CREATE';\nlet opportunityId = null;\nlet matchReason = '';\n\n// (1) Mapeo Baserow global\nlet baserowRows = [];\ntry { baserowRows = $('Buscar Mapeo Opp - Baserow').all().map(i => i.json); } catch (e) { baserowRows = []; }\nconst mapped = baserowRows.find(r =>\n String(r.id_opp_sucursal || '') === String(sucursalOppId) && String(r.id_opp_marca || '').trim()\n);\n\nif (mapped) {\n action = 'UPDATE';\n opportunityId = String(mapped.id_opp_marca).trim();\n matchReason = 'Match por mapeo Baserow (global, tabla 754)';\n} else {\n // (2) match por CF entre las opps del contacto resuelto\n const match = opportunities.find(o =>\n (o.customFields || []).some(cf => {\n const v = cf.fieldValueString ?? cf.fieldValue ?? '';\n return String(v) === String(sucursalOppId);\n })\n );\n if (match) {\n action = 'UPDATE';\n opportunityId = match.id;\n matchReason = 'Match por ID Oportunidad Sucursal (contacto)';\n } else {\n action = 'CREATE';\n matchReason = 'Sin match (Baserow ni contacto) -> CREATE (contacto tiene ' + opportunities.length + ' opps)';\n }\n}\n\nreturn [{\n json: {\n action,\n opportunityId,\n matchReason,\n sucursalOppId,\n contactId: $('Set Contact ID Resuelto').first().json.contactId,\n totalOppsContacto: opportunities.length\n }\n}];\n" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 4560, 960 ], "id": "6ca30f13-8503-427f-95ec-b243d30688ec", "name": "Decidir Match (Create vs Update)" }, { "parameters": { "rules": { "values": [ { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 }, "conditions": [ { "id": "switch-update", "leftValue": "={{ $json.action }}", "rightValue": "UPDATE", "operator": { "type": "string", "operation": "equals" } } ], "combinator": "and" }, "renameOutput": true, "outputKey": "UPDATE" }, { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 }, "conditions": [ { "id": "switch-create", "leftValue": "={{ $json.action }}", "rightValue": "CREATE", "operator": { "type": "string", "operation": "equals" } } ], "combinator": "and" }, "renameOutput": true, "outputKey": "CREATE" } ] }, "options": {} }, "type": "n8n-nodes-base.switch", "typeVersion": 3.2, "position": [ 4800, 960 ], "id": "bff7a5dc-b4af-4033-83ea-c508aa92264a", "name": "Switch UPDATE vs CREATE" }, { "parameters": { "url": "=https://services.leadconnectorhq.com/opportunities/{{ $('Decidir Match (Create vs Update)').item.json.opportunityId }}", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 5040, 816 ], "id": "83cd0fd7-1ee9-4896-926e-a0b752e216fe", "name": "Obtener info de Oportunidad - MARCA (v2)", "notes": "Sólo se ejecuta en rama UPDATE.\nReemplaza el nodo original 'Obtener info de Oportunidad - MARCA' que dependía de búsqueda por nombre." }, { "parameters": { "url": "=https://services.leadconnectorhq.com/locations/{{ $('DATOS API').item.json['Location ID'] }}/customFields", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "model", "value": "opportunity" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "options": { "redirect": { "redirect": { "maxRedirects": 90 } } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 5040, 1104 ], "id": "0fb2fdea-cf40-4dfb-abfa-c422282e5d2a", "name": "Conseguir Custom Fields - Opportunity - MARCA (CREATE)", "notes": "Necesitamos los custom fields de la marca también en la rama CREATE para mapear los valores que vienen de sucursal." }, { "parameters": { "url": "https://services.leadconnectorhq.com/opportunities/pipelines", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "locationId", "value": "={{ $('DATOS API').item.json['Location ID'] }}" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "options": {} }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 5280, 1104 ], "id": "58114758-f0fb-483a-bd5b-d28188880a02", "name": "Obtener Pipelines - MARCA (CREATE)" }, { "parameters": { "jsCode": "// ─── ARMAR BODY PARA CREAR OPORTUNIDAD EN MARCA ──────────────────────\n// Mapea custom fields por fieldKey (fallback name) y FIJA el campo de enlace\n// \"ID Oportunidad Sucursal\" = id de la opp de sucursal (idempotencia futura).\n\nconst sucursalOpp = $('Mapeo completo oportunidad origen - SUCURSAL').first().json.opportunity;\nconst marcaCustomFieldsDefs = $('Conseguir Custom Fields - Opportunity - MARCA (CREATE)').first().json.customFields || [];\nconst marcaPipelines = $('Obtener Pipelines - MARCA (CREATE)').first().json.pipelines || [];\nconst locationId = $('DATOS API').first().json['Location ID'];\nconst decision = $('Decidir Match (Create vs Update)').first().json;\nconst contactId = decision.contactId;\nconst sucursalOppId = decision.sucursalOppId;\n\nconst norm = (s) => (s || '').toString().trim().toLowerCase();\n\n// Map pipelines/stages de la marca por nombre normalizado\nconst marcaPipelineByName = {};\nconst marcaStageByName = {};\nfor (const pipeline of marcaPipelines) {\n marcaPipelineByName[norm(pipeline.name)] = pipeline.id;\n for (const stage of pipeline.stages) {\n marcaStageByName[norm(stage.name)] = stage.id;\n }\n}\n\nconst resolvedPipelineId = marcaPipelineByName[norm(sucursalOpp.pipelineName)];\nconst resolvedStageId = marcaStageByName[norm(sucursalOpp.pipelineStageName)];\n\nif (!resolvedPipelineId) {\n throw new Error(`No se encontró pipeline en marca: \"${sucursalOpp.pipelineName}\". Revisa que el nombre coincida.`);\n}\nif (!resolvedStageId) {\n throw new Error(`No se encontró stage en marca: \"${sucursalOpp.pipelineStageName}\". Revisa que el nombre coincida.`);\n}\n\n// Mapear custom fields: preferir fieldKey, fallback a name normalizado\nconst sucursalValueByFieldKey = {};\nconst sucursalValueByName = {};\nfor (const cf of sucursalOpp.customFields || []) {\n if (cf.fieldKey) sucursalValueByFieldKey[cf.fieldKey] = cf.fieldValue;\n if (cf.name) sucursalValueByName[norm(cf.name)] = cf.fieldValue;\n}\n\nconst customFields = [];\nfor (const def of marcaCustomFieldsDefs) {\n let value = sucursalValueByFieldKey[def.fieldKey];\n if (value === undefined && def.name) value = sucursalValueByName[norm(def.name)];\n if (value === undefined || value === null || value === '') continue;\n customFields.push({ id: def.id, key: def.fieldKey, field_value: value });\n}\n\n// FIJAR el campo de enlace \"ID Oportunidad Sucursal\" = id de la opp de sucursal\nconst linkDef = marcaCustomFieldsDefs.find(d =>\n d.fieldKey === 'opportunity.id_oportunidad_sucursal' || norm(d.name) === 'id oportunidad sucursal'\n);\nlet linkFieldFound = false;\nif (linkDef) {\n linkFieldFound = true;\n const idx = customFields.findIndex(c => c.id === linkDef.id);\n const entry = { id: linkDef.id, key: linkDef.fieldKey, field_value: sucursalOppId };\n if (idx >= 0) customFields[idx] = entry; else customFields.push(entry);\n}\n\nconst body = {\n pipelineId: resolvedPipelineId,\n locationId: locationId,\n name: sucursalOpp.name,\n pipelineStageId: resolvedStageId,\n status: sucursalOpp.status || 'open',\n contactId: contactId,\n monetaryValue: sucursalOpp.monetaryValue,\n source: sucursalOpp.source || 'Sincronización Sucursal',\n customFields: customFields\n};\n\nreturn [{\n json: {\n body: JSON.stringify(body),\n debug: { resolvedPipelineId, resolvedStageId, customFieldsCount: customFields.length, sucursalOppId, linkFieldFound }\n }\n}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 5520, 1104 ], "id": "2f9a63e7-277d-49de-8838-a00922c993b2", "name": "Armar Body - CREATE" }, { "parameters": { "method": "POST", "url": "https://services.leadconnectorhq.com/opportunities/", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" }, { "name": "Content-Type", "value": "application/json" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={{ $json.body }}", "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 5760, 1104 ], "id": "fc4b3398-91bb-4dd9-b406-96c8d75a17be", "name": "Crear Oportunidad - MARCA" }, { "parameters": { "jsCode": "// ─── ARMAR BODY PARA ACTUALIZAR OPORTUNIDAD EN MARCA (v2) ────────────\n// Mapea CF por fieldKey (fallback name) y reafirma el campo de enlace\n// \"ID Oportunidad Sucursal\" = id de la opp de sucursal (idempotencia).\n\nconst marcaOppData = $('Obtener info de Oportunidad - MARCA (v2)').first().json;\nconst marcaOpp = marcaOppData.opportunity;\nconst marcaCustomFieldsDefs = $('Conseguir Custom Fields - Opportunity - MARCA (UPDATE)').first().json.customFields || [];\nconst marcaPipelines = $('Obtener Pipelines - MARCA (UPDATE)').first().json.pipelines || [];\nconst sucursalOpp = $('Mapeo completo oportunidad origen - SUCURSAL').first().json.opportunity;\nconst decision = $('Decidir Match (Create vs Update)').first().json;\nconst sucursalOppId = decision.sucursalOppId;\n\nconst norm = (s) => (s || '').toString().trim().toLowerCase();\n\nconst marcaPipelineByName = {};\nconst marcaStageByName = {};\nfor (const pipeline of marcaPipelines) {\n marcaPipelineByName[norm(pipeline.name)] = pipeline.id;\n for (const stage of pipeline.stages) {\n marcaStageByName[norm(stage.name)] = stage.id;\n }\n}\n\nconst resolvedPipelineId = marcaPipelineByName[norm(sucursalOpp.pipelineName)] || marcaOpp.pipelineId;\nconst resolvedStageId = marcaStageByName[norm(sucursalOpp.pipelineStageName)] || marcaOpp.pipelineStageId;\n\nconst sucursalValueByFieldKey = {};\nconst sucursalValueByName = {};\nfor (const cf of sucursalOpp.customFields || []) {\n if (cf.fieldKey) sucursalValueByFieldKey[cf.fieldKey] = cf.fieldValue;\n if (cf.name) sucursalValueByName[norm(cf.name)] = cf.fieldValue;\n}\n\nconst customFields = [];\nfor (const def of marcaCustomFieldsDefs) {\n let value = sucursalValueByFieldKey[def.fieldKey];\n if (value === undefined && def.name) value = sucursalValueByName[norm(def.name)];\n if (value === undefined || value === null) {\n const marcaOriginal = marcaOpp.customFields?.find(cf => cf.id === def.id);\n value = marcaOriginal?.fieldValue;\n }\n if (value === undefined || value === null) continue;\n customFields.push({ id: def.id, key: def.fieldKey, field_value: value });\n}\n\n// Reafirmar el campo de enlace\nconst linkDef = marcaCustomFieldsDefs.find(d =>\n d.fieldKey === 'opportunity.id_oportunidad_sucursal' || norm(d.name) === 'id oportunidad sucursal'\n);\nlet linkFieldFound = false;\nif (linkDef) {\n linkFieldFound = true;\n const idx = customFields.findIndex(c => c.id === linkDef.id);\n const entry = { id: linkDef.id, key: linkDef.fieldKey, field_value: sucursalOppId };\n if (idx >= 0) customFields[idx] = entry; else customFields.push(entry);\n}\n\nconst body = {\n pipelineId: resolvedPipelineId,\n name: sucursalOpp.name,\n pipelineStageId: resolvedStageId,\n status: sucursalOpp.status || marcaOpp.status,\n monetaryValue: sucursalOpp.monetaryValue ?? marcaOpp.monetaryValue,\n source: sucursalOpp.source || marcaOpp.source,\n customFields: customFields\n};\n\nreturn [{\n json: {\n opportunityId: marcaOpp.id,\n body: JSON.stringify(body),\n debug: { matchReason: decision.matchReason, customFieldsCount: customFields.length, sucursalOppId, linkFieldFound }\n }\n}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 5280, 816 ], "id": "969e46cd-bbae-4372-9808-c939f63e3c02", "name": "Armar Body - UPDATE (v2)" }, { "parameters": { "method": "PUT", "url": "=https://services.leadconnectorhq.com/opportunities/{{ $json.opportunityId }}", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" }, { "name": "Content-Type", "value": "application/json" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={{ $json.body }}", "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 5520, 816 ], "id": "83929e08-7afd-4670-9c18-be22b8c3656f", "name": "Actualizar Oportunidad - MARCA (v2)" }, { "parameters": { "content": "# RAMA UPDATE\n## Oportunidad ya existe en marca → se actualiza", "height": 280, "width": 880, "color": 4 }, "type": "n8n-nodes-base.stickyNote", "position": [ 5008, 720 ], "typeVersion": 1, "id": "1c285234-8d90-49ef-8dac-c98cb379299a", "name": "Sticky Update" }, { "parameters": { "content": "# RAMA CREATE\n## Oportunidad no existe en marca → se crea desde cero\n### Incluye contacto + custom fields + tag origin-id", "height": 280, "width": 1120, "color": 5 }, "type": "n8n-nodes-base.stickyNote", "position": [ 5008, 1024 ], "typeVersion": 1, "id": "7e8f350c-9562-485b-8ce5-1b13b4086856", "name": "Sticky Create" }, { "parameters": { "content": "# MATCHING ROBUSTO\n## 1. Buscar/crear contacto en marca\n## 2. Buscar oportunidades DEL CONTACTO\n## 3. Decidir match por cantidad + tag origin-id", "height": 320, "width": 1500, "color": 6 }, "type": "n8n-nodes-base.stickyNote", "position": [ 3328, 864 ], "typeVersion": 1, "id": "8a583e46-41b6-44e0-9313-b70ee085b740", "name": "Sticky Matching" }, { "parameters": { "url": "=https://services.leadconnectorhq.com/locations/{{ $('DATOS API').item.json['Location ID'] }}/customFields", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "model", "value": "opportunity" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "options": { "redirect": { "redirect": { "maxRedirects": 90 } } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 5040, 560 ], "id": "45f0a6b0-f44d-4e83-b2ab-cdd3fbfe7911", "name": "Conseguir Custom Fields - Opportunity - MARCA (UPDATE)", "notes": "Necesitamos los custom fields de la marca también en la rama CREATE para mapear los valores que vienen de sucursal." }, { "parameters": { "url": "https://services.leadconnectorhq.com/opportunities/pipelines", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "locationId", "value": "={{ $('DATOS API').item.json['Location ID'] }}" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "options": {} }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 5280, 560 ], "id": "5ca962a9-9e56-42d1-af05-ce05d39ed77f", "name": "Obtener Pipelines - MARCA (UPDATE)" }, { "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": "={{ 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 } ] }) }}", "options": {} }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 1328, -32 ], "id": "a9572dee-ed57-4104-966a-4b22721e75f1", "name": "Mapear ID Oportunidad Sucursal - SUCURSAL", "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." }, { "parameters": { "databaseId": 63, "tableId": 754, "limit": 1, "additionalOptions": { "filters": { "fields": [ { "field": 7280, "value": "={{ $('Datos de Lead').item.json.Oportunidad.opportunity_id }}" } ] } } }, "type": "n8n-nodes-base.baserow", "typeVersion": 1.1, "position": [ 4200, 1140 ], "id": "a64fdffd-ab8f-4ddd-a4d4-4d683a05132d", "name": "Buscar Mapeo Opp - Baserow", "credentials": { "baserowApi": { "id": "LZztQ3WMpzXjSTIH", "name": "Baserow account" } }, "alwaysOutputData": true, "onError": "continueRegularOutput", "notes": "Idempotencia global: busca en la tabla 754 el mapeo id_opp_sucursal->id_opp_marca. Si existe, 'Decidir Match' hara UPDATE de esa opp aunque el contacto resuelto sea otro. alwaysOutputData + onError para no romper el flujo si no hay match o si Baserow falla." } ], "connections": { "Webhook": { "main": [ [ { "node": "Datos de Lead", "type": "main", "index": 0 } ] ] }, "Datos de Lead": { "main": [ [ { "node": "Omitir @ezcorp.com", "type": "main", "index": 0 } ] ] }, "DATOS API": { "main": [ [ { "node": "Buscar Contacto en MARCA", "type": "main", "index": 0 } ] ] }, "Omitir @ezcorp.com": { "main": [ [ { "node": "API de Sucursal", "type": "main", "index": 0 } ] ] }, "Buscar Oportunidad - SUCURSAL": { "main": [ [ { "node": "Obtener info de Oportunidad - SUCURSAL", "type": "main", "index": 0 } ] ] }, "DATOS API - SUCURSAL": { "main": [ [ { "node": "Conseguir Custom Fields - Opportunity - SUCURSAL", "type": "main", "index": 0 } ] ] }, "Conseguir Custom Fields - Opportunity - SUCURSAL": { "main": [ [ { "node": "Mapear ID Oportunidad Sucursal - SUCURSAL", "type": "main", "index": 0 } ] ] }, "Obtener info de Oportunidad - SUCURSAL": { "main": [ [ { "node": "Obtener Pipelines - SUCURSAL", "type": "main", "index": 0 } ] ] }, "API de Sucursal": { "main": [ [ { "node": "DATOS API - SUCURSAL", "type": "main", "index": 0 } ] ] }, "API de MARCA": { "main": [ [ { "node": "DATOS API", "type": "main", "index": 0 } ] ] }, "Mapeo completo oportunidad origen - SUCURSAL": { "main": [ [ { "node": "API de MARCA", "type": "main", "index": 0 } ] ] }, "Obtener Pipelines - SUCURSAL": { "main": [ [ { "node": "Mapeo completo oportunidad origen - SUCURSAL", "type": "main", "index": 0 } ] ] }, "Obtener info de Oportunidad - MARCA": { "main": [ [ { "node": "Obtener Pipelines - MARCA", "type": "main", "index": 0 } ] ] }, "Obtener Pipelines - MARCA": { "main": [ [ { "node": "Code in JavaScript", "type": "main", "index": 0 } ] ] }, "Buscar Oportunidad - MARCA": { "main": [ [ { "node": "Conseguir Custom Fields - Opportunity - MARCA", "type": "main", "index": 0 } ] ] }, "Conseguir Custom Fields - Opportunity - MARCA": { "main": [ [ { "node": "Obtener info de Oportunidad - MARCA", "type": "main", "index": 0 } ] ] }, "Code in JavaScript": { "main": [ [ { "node": "Actualizar Oportunidad - MARCA2", "type": "main", "index": 0 } ] ] }, "Buscar Contacto en MARCA": { "main": [ [ { "node": "¿Existe contacto en MARCA?", "type": "main", "index": 0 } ] ] }, "¿Existe contacto en MARCA?": { "main": [ [ { "node": "Set Contact ID Resuelto", "type": "main", "index": 0 } ], [ { "node": "Crear Contacto en MARCA", "type": "main", "index": 0 } ] ] }, "Crear Contacto en MARCA": { "main": [ [ { "node": "Set Contact ID Resuelto", "type": "main", "index": 0 } ] ] }, "Set Contact ID Resuelto": { "main": [ [ { "node": "Buscar Mapeo Opp - Baserow", "type": "main", "index": 0 } ] ] }, "Buscar Oportunidades del Contacto - MARCA": { "main": [ [ { "node": "Decidir Match (Create vs Update)", "type": "main", "index": 0 } ] ] }, "Decidir Match (Create vs Update)": { "main": [ [ { "node": "Switch UPDATE vs CREATE", "type": "main", "index": 0 } ] ] }, "Switch UPDATE vs CREATE": { "main": [ [ { "node": "Obtener info de Oportunidad - MARCA (v2)", "type": "main", "index": 0 } ], [ { "node": "Conseguir Custom Fields - Opportunity - MARCA (CREATE)", "type": "main", "index": 0 } ] ] }, "Obtener info de Oportunidad - MARCA (v2)": { "main": [ [ { "node": "Conseguir Custom Fields - Opportunity - MARCA (UPDATE)", "type": "main", "index": 0 } ] ] }, "Armar Body - UPDATE (v2)": { "main": [ [ { "node": "Actualizar Oportunidad - MARCA (v2)", "type": "main", "index": 0 } ] ] }, "Conseguir Custom Fields - Opportunity - MARCA (CREATE)": { "main": [ [ { "node": "Obtener Pipelines - MARCA (CREATE)", "type": "main", "index": 0 } ] ] }, "Obtener Pipelines - MARCA (CREATE)": { "main": [ [ { "node": "Armar Body - CREATE", "type": "main", "index": 0 } ] ] }, "Armar Body - CREATE": { "main": [ [ { "node": "Crear Oportunidad - MARCA", "type": "main", "index": 0 } ] ] }, "Conseguir Custom Fields - Opportunity - MARCA (UPDATE)": { "main": [ [ { "node": "Obtener Pipelines - MARCA (UPDATE)", "type": "main", "index": 0 } ] ] }, "Obtener Pipelines - MARCA (UPDATE)": { "main": [ [ { "node": "Armar Body - UPDATE (v2)", "type": "main", "index": 0 } ] ] }, "Mapear ID Oportunidad Sucursal - SUCURSAL": { "main": [ [ { "node": "Buscar Oportunidad - SUCURSAL", "type": "main", "index": 0 } ] ] }, "Buscar Mapeo Opp - Baserow": { "main": [ [ { "node": "Buscar Oportunidades del Contacto - MARCA", "type": "main", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1", "binaryMode": "separate", "availableInMCP": false }, "staticData": null, "meta": { "templateCredsSetupCompleted": true }, "pinData": { "Webhook": [ { "json": { "headers": { "host": "webhookn8.consultoriae3.com", "user-agent": "axios/1.13.2", "content-length": "1839", "accept": "application/json, text/plain, */*", "accept-encoding": "gzip, compress, deflate, br", "content-type": "application/json", "traceparent": "00-00e6586cc6967f6985b8aa87332de4e0-932bdb81faeff7c4-01", "x-forwarded-for": "34.55.150.6", "x-forwarded-host": "webhookn8.consultoriae3.com", "x-forwarded-port": "443", "x-forwarded-proto": "https", "x-forwarded-server": "f569f6e85d30", "x-real-ip": "34.55.150.6" }, "params": {}, "query": {}, "body": { "¿Cuándo necesitas el dinero?": "", "[Número de Teléfono para Atender]": "", "Información Adicional": "", "Presupuesto": "", "CANAL DE ORIGEN": "", "[Número de WhatsApp para Atender]": "", "[Dirección de la Empresa]": "", "Año del Vehículo": "2015", "¿Qué modalidad prefieres?": "Tradicional (Resguardo)", "Marca del Vehiculo": "RENAULT", "TIENDA": "TAMPICO", "Sucursal": "Tampico, Tamaulipas", "Descripción": "", "[Correo_Empresa]": "", "ID Contacto Monte Providencia": "", "Fuente de Prospecto": "REDES SOCIALES", "[Correo_Canalizados]": "", "Version del Vehiculo": "LOGAN", "Acepta los terminos para tu cotización": "", "[Nombre de la Empresa]": "", "Check Comunicaciones de Marketing": "", "Archivos Adicionales": "", "contact_id": "B9oJWsFXy6Ol9NdHL5Jh", "first_name": "RAUL", "last_name": "LOGAN", "full_name": "RAUL LOGAN", "email": "raulsincorreo@gmail.com", "phone": "+528332937527", "tags": "sucursal", "country": "MX", "date_created": "2026-05-27T21:16:44.369Z", "full_address": "", "contact_type": "lead", "opportunity_name": "RAUL LOGAN", "status": "open", "lead_value": 40000, "opportunity_source": "REDES SOCIALES", "source": "REDES SOCIALES", "pipleline_stage": "Cliente interesado", "pipeline_id": "ep1d4VpzRezVqWayFbBf", "id": "NuFArKAQL72I8QC69MDa", "pipeline_name": "Standar", "user": { "firstName": "Tampico - 85969", "lastName": "Tampico", "email": "ezstore85969@ezcorp.com" }, "owner": "Tampico - 85969 Tampico", "location": { "name": "85969 - MP - Tampico", "address": "Tampico", "city": "Tampico", "state": "Tamaulipas", "country": "MX", "postalCode": "10000", "fullAddress": "Tampico, Tampico Tamaulipas 10000", "id": "WCHyow6KpjLFYriQWdbJ" }, "workflow": { "id": "8ba8fdf1-85f2-4f1f-bf28-56400e1adcd6", "name": "Sincronizar Oportunidad V2" }, "triggerData": {}, "contact": { "attributionSource": { "sessionSource": "CRM UI", "mediumId": null, "medium": "manual" }, "lastAttributionSource": {} }, "attributionSource": {}, "customData": {} }, "webhookUrl": "https://webhookn8.consultoriae3.com/webhook/3eecb45a-e24c-49ac-aef7-99843f485819", "executionMode": "production" }, "pairedItem": { "item": 0 } } ] }, "versionId": "9caa764a-a07e-4c73-aa6a-f95fd5c8aa4d", "activeVersionId": "9caa764a-a07e-4c73-aa6a-f95fd5c8aa4d", "versionCounter": 428, "triggerCount": 1, "shared": [ { "updatedAt": "2026-03-02T01:12:56.387Z", "createdAt": "2026-03-02T01:12:56.387Z", "role": "workflow:owner", "workflowId": "Cfgwp0bOtDW8zuKW", "projectId": "aycNlMpnzsxvXbfG", "project": { "updatedAt": "2025-11-27T04:06:26.313Z", "createdAt": "2025-11-27T03:54:24.410Z", "id": "aycNlMpnzsxvXbfG", "name": "Consultoria E3 ® ", "type": "personal", "icon": null, "description": null, "creatorId": "74a7f127-b963-4eb0-aff4-1190428e8409" } } ], "tags": [ { "updatedAt": "2025-11-27T05:48:12.272Z", "createdAt": "2025-11-27T05:48:12.272Z", "id": "pHkPpq3Httzx4hnb", "name": "Bucefalo" } ], "activeVersion": { "updatedAt": "2026-05-30T15:55:46.494Z", "createdAt": "2026-05-30T15:55:46.494Z", "versionId": "9caa764a-a07e-4c73-aa6a-f95fd5c8aa4d", "workflowId": "Cfgwp0bOtDW8zuKW", "nodes": [ { "parameters": { "httpMethod": "POST", "path": "3eecb45a-e24c-49ac-aef7-99843f485819", "options": {} }, "type": "n8n-nodes-base.webhook", "typeVersion": 2.1, "position": [ -336, -16 ], "id": "dd424583-8295-4013-96ba-c7e29ea944c6", "name": "Webhook", "webhookId": "3eecb45a-e24c-49ac-aef7-99843f485819" }, { "parameters": { "assignments": { "assignments": [ { "id": "8a998fd4-2de6-4895-ab3d-e052e823d1b8", "name": "Cliente.Fuente Posible Cliente", "value": "={{ $json.body['Fuente de Posible cliente'] }}", "type": "string" }, { "id": "938c6fec-ae16-4e7a-ba2a-f450794fa40d", "name": "Cliente.Fecha de creación", "value": "={{ $json.body.date_created }}", "type": "string" }, { "id": "b56a1939-2608-47c8-85ad-b60b557d2a27", "name": "Cliente.Sucursal.Sucursal", "value": "={{ $json.body.Sucursal }}", "type": "string" }, { "id": "0d07b9c9-4450-497b-ab81-3baa441787fb", "name": "Vehiculo.Versión.Versión", "value": "={{ $json.body['Version del Vehiculo'] }}", "type": "string" }, { "id": "75e3f337-00d1-429d-8d5b-85ec18e6c5e4", "name": "Vehiculo.Marca.Marca", "value": "={{ $json.body['Marca del Vehiculo'] }}", "type": "string" }, { "id": "cb09c536-fe84-4598-aaae-aa79f2eda61b", "name": "Vehiculo.Marca.fieldKey", "value": "=contact.marca_del_vehiculo", "type": "string" }, { "id": "17d36409-4c54-48dd-8100-f7f667fd2415", "name": "Vehiculo.Año.Año", "value": "={{ $json.body['Año del Vehículo'] }}", "type": "string" }, { "id": "a1886afc-b0af-4950-9752-f8bfff594896", "name": "Vehiculo.Modalidad.Modalidad", "value": "={{ $json.body['¿Qué modalidad prefieres?'] }}", "type": "string" }, { "id": "33b2c28a-1ad3-4c74-917f-3cd718a3a709", "name": "Cliente.Nombre", "value": "={{ $json.body['Información Adicional'] }}", "type": "string" }, { "id": "b36131ac-2d88-41f8-8f0f-7640cdb02b57", "name": "Cliente.Apellido", "value": "={{ $json.body.first_name }}", "type": "string" }, { "id": "ae252c8f-f0a1-41d9-a21d-04ca949f01c8", "name": "Cliente.Nombre Completo", "value": "={{ $json.body.full_name }}", "type": "string" }, { "id": "342a9377-0ded-4f23-b93b-1f76e57c0cbd", "name": "Cliente.Email", "value": "={{ $json.body.email }}", "type": "string" }, { "id": "cf1b7058-96c2-4c73-9250-719a88b68673", "name": "Cliente.Telefono", "value": "={{ $json.body.phone }}", "type": "string" }, { "id": "0b916193-15e8-4a91-9ff2-0a6f262b3c38", "name": "Cliente.Contact ID", "value": "={{ $json.body.contact_id }}", "type": "string" }, { "id": "67eeaa9b-f703-4521-82af-9d2797131edc", "name": "Cliente.Sucursal.fieldKey", "value": "contact.sucursal", "type": "string" }, { "id": "b05ea7bb-bbaa-467b-8247-eabb162ff029", "name": "Vehiculo.Versión.fieldKey", "value": "contact.version_del_vehiculo", "type": "string" }, { "id": "9891b919-ef4c-46bd-8414-6d916565d896", "name": "Vehiculo.Año.fieldKey", "value": "contact.ano_del_vehiculo", "type": "string" }, { "id": "0b6bf582-49c1-41de-9c2e-6ae85c4e41e8", "name": "Vehiculo.Modalidad.fieldKey", "value": "contact.que_modalidad_prefieres", "type": "string" }, { "id": "b02bc821-6121-452d-a042-623fac6e443c", "name": "Oportunidad.opportunity_name", "value": "={{ $json.body.opportunity_name }}", "type": "string" }, { "id": "898817a2-7926-4ddf-b785-cac8e28afc58", "name": "Oportunidad.pipleline_stage (new)", "value": "={{ $json.body.pipleline_stage }}", "type": "string" }, { "id": "opp-id-sucursal-capture", "name": "Oportunidad.opportunity_id", "value": "={{ $json.body.id }}", "type": "string" } ] }, "options": {} }, "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [ -96, -16 ], "id": "2b3ec130-27ce-4988-82db-46e4f12c3f7d", "name": "Datos de Lead" }, { "parameters": { "content": "# OBTENER DATOS DE SUCURSAL", "height": 352, "width": 1152 }, "type": "n8n-nodes-base.stickyNote", "position": [ 1072, -144 ], "typeVersion": 1, "id": "19023e33-a9f1-4c60-b87c-957e751e3dc2", "name": "Sticky Note" }, { "parameters": { "content": "# OBTENER DATOS DE MARCA", "height": 208, "width": 1188, "color": 7 }, "type": "n8n-nodes-base.stickyNote", "position": [ 2240, -80 ], "typeVersion": 1, "id": "3a3d4f18-1a08-4dbc-a00b-7ae6bc4d49d1", "name": "Sticky Note1" }, { "parameters": { "assignments": { "assignments": [ { "id": "55ff7d12-17b9-4bec-a324-e633020b131d", "name": "Name Location", "value": "={{ $json.Nombre }}", "type": "string" }, { "id": "d877c8cd-db32-4c16-96dd-4eeb2dc48efe", "name": "Location ID", "value": "={{ $json.Location_ID }}", "type": "string" }, { "id": "7698f395-5db8-415b-919e-3ad61c6566f8", "name": "Token/API", "value": "={{ $json.API_token }}", "type": "string" } ] }, "options": {} }, "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [ 2480, -32 ], "id": "a46df506-6a9a-420d-9cdd-6fc51d1a691e", "name": "DATOS API" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 }, "conditions": [ { "id": "44d54b9e-d192-4b54-bf0c-156b79afc6e2", "leftValue": "={{ $json.Cliente.Email }}", "rightValue": "@ezcorp.com", "operator": { "type": "string", "operation": "notContains" } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ 80, -16 ], "id": "25db982f-7bc7-4318-a7b0-e94326abc437", "name": "Omitir @ezcorp.com" }, { "parameters": { "method": "PUT", "url": "=https://services.leadconnectorhq.com/opportunities/{{ $json.opportunityId }}", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={{ $json.body }}", "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 3952, -32 ], "id": "2320b102-816e-4a0c-ae9c-e305d25df6df", "name": "Actualizar Oportunidad - MARCA2", "notes": "El código mapea los custom fields de una oportunidad de una sucursal hacia los IDs equivalentes de una marca. Toma tres fuentes: los metadatos de campos de la sucursal, los valores reales de esos campos en la oportunidad, y los metadatos de campos de la marca. Para cada campo con valor en la oportunidad, primero busca su `fieldKey` en los metadatos de la sucursal usando el `id`, luego usa ese `fieldKey` para encontrar el campo equivalente en la marca, y construye un array con el `id` y `key` de la marca pero con el valor original de la sucursal. Finalmente arma el body de una petición para crear/actualizar una oportunidad en la marca, reutilizando pipeline, nombre, stage y valor monetario de otros nodos, con los custom fields ya traducidos al contexto de la marca." }, { "parameters": { "method": "POST", "url": "https://services.leadconnectorhq.com/opportunities/search", "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'] }}" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"locationId\": \"{{ $('DATOS API - SUCURSAL').item.json['Location ID'] }}\",\n \"query\": \"{{ $('Datos de Lead').item.json.Oportunidad.opportunity_name }}\",\n \"limit\": 1,\n \"page\": 0\n}", "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 1536, -32 ], "id": "4e89658b-7ffd-4a3b-b91e-9ed3223a1a73", "name": "Buscar Oportunidad - SUCURSAL", "notes": "NECESITA MEJORAS\n\nActualmente solo hace busqueda con base al NOMBRE DE OPORTUNIDAD.\n\nSe puede optimizar la busqueda futura añadiendo más parametros como valor de oportunidad o datos que sean 100% seguros e inmutables." }, { "parameters": { "assignments": { "assignments": [ { "id": "55ff7d12-17b9-4bec-a324-e633020b131d", "name": "Name Location", "value": "={{ $json.Nombre }}", "type": "string" }, { "id": "d877c8cd-db32-4c16-96dd-4eeb2dc48efe", "name": "Location ID", "value": "={{ $json.Location_ID }}", "type": "string" }, { "id": "7698f395-5db8-415b-919e-3ad61c6566f8", "name": "Token/API", "value": "={{ $json.API_token }}", "type": "string" } ] }, "options": {} }, "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [ 528, -32 ], "id": "b721a65d-bcbb-44ab-bb7f-8f200b34fcdd", "name": "DATOS API - SUCURSAL" }, { "parameters": { "url": "=https://services.leadconnectorhq.com/locations/{{ $('DATOS API - SUCURSAL').item.json['Location ID'] }}/customFields", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "model", "value": "opportunity" } ] }, "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'] }}" } ] }, "options": { "redirect": { "redirect": { "maxRedirects": 90 } } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 1136, -32 ], "id": "39ef9dcc-ac20-4ba2-b891-2a2baa6ea4f5", "name": "Conseguir Custom Fields - Opportunity - SUCURSAL" }, { "parameters": { "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'] }}" } ] }, "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 1712, -32 ], "id": "fbd46ae4-792b-451b-b99e-9816dc175d52", "name": "Obtener info de Oportunidad - SUCURSAL" }, { "parameters": { "content": "# ACTUALIZAR OPORTUNIDAD - MARCA", "height": 352, "width": 928 }, "type": "n8n-nodes-base.stickyNote", "position": [ 3456, -144 ], "typeVersion": 1, "id": "f3ca1cfe-08e2-485b-b238-9240f5753809", "name": "Sticky Note2" }, { "parameters": { "content": "", "height": 208, "width": 992, "color": 3 }, "type": "n8n-nodes-base.stickyNote", "position": [ 2768, -64 ], "typeVersion": 1, "id": "45066721-8404-48ed-94c1-c88edf48bca5", "name": "Sticky Note5" }, { "parameters": { "content": "", "height": 192, "width": 928, "color": 3 }, "type": "n8n-nodes-base.stickyNote", "position": [ 1104, -64 ], "typeVersion": 1, "id": "b1646bb4-8b64-4bf4-b380-189cc7902741", "name": "Sticky Note7" }, { "parameters": { "databaseId": 63, "tableId": 749, "limit": 1, "additionalOptions": { "filters": { "fields": [ { "field": 7235, "value": "={{ $('Webhook').item.json.body.location.name }}" } ] } } }, "type": "n8n-nodes-base.baserow", "typeVersion": 1.1, "position": [ 320, -32 ], "id": "12088f29-8bb4-475d-ae0e-2cbdf8033138", "name": "API de Sucursal", "credentials": { "baserowApi": { "id": "LZztQ3WMpzXjSTIH", "name": "Baserow account" } } }, { "parameters": { "databaseId": 63, "tableId": 749, "limit": 1, "additionalOptions": { "filters": { "fields": [ { "field": 7235, "value": "=Monte Providencia" } ] } } }, "type": "n8n-nodes-base.baserow", "typeVersion": 1.1, "position": [ 2288, -32 ], "id": "8c8fa238-6ce4-4adf-8926-b603987a55cf", "name": "API de MARCA", "credentials": { "baserowApi": { "id": "LZztQ3WMpzXjSTIH", "name": "Baserow account" } } }, { "parameters": { "jsCode": "const opportunityData = $('Obtener info de Oportunidad - SUCURSAL').first().json;\nconst opportunity = opportunityData.opportunity;\nconst customFieldsDefs = $('Conseguir Custom Fields - Opportunity - SUCURSAL').first().json.customFields;\nconst pipelines = $input.first().json.pipelines;\n\n// Map custom fields: id -> { fieldKey, name }\nconst fieldMap = {};\nfor (const def of customFieldsDefs) {\n fieldMap[def.id] = { fieldKey: def.fieldKey, name: def.name };\n}\n\n// Map pipelines: id -> name, stages: id -> { name, position, stageWinProbability }\nconst pipelineMap = {};\nconst stageMap = {};\nfor (const pipeline of pipelines) {\n pipelineMap[pipeline.id] = pipeline.name;\n for (const stage of pipeline.stages) {\n stageMap[stage.id] = {\n name: stage.name,\n position: stage.position,\n stageWinProbability: stage.stageWinProbability,\n color: stage.color || null\n };\n }\n}\n\n// Enrich custom fields with fieldKey and name\nconst enrichedCustomFields = opportunity.customFields.map(cf => ({\n id: cf.id,\n name: fieldMap[cf.id]?.name || null,\n fieldKey: fieldMap[cf.id]?.fieldKey || null,\n fieldValue: cf.fieldValue\n}));\n\n// Resolve pipeline and stage info\nconst stageInfo = stageMap[opportunity.pipelineStageId] || {};\n\n// Build enriched opportunity\nconst enrichedOpportunity = {\n ...opportunity,\n pipelineName: pipelineMap[opportunity.pipelineId] || null,\n pipelineStageName: stageInfo.name || null,\n pipelineStagePosition: stageInfo.position ?? null,\n pipelineStageWinProbability: stageInfo.stageWinProbability ?? null,\n pipelineStageColor: stageInfo.color || null,\n customFields: enrichedCustomFields\n};\n\nreturn [{ json: { opportunity: enrichedOpportunity, traceId: opportunityData.traceId } }];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 2080, -32 ], "id": "d9609dd9-9493-4f3d-b356-99438cedada6", "name": "Mapeo completo oportunidad origen - SUCURSAL" }, { "parameters": { "url": "https://services.leadconnectorhq.com/opportunities/pipelines", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "locationId", "value": "={{ $('Webhook').item.json.body.location.id }}" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('API de Sucursal').item.json.API_token }}" } ] }, "sendBody": true, "bodyParameters": { "parameters": [ {} ] }, "options": {} }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 1872, -32 ], "id": "2d799ae3-b6b1-4e4f-8774-714ebe4f009f", "name": "Obtener Pipelines - SUCURSAL" }, { "parameters": { "url": "=https://services.leadconnectorhq.com/opportunities/{{ $('Buscar Oportunidad - MARCA').item.json.opportunities[0].id }}", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 3216, -32 ], "id": "1eee43d2-c6a8-414b-bebf-4b31d6fb34d7", "name": "Obtener info de Oportunidad - MARCA" }, { "parameters": { "url": "https://services.leadconnectorhq.com/opportunities/pipelines", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "locationId", "value": "={{ $('API de MARCA').item.json.Location_ID }}" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('API de MARCA').item.json.API_token }}" } ] }, "sendBody": true, "bodyParameters": { "parameters": [ {} ] }, "options": {} }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 3424, -32 ], "id": "20a1a288-2cd8-471b-9203-5ba88770edb0", "name": "Obtener Pipelines - MARCA" }, { "parameters": { "method": "POST", "url": "https://services.leadconnectorhq.com/opportunities/search", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $json['Token/API'] }}" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"locationId\": \"{{ $json['Location ID'] }}\",\n \"query\": \"{{ $('Datos de Lead').item.json.Oportunidad.opportunity_name }}\",\n \"limit\": 1,\n \"page\": 0\n}", "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 2800, -32 ], "id": "798a7e51-b8ed-4364-947a-7396fab47940", "name": "Buscar Oportunidad - MARCA", "notes": "NECESITA MEJORAS\n\nActualmente solo hace busqueda con base al NOMBRE DE OPORTUNIDAD.\n\nSe puede optimizar la busqueda futura añadiendo más parametros como valor de oportunidad o datos que sean 100% seguros e inmutables." }, { "parameters": { "url": "=https://services.leadconnectorhq.com/locations/{{ $('DATOS API').item.json['Location ID'] }}/customFields", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "model", "value": "opportunity" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "options": { "redirect": { "redirect": { "maxRedirects": 90 } } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 3008, -32 ], "id": "cc37ea9b-0a9f-44ce-8ce2-ee2444822ecf", "name": "Conseguir Custom Fields - Opportunity - MARCA" }, { "parameters": { "jsCode": "// ── DATOS MARCA ──────────────────────────────────────────────────────────────\nconst marcaOppData = $('Obtener info de Oportunidad - MARCA').first().json;\nconst marcaOpp = marcaOppData.opportunity;\nconst marcaCustomFieldsDefs = $('Conseguir Custom Fields - Opportunity - MARCA').first().json.customFields;\nconst marcaPipelines = $input.first().json.pipelines;\n\n// ── DATOS SUCURSAL (ya enriquecidos) ─────────────────────────────────────────\nconst sucursalOpp = $('Mapeo completo oportunidad origen - SUCURSAL').first().json.opportunity;\n\n// ── MAP PIPELINES MARCA: name -> { id, stages } ───────────────────────────────\nconst marcaPipelineByName = {};\nconst marcaStageByName = {};\nfor (const pipeline of marcaPipelines) {\n marcaPipelineByName[pipeline.name.trim()] = pipeline.id;\n for (const stage of pipeline.stages) {\n marcaStageByName[stage.name.trim()] = stage.id;\n }\n}\n\n// ── RESOLVER PIPELINE Y STAGE POR NAME DESDE SUCURSAL ────────────────────────\nconst resolvedPipelineId = marcaPipelineByName[sucursalOpp.pipelineName?.trim()] || marcaOpp.pipelineId;\nconst resolvedStageId = marcaStageByName[sucursalOpp.pipelineStageName?.trim()] || marcaOpp.pipelineStageId;\n\n// ── MAP CUSTOM FIELDS SUCURSAL: name -> fieldValue ────────────────────────────\nconst sucursalValueByName = {};\nfor (const cf of sucursalOpp.customFields) {\n if (cf.name) {\n sucursalValueByName[cf.name.trim()] = cf.fieldValue;\n }\n}\n\n// ── CONSTRUIR CUSTOM FIELDS PARA EL BODY ─────────────────────────────────────\nconst customFields = [];\nfor (const def of marcaCustomFieldsDefs) {\n const nameKey = def.name.trim();\n const sucursalValue = sucursalValueByName[nameKey];\n const marcaOriginal = marcaOpp.customFields?.find(cf => cf.id === def.id);\n const fieldValue = sucursalValue !== undefined ? sucursalValue : (marcaOriginal?.fieldValue ?? null);\n\n if (fieldValue === null) continue;\n\n customFields.push({\n id: def.id,\n key: def.fieldKey,\n field_value: fieldValue\n });\n}\n\n// ── CONSTRUIR BODY VÁLIDO PARA UPDATE OPPORTUNITY ────────────────────────────\nconst body = {\n pipelineId: resolvedPipelineId,\n name: sucursalOpp.name,\n pipelineStageId: resolvedStageId,\n status: sucursalOpp.status,\n monetaryValue: sucursalOpp.monetaryValue,\n source: sucursalOpp.source,\n customFields: customFields\n};\n\nreturn [{ json: {\n opportunityId: marcaOpp.id,\n body: JSON.stringify(body)\n} }];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 3632, -32 ], "id": "3b547c2a-a541-4b48-8d97-ea2d5df52010", "name": "Code in JavaScript" }, { "parameters": { "method": "POST", "url": "https://services.leadconnectorhq.com/contacts/search", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"locationId\": \"{{ $('DATOS API').item.json['Location ID'] }}\",\n \"pageLimit\": 10,\n \"query\": \"{{ $('Datos de Lead').item.json.Cliente.Telefono || $('Datos de Lead').item.json.Cliente.Email }}\"\n}", "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 3360, 960 ], "id": "02cd0fd6-6bb8-4faa-b85f-5d42663fba29", "name": "Buscar Contacto en MARCA", "notes": "Busca contacto en la location de marca por email.\nSi no encuentra, la siguiente IF deriva a creación." }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 }, "conditions": [ { "id": "exist-contact-check", "leftValue": "={{ $json.contacts ? $json.contacts.length : 0 }}", "rightValue": 0, "operator": { "type": "number", "operation": "gt" } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ 3600, 960 ], "id": "aa2644dc-34b4-4159-8afb-89147b12f5ee", "name": "¿Existe contacto en MARCA?" }, { "parameters": { "method": "POST", "url": "https://services.leadconnectorhq.com/contacts/upsert", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" }, { "name": "Content-Type", "value": "application/json" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"locationId\": \"{{ $('DATOS API').item.json['Location ID'] }}\",\n \"firstName\": \"{{ $('Datos de Lead').item.json.Cliente.Apellido }}\",\n \"name\": \"{{ $('Datos de Lead').item.json.Cliente['Nombre Completo'] }}\",\n \"email\": \"{{ $('Datos de Lead').item.json.Cliente.Email }}\",\n \"phone\": \"{{ $('Datos de Lead').item.json.Cliente.Telefono }}\",\n \"source\": \"Sincronización Sucursal\",\n \"tags\": [\"sincronizado-sucursal\"]\n}", "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 3840, 1104 ], "id": "f6c75352-3b9e-4fc9-b8e4-063c2792d190", "name": "Crear Contacto en MARCA", "notes": "Crea contacto en la marca solo si no existía.\nIMPORTANTE: revisa el mapeo de Nombre/Apellido, en el workflow original están invertidos." }, { "parameters": { "assignments": { "assignments": [ { "id": "contact-id-resolved", "name": "contactId", "value": "={{ $json.contact ? $json.contact.id : $json.contacts[0].id }}", "type": "string" } ] }, "options": {} }, "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [ 4080, 960 ], "id": "2a49d01e-6679-4584-9d9b-5778dfc4431e", "name": "Set Contact ID Resuelto", "notes": "Unifica el contactId tanto si vino de la búsqueda (contacts[0].id) como de la creación (contact.id)." }, { "parameters": { "url": "https://services.leadconnectorhq.com/opportunities/search", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "location_id", "value": "={{ $('DATOS API').item.json['Location ID'] }}" }, { "name": "contact_id", "value": "={{ $('Set Contact ID Resuelto').item.json.contactId }}" }, { "name": "limit", "value": "100" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "options": {} }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 4320, 960 ], "id": "8e25f660-3ed2-4597-9c2a-7480ac7d150f", "name": "Buscar Oportunidades del Contacto - MARCA", "notes": "Busca TODAS las oportunidades del contacto en la marca.\nDespués el Code de decisión elige cuál (o crea nueva)." }, { "parameters": { "jsCode": "// DECISION (Create vs Update) con idempotencia GLOBAL via mapeo Baserow (tabla 754).\n// (1) Si el mapeo id_opp_sucursal -> id_opp_marca existe -> UPDATE esa opp de Marca,\n// independiente del contacto resuelto (evita duplicados por contacto ambiguo).\n// (2) Si no hay mapeo, match por CF entre las opps del contacto resuelto.\n// (3) Si nada -> CREATE.\nconst result = $input.first().json;\nconst opportunities = result.opportunities || [];\nconst sucursalOppId = $('Datos de Lead').first().json.Oportunidad.opportunity_id;\n\nlet action = 'CREATE';\nlet opportunityId = null;\nlet matchReason = '';\n\n// (1) Mapeo Baserow global\nlet baserowRows = [];\ntry { baserowRows = $('Buscar Mapeo Opp - Baserow').all().map(i => i.json); } catch (e) { baserowRows = []; }\nconst mapped = baserowRows.find(r =>\n String(r.id_opp_sucursal || '') === String(sucursalOppId) && String(r.id_opp_marca || '').trim()\n);\n\nif (mapped) {\n action = 'UPDATE';\n opportunityId = String(mapped.id_opp_marca).trim();\n matchReason = 'Match por mapeo Baserow (global, tabla 754)';\n} else {\n // (2) match por CF entre las opps del contacto resuelto\n const match = opportunities.find(o =>\n (o.customFields || []).some(cf => {\n const v = cf.fieldValueString ?? cf.fieldValue ?? '';\n return String(v) === String(sucursalOppId);\n })\n );\n if (match) {\n action = 'UPDATE';\n opportunityId = match.id;\n matchReason = 'Match por ID Oportunidad Sucursal (contacto)';\n } else {\n action = 'CREATE';\n matchReason = 'Sin match (Baserow ni contacto) -> CREATE (contacto tiene ' + opportunities.length + ' opps)';\n }\n}\n\nreturn [{\n json: {\n action,\n opportunityId,\n matchReason,\n sucursalOppId,\n contactId: $('Set Contact ID Resuelto').first().json.contactId,\n totalOppsContacto: opportunities.length\n }\n}];\n" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 4560, 960 ], "id": "6ca30f13-8503-427f-95ec-b243d30688ec", "name": "Decidir Match (Create vs Update)" }, { "parameters": { "rules": { "values": [ { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 }, "conditions": [ { "id": "switch-update", "leftValue": "={{ $json.action }}", "rightValue": "UPDATE", "operator": { "type": "string", "operation": "equals" } } ], "combinator": "and" }, "renameOutput": true, "outputKey": "UPDATE" }, { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 }, "conditions": [ { "id": "switch-create", "leftValue": "={{ $json.action }}", "rightValue": "CREATE", "operator": { "type": "string", "operation": "equals" } } ], "combinator": "and" }, "renameOutput": true, "outputKey": "CREATE" } ] }, "options": {} }, "type": "n8n-nodes-base.switch", "typeVersion": 3.2, "position": [ 4800, 960 ], "id": "bff7a5dc-b4af-4033-83ea-c508aa92264a", "name": "Switch UPDATE vs CREATE" }, { "parameters": { "url": "=https://services.leadconnectorhq.com/opportunities/{{ $('Decidir Match (Create vs Update)').item.json.opportunityId }}", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 5040, 816 ], "id": "83cd0fd7-1ee9-4896-926e-a0b752e216fe", "name": "Obtener info de Oportunidad - MARCA (v2)", "notes": "Sólo se ejecuta en rama UPDATE.\nReemplaza el nodo original 'Obtener info de Oportunidad - MARCA' que dependía de búsqueda por nombre." }, { "parameters": { "url": "=https://services.leadconnectorhq.com/locations/{{ $('DATOS API').item.json['Location ID'] }}/customFields", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "model", "value": "opportunity" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "options": { "redirect": { "redirect": { "maxRedirects": 90 } } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 5040, 1104 ], "id": "0fb2fdea-cf40-4dfb-abfa-c422282e5d2a", "name": "Conseguir Custom Fields - Opportunity - MARCA (CREATE)", "notes": "Necesitamos los custom fields de la marca también en la rama CREATE para mapear los valores que vienen de sucursal." }, { "parameters": { "url": "https://services.leadconnectorhq.com/opportunities/pipelines", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "locationId", "value": "={{ $('DATOS API').item.json['Location ID'] }}" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "options": {} }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 5280, 1104 ], "id": "58114758-f0fb-483a-bd5b-d28188880a02", "name": "Obtener Pipelines - MARCA (CREATE)" }, { "parameters": { "jsCode": "// ─── ARMAR BODY PARA CREAR OPORTUNIDAD EN MARCA ──────────────────────\n// Mapea custom fields por fieldKey (fallback name) y FIJA el campo de enlace\n// \"ID Oportunidad Sucursal\" = id de la opp de sucursal (idempotencia futura).\n\nconst sucursalOpp = $('Mapeo completo oportunidad origen - SUCURSAL').first().json.opportunity;\nconst marcaCustomFieldsDefs = $('Conseguir Custom Fields - Opportunity - MARCA (CREATE)').first().json.customFields || [];\nconst marcaPipelines = $('Obtener Pipelines - MARCA (CREATE)').first().json.pipelines || [];\nconst locationId = $('DATOS API').first().json['Location ID'];\nconst decision = $('Decidir Match (Create vs Update)').first().json;\nconst contactId = decision.contactId;\nconst sucursalOppId = decision.sucursalOppId;\n\nconst norm = (s) => (s || '').toString().trim().toLowerCase();\n\n// Map pipelines/stages de la marca por nombre normalizado\nconst marcaPipelineByName = {};\nconst marcaStageByName = {};\nfor (const pipeline of marcaPipelines) {\n marcaPipelineByName[norm(pipeline.name)] = pipeline.id;\n for (const stage of pipeline.stages) {\n marcaStageByName[norm(stage.name)] = stage.id;\n }\n}\n\nconst resolvedPipelineId = marcaPipelineByName[norm(sucursalOpp.pipelineName)];\nconst resolvedStageId = marcaStageByName[norm(sucursalOpp.pipelineStageName)];\n\nif (!resolvedPipelineId) {\n throw new Error(`No se encontró pipeline en marca: \"${sucursalOpp.pipelineName}\". Revisa que el nombre coincida.`);\n}\nif (!resolvedStageId) {\n throw new Error(`No se encontró stage en marca: \"${sucursalOpp.pipelineStageName}\". Revisa que el nombre coincida.`);\n}\n\n// Mapear custom fields: preferir fieldKey, fallback a name normalizado\nconst sucursalValueByFieldKey = {};\nconst sucursalValueByName = {};\nfor (const cf of sucursalOpp.customFields || []) {\n if (cf.fieldKey) sucursalValueByFieldKey[cf.fieldKey] = cf.fieldValue;\n if (cf.name) sucursalValueByName[norm(cf.name)] = cf.fieldValue;\n}\n\nconst customFields = [];\nfor (const def of marcaCustomFieldsDefs) {\n let value = sucursalValueByFieldKey[def.fieldKey];\n if (value === undefined && def.name) value = sucursalValueByName[norm(def.name)];\n if (value === undefined || value === null || value === '') continue;\n customFields.push({ id: def.id, key: def.fieldKey, field_value: value });\n}\n\n// FIJAR el campo de enlace \"ID Oportunidad Sucursal\" = id de la opp de sucursal\nconst linkDef = marcaCustomFieldsDefs.find(d =>\n d.fieldKey === 'opportunity.id_oportunidad_sucursal' || norm(d.name) === 'id oportunidad sucursal'\n);\nlet linkFieldFound = false;\nif (linkDef) {\n linkFieldFound = true;\n const idx = customFields.findIndex(c => c.id === linkDef.id);\n const entry = { id: linkDef.id, key: linkDef.fieldKey, field_value: sucursalOppId };\n if (idx >= 0) customFields[idx] = entry; else customFields.push(entry);\n}\n\nconst body = {\n pipelineId: resolvedPipelineId,\n locationId: locationId,\n name: sucursalOpp.name,\n pipelineStageId: resolvedStageId,\n status: sucursalOpp.status || 'open',\n contactId: contactId,\n monetaryValue: sucursalOpp.monetaryValue,\n source: sucursalOpp.source || 'Sincronización Sucursal',\n customFields: customFields\n};\n\nreturn [{\n json: {\n body: JSON.stringify(body),\n debug: { resolvedPipelineId, resolvedStageId, customFieldsCount: customFields.length, sucursalOppId, linkFieldFound }\n }\n}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 5520, 1104 ], "id": "2f9a63e7-277d-49de-8838-a00922c993b2", "name": "Armar Body - CREATE" }, { "parameters": { "method": "POST", "url": "https://services.leadconnectorhq.com/opportunities/", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" }, { "name": "Content-Type", "value": "application/json" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={{ $json.body }}", "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 5760, 1104 ], "id": "fc4b3398-91bb-4dd9-b406-96c8d75a17be", "name": "Crear Oportunidad - MARCA" }, { "parameters": { "jsCode": "// ─── ARMAR BODY PARA ACTUALIZAR OPORTUNIDAD EN MARCA (v2) ────────────\n// Mapea CF por fieldKey (fallback name) y reafirma el campo de enlace\n// \"ID Oportunidad Sucursal\" = id de la opp de sucursal (idempotencia).\n\nconst marcaOppData = $('Obtener info de Oportunidad - MARCA (v2)').first().json;\nconst marcaOpp = marcaOppData.opportunity;\nconst marcaCustomFieldsDefs = $('Conseguir Custom Fields - Opportunity - MARCA (UPDATE)').first().json.customFields || [];\nconst marcaPipelines = $('Obtener Pipelines - MARCA (UPDATE)').first().json.pipelines || [];\nconst sucursalOpp = $('Mapeo completo oportunidad origen - SUCURSAL').first().json.opportunity;\nconst decision = $('Decidir Match (Create vs Update)').first().json;\nconst sucursalOppId = decision.sucursalOppId;\n\nconst norm = (s) => (s || '').toString().trim().toLowerCase();\n\nconst marcaPipelineByName = {};\nconst marcaStageByName = {};\nfor (const pipeline of marcaPipelines) {\n marcaPipelineByName[norm(pipeline.name)] = pipeline.id;\n for (const stage of pipeline.stages) {\n marcaStageByName[norm(stage.name)] = stage.id;\n }\n}\n\nconst resolvedPipelineId = marcaPipelineByName[norm(sucursalOpp.pipelineName)] || marcaOpp.pipelineId;\nconst resolvedStageId = marcaStageByName[norm(sucursalOpp.pipelineStageName)] || marcaOpp.pipelineStageId;\n\nconst sucursalValueByFieldKey = {};\nconst sucursalValueByName = {};\nfor (const cf of sucursalOpp.customFields || []) {\n if (cf.fieldKey) sucursalValueByFieldKey[cf.fieldKey] = cf.fieldValue;\n if (cf.name) sucursalValueByName[norm(cf.name)] = cf.fieldValue;\n}\n\nconst customFields = [];\nfor (const def of marcaCustomFieldsDefs) {\n let value = sucursalValueByFieldKey[def.fieldKey];\n if (value === undefined && def.name) value = sucursalValueByName[norm(def.name)];\n if (value === undefined || value === null) {\n const marcaOriginal = marcaOpp.customFields?.find(cf => cf.id === def.id);\n value = marcaOriginal?.fieldValue;\n }\n if (value === undefined || value === null) continue;\n customFields.push({ id: def.id, key: def.fieldKey, field_value: value });\n}\n\n// Reafirmar el campo de enlace\nconst linkDef = marcaCustomFieldsDefs.find(d =>\n d.fieldKey === 'opportunity.id_oportunidad_sucursal' || norm(d.name) === 'id oportunidad sucursal'\n);\nlet linkFieldFound = false;\nif (linkDef) {\n linkFieldFound = true;\n const idx = customFields.findIndex(c => c.id === linkDef.id);\n const entry = { id: linkDef.id, key: linkDef.fieldKey, field_value: sucursalOppId };\n if (idx >= 0) customFields[idx] = entry; else customFields.push(entry);\n}\n\nconst body = {\n pipelineId: resolvedPipelineId,\n name: sucursalOpp.name,\n pipelineStageId: resolvedStageId,\n status: sucursalOpp.status || marcaOpp.status,\n monetaryValue: sucursalOpp.monetaryValue ?? marcaOpp.monetaryValue,\n source: sucursalOpp.source || marcaOpp.source,\n customFields: customFields\n};\n\nreturn [{\n json: {\n opportunityId: marcaOpp.id,\n body: JSON.stringify(body),\n debug: { matchReason: decision.matchReason, customFieldsCount: customFields.length, sucursalOppId, linkFieldFound }\n }\n}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 5280, 816 ], "id": "969e46cd-bbae-4372-9808-c939f63e3c02", "name": "Armar Body - UPDATE (v2)" }, { "parameters": { "method": "PUT", "url": "=https://services.leadconnectorhq.com/opportunities/{{ $json.opportunityId }}", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" }, { "name": "Content-Type", "value": "application/json" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={{ $json.body }}", "options": { "redirect": { "redirect": {} } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 5520, 816 ], "id": "83929e08-7afd-4670-9c18-be22b8c3656f", "name": "Actualizar Oportunidad - MARCA (v2)" }, { "parameters": { "content": "# RAMA UPDATE\n## Oportunidad ya existe en marca → se actualiza", "height": 280, "width": 880, "color": 4 }, "type": "n8n-nodes-base.stickyNote", "position": [ 5008, 720 ], "typeVersion": 1, "id": "1c285234-8d90-49ef-8dac-c98cb379299a", "name": "Sticky Update" }, { "parameters": { "content": "# RAMA CREATE\n## Oportunidad no existe en marca → se crea desde cero\n### Incluye contacto + custom fields + tag origin-id", "height": 280, "width": 1120, "color": 5 }, "type": "n8n-nodes-base.stickyNote", "position": [ 5008, 1024 ], "typeVersion": 1, "id": "7e8f350c-9562-485b-8ce5-1b13b4086856", "name": "Sticky Create" }, { "parameters": { "content": "# MATCHING ROBUSTO\n## 1. Buscar/crear contacto en marca\n## 2. Buscar oportunidades DEL CONTACTO\n## 3. Decidir match por cantidad + tag origin-id", "height": 320, "width": 1500, "color": 6 }, "type": "n8n-nodes-base.stickyNote", "position": [ 3328, 864 ], "typeVersion": 1, "id": "8a583e46-41b6-44e0-9313-b70ee085b740", "name": "Sticky Matching" }, { "parameters": { "url": "=https://services.leadconnectorhq.com/locations/{{ $('DATOS API').item.json['Location ID'] }}/customFields", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "model", "value": "opportunity" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "options": { "redirect": { "redirect": { "maxRedirects": 90 } } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 5040, 560 ], "id": "45f0a6b0-f44d-4e83-b2ab-cdd3fbfe7911", "name": "Conseguir Custom Fields - Opportunity - MARCA (UPDATE)", "notes": "Necesitamos los custom fields de la marca también en la rama CREATE para mapear los valores que vienen de sucursal." }, { "parameters": { "url": "https://services.leadconnectorhq.com/opportunities/pipelines", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "locationId", "value": "={{ $('DATOS API').item.json['Location ID'] }}" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Version", "value": "2021-07-28" }, { "name": "Authorization", "value": "=Bearer {{ $('DATOS API').item.json['Token/API'] }}" } ] }, "options": {} }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 5280, 560 ], "id": "5ca962a9-9e56-42d1-af05-ce05d39ed77f", "name": "Obtener Pipelines - MARCA (UPDATE)" }, { "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": "={{ 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 } ] }) }}", "options": {} }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 1328, -32 ], "id": "a9572dee-ed57-4104-966a-4b22721e75f1", "name": "Mapear ID Oportunidad Sucursal - SUCURSAL", "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." }, { "parameters": { "databaseId": 63, "tableId": 754, "limit": 1, "additionalOptions": { "filters": { "fields": [ { "field": 7280, "value": "={{ $('Datos de Lead').item.json.Oportunidad.opportunity_id }}" } ] } } }, "type": "n8n-nodes-base.baserow", "typeVersion": 1.1, "position": [ 4200, 1140 ], "id": "a64fdffd-ab8f-4ddd-a4d4-4d683a05132d", "name": "Buscar Mapeo Opp - Baserow", "credentials": { "baserowApi": { "id": "LZztQ3WMpzXjSTIH", "name": "Baserow account" } }, "alwaysOutputData": true, "onError": "continueRegularOutput", "notes": "Idempotencia global: busca en la tabla 754 el mapeo id_opp_sucursal->id_opp_marca. Si existe, 'Decidir Match' hara UPDATE de esa opp aunque el contacto resuelto sea otro. alwaysOutputData + onError para no romper el flujo si no hay match o si Baserow falla." } ], "connections": { "Webhook": { "main": [ [ { "node": "Datos de Lead", "type": "main", "index": 0 } ] ] }, "Datos de Lead": { "main": [ [ { "node": "Omitir @ezcorp.com", "type": "main", "index": 0 } ] ] }, "DATOS API": { "main": [ [ { "node": "Buscar Contacto en MARCA", "type": "main", "index": 0 } ] ] }, "Omitir @ezcorp.com": { "main": [ [ { "node": "API de Sucursal", "type": "main", "index": 0 } ] ] }, "Buscar Oportunidad - SUCURSAL": { "main": [ [ { "node": "Obtener info de Oportunidad - SUCURSAL", "type": "main", "index": 0 } ] ] }, "DATOS API - SUCURSAL": { "main": [ [ { "node": "Conseguir Custom Fields - Opportunity - SUCURSAL", "type": "main", "index": 0 } ] ] }, "Conseguir Custom Fields - Opportunity - SUCURSAL": { "main": [ [ { "node": "Mapear ID Oportunidad Sucursal - SUCURSAL", "type": "main", "index": 0 } ] ] }, "Obtener info de Oportunidad - SUCURSAL": { "main": [ [ { "node": "Obtener Pipelines - SUCURSAL", "type": "main", "index": 0 } ] ] }, "API de Sucursal": { "main": [ [ { "node": "DATOS API - SUCURSAL", "type": "main", "index": 0 } ] ] }, "API de MARCA": { "main": [ [ { "node": "DATOS API", "type": "main", "index": 0 } ] ] }, "Mapeo completo oportunidad origen - SUCURSAL": { "main": [ [ { "node": "API de MARCA", "type": "main", "index": 0 } ] ] }, "Obtener Pipelines - SUCURSAL": { "main": [ [ { "node": "Mapeo completo oportunidad origen - SUCURSAL", "type": "main", "index": 0 } ] ] }, "Obtener info de Oportunidad - MARCA": { "main": [ [ { "node": "Obtener Pipelines - MARCA", "type": "main", "index": 0 } ] ] }, "Obtener Pipelines - MARCA": { "main": [ [ { "node": "Code in JavaScript", "type": "main", "index": 0 } ] ] }, "Buscar Oportunidad - MARCA": { "main": [ [ { "node": "Conseguir Custom Fields - Opportunity - MARCA", "type": "main", "index": 0 } ] ] }, "Conseguir Custom Fields - Opportunity - MARCA": { "main": [ [ { "node": "Obtener info de Oportunidad - MARCA", "type": "main", "index": 0 } ] ] }, "Code in JavaScript": { "main": [ [ { "node": "Actualizar Oportunidad - MARCA2", "type": "main", "index": 0 } ] ] }, "Buscar Contacto en MARCA": { "main": [ [ { "node": "¿Existe contacto en MARCA?", "type": "main", "index": 0 } ] ] }, "¿Existe contacto en MARCA?": { "main": [ [ { "node": "Set Contact ID Resuelto", "type": "main", "index": 0 } ], [ { "node": "Crear Contacto en MARCA", "type": "main", "index": 0 } ] ] }, "Crear Contacto en MARCA": { "main": [ [ { "node": "Set Contact ID Resuelto", "type": "main", "index": 0 } ] ] }, "Set Contact ID Resuelto": { "main": [ [ { "node": "Buscar Mapeo Opp - Baserow", "type": "main", "index": 0 } ] ] }, "Buscar Oportunidades del Contacto - MARCA": { "main": [ [ { "node": "Decidir Match (Create vs Update)", "type": "main", "index": 0 } ] ] }, "Decidir Match (Create vs Update)": { "main": [ [ { "node": "Switch UPDATE vs CREATE", "type": "main", "index": 0 } ] ] }, "Switch UPDATE vs CREATE": { "main": [ [ { "node": "Obtener info de Oportunidad - MARCA (v2)", "type": "main", "index": 0 } ], [ { "node": "Conseguir Custom Fields - Opportunity - MARCA (CREATE)", "type": "main", "index": 0 } ] ] }, "Obtener info de Oportunidad - MARCA (v2)": { "main": [ [ { "node": "Conseguir Custom Fields - Opportunity - MARCA (UPDATE)", "type": "main", "index": 0 } ] ] }, "Armar Body - UPDATE (v2)": { "main": [ [ { "node": "Actualizar Oportunidad - MARCA (v2)", "type": "main", "index": 0 } ] ] }, "Conseguir Custom Fields - Opportunity - MARCA (CREATE)": { "main": [ [ { "node": "Obtener Pipelines - MARCA (CREATE)", "type": "main", "index": 0 } ] ] }, "Obtener Pipelines - MARCA (CREATE)": { "main": [ [ { "node": "Armar Body - CREATE", "type": "main", "index": 0 } ] ] }, "Armar Body - CREATE": { "main": [ [ { "node": "Crear Oportunidad - MARCA", "type": "main", "index": 0 } ] ] }, "Conseguir Custom Fields - Opportunity - MARCA (UPDATE)": { "main": [ [ { "node": "Obtener Pipelines - MARCA (UPDATE)", "type": "main", "index": 0 } ] ] }, "Obtener Pipelines - MARCA (UPDATE)": { "main": [ [ { "node": "Armar Body - UPDATE (v2)", "type": "main", "index": 0 } ] ] }, "Mapear ID Oportunidad Sucursal - SUCURSAL": { "main": [ [ { "node": "Buscar Oportunidad - SUCURSAL", "type": "main", "index": 0 } ] ] }, "Buscar Mapeo Opp - Baserow": { "main": [ [ { "node": "Buscar Oportunidades del Contacto - MARCA", "type": "main", "index": 0 } ] ] } }, "authors": "Consultoria E3 ®", "name": null, "description": null, "autosaved": false, "workflowPublishHistory": [ { "createdAt": "2026-05-30T15:55:46.618Z", "id": 672, "workflowId": "Cfgwp0bOtDW8zuKW", "versionId": "9caa764a-a07e-4c73-aa6a-f95fd5c8aa4d", "event": "deactivated", "userId": "74a7f127-b963-4eb0-aff4-1190428e8409" }, { "createdAt": "2026-05-30T15:55:46.662Z", "id": 673, "workflowId": "Cfgwp0bOtDW8zuKW", "versionId": "9caa764a-a07e-4c73-aa6a-f95fd5c8aa4d", "event": "activated", "userId": "74a7f127-b963-4eb0-aff4-1190428e8409" } ] } }