diff --git a/seguimiento-de-impuestos-glm-recordatorios-gmail-y-google-chat.json b/seguimiento-de-impuestos-glm-recordatorios-gmail-y-google-chat.json
index 3ea8844..643ebd7 100644
--- a/seguimiento-de-impuestos-glm-recordatorios-gmail-y-google-chat.json
+++ b/seguimiento-de-impuestos-glm-recordatorios-gmail-y-google-chat.json
@@ -1,5 +1,5 @@
{
- "updatedAt": "2026-08-03T14:27:06.453Z",
+ "updatedAt": "2026-08-12T17:42:20.872Z",
"createdAt": "2026-07-24T19:13:05.914Z",
"id": "cFu3Xx23KQBKfr0M",
"name": "Seguimiento de Impuestos GLM - Recordatorios Gmail y Google Chat",
@@ -21,10 +21,10 @@
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
- -32,
- 1456
+ -352,
+ 1920
],
- "id": "d9890ecf-a9ba-4604-9a68-03568e80bbe5",
+ "id": "0e8037b9-25e3-4fcb-9585-f11448a4b9bb",
"name": "Diario 8:00 AM"
},
{
@@ -32,10 +32,10 @@
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
- -32,
- 1616
+ -352,
+ 2080
],
- "id": "58d5e31d-10bb-4dec-af43-d3ea3225a4ad",
+ "id": "a63000b5-7dda-4c3a-98db-dd40064d4ed4",
"name": "Ejecutar manualmente"
},
{
@@ -47,10 +47,10 @@
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
- -32,
- 1808
+ -352,
+ 2272
],
- "id": "b1a94a40-005a-419c-9d3d-697b95d16749",
+ "id": "ae941003-35ae-47a8-8e81-a9db92140e62",
"name": "Webhook seguimiento-impuestos",
"webhookId": "seguimiento-impuestos-glm"
},
@@ -61,10 +61,10 @@
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 224,
- 1536
+ -96,
+ 2000
],
- "id": "da51143c-6cbd-4ea1-a49e-d0c4b097b952",
+ "id": "9dc0b144-b6e2-4238-8786-7bb418778bc1",
"name": "Preparar ejecución"
},
{
@@ -74,10 +74,10 @@
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 224,
- 1808
+ -96,
+ 2272
],
- "id": "0863e7a7-bc95-42f6-982f-f09f859ec6d6",
+ "id": "0b7ce2a9-6759-4eb7-9614-9ea588a27290",
"name": "Validar ejecución por Webhook"
},
{
@@ -109,23 +109,23 @@
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
- 480,
- 1616
+ 160,
+ 2080
],
- "id": "00dfa1be-5e07-4860-8322-d9f490ac4e4a",
+ "id": "9e198092-e114-491c-9672-048fa0ad5d2b",
"name": "Supabase - Recordatorios pendientes"
},
{
"parameters": {
- "jsCode": "const htmlEscape = (value) => String(value ?? '')\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n\nconst rows = [];\nfor (const item of $input.all()) {\n const value = item.json;\n if (Array.isArray(value)) rows.push(...value);\n else if (Array.isArray(value?.data)) rows.push(...value.data);\n else if (Array.isArray(value?.body)) rows.push(...value.body);\n else if (value?.obligation_id) rows.push(value);\n}\n\nconst logoUrl = 'https://home.digitalcompass.agency/glm-logo-completo.png';\nconst appUrl = 'https://digitalcompass.agency/calendario-impuestos/';\n\nconst formatDate = (iso) => {\n const [year, month, day] = String(iso).split('-').map(Number);\n return new Intl.DateTimeFormat('es-DO', {\n timeZone: 'UTC',\n day: '2-digit',\n month: 'long',\n year: 'numeric',\n }).format(new Date(Date.UTC(year, month - 1, day)));\n};\n\nreturn rows.map((row) => {\n const dueDate = formatDate(row.due_date);\n const isSameDay = row.alert_type === 'same_day';\n const reminderLabel = isSameDay ? 'Vence hoy' : 'Recordatorio previo';\n const categoryLabel = row.category === 'nomina' ? 'Nómina' : 'Administración';\n const firstName = String(row.contact_name ?? '').trim().split(/\\s+/)[0] || 'equipo';\n const subject = `${isSameDay ? 'Vence hoy' : 'Recordatorio'} · ${row.country_name} · ${row.description}`;\n\n const emailHtml = `\n\n\n
\n \n \n \n }\") | \n | | \n | \n ${htmlEscape(reminderLabel)} \n Seguimiento de Impuestos GLM\n Hola ${htmlEscape(firstName)}, este es el recordatorio correspondiente a la siguiente obligación tributaria: \n \n | País | ${htmlEscape(row.country_name)} | \n | Categoría | ${htmlEscape(categoryLabel)} | \n | Fecha límite | ${htmlEscape(dueDate)} | \n | Obligación | ${htmlEscape(row.description)} | \n \n Este aviso forma parte del seguimiento automático: miércoles anterior y fecha límite, incluidos sábados y domingos. \n \n | \n | GOMEZLEE MARKETING | Seguimiento de Impuestos GLM | Uso interno | \n \n |
\n
\n \n`.trim();\n\n const googleChatText = [\n `*${reminderLabel.toUpperCase()} · SEGUIMIENTO DE IMPUESTOS GLM*`,\n '',\n `Hola ${firstName},`,\n '',\n `*País:* ${row.country_name}`,\n `*Categoría:* ${categoryLabel}`,\n `*Fecha límite:* ${dueDate}`,\n `*Obligación:* ${row.description}`,\n '',\n 'Seguimiento automático: miércoles anterior y fecha límite, incluidos sábados y domingos.',\n '',\n `Abrir calendario: ${appUrl}`,\n ].join('\\n');\n\n return {\n json: {\n ...row,\n email_subject: subject,\n email_html: emailHtml,\n google_chat_text: googleChatText,\n },\n };\n});"
+ "jsCode": "const htmlEscape = (value) => String(value ?? '')\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n\nconst rows = [];\nfor (const item of $input.all()) {\n const value = item.json;\n if (Array.isArray(value)) rows.push(...value);\n else if (Array.isArray(value?.data)) rows.push(...value.data);\n else if (Array.isArray(value?.body)) rows.push(...value.body);\n else if (value?.obligation_id) rows.push(value);\n}\n\nconst logoUrl = 'https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM_completo.png';\nconst appUrl = 'https://digitalcompass.agency/calendario-impuestos/';\n\nconst formatDate = (iso) => {\n const [year, month, day] = String(iso).split('-').map(Number);\n return new Intl.DateTimeFormat('es-DO', {\n timeZone: 'UTC',\n day: '2-digit',\n month: 'long',\n year: 'numeric',\n }).format(new Date(Date.UTC(year, month - 1, day)));\n};\n\nreturn rows.map((row) => {\n const dueDate = formatDate(row.due_date);\n const isSameDay = row.alert_type === 'same_day';\n const reminderLabel = isSameDay ? 'Vence hoy' : 'Recordatorio previo';\n const categoryLabel = row.category === 'nomina' ? 'Nómina' : 'Administración';\n const firstName = String(row.contact_name ?? '').trim().split(/\\s+/)[0] || 'equipo';\n const subject = `${isSameDay ? 'Vence hoy' : 'Recordatorio'} · ${row.country_name} · ${row.description}`;\n\n const emailHtml = `\n\n\n \n \n \n \n  | \n | | \n | \n ${htmlEscape(reminderLabel)} \n Seguimiento de Impuestos GLM\n Hola ${htmlEscape(firstName)}, este es el recordatorio correspondiente a la siguiente obligación tributaria: \n \n | País | ${htmlEscape(row.country_name)} | \n | Categoría | ${htmlEscape(categoryLabel)} | \n | Fecha límite | ${htmlEscape(dueDate)} | \n | Obligación | ${htmlEscape(row.description)} | \n \n Este aviso forma parte del seguimiento automático: miércoles anterior y fecha límite, incluidos sábados y domingos. \n \n | \n | GOMEZLEE MARKETING | Seguimiento de Impuestos GLM | Uso interno | \n \n |
\n
\n \n`.trim();\n\n const googleChatText = [\n `*${reminderLabel.toUpperCase()} · SEGUIMIENTO DE IMPUESTOS GLM*`,\n '',\n `Hola ${firstName},`,\n '',\n `*País:* ${row.country_name}`,\n `*Categoría:* ${categoryLabel}`,\n `*Fecha límite:* ${dueDate}`,\n `*Obligación:* ${row.description}`,\n '',\n 'Seguimiento automático: miércoles anterior y fecha límite, incluidos sábados y domingos.',\n '',\n `Abrir calendario: ${appUrl}`,\n ].join('\\n');\n\n return {\n json: {\n ...row,\n email_subject: subject,\n email_html: emailHtml,\n google_chat_text: googleChatText,\n },\n };\n});"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 736,
- 1616
+ 416,
+ 2080
],
- "id": "780bc937-c373-43cc-9343-e3c73d076934",
+ "id": "c19543d0-6e85-4ed7-903a-1d254553cf49",
"name": "Construir mensajes GLM"
},
{
@@ -135,10 +135,10 @@
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 1008,
- 1472
+ 688,
+ 1936
],
- "id": "343dc1d3-cb5b-452c-b5d4-f69583b15280",
+ "id": "e923e3bc-02d7-4402-8ca4-4138f2db3cd2",
"name": "Preparar correos"
},
{
@@ -153,10 +153,10 @@
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
- 1264,
- 1472
+ 944,
+ 1936
],
- "id": "7f16857a-3674-4255-9674-cc040682f518",
+ "id": "084ac77b-6f26-41c8-ab55-8d0989f81fb8",
"name": "Gmail - Enviar recordatorio",
"webhookId": "16bfebbd-f4e3-4b1e-aba2-028fecf98da1",
"credentials": {
@@ -195,23 +195,23 @@
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
- 1520,
- 1472
+ 1200,
+ 1936
],
- "id": "bea9fc06-b8de-4091-bde0-d7be8c18e4cd",
+ "id": "ce69dcd5-c9ae-4770-9797-a9fff667a7ba",
"name": "Supabase - Registrar correo"
},
{
"parameters": {
- "jsCode": "return $input.all().filter((item) => item.json.google_chat_enabled === true && String(item.json.contact_email ?? '').trim());"
+ "jsCode": "const CALLING_USER_EMAIL = 'iaracena@gomezleemarketing.com';\n\nreturn $input.all().filter((item) => {\n const enabled = item.json.google_chat_enabled === true;\n const email = String(item.json.contact_email ?? '').trim().toLowerCase();\n\n return enabled && email && email !== CALLING_USER_EMAIL;\n});"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 1008,
- 1744
+ 688,
+ 2208
],
- "id": "3addf2bd-60c2-493c-8919-56b603aad7e8",
+ "id": "a02e0bac-f208-491d-8257-83dc91fe5dd4",
"name": "Preparar Google Chat"
},
{
@@ -239,33 +239,33 @@
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
- 1264,
- 1744
+ 944,
+ 2208
],
- "id": "630cdc84-f7aa-4db8-8356-942056f3ac22",
+ "id": "290d682a-55cf-411b-82f4-6e573fadaf9d",
"name": "Google Chat - Abrir DM",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 1500,
"credentials": {
"googleChatOAuth2Api": {
- "id": "V4eVQvEoy5QcBvUu",
- "name": "Chat account"
+ "id": "8UR1kLTQ4SDHgfaZ",
+ "name": "Google Chat - Seguimiento de Impuestos GLM"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
- "jsCode": "const source = $('Preparar Google Chat').item.json;\nconst spaceName = String($json.name ?? '').trim();\nreturn [{ json: { ...source, chat_space_name: spaceName, chat_setup_ok: Boolean(spaceName), google_chat_status: spaceName ? 'pending' : 'failed', google_chat_provider_response: $json } }];"
+ "jsCode": "const responses = $input.all();\nconst sources = $('Preparar Google Chat').all();\n\nreturn responses.map((item, index) => {\n const source = sources[index]?.json ?? {};\n const response = item.json ?? {};\n const spaceName = String(response.name ?? '').trim();\n const ok = Boolean(spaceName) && !response.error;\n\n return {\n json: {\n ...source,\n chat_space_name: spaceName,\n chat_setup_ok: ok,\n google_chat_status: ok ? 'pending' : 'failed',\n google_chat_provider_response: response,\n },\n pairedItem: { item: index },\n };\n});"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 1520,
- 1744
+ 1200,
+ 2208
],
- "id": "1002151d-cb96-46c1-9868-3e9aca7846c0",
+ "id": "04d40a89-5b44-441f-ae5b-e681c480820e",
"name": "Evaluar DM Google Chat"
},
{
@@ -275,10 +275,10 @@
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 1776,
- 1632
+ 1456,
+ 2096
],
- "id": "5978dd34-7cb2-46be-9536-65c22b7f06a4",
+ "id": "1ab28b37-2d73-4471-ae52-c62163c4d9f0",
"name": "Preparar envío Google Chat"
},
{
@@ -288,10 +288,10 @@
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 1776,
- 1888
+ 1456,
+ 2352
],
- "id": "cbc9f8d3-35f8-48a2-9251-c85c96d15be0",
+ "id": "fdd96034-cd48-427a-acda-3ac249eb3f31",
"name": "Preparar fallo DM Google Chat"
},
{
@@ -311,7 +311,7 @@
},
"sendBody": true,
"specifyBody": "json",
- "jsonBody": "={{ { text: $json.google_chat_text, createMessageNotificationOptions: { notificationType: 'NOTIFICATION_TYPE_FORCE_NOTIFY' } } }}",
+ "jsonBody": "={{ { text: $json.google_chat_text } }}",
"options": {
"timeout": 30000
}
@@ -319,33 +319,33 @@
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
- 2032,
- 1632
+ 1712,
+ 2096
],
- "id": "d4d67181-4079-4a46-9fd7-a10afe57db71",
+ "id": "2f510b09-4bb1-4dcb-863b-9d863868750b",
"name": "Google Chat - Enviar recordatorio",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 1500,
"credentials": {
"googleChatOAuth2Api": {
- "id": "V4eVQvEoy5QcBvUu",
- "name": "Chat account"
+ "id": "8UR1kLTQ4SDHgfaZ",
+ "name": "Google Chat - Seguimiento de Impuestos GLM"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
- "jsCode": "const source = $('Preparar envío Google Chat').item.json;\nconst sent = Boolean($json.name) && !$json.error;\nreturn [{ json: { ...source, google_chat_status: sent ? 'sent' : 'failed', google_chat_provider_response: $json } }];"
+ "jsCode": "const responses = $input.all();\nconst sources = $('Preparar envío Google Chat').all();\n\nreturn responses.map((item, index) => {\n const source = sources[index]?.json ?? {};\n const response = item.json ?? {};\n const sent = Boolean(response.name) && !response.error;\n\n return {\n json: {\n ...source,\n google_chat_status: sent ? 'sent' : 'failed',\n google_chat_provider_response: response,\n },\n pairedItem: { item: index },\n };\n});"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 2288,
- 1632
+ 1968,
+ 2096
],
- "id": "6398165b-9e0a-483f-9db6-71f0d85a69d0",
+ "id": "93094ae5-5e9b-4e42-9a9b-5ed9213943e3",
"name": "Evaluar envío Google Chat"
},
{
@@ -377,15 +377,15 @@
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
- 2544,
- 1744
+ 2224,
+ 2208
],
- "id": "29a93cc5-c157-4199-81c1-1fed7664edc6",
+ "id": "db27cf44-56e0-4544-90dd-d81bc0d4bd7d",
"name": "Supabase - Registrar Google Chat"
},
{
"parameters": {
- "content": "## RECORDATORIOS DE IMPUESTOS POR GMAIL Y GOOGLE CHAT\n\nEjecuta diariamente el proceso de recordatorios fiscales y notifica a los contactos correspondientes por correo electrónico y mensaje directo de Google Chat.\n\n- Puede iniciarse automáticamente a las 8:00 a. m., manualmente o desde el webhook de la aplicación.\n- Valida y normaliza el origen de la ejecución antes de continuar.\n- Consulta en Supabase las obligaciones que requieren recordatorio y sus destinatarios.\n- Construye mensajes personalizados con el formato corporativo de GLM.\n- Envía los recordatorios por Gmail y registra en Supabase el resultado de cada correo.\n- Abre o identifica la conversación directa del destinatario en Google Chat.\n- Envía el recordatorio por Google Chat cuando el DM está disponible.\n- Evalúa cada intento y registra tanto los envíos exitosos como los errores para mantener trazabilidad.",
+ "content": "## RECORDATORIOS DE IMPUESTOS POR GMAIL Y GOOGLE CHAT\n\nEjecuta diariamente el proceso de recordatorios fiscales y notifica a los contactos correspondientes por correo electrónico y mensaje directo de Google Chat.\n\n- Puede iniciarse automáticamente a las 8:00 a. m., manualmente o desde el webhook de la aplicación.\n- Consulta en Supabase las obligaciones que requieren recordatorio y sus destinatarios.\n- Construye mensajes personalizados con el formato corporativo de GLM.\n- Envía los recordatorios por Gmail al correo de cada contacto y registra el resultado.\n- Abre o reutiliza el DM del destinatario en Google Chat mediante `spaces:setup`.\n- Conserva todos los items de Google Chat de principio a fin; no colapsa múltiples destinatarios en uno solo.\n- Envía texto con `spaces.messages.create` usando un body válido `{ text: ... }`.\n- Omite el correo del propio usuario autenticado de Google Chat, porque Google agrega automáticamente al calling user y no permite especificarlo como membership.\n- Evalúa cada intento individualmente y registra éxitos o errores en Supabase.",
"height": 1184,
"width": 2880,
"color": "#204750"
@@ -393,10 +393,10 @@
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
- -144,
- 881.5847255369928
+ -464,
+ 1360
],
- "id": "8c9fe360-936b-4e86-bd17-5a396dd09419",
+ "id": "3ee2b7ce-eff0-4d62-b80d-f4df454e91df",
"name": "Sticky Note"
}
],
@@ -605,9 +605,9 @@
"meta": {
"templateCredsSetupCompleted": true
},
- "versionId": "ab159702-cf57-4e47-8de5-95da61a56b9b",
- "activeVersionId": "ab159702-cf57-4e47-8de5-95da61a56b9b",
- "versionCounter": 93,
+ "versionId": "0ebbe45e-f485-4abc-8de3-5f5b05857edf",
+ "activeVersionId": "0ebbe45e-f485-4abc-8de3-5f5b05857edf",
+ "versionCounter": 121,
"triggerCount": 2,
"shared": [
{
@@ -630,9 +630,9 @@
],
"tags": [],
"activeVersion": {
- "updatedAt": "2026-08-03T14:27:08.000Z",
- "createdAt": "2026-08-03T14:27:06.456Z",
- "versionId": "ab159702-cf57-4e47-8de5-95da61a56b9b",
+ "updatedAt": "2026-08-12T17:42:42.000Z",
+ "createdAt": "2026-08-12T17:42:20.874Z",
+ "versionId": "0ebbe45e-f485-4abc-8de3-5f5b05857edf",
"workflowId": "cFu3Xx23KQBKfr0M",
"nodes": [
{
@@ -649,10 +649,10 @@
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
- -32,
- 1456
+ -352,
+ 1920
],
- "id": "d9890ecf-a9ba-4604-9a68-03568e80bbe5",
+ "id": "0e8037b9-25e3-4fcb-9585-f11448a4b9bb",
"name": "Diario 8:00 AM"
},
{
@@ -660,10 +660,10 @@
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
- -32,
- 1616
+ -352,
+ 2080
],
- "id": "58d5e31d-10bb-4dec-af43-d3ea3225a4ad",
+ "id": "a63000b5-7dda-4c3a-98db-dd40064d4ed4",
"name": "Ejecutar manualmente"
},
{
@@ -675,10 +675,10 @@
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
- -32,
- 1808
+ -352,
+ 2272
],
- "id": "b1a94a40-005a-419c-9d3d-697b95d16749",
+ "id": "ae941003-35ae-47a8-8e81-a9db92140e62",
"name": "Webhook seguimiento-impuestos",
"webhookId": "seguimiento-impuestos-glm"
},
@@ -689,10 +689,10 @@
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 224,
- 1536
+ -96,
+ 2000
],
- "id": "da51143c-6cbd-4ea1-a49e-d0c4b097b952",
+ "id": "9dc0b144-b6e2-4238-8786-7bb418778bc1",
"name": "Preparar ejecución"
},
{
@@ -702,10 +702,10 @@
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 224,
- 1808
+ -96,
+ 2272
],
- "id": "0863e7a7-bc95-42f6-982f-f09f859ec6d6",
+ "id": "0b7ce2a9-6759-4eb7-9614-9ea588a27290",
"name": "Validar ejecución por Webhook"
},
{
@@ -737,23 +737,23 @@
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
- 480,
- 1616
+ 160,
+ 2080
],
- "id": "00dfa1be-5e07-4860-8322-d9f490ac4e4a",
+ "id": "9e198092-e114-491c-9672-048fa0ad5d2b",
"name": "Supabase - Recordatorios pendientes"
},
{
"parameters": {
- "jsCode": "const htmlEscape = (value) => String(value ?? '')\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n\nconst rows = [];\nfor (const item of $input.all()) {\n const value = item.json;\n if (Array.isArray(value)) rows.push(...value);\n else if (Array.isArray(value?.data)) rows.push(...value.data);\n else if (Array.isArray(value?.body)) rows.push(...value.body);\n else if (value?.obligation_id) rows.push(value);\n}\n\nconst logoUrl = 'https://home.digitalcompass.agency/glm-logo-completo.png';\nconst appUrl = 'https://digitalcompass.agency/calendario-impuestos/';\n\nconst formatDate = (iso) => {\n const [year, month, day] = String(iso).split('-').map(Number);\n return new Intl.DateTimeFormat('es-DO', {\n timeZone: 'UTC',\n day: '2-digit',\n month: 'long',\n year: 'numeric',\n }).format(new Date(Date.UTC(year, month - 1, day)));\n};\n\nreturn rows.map((row) => {\n const dueDate = formatDate(row.due_date);\n const isSameDay = row.alert_type === 'same_day';\n const reminderLabel = isSameDay ? 'Vence hoy' : 'Recordatorio previo';\n const categoryLabel = row.category === 'nomina' ? 'Nómina' : 'Administración';\n const firstName = String(row.contact_name ?? '').trim().split(/\\s+/)[0] || 'equipo';\n const subject = `${isSameDay ? 'Vence hoy' : 'Recordatorio'} · ${row.country_name} · ${row.description}`;\n\n const emailHtml = `\n\n\n \n \n \n \n }\") | \n | | \n | \n ${htmlEscape(reminderLabel)} \n Seguimiento de Impuestos GLM\n Hola ${htmlEscape(firstName)}, este es el recordatorio correspondiente a la siguiente obligación tributaria: \n \n | País | ${htmlEscape(row.country_name)} | \n | Categoría | ${htmlEscape(categoryLabel)} | \n | Fecha límite | ${htmlEscape(dueDate)} | \n | Obligación | ${htmlEscape(row.description)} | \n \n Este aviso forma parte del seguimiento automático: miércoles anterior y fecha límite, incluidos sábados y domingos. \n \n | \n | GOMEZLEE MARKETING | Seguimiento de Impuestos GLM | Uso interno | \n \n |
\n
\n \n`.trim();\n\n const googleChatText = [\n `*${reminderLabel.toUpperCase()} · SEGUIMIENTO DE IMPUESTOS GLM*`,\n '',\n `Hola ${firstName},`,\n '',\n `*País:* ${row.country_name}`,\n `*Categoría:* ${categoryLabel}`,\n `*Fecha límite:* ${dueDate}`,\n `*Obligación:* ${row.description}`,\n '',\n 'Seguimiento automático: miércoles anterior y fecha límite, incluidos sábados y domingos.',\n '',\n `Abrir calendario: ${appUrl}`,\n ].join('\\n');\n\n return {\n json: {\n ...row,\n email_subject: subject,\n email_html: emailHtml,\n google_chat_text: googleChatText,\n },\n };\n});"
+ "jsCode": "const htmlEscape = (value) => String(value ?? '')\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n\nconst rows = [];\nfor (const item of $input.all()) {\n const value = item.json;\n if (Array.isArray(value)) rows.push(...value);\n else if (Array.isArray(value?.data)) rows.push(...value.data);\n else if (Array.isArray(value?.body)) rows.push(...value.body);\n else if (value?.obligation_id) rows.push(value);\n}\n\nconst logoUrl = 'https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM_completo.png';\nconst appUrl = 'https://digitalcompass.agency/calendario-impuestos/';\n\nconst formatDate = (iso) => {\n const [year, month, day] = String(iso).split('-').map(Number);\n return new Intl.DateTimeFormat('es-DO', {\n timeZone: 'UTC',\n day: '2-digit',\n month: 'long',\n year: 'numeric',\n }).format(new Date(Date.UTC(year, month - 1, day)));\n};\n\nreturn rows.map((row) => {\n const dueDate = formatDate(row.due_date);\n const isSameDay = row.alert_type === 'same_day';\n const reminderLabel = isSameDay ? 'Vence hoy' : 'Recordatorio previo';\n const categoryLabel = row.category === 'nomina' ? 'Nómina' : 'Administración';\n const firstName = String(row.contact_name ?? '').trim().split(/\\s+/)[0] || 'equipo';\n const subject = `${isSameDay ? 'Vence hoy' : 'Recordatorio'} · ${row.country_name} · ${row.description}`;\n\n const emailHtml = `\n\n\n \n \n \n \n  | \n | | \n | \n ${htmlEscape(reminderLabel)} \n Seguimiento de Impuestos GLM\n Hola ${htmlEscape(firstName)}, este es el recordatorio correspondiente a la siguiente obligación tributaria: \n \n | País | ${htmlEscape(row.country_name)} | \n | Categoría | ${htmlEscape(categoryLabel)} | \n | Fecha límite | ${htmlEscape(dueDate)} | \n | Obligación | ${htmlEscape(row.description)} | \n \n Este aviso forma parte del seguimiento automático: miércoles anterior y fecha límite, incluidos sábados y domingos. \n \n | \n | GOMEZLEE MARKETING | Seguimiento de Impuestos GLM | Uso interno | \n \n |
\n
\n \n`.trim();\n\n const googleChatText = [\n `*${reminderLabel.toUpperCase()} · SEGUIMIENTO DE IMPUESTOS GLM*`,\n '',\n `Hola ${firstName},`,\n '',\n `*País:* ${row.country_name}`,\n `*Categoría:* ${categoryLabel}`,\n `*Fecha límite:* ${dueDate}`,\n `*Obligación:* ${row.description}`,\n '',\n 'Seguimiento automático: miércoles anterior y fecha límite, incluidos sábados y domingos.',\n '',\n `Abrir calendario: ${appUrl}`,\n ].join('\\n');\n\n return {\n json: {\n ...row,\n email_subject: subject,\n email_html: emailHtml,\n google_chat_text: googleChatText,\n },\n };\n});"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 736,
- 1616
+ 416,
+ 2080
],
- "id": "780bc937-c373-43cc-9343-e3c73d076934",
+ "id": "c19543d0-6e85-4ed7-903a-1d254553cf49",
"name": "Construir mensajes GLM"
},
{
@@ -763,10 +763,10 @@
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 1008,
- 1472
+ 688,
+ 1936
],
- "id": "343dc1d3-cb5b-452c-b5d4-f69583b15280",
+ "id": "e923e3bc-02d7-4402-8ca4-4138f2db3cd2",
"name": "Preparar correos"
},
{
@@ -781,10 +781,10 @@
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
- 1264,
- 1472
+ 944,
+ 1936
],
- "id": "7f16857a-3674-4255-9674-cc040682f518",
+ "id": "084ac77b-6f26-41c8-ab55-8d0989f81fb8",
"name": "Gmail - Enviar recordatorio",
"webhookId": "16bfebbd-f4e3-4b1e-aba2-028fecf98da1",
"credentials": {
@@ -823,23 +823,23 @@
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
- 1520,
- 1472
+ 1200,
+ 1936
],
- "id": "bea9fc06-b8de-4091-bde0-d7be8c18e4cd",
+ "id": "ce69dcd5-c9ae-4770-9797-a9fff667a7ba",
"name": "Supabase - Registrar correo"
},
{
"parameters": {
- "jsCode": "return $input.all().filter((item) => item.json.google_chat_enabled === true && String(item.json.contact_email ?? '').trim());"
+ "jsCode": "const CALLING_USER_EMAIL = 'iaracena@gomezleemarketing.com';\n\nreturn $input.all().filter((item) => {\n const enabled = item.json.google_chat_enabled === true;\n const email = String(item.json.contact_email ?? '').trim().toLowerCase();\n\n return enabled && email && email !== CALLING_USER_EMAIL;\n});"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 1008,
- 1744
+ 688,
+ 2208
],
- "id": "3addf2bd-60c2-493c-8919-56b603aad7e8",
+ "id": "a02e0bac-f208-491d-8257-83dc91fe5dd4",
"name": "Preparar Google Chat"
},
{
@@ -867,33 +867,33 @@
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
- 1264,
- 1744
+ 944,
+ 2208
],
- "id": "630cdc84-f7aa-4db8-8356-942056f3ac22",
+ "id": "290d682a-55cf-411b-82f4-6e573fadaf9d",
"name": "Google Chat - Abrir DM",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 1500,
"credentials": {
"googleChatOAuth2Api": {
- "id": "V4eVQvEoy5QcBvUu",
- "name": "Chat account"
+ "id": "8UR1kLTQ4SDHgfaZ",
+ "name": "Google Chat - Seguimiento de Impuestos GLM"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
- "jsCode": "const source = $('Preparar Google Chat').item.json;\nconst spaceName = String($json.name ?? '').trim();\nreturn [{ json: { ...source, chat_space_name: spaceName, chat_setup_ok: Boolean(spaceName), google_chat_status: spaceName ? 'pending' : 'failed', google_chat_provider_response: $json } }];"
+ "jsCode": "const responses = $input.all();\nconst sources = $('Preparar Google Chat').all();\n\nreturn responses.map((item, index) => {\n const source = sources[index]?.json ?? {};\n const response = item.json ?? {};\n const spaceName = String(response.name ?? '').trim();\n const ok = Boolean(spaceName) && !response.error;\n\n return {\n json: {\n ...source,\n chat_space_name: spaceName,\n chat_setup_ok: ok,\n google_chat_status: ok ? 'pending' : 'failed',\n google_chat_provider_response: response,\n },\n pairedItem: { item: index },\n };\n});"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 1520,
- 1744
+ 1200,
+ 2208
],
- "id": "1002151d-cb96-46c1-9868-3e9aca7846c0",
+ "id": "04d40a89-5b44-441f-ae5b-e681c480820e",
"name": "Evaluar DM Google Chat"
},
{
@@ -903,10 +903,10 @@
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 1776,
- 1632
+ 1456,
+ 2096
],
- "id": "5978dd34-7cb2-46be-9536-65c22b7f06a4",
+ "id": "1ab28b37-2d73-4471-ae52-c62163c4d9f0",
"name": "Preparar envío Google Chat"
},
{
@@ -916,10 +916,10 @@
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 1776,
- 1888
+ 1456,
+ 2352
],
- "id": "cbc9f8d3-35f8-48a2-9251-c85c96d15be0",
+ "id": "fdd96034-cd48-427a-acda-3ac249eb3f31",
"name": "Preparar fallo DM Google Chat"
},
{
@@ -939,7 +939,7 @@
},
"sendBody": true,
"specifyBody": "json",
- "jsonBody": "={{ { text: $json.google_chat_text, createMessageNotificationOptions: { notificationType: 'NOTIFICATION_TYPE_FORCE_NOTIFY' } } }}",
+ "jsonBody": "={{ { text: $json.google_chat_text } }}",
"options": {
"timeout": 30000
}
@@ -947,33 +947,33 @@
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
- 2032,
- 1632
+ 1712,
+ 2096
],
- "id": "d4d67181-4079-4a46-9fd7-a10afe57db71",
+ "id": "2f510b09-4bb1-4dcb-863b-9d863868750b",
"name": "Google Chat - Enviar recordatorio",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 1500,
"credentials": {
"googleChatOAuth2Api": {
- "id": "V4eVQvEoy5QcBvUu",
- "name": "Chat account"
+ "id": "8UR1kLTQ4SDHgfaZ",
+ "name": "Google Chat - Seguimiento de Impuestos GLM"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
- "jsCode": "const source = $('Preparar envío Google Chat').item.json;\nconst sent = Boolean($json.name) && !$json.error;\nreturn [{ json: { ...source, google_chat_status: sent ? 'sent' : 'failed', google_chat_provider_response: $json } }];"
+ "jsCode": "const responses = $input.all();\nconst sources = $('Preparar envío Google Chat').all();\n\nreturn responses.map((item, index) => {\n const source = sources[index]?.json ?? {};\n const response = item.json ?? {};\n const sent = Boolean(response.name) && !response.error;\n\n return {\n json: {\n ...source,\n google_chat_status: sent ? 'sent' : 'failed',\n google_chat_provider_response: response,\n },\n pairedItem: { item: index },\n };\n});"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
- 2288,
- 1632
+ 1968,
+ 2096
],
- "id": "6398165b-9e0a-483f-9db6-71f0d85a69d0",
+ "id": "93094ae5-5e9b-4e42-9a9b-5ed9213943e3",
"name": "Evaluar envío Google Chat"
},
{
@@ -1005,15 +1005,15 @@
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
- 2544,
- 1744
+ 2224,
+ 2208
],
- "id": "29a93cc5-c157-4199-81c1-1fed7664edc6",
+ "id": "db27cf44-56e0-4544-90dd-d81bc0d4bd7d",
"name": "Supabase - Registrar Google Chat"
},
{
"parameters": {
- "content": "## RECORDATORIOS DE IMPUESTOS POR GMAIL Y GOOGLE CHAT\n\nEjecuta diariamente el proceso de recordatorios fiscales y notifica a los contactos correspondientes por correo electrónico y mensaje directo de Google Chat.\n\n- Puede iniciarse automáticamente a las 8:00 a. m., manualmente o desde el webhook de la aplicación.\n- Valida y normaliza el origen de la ejecución antes de continuar.\n- Consulta en Supabase las obligaciones que requieren recordatorio y sus destinatarios.\n- Construye mensajes personalizados con el formato corporativo de GLM.\n- Envía los recordatorios por Gmail y registra en Supabase el resultado de cada correo.\n- Abre o identifica la conversación directa del destinatario en Google Chat.\n- Envía el recordatorio por Google Chat cuando el DM está disponible.\n- Evalúa cada intento y registra tanto los envíos exitosos como los errores para mantener trazabilidad.",
+ "content": "## RECORDATORIOS DE IMPUESTOS POR GMAIL Y GOOGLE CHAT\n\nEjecuta diariamente el proceso de recordatorios fiscales y notifica a los contactos correspondientes por correo electrónico y mensaje directo de Google Chat.\n\n- Puede iniciarse automáticamente a las 8:00 a. m., manualmente o desde el webhook de la aplicación.\n- Consulta en Supabase las obligaciones que requieren recordatorio y sus destinatarios.\n- Construye mensajes personalizados con el formato corporativo de GLM.\n- Envía los recordatorios por Gmail al correo de cada contacto y registra el resultado.\n- Abre o reutiliza el DM del destinatario en Google Chat mediante `spaces:setup`.\n- Conserva todos los items de Google Chat de principio a fin; no colapsa múltiples destinatarios en uno solo.\n- Envía texto con `spaces.messages.create` usando un body válido `{ text: ... }`.\n- Omite el correo del propio usuario autenticado de Google Chat, porque Google agrega automáticamente al calling user y no permite especificarlo como membership.\n- Evalúa cada intento individualmente y registra éxitos o errores en Supabase.",
"height": 1184,
"width": 2880,
"color": "#204750"
@@ -1021,10 +1021,10 @@
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
- -144,
- 881.5847255369928
+ -464,
+ 1360
],
- "id": "8c9fe360-936b-4e86-bd17-5a396dd09419",
+ "id": "3ee2b7ce-eff0-4d62-b80d-f4df454e91df",
"name": "Sticky Note"
}
],
@@ -1217,15 +1217,15 @@
}
},
"authors": "Isaac Aracena",
- "name": "Version ab159702",
+ "name": "Version 0ebbe45e",
"description": "",
"autosaved": true,
"workflowPublishHistory": [
{
- "createdAt": "2026-08-03T14:27:08.495Z",
- "id": 3860,
+ "createdAt": "2026-08-12T17:42:42.706Z",
+ "id": 4607,
"workflowId": "cFu3Xx23KQBKfr0M",
- "versionId": "ab159702-cf57-4e47-8de5-95da61a56b9b",
+ "versionId": "0ebbe45e-f485-4abc-8de3-5f5b05857edf",
"event": "activated",
"userId": "0a88c0b1-928e-4412-896e-c5d1c99b2029"
}