{
  "name": "Chanchito_PROD",
  "nodes": [
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "models/gemini-2.5-flash",
          "mode": "list",
          "cachedResultName": "models/gemini-2.5-flash"
        },
        "messages": {
          "values": [
            {
              "content": "=Act\u00faa como un asistente financiero experto en el contexto econ\u00f3mico argentino.\nTu objetivo es extraer datos estructurados de un mensaje natural y categorizarlos con precisi\u00f3n usando los IDs provistos.\n\nINPUTS:\n1. Mensaje del Usuario: \n\"\"\"\n{{ $('Parseo de mensaje para Gemini').first().json.text }}\n\"\"\"\n\n2. Lista de Categor\u00edas (Referencia):\n{{ $('Formatear Categor\u00edas').first().json.categories_prompt }}\n\n3. DICCIONARIO DE IDs (Mapa Nombre -> UUID):\n{{ JSON.stringify($('Formatear Categor\u00edas').first().json.categories_map) }}\n\nINSTRUCCIONES:\nAnaliza el mensaje y devuelve EXCLUSIVAMENTE un objeto JSON.\nDetecta la INTENCI\u00d3N y elige la estructura correcta.\nIMPORTANTE: Cuando elijas una categor\u00eda, busca su nombre exacto en el \"DICCIONARIO DE IDs\" y extrae el UUID correspondiente para el campo \"category_id\".\n\n--- CASO A: ES UNA TRANSACCI\u00d3N (Gasto, Compra, Cuotas, Ingreso) ---\nSi el usuario informa un movimiento de dinero.\nDevuelve esta estructura:\n{\n  \"intencion\": \"transaccion\",\n  \"compra\": \"Breve descripci\u00f3n del \u00edtem (ej: Zapatillas Nike)\",\n  \"categoria\": \"El nombre exacto de la categor\u00eda elegida (ej: 'Comida')\",\n\"category_id\": \"El UUID exacto sacado del DICCIONARIO DE IDs correspondiente a la categor\u00eda elegida.\",\n  \"valor\": 0, (N\u00famero positivo puro. Si es gasto 12000, pon 12000. Si es ingreso, tambi\u00e9n positivo).\n  \"tipo\": \"Uno de: 'expense' (gasto) o 'income' (ingreso/sueldo/cobro)\",\n  \"medio_pago\": \"Nombre del medio si se menciona (ej: 'Visa', 'Master', 'Mercado Pago', 'Efectivo'). Si no dice nada, devuelve null.\",\n  \"es_gasto_real\": true, (Poner false si es publicidad, spam, aviso de seguridad, 'novedades', o notificaciones que NO implican movimiento de dinero),\n  \"cuotas\": {\n    \"es_cuota\": boolean, (true si el usuario menciona expl\u00edcitamente cuotas, pagos o plan de pagos),\n    \"cantidad\": number, (1 si es pago \u00fanico. Si son cuotas, la cantidad, ej: 6),\n    \"monto_total\": number (El precio TOTAL de la compra. IMPORTANTE: Si el usuario dice '6 cuotas de 10.000', el total es 60000. Si dice 'TV 100.000 en 6 pagos', el total es 100000)\n  },\n  \"fecha\": \"YYYY-MM-DD\" (Calculada en relaci\u00f3n a hoy: {{ $now }}. Por ejemplo, si dice 'hoy' es {{ $now }}, si es ayer es el dia previo a {{ $now }}. Si no dice nada, se asume que es {{ $now }})\n}\n\n--- CASO B: CONFIGURACI\u00d3N DE TARJETA (El usuario informa fechas) ---\nSi el usuario dice algo como \"La Visa cierra el 24/12 y vence el 05/01\" o \"Master cierra el 20\".\nDevuelve esta estructura:\n{\n  \"intencion\": \"configuracion_tarjeta\",\n  \"tarjeta_match\": \"Parte del nombre de la tarjeta para buscarla (ej: 'Visa')\",\n  \"fecha_cierre\": \"YYYY-MM-DD\" (Si solo dice el d\u00eda '24', asume el cierre pr\u00f3ximo l\u00f3gico seg\u00fan la fecha de hoy: {{ $now }}),\n  \"fecha_vencimiento\": \"YYYY-MM-DD\" (Calcula la fecha l\u00f3gica de vencimiento posterior al cierre)\n}\n\n--- CASO C: SUSCRIPCI\u00d3N O GASTO FIJO (Recurring Plan) ---\nSi el usuario menciona un gasto que se repite (ej: \"Suscripci\u00f3n Netflix\", \"Pago el gimnasio todos los meses\", \"D\u00e9bito autom\u00e1tico de seguro\", \"Alquiler\").\nDevuelve esta estructura:\n{\n  \"intencion\": \"suscripcion\",\n  \"descripcion\": \"Nombre del servicio (ej: Spotify)\",\n  \"valor\": 0, (Monto mensual),\n  \"moneda\": \"ARS\" (o USD si especifica),\n  \"categoria\": \"Nombre de la categor\u00eda elegida\",\n  \"category_id\": \"El UUID exacto sacado del DICCIONARIO DE IDs\",\n  \"frecuencia\": \"monthly\", (Por defecto 'monthly', salvo que diga 'anual' o 'semanal'),\n  \"medio_pago\": \"Nombre del medio de pago si se menciona (ej: 'Visa'). Si no, null.\"\n}\n\nREGLAS CR\u00cdTICAS DE PROCESAMIENTO:\n1. Si detectas palabras como \"Cobr\u00e9\", \"Sueldo\", \"Me transfirieron\", \"Ingreso\", define \"tipo\": \"income\" y \"categoria\": \"Ingresos\".\n2. Si \"es_gasto_real\" es false, el resto de campos pueden ser null.\n3. Prioriza tu lista de categor\u00edas personalizada. Si no encaja, usa \"Otros\".\n4. Si el usuario dice palabras como 'mensual', 'suscripci\u00f3n', 'd\u00e9bito autom\u00e1tico', 'plan', prioriza la intenci\u00f3n 'suscripcion' sobre 'transaccion'.\n5. El campo \"category_id\" ES OBLIGATORIO para transacciones y suscripciones. Nunca lo dejes null si encontraste una categor\u00eda."
            }
          ]
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "typeVersion": 1,
      "position": [
        -4368,
        1712
      ],
      "id": "1a06738d-3b5e-4fe2-9252-de38ee7651fc",
      "name": "Procesar mensaje y categorizar",
      "retryOnFail": true,
      "waitBetweenTries": 5000,
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "ac739398-3003-494d-aa2f-9cdf926f5a53",
              "leftValue": "={{ $json.valor }}",
              "rightValue": "null",
              "operator": {
                "type": "number",
                "operation": "exists",
                "singleValue": true
              }
            },
            {
              "id": "0383615c-cc1d-463a-9d63-bad0e70f321c",
              "leftValue": "={{ $json.compra }}",
              "rightValue": "null",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              }
            },
            {
              "id": "5a7d4df5-a7d4-4d6d-a322-802121dbfc34",
              "leftValue": "={{ $json.categoria }}",
              "rightValue": "null",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              }
            },
            {
              "id": "8720a94f-e18e-4ea4-862b-799adca3459c",
              "leftValue": "={{ $json.fecha }}",
              "rightValue": "null",
              "operator": {
                "type": "dateTime",
                "operation": "exists",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -3664,
        1520
      ],
      "id": "4d4648cf-ebae-47ab-b1c8-165601f7fa8d",
      "name": "Chequeo de campos v\u00e1lidos"
    },
    {
      "parameters": {
        "jsCode": "// 1. Obtener texto de Gemini\nconst rawText = $input.first().json.text\nconst cleaned = rawText.replace(/```json|```/g, '').trim();\n\nlet result;\n\n// 2. Intentar parsear el JSON\ntry {\n  result = JSON.parse(cleaned);\n} catch (error) {\n  result = {\n    compra: null,\n    categoria: null,\n    valor: null,\n    fecha: null,\n    es_gasto_real: false // Asumimos que no es gasto si fall\u00f3 catastr\u00f3ficamente\n  };\n}\n\n// 3. RECUPERAR EL ORIGEN (Source)\n// Esto es vital: buscamos en el nodo unificador si vino de 'android' o 'telegram'\ntry {\n  result = JSON.parse(cleaned);\n  \n  // MANTENER INTENCI\u00d3N Y MEDIO DE PAGO\n  // Si Gemini no devolvi\u00f3 medio_pago, lo forzamos a null para evitar undefined\n  if (!result.medio_pago) result.medio_pago = null;\n  if (!result.intencion) result.intencion = 'transaccion'; // Default por seguridad\n\n} catch (error) {\n    // Si falla, por defecto asumimos telegram para que te avise el error\n    result.source = 'telegram';\n}\n\nreturn [{\n  json: result\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -4032,
        1712
      ],
      "id": "b37e8bb9-f115-48de-9c26-48ab2c2c1f0d",
      "name": "Parseo post Gemini"
    },
    {
      "parameters": {
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "installment_plans",
          "mode": "list",
          "cachedResultName": "installment_plans"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "total_amount": "={{ $('Seteo de campos').first\n().json['Monto total'] }}",
            "installments_count": "={{ $('Seteo de campos').first\n().json['Cantidad de cuotas'] }}",
            "user_id": "={{ $('Identificar usuario').first\n().json.id }}",
            "description": "={{ $json.Compra }}",
            "purchase_date": "={{ $json.FechaRealPago }}",
            "payment_method_id": "={{ $('Calculadora de vencimiento').first\n().json.payment_method_id }}",
            "category_id": "={{ $('Seteo de campos').item.json['Id Categoria'] }}"
          },
          "matchingColumns": [
            "id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": false,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "description",
              "displayName": "description",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "total_amount",
              "displayName": "total_amount",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true
            },
            {
              "id": "installments_count",
              "displayName": "installments_count",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true
            },
            {
              "id": "purchase_date",
              "displayName": "purchase_date",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "payment_method_id",
              "displayName": "payment_method_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "category_id",
              "displayName": "category_id",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -1968,
        1168
      ],
      "id": "e5faf890-28d2-4198-9663-d1f1b33d2396",
      "name": "Crear Plan (Cuotas)",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const plan = $input.first().json; // Datos del plan reci\u00e9n creado (necesitamos el ID)\nconst gemini = $('Seteo de campos').first().json; // Datos originales\nconst userId = $('Identificar usuario').first().json.id;\nconst cantidad = gemini['Cantidad de cuotas']\nconst montoCuota = gemini['Monto total'] / cantidad;\nconst fechaInicioPagos = new Date($('Calculadora de vencimiento').first().json.FechaRealPago)\n\nconst transacciones = [];\n\nfor (let i = 0; i < cantidad; i++) {\n  let fechaPago = new Date(fechaInicioPagos);\n  fechaPago.setMonth(fechaPago.getMonth() + i); // Sumamos meses desde el primer pago\n  \n  transacciones.push({\n    user_id: userId,\n    description: `${gemini['Compra']} (Cuota ${i + 1}/${cantidad})`,\n    category: gemini.categoria,\n    amount: Math.abs(montoCuota), // Siempre negativo\n    date: fechaPago.toISOString(), // Formato ISO para Postgres\n    type: 'expense',\n    payment_method: 'Credit Card', // Asumimos tarjeta si es cuota\n    installment_plan_id: plan.id // Vinculamos al padre\n  });\n}\n\nreturn transacciones;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -1776,
        1168
      ],
      "id": "f95ebf87-39d5-42c3-bd75-bb6bf07bde3a",
      "name": "Calculadora de fechas"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "fb7f0829-d48c-4299-89be-b41e1309cd40",
              "leftValue": "={{ $('Chequeo de campos v\u00e1lidos').item.json.tipo }}",
              "rightValue": "=expense",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            },
            {
              "id": "1b63324a-7282-49a1-b86e-ff01a9755fe4",
              "leftValue": "={{ $('Chequeo de campos v\u00e1lidos').item.json.cuotas.es_cuota }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -2224,
        1344
      ],
      "id": "4e596150-4288-4f96-8474-0f535d7aa94e",
      "name": "Es gasto en cuotas?"
    },
    {
      "parameters": {
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "transactions",
          "mode": "list",
          "cachedResultName": "transactions"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "user_id": "={{ $('Identificar usuario').first().json.id }}",
            "amount": "={{ $('Seteo de campos').item.json.Valor }}",
            "description": "={{ $('Seteo de campos').item.json.Compra }}",
            "date": "={{ $('Calculadora de vencimiento').first().json.FechaRealPago }}",
            "type": "={{ $('Parseo post Gemini').first().json.tipo }}",
            "payment_method_id": "={{ $('Seteo de campos').first().json['Id Medio de pago'] }}",
            "category_id": "={{ $('Seteo de campos').item.json['Id Categoria'] }}"
          },
          "matchingColumns": [
            "id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": false,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "description",
              "displayName": "description",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "amount",
              "displayName": "amount",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true
            },
            {
              "id": "date",
              "displayName": "date",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true
            },
            {
              "id": "type",
              "displayName": "type",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "installment_plan_id",
              "displayName": "installment_plan_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "recurring_plan_id",
              "displayName": "recurring_plan_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "payment_method_id",
              "displayName": "payment_method_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "category_id",
              "displayName": "category_id",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -1904,
        1568
      ],
      "id": "a18ba05c-9d24-4bc7-ad3d-2fe1dd842310",
      "name": "Guardar Transaccion",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Obtener el input inmediato (para ver si es Webhook)\nconst item = $input.first();\n\n// --- CASO 1: Viene del WEBHOOK (Android/MacroDroid) ---\n// Verificamos si la entrada inmediata tiene \"body\" (t\u00edpico de Webhook)\nif (item.json.body) {\n  return {\n    text: item.json.body.mensaje, // Asegurate que en MacroDroid mandaste la variable \"mensaje\"\n    source: 'android',\n    chat_id: 1995566176 // Tu ID fijo que pusiste\n  };\n}\n\n// --- CASO 2: Viene de TELEGRAM ---\n// Si no es webhook, asumimos que es Telegram.\n// PERO, como venimos de un nodo de \"Respuesta\", tenemos que ignorar el input inmediato\n// y buscar los datos \"aguas arriba\" en el nodo Trigger original.\n\ntry {\n  // Accedemos directamente a los datos del nodo \"Trigger mensaje\"\n  // Usamos try/catch por si acaso el nodo no existe o no corri\u00f3\n  \n  \n  if ($('Telegram Trigger').first().json.message) {\n    return {\n      text: $('Telegram Trigger').first().json.message.text,\n      source: 'telegram',\n      chat_id: ($('Telegram Trigger').first().json.message.from.id).toString()\n    };\n  }\n} catch (error) {\n  // Si da error aqu\u00ed, es porque el nodo Trigger no se ejecut\u00f3 \n  // (probablemente estamos en una prueba aislada o algo raro)\n  console.log(\"No se encontraron datos del Trigger de Telegram\");\n}\n\n// Si nada funcion\u00f3:\nreturn { text: '', error: 'No se detect\u00f3 origen v\u00e1lido' };"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -6112,
        1456
      ],
      "id": "8f799e63-2a2d-40e2-9ba7-d12b9ca72ebd",
      "name": "Parseo de mensaje para Gemini"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.intencion }}",
                    "rightValue": "transaccion",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "id": "f5414ca4-f772-49b9-8c14-7ea21628c76c"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Es transacci\u00f3n"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "32be032e-b2f5-4c00-b7da-1b4d89770966",
                    "leftValue": "={{ $json.intencion }}",
                    "rightValue": "configuracion_tarjeta",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Es configuraci\u00f3n de tarjeta"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "a41b3cde-3664-428b-b6d1-e77202076a1c",
                    "leftValue": "={{ $json.intencion }}",
                    "rightValue": "suscripcion",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Es suscripci\u00f3n"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.3,
      "position": [
        -3856,
        1696
      ],
      "id": "7d9ff517-6206-4e2c-a7f1-213181a2760b",
      "name": "Es transacci\u00f3n o configuraci\u00f3n de tarjeta"
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT *\nFROM public.payment_methods\nWHERE user_id = {{ $('Identificar usuario').first\n().json.id }}\nORDER BY SIMILARITY(name, '{{ $('Parseo post Gemini').item.json.tarjeta_match || $('Parseo post Gemini').item.json.medio_pago }}') DESC -- Ordenar por el que m\u00e1s se parezca\nLIMIT 1;",
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -3424,
        1840
      ],
      "id": "8e7e8cb1-9135-496a-bc7e-07762c0b9be7",
      "name": "Identificar medio de pago",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "update",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "payment_methods",
          "mode": "list",
          "cachedResultName": "payment_methods"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "default_closing_day": "={{ new Date($('Parseo post Gemini').first\n().json.fecha_cierre).getUTCDate() }}",
            "default_payment_day": "={{ new Date($('Parseo post Gemini').first\n().json.fecha_vencimiento).getUTCDate() }}",
            "id": "={{ $json.id }}",
            "user_id": "={{ $json.user_id }}",
            "name": "={{ $json.name }}",
            "type": "={{ $json.type }}",
            "created_at": "={{ $json.created_at }}"
          },
          "matchingColumns": [
            "id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": false,
              "defaultMatch": true,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false,
              "removed": false
            },
            {
              "id": "name",
              "displayName": "name",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false,
              "removed": false
            },
            {
              "id": "type",
              "displayName": "type",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false,
              "removed": false
            },
            {
              "id": "default_closing_day",
              "displayName": "default_closing_day",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "default_payment_day",
              "displayName": "default_payment_day",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": false,
              "removed": false
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -3248,
        1840
      ],
      "id": "2e63b169-0a32-40ce-af9b-cb15d112d532",
      "name": "Actualizar medio de pago",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{ $('Parseo de mensaje para Gemini').first\n().json.chat_id }}",
        "text": "=Error al procesar el mensaje. Asegurate de que todos los campos esten completos (nombre de gasto, precio y fecha). Por ejemplo: \"Gast\u00e9 $10000 pesos en ropa\".\nSi este gasto es de una notificaci\u00f3n, escrib\u00ed el gasto manual a continuaci\u00f3n.",
        "additionalFields": {}
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        -3424,
        1648
      ],
      "id": "8efb59a9-18fd-4220-b609-6cdc30c21888",
      "name": "Enviar mensaje de error",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "transactions",
          "mode": "list",
          "cachedResultName": "transactions"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "user_id": "={{ $json.user_id }}",
            "description": "={{ $json.description }}",
            "amount": "={{ $json.amount }}",
            "date": "={{ $json.date }}",
            "type": "={{ $json.type }}",
            "installment_plan_id": "={{ $json.installment_plan_id }}",
            "payment_method_id": "={{ $('Calculadora de vencimiento').first\n().json.payment_method_id }}",
            "category_id": "={{ $('Seteo de campos').item.json['Id Categoria'] }}"
          },
          "matchingColumns": [
            "id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": false,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "description",
              "displayName": "description",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "amount",
              "displayName": "amount",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true
            },
            {
              "id": "date",
              "displayName": "date",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true
            },
            {
              "id": "type",
              "displayName": "type",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "installment_plan_id",
              "displayName": "installment_plan_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "recurring_plan_id",
              "displayName": "recurring_plan_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "payment_method_id",
              "displayName": "payment_method_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "category_id",
              "displayName": "category_id",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -1600,
        1168
      ],
      "id": "9c033ff7-4293-4716-baf4-a45789da8b95",
      "name": "Guardar cuotas",
      "alwaysOutputData": true,
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "\n// 2. INICIALIZAR FECHAS\nconst fechaCompra = new Date($input.first().json.Fecha);\nlet fechaPagoReal = new Date(fechaCompra);\n\n// 3. L\u00d3GICA DE CR\u00c9DITO (Cash Flow Real)\nif ($input.first().json['Tipo de Medio de pago'] === 'credit') {\n  const diaCompra = fechaCompra.getDate();\n  \n  // Paso A: Determinar si salta al pr\u00f3ximo resumen\n  if (diaCompra > $input.first().json['D\u00eda de cierre']) {\n    fechaPagoReal.setMonth(fechaPagoReal.getMonth() + 1);\n  }\n  \n  // Paso B: Determinar si el pago cae al mes siguiente del cierre\n  // (Si vence el 5 y cierra el 25, paga al mes siguiente)\n  if ($input.first().json['D\u00eda de vencimiento'] < $input.first().json['D\u00eda de cierre']) {\n    fechaPagoReal.setMonth(fechaPagoReal.getMonth() + 1);\n  }\n  \n  // Paso C: Fijar el d\u00eda exacto de PAGO\n  fechaPagoReal.setDate($input.first().json['D\u00eda de vencimiento']);\n}\n\n// 4. RETORNAR\nreturn {\n  Compra: $input.first().json.Compra,\n  Categor\u00eda: $input.first().json['Categor\u00eda'],\n  Valor:$input.first().json.Valor,\n  payment_method_id: $input.first().json['Id Medio de pago'],\n  FechaRealPago: fechaPagoReal.toISOString().split('T')[0]\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -2464,
        1344
      ],
      "id": "fda00648-da19-4d18-a634-9bca4294624c",
      "name": "Calculadora de vencimiento"
    },
    {
      "parameters": {
        "chatId": "={{ $('Parseo de mensaje para Gemini').first\n().json.chat_id }}",
        "text": "=\u2705 Gasto en cuotas guardado:  \n- {{ $('Crear Plan (Cuotas)').item.json.description }}\n- {{ $('Seteo de campos').item.json['Categor\u00eda'] }}\n- \ud83d\udcb5${{ $('Chequeo de campos v\u00e1lidos').item.json.cuotas.es_cuota ? $('Seteo de campos').item.json.Valor + \" en \" + $('Seteo de campos').item.json['Cantidad de cuotas'] + \" cuotas\" : $('Seteo de campos').item.json.Valor }}\n- \ud83d\udcb3{{ $('Seteo de campos').item.json['Medio de pago'] }}\n- \ud83d\udd50{{ $('Seteo de campos').item.json.Fecha }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        -1424,
        1168
      ],
      "id": "5967a4fd-0ccc-455e-8e1e-5fc1cfc622d9",
      "name": "Enviar mensaje de confirmaci\u00f3n de cuotas",
      "executeOnce": true,
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "7fcef0ec-9a8f-4e0f-824a-15f680683aa9",
              "leftValue": "={{ $json.type }}",
              "rightValue": "income",
              "operator": {
                "type": "string",
                "operation": "equals",
                "name": "filter.operator.equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -1712,
        1568
      ],
      "id": "daea3212-9049-486a-993d-2abb5e61a5b9",
      "name": "Es ingreso?"
    },
    {
      "parameters": {
        "chatId": "={{ $('Parseo de mensaje para Gemini').first\n().json.chat_id }}",
        "text": "=\u2705 Gasto guardado:  \n- {{ $json.description }}\n- {{ $('Seteo de campos').item.json['Categor\u00eda'] }}\n- \ud83d\udcb5${{ $('Chequeo de campos v\u00e1lidos').item.json.cuotas.es_cuota ? $('Seteo de campos').item.json['Monto total'] + \" en \" + $('Seteo de campos').item.json['Cantidad de cuotas'] + \" cuotas\" : $('Seteo de campos').item.json.Valor}}\n- \ud83d\udcb3{{ $('Seteo de campos').item.json['Medio de pago'] }}\n- \ud83d\udd50 {{ $('Calculadora de vencimiento').item.json.FechaRealPago }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        -1488,
        1680
      ],
      "id": "23c93460-7483-4301-9f74-780caeb594b9",
      "name": "Enviar mensaje de confirmaci\u00f3n de gasto",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{ $('Parseo de mensaje para Gemini').first\n().json.chat_id }}",
        "text": "=\u2705 Ingreso guardado:  \n- {{ $json.description }}\n- {{ $('Seteo de campos').item.json['Categor\u00eda'] }}\n- \ud83d\udcb5${{ $json.amount }}\n- \ud83d\udcb3{{ $('Seteo de campos').item.json['Medio de pago'] }}\n- \ud83d\udd50{{ $('Seteo de campos').item.json.Fecha }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        -1488,
        1504
      ],
      "id": "bf5bf8cf-bbfd-4abf-87c9-04358d4f64bf",
      "name": "Enviar mensaje de confirmaci\u00f3n de ingreso",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT \n  pm.name as nombre_tarjeta,\n  u.telegram_chat_id,\n  u.first_name\nFROM public.payment_methods pm\nJOIN public.users u ON pm.user_id = u.id\nWHERE \n  pm.type = 'credit'\n  -- Calculamos si el d\u00eda de cierre fue \"Ayer\" respetando la zona horaria argentina\n  AND pm.default_closing_day = EXTRACT(DAY FROM (NOW() AT TIME ZONE 'America/Argentina/Buenos_Aires' - INTERVAL '1 day'));",
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -7280,
        576
      ],
      "id": "7eaf5523-72ef-4907-967e-2322f51034d0",
      "name": "Chequeo de cierres diario",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 10
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        -7488,
        576
      ],
      "id": "6c4f7b43-8e42-4dc1-9a9f-028206399a52",
      "name": "Trigger de chequeo de cierres diario"
    },
    {
      "parameters": {
        "operation": "sendAndWait",
        "chatId": "={{ $json.telegram_chat_id }}",
        "message": "=\u26a0\ufe0f *Actualizaci\u00f3n de Ciclo*\n\nHola {{ $json.first_name }}, ayer cerr\u00f3 tu tarjeta: *{{ $json.nombre_tarjeta }}*.\n\nPor favor, revisa el resumen y decime las nuevas fechas para calibrar el sistema.\n\nRespondeme con este formato exacto:\n\"{{ $json.nombre_tarjeta }} cierra el DD/MM y vence el DD/MM\"",
        "options": {
          "appendAttribution": false
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        -7088,
        576
      ],
      "id": "ca9bdeeb-4259-406d-820b-0a01520e682c",
      "name": "Send message and wait for response",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "select",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "users",
          "mode": "list",
          "cachedResultName": "users"
        },
        "limit": 1,
        "where": {
          "values": [
            {
              "column": "telegram_chat_id",
              "value": "={{ $json.chat_id }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -5904,
        1456
      ],
      "id": "562b225d-a03c-411c-9847-07b1155162a7",
      "name": "Identificar usuario",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE public.transactions\nSET date = make_date(\n    CAST(EXTRACT(YEAR FROM date) AS INTEGER),\n    CAST(EXTRACT(MONTH FROM date) AS INTEGER),\n    {{ new Date($('Parseo post Gemini').first\n().json.fecha_vencimiento).getUTCDate() }}\n)\nWHERE \n  payment_method_id = {{ $('Identificar medio de pago').first\n().json.id }}\n  AND type = 'expense'\n  -- L\u00d3GICA DE PROTECCI\u00d3N:\n  -- Solo actualiza si la fecha es mayor a HOY + 20 D\u00cdAS.\n  -- Esto salta cualquier vencimiento inminente (que ya tiene resumen cerrado)\n  -- y va directo a modificar Enero, Febrero, etc.\n  AND date > (CURRENT_DATE + interval '20 days');",
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -3040,
        1840
      ],
      "id": "e2413bcf-f9fb-4b80-b650-b60224d58a79",
      "name": "Actualizar futuros",
      "alwaysOutputData": true,
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{ $('Parseo de mensaje para Gemini').first\n().json.chat_id }}",
        "text": "=\u2705 Medio de pago modificado:\n- \ud83d\udcb3 {{ $('Identificar medio de pago').item.json.name }}\n- \ud83d\udcc5 Nuevo cierre: {{ $('Parseo post Gemini').item.json.fecha_cierre }}\n- \ud83d\udcc5 Nuevo vencimiento: {{ $('Parseo post Gemini').item.json.fecha_vencimiento }}",
        "additionalFields": {}
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        -2848,
        1840
      ],
      "id": "7881144e-d864-456d-bce7-dbb0dcf15ee2",
      "name": "Enviar mensaje de confirmaci\u00f3n de configuraci\u00f3n",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 30
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        -5712,
        -144
      ],
      "id": "e48a3963-a876-4209-9916-359de7aa58bf",
      "name": "Schedule Trigger"
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "-- Traemos solo los tickers \u00fanicos para no buscar AAPL 2 veces si compraste en dos fechas\nSELECT DISTINCT ticker, type, data_source_url\nFROM public.investments\nWHERE type IN ('stock', 'cedear', 'bond', 'on', 'crypto');",
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -5408,
        -144
      ],
      "id": "9de1d74c-0c47-440c-af26-2d100ce95b7f",
      "name": "Leer Cartera",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {
          "reset": false
        }
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        -5200,
        -144
      ],
      "id": "7665bffe-156d-4764-a398-c70bec78d884",
      "name": "Split Batches"
    },
    {
      "parameters": {
        "url": "=https://query1.finance.yahoo.com/v8/finance/chart/{{ $json.ticker }}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        -4784,
        -208
      ],
      "id": "6daa26c9-531d-4329-90a8-e33813e4bb28",
      "name": "Obtener valores",
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "url": "=https://api.coingecko.com/api/v3/simple/price?ids={{ $json.ticker }}&vs_currencies=usd",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        -4784,
        -64
      ],
      "id": "1705eb74-fcbd-492a-ba2c-466259515527",
      "name": "Obtener valores cripto",
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "const data = $input.first().json;\n\n// Navegamos la estructura loca de Yahoo\nconst meta = data.chart.result[0].meta;\nconst precio = meta.regularMarketPrice; // Precio actual de mercado\nconst moneda = meta.currency; // ARS o USD\n\nreturn {\n  ticker: meta.symbol,\n  last_price: precio,\n  currency: moneda\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -4576,
        -208
      ],
      "id": "142325ac-1f4d-404a-9c70-eb6ed3019af3",
      "name": "Limpiar valores"
    },
    {
      "parameters": {
        "jsCode": "const idCripto = $('Split Batches').first().json.ticker // \"bitcoin\"\nconst data = $input.first().json;\nconst precio = data[idCripto].usd;\n\nreturn {\n  ticker: idCripto,\n  last_price: precio,\n  currency: 'ARS'\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -4576,
        -64
      ],
      "id": "4d2caed3-be6f-4deb-9747-ce2699438f98",
      "name": "Limpiar valores cripto"
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO public.market_prices (ticker, last_price, last_update)\nVALUES ('{{ $json.ticker }}', {{ $json.last_price }}, NOW()) -- Comillas aqu\u00ed\nON CONFLICT (ticker) \nDO UPDATE SET \n  last_price = EXCLUDED.last_price, \n  last_update = NOW();",
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -4192,
        -64
      ],
      "id": "442268bc-9442-4a6d-ad23-4fafee02be05",
      "name": "Execute a SQL query",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.type }}",
                    "rightValue": "={{ \"stock\" }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "id": "b9f548ff-3e20-403d-a0ea-16e39e8f8328"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "cedear OR stock OR bond OR on"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "891a3190-7a55-4797-9ca8-0cfbde0dd472",
                    "leftValue": "={{ $json.type }}",
                    "rightValue": "crypto",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "crypto"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "2448734c-8233-4dba-aff4-e8c64961a43b",
                    "leftValue": "={{ $json.type }}",
                    "rightValue": "={{ \"on\" || \"bond\" || \"cedear\" }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "on"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.3,
      "position": [
        -4992,
        -80
      ],
      "id": "6a9cf6ba-be92-4849-93e1-b1808ba2642c",
      "name": "El Clasificador"
    },
    {
      "parameters": {
        "url": "={{ $json.data_source_url }}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        -4784,
        160
      ],
      "id": "ccba4f2a-c9d3-4583-97c1-dbe27149b716",
      "name": "HTTP Request"
    },
    {
      "parameters": {
        "operation": "extractHtmlContent",
        "extractionValues": {
          "values": [
            {
              "key": "precio_texto",
              "cssSelector": "span[data-field=\"UltimoPrecio\"]"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.html",
      "typeVersion": 1.2,
      "position": [
        -4624,
        160
      ],
      "id": "a996a3ef-61d3-410b-a56d-bd75d0d4fc80",
      "name": "HTML"
    },
    {
      "parameters": {
        "jsCode": "const raw = $input.first().json.precio_texto; // Ej: \"1.050,50\"\n\nif (!raw) {\n  throw new Error(\"No se pudo extraer el precio. Revisa el selector CSS.\");\n}\n\n// 1. Limpieza de texto (String)\nconst textoLimpio = raw\n  .replace(/[^0-9,]/g, '') // Borra todo lo que NO sea n\u00famero o coma (borra el punto de mil y el $)\n  .replace(',', '.');      // Cambia la coma decimal por punto (formato JS)\n\n// 2. Conversi\u00f3n a N\u00famero (Float)\n// Usamos 'let' porque vamos a modificar esta variable si entra en la regla\nlet precioFinal = parseFloat(textoLimpio);\n\n// 3. Regla Heur\u00edstica (ONs/Bonos)\n// Recuperamos el tipo del nodo anterior\nconst tipoActivo = $('El Clasificador').first().json.type;\n\nif (tipoActivo === 'on' || tipoActivo === 'bond') {\n  // Si vale m\u00e1s de 20 (ej: 109.90), asumimos que es precio \"cada 100\"\n  if (precioFinal > 20) {\n    precioFinal = precioFinal / 100;\n  }\n}\n\nreturn {\n  ticker: $('El Clasificador').first().json.ticker, // Mantenemos el ticker original\n  last_price: precioFinal\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -4464,
        160
      ],
      "id": "657f59fe-8b69-4ae8-a9d6-640a6db76ca2",
      "name": "Limpiar Scrap"
    },
    {
      "parameters": {
        "content": "## Actualizaci\u00f3n mensual de tarjetas",
        "height": 240,
        "width": 720,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -7584,
        512
      ],
      "id": "8ea1f22e-1f31-4117-9885-1cbcc5fbecea",
      "name": "Sticky Note5"
    },
    {
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "type": "n8n-nodes-base.telegramTrigger",
      "typeVersion": 1.2,
      "position": [
        -7536,
        1280
      ],
      "id": "8007133a-74c1-483e-9e08-b69afac78989",
      "name": "Telegram Trigger",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const text = $('Telegram Trigger').first().json.message.text || \"\";\n\n// Separamos por espacios y limpiamos bordes\nconst parts = text.trim().split(/\\s+/);\n\n// VALIDACI\u00d3N ESTRICTA\n// 1. parts[0] debe ser \"/start\"\n// 2. parts[1] debe existir y tener longitud de UUID (36 chars)\n//    (Ej: 06e2ba95-3025-4aed-be17-410a88cc1eb4)\n\nif (parts[0] === '/start' && parts.length >= 2 && parts[1].length === 36) {\n  return {\n    isValid: true,\n    token: parts[1], // El UUID limpio\n    chatId: $('Telegram Trigger').first().json.message.chat.id,\n    firstName: $('Telegram Trigger').first().json.message.chat.first_name\n  };\n} else {\n  // Si dice \"gaste 4000 en un sanguche\", cae ac\u00e1\n  return { isValid: false }; \n}"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -7200,
        1280
      ],
      "id": "030e55bc-a407-45b9-be98-b1dbeeab8f29",
      "name": "Extraer el Token"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "f1217c3a-fa99-43bd-95cb-bea19049941d",
              "leftValue": "={{ $json.token }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -7008,
        1280
      ],
      "id": "2309b887-6e95-4282-b6c2-3abb12d8f196",
      "name": "Filtrar nuevos mensajes"
    },
    {
      "parameters": {
        "operation": "update",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "users",
          "mode": "list",
          "cachedResultName": "users"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "telegram_chat_id": "={{ $('Extraer el Token').first\n().json.chatId }}",
            "id": "={{ $('Extraer el Token').first\n().json.token }}"
          },
          "matchingColumns": [
            "id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": true,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "email",
              "displayName": "email",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "first_name",
              "displayName": "first_name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "last_name",
              "displayName": "last_name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "avatar_url",
              "displayName": "avatar_url",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "telegram_chat_id",
              "displayName": "telegram_chat_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true,
              "removed": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -6800,
        896
      ],
      "id": "bd225d46-6485-4495-ad92-f80f1be4aeac",
      "name": "Actualizar ID Telegram del usuario",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{ $json.telegram_chat_id }}",
        "text": "=\u00a1Cuenta vinculada! \ud83d\udc37 Decime crack, \u00bfc\u00f3mo quer\u00e9s que te llame? \ud83d\udc47",
        "replyMarkup": "forceReply",
        "forceReply": {
          "force_reply": true
        },
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        -6640,
        896
      ],
      "id": "f01496bd-364d-4c03-9d0c-7925a622500a",
      "name": "Confirmaci\u00f3n de vinculaci\u00f3n de telegram",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $('Telegram Trigger').item.json.message.reply_to_message.text }}",
              "operation": "contains",
              "value2": "c\u00f3mo quer\u00e9s que te llame"
            }
          ]
        }
      },
      "id": "dfdc2269-abc4-4e69-aba6-6a8f69c89dbb",
      "name": "Es Respuesta Nombre?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        -6816,
        1440
      ]
    },
    {
      "parameters": {
        "operation": "update",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "users",
          "mode": "list",
          "cachedResultName": "users"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "interaction_mode": "waiting_for_categories",
            "telegram_chat_id": "={{ $('Telegram Trigger').first\n().json.message.from.id }}",
            "first_name": "={{ $('Telegram Trigger').first\n().json.message.text }}"
          },
          "matchingColumns": [
            "telegram_chat_id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": true,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "email",
              "displayName": "email",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "first_name",
              "displayName": "first_name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "avatar_url",
              "displayName": "avatar_url",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "telegram_chat_id",
              "displayName": "telegram_chat_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "custom_categories_prompt",
              "displayName": "custom_categories_prompt",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "interaction_mode",
              "displayName": "interaction_mode",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -6640,
        1248
      ],
      "id": "67bfde36-c328-4985-8673-1c8347872778",
      "name": "Guardar nombre",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{ $json.telegram_chat_id }}",
        "text": "=\u00a1Un gusto, {{ $('Telegram Trigger').first\n().json.message.text }}! \ud83d\udc37\n\nTe voy a joder un cachiiito m\u00e1s para dejar todo listo.\n\nDecime qu\u00e9 categor\u00edas quer\u00e9s usar. Mencionalas y describilas como quieras.\n\nEjemplo: 'Comida para gastos de delivery, Super para las compras del mes, Vicios para el escabio y los puchitos...'. Incluso podes ser bien random tipo 'Casona para los gastos que tengan que ver con el hogar'. Mientras m\u00e1s descriptivo, mejor! \ud83d\ude01\n\n\ud83d\udc47 Te leo:",
        "replyMarkup": "forceReply",
        "forceReply": {
          "force_reply": true
        },
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        -6448,
        1248
      ],
      "id": "29a2003b-b6c0-4c54-8a9f-6cd52484e38e",
      "name": "Confirmaci\u00f3n de nombre y configuraci\u00f3n de categorias",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "models/gemini-2.5-flash",
          "mode": "list",
          "cachedResultName": "models/gemini-2.5-flash"
        },
        "messages": {
          "values": [
            {
              "content": "=Act\u00faa como un arquitecto de datos financieros.\nAnaliza la solicitud del usuario: \"{{ $('Parseo de mensaje para Gemini').first().json.text }}\"\n\nTu objetivo es generar categor\u00edas financieras precisas. Para cada categor\u00eda, necesito dos tipos de descripci\u00f3n:\n1. \"full\": Una descripci\u00f3n detallada y extensa para entrenar a una IA (incluye sin\u00f3nimos, ejemplos, contextos).\n2. \"short\": Un resumen tipo \"lista de palabras clave\" para lectura r\u00e1pida humana (M\u00e1ximo 10 palabras, separadas por comas).\n\nEjemplo de Output requerido (Formato JSON Array EXCLUSIVAMENTE):\n[\n  {\n    \"emoji\": \"\ud83c\udfac\",\n    \"name\": \"Entretenimiento\",\n    \"description_full\": \"Gastos relacionados con ocio, cine, teatro, videojuegos, servicios de streaming como Netflix o Spotify, y actividades recreativas.\",\n    \"description_short\": \"Cine, streaming, juegos, ocio, teatro, diversi\u00f3n.\"\n  },\n  {\n    \"emoji\": \"\ud83d\uded2\",\n    \"name\": \"Supermercado\",\n    \"description_full\": \"Compras de alimentos, bebidas, art\u00edculos de limpieza e higiene personal adquiridos en grandes superficies o tiendas de barrio.\",\n    \"description_short\": \"Comida, limpieza, higiene, bebidas, almac\u00e9n.\"\n  }\n]\n\nIMPORTANTE:\n- Devuelve SOLO el JSON.\n- No uses Markdown.\n- Aseg\u00farate de cerrar todos los corchetes y comillas."
            }
          ]
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "typeVersion": 1,
      "position": [
        -4336,
        544
      ],
      "id": "7da82892-e769-40f5-8cec-c5a456cfce46",
      "name": "Procesar categor\u00edas",
      "retryOnFail": true,
      "waitBetweenTries": 3000,
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "update",
        "schema": {
          "__rl": true,
          "value": "public",
          "mode": "list",
          "cachedResultName": "public"
        },
        "table": {
          "__rl": true,
          "value": "users",
          "mode": "list",
          "cachedResultName": "users"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "custom_categories_prompt": "={{ $json.formatted_text_full }}",
            "interaction_mode": "confirming_categories",
            "telegram_chat_id": "={{ $('Identificar usuario').item.json.telegram_chat_id }}"
          },
          "matchingColumns": [
            "telegram_chat_id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": true,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "email",
              "displayName": "email",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "first_name",
              "displayName": "first_name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "avatar_url",
              "displayName": "avatar_url",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "telegram_chat_id",
              "displayName": "telegram_chat_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "custom_categories_prompt",
              "displayName": "custom_categories_prompt",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "interaction_mode",
              "displayName": "interaction_mode",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -3744,
        544
      ],
      "id": "fecb615d-ba42-45fc-9394-a8bf793d50b8",
      "name": "Actualizar prompt de categorias",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{ $json.telegram_chat_id }}",
        "text": "=Te propongo estas categor\u00edas para tu perfil: \n\n{{ $('Parsear Categor\u00edas').item.json.formatted_text_short }}\n\n\u00bfTe parece bien? \u2705 Respond\u00e9 S\u00cd para guardar. \u270f\ufe0f O escrib\u00ed qu\u00e9 quer\u00e9s cambiar.",
        "replyMarkup": "forceReply",
        "forceReply": {
          "force_reply": true
        },
        "additionalFields": {
          "appendAttribution": false,
          "parse_mode": "HTML"
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        -3456,
        544
      ],
      "id": "d241f960-3057-4c34-87e8-da7d4ab406ac",
      "name": "Confirmaci\u00f3n de categorias",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $('Identificar usuario').item.json.interaction_mode }}",
                    "rightValue": "waiting_for_categories",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "id": "6040a99e-305e-4756-92f4-e514ab41d495"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Est\u00e1 en modo configuraci\u00f3n"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "77744db9-a95b-414b-bc03-ea198a9a1c9b",
                    "leftValue": "={{ $('Identificar usuario').item.json.interaction_mode }}",
                    "rightValue": "confirming_categories",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Modificando categorias"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "88ab042e-eba6-4099-8c8b-733ac379690f",
                    "leftValue": "={{ $('Identificar usuario').item.json.interaction_mode }}",
                    "rightValue": "standard",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Gasto normal"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "75124bd9-1bd2-47e2-a028-67e0788c7c4a",
                    "leftValue": "={{ $('Identificar usuario').item.json.interaction_mode }}",
                    "rightValue": "waiting_for_payment_methods",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Configurando medios de pago"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "2ed871dd-251f-4a98-b4b1-859bd6cccce3",
                    "leftValue": "={{ $('Identificar usuario').item.json.interaction_mode }}",
                    "rightValue": "waiting_for_default_payment",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Decidiendo medio de pago default"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.3,
      "position": [
        -5712,
        1408
      ],
      "id": "43b2e09c-e8e9-480e-9d90-d82340ef2f1a",
      "name": "Router"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "5ee3187d-53e6-4c61-bc21-d665871c7ad1",
              "leftValue": "={{ $json.content.parts[0].text }}",
              "rightValue": "=CONFIRM",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -4160,
        960
      ],
      "id": "8f29c65f-9bfa-4b06-aeef-01f61e239acf",
      "name": "If"
    },
    {
      "parameters": {
        "operation": "update",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "users",
          "mode": "list",
          "cachedResultName": "users"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "id": "={{ $('Router').item.json.id }}",
            "interaction_mode": "waiting_for_payment_methods"
          },
          "matchingColumns": [
            "id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": true,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "email",
              "displayName": "email",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "first_name",
              "displayName": "first_name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "avatar_url",
              "displayName": "avatar_url",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "telegram_chat_id",
              "displayName": "telegram_chat_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "custom_categories_prompt",
              "displayName": "custom_categories_prompt",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "interaction_mode",
              "displayName": "interaction_mode",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -3952,
        752
      ],
      "id": "fafc8f48-27dd-4792-87cd-af16a7a0b953",
      "name": "Actualizar interaction mode",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{ $('Router').item.json.telegram_chat_id }}",
        "text": "=\u00a1Categor\u00edas guardadas! \ud83d\udcbe \nPero necesitamos un poquito maaaa' \ud83e\udd7a. \n\nPara que Chanchito funcione, necesito saber con qu\u00e9 vas a pagar. Agreguemos tus medios de pago. Decime uno por uno. Si es tarjeta de cr\u00e9dito, necesito el cierre y vencimiento. Ejemplos: \ud83d\udcb3 'Visa Cr\u00e9dito cierra el 24 y vence el 5' \ud83c\udfe7 'Mercado Pago d\u00e9bito' \ud83d\udcb5 'Efectivo' \ud83d\udc47 Decime el primero:\n",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        -3024,
        752
      ],
      "id": "5fb64f63-0756-4c81-88b6-1d84b3243421",
      "name": "Confirmar categorias guardadas",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "select",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "users",
          "mode": "list",
          "cachedResultName": "users"
        },
        "where": {
          "values": [
            {
              "column": "id",
              "value": "={{ $('Identificar usuario').item.json.id }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -3984,
        1088
      ],
      "id": "6b982371-7f6d-4ff9-9f60-7654b1294555",
      "name": "Obtener prompt de categorias guardado",
      "alwaysOutputData": true,
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "update",
        "schema": {
          "__rl": true,
          "value": "public",
          "mode": "list",
          "cachedResultName": "public"
        },
        "table": {
          "__rl": true,
          "value": "users",
          "mode": "list",
          "cachedResultName": "users"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "custom_categories_prompt": "={{ $json.formatted_text_full }}",
            "interaction_mode": "confirming_categories",
            "telegram_chat_id": "={{ $('Identificar usuario').item.json.telegram_chat_id }}"
          },
          "matchingColumns": [
            "telegram_chat_id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": true,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "email",
              "displayName": "email",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "first_name",
              "displayName": "first_name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "avatar_url",
              "displayName": "avatar_url",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "telegram_chat_id",
              "displayName": "telegram_chat_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "custom_categories_prompt",
              "displayName": "custom_categories_prompt",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "interaction_mode",
              "displayName": "interaction_mode",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -3168,
        1088
      ],
      "id": "edc8a876-b0ed-4af8-b822-12f6a25e1d8f",
      "name": "Actualizar nuevo prompt de categorias",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{ $json.telegram_chat_id }}",
        "text": "=A ver ahora \ud83d\udc37: \n\n\u00bfQued\u00f3 bien?\n\n{{ $('Parsear nuevas categor\u00edas').item.json.formatted_text_short }}",
        "replyMarkup": "forceReply",
        "forceReply": {
          "force_reply": true
        },
        "additionalFields": {
          "appendAttribution": false,
          "parse_mode": "HTML"
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        -2944,
        1088
      ],
      "id": "b3919341-7999-48a9-a3cc-443b5321f8ba",
      "name": "Confirmaci\u00f3n de nuevas categorias",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "content": "## \ud83d\udcb3 M\u00f3dulo: Medios de Pago\nAqu\u00ed procesamos la configuraci\u00f3n de billetera",
        "height": 677,
        "width": 1930,
        "color": 7
      },
      "id": "12f3127a-4442-401a-9072-9ef07aecf8be",
      "name": "Sticky Note - Pagos",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -4976,
        2656
      ]
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "models/gemini-2.5-flash",
          "mode": "list",
          "cachedResultName": "models/gemini-2.5-flash"
        },
        "messages": {
          "values": [
            {
              "content": "=Role: Asistente financiero experto en medios de pago.\n\nObjetivo: Analizar el texto del usuario para extraer configuraci\u00f3n de billetera.\n\nTarea 1: Detectar Intenci\u00f3n\n- Si el usuario dice \"Listo\", \"Termin\u00e9\", \"No tengo m\u00e1s\", \"Ya est\u00e1\", la intenci\u00f3n es 'finish'.\n- Si describe un medio de pago, la intenci\u00f3n es 'create'.\n\nTarea 2: Extraer Datos (Solo si intenci\u00f3n es 'create')\n- name: Nombre del medio (Ej: \"Visa Galicia\", \"Efectivo\", \"MP\").\n- type: \u00daNICAMENTE uno de estos valores: 'credit', 'debit', 'cash'.\n  - Si dice \"Cr\u00e9dito\" -> 'credit'.\n  - Si dice \"D\u00e9bito\", \"Mercado Pago\", \"Cuenta DNI\" (sin aclarar cr\u00e9dito) -> 'debit'.\n  - Si dice \"Efectivo\", \"Cash\" -> 'cash'.\n- closing_day: (Solo para 'credit') El n\u00famero del d\u00eda de cierre. Si dice \"cierra el 24\", es 24. Si no lo dice, null.\n- payment_day: (Solo para 'credit') El n\u00famero del d\u00eda de vencimiento. Si no lo dice, null.\n\nOutput JSON:\n{\n  \"intention\": \"create\" | \"finish\",\n  \"name\": \"Visa\",\n  \"type\": \"credit\",\n  \"closing_day\": 24,\n  \"payment_day\": 5\n}\n\nInput Usuario: \"{{ $('Parseo de mensaje para Gemini').first\n().json.text }}\""
            }
          ]
        },
        "jsonOutput": true,
        "options": {}
      },
      "id": "ee7a6d3f-a7e0-4b78-891b-5c8207c8ef8b",
      "name": "Gemini - Extractor Pagos",
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "typeVersion": 1,
      "position": [
        -4400,
        2928
      ],
      "retryOnFail": true,
      "waitBetweenTries": 3000,
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.intention }}",
              "value2": "create"
            }
          ]
        }
      },
      "id": "2dc38c16-f94f-41be-9326-cd0b37c87481",
      "name": "Crear o Terminar?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        -3808,
        2928
      ]
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{ $json.type === 'credit' && (!$json.closing_day || !$json.payment_day) }}",
              "value2": true
            }
          ]
        }
      },
      "id": "46c0e633-e2f4-4c20-bc8c-138470add007",
      "name": "Faltan Fechas Cr\u00e9dito?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        -3632,
        2816
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $('Identificar usuario').first\n().json.telegram_chat_id }}",
        "text": "\u270b Epa, para las tarjetas de *Cr\u00e9dito* necesito s\u00ed o s\u00ed el d\u00eda de Cierre y de Vencimiento.\n\nPorfa, escribila de nuevo completa.\nEj: _\"Visa cierra el 24 y vence el 5\"_",
        "additionalFields": {}
      },
      "id": "4306d1f5-8d33-4adc-b1b6-59b0443047c5",
      "name": "Error: Faltan Fechas",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1,
      "position": [
        -3424,
        2688
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{ $('Identificar usuario').first\n().json.telegram_chat_id }}",
        "text": "=\u2705 Guardado: *{{ $json.name }}* ({{ $json.type == 'credit' ? 'Cr\u00e9dito' : 'D\u00e9bito/Efectivo' }}).\n\n\u00bfTen\u00e9s otro? Decime cu\u00e1l \ud83d\udc47\n_(O escrib\u00ed 'Listo' para terminar)_",
        "additionalFields": {}
      },
      "id": "a29398a8-4186-4c3a-8a2d-23cd03fe1c45",
      "name": "Confirmar y Pedir Otro",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1,
      "position": [
        -2992,
        2928
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "=SELECT name, type, default_closing_day, default_payment_day \nFROM payment_methods \nWHERE user_id = '{{ $('Identificar usuario').first\n().json.id }}'",
        "additionalFields": {}
      },
      "id": "8f90e6b8-223e-49d4-a6f4-9f3eca76a5af",
      "name": "Leer Todos los Pagos",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 1,
      "position": [
        -3632,
        3120
      ],
      "alwaysOutputData": true,
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all();\nlet texto = \"\u00a1Excelente! Configuraci\u00f3n terminada. \ud83d\ude80\\n\\n<b>Tus medios de pago:</b>\\n\";\n\nfor (const item of items) {\n  const data = item.json;\n  let icono = \"\ud83d\udcb3\";\n  if (data.type === 'cash') icono = \"\ud83d\udcb5\";\n  if (data.type === 'debit') icono = \"\ud83c\udfe7\";\n\n  texto += `${icono} <b>${data.name}</b>`;\n\n  if (data.type === 'credit') {\n    texto += ` (Cierra: ${data.default_closing_day}, Vence: ${data.default_payment_day})`;\n  }\n  texto += \"\\n\";\n}\n\nreturn { id: $('Router').first().json.id,text: texto };"
      },
      "id": "d7194831-f154-4d93-a00d-92ef61cd9926",
      "name": "Formatear Lista Final",
      "type": "n8n-nodes-base.code",
      "typeVersion": 1,
      "position": [
        -3408,
        3120
      ]
    },
    {
      "parameters": {
        "jsCode": "// 1. Obtenemos la respuesta cruda de Gemini\n// Ajusta 'text' si tu nodo Gemini devuelve el contenido en otro campo (ej: 'output', 'content')\nconst rawResponse = $input.first().json.content.parts[0].text || $input.first().json.output || \"\";\n\n// 2. Limpieza Quir\u00fargica \ud83e\uddf9\n// A veces Gemini devuelve: ```json { ... } ``` o texto antes/despu\u00e9s.\n// Esta Regex busca lo que est\u00e1 entre el primer '{' y el \u00faltimo '}'\nconst jsonMatch = rawResponse.match(/\\{[\\s\\S]*\\}/);\n\nlet finalJson = {};\n\nif (jsonMatch) {\n  try {\n    // 3. Intentamos parsear lo que encontramos\n    finalJson = JSON.parse(jsonMatch[0]);\n  } catch (error) {\n    // Si falla, devolvemos un error controlado\n    finalJson = { error: \"No se pudo parsear el JSON\", raw: rawResponse };\n  }\n} else {\n  // Si no encontr\u00f3 llaves {}, devolvemos error\n  finalJson = { error: \"No se encontr\u00f3 estructura JSON\", raw: rawResponse };\n}\n\n// 4. Retornamos el objeto limpio para que el resto del flujo lo use directo\nreturn  finalJson;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -4048,
        2928
      ],
      "id": "554b1262-3474-4ab2-8a4f-bc7836e25a9d",
      "name": "Parseo de Gemini"
    },
    {
      "parameters": {
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "payment_methods",
          "mode": "list",
          "cachedResultName": "payment_methods"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "user_id": "={{ $('Identificar usuario').first\n().json.id }}",
            "name": "={{ $json.name }}",
            "type": "={{ $json.type }}",
            "default_closing_day": "={{ $json.closing_day }}",
            "default_payment_day": "={{ $json.payment_day }}"
          },
          "matchingColumns": [
            "id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": false,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "name",
              "displayName": "name",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "type",
              "displayName": "type",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "default_closing_day",
              "displayName": "default_closing_day",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true
            },
            {
              "id": "default_payment_day",
              "displayName": "default_payment_day",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "is_personal",
              "displayName": "is_personal",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "boolean",
              "canBeUsedToMatch": true,
              "removed": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -3344,
        2928
      ],
      "id": "91504be0-7a82-40cb-8292-af0569e360ce",
      "name": "Guardar medio de pago",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{ $json.message.from.id }}",
        "text": "=Estoy pensando... bancame \ud83d\udc4d",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        -7360,
        1280
      ],
      "id": "23b5044a-2507-4820-83f1-06a89c132b6c",
      "name": "Mensaje de espera",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT id, name\nFROM public.payment_methods\nWHERE user_id = '{{ $('Identificar usuario').first().json.id }}'\nAND name ILIKE '{{ \"%\" + $json.termino_busqueda + \"%\" }}'\nLIMIT 1;",
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -4384,
        3408
      ],
      "id": "d4faeee7-0789-4a0d-9e31-bb1dc70ee713",
      "name": "Buscar medio de pago elegido",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "update",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "payment_methods",
          "mode": "list",
          "cachedResultName": "payment_methods"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "is_default": false,
            "user_id": "={{ $('Identificar usuario').first\n().json.id }}"
          },
          "matchingColumns": [
            "user_id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": false,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "name",
              "displayName": "name",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "type",
              "displayName": "type",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "default_closing_day",
              "displayName": "default_closing_day",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "default_payment_day",
              "displayName": "default_payment_day",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "is_personal",
              "displayName": "is_personal",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "boolean",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "is_default",
              "displayName": "is_default",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "boolean",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -4816,
        3408
      ],
      "id": "fea65812-611e-4d58-969c-93123cc79536",
      "name": "Reiniciar defaults",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const text = $('Telegram Trigger').first().json.message.text;\n\n// Palabras de relleno a eliminar (case insensitive)\n// Borra: \"la\", \"el\", \"mi\", \"tarjeta\", \"de\", \"banco\", \"uso\"\nconst cleanText = text\n  .replace(/\\b(el|la|los|las|un|una|mi|mis|tarjeta|tarjetas|de|del|banco|uso|quiero)\\b/gi, '')\n  .replace(/\\s+/g, ' ') // Elimina espacios dobles\n  .trim();\n\nreturn { \n  original: text,\n  termino_busqueda: cleanText \n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -4608,
        3408
      ],
      "id": "03119ce9-3bda-4db3-bfcf-37c9b0644a95",
      "name": "Limpiar b\u00fasqueda"
    },
    {
      "parameters": {
        "operation": "update",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "payment_methods",
          "mode": "list",
          "cachedResultName": "payment_methods"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "is_default": true,
            "id": "={{ $json.id }}"
          },
          "matchingColumns": [
            "id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": false,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "name",
              "displayName": "name",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "type",
              "displayName": "type",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "default_closing_day",
              "displayName": "default_closing_day",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "default_payment_day",
              "displayName": "default_payment_day",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "is_personal",
              "displayName": "is_personal",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "boolean",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "is_default",
              "displayName": "is_default",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "boolean",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -4176,
        3408
      ],
      "id": "2a974589-72ef-4416-9afb-27def4c2f90c",
      "name": "Actualizar medio de pago por defecto",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "update",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "users",
          "mode": "list",
          "cachedResultName": "users"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "id": "={{ $json.user_id }}",
            "interaction_mode": "standard"
          },
          "matchingColumns": [
            "id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": true,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "email",
              "displayName": "email",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "first_name",
              "displayName": "first_name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "avatar_url",
              "displayName": "avatar_url",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "telegram_chat_id",
              "displayName": "telegram_chat_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "custom_categories_prompt",
              "displayName": "custom_categories_prompt",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "interaction_mode",
              "displayName": "interaction_mode",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -3968,
        3408
      ],
      "id": "eb6ee744-c9bf-4d80-8709-de114c3c9d2e",
      "name": "Volver a modo Standard",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{ $json.telegram_chat_id }}",
        "text": "={{ $('Formatear Lista Final').first\n().json.text }}\n\n\ud83e\udd14 Una \u00faltima cosa: \u00bfCu\u00e1l us\u00e1s m\u00e1s frecuentemente? Esto me sirve para cuando te olvides de explicitar el medio de pago, pueda suponerlo \ud83d\ude09\n\n(Escrib\u00ed el nombre tal cual lo ves arriba, ej: 'Visa') ",
        "additionalFields": {
          "appendAttribution": false,
          "parse_mode": "HTML"
        }
      },
      "id": "6d4c7ec2-c53c-44ed-a38a-0359651b9f4a",
      "name": "Confirmaci\u00f3n de medios de pago",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1,
      "position": [
        -2896,
        3120
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{ $json.telegram_chat_id }}",
        "text": "=\u00a1Listo el pollo! \ud83c\udf57 Tu tarjeta por defecto es: {{ $('Actualizar medio de pago por defecto').first\n().json.name }}. Ahora s\u00ed, cuando me digas un gasto y no aclares con qu\u00e9 pagaste, voy a asumir que usaste esta. \ud83d\ude09\n\n\u00a1Ya pod\u00e9s empezar a anotar gastos e ingresos! \ud83d\ude80\nPor ejemplo:\n\n- \"hoy gast\u00e9 10000 pesos en un sanguche con mercado pago\"\n- \"ayer compr\u00e9 una tele por 300000 pesos en 12 cuotas con la visa\"\n- \"ayer cobr\u00e9 mi sueldo por 1 millon de pesos\"",
        "additionalFields": {
          "appendAttribution": false,
          "parse_mode": "HTML"
        }
      },
      "id": "a6271621-a9aa-490b-be21-e5968ceb77e5",
      "name": "Confirmaci\u00f3n de medio de pago por default",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1,
      "position": [
        -3760,
        3408
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "select",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "payment_methods",
          "mode": "list",
          "cachedResultName": "payment_methods"
        },
        "limit": 1,
        "where": {
          "values": [
            {
              "column": "user_id",
              "value": "={{ $('Identificar usuario').first().json.id }}"
            },
            {
              "column": "is_default",
              "value": "true"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -3088,
        1488
      ],
      "id": "30f22922-2417-4ba4-8860-f68a6ca18400",
      "name": "Buscar medio de pago default",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT *\nFROM public.payment_methods\nWHERE user_id = '{{ $('Identificar usuario').first().json.id }}'\nAND name ILIKE '{{ \"%\" + $json.medio_pago + \"%\" }}'\nLIMIT 1;",
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -3088,
        1296
      ],
      "id": "4faedebd-61bc-480d-8f40-4b241aed365c",
      "name": "Buscar medio de pago",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "0a388403-df3d-41e7-b5bb-7ec0dc88a7fd",
              "name": "Compra",
              "value": "={{ $('Dice medio de pago?').item.json.compra }}",
              "type": "string"
            },
            {
              "id": "bda514cb-f2f5-46b4-b539-e3f87dd48742",
              "name": "Categor\u00eda",
              "value": "={{ $('Dice medio de pago?').item.json.categoria }}",
              "type": "string"
            },
            {
              "id": "6b47ddf2-5150-4d44-ba99-a2e50f2e6c93",
              "name": "Valor",
              "value": "={{ $('Dice medio de pago?').item.json.valor }}",
              "type": "number"
            },
            {
              "id": "1d283e1c-d3d1-4d64-8f1c-11d953b39691",
              "name": "Fecha",
              "value": "={{ $('Dice medio de pago?').item.json.fecha }}",
              "type": "string"
            },
            {
              "id": "16fc6b4f-f518-43c0-96cd-552b8bbf7d51",
              "name": "Monto total",
              "value": "={{ $('Dice medio de pago?').item.json.cuotas.monto_total }}",
              "type": "number"
            },
            {
              "id": "01c965ce-addf-4c74-8097-e6bbc6aeef96",
              "name": "Cantidad de cuotas",
              "value": "={{ $('Dice medio de pago?').item.json.cuotas.cantidad }}",
              "type": "number"
            },
            {
              "id": "88d764ec-5665-45d1-8d96-0fc1863d3a43",
              "name": "Medio de pago",
              "value": "={{ $json.name }}",
              "type": "string"
            },
            {
              "id": "221e4f1f-7b41-4a2d-b815-e5740011d1f0",
              "name": "Tipo",
              "value": "={{ $('Dice medio de pago?').item.json.tipo }}",
              "type": "string"
            },
            {
              "id": "68c4faa4-fe25-482f-8e1f-af4f1b684571",
              "name": "D\u00eda de cierre",
              "value": "={{ $json.default_closing_day }}",
              "type": "string"
            },
            {
              "id": "78033874-e84c-4501-98fd-03307fb51be9",
              "name": "D\u00eda de vencimiento",
              "value": "={{ $json.default_payment_day }}",
              "type": "number"
            },
            {
              "id": "a04bc8a6-c3fd-416c-8dab-df41c92f0f51",
              "name": "Es personal",
              "value": "={{ $json.is_personal }}",
              "type": "boolean"
            },
            {
              "id": "bdfca3ca-dca3-4c22-8018-5a30612f093a",
              "name": "Tipo de Medio de pago",
              "value": "={{ $json.type }}",
              "type": "string"
            },
            {
              "id": "b292353a-337e-4cbb-b99e-333cdfea1d73",
              "name": "Id Medio de pago",
              "value": "={{ $json.id }}",
              "type": "string"
            },
            {
              "id": "3ba7a89d-31f9-4138-9bde-79dff98451dd",
              "name": "Id Categoria",
              "value": "={{ $('Parseo post Gemini').item.json.category_id }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -2752,
        1344
      ],
      "id": "7d8d0118-381e-4c17-9cd0-6ff1b82c3c95",
      "name": "Seteo de campos"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "3c83c788-6baa-4595-9e19-cfd3975d0337",
              "leftValue": "={{ $json.medio_pago }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -3472,
        1392
      ],
      "id": "76341da4-84b4-41c9-9d2c-e62855815056",
      "name": "Dice medio de pago?"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "3c83c788-6baa-4595-9e19-cfd3975d0337",
              "leftValue": "={{ $json.medio_pago }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "empty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -3424,
        2224
      ],
      "id": "b2854d89-bdd3-416e-9026-b2de3c6971df",
      "name": "Dice medio de pago? - Suscripci\u00f3n"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "0a388403-df3d-41e7-b5bb-7ec0dc88a7fd",
              "name": "Compra",
              "value": "={{ $('Es transacci\u00f3n o configuraci\u00f3n de tarjeta').item.json.descripcion }}",
              "type": "string"
            },
            {
              "id": "bda514cb-f2f5-46b4-b539-e3f87dd48742",
              "name": "Categor\u00eda",
              "value": "={{ $('Es transacci\u00f3n o configuraci\u00f3n de tarjeta').item.json.categoria }}",
              "type": "string"
            },
            {
              "id": "6b47ddf2-5150-4d44-ba99-a2e50f2e6c93",
              "name": "Valor",
              "value": "={{ $('Es transacci\u00f3n o configuraci\u00f3n de tarjeta').item.json.valor }}",
              "type": "number"
            },
            {
              "id": "16fc6b4f-f518-43c0-96cd-552b8bbf7d51",
              "name": "Frecuencia",
              "value": "={{ $('Es transacci\u00f3n o configuraci\u00f3n de tarjeta').item.json.frecuencia }}",
              "type": "number"
            },
            {
              "id": "88d764ec-5665-45d1-8d96-0fc1863d3a43",
              "name": "Medio de pago",
              "value": "={{ $json.name }}",
              "type": "string"
            },
            {
              "id": "221e4f1f-7b41-4a2d-b815-e5740011d1f0",
              "name": "Moneda",
              "value": "={{ $('Es transacci\u00f3n o configuraci\u00f3n de tarjeta').item.json.moneda }}",
              "type": "string"
            },
            {
              "id": "ae3e5bbd-ca1b-4583-b472-a5fc24d15afa",
              "name": "D\u00eda de cierre",
              "value": "={{ $json.default_closing_day }}",
              "type": "string"
            },
            {
              "id": "c615f137-3114-4cde-b578-7e4ed481bf39",
              "name": "D\u00eda de vencimiento",
              "value": "={{ $json.default_payment_day }}",
              "type": "string"
            },
            {
              "id": "be3a499d-a761-41ec-b9d6-f3c05d67559b",
              "name": "Id Medio de pago",
              "value": "={{ $json.id }}",
              "type": "string"
            },
            {
              "id": "9c9c1807-3a3a-4e2f-9317-de020c6d6804",
              "name": "Id Usuario",
              "value": "={{ $json.user_id }}",
              "type": "string"
            }
          ]
        },
        "options": {
          "ignoreConversionErrors": true
        }
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -2704,
        2176
      ],
      "id": "2215431f-bbae-4ad4-a029-60394bc6d8af",
      "name": "Seteo de campos - Suscripci\u00f3n"
    },
    {
      "parameters": {
        "operation": "select",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "payment_methods",
          "mode": "list",
          "cachedResultName": "payment_methods"
        },
        "limit": 1,
        "where": {
          "values": [
            {
              "column": "user_id",
              "value": "={{ $('Identificar usuario').first\n().json.id }}"
            },
            {
              "column": "is_default",
              "value": "true"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -3024,
        2096
      ],
      "id": "4b02ce5a-0194-4296-917d-48144d565253",
      "name": "Buscar medio de pago default  - Suscripci\u00f3n",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT *\nFROM public.payment_methods\nWHERE user_id = '{{ $('Identificar usuario').first().json.id }}'\nAND name ILIKE '{{ \"%\" + $json.medio_pago + \"%\" }}'\nLIMIT 1;",
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -3024,
        2320
      ],
      "id": "cdd0e2a1-dd92-4802-8671-98b33566aa0a",
      "name": "Buscar medio de pago  - Suscripci\u00f3n",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{ $('Parseo de mensaje para Gemini').item.json.chat_id }}",
        "text": "=\ud83d\udd04 <strong>Suscripci\u00f3n Guardada</strong>  \n\ud83d\udccc <strong>Plan:</strong> {{ $('Parseo post Gemini').first\n().json.descripcion }} \n\ud83d\udcb0 <strong>Monto:</strong> ${{ $('Parseo post Gemini').first\n().json.valor }} {{ $('Parseo post Gemini').item.json.moneda }} / mes \n\ud83d\udcb3 <strong>Medio:</strong> {{ $('Seteo de campos - Suscripci\u00f3n').first\n().json['Medio de pago'] }} \n\ud83d\udcc2 <strong>Categor\u00eda:</strong> {{ $('Parseo post Gemini').first\n().json.categoria }}  ",
        "additionalFields": {
          "appendAttribution": false,
          "parse_mode": "HTML"
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        -2288,
        2176
      ],
      "id": "468c48e3-6f14-4697-8b75-4f858097e80c",
      "name": "Confirmaci\u00f3n de suscripci\u00f3n",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "select",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "categories",
          "mode": "list",
          "cachedResultName": "categories"
        },
        "returnAll": true,
        "where": {
          "values": [
            {
              "column": "user_id",
              "value": "={{ $('Identificar usuario').item.json.id }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -4752,
        1712
      ],
      "id": "8b378bd3-dd8b-4ecf-b2c6-0697b9f61ab5",
      "name": "Leer Categor\u00edas",
      "alwaysOutputData": true,
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all();\n\n// Lista para el Prompt (Texto)\nconst listaPrompt = items.map(i => {\n   return `${i.json.name}`;\n}).join(', ');\n\n// Diccionario de IDs (Nuevo!)\n// Crea algo as\u00ed: { \"Supermercado\": \"uuid-123...\", \"Ropa\": \"uuid-456...\" }\nconst mapaIds = {};\nitems.forEach(i => {\n    mapaIds[i.json.name] = i.json.id;\n});\n\nreturn [{\n  json: {\n    categories_prompt: listaPrompt,\n    categories_map: mapaIds, // Pasamos el mapa hacia adelante\n    user_id: items[0].json.user_id\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -4560,
        1712
      ],
      "id": "3b1a206b-1d43-4a17-b140-20e8cbb731c9",
      "name": "Formatear Categor\u00edas"
    },
    {
      "parameters": {
        "jsCode": "// 1. Obtenemos el texto FINAL que aprob\u00f3 el usuario.\n// Aseg\u00farate de traer el campo 'custom_categories_prompt' del nodo 'Identificar usuario' \n// o del nodo que actualiz\u00f3 el prompt por \u00faltima vez.\nconst promptText = $input.first().json.custom_categories_prompt\n\nconst userId = $('Identificar usuario').first().json.id;\n\n// 2. Regex para desarmar el formato: \"\ud83d\uded2 *Nombre*: Descripci\u00f3n\"\n// Esta regex busca: Emoji opcional -> Nombre entre asteriscos -> Separador -> Descripci\u00f3n\nconst regex = /(?:^|\\n)([^a-zA-Z0-9\\s]*)\\s*\\*?([^*]+)\\*?\\s*[:|-]\\s*([^\\n]+)/g;\n\nlet match;\nconst categories = [];\n\n// 3. Iteramos todas las coincidencias\nwhile ((match = regex.exec(promptText)) !== null) {\n    const emoji = match[1].trim(); // Grupo 1: Emoji\n    const name = match[2].trim();  // Grupo 2: Nombre\n    const desc = match[3].trim();  // Grupo 3: Descripci\u00f3n\n\n    categories.push({\n        user_id: userId,\n        name: name,\n        emoji: emoji || '\ud83d\udce6', // Emoji default si no encuentra\n        description: desc\n    });\n}\n\n// 4. Devolvemos el array listo para insertar\nreturn {\n    json: {\n        categories_to_insert: categories\n    }\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -3584,
        752
      ],
      "id": "4c634fde-61eb-4aa0-bb3e-a95df7365e82",
      "name": "Parsear Prompt Final"
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "-- 1. BORRAR (Igual que antes)\nDELETE FROM public.categories \nWHERE user_id = '{{ $('Identificar usuario').item.json.id }}' \n  AND is_system = false;\n\n-- 2. INSERTAR (Con Dollar Quoting $$ para blindar el JSON)\nINSERT INTO public.categories (user_id, name, emoji, description)\nSELECT \n  '{{ $('Identificar usuario').item.json.id }}'::uuid, -- ID del usuario\n  elem->>'name',        -- Nombre\n  elem->>'emoji',       -- Emoji\n  elem->>'description'  -- Descripci\u00f3n completa\nFROM jsonb_array_elements($${{ JSON.stringify($json.categories_to_insert) }}$$::jsonb) AS elem;",
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -3328,
        752
      ],
      "id": "97f9f8f1-2792-4ca4-858f-27cb13d0178a",
      "name": "Materializar Categor\u00edas SQL",
      "alwaysOutputData": true,
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "recurring_plans",
          "mode": "list",
          "cachedResultName": "recurring_plans"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "is_active": true,
            "user_id": "={{ $json['Id Usuario'] }}",
            "description": "={{ $json.Compra }}",
            "amount": "={{ $json.Valor }}",
            "currency": "={{ $json.Moneda }}",
            "frequency": "={{ $json.Frecuencia }}",
            "category": "={{ $json['Categor\u00eda'] }}",
            "payment_method_id": "={{ $json['Id Medio de pago'] }}"
          },
          "matchingColumns": [
            "id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": false,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "description",
              "displayName": "description",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "amount",
              "displayName": "amount",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true
            },
            {
              "id": "currency",
              "displayName": "currency",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "frequency",
              "displayName": "frequency",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "is_active",
              "displayName": "is_active",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "boolean",
              "canBeUsedToMatch": true
            },
            {
              "id": "category",
              "displayName": "category",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "payment_method_id",
              "displayName": "payment_method_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -2496,
        2176
      ],
      "id": "caf6fcb8-95b0-48f4-824b-c474a42550a4",
      "name": "Guardar mensualidad",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "update",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "users",
          "mode": "list",
          "cachedResultName": "users"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "id": "={{ $json.id }}",
            "interaction_mode": "waiting_for_default_payment"
          },
          "matchingColumns": [
            "id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": true,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "email",
              "displayName": "email",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "first_name",
              "displayName": "first_name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "avatar_url",
              "displayName": "avatar_url",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "telegram_chat_id",
              "displayName": "telegram_chat_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "custom_categories_prompt",
              "displayName": "custom_categories_prompt",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "interaction_mode",
              "displayName": "interaction_mode",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -3168,
        3120
      ],
      "id": "974ea529-05ce-4856-9416-2b6b53652bbc",
      "name": "Actualizar interaction mode - waiting_for_default_payment",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// 1. Obtenemos el output de Gemini\nconst rawInput = $input.first().json.content.parts[0].text \n\n// 2. LIMPIEZA ROBUSTA: Quitamos markdown (```json ... ```) y espacios extras\nconst cleanJson = rawInput\n    .replace(/```json/g, '') // Quita inicio de bloque\n    .replace(/```/g, '')     // Quita fin de bloque\n    .trim();                 // Quita espacios\n\nlet categories = [];\ntry {\n    categories = JSON.parse(cleanJson);\n} catch (e) {\n    // Si falla el parseo, devolvemos array vac\u00edo o un fallback\n    console.log(\"Error parseando JSON de Gemini:\", e);\n    categories = [];\n}\n\n// 3. GENERAR LAS DOS VERSIONES\n\n// Versi\u00f3n FULL: Para la Base de Datos (Postgres)\n// Usamos description_full para que Gemini tenga mucho contexto en el futuro\nconst fullText = categories.map(c => \n    `${c.emoji} *${c.name}*: ${c.description_full}`\n).join('\\n');\n\n// Versi\u00f3n SHORT: Para Telegram (Chat)\n// Usamos description_short para que sea legible y NO corte con \"...\"\nconst shortText = categories.map(c => \n    `${c.emoji} <b>${c.name}</b>: ${c.description_short}`\n).join('\\n');\n\n\nreturn {\n    json: {\n        categories_parsed: categories,   // Para debug\n        formatted_text_full: fullText,   // -> Mapear a Postgres\n        formatted_text_short: shortText  // -> Mapear a Telegram\n    }\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -3984,
        544
      ],
      "id": "3f49e59c-48ad-4f06-9c08-9057626bc99d",
      "name": "Parsear Categor\u00edas"
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "models/gemini-2.5-flash",
          "mode": "list",
          "cachedResultName": "models/gemini-2.5-flash"
        },
        "messages": {
          "values": [
            {
              "content": "=Act\u00faa como un arquitecto de datos financieros inteligente.\nTu tarea es GESTIONAR la lista de categor\u00edas de gastos del usuario.\n\nINPUTS:\n1. **Contexto Actual** (Lista existente): \n\"\"\"\n{{ $('Obtener prompt de categorias guardado').first().json.custom_categories_prompt || \"Lista vac\u00eda\" }}\n\"\"\"\n\n2. **Solicitud del Usuario** (Cambios o Definici\u00f3n inicial): \n\"\"\"\n{{ $('Parseo de mensaje para Gemini').first().json.text }}\n\"\"\"\n\nINSTRUCCIONES:\n- Si el \"Contexto Actual\" est\u00e1 vac\u00edo, genera la lista basada en la \"Solicitud del Usuario\".\n- Si el \"Contexto Actual\" tiene datos, **MODIFICA** esa lista aplicando lo que pide el usuario (Agregar, Borrar, Renombrar o Cambiar descripciones). MANT\u00c9N las categor\u00edas que el usuario no pidi\u00f3 tocar.\n- Genera descripciones ricas (\"full\") para la IA y res\u00famenes (\"short\") para el usuario.\n\nOUTPUT REQUERIDO (JSON Array EXCLUSIVAMENTE):\n[\n  {\n    \"emoji\": \"\ud83c\udfac\",\n    \"name\": \"Entretenimiento\",\n    \"description_full\": \"Gastos relacionados con ocio, cine, teatro, videojuegos, servicios de streaming como Netflix o Spotify, y actividades recreativas.\",\n    \"description_short\": \"Cine, streaming, juegos, ocio, teatro, diversi\u00f3n.\"\n  }\n]\n\nREGLAS:\n- Devuelve SOLO el JSON.\n- No uses Markdown.\n- Mant\u00e9n la coherencia de la lista completa."
            }
          ]
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "typeVersion": 1,
      "position": [
        -3792,
        1088
      ],
      "id": "5be16eee-348d-4b2d-a030-ddd127c0c60e",
      "name": "Procesar nuevas categor\u00edas",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// 1. Obtenemos el output de Gemini\nconst rawInput = $input.first().json.content.parts[0].text \n\n// 2. LIMPIEZA ROBUSTA: Quitamos markdown (```json ... ```) y espacios extras\nconst cleanJson = rawInput\n    .replace(/```json/g, '') // Quita inicio de bloque\n    .replace(/```/g, '')     // Quita fin de bloque\n    .trim();                 // Quita espacios\n\nlet categories = [];\ntry {\n    categories = JSON.parse(cleanJson);\n} catch (e) {\n    // Si falla el parseo, devolvemos array vac\u00edo o un fallback\n    console.log(\"Error parseando JSON de Gemini:\", e);\n    categories = [];\n}\n\n// 3. GENERAR LAS DOS VERSIONES\n\n// Versi\u00f3n FULL: Para la Base de Datos (Postgres)\n// Usamos description_full para que Gemini tenga mucho contexto en el futuro\nconst fullText = categories.map(c => \n    `${c.emoji} *${c.name}*: ${c.description_full}`\n).join('\\n');\n\n// Versi\u00f3n SHORT: Para Telegram (Chat)\n// Usamos description_short para que sea legible y NO corte con \"...\"\nconst shortText = categories.map(c => \n    `${c.emoji} <b>${c.name}</b>: ${c.description_short}`\n).join('\\n');\n\n\nreturn {\n    json: {\n        categories_parsed: categories,   // Para debug\n        formatted_text_full: fullText,   // -> Mapear a Postgres\n        formatted_text_short: shortText  // -> Mapear a Telegram\n    }\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -3440,
        1088
      ],
      "id": "5835b267-34a9-48d6-8805-b865ea4f9d82",
      "name": "Parsear nuevas categor\u00edas"
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "models/gemini-2.5-flash",
          "mode": "list",
          "cachedResultName": "models/gemini-2.5-flash"
        },
        "messages": {
          "values": [
            {
              "content": "=Analiza la respuesta del usuario: \"{{ $('Parseo de mensaje para Gemini').first().json.text }}\"\n\nDetermina si el usuario est\u00e1 CONFIRMANDO (aceptando) o si quiere MODIFICAR (cambiar algo).\n\nReglas:\n- Si dice \"si\", \"ok\", \"listo\", \"me gusta\", \"guardar\", \"joya\", etc -> intent: \"CONFIRM\"\n- Si dice \"no\", \"cambia tal cosa\", \"agregame esto\", \"saca aquello\" -> intent: \"MODIFY\"\n- Si dice algo nada que ver -> intent: \"UNKNOWN\"\n\nResponde SOLAMENTE \"CONFIRM\" o \"MODIFY\""
            }
          ]
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "typeVersion": 1,
      "position": [
        -4480,
        960
      ],
      "id": "f1022cac-4232-4606-9bff-6e49365526bf",
      "name": "Clasificador de Intenci\u00f3n",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "projectId": {
          "__rl": true,
          "value": "autonomous-key-470603-i3",
          "mode": "list",
          "cachedResultName": "My First Project"
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleVertex",
      "typeVersion": 1,
      "position": [
        -4400,
        2112
      ],
      "id": "b282118a-1d9c-490e-ac09-5d1a94b47f4a",
      "name": "Google Vertex Chat Model",
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=Act\u00faa como un asistente financiero experto en el contexto econ\u00f3mico argentino.\nTu objetivo es extraer datos estructurados de un mensaje natural y categorizarlos con precisi\u00f3n usando los IDs provistos.\n\nINPUTS:\n1. Mensaje del Usuario: \n\"\"\"\n{{ $('Parseo de mensaje para Gemini').first().json.text }}\n\"\"\"\n\n2. Lista de Categor\u00edas (Referencia):\n{{ $('Formatear Categor\u00edas').first().json.categories_prompt }}\n\n3. DICCIONARIO DE IDs (Mapa Nombre -> UUID):\n{{ JSON.stringify($('Formatear Categor\u00edas').first().json.categories_map) }}\n\nINSTRUCCIONES:\nAnaliza el mensaje y devuelve EXCLUSIVAMENTE un objeto JSON.\nDetecta la INTENCI\u00d3N y elige la estructura correcta.\nIMPORTANTE: Cuando elijas una categor\u00eda, busca su nombre exacto en el \"DICCIONARIO DE IDs\" y extrae el UUID correspondiente para el campo \"category_id\".\n\n--- CASO A: ES UNA TRANSACCI\u00d3N (Gasto, Compra, Cuotas, Ingreso) ---\nSi el usuario informa un movimiento de dinero.\nDevuelve esta estructura:\n{\n  \"intencion\": \"transaccion\",\n  \"compra\": \"Breve descripci\u00f3n del \u00edtem (ej: Zapatillas Nike)\",\n  \"categoria\": \"El nombre exacto de la categor\u00eda elegida (ej: 'Comida')\",\n\"category_id\": \"El UUID exacto sacado del DICCIONARIO DE IDs correspondiente a la categor\u00eda elegida.\",\n  \"valor\": 0, (N\u00famero positivo puro. Si es gasto 12000, pon 12000. Si es ingreso, tambi\u00e9n positivo).\n  \"tipo\": \"Uno de: 'expense' (gasto) o 'income' (ingreso/sueldo/cobro)\",\n  \"medio_pago\": \"Nombre del medio si se menciona (ej: 'Visa', 'Master', 'Mercado Pago', 'Efectivo'). Si no dice nada, devuelve null.\",\n  \"es_gasto_real\": true, (Poner false si es publicidad, spam, aviso de seguridad, 'novedades', o notificaciones que NO implican movimiento de dinero),\n  \"cuotas\": {\n    \"es_cuota\": boolean, (true si el usuario menciona expl\u00edcitamente cuotas, pagos o plan de pagos),\n    \"cantidad\": number, (1 si es pago \u00fanico. Si son cuotas, la cantidad, ej: 6),\n    \"monto_total\": number (El precio TOTAL de la compra. IMPORTANTE: Si el usuario dice '6 cuotas de 10.000', el total es 60000. Si dice 'TV 100.000 en 6 pagos', el total es 100000)\n  },\n  \"fecha\": \"YYYY-MM-DD\" (Calculada en relaci\u00f3n a hoy: {{ $now }}. Por ejemplo, si dice 'hoy' es {{ $now }}, si es ayer es el dia previo a {{ $now }}. Si no dice nada, se asume que es {{ $now }})\n}\n\n--- CASO B: CONFIGURACI\u00d3N DE TARJETA (El usuario informa fechas) ---\nSi el usuario dice algo como \"La Visa cierra el 24/12 y vence el 05/01\" o \"Master cierra el 20\".\nDevuelve esta estructura:\n{\n  \"intencion\": \"configuracion_tarjeta\",\n  \"tarjeta_match\": \"Parte del nombre de la tarjeta para buscarla (ej: 'Visa')\",\n  \"fecha_cierre\": \"YYYY-MM-DD\" (Si solo dice el d\u00eda '24', asume el cierre pr\u00f3ximo l\u00f3gico seg\u00fan la fecha de hoy: {{ $now }}),\n  \"fecha_vencimiento\": \"YYYY-MM-DD\" (Calcula la fecha l\u00f3gica de vencimiento posterior al cierre)\n}\n\n--- CASO C: SUSCRIPCI\u00d3N O GASTO FIJO (Recurring Plan) ---\nSi el usuario menciona un gasto que se repite (ej: \"Suscripci\u00f3n Netflix\", \"Pago el gimnasio todos los meses\", \"D\u00e9bito autom\u00e1tico de seguro\", \"Alquiler\").\nDevuelve esta estructura:\n{\n  \"intencion\": \"suscripcion\",\n  \"descripcion\": \"Nombre del servicio (ej: Spotify)\",\n  \"valor\": 0, (Monto mensual),\n  \"moneda\": \"ARS\" (o USD si especifica),\n  \"categoria\": \"Nombre de la categor\u00eda elegida\",\n  \"category_id\": \"El UUID exacto sacado del DICCIONARIO DE IDs\",\n  \"frecuencia\": \"monthly\", (Por defecto 'monthly', salvo que diga 'anual' o 'semanal'),\n  \"medio_pago\": \"Nombre del medio de pago si se menciona (ej: 'Visa'). Si no, null.\"\n}\n\nREGLAS CR\u00cdTICAS DE PROCESAMIENTO:\n1. Si detectas palabras como \"Cobr\u00e9\", \"Sueldo\", \"Me transfirieron\", \"Ingreso\", define \"tipo\": \"income\" y \"categoria\": \"Ingresos\".\n2. Si \"es_gasto_real\" es false, el resto de campos pueden ser null.\n3. Prioriza tu lista de categor\u00edas personalizada. Si no encaja, usa \"Otros\".\n4. Si el usuario dice palabras como 'mensual', 'suscripci\u00f3n', 'd\u00e9bito autom\u00e1tico', 'plan', prioriza la intenci\u00f3n 'suscripcion' sobre 'transaccion'.\n5. El campo \"category_id\" ES OBLIGATORIO para transacciones y suscripciones. Nunca lo dejes null si encontraste una categor\u00eda.",
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.7,
      "position": [
        -4352,
        1952
      ],
      "id": "16ae0035-59e7-4ba0-8bb5-2bbb2a544956",
      "name": "Basic LLM Chain"
    }
  ],
  "connections": {
    "Procesar mensaje y categorizar": {
      "main": [
        []
      ]
    },
    "Chequeo de campos v\u00e1lidos": {
      "main": [
        [
          {
            "node": "Dice medio de pago?",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Enviar mensaje de error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parseo post Gemini": {
      "main": [
        [
          {
            "node": "Es transacci\u00f3n o configuraci\u00f3n de tarjeta",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Crear Plan (Cuotas)": {
      "main": [
        [
          {
            "node": "Calculadora de fechas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculadora de fechas": {
      "main": [
        [
          {
            "node": "Guardar cuotas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Es gasto en cuotas?": {
      "main": [
        [
          {
            "node": "Crear Plan (Cuotas)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Guardar Transaccion",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Guardar Transaccion": {
      "main": [
        [
          {
            "node": "Es ingreso?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parseo de mensaje para Gemini": {
      "main": [
        [
          {
            "node": "Identificar usuario",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Es transacci\u00f3n o configuraci\u00f3n de tarjeta": {
      "main": [
        [
          {
            "node": "Chequeo de campos v\u00e1lidos",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Identificar medio de pago",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Dice medio de pago? - Suscripci\u00f3n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Identificar medio de pago": {
      "main": [
        [
          {
            "node": "Actualizar medio de pago",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Guardar cuotas": {
      "main": [
        [
          {
            "node": "Enviar mensaje de confirmaci\u00f3n de cuotas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculadora de vencimiento": {
      "main": [
        [
          {
            "node": "Es gasto en cuotas?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Es ingreso?": {
      "main": [
        [
          {
            "node": "Enviar mensaje de confirmaci\u00f3n de ingreso",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Enviar mensaje de confirmaci\u00f3n de gasto",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Actualizar medio de pago": {
      "main": [
        [
          {
            "node": "Actualizar futuros",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Trigger de chequeo de cierres diario": {
      "main": [
        [
          {
            "node": "Chequeo de cierres diario",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Chequeo de cierres diario": {
      "main": [
        [
          {
            "node": "Send message and wait for response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Identificar usuario": {
      "main": [
        [
          {
            "node": "Router",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Actualizar futuros": {
      "main": [
        [
          {
            "node": "Enviar mensaje de confirmaci\u00f3n de configuraci\u00f3n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Leer Cartera",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Leer Cartera": {
      "main": [
        [
          {
            "node": "Split Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Batches": {
      "main": [
        [],
        [
          {
            "node": "El Clasificador",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Obtener valores": {
      "main": [
        [
          {
            "node": "Limpiar valores",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Obtener valores cripto": {
      "main": [
        [
          {
            "node": "Limpiar valores cripto",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Limpiar valores cripto": {
      "main": [
        [
          {
            "node": "Execute a SQL query",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Limpiar valores": {
      "main": [
        [
          {
            "node": "Execute a SQL query",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Execute a SQL query": {
      "main": [
        [
          {
            "node": "Split Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "El Clasificador": {
      "main": [
        [
          {
            "node": "Obtener valores",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Obtener valores cripto",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request": {
      "main": [
        [
          {
            "node": "HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTML": {
      "main": [
        [
          {
            "node": "Limpiar Scrap",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Limpiar Scrap": {
      "main": [
        [
          {
            "node": "Execute a SQL query",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telegram Trigger": {
      "main": [
        [
          {
            "node": "Mensaje de espera",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extraer el Token": {
      "main": [
        [
          {
            "node": "Filtrar nuevos mensajes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filtrar nuevos mensajes": {
      "main": [
        [
          {
            "node": "Actualizar ID Telegram del usuario",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Es Respuesta Nombre?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Actualizar ID Telegram del usuario": {
      "main": [
        [
          {
            "node": "Confirmaci\u00f3n de vinculaci\u00f3n de telegram",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Es Respuesta Nombre?": {
      "main": [
        [
          {
            "node": "Guardar nombre",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Parseo de mensaje para Gemini",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Guardar nombre": {
      "main": [
        [
          {
            "node": "Confirmaci\u00f3n de nombre y configuraci\u00f3n de categorias",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Procesar categor\u00edas": {
      "main": [
        [
          {
            "node": "Parsear Categor\u00edas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Actualizar prompt de categorias": {
      "main": [
        [
          {
            "node": "Confirmaci\u00f3n de categorias",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Router": {
      "main": [
        [
          {
            "node": "Procesar categor\u00edas",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Clasificador de Intenci\u00f3n",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Leer Categor\u00edas",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Gemini - Extractor Pagos",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Reiniciar defaults",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If": {
      "main": [
        [
          {
            "node": "Actualizar interaction mode",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Obtener prompt de categorias guardado",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Actualizar interaction mode": {
      "main": [
        [
          {
            "node": "Parsear Prompt Final",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Obtener prompt de categorias guardado": {
      "main": [
        [
          {
            "node": "Procesar nuevas categor\u00edas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Actualizar nuevo prompt de categorias": {
      "main": [
        [
          {
            "node": "Confirmaci\u00f3n de nuevas categorias",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gemini - Extractor Pagos": {
      "main": [
        [
          {
            "node": "Parseo de Gemini",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Crear o Terminar?": {
      "main": [
        [
          {
            "node": "Faltan Fechas Cr\u00e9dito?",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Leer Todos los Pagos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Faltan Fechas Cr\u00e9dito?": {
      "main": [
        [
          {
            "node": "Error: Faltan Fechas",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Guardar medio de pago",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Leer Todos los Pagos": {
      "main": [
        [
          {
            "node": "Formatear Lista Final",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Formatear Lista Final": {
      "main": [
        [
          {
            "node": "Actualizar interaction mode - waiting_for_default_payment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parseo de Gemini": {
      "main": [
        [
          {
            "node": "Crear o Terminar?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Guardar medio de pago": {
      "main": [
        [
          {
            "node": "Confirmar y Pedir Otro",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mensaje de espera": {
      "main": [
        [
          {
            "node": "Extraer el Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Reiniciar defaults": {
      "main": [
        [
          {
            "node": "Limpiar b\u00fasqueda",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Limpiar b\u00fasqueda": {
      "main": [
        [
          {
            "node": "Buscar medio de pago elegido",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buscar medio de pago elegido": {
      "main": [
        [
          {
            "node": "Actualizar medio de pago por defecto",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Actualizar medio de pago por defecto": {
      "main": [
        [
          {
            "node": "Volver a modo Standard",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Volver a modo Standard": {
      "main": [
        [
          {
            "node": "Confirmaci\u00f3n de medio de pago por default",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buscar medio de pago default": {
      "main": [
        [
          {
            "node": "Seteo de campos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buscar medio de pago": {
      "main": [
        [
          {
            "node": "Seteo de campos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Seteo de campos": {
      "main": [
        [
          {
            "node": "Calculadora de vencimiento",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Dice medio de pago?": {
      "main": [
        [
          {
            "node": "Buscar medio de pago",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Buscar medio de pago default",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Dice medio de pago? - Suscripci\u00f3n": {
      "main": [
        [
          {
            "node": "Buscar medio de pago default  - Suscripci\u00f3n",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Buscar medio de pago  - Suscripci\u00f3n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buscar medio de pago default  - Suscripci\u00f3n": {
      "main": [
        [
          {
            "node": "Seteo de campos - Suscripci\u00f3n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buscar medio de pago  - Suscripci\u00f3n": {
      "main": [
        [
          {
            "node": "Seteo de campos - Suscripci\u00f3n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Seteo de campos - Suscripci\u00f3n": {
      "main": [
        [
          {
            "node": "Guardar mensualidad",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Leer Categor\u00edas": {
      "main": [
        [
          {
            "node": "Formatear Categor\u00edas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Formatear Categor\u00edas": {
      "main": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parsear Prompt Final": {
      "main": [
        [
          {
            "node": "Materializar Categor\u00edas SQL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Materializar Categor\u00edas SQL": {
      "main": [
        [
          {
            "node": "Confirmar categorias guardadas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Guardar mensualidad": {
      "main": [
        [
          {
            "node": "Confirmaci\u00f3n de suscripci\u00f3n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Actualizar interaction mode - waiting_for_default_payment": {
      "main": [
        [
          {
            "node": "Confirmaci\u00f3n de medios de pago",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parsear Categor\u00edas": {
      "main": [
        [
          {
            "node": "Actualizar prompt de categorias",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Procesar nuevas categor\u00edas": {
      "main": [
        [
          {
            "node": "Parsear nuevas categor\u00edas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parsear nuevas categor\u00edas": {
      "main": [
        [
          {
            "node": "Actualizar nuevo prompt de categorias",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Clasificador de Intenci\u00f3n": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Vertex Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Basic LLM Chain": {
      "main": [
        [
          {
            "node": "Parseo post Gemini",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "1cd6616a-8dae-49fe-bb13-1da69c8a04b2",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "u3m9MELYLdBjgddW",
  "tags": []
}