{ "updatedAt": "2026-08-29T16:24:36.304Z", "createdAt": "2026-08-22T14:54:47.146Z", "id": "kHT6jUVIcYGjagV3", "name": "Cotizador WMC - Artefactos", "description": null, "active": true, "isArchived": false, "nodes": [ { "parameters": { "httpMethod": "POST", "path": "cotizador-wmc-artifacts", "responseMode": "responseNode", "options": {} }, "type": "n8n-nodes-base.webhook", "typeVersion": 2.1, "position": [ -6256, 8400 ], "id": "d2b8313c-4151-4279-b878-717c542c5921", "name": "Webhook - Artefactos", "webhookId": "796454bf-78e1-404c-9ff2-2fb65c10b41b" }, { "parameters": { "jsCode": "// Configuraci贸n local del workflow. No utiliza variables de entorno.\nreturn [{json:{\n ...$json,\n config:{\n supabaseUrl:\"https://dbit.digitalcompass.agency\",\n supabaseAnonKey:\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE\",\n googleAutomationUrl:\"https://script.google.com/macros/s/AKfycbxCmB1VwGO9omH0jPWecOKBiRVQexhCLQa-uCDEXu1Q4vmYCjVPQig_lRFhXFZvFyct/exec\",\n googleAutomationSecret:\"mwI_n-1r4_-QTLp1-zIt-zQKh_HqaoGoVhyapyLN2T2-r7xf8iP5AC3v9wJt5Av6\",\n internalEmailSecret:\"fLf-Fl4AcRL912NsWfC4wGwlfEZ9kvOXJ33ylUjXJ9prTuML4b2sSJt3tDrG5D08\"\n }\n}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -6048, 8400 ], "id": "48caedca-d987-4262-9a64-8fe7f269f28b", "name": "Configuraci贸n - sin ENV" }, { "parameters": { "jsCode": "const body=$json.body??{};\nconst headers=$json.headers??{};\nconst clean=(v,m=12000)=>typeof v==='string'?v.trim().slice(0,m):'';\nconst auth=clean(headers.authorization||headers.Authorization);\nconst internalSecret=clean(headers['x-wmc-internal-secret']||headers['X-WMC-Internal-Secret'],500);\nconst expectedInternalSecret='fLf-Fl4AcRL912NsWfC4wGwlfEZ9kvOXJ33ylUjXJ9prTuML4b2sSJt3tDrG5D08';\nconst action=clean(body.action,80);\nconst allowed=['generate_quote','generate_proposal','generate_image','generate_monthly_glm'];\nconst internalEmail=body.internalEmail===true || internalSecret!=='';\nif(!internalEmail && !auth.startsWith('Bearer ')) throw new Error('Falta Authorization Bearer.');\nreturn [{json:{\n auth, internalEmail, internalAuthorized: internalEmail && internalSecret===expectedInternalSecret,\n action, shouldGenerate:allowed.includes(action), quote:body.quote??null, artifact:body.artifact??null,\n user:body.user??{}, conversationId:clean(body.conversationId,220),\n appSessionId:clean(body.appSessionId,250)||`artifact-${Date.now()}`, model:clean(body.model,120)\n}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -5824, 8400 ], "id": "69882ba8-924f-4f90-b5de-563bed38f4ae", "name": "Normalizar solicitud" }, { "parameters": { "url": "https://dbit.digitalcompass.agency/auth/v1/user", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "apikey", "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE" }, { "name": "Authorization", "value": "={{ $json.auth }}" } ] }, "options": { "timeout": 20000 } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ -5600, 8400 ], "id": "cc69a496-1954-47cd-abd7-8011d090f114", "name": "Supabase - validar JWT", "continueOnFail": true }, { "parameters": { "jsCode": "const req=$node[\"Normalizar solicitud\"].json;\nconst u=$json??{};\nconst id=String(u.id||'').trim();\nconst email=String(u.email||'').trim().toLowerCase();\nconst claimed=String(req.user?.email||'').trim().toLowerCase();\nconst jwtValid=Boolean(id&&email.endsWith('@gomezleemarketing.com')&&(!claimed||claimed===email));\nreturn [{json:{...req,userId:id,verifiedEmail:email,jwtValid}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -5376, 8400 ], "id": "b8b1ec7a-90d3-4613-905c-073fb53acdc8", "name": "Validar identidad" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "b044dcb5-a78a-40ce-a537-a7949ef226c8", "leftValue": "={{ $json.jwtValid }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -5168, 8400 ], "id": "c3a2edf7-9d21-4c6a-9a63-665ca99b29d4", "name": "JWT v谩lido?" }, { "parameters": { "respondWith": "json", "responseBody": "={{ {ok:false,error:'Sesi贸n Supabase inv谩lida.'} }}", "options": { "responseCode": 401 } }, "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.4, "position": [ -4944, 8688 ], "id": "f8c7aea9-0bdb-4828-badf-98f6caaf9c16", "name": "Responder 401" }, { "parameters": { "url": "={{ 'https://dbit.digitalcompass.agency/rest/v1/cotizador_wmc_access?select=email,full_name,is_active,can_use_tarifario&email=eq.' + encodeURIComponent($json.verifiedEmail) + '&is_active=eq.true' + '&limit=1' }}", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "apikey", "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE" }, { "name": "Authorization", "value": "={{ $json.auth }}" } ] }, "options": { "timeout": 20000 } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ -4944, 8320 ], "id": "2f107a29-ff3b-430a-9879-c6be179d3da3", "name": "Supabase - acceso", "continueOnFail": true }, { "parameters": { "jsCode": "const req = $node[\"Validar identidad\"].json;\nconst raw = $json ?? {};\n\n// n8n 2.21.4 puede convertir una respuesta PostgREST con una sola fila\n// en un objeto individual en vez de conservar el array original.\n// Aceptamos todas las formas posibles de respuesta.\nlet row = null;\n\nif (Array.isArray(raw)) {\n row = raw[0] ?? null;\n} else if (Array.isArray(raw?.data)) {\n row = raw.data[0] ?? null;\n} else if (Array.isArray(raw?.body)) {\n row = raw.body[0] ?? null;\n} else if (raw?.body && typeof raw.body === 'object' && !Array.isArray(raw.body)) {\n row = raw.body;\n} else if (raw && typeof raw === 'object' && ('email' in raw || 'is_active' in raw || 'full_name' in raw)) {\n row = raw;\n}\n\nconst normalizeEmail = (value) => String(value ?? '').trim().toLowerCase();\nconst rowEmail = normalizeEmail(row?.email);\nconst active = row?.is_active === true || String(row?.is_active ?? '').toLowerCase() === 'true';\n\nconst accessAllowed = Boolean(\n row &&\n active &&\n rowEmail &&\n rowEmail === normalizeEmail(req.verifiedEmail)\n);\n\nreturn [{\n json: {\n ...req,\n accessAllowed,\n fullName: row?.full_name || req.user?.name || req.verifiedEmail,\n canUseTarifario: accessAllowed && (\n row?.can_use_tarifario === true ||\n String(row?.can_use_tarifario ?? '').toLowerCase() === 'true'\n ),\n accessLookupOk: Boolean(row)\n }\n}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -4720, 8320 ], "id": "c9ef4878-6880-43af-8040-2040d43c521b", "name": "Validar acceso" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "4539e2f3-4739-4d34-bbe0-4239868c30c4", "leftValue": "={{ $json.accessAllowed }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -4496, 8320 ], "id": "5c315269-c38d-47e2-9d2b-fa02a4f3f1cc", "name": "Acceso permitido?" }, { "parameters": { "respondWith": "json", "responseBody": "={{ {ok:false,error:'No tienes acceso activo al Cotizador Walmart Connect.'} }}", "options": { "responseCode": 403 } }, "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.4, "position": [ -4288, 8688 ], "id": "3a052ddc-3a65-4be0-8375-db968369562e", "name": "Responder 403" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "25b6fd12-c4b4-4938-a319-0572e307e49b", "leftValue": "={{ $json.shouldGenerate }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -4288, 8320 ], "id": "41bbecc4-458e-4bc2-8c68-7b32fa9ef020", "name": "Debe generar?" }, { "parameters": { "respondWith": "json", "responseBody": "={{ {ok:true,skipped:true,message:'La respuesta no requiere crear un archivo.'} }}", "options": { "responseCode": 200 } }, "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.4, "position": [ -4064, 8688 ], "id": "799cfcaf-c04c-4b95-aec0-b2abc39613e1", "name": "Responder sin artefacto" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "cd73b109-158e-4aa8-93ab-40b1c9c77de5", "leftValue": "={{ $json.action }}", "rightValue": "generate_image", "operator": { "type": "string", "operation": "equals" } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -4064, 8320 ], "id": "5a3ec8cb-c3d9-4e5c-8cea-7a389247adc0", "name": "Es imagen?" }, { "parameters": { "resource": "image", "modelId": { "__rl": true, "value": "models/gemini-3-pro-image", "mode": "list", "cachedResultName": "models/gemini-3-pro-image (Nano Banana Pro)" }, "prompt": "={{ $json.artifact?.imagePrompt || $json.artifact?.prompt || $json.artifact?.title || 'Visual profesional para Walmart Connect' }}", "options": { "binaryPropertyOutput": "data" } }, "type": "@n8n/n8n-nodes-langchain.googleGemini", "typeVersion": 1.2, "position": [ -3840, 8080 ], "id": "bc3a2875-1e89-42e5-a2fb-a853901f9f5c", "name": "Gemini - Generar imagen", "retryOnFail": true, "maxTries": 2, "waitBetweenTries": 1500, "credentials": { "googlePalmApi": { "id": "jvsXYwL6IOoY2DBU", "name": "Isaac - Gemini Api Pago" } } }, { "parameters": { "name": "={{ 'WMC_' + String($node[\"Contexto Artefacto\"].json.artifact?.title || 'visual').replace(/[^a-zA-Z0-9谩茅铆贸煤脕脡脥脫脷帽脩_-]+/g,'_').slice(0,80) + '.png' }}", "driveId": { "__rl": true, "mode": "list", "value": "My Drive" }, "folderId": { "__rl": true, "mode": "list", "value": "root", "cachedResultName": "/ (Root folder)" }, "options": { "simplifyOutput": true } }, "type": "n8n-nodes-base.googleDrive", "typeVersion": 3, "position": [ -3616, 8080 ], "id": "f38634c2-9aff-4f37-9b49-f0b951ca5459", "name": "Subir imagen a Drive", "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } } }, { "parameters": { "operation": "share", "fileId": { "__rl": true, "value": "={{ $node[\"Subir imagen a Drive\"].json.id }}", "mode": "id" }, "permissionsUi": { "permissionsValues": { "role": "writer", "type": "domain", "domain": "gomezleemarketing.com" } }, "options": {} }, "type": "n8n-nodes-base.googleDrive", "typeVersion": 3, "position": [ -3392, 8080 ], "id": "27946335-650b-4954-869b-2c20b1d6d717", "name": "Compartir imagen con GomezLee Marketing", "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } } }, { "parameters": { "jsCode": "const req=$node[\"Contexto Artefacto\"].json;\nconst upload=$node[\"Subir imagen a Drive\"].json||{};\nconst id=String(upload.id||'');\nif(!id) return [{json:{ok:false,error:'Google Drive no devolvi贸 el ID de la imagen.',artifactType:null,artifactUrl:null}}];\nreturn [{json:{\n ok:true,\n artifactType:'image',\n artifactUrl:`https://drive.google.com/file/d/${id}/view`,\n artifactId:id,\n title:req.artifact?.title||'Visual WMC',\n quote:req.quote,\n user:{id:req.userId,email:req.verifiedEmail,name:req.fullName},\n conversationId:req.conversationId,\n appSessionId:req.appSessionId,\n provider:'Google Gemini + Google Drive'\n}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -3168, 8080 ], "id": "3227132d-a14c-4d73-bfc8-8dfc7986eee2", "name": "Normalizar imagen generada" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "9f0781ba-0f4e-4d98-a205-e3b17998306b", "leftValue": "={{ $json.action }}", "rightValue": "generate_proposal", "operator": { "type": "string", "operation": "equals" } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -3840, 8432 ], "id": "9eb3b0dd-fbdd-4918-bd5e-19372a67f815", "name": "Es propuesta?" }, { "parameters": { "jsCode": "const req=$node[\"Contexto Artefacto\"].json;\nconst slides=Array.isArray(req.artifact?.slides)?req.artifact.slides:[];\nconst out=[];\nslides.forEach((slide,index)=>{\n const prompt=String(slide?.imagePrompt||'').trim();\n const dark=['cover','section','thankyou'].includes(String(slide?.type||'').toLowerCase());\n if(prompt && !dark && !slide?.imageUrl && !slide?.imageDriveId){\n out.push({json:{...req,hasVisual:true,slideIndex:index,imagePrompt:prompt,slideTitle:String(slide?.title||`Slide ${index+1}`)}});\n }\n});\nif(!out.length) out.push({json:{...req,hasVisual:false}});\nreturn out;" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -3616, 8432 ], "id": "d42489cd-4103-4a16-8479-5d8405e5b1f1", "name": "Preparar visuales propuesta" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "b287fc35-9b12-45a2-bd69-f39a3d455454", "leftValue": "={{ $json.hasVisual }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -3392, 8432 ], "id": "6da63b03-7229-496d-93b1-31936e32b7ae", "name": "Tiene visuales?" }, { "parameters": { "resource": "image", "modelId": { "__rl": true, "value": "models/gemini-3-pro-image", "mode": "list", "cachedResultName": "models/gemini-3-pro-image (Nano Banana Pro)" }, "prompt": "={{ $json.imagePrompt }}", "options": { "binaryPropertyOutput": "data" } }, "type": "@n8n/n8n-nodes-langchain.googleGemini", "typeVersion": 1.2, "position": [ -3168, 8368 ], "id": "22f5b63b-96bd-4cac-ace4-296e9fa91dc1", "name": "Gemini - Visuales propuesta", "retryOnFail": true, "maxTries": 2, "waitBetweenTries": 1500, "credentials": { "googlePalmApi": { "id": "jvsXYwL6IOoY2DBU", "name": "Isaac - Gemini Api Pago" } } }, { "parameters": { "name": "={{ 'WMC_Propuesta_' + ($itemIndex + 1) + '.png' }}", "driveId": { "__rl": true, "mode": "list", "value": "My Drive" }, "folderId": { "__rl": true, "mode": "list", "value": "root", "cachedResultName": "/ (Root folder)" }, "options": { "simplifyOutput": true } }, "type": "n8n-nodes-base.googleDrive", "typeVersion": 3, "position": [ -2960, 8368 ], "id": "fbbe74fb-4b38-499c-9954-19afb75aaf74", "name": "Subir visuales propuesta", "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } } }, { "parameters": { "jsCode": "const req=$node[\"Contexto Artefacto\"].json;\nconst artifact=JSON.parse(JSON.stringify(req.artifact||{}));\nconst slides=Array.isArray(artifact.slides)?artifact.slides:[];\nconst specs=$items(\"Preparar visuales propuesta\").filter(i=>i.json?.hasVisual===true);\nconst uploads=$items(\"Subir visuales propuesta\");\n\nfor(let i=0;i{\n const obj=(ref && typeof ref==='object')?ref:{};\n const prompt=String(obj.imagePrompt||obj.prompt||'').trim();\n const already=String(obj.imageDriveId||obj.driveId||obj.fileId||obj.imageUrl||obj.url||'').trim();\n if(prompt && !already){\n out.push({json:{...req,hasVisual:true,visualIndex:index,imagePrompt:prompt,visualTitle:String(obj.title||`Referencia visual ${index+1}`)}});\n }\n});\nif(!out.length) out.push({json:{...req,hasVisual:false}});\nreturn out;" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -3392, 8560 ], "id": "f107280d-36b5-4d46-b69d-592d79a6a1fb", "name": "Preparar visuales cotizaci贸n" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "d5a0d13b-e1b9-465b-b321-b4c303ede9e1", "leftValue": "={{ $json.hasVisual }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -3168, 8560 ], "id": "1fe96ff3-f7aa-4058-8fd9-1b983d288c10", "name": "Tiene visuales cotizaci贸n?" }, { "parameters": { "resource": "image", "modelId": { "__rl": true, "value": "models/gemini-3-pro-image", "mode": "list", "cachedResultName": "models/gemini-3-pro-image (Nano Banana Pro)" }, "prompt": "={{ $json.imagePrompt }}", "options": { "binaryPropertyOutput": "data" } }, "type": "@n8n/n8n-nodes-langchain.googleGemini", "typeVersion": 1.2, "position": [ -2960, 8528 ], "id": "2f44ef05-7115-4ee2-8202-82adc2f0c979", "name": "Gemini - Visuales cotizaci贸n", "retryOnFail": true, "maxTries": 2, "waitBetweenTries": 1500, "credentials": { "googlePalmApi": { "id": "jvsXYwL6IOoY2DBU", "name": "Isaac - Gemini Api Pago" } } }, { "parameters": { "name": "={{ 'WMC_Cotizacion_Visual_' + ($itemIndex + 1) + '.png' }}", "driveId": { "__rl": true, "mode": "list", "value": "My Drive" }, "folderId": { "__rl": true, "mode": "list", "value": "root", "cachedResultName": "/ (Root folder)" }, "options": { "simplifyOutput": true } }, "type": "n8n-nodes-base.googleDrive", "typeVersion": 3, "position": [ -2736, 8528 ], "id": "e13fdd03-2239-4a23-9d6a-3d8163e58015", "name": "Subir visuales cotizaci贸n", "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } } }, { "parameters": { "jsCode": "const req=$node[\"Contexto Artefacto\"].json;\nconst quote=JSON.parse(JSON.stringify(req.quote||{}));\nconst refs=Array.isArray(quote.visualReferences)?quote.visualReferences:[];\nconst specs=$items(\"Preparar visuales cotizaci贸n\").filter(i=>i.json?.hasVisual===true);\nconst uploads=$items(\"Subir visuales cotizaci贸n\");\nfor(let i=0;i n_(a?.sort_order,0) - n_(b?.sort_order,0))\n .map((it) => ({\n section: it?.section || 'Otros',\n description: it?.description || 'Item',\n units: n_(it?.units, 0),\n days: n_(it?.days, 1),\n unitCostUsd: money_(it?.unit_cost_usd),\n totalUsd: money_(it?.total_usd),\n unitCostLocal: money_(it?.unit_cost_local),\n totalLocal: money_(it?.total_local),\n isEstimated: it?.is_estimated === true,\n confidence: it?.confidence === null || it?.confidence === undefined ? null : n_(it.confidence, 0),\n estimationReason: it?.estimation_reason || null,\n metadata: it?.metadata && typeof it.metadata === 'object' ? it.metadata : {}\n }));\n\n const subtotalUsd = money_(items.reduce((s,it)=>s+n_(it.totalUsd,0),0));\n const subtotalLocal = money_(items.reduce((s,it)=>s+n_(it.totalLocal,0),0));\n const totalUsd = money_(row.total_usd);\n const totalLocal = money_(row.total_local);\n const feeUsd = money_(Math.max(0, totalUsd - subtotalUsd));\n const feeLocal = money_(Math.max(0, totalLocal - subtotalLocal));\n const feeRate = subtotalUsd > 0 ? feeUsd / subtotalUsd : 0;\n\n q = {\n ...q,\n countryCode: String(row.country_code || q.countryCode || '').toUpperCase(),\n country: row.country_name || q.country || countryFor_(row.country_code),\n brandSolution: row.brand_solution || q.brandSolution || 'Walmart Connect',\n project: row.project || q.project || '',\n advertiser: row.advertiser || q.advertiser || '',\n format: row.format || q.format || '',\n exchangeRate: n_(row.exchange_rate, n_(q.exchangeRate,1)),\n currencyCode: row.local_currency_code || q.currencyCode || currencyFor_(row.country_code),\n status: row.status || q.status || 'generated',\n items: items.length ? items : (Array.isArray(q.items) ? q.items : []),\n subtotalUsd,\n subtotalLocal,\n agencyFeeRate: feeRate,\n agencyFeeUsd: feeUsd,\n agencyFeeLocal: feeLocal,\n totalUsd,\n totalLocal,\n documentUrl: row.document_url || q.documentUrl || null\n };\n sourceQuoteId = String(row.id || sourceQuoteId || '');\n}\n\nif (!q.countryCode || !q.country || !q.currencyCode || !Array.isArray(q.items) || !q.items.length) {\n throw new Error('No se encontr贸 una cotizaci贸n WMC previa completa en esta conversaci贸n para mensualizar.');\n}\n\nconst baseSubtotalLocal = money_(q.items.reduce((s,it)=>s+n_(it.totalLocal,0),0));\nconst approvedTotalLocal = money_(q.totalLocal);\nconst approvedTotalUsd = money_(q.totalUsd);\nlet feeLocal = n_(q.agencyFeeLocal, NaN);\nlet feeUsd = n_(q.agencyFeeUsd, NaN);\nlet feeRate = n_(q.agencyFeeRate, NaN);\n\nif (!Number.isFinite(feeLocal)) feeLocal = money_(Math.max(0, approvedTotalLocal - baseSubtotalLocal));\nif (!Number.isFinite(feeUsd)) {\n const subtotalUsd = money_(q.items.reduce((s,it)=>s+n_(it.totalUsd,0),0));\n feeUsd = money_(Math.max(0, approvedTotalUsd - subtotalUsd));\n}\nif (!Number.isFinite(feeRate)) {\n const subtotalUsd = money_(q.items.reduce((s,it)=>s+n_(it.totalUsd,0),0));\n feeRate = subtotalUsd > 0 ? feeUsd / subtotalUsd : 0;\n}\n\nq.agencyFeeLocal = money_(feeLocal);\nq.agencyFeeUsd = money_(feeUsd);\nq.agencyFeeRate = feeRate;\n\nconst monthlyLines = q.items.map(it => ({...it}));\nif (q.agencyFeeLocal > 0.005) {\n monthlyLines.push({\n section: 'Fee de agencia',\n description: `Fee de agencia (${(q.agencyFeeRate * 100).toFixed(2).replace(/\\.00$/,'')}%)`,\n units: 1,\n days: 1,\n unitCostUsd: q.agencyFeeUsd,\n totalUsd: q.agencyFeeUsd,\n unitCostLocal: q.agencyFeeLocal,\n totalLocal: q.agencyFeeLocal,\n isEstimated: false,\n confidence: 1,\n estimationReason: null,\n metadata: {systemGeneratedFromApprovedWmcTotal:true}\n });\n}\n\nconst artifact = JSON.parse(JSON.stringify(req.artifact || {}));\nartifact.sourceQuoteId = sourceQuoteId || artifact.sourceQuoteId || null;\nartifact.monthlyLines = monthlyLines;\nartifact.metadata = {\n ...(artifact.metadata && typeof artifact.metadata === 'object' ? artifact.metadata : {}),\n sourceQuoteId: artifact.sourceQuoteId,\n sourceDocumentUrl: q.documentUrl || null,\n countryCode: q.countryCode,\n country: q.country,\n currencyCode: q.currencyCode,\n exchangeRate: q.exchangeRate,\n approvedWmcTotalUsd: approvedTotalUsd,\n approvedWmcTotalLocal: approvedTotalLocal,\n agencyFeeRate: q.agencyFeeRate,\n agencyFeeUsd: q.agencyFeeUsd,\n agencyFeeLocal: q.agencyFeeLocal,\n walmartApproved: true,\n glmIvaRate: 0.12\n};\n\nreturn [{json:{...req,quote:q,artifact}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -2944, 8688 ], "id": "fd12a715-5138-46ec-8e50-a4c5e70a0f81", "name": "Hidratar mensualizaci贸n aprobada" }, { "parameters": { "operation": "share", "fileId": { "__rl": true, "value": "={{ $json.id }}", "mode": "id" }, "permissionsUi": { "permissionsValues": { "role": "writer", "type": "domain", "domain": "gomezleemarketing.com" } }, "options": {} }, "type": "n8n-nodes-base.googleDrive", "typeVersion": 3, "position": [ -2736, 8272 ], "id": "762165ec-1698-423a-a2f1-bc693d337532", "name": "Compartir visuales propuesta con GomezLee Marketing", "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } } }, { "parameters": { "operation": "share", "fileId": { "__rl": true, "value": "={{ $json.id }}", "mode": "id" }, "permissionsUi": { "permissionsValues": { "role": "writer", "type": "domain", "domain": "gomezleemarketing.com" } }, "options": {} }, "type": "n8n-nodes-base.googleDrive", "typeVersion": 3, "position": [ -2512, 8752 ], "id": "f8aff62a-85af-4d36-8981-fed579a7be1e", "name": "Compartir visuales cotizaci贸n con GomezLee Marketing", "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } } }, { "parameters": { "jsCode": "const a = $json ?? {};\n\nif (a.ok === false) {\n return [{json:{...a,shareFileId:null,shareRequired:false}}];\n}\n\nlet id = String(a.artifactId || '').trim();\nconst url = String(a.artifactUrl || '').trim();\n\nif (!id && url) {\n const patterns = [\n /\\/d\\/([A-Za-z0-9_-]{20,})/,\n /[?&]id=([A-Za-z0-9_-]{20,})/,\n /\\/folders\\/([A-Za-z0-9_-]{20,})/\n ];\n for (const pattern of patterns) {\n const match = url.match(pattern);\n if (match?.[1]) {\n id = match[1];\n break;\n }\n }\n}\n\nif (!id) {\n throw new Error('No se pudo identificar el archivo de Google Workspace para aplicar el acceso de GomezLee Marketing.');\n}\n\nreturn [{json:{...a,shareFileId:id,shareRequired:true}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -1392, 8480 ], "id": "6f44d625-0528-4a0e-9285-880a136e37e9", "name": "Preparar permiso GomezLee Marketing" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "c8060fe4-e989-4cea-8b44-3e1f0e0c153c", "leftValue": "={{ $json.shareRequired }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -1168, 8480 ], "id": "d5bf4b40-b2b7-40ac-abdc-19022b65d8a0", "name": "驴Archivo Google para compartir?" }, { "parameters": { "operation": "share", "fileId": { "__rl": true, "value": "={{ $json.shareFileId }}", "mode": "id" }, "permissionsUi": { "permissionsValues": { "role": "writer", "type": "domain", "domain": "gomezleemarketing.com" } }, "options": {} }, "type": "n8n-nodes-base.googleDrive", "typeVersion": 3, "position": [ -944, 8368 ], "id": "0755c9e3-db77-4263-a135-10c9e6edc017", "name": "Compartir archivo final con GomezLee Marketing", "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } } }, { "parameters": { "jsCode": "const original = $node[\"Normalizar resultado\"].json ?? {};\nreturn [{json:original}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -704, 8368 ], "id": "ded9cefe-006e-44bc-9ffb-1df081b8a59a", "name": "Restaurar resultado tras compartir" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "889b613b-a5d6-4362-bac9-969a9776b06f", "leftValue": "={{ $json.internalEmail }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -5600, 7952 ], "id": "08fb954f-6326-4cbf-814f-8961d3252511", "name": "驴Solicitud interna email?" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "5ee8550d-b245-47c1-9c58-722bf3e0c7d1", "leftValue": "={{ $json.internalAuthorized }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -5376, 7952 ], "id": "5fbba220-1d24-4348-8c43-745664a9b848", "name": "Interno autorizado?" }, { "parameters": { "respondWith": "json", "responseBody": "={{ {ok:false,error:'Solicitud interna no autorizada.'} }}", "options": { "responseCode": 401 } }, "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.4, "position": [ -5152, 8128 ], "id": "4fb3d352-64b1-4c11-aa23-1e802e8c00c4", "name": "Responder 401 Interno" }, { "parameters": { "jsCode": "const req=$node[\"Normalizar solicitud\"].json;\nconst email=String(req.user?.email||'wmc@gomezlee.marketing').trim().toLowerCase();\nreturn [{json:{...req,userId:null,verifiedEmail:email,fullName:req.user?.name||'Walmart Connect Email Agent',accessAllowed:true,canUseTarifario:false,internalEmail:true}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -5152, 7872 ], "id": "be28584f-082d-4774-818f-6670465432e8", "name": "Autorizar email interno" }, { "parameters": { "jsCode": "const x=$json??{};\nreturn [{json:{...x,internalEmail:Boolean(x.internalEmail)}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -4064, 8128 ], "id": "f832489e-9cf7-43ad-b246-0b89204dda0a", "name": "Contexto Artefacto" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "03140a28-4f09-4a9c-b82b-4c6eeced8c17", "leftValue": "={{ $node[\"Contexto Artefacto\"].json.internalEmail }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ 80, 7968 ], "id": "3c1eaefc-44eb-4e31-8e9c-bacae9e6c86e", "name": "驴Imagen interna email?" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "12b1ba07-d2ac-47df-9c66-5e18bdb41d79", "leftValue": "={{ $node[\"Contexto Artefacto\"].json.internalEmail }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ 112, 8400 ], "id": "e2370114-e36a-49f0-97a6-313a1af66866", "name": "驴Resultado interno email?" }, { "parameters": { "jsCode": "const a=$json??{};\nreturn [{json:{ok:a.ok!==false,artifactUrl:a.artifactUrl||null,artifactType:a.artifactType||null,artifactId:a.artifactId||null,quoteId:null,title:a.title||null,error:a.error||null}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 320, 8160 ], "id": "c6fe38d4-fa37-49a8-aa84-c7065a763b3b", "name": "Preparar respuesta interna Artefactos" }, { "parameters": { "respondWith": "json", "responseBody": "={{ $json }}", "options": { "responseCode": 200 } }, "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.4, "position": [ 560, 8160 ], "id": "eba6e35b-623e-4e6d-bdb2-00b943a5873a", "name": "Responder artefacto interno" } ], "connections": { "Webhook - Artefactos": { "main": [ [ { "node": "Configuraci贸n - sin ENV", "type": "main", "index": 0 } ] ] }, "Configuraci贸n - sin ENV": { "main": [ [ { "node": "Normalizar solicitud", "type": "main", "index": 0 } ] ] }, "Normalizar solicitud": { "main": [ [ { "node": "驴Solicitud interna email?", "type": "main", "index": 0 } ] ] }, "Supabase - validar JWT": { "main": [ [ { "node": "Validar identidad", "type": "main", "index": 0 } ] ] }, "Validar identidad": { "main": [ [ { "node": "JWT v谩lido?", "type": "main", "index": 0 } ] ] }, "JWT v谩lido?": { "main": [ [ { "node": "Supabase - acceso", "type": "main", "index": 0 } ], [ { "node": "Responder 401", "type": "main", "index": 0 } ] ] }, "Supabase - acceso": { "main": [ [ { "node": "Validar acceso", "type": "main", "index": 0 } ] ] }, "Validar acceso": { "main": [ [ { "node": "Acceso permitido?", "type": "main", "index": 0 } ] ] }, "Acceso permitido?": { "main": [ [ { "node": "Contexto Artefacto", "type": "main", "index": 0 } ], [ { "node": "Responder 403", "type": "main", "index": 0 } ] ] }, "Debe generar?": { "main": [ [ { "node": "Es imagen?", "type": "main", "index": 0 } ], [ { "node": "Responder sin artefacto", "type": "main", "index": 0 } ] ] }, "Es imagen?": { "main": [ [ { "node": "Gemini - Generar imagen", "type": "main", "index": 0 } ], [ { "node": "Es propuesta?", "type": "main", "index": 0 } ] ] }, "Gemini - Generar imagen": { "main": [ [ { "node": "Subir imagen a Drive", "type": "main", "index": 0 } ] ] }, "Subir imagen a Drive": { "main": [ [ { "node": "Compartir imagen con GomezLee Marketing", "type": "main", "index": 0 } ] ] }, "Normalizar imagen generada": { "main": [ [ { "node": "驴Imagen interna email?", "type": "main", "index": 0 } ] ] }, "Es propuesta?": { "main": [ [ { "node": "Preparar visuales propuesta", "type": "main", "index": 0 } ], [ { "node": "Acci贸n es cotizaci贸n?", "type": "main", "index": 0 } ] ] }, "Preparar visuales propuesta": { "main": [ [ { "node": "Tiene visuales?", "type": "main", "index": 0 } ] ] }, "Tiene visuales?": { "main": [ [ { "node": "Gemini - Visuales propuesta", "type": "main", "index": 0 } ], [ { "node": "Preparar Google", "type": "main", "index": 0 } ] ] }, "Gemini - Visuales propuesta": { "main": [ [ { "node": "Subir visuales propuesta", "type": "main", "index": 0 } ] ] }, "Subir visuales propuesta": { "main": [ [ { "node": "Compartir visuales propuesta con GomezLee Marketing", "type": "main", "index": 0 } ] ] }, "Recomponer propuesta": { "main": [ [ { "node": "Preparar Google", "type": "main", "index": 0 } ] ] }, "Preparar Google": { "main": [ [ { "node": "Google Automation", "type": "main", "index": 0 } ] ] }, "Google Automation": { "main": [ [ { "node": "Normalizar resultado", "type": "main", "index": 0 } ] ] }, "Normalizar resultado": { "main": [ [ { "node": "驴Resultado interno email?", "type": "main", "index": 0 } ] ] }, "Guardar cotizaci贸n Supabase": { "main": [ [ { "node": "Preparar respuesta cotizaci贸n", "type": "main", "index": 0 } ] ] }, "Preparar respuesta cotizaci贸n": { "main": [ [ { "node": "Responder artefacto", "type": "main", "index": 0 } ] ] }, "Guardar otro artefacto Supabase": { "main": [ [ { "node": "Preparar respuesta artefacto", "type": "main", "index": 0 } ] ] }, "Preparar respuesta artefacto": { "main": [ [ { "node": "Responder artefacto", "type": "main", "index": 0 } ] ] }, "Resultado es cotizaci贸n?": { "main": [ [ { "node": "Guardar cotizaci贸n Supabase", "type": "main", "index": 0 } ], [ { "node": "Guardar otro artefacto Supabase", "type": "main", "index": 0 } ] ] }, "Acci贸n es cotizaci贸n?": { "main": [ [ { "node": "Preparar visuales cotizaci贸n", "type": "main", "index": 0 } ], [ { "node": "Es mensualizaci贸n?", "type": "main", "index": 0 } ] ] }, "Preparar visuales cotizaci贸n": { "main": [ [ { "node": "Tiene visuales cotizaci贸n?", "type": "main", "index": 0 } ] ] }, "Tiene visuales cotizaci贸n?": { "main": [ [ { "node": "Gemini - Visuales cotizaci贸n", "type": "main", "index": 0 } ], [ { "node": "Preparar Google", "type": "main", "index": 0 } ] ] }, "Gemini - Visuales cotizaci贸n": { "main": [ [ { "node": "Subir visuales cotizaci贸n", "type": "main", "index": 0 } ] ] }, "Subir visuales cotizaci贸n": { "main": [ [ { "node": "Compartir visuales cotizaci贸n con GomezLee Marketing", "type": "main", "index": 0 } ] ] }, "Recomponer cotizaci贸n": { "main": [ [ { "node": "Preparar Google", "type": "main", "index": 0 } ] ] }, "Es mensualizaci贸n?": { "main": [ [ { "node": "Supabase - 煤ltima cotizaci贸n WMC", "type": "main", "index": 0 } ], [ { "node": "Preparar Google", "type": "main", "index": 0 } ] ] }, "Supabase - 煤ltima cotizaci贸n WMC": { "main": [ [ { "node": "Hidratar mensualizaci贸n aprobada", "type": "main", "index": 0 } ] ] }, "Hidratar mensualizaci贸n aprobada": { "main": [ [ { "node": "Preparar Google", "type": "main", "index": 0 } ] ] }, "Compartir imagen con GomezLee Marketing": { "main": [ [ { "node": "Normalizar imagen generada", "type": "main", "index": 0 } ] ] }, "Compartir visuales propuesta con GomezLee Marketing": { "main": [ [ { "node": "Recomponer propuesta", "type": "main", "index": 0 } ] ] }, "Compartir visuales cotizaci贸n con GomezLee Marketing": { "main": [ [ { "node": "Recomponer cotizaci贸n", "type": "main", "index": 0 } ] ] }, "Preparar permiso GomezLee Marketing": { "main": [ [ { "node": "驴Archivo Google para compartir?", "type": "main", "index": 0 } ] ] }, "驴Archivo Google para compartir?": { "main": [ [ { "node": "Compartir archivo final con GomezLee Marketing", "type": "main", "index": 0 } ], [ { "node": "Resultado es cotizaci贸n?", "type": "main", "index": 0 } ] ] }, "Compartir archivo final con GomezLee Marketing": { "main": [ [ { "node": "Restaurar resultado tras compartir", "type": "main", "index": 0 } ] ] }, "Restaurar resultado tras compartir": { "main": [ [ { "node": "Resultado es cotizaci贸n?", "type": "main", "index": 0 } ] ] }, "驴Solicitud interna email?": { "main": [ [ { "node": "Interno autorizado?", "type": "main", "index": 0 } ], [ { "node": "Supabase - validar JWT", "type": "main", "index": 0 } ] ] }, "Interno autorizado?": { "main": [ [ { "node": "Autorizar email interno", "type": "main", "index": 0 } ], [ { "node": "Responder 401 Interno", "type": "main", "index": 0 } ] ] }, "Autorizar email interno": { "main": [ [ { "node": "Contexto Artefacto", "type": "main", "index": 0 } ] ] }, "Contexto Artefacto": { "main": [ [ { "node": "Debe generar?", "type": "main", "index": 0 } ] ] }, "驴Imagen interna email?": { "main": [ [ { "node": "Preparar respuesta interna Artefactos", "type": "main", "index": 0 } ], [ { "node": "Guardar otro artefacto Supabase", "type": "main", "index": 0 } ] ] }, "驴Resultado interno email?": { "main": [ [ { "node": "Preparar respuesta interna Artefactos", "type": "main", "index": 0 } ], [ { "node": "Preparar permiso GomezLee Marketing", "type": "main", "index": 0 } ] ] }, "Preparar respuesta interna Artefactos": { "main": [ [ { "node": "Responder artefacto interno", "type": "main", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1", "binaryMode": "separate" }, "staticData": null, "meta": null, "versionId": "59b8fc04-1a98-4aa6-b66f-fd437fe59265", "activeVersionId": "59b8fc04-1a98-4aa6-b66f-fd437fe59265", "versionCounter": 40, "triggerCount": 1, "shared": [ { "updatedAt": "2026-08-22T14:54:47.152Z", "createdAt": "2026-08-22T14:54:47.152Z", "role": "workflow:owner", "workflowId": "kHT6jUVIcYGjagV3", "projectId": "PJpTANzTXIFibWsW", "project": { "updatedAt": "2026-04-22T14:25:09.686Z", "createdAt": "2026-04-22T14:22:54.790Z", "id": "PJpTANzTXIFibWsW", "name": "Isaac Aracena ", "type": "personal", "icon": null, "description": null, "creatorId": "0a88c0b1-928e-4412-896e-c5d1c99b2029" } } ], "tags": [], "activeVersion": { "updatedAt": "2026-08-29T16:24:37.000Z", "createdAt": "2026-08-29T16:24:36.307Z", "versionId": "59b8fc04-1a98-4aa6-b66f-fd437fe59265", "workflowId": "kHT6jUVIcYGjagV3", "nodes": [ { "parameters": { "httpMethod": "POST", "path": "cotizador-wmc-artifacts", "responseMode": "responseNode", "options": {} }, "type": "n8n-nodes-base.webhook", "typeVersion": 2.1, "position": [ -6256, 8400 ], "id": "d2b8313c-4151-4279-b878-717c542c5921", "name": "Webhook - Artefactos", "webhookId": "796454bf-78e1-404c-9ff2-2fb65c10b41b" }, { "parameters": { "jsCode": "// Configuraci贸n local del workflow. No utiliza variables de entorno.\nreturn [{json:{\n ...$json,\n config:{\n supabaseUrl:\"https://dbit.digitalcompass.agency\",\n supabaseAnonKey:\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE\",\n googleAutomationUrl:\"https://script.google.com/macros/s/AKfycbxCmB1VwGO9omH0jPWecOKBiRVQexhCLQa-uCDEXu1Q4vmYCjVPQig_lRFhXFZvFyct/exec\",\n googleAutomationSecret:\"mwI_n-1r4_-QTLp1-zIt-zQKh_HqaoGoVhyapyLN2T2-r7xf8iP5AC3v9wJt5Av6\",\n internalEmailSecret:\"fLf-Fl4AcRL912NsWfC4wGwlfEZ9kvOXJ33ylUjXJ9prTuML4b2sSJt3tDrG5D08\"\n }\n}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -6048, 8400 ], "id": "48caedca-d987-4262-9a64-8fe7f269f28b", "name": "Configuraci贸n - sin ENV" }, { "parameters": { "jsCode": "const body=$json.body??{};\nconst headers=$json.headers??{};\nconst clean=(v,m=12000)=>typeof v==='string'?v.trim().slice(0,m):'';\nconst auth=clean(headers.authorization||headers.Authorization);\nconst internalSecret=clean(headers['x-wmc-internal-secret']||headers['X-WMC-Internal-Secret'],500);\nconst expectedInternalSecret='fLf-Fl4AcRL912NsWfC4wGwlfEZ9kvOXJ33ylUjXJ9prTuML4b2sSJt3tDrG5D08';\nconst action=clean(body.action,80);\nconst allowed=['generate_quote','generate_proposal','generate_image','generate_monthly_glm'];\nconst internalEmail=body.internalEmail===true || internalSecret!=='';\nif(!internalEmail && !auth.startsWith('Bearer ')) throw new Error('Falta Authorization Bearer.');\nreturn [{json:{\n auth, internalEmail, internalAuthorized: internalEmail && internalSecret===expectedInternalSecret,\n action, shouldGenerate:allowed.includes(action), quote:body.quote??null, artifact:body.artifact??null,\n user:body.user??{}, conversationId:clean(body.conversationId,220),\n appSessionId:clean(body.appSessionId,250)||`artifact-${Date.now()}`, model:clean(body.model,120)\n}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -5824, 8400 ], "id": "69882ba8-924f-4f90-b5de-563bed38f4ae", "name": "Normalizar solicitud" }, { "parameters": { "url": "https://dbit.digitalcompass.agency/auth/v1/user", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "apikey", "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE" }, { "name": "Authorization", "value": "={{ $json.auth }}" } ] }, "options": { "timeout": 20000 } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ -5600, 8400 ], "id": "cc69a496-1954-47cd-abd7-8011d090f114", "name": "Supabase - validar JWT", "continueOnFail": true }, { "parameters": { "jsCode": "const req=$node[\"Normalizar solicitud\"].json;\nconst u=$json??{};\nconst id=String(u.id||'').trim();\nconst email=String(u.email||'').trim().toLowerCase();\nconst claimed=String(req.user?.email||'').trim().toLowerCase();\nconst jwtValid=Boolean(id&&email.endsWith('@gomezleemarketing.com')&&(!claimed||claimed===email));\nreturn [{json:{...req,userId:id,verifiedEmail:email,jwtValid}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -5376, 8400 ], "id": "b8b1ec7a-90d3-4613-905c-073fb53acdc8", "name": "Validar identidad" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "b044dcb5-a78a-40ce-a537-a7949ef226c8", "leftValue": "={{ $json.jwtValid }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -5168, 8400 ], "id": "c3a2edf7-9d21-4c6a-9a63-665ca99b29d4", "name": "JWT v谩lido?" }, { "parameters": { "respondWith": "json", "responseBody": "={{ {ok:false,error:'Sesi贸n Supabase inv谩lida.'} }}", "options": { "responseCode": 401 } }, "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.4, "position": [ -4944, 8688 ], "id": "f8c7aea9-0bdb-4828-badf-98f6caaf9c16", "name": "Responder 401" }, { "parameters": { "url": "={{ 'https://dbit.digitalcompass.agency/rest/v1/cotizador_wmc_access?select=email,full_name,is_active,can_use_tarifario&email=eq.' + encodeURIComponent($json.verifiedEmail) + '&is_active=eq.true' + '&limit=1' }}", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "apikey", "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE" }, { "name": "Authorization", "value": "={{ $json.auth }}" } ] }, "options": { "timeout": 20000 } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ -4944, 8320 ], "id": "2f107a29-ff3b-430a-9879-c6be179d3da3", "name": "Supabase - acceso", "continueOnFail": true }, { "parameters": { "jsCode": "const req = $node[\"Validar identidad\"].json;\nconst raw = $json ?? {};\n\n// n8n 2.21.4 puede convertir una respuesta PostgREST con una sola fila\n// en un objeto individual en vez de conservar el array original.\n// Aceptamos todas las formas posibles de respuesta.\nlet row = null;\n\nif (Array.isArray(raw)) {\n row = raw[0] ?? null;\n} else if (Array.isArray(raw?.data)) {\n row = raw.data[0] ?? null;\n} else if (Array.isArray(raw?.body)) {\n row = raw.body[0] ?? null;\n} else if (raw?.body && typeof raw.body === 'object' && !Array.isArray(raw.body)) {\n row = raw.body;\n} else if (raw && typeof raw === 'object' && ('email' in raw || 'is_active' in raw || 'full_name' in raw)) {\n row = raw;\n}\n\nconst normalizeEmail = (value) => String(value ?? '').trim().toLowerCase();\nconst rowEmail = normalizeEmail(row?.email);\nconst active = row?.is_active === true || String(row?.is_active ?? '').toLowerCase() === 'true';\n\nconst accessAllowed = Boolean(\n row &&\n active &&\n rowEmail &&\n rowEmail === normalizeEmail(req.verifiedEmail)\n);\n\nreturn [{\n json: {\n ...req,\n accessAllowed,\n fullName: row?.full_name || req.user?.name || req.verifiedEmail,\n canUseTarifario: accessAllowed && (\n row?.can_use_tarifario === true ||\n String(row?.can_use_tarifario ?? '').toLowerCase() === 'true'\n ),\n accessLookupOk: Boolean(row)\n }\n}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -4720, 8320 ], "id": "c9ef4878-6880-43af-8040-2040d43c521b", "name": "Validar acceso" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "4539e2f3-4739-4d34-bbe0-4239868c30c4", "leftValue": "={{ $json.accessAllowed }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -4496, 8320 ], "id": "5c315269-c38d-47e2-9d2b-fa02a4f3f1cc", "name": "Acceso permitido?" }, { "parameters": { "respondWith": "json", "responseBody": "={{ {ok:false,error:'No tienes acceso activo al Cotizador Walmart Connect.'} }}", "options": { "responseCode": 403 } }, "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.4, "position": [ -4288, 8688 ], "id": "3a052ddc-3a65-4be0-8375-db968369562e", "name": "Responder 403" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "25b6fd12-c4b4-4938-a319-0572e307e49b", "leftValue": "={{ $json.shouldGenerate }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -4288, 8320 ], "id": "41bbecc4-458e-4bc2-8c68-7b32fa9ef020", "name": "Debe generar?" }, { "parameters": { "respondWith": "json", "responseBody": "={{ {ok:true,skipped:true,message:'La respuesta no requiere crear un archivo.'} }}", "options": { "responseCode": 200 } }, "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.4, "position": [ -4064, 8688 ], "id": "799cfcaf-c04c-4b95-aec0-b2abc39613e1", "name": "Responder sin artefacto" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "cd73b109-158e-4aa8-93ab-40b1c9c77de5", "leftValue": "={{ $json.action }}", "rightValue": "generate_image", "operator": { "type": "string", "operation": "equals" } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -4064, 8320 ], "id": "5a3ec8cb-c3d9-4e5c-8cea-7a389247adc0", "name": "Es imagen?" }, { "parameters": { "resource": "image", "modelId": { "__rl": true, "value": "models/gemini-3-pro-image", "mode": "list", "cachedResultName": "models/gemini-3-pro-image (Nano Banana Pro)" }, "prompt": "={{ $json.artifact?.imagePrompt || $json.artifact?.prompt || $json.artifact?.title || 'Visual profesional para Walmart Connect' }}", "options": { "binaryPropertyOutput": "data" } }, "type": "@n8n/n8n-nodes-langchain.googleGemini", "typeVersion": 1.2, "position": [ -3840, 8080 ], "id": "bc3a2875-1e89-42e5-a2fb-a853901f9f5c", "name": "Gemini - Generar imagen", "retryOnFail": true, "maxTries": 2, "waitBetweenTries": 1500, "credentials": { "googlePalmApi": { "id": "jvsXYwL6IOoY2DBU", "name": "Isaac - Gemini Api Pago" } } }, { "parameters": { "name": "={{ 'WMC_' + String($node[\"Contexto Artefacto\"].json.artifact?.title || 'visual').replace(/[^a-zA-Z0-9谩茅铆贸煤脕脡脥脫脷帽脩_-]+/g,'_').slice(0,80) + '.png' }}", "driveId": { "__rl": true, "mode": "list", "value": "My Drive" }, "folderId": { "__rl": true, "mode": "list", "value": "root", "cachedResultName": "/ (Root folder)" }, "options": { "simplifyOutput": true } }, "type": "n8n-nodes-base.googleDrive", "typeVersion": 3, "position": [ -3616, 8080 ], "id": "f38634c2-9aff-4f37-9b49-f0b951ca5459", "name": "Subir imagen a Drive", "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } } }, { "parameters": { "operation": "share", "fileId": { "__rl": true, "value": "={{ $node[\"Subir imagen a Drive\"].json.id }}", "mode": "id" }, "permissionsUi": { "permissionsValues": { "role": "writer", "type": "domain", "domain": "gomezleemarketing.com" } }, "options": {} }, "type": "n8n-nodes-base.googleDrive", "typeVersion": 3, "position": [ -3392, 8080 ], "id": "27946335-650b-4954-869b-2c20b1d6d717", "name": "Compartir imagen con GomezLee Marketing", "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } } }, { "parameters": { "jsCode": "const req=$node[\"Contexto Artefacto\"].json;\nconst upload=$node[\"Subir imagen a Drive\"].json||{};\nconst id=String(upload.id||'');\nif(!id) return [{json:{ok:false,error:'Google Drive no devolvi贸 el ID de la imagen.',artifactType:null,artifactUrl:null}}];\nreturn [{json:{\n ok:true,\n artifactType:'image',\n artifactUrl:`https://drive.google.com/file/d/${id}/view`,\n artifactId:id,\n title:req.artifact?.title||'Visual WMC',\n quote:req.quote,\n user:{id:req.userId,email:req.verifiedEmail,name:req.fullName},\n conversationId:req.conversationId,\n appSessionId:req.appSessionId,\n provider:'Google Gemini + Google Drive'\n}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -3168, 8080 ], "id": "3227132d-a14c-4d73-bfc8-8dfc7986eee2", "name": "Normalizar imagen generada" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "9f0781ba-0f4e-4d98-a205-e3b17998306b", "leftValue": "={{ $json.action }}", "rightValue": "generate_proposal", "operator": { "type": "string", "operation": "equals" } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -3840, 8432 ], "id": "9eb3b0dd-fbdd-4918-bd5e-19372a67f815", "name": "Es propuesta?" }, { "parameters": { "jsCode": "const req=$node[\"Contexto Artefacto\"].json;\nconst slides=Array.isArray(req.artifact?.slides)?req.artifact.slides:[];\nconst out=[];\nslides.forEach((slide,index)=>{\n const prompt=String(slide?.imagePrompt||'').trim();\n const dark=['cover','section','thankyou'].includes(String(slide?.type||'').toLowerCase());\n if(prompt && !dark && !slide?.imageUrl && !slide?.imageDriveId){\n out.push({json:{...req,hasVisual:true,slideIndex:index,imagePrompt:prompt,slideTitle:String(slide?.title||`Slide ${index+1}`)}});\n }\n});\nif(!out.length) out.push({json:{...req,hasVisual:false}});\nreturn out;" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -3616, 8432 ], "id": "d42489cd-4103-4a16-8479-5d8405e5b1f1", "name": "Preparar visuales propuesta" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "b287fc35-9b12-45a2-bd69-f39a3d455454", "leftValue": "={{ $json.hasVisual }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -3392, 8432 ], "id": "6da63b03-7229-496d-93b1-31936e32b7ae", "name": "Tiene visuales?" }, { "parameters": { "resource": "image", "modelId": { "__rl": true, "value": "models/gemini-3-pro-image", "mode": "list", "cachedResultName": "models/gemini-3-pro-image (Nano Banana Pro)" }, "prompt": "={{ $json.imagePrompt }}", "options": { "binaryPropertyOutput": "data" } }, "type": "@n8n/n8n-nodes-langchain.googleGemini", "typeVersion": 1.2, "position": [ -3168, 8368 ], "id": "22f5b63b-96bd-4cac-ace4-296e9fa91dc1", "name": "Gemini - Visuales propuesta", "retryOnFail": true, "maxTries": 2, "waitBetweenTries": 1500, "credentials": { "googlePalmApi": { "id": "jvsXYwL6IOoY2DBU", "name": "Isaac - Gemini Api Pago" } } }, { "parameters": { "name": "={{ 'WMC_Propuesta_' + ($itemIndex + 1) + '.png' }}", "driveId": { "__rl": true, "mode": "list", "value": "My Drive" }, "folderId": { "__rl": true, "mode": "list", "value": "root", "cachedResultName": "/ (Root folder)" }, "options": { "simplifyOutput": true } }, "type": "n8n-nodes-base.googleDrive", "typeVersion": 3, "position": [ -2960, 8368 ], "id": "fbbe74fb-4b38-499c-9954-19afb75aaf74", "name": "Subir visuales propuesta", "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } } }, { "parameters": { "jsCode": "const req=$node[\"Contexto Artefacto\"].json;\nconst artifact=JSON.parse(JSON.stringify(req.artifact||{}));\nconst slides=Array.isArray(artifact.slides)?artifact.slides:[];\nconst specs=$items(\"Preparar visuales propuesta\").filter(i=>i.json?.hasVisual===true);\nconst uploads=$items(\"Subir visuales propuesta\");\n\nfor(let i=0;i{\n const obj=(ref && typeof ref==='object')?ref:{};\n const prompt=String(obj.imagePrompt||obj.prompt||'').trim();\n const already=String(obj.imageDriveId||obj.driveId||obj.fileId||obj.imageUrl||obj.url||'').trim();\n if(prompt && !already){\n out.push({json:{...req,hasVisual:true,visualIndex:index,imagePrompt:prompt,visualTitle:String(obj.title||`Referencia visual ${index+1}`)}});\n }\n});\nif(!out.length) out.push({json:{...req,hasVisual:false}});\nreturn out;" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -3392, 8560 ], "id": "f107280d-36b5-4d46-b69d-592d79a6a1fb", "name": "Preparar visuales cotizaci贸n" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "d5a0d13b-e1b9-465b-b321-b4c303ede9e1", "leftValue": "={{ $json.hasVisual }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -3168, 8560 ], "id": "1fe96ff3-f7aa-4058-8fd9-1b983d288c10", "name": "Tiene visuales cotizaci贸n?" }, { "parameters": { "resource": "image", "modelId": { "__rl": true, "value": "models/gemini-3-pro-image", "mode": "list", "cachedResultName": "models/gemini-3-pro-image (Nano Banana Pro)" }, "prompt": "={{ $json.imagePrompt }}", "options": { "binaryPropertyOutput": "data" } }, "type": "@n8n/n8n-nodes-langchain.googleGemini", "typeVersion": 1.2, "position": [ -2960, 8528 ], "id": "2f44ef05-7115-4ee2-8202-82adc2f0c979", "name": "Gemini - Visuales cotizaci贸n", "retryOnFail": true, "maxTries": 2, "waitBetweenTries": 1500, "credentials": { "googlePalmApi": { "id": "jvsXYwL6IOoY2DBU", "name": "Isaac - Gemini Api Pago" } } }, { "parameters": { "name": "={{ 'WMC_Cotizacion_Visual_' + ($itemIndex + 1) + '.png' }}", "driveId": { "__rl": true, "mode": "list", "value": "My Drive" }, "folderId": { "__rl": true, "mode": "list", "value": "root", "cachedResultName": "/ (Root folder)" }, "options": { "simplifyOutput": true } }, "type": "n8n-nodes-base.googleDrive", "typeVersion": 3, "position": [ -2736, 8528 ], "id": "e13fdd03-2239-4a23-9d6a-3d8163e58015", "name": "Subir visuales cotizaci贸n", "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } } }, { "parameters": { "jsCode": "const req=$node[\"Contexto Artefacto\"].json;\nconst quote=JSON.parse(JSON.stringify(req.quote||{}));\nconst refs=Array.isArray(quote.visualReferences)?quote.visualReferences:[];\nconst specs=$items(\"Preparar visuales cotizaci贸n\").filter(i=>i.json?.hasVisual===true);\nconst uploads=$items(\"Subir visuales cotizaci贸n\");\nfor(let i=0;i n_(a?.sort_order,0) - n_(b?.sort_order,0))\n .map((it) => ({\n section: it?.section || 'Otros',\n description: it?.description || 'Item',\n units: n_(it?.units, 0),\n days: n_(it?.days, 1),\n unitCostUsd: money_(it?.unit_cost_usd),\n totalUsd: money_(it?.total_usd),\n unitCostLocal: money_(it?.unit_cost_local),\n totalLocal: money_(it?.total_local),\n isEstimated: it?.is_estimated === true,\n confidence: it?.confidence === null || it?.confidence === undefined ? null : n_(it.confidence, 0),\n estimationReason: it?.estimation_reason || null,\n metadata: it?.metadata && typeof it.metadata === 'object' ? it.metadata : {}\n }));\n\n const subtotalUsd = money_(items.reduce((s,it)=>s+n_(it.totalUsd,0),0));\n const subtotalLocal = money_(items.reduce((s,it)=>s+n_(it.totalLocal,0),0));\n const totalUsd = money_(row.total_usd);\n const totalLocal = money_(row.total_local);\n const feeUsd = money_(Math.max(0, totalUsd - subtotalUsd));\n const feeLocal = money_(Math.max(0, totalLocal - subtotalLocal));\n const feeRate = subtotalUsd > 0 ? feeUsd / subtotalUsd : 0;\n\n q = {\n ...q,\n countryCode: String(row.country_code || q.countryCode || '').toUpperCase(),\n country: row.country_name || q.country || countryFor_(row.country_code),\n brandSolution: row.brand_solution || q.brandSolution || 'Walmart Connect',\n project: row.project || q.project || '',\n advertiser: row.advertiser || q.advertiser || '',\n format: row.format || q.format || '',\n exchangeRate: n_(row.exchange_rate, n_(q.exchangeRate,1)),\n currencyCode: row.local_currency_code || q.currencyCode || currencyFor_(row.country_code),\n status: row.status || q.status || 'generated',\n items: items.length ? items : (Array.isArray(q.items) ? q.items : []),\n subtotalUsd,\n subtotalLocal,\n agencyFeeRate: feeRate,\n agencyFeeUsd: feeUsd,\n agencyFeeLocal: feeLocal,\n totalUsd,\n totalLocal,\n documentUrl: row.document_url || q.documentUrl || null\n };\n sourceQuoteId = String(row.id || sourceQuoteId || '');\n}\n\nif (!q.countryCode || !q.country || !q.currencyCode || !Array.isArray(q.items) || !q.items.length) {\n throw new Error('No se encontr贸 una cotizaci贸n WMC previa completa en esta conversaci贸n para mensualizar.');\n}\n\nconst baseSubtotalLocal = money_(q.items.reduce((s,it)=>s+n_(it.totalLocal,0),0));\nconst approvedTotalLocal = money_(q.totalLocal);\nconst approvedTotalUsd = money_(q.totalUsd);\nlet feeLocal = n_(q.agencyFeeLocal, NaN);\nlet feeUsd = n_(q.agencyFeeUsd, NaN);\nlet feeRate = n_(q.agencyFeeRate, NaN);\n\nif (!Number.isFinite(feeLocal)) feeLocal = money_(Math.max(0, approvedTotalLocal - baseSubtotalLocal));\nif (!Number.isFinite(feeUsd)) {\n const subtotalUsd = money_(q.items.reduce((s,it)=>s+n_(it.totalUsd,0),0));\n feeUsd = money_(Math.max(0, approvedTotalUsd - subtotalUsd));\n}\nif (!Number.isFinite(feeRate)) {\n const subtotalUsd = money_(q.items.reduce((s,it)=>s+n_(it.totalUsd,0),0));\n feeRate = subtotalUsd > 0 ? feeUsd / subtotalUsd : 0;\n}\n\nq.agencyFeeLocal = money_(feeLocal);\nq.agencyFeeUsd = money_(feeUsd);\nq.agencyFeeRate = feeRate;\n\nconst monthlyLines = q.items.map(it => ({...it}));\nif (q.agencyFeeLocal > 0.005) {\n monthlyLines.push({\n section: 'Fee de agencia',\n description: `Fee de agencia (${(q.agencyFeeRate * 100).toFixed(2).replace(/\\.00$/,'')}%)`,\n units: 1,\n days: 1,\n unitCostUsd: q.agencyFeeUsd,\n totalUsd: q.agencyFeeUsd,\n unitCostLocal: q.agencyFeeLocal,\n totalLocal: q.agencyFeeLocal,\n isEstimated: false,\n confidence: 1,\n estimationReason: null,\n metadata: {systemGeneratedFromApprovedWmcTotal:true}\n });\n}\n\nconst artifact = JSON.parse(JSON.stringify(req.artifact || {}));\nartifact.sourceQuoteId = sourceQuoteId || artifact.sourceQuoteId || null;\nartifact.monthlyLines = monthlyLines;\nartifact.metadata = {\n ...(artifact.metadata && typeof artifact.metadata === 'object' ? artifact.metadata : {}),\n sourceQuoteId: artifact.sourceQuoteId,\n sourceDocumentUrl: q.documentUrl || null,\n countryCode: q.countryCode,\n country: q.country,\n currencyCode: q.currencyCode,\n exchangeRate: q.exchangeRate,\n approvedWmcTotalUsd: approvedTotalUsd,\n approvedWmcTotalLocal: approvedTotalLocal,\n agencyFeeRate: q.agencyFeeRate,\n agencyFeeUsd: q.agencyFeeUsd,\n agencyFeeLocal: q.agencyFeeLocal,\n walmartApproved: true,\n glmIvaRate: 0.12\n};\n\nreturn [{json:{...req,quote:q,artifact}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -2944, 8688 ], "id": "fd12a715-5138-46ec-8e50-a4c5e70a0f81", "name": "Hidratar mensualizaci贸n aprobada" }, { "parameters": { "operation": "share", "fileId": { "__rl": true, "value": "={{ $json.id }}", "mode": "id" }, "permissionsUi": { "permissionsValues": { "role": "writer", "type": "domain", "domain": "gomezleemarketing.com" } }, "options": {} }, "type": "n8n-nodes-base.googleDrive", "typeVersion": 3, "position": [ -2736, 8272 ], "id": "762165ec-1698-423a-a2f1-bc693d337532", "name": "Compartir visuales propuesta con GomezLee Marketing", "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } } }, { "parameters": { "operation": "share", "fileId": { "__rl": true, "value": "={{ $json.id }}", "mode": "id" }, "permissionsUi": { "permissionsValues": { "role": "writer", "type": "domain", "domain": "gomezleemarketing.com" } }, "options": {} }, "type": "n8n-nodes-base.googleDrive", "typeVersion": 3, "position": [ -2512, 8752 ], "id": "f8aff62a-85af-4d36-8981-fed579a7be1e", "name": "Compartir visuales cotizaci贸n con GomezLee Marketing", "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } } }, { "parameters": { "jsCode": "const a = $json ?? {};\n\nif (a.ok === false) {\n return [{json:{...a,shareFileId:null,shareRequired:false}}];\n}\n\nlet id = String(a.artifactId || '').trim();\nconst url = String(a.artifactUrl || '').trim();\n\nif (!id && url) {\n const patterns = [\n /\\/d\\/([A-Za-z0-9_-]{20,})/,\n /[?&]id=([A-Za-z0-9_-]{20,})/,\n /\\/folders\\/([A-Za-z0-9_-]{20,})/\n ];\n for (const pattern of patterns) {\n const match = url.match(pattern);\n if (match?.[1]) {\n id = match[1];\n break;\n }\n }\n}\n\nif (!id) {\n throw new Error('No se pudo identificar el archivo de Google Workspace para aplicar el acceso de GomezLee Marketing.');\n}\n\nreturn [{json:{...a,shareFileId:id,shareRequired:true}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -1392, 8480 ], "id": "6f44d625-0528-4a0e-9285-880a136e37e9", "name": "Preparar permiso GomezLee Marketing" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "c8060fe4-e989-4cea-8b44-3e1f0e0c153c", "leftValue": "={{ $json.shareRequired }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -1168, 8480 ], "id": "d5bf4b40-b2b7-40ac-abdc-19022b65d8a0", "name": "驴Archivo Google para compartir?" }, { "parameters": { "operation": "share", "fileId": { "__rl": true, "value": "={{ $json.shareFileId }}", "mode": "id" }, "permissionsUi": { "permissionsValues": { "role": "writer", "type": "domain", "domain": "gomezleemarketing.com" } }, "options": {} }, "type": "n8n-nodes-base.googleDrive", "typeVersion": 3, "position": [ -944, 8368 ], "id": "0755c9e3-db77-4263-a135-10c9e6edc017", "name": "Compartir archivo final con GomezLee Marketing", "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } } }, { "parameters": { "jsCode": "const original = $node[\"Normalizar resultado\"].json ?? {};\nreturn [{json:original}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -704, 8368 ], "id": "ded9cefe-006e-44bc-9ffb-1df081b8a59a", "name": "Restaurar resultado tras compartir" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "889b613b-a5d6-4362-bac9-969a9776b06f", "leftValue": "={{ $json.internalEmail }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -5600, 7952 ], "id": "08fb954f-6326-4cbf-814f-8961d3252511", "name": "驴Solicitud interna email?" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "5ee8550d-b245-47c1-9c58-722bf3e0c7d1", "leftValue": "={{ $json.internalAuthorized }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -5376, 7952 ], "id": "5fbba220-1d24-4348-8c43-745664a9b848", "name": "Interno autorizado?" }, { "parameters": { "respondWith": "json", "responseBody": "={{ {ok:false,error:'Solicitud interna no autorizada.'} }}", "options": { "responseCode": 401 } }, "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.4, "position": [ -5152, 8128 ], "id": "4fb3d352-64b1-4c11-aa23-1e802e8c00c4", "name": "Responder 401 Interno" }, { "parameters": { "jsCode": "const req=$node[\"Normalizar solicitud\"].json;\nconst email=String(req.user?.email||'wmc@gomezlee.marketing').trim().toLowerCase();\nreturn [{json:{...req,userId:null,verifiedEmail:email,fullName:req.user?.name||'Walmart Connect Email Agent',accessAllowed:true,canUseTarifario:false,internalEmail:true}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -5152, 7872 ], "id": "be28584f-082d-4774-818f-6670465432e8", "name": "Autorizar email interno" }, { "parameters": { "jsCode": "const x=$json??{};\nreturn [{json:{...x,internalEmail:Boolean(x.internalEmail)}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -4064, 8128 ], "id": "f832489e-9cf7-43ad-b246-0b89204dda0a", "name": "Contexto Artefacto" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "03140a28-4f09-4a9c-b82b-4c6eeced8c17", "leftValue": "={{ $node[\"Contexto Artefacto\"].json.internalEmail }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ 80, 7968 ], "id": "3c1eaefc-44eb-4e31-8e9c-bacae9e6c86e", "name": "驴Imagen interna email?" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "12b1ba07-d2ac-47df-9c66-5e18bdb41d79", "leftValue": "={{ $node[\"Contexto Artefacto\"].json.internalEmail }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ 112, 8400 ], "id": "e2370114-e36a-49f0-97a6-313a1af66866", "name": "驴Resultado interno email?" }, { "parameters": { "jsCode": "const a=$json??{};\nreturn [{json:{ok:a.ok!==false,artifactUrl:a.artifactUrl||null,artifactType:a.artifactType||null,artifactId:a.artifactId||null,quoteId:null,title:a.title||null,error:a.error||null}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 320, 8160 ], "id": "c6fe38d4-fa37-49a8-aa84-c7065a763b3b", "name": "Preparar respuesta interna Artefactos" }, { "parameters": { "respondWith": "json", "responseBody": "={{ $json }}", "options": { "responseCode": 200 } }, "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.4, "position": [ 560, 8160 ], "id": "eba6e35b-623e-4e6d-bdb2-00b943a5873a", "name": "Responder artefacto interno" } ], "connections": { "Webhook - Artefactos": { "main": [ [ { "node": "Configuraci贸n - sin ENV", "type": "main", "index": 0 } ] ] }, "Configuraci贸n - sin ENV": { "main": [ [ { "node": "Normalizar solicitud", "type": "main", "index": 0 } ] ] }, "Normalizar solicitud": { "main": [ [ { "node": "驴Solicitud interna email?", "type": "main", "index": 0 } ] ] }, "Supabase - validar JWT": { "main": [ [ { "node": "Validar identidad", "type": "main", "index": 0 } ] ] }, "Validar identidad": { "main": [ [ { "node": "JWT v谩lido?", "type": "main", "index": 0 } ] ] }, "JWT v谩lido?": { "main": [ [ { "node": "Supabase - acceso", "type": "main", "index": 0 } ], [ { "node": "Responder 401", "type": "main", "index": 0 } ] ] }, "Supabase - acceso": { "main": [ [ { "node": "Validar acceso", "type": "main", "index": 0 } ] ] }, "Validar acceso": { "main": [ [ { "node": "Acceso permitido?", "type": "main", "index": 0 } ] ] }, "Acceso permitido?": { "main": [ [ { "node": "Contexto Artefacto", "type": "main", "index": 0 } ], [ { "node": "Responder 403", "type": "main", "index": 0 } ] ] }, "Debe generar?": { "main": [ [ { "node": "Es imagen?", "type": "main", "index": 0 } ], [ { "node": "Responder sin artefacto", "type": "main", "index": 0 } ] ] }, "Es imagen?": { "main": [ [ { "node": "Gemini - Generar imagen", "type": "main", "index": 0 } ], [ { "node": "Es propuesta?", "type": "main", "index": 0 } ] ] }, "Gemini - Generar imagen": { "main": [ [ { "node": "Subir imagen a Drive", "type": "main", "index": 0 } ] ] }, "Subir imagen a Drive": { "main": [ [ { "node": "Compartir imagen con GomezLee Marketing", "type": "main", "index": 0 } ] ] }, "Normalizar imagen generada": { "main": [ [ { "node": "驴Imagen interna email?", "type": "main", "index": 0 } ] ] }, "Es propuesta?": { "main": [ [ { "node": "Preparar visuales propuesta", "type": "main", "index": 0 } ], [ { "node": "Acci贸n es cotizaci贸n?", "type": "main", "index": 0 } ] ] }, "Preparar visuales propuesta": { "main": [ [ { "node": "Tiene visuales?", "type": "main", "index": 0 } ] ] }, "Tiene visuales?": { "main": [ [ { "node": "Gemini - Visuales propuesta", "type": "main", "index": 0 } ], [ { "node": "Preparar Google", "type": "main", "index": 0 } ] ] }, "Gemini - Visuales propuesta": { "main": [ [ { "node": "Subir visuales propuesta", "type": "main", "index": 0 } ] ] }, "Subir visuales propuesta": { "main": [ [ { "node": "Compartir visuales propuesta con GomezLee Marketing", "type": "main", "index": 0 } ] ] }, "Recomponer propuesta": { "main": [ [ { "node": "Preparar Google", "type": "main", "index": 0 } ] ] }, "Preparar Google": { "main": [ [ { "node": "Google Automation", "type": "main", "index": 0 } ] ] }, "Google Automation": { "main": [ [ { "node": "Normalizar resultado", "type": "main", "index": 0 } ] ] }, "Normalizar resultado": { "main": [ [ { "node": "驴Resultado interno email?", "type": "main", "index": 0 } ] ] }, "Guardar cotizaci贸n Supabase": { "main": [ [ { "node": "Preparar respuesta cotizaci贸n", "type": "main", "index": 0 } ] ] }, "Preparar respuesta cotizaci贸n": { "main": [ [ { "node": "Responder artefacto", "type": "main", "index": 0 } ] ] }, "Guardar otro artefacto Supabase": { "main": [ [ { "node": "Preparar respuesta artefacto", "type": "main", "index": 0 } ] ] }, "Preparar respuesta artefacto": { "main": [ [ { "node": "Responder artefacto", "type": "main", "index": 0 } ] ] }, "Resultado es cotizaci贸n?": { "main": [ [ { "node": "Guardar cotizaci贸n Supabase", "type": "main", "index": 0 } ], [ { "node": "Guardar otro artefacto Supabase", "type": "main", "index": 0 } ] ] }, "Acci贸n es cotizaci贸n?": { "main": [ [ { "node": "Preparar visuales cotizaci贸n", "type": "main", "index": 0 } ], [ { "node": "Es mensualizaci贸n?", "type": "main", "index": 0 } ] ] }, "Preparar visuales cotizaci贸n": { "main": [ [ { "node": "Tiene visuales cotizaci贸n?", "type": "main", "index": 0 } ] ] }, "Tiene visuales cotizaci贸n?": { "main": [ [ { "node": "Gemini - Visuales cotizaci贸n", "type": "main", "index": 0 } ], [ { "node": "Preparar Google", "type": "main", "index": 0 } ] ] }, "Gemini - Visuales cotizaci贸n": { "main": [ [ { "node": "Subir visuales cotizaci贸n", "type": "main", "index": 0 } ] ] }, "Subir visuales cotizaci贸n": { "main": [ [ { "node": "Compartir visuales cotizaci贸n con GomezLee Marketing", "type": "main", "index": 0 } ] ] }, "Recomponer cotizaci贸n": { "main": [ [ { "node": "Preparar Google", "type": "main", "index": 0 } ] ] }, "Es mensualizaci贸n?": { "main": [ [ { "node": "Supabase - 煤ltima cotizaci贸n WMC", "type": "main", "index": 0 } ], [ { "node": "Preparar Google", "type": "main", "index": 0 } ] ] }, "Supabase - 煤ltima cotizaci贸n WMC": { "main": [ [ { "node": "Hidratar mensualizaci贸n aprobada", "type": "main", "index": 0 } ] ] }, "Hidratar mensualizaci贸n aprobada": { "main": [ [ { "node": "Preparar Google", "type": "main", "index": 0 } ] ] }, "Compartir imagen con GomezLee Marketing": { "main": [ [ { "node": "Normalizar imagen generada", "type": "main", "index": 0 } ] ] }, "Compartir visuales propuesta con GomezLee Marketing": { "main": [ [ { "node": "Recomponer propuesta", "type": "main", "index": 0 } ] ] }, "Compartir visuales cotizaci贸n con GomezLee Marketing": { "main": [ [ { "node": "Recomponer cotizaci贸n", "type": "main", "index": 0 } ] ] }, "Preparar permiso GomezLee Marketing": { "main": [ [ { "node": "驴Archivo Google para compartir?", "type": "main", "index": 0 } ] ] }, "驴Archivo Google para compartir?": { "main": [ [ { "node": "Compartir archivo final con GomezLee Marketing", "type": "main", "index": 0 } ], [ { "node": "Resultado es cotizaci贸n?", "type": "main", "index": 0 } ] ] }, "Compartir archivo final con GomezLee Marketing": { "main": [ [ { "node": "Restaurar resultado tras compartir", "type": "main", "index": 0 } ] ] }, "Restaurar resultado tras compartir": { "main": [ [ { "node": "Resultado es cotizaci贸n?", "type": "main", "index": 0 } ] ] }, "驴Solicitud interna email?": { "main": [ [ { "node": "Interno autorizado?", "type": "main", "index": 0 } ], [ { "node": "Supabase - validar JWT", "type": "main", "index": 0 } ] ] }, "Interno autorizado?": { "main": [ [ { "node": "Autorizar email interno", "type": "main", "index": 0 } ], [ { "node": "Responder 401 Interno", "type": "main", "index": 0 } ] ] }, "Autorizar email interno": { "main": [ [ { "node": "Contexto Artefacto", "type": "main", "index": 0 } ] ] }, "Contexto Artefacto": { "main": [ [ { "node": "Debe generar?", "type": "main", "index": 0 } ] ] }, "驴Imagen interna email?": { "main": [ [ { "node": "Preparar respuesta interna Artefactos", "type": "main", "index": 0 } ], [ { "node": "Guardar otro artefacto Supabase", "type": "main", "index": 0 } ] ] }, "驴Resultado interno email?": { "main": [ [ { "node": "Preparar respuesta interna Artefactos", "type": "main", "index": 0 } ], [ { "node": "Preparar permiso GomezLee Marketing", "type": "main", "index": 0 } ] ] }, "Preparar respuesta interna Artefactos": { "main": [ [ { "node": "Responder artefacto interno", "type": "main", "index": 0 } ] ] } }, "authors": "Isaac Aracena", "name": "Version 59b8fc04", "description": "", "autosaved": true, "workflowPublishHistory": [ { "createdAt": "2026-08-29T16:24:37.308Z", "id": 5304, "workflowId": "kHT6jUVIcYGjagV3", "versionId": "59b8fc04-1a98-4aa6-b66f-fd437fe59265", "event": "activated", "userId": "0a88c0b1-928e-4412-896e-c5d1c99b2029" } ] } }