{ "updatedAt": "2026-06-16T20:43:37.592Z", "createdAt": "2026-06-16T17:22:11.395Z", "id": "g2JtKXNz5GDbkmQH", "name": "DEV - Tablero CDC - Refrescar Banco Fulgencio Diario", "description": null, "active": true, "isArchived": false, "nodes": [ { "parameters": { "rule": { "interval": [ { "triggerAtHour": 23 } ] } }, "type": "n8n-nodes-base.scheduleTrigger", "typeVersion": 1.3, "position": [ 0, 0 ], "id": "37cc170e-2f53-4e2e-915a-f6020e701c2e", "name": "Schedule Trigger" }, { "parameters": { "documentId": { "__rl": true, "value": "17WDzCrgHy67oIK7y0UUkxiMXzTgTvENPXcsfjK9lmio", "mode": "list", "cachedResultName": "TEST - BANCO DE PROPUESTAS CDC FULGENCIO REFRESCO", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/17WDzCrgHy67oIK7y0UUkxiMXzTgTvENPXcsfjK9lmio/edit?usp=drivesdk" }, "sheetName": { "__rl": true, "value": "gid=0", "mode": "list", "cachedResultName": "propuestas", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/17WDzCrgHy67oIK7y0UUkxiMXzTgTvENPXcsfjK9lmio/edit#gid=0" }, "options": {} }, "type": "n8n-nodes-base.googleSheets", "typeVersion": 4.7, "position": [ 208, 0 ], "id": "da0ce8a1-0efe-4f5b-909d-7f64b67e8f3b", "name": "Sheets - Leer Banco Fulgencio", "credentials": { "googleSheetsOAuth2Api": { "id": "K0hDZh3a85MpOHCs", "name": "Google Sheets account 2" } } }, { "parameters": { "jsCode": "function clean(value) {\n return String(value ?? '').trim();\n}\n\nfunction extractGoogleFileId(url) {\n const text = clean(url);\n\n if (!text) return '';\n\n const patterns = [\n /\\/d\\/([a-zA-Z0-9_-]+)/,\n /id=([a-zA-Z0-9_-]+)/,\n /\\/file\\/d\\/([a-zA-Z0-9_-]+)/,\n /\\/presentation\\/d\\/([a-zA-Z0-9_-]+)/,\n ];\n\n for (const pattern of patterns) {\n const match = text.match(pattern);\n if (match && match[1]) return match[1];\n }\n\n return '';\n}\n\nconst rows = $input.all();\n\nconst result = [];\n\nfor (const item of rows) {\n const row = item.json || {};\n\n const origen = clean(row.tablero_origen);\n const syncKey = clean(row.tablero_sync_key);\n const projectId = clean(row.tablero_project_id);\n const proposalUrl = clean(row['Enlace a la propuesta']);\n const existingFileId = clean(row.file_id);\n const fileId = existingFileId || extractGoogleFileId(proposalUrl);\n\n if (origen !== 'Tablero CDC') continue;\n if (!syncKey) continue;\n if (!projectId) continue;\n if (!proposalUrl) continue;\n\n result.push({\n json: {\n ...row,\n file_id_refresco: fileId,\n proposal_url_refresco: proposalUrl,\n refresh_attempts_actual: Number(row.refresh_attempts || 0),\n },\n });\n}\n\nreturn result.slice(0, 1);" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 416, 0 ], "id": "1422a9de-12a8-4b2d-bda9-9dc7193a5d67", "name": "Code - Filtrar filas Tablero CDC" }, { "parameters": { "options": {} }, "type": "n8n-nodes-base.splitInBatches", "typeVersion": 3, "position": [ 640, 0 ], "id": "3fb77467-0f3c-419e-8a6e-ab44d118ceef", "name": "Loop - Filas Banco Fulgencio" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 }, "conditions": [ { "id": "8c79f0ce-b901-43c8-b863-ad490d267c37", "leftValue": "={{ $json.file_id_refresco }}", "rightValue": "", "operator": { "type": "string", "operation": "notEmpty", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ 800, -144 ], "id": "6896c55a-b17b-41bf-8f99-3fa949c29d67", "name": "IF - Tiene file_id?" }, { "parameters": { "url": "=https://www.googleapis.com/drive/v3/files/{{$json.file_id_refresco}}?fields=id,name,mimeType,modifiedTime,webViewLink&supportsAllDrives=true", "authentication": "predefinedCredentialType", "nodeCredentialType": "googleDriveOAuth2Api", "options": {} }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 992, -368 ], "id": "40ccb6f9-4e2d-4b21-ad1c-583151c84641", "name": "HTTP - Obtener metadata Drive", "retryOnFail": true, "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } }, "onError": "continueErrorOutput" }, { "parameters": { "jsCode": "const original = $('IF - Tiene file_id?').item.json || {};\nconst metadata = $json || {};\n\nfunction clean(value) {\n return String(value ?? '').trim();\n}\n\nfunction toDate(value) {\n const date = value ? new Date(value) : null;\n if (!date || Number.isNaN(date.getTime())) return null;\n return date;\n}\n\nconst driveModifiedTime = clean(metadata.modifiedTime || metadata.modified_time);\nconst lastRefresh = clean(original.ultimo_refresco_ia);\nconst existingDriveModified = clean(original.drive_modified_time);\n\nconst driveDate = toDate(driveModifiedTime);\nconst lastRefreshDate = toDate(lastRefresh);\nconst existingDriveDate = toDate(existingDriveModified);\n\nlet shouldRefresh = false;\nlet reason = '';\n\nif (!driveDate) {\n shouldRefresh = false;\n reason = 'sin_modified_time';\n} else if (!lastRefreshDate) {\n shouldRefresh = true;\n reason = 'nunca_refrescado';\n} else if (driveDate > lastRefreshDate) {\n shouldRefresh = true;\n reason = 'archivo_modificado_desde_ultimo_refresco';\n} else if (existingDriveDate && driveDate > existingDriveDate) {\n shouldRefresh = true;\n reason = 'drive_modified_time_cambio';\n} else {\n shouldRefresh = false;\n reason = 'sin_cambios';\n}\n\nreturn [\n {\n json: {\n ...original,\n drive_file_id: metadata.id || original.file_id_refresco,\n drive_name: metadata.name || '',\n drive_mime_type: metadata.mimeType || '',\n drive_modified_time_actual: driveModifiedTime,\n should_refresh: shouldRefresh,\n refresh_reason: reason,\n },\n },\n];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 1936, -224 ], "id": "ebeb387e-0038-4166-b3a9-bdfdd863550a", "name": "Code - Evaluar refresco" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 }, "conditions": [ { "id": "a6356649-3547-40be-bdc6-55730f280fa9", "leftValue": "={{ $json.should_refresh }}", "rightValue": "", "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ 2112, -224 ], "id": "a0ac9c90-9029-41de-9338-1d076f045947", "name": "IF - Debe refrescar?" }, { "parameters": { "url": "=https://www.googleapis.com/drive/v3/files/{{ $json.drive_file_id }}/export?mimeType=text/plain", "authentication": "predefinedCredentialType", "nodeCredentialType": "googleDriveOAuth2Api", "options": { "response": { "response": { "responseFormat": "text" } } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 2400, -288 ], "id": "2eabdc4e-1bb5-4f8a-bacb-844e87d379c0", "name": "HTTP - Exportar Slides TXT", "retryOnFail": true, "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } }, "onError": "continueErrorOutput" }, { "parameters": { "jsCode": "const original = $('Code - Evaluar refresco').item.json || {};\nconst incoming = $json || {};\n\nfunction clean(value) {\n return String(value ?? '').trim().replace(/\\s+/g, ' ');\n}\n\nlet exportedText = '';\n\nif (typeof incoming === 'string') {\n exportedText = incoming;\n} else {\n exportedText =\n incoming.body ||\n incoming.data ||\n incoming.text ||\n incoming.content ||\n incoming.response ||\n '';\n}\n\nexportedText = clean(exportedText);\n\nconst hasContent = exportedText.length >= 80;\n\nreturn [\n {\n json: {\n ...original,\n contenido_presentacion: exportedText.slice(0, 18000),\n contenido_chars: exportedText.length,\n contenido_valido: hasContent,\n refresh_attempts: Number(original.refresh_attempts_actual || 0) + 1,\n },\n },\n];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 2672, -384 ], "id": "fadb71e0-541f-4cc0-8e03-be43fb3fd841", "name": "Code - Preparar texto IA Refresco" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 }, "conditions": [ { "id": "c0faa484-9c5d-4af3-b725-bfbc67f7f89d", "leftValue": "={{ $json.contenido_valido }}", "rightValue": "", "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ 2880, -384 ], "id": "cade8a8b-995a-4951-9b76-7f695a10fe7d", "name": "IF - Tiene contenido?" }, { "parameters": { "text": "=Nombre de la propuesta: {{$json.NOMBRE}}\nCliente: {{$json.CLIENTE}}\nMarca: {{$json.MARCA}}\nPaís: {{$json.PAIS}}\nLink: {{$json[\"Enlace a la propuesta\"]}}\n\nContenido exportado de la presentación:\n{{$json.contenido_presentacion}}", "attributes": { "attributes": [ { "name": "nombre_propuesta", "description": "Nombre limpio o comercial de la propuesta." }, { "name": "tipo_accion", "description": "Tipo de acción o formato de propuesta. Ejemplos: campaña, evento, mueble, exhibidor, diseño gráfico, activación PDV, material POP, uniforme, promoción, stand. Si no se puede determinar, usar PENDIENTE." }, { "name": "canal", "description": "Canal o lugar donde aplica la propuesta. Ejemplos: moderno, tradicional, online, PDV, no aplica. Si no se puede determinar, usar PENDIENTE." }, { "name": "tags", "description": "Palabras clave separadas por comas para facilitar búsqueda. Ejemplos: campaña, corporativo, exhibidor, punto de venta, juegos, uniforme, material POP." }, { "name": "descripcion", "description": "Párrafo profesional de 35 a 70 palabras. Debe iniciar preferiblemente con “La presentación muestra...”, “La pieza muestra...” o “La propuesta corresponde a...”. Debe mencionar cliente/marca, tipo de acción, concepto o tema principal y objetivo. No inventar detalles." }, { "name": "tactica_promocional", "description": "Táctica promocional principal. Ejemplos: DEGUSTACIÓN, RULETA, SAMPLING - MUESTREO, PLINKO, WHATSAPP, LANDING PAGE, POP, PHOTOBOOTH, CANJE, SORTEO, PREMIOS INSTANTÁNEOS, JUEGO DIGITAL, TRIVIA, EXHIBICIÓN, IMPULSO o PENDIENTE." } ] }, "options": { "systemPromptTemplate": "Analiza el contenido real exportado de una presentación de Google Slides para actualizar el banco de propuestas de Fulgencio Fumado.\n\nIMPORTANTE:\n- Usa el contenido de la presentación como fuente principal.\n- No cambies el país, cliente ni marca recibidos desde Tablero CDC.\n- No determines APROBADA. Ese campo debe quedar como PENDIENTE DE APROBACION.\n- No determines AMBIENTE DE COMPRA (RE). Ese campo debe quedar como PENDIENTE.\n- Si el contenido es insuficiente, usa PENDIENTE.\n- No inventes detalles.\n- Devuelve:\n nombre_propuesta\n tipo_accion\n canal\n tags\n descripcion\n tactica_promocional" } }, "type": "@n8n/n8n-nodes-langchain.informationExtractor", "typeVersion": 1.2, "position": [ 3488, -448 ], "id": "08c0d48c-400f-454a-832d-9e08d4724fbd", "name": "Gemini - Reanalizar contenido Slides" }, { "parameters": { "modelName": "models/gemini-3.1-pro-preview", "options": {} }, "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini", "typeVersion": 1.1, "position": [ 3488, -240 ], "id": "5875c1c9-5aa3-4f60-a3ee-f94e0293ec04", "name": "Google Gemini Chat Model", "credentials": { "googlePalmApi": { "id": "jvsXYwL6IOoY2DBU", "name": "Isaac - Gemini Api Pago" } } }, { "parameters": { "jsCode": "const original = $('Code - Preparar texto IA Refresco').item.json || {};\nconst incoming = $input.first().json || {};\nconst ai = incoming.output || incoming;\n\nfunction clean(value) {\n if (Array.isArray(value)) return value.map(clean).filter(Boolean).join(', ');\n return String(value ?? '').trim().replace(/\\s+/g, ' ');\n}\n\nfunction removeAccents(value) {\n return clean(value)\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '');\n}\n\nfunction upper(value) {\n return removeAccents(value).toUpperCase();\n}\n\nfunction splitMulti(value) {\n return clean(value)\n .split(',')\n .map(v => upper(v))\n .map(v => v.trim())\n .filter(Boolean);\n}\n\nfunction unique(values) {\n return [...new Set(values.filter(Boolean))];\n}\n\nfunction joinMulti(values) {\n return unique(values).join(', ');\n}\n\nfunction normalizeTipoAccion(value) {\n const v = upper(value);\n\n const synonyms = {\n 'ACTIVACION PDV': 'ACTIVACION EN PDV',\n 'ACTIVACION EN PUNTO DE VENTA': 'ACTIVACION EN PDV',\n 'ACTIVACION PUNTO DE VENTA': 'ACTIVACION EN PDV',\n 'PUNTO DE VENTA': 'ACTIVACION EN PDV',\n 'PDV': 'ACTIVACION EN PDV',\n 'DISEÑO GRAFICO': 'DISENO GRAFICO',\n 'DISEÑO GRÁFICO': 'DISENO GRAFICO',\n 'DISENO GRAFICO': 'DISENO GRAFICO',\n 'CAMPAÑA': 'CAMPAÑA',\n 'CAMPANA': 'CAMPAÑA',\n 'PROMOCION': 'PROMOCION',\n 'PROMOCIÓN': 'PROMOCION',\n 'MUEBLE': 'MUEBLE',\n 'EXHIBIDOR': 'MUEBLE',\n 'STAND': 'STAND',\n 'EVENTO': 'EVENTO',\n 'UNIFORME': 'UNIFORME',\n 'MATERIAL POP': 'DISENO GRAFICO',\n 'POP': 'DISENO GRAFICO'\n };\n\n return synonyms[v] || v;\n}\n\nfunction normalizeCanal(value) {\n const v = upper(value);\n\n const synonyms = {\n 'PUNTO DE VENTA': 'PDV',\n 'PDV': 'PDV',\n 'CANAL MODERNO': 'MODERNO',\n 'MODERNO': 'MODERNO',\n 'CANAL TRADICIONAL': 'TRADICIONAL',\n 'TRADICIONAL': 'TRADICIONAL',\n 'DIGITAL': 'ONLINE',\n 'ONLINE': 'ONLINE',\n 'NO APLICA': 'NO APLICA',\n 'N/A': 'NO APLICA'\n };\n\n return synonyms[v] || v;\n}\n\nfunction normalizeTactica(value) {\n const v = upper(value);\n\n const synonyms = {\n 'SAMPLING': 'SAMPLING - MUESTREO',\n 'MUESTREO': 'SAMPLING - MUESTREO',\n 'DEGUSTACION': 'DEGUSTACIÓN',\n 'DEGUSTACIÓN': 'DEGUSTACIÓN',\n 'RULETA DIGITAL': 'RULETA',\n 'RULETA': 'RULETA',\n 'PLINKO': 'PLINKO',\n 'WHATSAPP': 'WHATSAPP',\n 'LANDING': 'LANDING PAGE',\n 'LANDING PAGE': 'LANDING PAGE',\n 'MATERIAL POP': 'POP',\n 'POP': 'POP',\n 'JUEGO DIGITAL': 'JUEGO DIGITAL',\n 'JUEGOS DIGITALES': 'JUEGO DIGITAL',\n 'EXHIBICION': 'EXHIBICIÓN',\n 'EXHIBICIÓN': 'EXHIBICIÓN',\n 'IMPULSO': 'IMPULSO'\n };\n\n return synonyms[v] || v;\n}\n\nfunction normalizeEtiqueta(value) {\n const v = upper(value);\n\n const synonyms = {\n 'ACTIVACION': 'ACTIVACION',\n 'ACTIVACIÓN': 'ACTIVACION',\n 'EXHIBICION': 'EXHIBICION',\n 'EXHIBICIÓN': 'EXHIBICION',\n 'EXHIBIDOR': 'EXHIBIDOR',\n 'DEGUSTACION': 'DEGUSTACION',\n 'DEGUSTACIÓN': 'DEGUSTACION',\n 'PROMOCION': 'PROMOCIÓN',\n 'PROMOCIÓN': 'PROMOCIÓN',\n 'DISENO': 'DISEÑO',\n 'DISEÑO': 'DISEÑO',\n 'CAMPANA': 'CAMPAÑA',\n 'CAMPAÑA': 'CAMPAÑA',\n 'JUEGO DIGITAL': 'JUEGOS DIGITALES',\n 'JUEGOS DIGITALES': 'JUEGOS DIGITALES',\n 'PUNTO DE VENTA': 'PUNTO DE VENTA',\n 'PDV': 'PUNTO DE VENTA',\n 'F1': 'JUEGOS',\n 'SIMULADOR': 'JUEGOS DIGITALES',\n 'EXPERIENCIA': 'ACTIVIDADES',\n 'CORPORATIVO': 'CORPORATIVO',\n 'UNIFORME': 'UNIFORMES',\n 'UNIFORMES': 'UNIFORMES',\n 'POP': 'PUNTO DE VENTA',\n 'MATERIAL POP': 'PUNTO DE VENTA'\n };\n\n return synonyms[v] || v;\n}\n\nfunction normalizeOne(value, allowedList, fallback = 'PENDIENTE', normalizer = upper) {\n const raw = clean(value);\n if (!raw) return fallback;\n\n const mapped = normalizer(raw);\n return allowedList.includes(mapped) ? mapped : fallback;\n}\n\nfunction normalizeMulti(value, allowedList, fallback = 'PENDIENTE', unknownValue = 'OTRO', normalizer = upper) {\n const parts = splitMulti(value);\n if (!parts.length) return fallback;\n\n const result = [];\n\n for (const part of parts) {\n const mapped = normalizer(part);\n const expanded = String(mapped)\n .split(',')\n .map(v => v.trim())\n .filter(Boolean);\n\n for (const val of expanded) {\n if (allowedList.includes(val)) {\n result.push(val);\n } else {\n result.push(unknownValue);\n }\n }\n }\n\n const finalValues = unique(result);\n if (!finalValues.length) return fallback;\n\n return joinMulti(finalValues);\n}\n\nconst ALLOWED_TIPO_ACCION = [\n 'ACTIVACION EN PDV',\n 'IMPULSO DE VENTA',\n 'ACTIVACION FUERA DE PDV',\n 'EVENTO',\n 'KICK OFF',\n 'FERIA',\n 'STAND',\n 'MUEBLE',\n 'DISENO GRAFICO',\n 'DIGITAL',\n 'PUBLICIDAD',\n 'TUTORIAL',\n 'INFORMATIVA',\n 'LOGOTIPO',\n 'PROMOCION',\n 'UNIFORME',\n 'ACTIVACIÓN',\n 'INAUGURACIÓN',\n 'PARQUE',\n 'TROFEO',\n 'ANAQUEL',\n 'FOOD TRUCK',\n 'EMPAQUES',\n 'CAMPAÑA',\n 'QUICK COUNTER',\n 'DISEÑO',\n 'PPT',\n 'PENDIENTE',\n 'OTRO'\n];\n\nconst ALLOWED_CANAL = [\n 'MODERNO',\n 'TRADICIONAL',\n 'ONLINE',\n 'NO APLICA',\n 'PDV',\n 'PENDIENTE'\n];\n\nconst ALLOWED_TACTICA = [\n 'DEGUSTACIÓN',\n 'RULETA',\n 'SAMPLING - MUESTREO',\n 'PLINKO',\n 'WHATSAPP',\n 'LANDING PAGE',\n 'POP',\n 'PHOTOBOOTH',\n 'CANJE',\n 'SORTEO',\n 'PREMIOS INSTANTÁNEOS',\n 'JUEGO DIGITAL',\n 'TRIVIA',\n 'EXHIBICIÓN',\n 'IMPULSO',\n 'PENDIENTE',\n 'OTRO'\n];\n\nconst ALLOWED_ETIQUETAS = [\n 'ACTIVACION',\n 'ACTIVIDADES',\n 'BANDEJA',\n 'BTS',\n 'CORPORATIVO',\n 'DEGUSTACION',\n 'EXHIBICION',\n 'EXHIBIDOR',\n 'FUERZA DE VENTAS',\n 'JUEGOS',\n 'PREMIOS',\n 'PUNTO DE VENTA',\n 'REFERENCIAS',\n 'REUNIÓN',\n 'RULETA',\n 'SAMPLING',\n 'HALLOWEEN',\n 'LUCES NEON',\n 'INFORMATIVA',\n 'CARRITO DEGUSTACIÓN',\n 'RED SOCIAL/INFLUENCER',\n 'UNIFORMES',\n 'REGALIAS',\n 'STAND',\n 'CAPACITACIÓN',\n 'NAVIDAD',\n 'DÍA DE LAS MADRES',\n 'INDEPENDENCIA',\n 'LOGOTIPO',\n 'QUICK COUNTER',\n 'PPT',\n 'TEMPLATES',\n 'DISEÑO',\n 'PROMOCIÓN',\n 'MODERNO',\n 'MAYORISTA',\n 'PULPERÍAS',\n 'JUEGOS DIGITALES',\n 'WHATSAPP',\n 'CAMPAÑA',\n 'CONCURSO',\n 'REGALOS CORPORATIVOS',\n 'PENDIENTE',\n 'OTRO'\n];\n\nlet nombrePropuesta = clean(\n ai.nombre_propuesta ||\n original.NOMBRE ||\n original.nombre_limpio ||\n original.drive_name ||\n ''\n);\n\nif (!nombrePropuesta) {\n nombrePropuesta = 'PENDIENTE';\n}\n\nlet tipoAccion = normalizeMulti(\n ai.tipo_accion,\n ALLOWED_TIPO_ACCION,\n 'PENDIENTE',\n 'OTRO',\n normalizeTipoAccion\n);\n\nconst canal = normalizeOne(\n ai.canal,\n ALLOWED_CANAL,\n 'PENDIENTE',\n normalizeCanal\n);\n\nconst tacticaPromocional = normalizeMulti(\n ai.tactica_promocional,\n ALLOWED_TACTICA,\n 'PENDIENTE',\n 'OTRO',\n normalizeTactica\n);\n\nlet etiquetas = normalizeMulti(\n ai.tags,\n ALLOWED_ETIQUETAS,\n 'PENDIENTE',\n 'OTRO',\n normalizeEtiqueta\n);\n\nif (etiquetas.includes('OTRO') && etiquetas !== 'OTRO') {\n etiquetas = etiquetas\n .split(',')\n .map(v => v.trim())\n .filter(v => v !== 'OTRO')\n .join(', ');\n}\n\nconst ambienteCompra = 'PENDIENTE';\nconst aprobada = 'PENDIENTE DE APROBACION';\n\nlet descripcion = clean(ai.descripcion);\n\nif (!descripcion) {\n descripcion = clean(\n original.Descripcion ||\n original.NOMBRE ||\n original.drive_name ||\n ''\n );\n}\n\nlet requiereRevision = false;\nconst revisionReasons = [];\n\nif (tipoAccion.includes('OTRO') || tipoAccion === 'PENDIENTE') {\n requiereRevision = true;\n revisionReasons.push('tipo_accion_revisar');\n}\n\nif (canal === 'PENDIENTE') {\n requiereRevision = true;\n revisionReasons.push('canal_revisar');\n}\n\nif (tacticaPromocional.includes('OTRO') || tacticaPromocional === 'PENDIENTE') {\n requiereRevision = true;\n revisionReasons.push('tactica_revisar');\n}\n\nif (etiquetas.includes('OTRO') || etiquetas === 'PENDIENTE') {\n requiereRevision = true;\n revisionReasons.push('etiquetas_revisar');\n}\n\nreturn [\n {\n json: {\n NOMBRE: nombrePropuesta,\n 'TIPO DE ACCION': tipoAccion,\n CLIENTE: original.CLIENTE || '',\n MARCA: original.MARCA || '',\n PAIS: original.PAIS || '',\n CANAL: canal,\n 'AMBIENTE DE COMPRA (RE)': ambienteCompra,\n 'TÁCTICA PROMOCIONAL': tacticaPromocional,\n APROBADA: aprobada,\n ETIQUETAS: etiquetas,\n 'AÑO': original['AÑO'] || '',\n 'Enlace a la propuesta': original['Enlace a la propuesta'] || '',\n Descripcion: descripcion,\n\n file_id: original.file_id || original.file_id_refresco || original.drive_file_id || '',\n nombre_archivo: original.nombre_archivo || original.NOMBRE || original.drive_name || '',\n mime_type: original.mime_type || original.drive_mime_type || '',\n fuente_pais: original.fuente_pais || 'Tablero CDC',\n confianza_pais: original.confianza_pais || '',\n requiere_revision: requiereRevision,\n motivos_revision: revisionReasons.join(', '),\n procesado_ia: true,\n ultima_actualizacion: new Date().toISOString(),\n 'Enlaces a propuestas ejecutadas': original['Enlaces a propuestas ejecutadas'] || '',\n\n tablero_sync_key: original.tablero_sync_key || '',\n tablero_project_id: original.tablero_project_id || '',\n tablero_origen: original.tablero_origen || 'Tablero CDC',\n\n drive_modified_time: original.drive_modified_time_actual || original.drive_modified_time || '',\n ultimo_refresco_ia: new Date().toISOString(),\n refresh_status: 'OK',\n refresh_attempts: original.refresh_attempts || 1,\n },\n },\n];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 3840, -448 ], "id": "525e3816-a692-49e3-9885-20b8b4ddccbe", "name": "Code - Normalizar respuesta refresco" }, { "parameters": { "operation": "appendOrUpdate", "documentId": { "__rl": true, "value": "17WDzCrgHy67oIK7y0UUkxiMXzTgTvENPXcsfjK9lmio", "mode": "list", "cachedResultName": "TEST - BANCO DE PROPUESTAS CDC FULGENCIO REFRESCO", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/17WDzCrgHy67oIK7y0UUkxiMXzTgTvENPXcsfjK9lmio/edit?usp=drivesdk" }, "sheetName": { "__rl": true, "value": "gid=0", "mode": "list", "cachedResultName": "propuestas", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1iy3lC3DS3ZfShb7d26iQOrPjx9s_3B-PC07XfYew7ng/edit#gid=0" }, "columns": { "mappingMode": "defineBelow", "value": { "NOMBRE": "={{ $json[\"NOMBRE\"] }}", "TIPO DE ACCION": "={{ $json[\"TIPO DE ACCION\"] }}", "CLIENTE": "={{ $json[\"CLIENTE\"] }}", "MARCA": "={{ $json[\"MARCA\"] }}", "PAIS": "={{ $json[\"PAIS\"] }}", "CANAL": "={{ $json[\"CANAL\"] }}", "AMBIENTE DE COMPRA (RE)": "={{ $json[\"AMBIENTE DE COMPRA (RE)\"] }}", "TÁCTICA PROMOCIONAL": "={{ $json[\"TÁCTICA PROMOCIONAL\"] }}", "APROBADA": "={{ $json[\"APROBADA\"] }}", "ETIQUETAS": "={{ $json[\"ETIQUETAS\"] }}", "AÑO": "={{ $json[\"AÑO\"] }}", "Enlace a la propuesta": "={{ $json[\"Enlace a la propuesta\"] }}", "Descripcion": "={{ $json[\"Descripcion\"] }}", "file_id": "={{ $json[\"file_id\"] }}", "nombre_archivo": "={{ $json[\"nombre_archivo\"] }}", "mime_type": "={{ $json[\"mime_type\"] }}", "fuente_pais": "={{ $json[\"fuente_pais\"] }}", "confianza_pais": "={{ $json[\"confianza_pais\"] }}", "requiere_revision": "={{ $json[\"requiere_revision\"] }}", "procesado_ia": "={{ $json[\"procesado_ia\"] }}", "ultima_actualizacion": "={{ $json[\"ultima_actualizacion\"] }}", "motivos_revision": "={{ $json[\"motivos_revision\"] }}", "Enlaces a propuestas ejecutadas": "={{ $json[\"Enlaces a propuestas ejecutadas\"] }}", "tablero_project_id": "={{ $json[\"tablero_project_id\"] }}", "tablero_origen": "={{ $json[\"tablero_origen\"] }}", "tablero_sync_key": "={{ $json[\"tablero_sync_key\"] }}", "drive_modified_time": "={{ $json[\"drive_modified_time\"] }}", "ultimo_refresco_ia": "={{ $json[\"ultimo_refresco_ia\"] }}", "refresh_status": "={{ $json[\"refresh_status\"] }}", "refresh_attempts": "={{ $json[\"refresh_attempts\"] }}" }, "matchingColumns": [ "tablero_sync_key" ], "schema": [ { "id": "NOMBRE", "displayName": "NOMBRE", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "TIPO DE ACCION", "displayName": "TIPO DE ACCION", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "CLIENTE", "displayName": "CLIENTE", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "MARCA", "displayName": "MARCA", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "PAIS", "displayName": "PAIS", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "CANAL", "displayName": "CANAL", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "AMBIENTE DE COMPRA (RE)", "displayName": "AMBIENTE DE COMPRA (RE)", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "TÁCTICA PROMOCIONAL", "displayName": "TÁCTICA PROMOCIONAL", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "APROBADA", "displayName": "APROBADA", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "ETIQUETAS", "displayName": "ETIQUETAS", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "AÑO", "displayName": "AÑO", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "Enlace a la propuesta", "displayName": "Enlace a la propuesta", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "Descripcion", "displayName": "Descripcion", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "file_id", "displayName": "file_id", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "nombre_archivo", "displayName": "nombre_archivo", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "mime_type", "displayName": "mime_type", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "fuente_pais", "displayName": "fuente_pais", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "confianza_pais", "displayName": "confianza_pais", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "requiere_revision", "displayName": "requiere_revision", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "procesado_ia", "displayName": "procesado_ia", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "ultima_actualizacion", "displayName": "ultima_actualizacion", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "motivos_revision", "displayName": "motivos_revision", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "Enlaces a propuestas ejecutadas", "displayName": "Enlaces a propuestas ejecutadas", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "tablero_sync_key", "displayName": "tablero_sync_key", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false }, { "id": "tablero_project_id", "displayName": "tablero_project_id", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "tablero_origen", "displayName": "tablero_origen", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "drive_modified_time", "displayName": "drive_modified_time", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false }, { "id": "ultimo_refresco_ia", "displayName": "ultimo_refresco_ia", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false }, { "id": "refresh_status", "displayName": "refresh_status", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false }, { "id": "refresh_attempts", "displayName": "refresh_attempts", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false } ], "attemptToConvertTypes": false, "convertFieldsToString": false }, "options": {} }, "type": "n8n-nodes-base.googleSheets", "typeVersion": 4.7, "position": [ 4608, 400 ], "id": "f6487012-88de-4be3-b62e-fa9bdfdda270", "name": "Google Sheets - Upsert Banco Fulgencio", "credentials": { "googleSheetsOAuth2Api": { "id": "K0hDZh3a85MpOHCs", "name": "Google Sheets account 2" } } }, { "parameters": { "jsCode": "const original = $('Code - Preparar texto IA Refresco').item.json || {};\n\nreturn [\n {\n json: {\n ...original,\n drive_modified_time: original.drive_modified_time_actual || '',\n ultimo_refresco_ia: new Date().toISOString(),\n refresh_status: 'SIN_CONTENIDO',\n refresh_attempts: original.refresh_attempts || 1,\n procesado_ia: false,\n },\n },\n];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 3264, 48 ], "id": "42c459da-dd49-4ed8-aa1d-ff1f39688acf", "name": "Code - Marcar sin contenido" }, { "parameters": { "jsCode": "const original = $json || {};\n\nreturn [\n {\n json: {\n ...original,\n drive_modified_time: original.drive_modified_time || '',\n ultimo_refresco_ia: new Date().toISOString(),\n refresh_status: 'SIN_FILE_ID',\n refresh_attempts: Number(original.refresh_attempts_actual || original.refresh_attempts || 0) + 1,\n procesado_ia: false,\n },\n },\n];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 1984, 176 ], "id": "6287af34-de8e-49aa-b432-778c016c9f8d", "name": "Code - Marcar sin file_id" }, { "parameters": { "jsCode": "const original = $('IF - Tiene file_id?').item.json || {};\nconst errorData = $json || {};\n\nreturn [\n {\n json: {\n ...original,\n drive_modified_time: original.drive_modified_time || '',\n ultimo_refresco_ia: new Date().toISOString(),\n refresh_status: 'ERROR_METADATA_DRIVE',\n refresh_attempts: Number(original.refresh_attempts_actual || original.refresh_attempts || 0) + 1,\n procesado_ia: false,\n motivos_revision: `error_metadata_drive: ${String(errorData.message || errorData.error || '').slice(0, 200)}`,\n },\n },\n];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 1936, -32 ], "id": "389332ff-4d6b-4a5d-824d-28a1098030ef", "name": "Code - Marcar error metadata Drive" }, { "parameters": { "jsCode": "const original = $('Code - Evaluar refresco').item.json || {};\nconst errorData = $json || {};\n\nreturn [\n {\n json: {\n ...original,\n drive_modified_time: original.drive_modified_time_actual || original.drive_modified_time || '',\n ultimo_refresco_ia: new Date().toISOString(),\n refresh_status: 'ERROR_EXPORT_SLIDES',\n refresh_attempts: Number(original.refresh_attempts_actual || original.refresh_attempts || 0) + 1,\n procesado_ia: false,\n motivos_revision: `error_export_slides: ${String(errorData.message || errorData.error || '').slice(0, 200)}`,\n },\n },\n];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 2608, -192 ], "id": "251b1833-27c9-4a63-9a97-6ad600ea5283", "name": "Code - Marcar error export Slides" } ], "connections": { "Schedule Trigger": { "main": [ [ { "node": "Sheets - Leer Banco Fulgencio", "type": "main", "index": 0 } ] ] }, "Sheets - Leer Banco Fulgencio": { "main": [ [ { "node": "Code - Filtrar filas Tablero CDC", "type": "main", "index": 0 } ] ] }, "Code - Filtrar filas Tablero CDC": { "main": [ [ { "node": "Loop - Filas Banco Fulgencio", "type": "main", "index": 0 } ] ] }, "Loop - Filas Banco Fulgencio": { "main": [ [], [ { "node": "IF - Tiene file_id?", "type": "main", "index": 0 } ] ] }, "IF - Tiene file_id?": { "main": [ [ { "node": "HTTP - Obtener metadata Drive", "type": "main", "index": 0 } ], [ { "node": "Code - Marcar sin file_id", "type": "main", "index": 0 } ] ] }, "HTTP - Obtener metadata Drive": { "main": [ [ { "node": "Code - Evaluar refresco", "type": "main", "index": 0 } ], [ { "node": "Code - Marcar error metadata Drive", "type": "main", "index": 0 } ] ] }, "Code - Evaluar refresco": { "main": [ [ { "node": "IF - Debe refrescar?", "type": "main", "index": 0 } ] ] }, "IF - Debe refrescar?": { "main": [ [ { "node": "HTTP - Exportar Slides TXT", "type": "main", "index": 0 } ], [ { "node": "Loop - Filas Banco Fulgencio", "type": "main", "index": 0 } ] ] }, "HTTP - Exportar Slides TXT": { "main": [ [ { "node": "Code - Preparar texto IA Refresco", "type": "main", "index": 0 } ], [ { "node": "Code - Marcar error export Slides", "type": "main", "index": 0 } ] ] }, "Code - Preparar texto IA Refresco": { "main": [ [ { "node": "IF - Tiene contenido?", "type": "main", "index": 0 } ] ] }, "IF - Tiene contenido?": { "main": [ [ { "node": "Gemini - Reanalizar contenido Slides", "type": "main", "index": 0 } ], [ { "node": "Code - Marcar sin contenido", "type": "main", "index": 0 } ] ] }, "Google Gemini Chat Model": { "ai_languageModel": [ [ { "node": "Gemini - Reanalizar contenido Slides", "type": "ai_languageModel", "index": 0 } ] ] }, "Gemini - Reanalizar contenido Slides": { "main": [ [ { "node": "Code - Normalizar respuesta refresco", "type": "main", "index": 0 } ] ] }, "Code - Normalizar respuesta refresco": { "main": [ [ { "node": "Google Sheets - Upsert Banco Fulgencio", "type": "main", "index": 0 } ] ] }, "Code - Marcar sin contenido": { "main": [ [ { "node": "Google Sheets - Upsert Banco Fulgencio", "type": "main", "index": 0 } ] ] }, "Google Sheets - Upsert Banco Fulgencio": { "main": [ [ { "node": "Loop - Filas Banco Fulgencio", "type": "main", "index": 0 } ] ] }, "Code - Marcar sin file_id": { "main": [ [ { "node": "Google Sheets - Upsert Banco Fulgencio", "type": "main", "index": 0 } ] ] }, "Code - Marcar error metadata Drive": { "main": [ [ { "node": "Google Sheets - Upsert Banco Fulgencio", "type": "main", "index": 0 } ] ] }, "Code - Marcar error export Slides": { "main": [ [ { "node": "Google Sheets - Upsert Banco Fulgencio", "type": "main", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1", "binaryMode": "separate" }, "staticData": { "node:Schedule Trigger": { "recurrenceRules": [] } }, "meta": { "templateCredsSetupCompleted": true }, "versionId": "fd39df42-6d7e-4305-973d-cf2c6ba679fc", "activeVersionId": "fd39df42-6d7e-4305-973d-cf2c6ba679fc", "versionCounter": 146, "triggerCount": 1, "shared": [ { "updatedAt": "2026-06-16T17:22:11.399Z", "createdAt": "2026-06-16T17:22:11.399Z", "role": "workflow:owner", "workflowId": "g2JtKXNz5GDbkmQH", "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-06-16T20:43:40.000Z", "createdAt": "2026-06-16T20:43:37.594Z", "versionId": "fd39df42-6d7e-4305-973d-cf2c6ba679fc", "workflowId": "g2JtKXNz5GDbkmQH", "nodes": [ { "parameters": { "rule": { "interval": [ { "triggerAtHour": 23 } ] } }, "type": "n8n-nodes-base.scheduleTrigger", "typeVersion": 1.3, "position": [ 0, 0 ], "id": "37cc170e-2f53-4e2e-915a-f6020e701c2e", "name": "Schedule Trigger" }, { "parameters": { "documentId": { "__rl": true, "value": "17WDzCrgHy67oIK7y0UUkxiMXzTgTvENPXcsfjK9lmio", "mode": "list", "cachedResultName": "TEST - BANCO DE PROPUESTAS CDC FULGENCIO REFRESCO", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/17WDzCrgHy67oIK7y0UUkxiMXzTgTvENPXcsfjK9lmio/edit?usp=drivesdk" }, "sheetName": { "__rl": true, "value": "gid=0", "mode": "list", "cachedResultName": "propuestas", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/17WDzCrgHy67oIK7y0UUkxiMXzTgTvENPXcsfjK9lmio/edit#gid=0" }, "options": {} }, "type": "n8n-nodes-base.googleSheets", "typeVersion": 4.7, "position": [ 208, 0 ], "id": "da0ce8a1-0efe-4f5b-909d-7f64b67e8f3b", "name": "Sheets - Leer Banco Fulgencio", "credentials": { "googleSheetsOAuth2Api": { "id": "K0hDZh3a85MpOHCs", "name": "Google Sheets account 2" } } }, { "parameters": { "jsCode": "function clean(value) {\n return String(value ?? '').trim();\n}\n\nfunction extractGoogleFileId(url) {\n const text = clean(url);\n\n if (!text) return '';\n\n const patterns = [\n /\\/d\\/([a-zA-Z0-9_-]+)/,\n /id=([a-zA-Z0-9_-]+)/,\n /\\/file\\/d\\/([a-zA-Z0-9_-]+)/,\n /\\/presentation\\/d\\/([a-zA-Z0-9_-]+)/,\n ];\n\n for (const pattern of patterns) {\n const match = text.match(pattern);\n if (match && match[1]) return match[1];\n }\n\n return '';\n}\n\nconst rows = $input.all();\n\nconst result = [];\n\nfor (const item of rows) {\n const row = item.json || {};\n\n const origen = clean(row.tablero_origen);\n const syncKey = clean(row.tablero_sync_key);\n const projectId = clean(row.tablero_project_id);\n const proposalUrl = clean(row['Enlace a la propuesta']);\n const existingFileId = clean(row.file_id);\n const fileId = existingFileId || extractGoogleFileId(proposalUrl);\n\n if (origen !== 'Tablero CDC') continue;\n if (!syncKey) continue;\n if (!projectId) continue;\n if (!proposalUrl) continue;\n\n result.push({\n json: {\n ...row,\n file_id_refresco: fileId,\n proposal_url_refresco: proposalUrl,\n refresh_attempts_actual: Number(row.refresh_attempts || 0),\n },\n });\n}\n\nreturn result.slice(0, 1);" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 416, 0 ], "id": "1422a9de-12a8-4b2d-bda9-9dc7193a5d67", "name": "Code - Filtrar filas Tablero CDC" }, { "parameters": { "options": {} }, "type": "n8n-nodes-base.splitInBatches", "typeVersion": 3, "position": [ 640, 0 ], "id": "3fb77467-0f3c-419e-8a6e-ab44d118ceef", "name": "Loop - Filas Banco Fulgencio" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 }, "conditions": [ { "id": "8c79f0ce-b901-43c8-b863-ad490d267c37", "leftValue": "={{ $json.file_id_refresco }}", "rightValue": "", "operator": { "type": "string", "operation": "notEmpty", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ 800, -144 ], "id": "6896c55a-b17b-41bf-8f99-3fa949c29d67", "name": "IF - Tiene file_id?" }, { "parameters": { "url": "=https://www.googleapis.com/drive/v3/files/{{$json.file_id_refresco}}?fields=id,name,mimeType,modifiedTime,webViewLink&supportsAllDrives=true", "authentication": "predefinedCredentialType", "nodeCredentialType": "googleDriveOAuth2Api", "options": {} }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 992, -368 ], "id": "40ccb6f9-4e2d-4b21-ad1c-583151c84641", "name": "HTTP - Obtener metadata Drive", "retryOnFail": true, "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } }, "onError": "continueErrorOutput" }, { "parameters": { "jsCode": "const original = $('IF - Tiene file_id?').item.json || {};\nconst metadata = $json || {};\n\nfunction clean(value) {\n return String(value ?? '').trim();\n}\n\nfunction toDate(value) {\n const date = value ? new Date(value) : null;\n if (!date || Number.isNaN(date.getTime())) return null;\n return date;\n}\n\nconst driveModifiedTime = clean(metadata.modifiedTime || metadata.modified_time);\nconst lastRefresh = clean(original.ultimo_refresco_ia);\nconst existingDriveModified = clean(original.drive_modified_time);\n\nconst driveDate = toDate(driveModifiedTime);\nconst lastRefreshDate = toDate(lastRefresh);\nconst existingDriveDate = toDate(existingDriveModified);\n\nlet shouldRefresh = false;\nlet reason = '';\n\nif (!driveDate) {\n shouldRefresh = false;\n reason = 'sin_modified_time';\n} else if (!lastRefreshDate) {\n shouldRefresh = true;\n reason = 'nunca_refrescado';\n} else if (driveDate > lastRefreshDate) {\n shouldRefresh = true;\n reason = 'archivo_modificado_desde_ultimo_refresco';\n} else if (existingDriveDate && driveDate > existingDriveDate) {\n shouldRefresh = true;\n reason = 'drive_modified_time_cambio';\n} else {\n shouldRefresh = false;\n reason = 'sin_cambios';\n}\n\nreturn [\n {\n json: {\n ...original,\n drive_file_id: metadata.id || original.file_id_refresco,\n drive_name: metadata.name || '',\n drive_mime_type: metadata.mimeType || '',\n drive_modified_time_actual: driveModifiedTime,\n should_refresh: shouldRefresh,\n refresh_reason: reason,\n },\n },\n];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 1936, -224 ], "id": "ebeb387e-0038-4166-b3a9-bdfdd863550a", "name": "Code - Evaluar refresco" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 }, "conditions": [ { "id": "a6356649-3547-40be-bdc6-55730f280fa9", "leftValue": "={{ $json.should_refresh }}", "rightValue": "", "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ 2112, -224 ], "id": "a0ac9c90-9029-41de-9338-1d076f045947", "name": "IF - Debe refrescar?" }, { "parameters": { "url": "=https://www.googleapis.com/drive/v3/files/{{ $json.drive_file_id }}/export?mimeType=text/plain", "authentication": "predefinedCredentialType", "nodeCredentialType": "googleDriveOAuth2Api", "options": { "response": { "response": { "responseFormat": "text" } } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 2400, -288 ], "id": "2eabdc4e-1bb5-4f8a-bacb-844e87d379c0", "name": "HTTP - Exportar Slides TXT", "retryOnFail": true, "credentials": { "googleDriveOAuth2Api": { "id": "g23xdGLZRzBGqKgH", "name": "Isaac - Google Drive" } }, "onError": "continueErrorOutput" }, { "parameters": { "jsCode": "const original = $('Code - Evaluar refresco').item.json || {};\nconst incoming = $json || {};\n\nfunction clean(value) {\n return String(value ?? '').trim().replace(/\\s+/g, ' ');\n}\n\nlet exportedText = '';\n\nif (typeof incoming === 'string') {\n exportedText = incoming;\n} else {\n exportedText =\n incoming.body ||\n incoming.data ||\n incoming.text ||\n incoming.content ||\n incoming.response ||\n '';\n}\n\nexportedText = clean(exportedText);\n\nconst hasContent = exportedText.length >= 80;\n\nreturn [\n {\n json: {\n ...original,\n contenido_presentacion: exportedText.slice(0, 18000),\n contenido_chars: exportedText.length,\n contenido_valido: hasContent,\n refresh_attempts: Number(original.refresh_attempts_actual || 0) + 1,\n },\n },\n];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 2672, -384 ], "id": "fadb71e0-541f-4cc0-8e03-be43fb3fd841", "name": "Code - Preparar texto IA Refresco" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 }, "conditions": [ { "id": "c0faa484-9c5d-4af3-b725-bfbc67f7f89d", "leftValue": "={{ $json.contenido_valido }}", "rightValue": "", "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ 2880, -384 ], "id": "cade8a8b-995a-4951-9b76-7f695a10fe7d", "name": "IF - Tiene contenido?" }, { "parameters": { "text": "=Nombre de la propuesta: {{$json.NOMBRE}}\nCliente: {{$json.CLIENTE}}\nMarca: {{$json.MARCA}}\nPaís: {{$json.PAIS}}\nLink: {{$json[\"Enlace a la propuesta\"]}}\n\nContenido exportado de la presentación:\n{{$json.contenido_presentacion}}", "attributes": { "attributes": [ { "name": "nombre_propuesta", "description": "Nombre limpio o comercial de la propuesta." }, { "name": "tipo_accion", "description": "Tipo de acción o formato de propuesta. Ejemplos: campaña, evento, mueble, exhibidor, diseño gráfico, activación PDV, material POP, uniforme, promoción, stand. Si no se puede determinar, usar PENDIENTE." }, { "name": "canal", "description": "Canal o lugar donde aplica la propuesta. Ejemplos: moderno, tradicional, online, PDV, no aplica. Si no se puede determinar, usar PENDIENTE." }, { "name": "tags", "description": "Palabras clave separadas por comas para facilitar búsqueda. Ejemplos: campaña, corporativo, exhibidor, punto de venta, juegos, uniforme, material POP." }, { "name": "descripcion", "description": "Párrafo profesional de 35 a 70 palabras. Debe iniciar preferiblemente con “La presentación muestra...”, “La pieza muestra...” o “La propuesta corresponde a...”. Debe mencionar cliente/marca, tipo de acción, concepto o tema principal y objetivo. No inventar detalles." }, { "name": "tactica_promocional", "description": "Táctica promocional principal. Ejemplos: DEGUSTACIÓN, RULETA, SAMPLING - MUESTREO, PLINKO, WHATSAPP, LANDING PAGE, POP, PHOTOBOOTH, CANJE, SORTEO, PREMIOS INSTANTÁNEOS, JUEGO DIGITAL, TRIVIA, EXHIBICIÓN, IMPULSO o PENDIENTE." } ] }, "options": { "systemPromptTemplate": "Analiza el contenido real exportado de una presentación de Google Slides para actualizar el banco de propuestas de Fulgencio Fumado.\n\nIMPORTANTE:\n- Usa el contenido de la presentación como fuente principal.\n- No cambies el país, cliente ni marca recibidos desde Tablero CDC.\n- No determines APROBADA. Ese campo debe quedar como PENDIENTE DE APROBACION.\n- No determines AMBIENTE DE COMPRA (RE). Ese campo debe quedar como PENDIENTE.\n- Si el contenido es insuficiente, usa PENDIENTE.\n- No inventes detalles.\n- Devuelve:\n nombre_propuesta\n tipo_accion\n canal\n tags\n descripcion\n tactica_promocional" } }, "type": "@n8n/n8n-nodes-langchain.informationExtractor", "typeVersion": 1.2, "position": [ 3488, -448 ], "id": "08c0d48c-400f-454a-832d-9e08d4724fbd", "name": "Gemini - Reanalizar contenido Slides" }, { "parameters": { "modelName": "models/gemini-3.1-pro-preview", "options": {} }, "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini", "typeVersion": 1.1, "position": [ 3488, -240 ], "id": "5875c1c9-5aa3-4f60-a3ee-f94e0293ec04", "name": "Google Gemini Chat Model", "credentials": { "googlePalmApi": { "id": "jvsXYwL6IOoY2DBU", "name": "Isaac - Gemini Api Pago" } } }, { "parameters": { "jsCode": "const original = $('Code - Preparar texto IA Refresco').item.json || {};\nconst incoming = $input.first().json || {};\nconst ai = incoming.output || incoming;\n\nfunction clean(value) {\n if (Array.isArray(value)) return value.map(clean).filter(Boolean).join(', ');\n return String(value ?? '').trim().replace(/\\s+/g, ' ');\n}\n\nfunction removeAccents(value) {\n return clean(value)\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '');\n}\n\nfunction upper(value) {\n return removeAccents(value).toUpperCase();\n}\n\nfunction splitMulti(value) {\n return clean(value)\n .split(',')\n .map(v => upper(v))\n .map(v => v.trim())\n .filter(Boolean);\n}\n\nfunction unique(values) {\n return [...new Set(values.filter(Boolean))];\n}\n\nfunction joinMulti(values) {\n return unique(values).join(', ');\n}\n\nfunction normalizeTipoAccion(value) {\n const v = upper(value);\n\n const synonyms = {\n 'ACTIVACION PDV': 'ACTIVACION EN PDV',\n 'ACTIVACION EN PUNTO DE VENTA': 'ACTIVACION EN PDV',\n 'ACTIVACION PUNTO DE VENTA': 'ACTIVACION EN PDV',\n 'PUNTO DE VENTA': 'ACTIVACION EN PDV',\n 'PDV': 'ACTIVACION EN PDV',\n 'DISEÑO GRAFICO': 'DISENO GRAFICO',\n 'DISEÑO GRÁFICO': 'DISENO GRAFICO',\n 'DISENO GRAFICO': 'DISENO GRAFICO',\n 'CAMPAÑA': 'CAMPAÑA',\n 'CAMPANA': 'CAMPAÑA',\n 'PROMOCION': 'PROMOCION',\n 'PROMOCIÓN': 'PROMOCION',\n 'MUEBLE': 'MUEBLE',\n 'EXHIBIDOR': 'MUEBLE',\n 'STAND': 'STAND',\n 'EVENTO': 'EVENTO',\n 'UNIFORME': 'UNIFORME',\n 'MATERIAL POP': 'DISENO GRAFICO',\n 'POP': 'DISENO GRAFICO'\n };\n\n return synonyms[v] || v;\n}\n\nfunction normalizeCanal(value) {\n const v = upper(value);\n\n const synonyms = {\n 'PUNTO DE VENTA': 'PDV',\n 'PDV': 'PDV',\n 'CANAL MODERNO': 'MODERNO',\n 'MODERNO': 'MODERNO',\n 'CANAL TRADICIONAL': 'TRADICIONAL',\n 'TRADICIONAL': 'TRADICIONAL',\n 'DIGITAL': 'ONLINE',\n 'ONLINE': 'ONLINE',\n 'NO APLICA': 'NO APLICA',\n 'N/A': 'NO APLICA'\n };\n\n return synonyms[v] || v;\n}\n\nfunction normalizeTactica(value) {\n const v = upper(value);\n\n const synonyms = {\n 'SAMPLING': 'SAMPLING - MUESTREO',\n 'MUESTREO': 'SAMPLING - MUESTREO',\n 'DEGUSTACION': 'DEGUSTACIÓN',\n 'DEGUSTACIÓN': 'DEGUSTACIÓN',\n 'RULETA DIGITAL': 'RULETA',\n 'RULETA': 'RULETA',\n 'PLINKO': 'PLINKO',\n 'WHATSAPP': 'WHATSAPP',\n 'LANDING': 'LANDING PAGE',\n 'LANDING PAGE': 'LANDING PAGE',\n 'MATERIAL POP': 'POP',\n 'POP': 'POP',\n 'JUEGO DIGITAL': 'JUEGO DIGITAL',\n 'JUEGOS DIGITALES': 'JUEGO DIGITAL',\n 'EXHIBICION': 'EXHIBICIÓN',\n 'EXHIBICIÓN': 'EXHIBICIÓN',\n 'IMPULSO': 'IMPULSO'\n };\n\n return synonyms[v] || v;\n}\n\nfunction normalizeEtiqueta(value) {\n const v = upper(value);\n\n const synonyms = {\n 'ACTIVACION': 'ACTIVACION',\n 'ACTIVACIÓN': 'ACTIVACION',\n 'EXHIBICION': 'EXHIBICION',\n 'EXHIBICIÓN': 'EXHIBICION',\n 'EXHIBIDOR': 'EXHIBIDOR',\n 'DEGUSTACION': 'DEGUSTACION',\n 'DEGUSTACIÓN': 'DEGUSTACION',\n 'PROMOCION': 'PROMOCIÓN',\n 'PROMOCIÓN': 'PROMOCIÓN',\n 'DISENO': 'DISEÑO',\n 'DISEÑO': 'DISEÑO',\n 'CAMPANA': 'CAMPAÑA',\n 'CAMPAÑA': 'CAMPAÑA',\n 'JUEGO DIGITAL': 'JUEGOS DIGITALES',\n 'JUEGOS DIGITALES': 'JUEGOS DIGITALES',\n 'PUNTO DE VENTA': 'PUNTO DE VENTA',\n 'PDV': 'PUNTO DE VENTA',\n 'F1': 'JUEGOS',\n 'SIMULADOR': 'JUEGOS DIGITALES',\n 'EXPERIENCIA': 'ACTIVIDADES',\n 'CORPORATIVO': 'CORPORATIVO',\n 'UNIFORME': 'UNIFORMES',\n 'UNIFORMES': 'UNIFORMES',\n 'POP': 'PUNTO DE VENTA',\n 'MATERIAL POP': 'PUNTO DE VENTA'\n };\n\n return synonyms[v] || v;\n}\n\nfunction normalizeOne(value, allowedList, fallback = 'PENDIENTE', normalizer = upper) {\n const raw = clean(value);\n if (!raw) return fallback;\n\n const mapped = normalizer(raw);\n return allowedList.includes(mapped) ? mapped : fallback;\n}\n\nfunction normalizeMulti(value, allowedList, fallback = 'PENDIENTE', unknownValue = 'OTRO', normalizer = upper) {\n const parts = splitMulti(value);\n if (!parts.length) return fallback;\n\n const result = [];\n\n for (const part of parts) {\n const mapped = normalizer(part);\n const expanded = String(mapped)\n .split(',')\n .map(v => v.trim())\n .filter(Boolean);\n\n for (const val of expanded) {\n if (allowedList.includes(val)) {\n result.push(val);\n } else {\n result.push(unknownValue);\n }\n }\n }\n\n const finalValues = unique(result);\n if (!finalValues.length) return fallback;\n\n return joinMulti(finalValues);\n}\n\nconst ALLOWED_TIPO_ACCION = [\n 'ACTIVACION EN PDV',\n 'IMPULSO DE VENTA',\n 'ACTIVACION FUERA DE PDV',\n 'EVENTO',\n 'KICK OFF',\n 'FERIA',\n 'STAND',\n 'MUEBLE',\n 'DISENO GRAFICO',\n 'DIGITAL',\n 'PUBLICIDAD',\n 'TUTORIAL',\n 'INFORMATIVA',\n 'LOGOTIPO',\n 'PROMOCION',\n 'UNIFORME',\n 'ACTIVACIÓN',\n 'INAUGURACIÓN',\n 'PARQUE',\n 'TROFEO',\n 'ANAQUEL',\n 'FOOD TRUCK',\n 'EMPAQUES',\n 'CAMPAÑA',\n 'QUICK COUNTER',\n 'DISEÑO',\n 'PPT',\n 'PENDIENTE',\n 'OTRO'\n];\n\nconst ALLOWED_CANAL = [\n 'MODERNO',\n 'TRADICIONAL',\n 'ONLINE',\n 'NO APLICA',\n 'PDV',\n 'PENDIENTE'\n];\n\nconst ALLOWED_TACTICA = [\n 'DEGUSTACIÓN',\n 'RULETA',\n 'SAMPLING - MUESTREO',\n 'PLINKO',\n 'WHATSAPP',\n 'LANDING PAGE',\n 'POP',\n 'PHOTOBOOTH',\n 'CANJE',\n 'SORTEO',\n 'PREMIOS INSTANTÁNEOS',\n 'JUEGO DIGITAL',\n 'TRIVIA',\n 'EXHIBICIÓN',\n 'IMPULSO',\n 'PENDIENTE',\n 'OTRO'\n];\n\nconst ALLOWED_ETIQUETAS = [\n 'ACTIVACION',\n 'ACTIVIDADES',\n 'BANDEJA',\n 'BTS',\n 'CORPORATIVO',\n 'DEGUSTACION',\n 'EXHIBICION',\n 'EXHIBIDOR',\n 'FUERZA DE VENTAS',\n 'JUEGOS',\n 'PREMIOS',\n 'PUNTO DE VENTA',\n 'REFERENCIAS',\n 'REUNIÓN',\n 'RULETA',\n 'SAMPLING',\n 'HALLOWEEN',\n 'LUCES NEON',\n 'INFORMATIVA',\n 'CARRITO DEGUSTACIÓN',\n 'RED SOCIAL/INFLUENCER',\n 'UNIFORMES',\n 'REGALIAS',\n 'STAND',\n 'CAPACITACIÓN',\n 'NAVIDAD',\n 'DÍA DE LAS MADRES',\n 'INDEPENDENCIA',\n 'LOGOTIPO',\n 'QUICK COUNTER',\n 'PPT',\n 'TEMPLATES',\n 'DISEÑO',\n 'PROMOCIÓN',\n 'MODERNO',\n 'MAYORISTA',\n 'PULPERÍAS',\n 'JUEGOS DIGITALES',\n 'WHATSAPP',\n 'CAMPAÑA',\n 'CONCURSO',\n 'REGALOS CORPORATIVOS',\n 'PENDIENTE',\n 'OTRO'\n];\n\nlet nombrePropuesta = clean(\n ai.nombre_propuesta ||\n original.NOMBRE ||\n original.nombre_limpio ||\n original.drive_name ||\n ''\n);\n\nif (!nombrePropuesta) {\n nombrePropuesta = 'PENDIENTE';\n}\n\nlet tipoAccion = normalizeMulti(\n ai.tipo_accion,\n ALLOWED_TIPO_ACCION,\n 'PENDIENTE',\n 'OTRO',\n normalizeTipoAccion\n);\n\nconst canal = normalizeOne(\n ai.canal,\n ALLOWED_CANAL,\n 'PENDIENTE',\n normalizeCanal\n);\n\nconst tacticaPromocional = normalizeMulti(\n ai.tactica_promocional,\n ALLOWED_TACTICA,\n 'PENDIENTE',\n 'OTRO',\n normalizeTactica\n);\n\nlet etiquetas = normalizeMulti(\n ai.tags,\n ALLOWED_ETIQUETAS,\n 'PENDIENTE',\n 'OTRO',\n normalizeEtiqueta\n);\n\nif (etiquetas.includes('OTRO') && etiquetas !== 'OTRO') {\n etiquetas = etiquetas\n .split(',')\n .map(v => v.trim())\n .filter(v => v !== 'OTRO')\n .join(', ');\n}\n\nconst ambienteCompra = 'PENDIENTE';\nconst aprobada = 'PENDIENTE DE APROBACION';\n\nlet descripcion = clean(ai.descripcion);\n\nif (!descripcion) {\n descripcion = clean(\n original.Descripcion ||\n original.NOMBRE ||\n original.drive_name ||\n ''\n );\n}\n\nlet requiereRevision = false;\nconst revisionReasons = [];\n\nif (tipoAccion.includes('OTRO') || tipoAccion === 'PENDIENTE') {\n requiereRevision = true;\n revisionReasons.push('tipo_accion_revisar');\n}\n\nif (canal === 'PENDIENTE') {\n requiereRevision = true;\n revisionReasons.push('canal_revisar');\n}\n\nif (tacticaPromocional.includes('OTRO') || tacticaPromocional === 'PENDIENTE') {\n requiereRevision = true;\n revisionReasons.push('tactica_revisar');\n}\n\nif (etiquetas.includes('OTRO') || etiquetas === 'PENDIENTE') {\n requiereRevision = true;\n revisionReasons.push('etiquetas_revisar');\n}\n\nreturn [\n {\n json: {\n NOMBRE: nombrePropuesta,\n 'TIPO DE ACCION': tipoAccion,\n CLIENTE: original.CLIENTE || '',\n MARCA: original.MARCA || '',\n PAIS: original.PAIS || '',\n CANAL: canal,\n 'AMBIENTE DE COMPRA (RE)': ambienteCompra,\n 'TÁCTICA PROMOCIONAL': tacticaPromocional,\n APROBADA: aprobada,\n ETIQUETAS: etiquetas,\n 'AÑO': original['AÑO'] || '',\n 'Enlace a la propuesta': original['Enlace a la propuesta'] || '',\n Descripcion: descripcion,\n\n file_id: original.file_id || original.file_id_refresco || original.drive_file_id || '',\n nombre_archivo: original.nombre_archivo || original.NOMBRE || original.drive_name || '',\n mime_type: original.mime_type || original.drive_mime_type || '',\n fuente_pais: original.fuente_pais || 'Tablero CDC',\n confianza_pais: original.confianza_pais || '',\n requiere_revision: requiereRevision,\n motivos_revision: revisionReasons.join(', '),\n procesado_ia: true,\n ultima_actualizacion: new Date().toISOString(),\n 'Enlaces a propuestas ejecutadas': original['Enlaces a propuestas ejecutadas'] || '',\n\n tablero_sync_key: original.tablero_sync_key || '',\n tablero_project_id: original.tablero_project_id || '',\n tablero_origen: original.tablero_origen || 'Tablero CDC',\n\n drive_modified_time: original.drive_modified_time_actual || original.drive_modified_time || '',\n ultimo_refresco_ia: new Date().toISOString(),\n refresh_status: 'OK',\n refresh_attempts: original.refresh_attempts || 1,\n },\n },\n];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 3840, -448 ], "id": "525e3816-a692-49e3-9885-20b8b4ddccbe", "name": "Code - Normalizar respuesta refresco" }, { "parameters": { "operation": "appendOrUpdate", "documentId": { "__rl": true, "value": "17WDzCrgHy67oIK7y0UUkxiMXzTgTvENPXcsfjK9lmio", "mode": "list", "cachedResultName": "TEST - BANCO DE PROPUESTAS CDC FULGENCIO REFRESCO", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/17WDzCrgHy67oIK7y0UUkxiMXzTgTvENPXcsfjK9lmio/edit?usp=drivesdk" }, "sheetName": { "__rl": true, "value": "gid=0", "mode": "list", "cachedResultName": "propuestas", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1iy3lC3DS3ZfShb7d26iQOrPjx9s_3B-PC07XfYew7ng/edit#gid=0" }, "columns": { "mappingMode": "defineBelow", "value": { "NOMBRE": "={{ $json[\"NOMBRE\"] }}", "TIPO DE ACCION": "={{ $json[\"TIPO DE ACCION\"] }}", "CLIENTE": "={{ $json[\"CLIENTE\"] }}", "MARCA": "={{ $json[\"MARCA\"] }}", "PAIS": "={{ $json[\"PAIS\"] }}", "CANAL": "={{ $json[\"CANAL\"] }}", "AMBIENTE DE COMPRA (RE)": "={{ $json[\"AMBIENTE DE COMPRA (RE)\"] }}", "TÁCTICA PROMOCIONAL": "={{ $json[\"TÁCTICA PROMOCIONAL\"] }}", "APROBADA": "={{ $json[\"APROBADA\"] }}", "ETIQUETAS": "={{ $json[\"ETIQUETAS\"] }}", "AÑO": "={{ $json[\"AÑO\"] }}", "Enlace a la propuesta": "={{ $json[\"Enlace a la propuesta\"] }}", "Descripcion": "={{ $json[\"Descripcion\"] }}", "file_id": "={{ $json[\"file_id\"] }}", "nombre_archivo": "={{ $json[\"nombre_archivo\"] }}", "mime_type": "={{ $json[\"mime_type\"] }}", "fuente_pais": "={{ $json[\"fuente_pais\"] }}", "confianza_pais": "={{ $json[\"confianza_pais\"] }}", "requiere_revision": "={{ $json[\"requiere_revision\"] }}", "procesado_ia": "={{ $json[\"procesado_ia\"] }}", "ultima_actualizacion": "={{ $json[\"ultima_actualizacion\"] }}", "motivos_revision": "={{ $json[\"motivos_revision\"] }}", "Enlaces a propuestas ejecutadas": "={{ $json[\"Enlaces a propuestas ejecutadas\"] }}", "tablero_project_id": "={{ $json[\"tablero_project_id\"] }}", "tablero_origen": "={{ $json[\"tablero_origen\"] }}", "tablero_sync_key": "={{ $json[\"tablero_sync_key\"] }}", "drive_modified_time": "={{ $json[\"drive_modified_time\"] }}", "ultimo_refresco_ia": "={{ $json[\"ultimo_refresco_ia\"] }}", "refresh_status": "={{ $json[\"refresh_status\"] }}", "refresh_attempts": "={{ $json[\"refresh_attempts\"] }}" }, "matchingColumns": [ "tablero_sync_key" ], "schema": [ { "id": "NOMBRE", "displayName": "NOMBRE", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "TIPO DE ACCION", "displayName": "TIPO DE ACCION", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "CLIENTE", "displayName": "CLIENTE", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "MARCA", "displayName": "MARCA", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "PAIS", "displayName": "PAIS", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "CANAL", "displayName": "CANAL", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "AMBIENTE DE COMPRA (RE)", "displayName": "AMBIENTE DE COMPRA (RE)", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "TÁCTICA PROMOCIONAL", "displayName": "TÁCTICA PROMOCIONAL", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "APROBADA", "displayName": "APROBADA", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "ETIQUETAS", "displayName": "ETIQUETAS", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "AÑO", "displayName": "AÑO", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "Enlace a la propuesta", "displayName": "Enlace a la propuesta", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "Descripcion", "displayName": "Descripcion", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "file_id", "displayName": "file_id", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "nombre_archivo", "displayName": "nombre_archivo", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "mime_type", "displayName": "mime_type", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "fuente_pais", "displayName": "fuente_pais", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "confianza_pais", "displayName": "confianza_pais", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "requiere_revision", "displayName": "requiere_revision", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "procesado_ia", "displayName": "procesado_ia", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "ultima_actualizacion", "displayName": "ultima_actualizacion", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "motivos_revision", "displayName": "motivos_revision", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "Enlaces a propuestas ejecutadas", "displayName": "Enlaces a propuestas ejecutadas", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "tablero_sync_key", "displayName": "tablero_sync_key", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false }, { "id": "tablero_project_id", "displayName": "tablero_project_id", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "tablero_origen", "displayName": "tablero_origen", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "drive_modified_time", "displayName": "drive_modified_time", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false }, { "id": "ultimo_refresco_ia", "displayName": "ultimo_refresco_ia", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false }, { "id": "refresh_status", "displayName": "refresh_status", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false }, { "id": "refresh_attempts", "displayName": "refresh_attempts", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false } ], "attemptToConvertTypes": false, "convertFieldsToString": false }, "options": {} }, "type": "n8n-nodes-base.googleSheets", "typeVersion": 4.7, "position": [ 4608, 400 ], "id": "f6487012-88de-4be3-b62e-fa9bdfdda270", "name": "Google Sheets - Upsert Banco Fulgencio", "credentials": { "googleSheetsOAuth2Api": { "id": "K0hDZh3a85MpOHCs", "name": "Google Sheets account 2" } } }, { "parameters": { "jsCode": "const original = $('Code - Preparar texto IA Refresco').item.json || {};\n\nreturn [\n {\n json: {\n ...original,\n drive_modified_time: original.drive_modified_time_actual || '',\n ultimo_refresco_ia: new Date().toISOString(),\n refresh_status: 'SIN_CONTENIDO',\n refresh_attempts: original.refresh_attempts || 1,\n procesado_ia: false,\n },\n },\n];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 3264, 48 ], "id": "42c459da-dd49-4ed8-aa1d-ff1f39688acf", "name": "Code - Marcar sin contenido" }, { "parameters": { "jsCode": "const original = $json || {};\n\nreturn [\n {\n json: {\n ...original,\n drive_modified_time: original.drive_modified_time || '',\n ultimo_refresco_ia: new Date().toISOString(),\n refresh_status: 'SIN_FILE_ID',\n refresh_attempts: Number(original.refresh_attempts_actual || original.refresh_attempts || 0) + 1,\n procesado_ia: false,\n },\n },\n];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 1984, 176 ], "id": "6287af34-de8e-49aa-b432-778c016c9f8d", "name": "Code - Marcar sin file_id" }, { "parameters": { "jsCode": "const original = $('IF - Tiene file_id?').item.json || {};\nconst errorData = $json || {};\n\nreturn [\n {\n json: {\n ...original,\n drive_modified_time: original.drive_modified_time || '',\n ultimo_refresco_ia: new Date().toISOString(),\n refresh_status: 'ERROR_METADATA_DRIVE',\n refresh_attempts: Number(original.refresh_attempts_actual || original.refresh_attempts || 0) + 1,\n procesado_ia: false,\n motivos_revision: `error_metadata_drive: ${String(errorData.message || errorData.error || '').slice(0, 200)}`,\n },\n },\n];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 1936, -32 ], "id": "389332ff-4d6b-4a5d-824d-28a1098030ef", "name": "Code - Marcar error metadata Drive" }, { "parameters": { "jsCode": "const original = $('Code - Evaluar refresco').item.json || {};\nconst errorData = $json || {};\n\nreturn [\n {\n json: {\n ...original,\n drive_modified_time: original.drive_modified_time_actual || original.drive_modified_time || '',\n ultimo_refresco_ia: new Date().toISOString(),\n refresh_status: 'ERROR_EXPORT_SLIDES',\n refresh_attempts: Number(original.refresh_attempts_actual || original.refresh_attempts || 0) + 1,\n procesado_ia: false,\n motivos_revision: `error_export_slides: ${String(errorData.message || errorData.error || '').slice(0, 200)}`,\n },\n },\n];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 2608, -192 ], "id": "251b1833-27c9-4a63-9a97-6ad600ea5283", "name": "Code - Marcar error export Slides" } ], "connections": { "Schedule Trigger": { "main": [ [ { "node": "Sheets - Leer Banco Fulgencio", "type": "main", "index": 0 } ] ] }, "Sheets - Leer Banco Fulgencio": { "main": [ [ { "node": "Code - Filtrar filas Tablero CDC", "type": "main", "index": 0 } ] ] }, "Code - Filtrar filas Tablero CDC": { "main": [ [ { "node": "Loop - Filas Banco Fulgencio", "type": "main", "index": 0 } ] ] }, "Loop - Filas Banco Fulgencio": { "main": [ [], [ { "node": "IF - Tiene file_id?", "type": "main", "index": 0 } ] ] }, "IF - Tiene file_id?": { "main": [ [ { "node": "HTTP - Obtener metadata Drive", "type": "main", "index": 0 } ], [ { "node": "Code - Marcar sin file_id", "type": "main", "index": 0 } ] ] }, "HTTP - Obtener metadata Drive": { "main": [ [ { "node": "Code - Evaluar refresco", "type": "main", "index": 0 } ], [ { "node": "Code - Marcar error metadata Drive", "type": "main", "index": 0 } ] ] }, "Code - Evaluar refresco": { "main": [ [ { "node": "IF - Debe refrescar?", "type": "main", "index": 0 } ] ] }, "IF - Debe refrescar?": { "main": [ [ { "node": "HTTP - Exportar Slides TXT", "type": "main", "index": 0 } ], [ { "node": "Loop - Filas Banco Fulgencio", "type": "main", "index": 0 } ] ] }, "HTTP - Exportar Slides TXT": { "main": [ [ { "node": "Code - Preparar texto IA Refresco", "type": "main", "index": 0 } ], [ { "node": "Code - Marcar error export Slides", "type": "main", "index": 0 } ] ] }, "Code - Preparar texto IA Refresco": { "main": [ [ { "node": "IF - Tiene contenido?", "type": "main", "index": 0 } ] ] }, "IF - Tiene contenido?": { "main": [ [ { "node": "Gemini - Reanalizar contenido Slides", "type": "main", "index": 0 } ], [ { "node": "Code - Marcar sin contenido", "type": "main", "index": 0 } ] ] }, "Google Gemini Chat Model": { "ai_languageModel": [ [ { "node": "Gemini - Reanalizar contenido Slides", "type": "ai_languageModel", "index": 0 } ] ] }, "Gemini - Reanalizar contenido Slides": { "main": [ [ { "node": "Code - Normalizar respuesta refresco", "type": "main", "index": 0 } ] ] }, "Code - Normalizar respuesta refresco": { "main": [ [ { "node": "Google Sheets - Upsert Banco Fulgencio", "type": "main", "index": 0 } ] ] }, "Code - Marcar sin contenido": { "main": [ [ { "node": "Google Sheets - Upsert Banco Fulgencio", "type": "main", "index": 0 } ] ] }, "Google Sheets - Upsert Banco Fulgencio": { "main": [ [ { "node": "Loop - Filas Banco Fulgencio", "type": "main", "index": 0 } ] ] }, "Code - Marcar sin file_id": { "main": [ [ { "node": "Google Sheets - Upsert Banco Fulgencio", "type": "main", "index": 0 } ] ] }, "Code - Marcar error metadata Drive": { "main": [ [ { "node": "Google Sheets - Upsert Banco Fulgencio", "type": "main", "index": 0 } ] ] }, "Code - Marcar error export Slides": { "main": [ [ { "node": "Google Sheets - Upsert Banco Fulgencio", "type": "main", "index": 0 } ] ] } }, "authors": "Isaac Aracena", "name": "Version fd39df42", "description": "", "autosaved": true, "workflowPublishHistory": [ { "createdAt": "2026-06-16T20:43:40.864Z", "id": 1466, "workflowId": "g2JtKXNz5GDbkmQH", "versionId": "fd39df42-6d7e-4305-973d-cf2c6ba679fc", "event": "activated", "userId": "0a88c0b1-928e-4412-896e-c5d1c99b2029" } ] } }