{
  "name": "Workshop · Leer comprobante - Workflow 4 (SW)",
  "nodes": [
    {
      "parameters": {
        "workflowInputs": {
          "values": [
            {
              "name": "media_url"
            },
            {
              "name": "content_type"
            }
          ]
        }
      },
      "id": "7f8d925a-44d6-4787-9259-cc1a553bb666",
      "name": "Entrada · datos del adjunto",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.1,
      "position": [
        -1008,
        -80
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 2
          },
          "conditions": [
            {
              "id": "m1",
              "leftValue": "={{ $json.content_type }}",
              "rightValue": "image/jpeg",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            },
            {
              "id": "m2",
              "leftValue": "={{ $json.content_type }}",
              "rightValue": "image/png",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            },
            {
              "id": "m3",
              "leftValue": "={{ $json.content_type }}",
              "rightValue": "application/pdf",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "or"
        },
        "options": {}
      },
      "id": "8a347d50-598a-4ebb-bc49-26e7b50ba496",
      "name": "Gate · Formato procesable",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -768,
        -80
      ]
    },
    {
      "parameters": {
        "url": "={{ $json.media_url }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        }
      },
      "id": "7de0f349-63fc-4294-a674-4b1ce2ffaa6a",
      "name": "Descargar el adjunto",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.5,
      "position": [
        -336,
        -96
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "Leé el comprobante adjunto y devolvé los campos del esquema.",
        "hasOutputParser": true,
        "options": {
          "systemMessage": "=# OBJETIVO\n\nLeés comprobantes de transferencia bancaria de Argentina y devolvés sus datos en un esquema fijo.\n\nTu salida alimenta un sistema que maneja plata real. Un dato inventado es peor que un dato faltante, porque un dato faltante se ve y uno inventado no.\n\nVos NO decidís si el comprobante sirve o no. Solo reportás lo que ves. Otro paso decide.\n\n# TAREAS\n\n1. Mirá el documento adjunto.\n2. Si no estás viendo un documento, devolvé `documento_recibido: false`, todo lo demás vacío, y `campos_ilegibles: [\"documento_no_recibido\"]`.\n3. Si lo estás viendo, clasificá qué tipo de documento es.\n4. Extraé cada campo que esté presente y puedas leer con certeza.\n5. Listá en `campos_ilegibles` únicamente los campos que ESTÁN en el documento pero no pudiste leer.\n\n# REGLAS\n\n**La regla que manda sobre todas las demás**\n\nNunca escribas un valor que no estés leyendo del documento en este momento. Ni por inferencia, ni por contexto, ni porque suele ser así, ni para completar el esquema.\n\nUn esquema con campos vacíos es un resultado correcto.\n\n**Ilegible NO es lo mismo que ausente**\n\nEsta distinción importa más de lo que parece.\n\n- **Ilegible** = el campo está en el documento pero no se puede leer: borroso, cortado, tapado, con reflejo, pixelado. Ese sí va en `campos_ilegibles`.\n- **Ausente** = el comprobante directamente no incluye ese dato. Va como cadena vacía y **NO** va en `campos_ilegibles`.\n\nEjemplo concreto y muy común: casi ningún comprobante muestra el CBU/CVU y el alias de destino al mismo tiempo. Muestra uno o el otro. Que falte el alias cuando hay CVU **no es un error de lectura**, es como son los comprobantes. No lo listes como ilegible.\n\nLo mismo vale para el banco de origen en comprobantes de billeteras, o para el alias cuando el comprobante es de banco.\n\n**Formato de cada campo**\n\n- `monto`: número, sin símbolo de moneda, punto como separador decimal. Siempre pesos argentinos.\n- `fecha`: cuándo se hizo la transferencia, NO cuándo se recibió el documento. Formato YYYY-MM-DD.\n- `numero_operacion`: el identificador de la operación, tal cual figura.\n- `titular_origen`: quién envía el dinero.\n- `cbu_cvu_destino`: la cuenta que RECIBE el dinero, no la que envía. Si está enmascarada, copiá exactamente lo que se ve.\n- `alias_destino`: el alias de la cuenta que recibe, si figura.\n- `banco_origen`: el banco o billetera desde donde sale el dinero.\n- `cuenta_origen`: el CBU/CVU o ALIAS desde donde sale el dinero.\n\n**Clasificación de tipo_documento**\n\n- `comprobante_transferencia`: comprobante de transferencia o pago\n- `echeque`: cheque electrónico\n- `otro_documento`: es un documento pero no un comprobante de pago (factura, remito, DNI)\n- `no_es_documento`: la imagen no es un documento\n\n# FORMATO DE SALIDA\n\nEl esquema completo, siempre, sin explicaciones alrededor. No tenés herramientas: tu única tarea es leer y reportar.",
          "passthroughBinaryImages": true,
          "passthroughBinaryPdfs": true
        }
      },
      "id": "9aa90261-cd63-48ba-b142-c6f7f29d4c41",
      "name": "Leer el comprobante",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3.1,
      "position": [
        -96,
        -96
      ]
    },
    {
      "parameters": {
        "modelName": "models/gemini-3.5-flash-lite",
        "options": {}
      },
      "id": "e350d0b9-1fe4-4386-a329-90964c6d732d",
      "name": "Modelo de lectura",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1.1,
      "position": [
        -112,
        160
      ]
    },
    {
      "parameters": {
        "jsonSchemaExample": "{\n  \"documento_recibido\": true,\n  \"tipo_documento\": \"comprobante_transferencia\",\n  \"monto\": 125430.50,\n  \"fecha\": \"2026-08-14\",\n  \"numero_operacion\": \"0012345678\",\n  \"titular_origen\": \"Carniceria San Martin SRL\",\n  \"cbu_cvu_destino\": \"0000003100083203623128\",\n  \"alias_destino\": \"\",\n  \"banco_origen\": \"Mercado Pago\",\n  \"cuenta_origen\":\"el CBU/CVU o ALIAS desde donde sale el dinero.\",\n  \"campos_ilegibles\": [\"monto\"]\n}"
      },
      "id": "e467f9b3-09c4-4b3e-b42e-9785a205d881",
      "name": "Esquema del comprobante",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "typeVersion": 1.3,
      "position": [
        80,
        160
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "o1",
              "name": "documento_recibido",
              "type": "boolean",
              "value": "={{ $json.output.documento_recibido }}"
            },
            {
              "id": "o2",
              "name": "tipo_documento",
              "type": "string",
              "value": "={{ $json.output.tipo_documento }}"
            },
            {
              "id": "o3",
              "name": "monto",
              "type": "number",
              "value": "={{ $json.output.monto}}"
            },
            {
              "id": "o4",
              "name": "fecha",
              "type": "string",
              "value": "={{ $json.output.fecha}}"
            },
            {
              "id": "o5",
              "name": "numero_operacion",
              "type": "string",
              "value": "={{ $json.output.numero_operacion }}"
            },
            {
              "id": "o6",
              "name": "titular_origen",
              "type": "string",
              "value": "={{ $json.output.titular_origen }}"
            },
            {
              "id": "o7",
              "name": "cbu_cvu_destino",
              "type": "string",
              "value": "={{ $json.output.cbu_cvu_destino }}"
            },
            {
              "id": "o8",
              "name": "alias_destino",
              "type": "string",
              "value": "={{ $json.output.alias_destino }}"
            },
            {
              "id": "o9",
              "name": "banco_origen",
              "type": "string",
              "value": "={{ $json.output.banco_origen }}"
            },
            {
              "id": "o10",
              "name": "campos_ilegibles",
              "type": "string",
              "value": "={{ ($json.output.campos_ilegibles ?? []).join(\", \") }}"
            },
            {
              "id": "b757befa-ffec-4f25-9eef-71b9ec3aa1bd",
              "name": "cuenta_origen",
              "value": "={{ $json.output.cuenta_origen }}",
              "type": "string"
            },
            {
              "id": "o11",
              "name": "listo_para_registrar",
              "type": "boolean",
              "value": "={{ $json.output.tipo_documento === \"comprobante_transferencia\" && ($json.output.campos_ilegibles ?? []).length === 0 && !!$json.output.monto && !!$json.output.fecha && !!$json.output.numero_operacion && !!$json.output.titular_origen && (!!$json.output.cbu_cvu_destino || !!$json.output.alias_destino) }}"
            },
            {
              "id": "o12",
              "name": "motivo",
              "type": "string",
              "value": "={{ $json.output.tipo_documento !== \"comprobante_transferencia\" ? \"no_es_comprobante_de_transferencia\" : ($json.output.campos_ilegibles ?? []).length > 0 ? \"campos_ilegibles: \" + ($json.output.campos_ilegibles ?? []).join(\", \") : (!$json.output.monto || !$json.output.fecha || !$json.output.numero_operacion || !$json.output.titular_origen) ? \"faltan_datos_obligatorios\" : (!$json.output.cbu_cvu_destino && !$json.output.alias_destino) ? \"sin_cuenta_destino\" : \"ok\" }}"
            }
          ]
        },
        "options": {}
      },
      "id": "089c150a-a6a5-4930-9641-eac6103150d4",
      "name": "Salida · comprobante leido",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        256,
        -96
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "d1",
              "name": "documento_recibido",
              "type": "boolean",
              "value": "false"
            },
            {
              "id": "d2",
              "name": "tipo_documento",
              "type": "string",
              "value": ""
            },
            {
              "id": "d3",
              "name": "monto",
              "type": "number",
              "value": 0
            },
            {
              "id": "d4",
              "name": "fecha",
              "type": "string",
              "value": ""
            },
            {
              "id": "d5",
              "name": "numero_operacion",
              "type": "string",
              "value": ""
            },
            {
              "id": "d6",
              "name": "titular_origen",
              "type": "string",
              "value": ""
            },
            {
              "id": "d7",
              "name": "cbu_cvu_destino",
              "type": "string",
              "value": ""
            },
            {
              "id": "d8",
              "name": "alias_destino",
              "type": "string",
              "value": ""
            },
            {
              "id": "d9",
              "name": "banco_origen",
              "type": "string",
              "value": ""
            },
            {
              "id": "d10",
              "name": "campos_ilegibles",
              "type": "string",
              "value": ""
            },
            {
              "id": "d11",
              "name": "listo_para_registrar",
              "type": "boolean",
              "value": "false"
            },
            {
              "id": "d12",
              "name": "motivo",
              "type": "string",
              "value": "documento_no_recibido"
            },
            {
              "id": "d13",
              "name": "cuenta_origen",
              "type": "string",
              "value": ""
            }
          ]
        },
        "options": {}
      },
      "id": "4f022c41-bf1e-45c5-9a34-6f29f6e8f43b",
      "name": "Salida · no se pudo descargar",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -320,
        272
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "f1",
              "name": "documento_recibido",
              "type": "boolean",
              "value": "false"
            },
            {
              "id": "f2",
              "name": "tipo_documento",
              "type": "string",
              "value": "no_es_documento"
            },
            {
              "id": "f3",
              "name": "monto",
              "type": "number",
              "value": 0
            },
            {
              "id": "f4",
              "name": "fecha",
              "type": "string",
              "value": ""
            },
            {
              "id": "f5",
              "name": "numero_operacion",
              "type": "string",
              "value": ""
            },
            {
              "id": "f6",
              "name": "titular_origen",
              "type": "string",
              "value": ""
            },
            {
              "id": "f7",
              "name": "cbu_cvu_destino",
              "type": "string",
              "value": ""
            },
            {
              "id": "f8",
              "name": "alias_destino",
              "type": "string",
              "value": ""
            },
            {
              "id": "f9",
              "name": "banco_origen",
              "type": "string",
              "value": ""
            },
            {
              "id": "f10",
              "name": "campos_ilegibles",
              "type": "string",
              "value": ""
            },
            {
              "id": "f11",
              "name": "listo_para_registrar",
              "type": "boolean",
              "value": "false"
            },
            {
              "id": "f12",
              "name": "motivo",
              "type": "string",
              "value": "formato_no_soportado"
            },
            {
              "id": "f13",
              "name": "cuenta_origen",
              "type": "string",
              "value": ""
            }
          ]
        },
        "options": {}
      },
      "id": "68a45b85-87e3-42cc-b9e6-e5f93e516234",
      "name": "Salida · formato no soportado",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -608,
        112
      ]
    },
    {
      "parameters": {
        "content": "## LEER COMPROBANTE\n### Sub-workflow del bot de WhatsApp\n\n**Por que esto es un workflow y no un sub-agente.**\n\nUn agente anidado como herramienta recibe TEXTO. Nunca el binario del padre. Por eso no puede ver una imagen y termina inventando datos para completar el esquema.\n\nUn sub-workflow, en cambio, tiene su propio main path. El binario vive aca adentro y el agente lo ve de verdad.\n\nEl bot de arriba solo intercambia JSON con este workflow: manda media_url y content_type, recibe el esquema.",
        "height": 620,
        "width": 460,
        "color": 7
      },
      "id": "5a42506b-0b5f-49bd-9d35-7e6c486e39c5",
      "name": "Sticky Note 393bc01a",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1600,
        -160
      ]
    },
    {
      "parameters": {
        "content": "### El contrato de salida\n\nLas TRES salidas devuelven **exactamente los mismos campos**. El que llama nunca tiene que adivinar la forma.\n\n**`documento_recibido`** le da al modelo una forma de decir \"no lo vi\", en vez de obligarlo a inventar un comprobante verosimil.\n\n**`listo_para_registrar`** es la decision, y la calcula un nodo, no el modelo.\n\nLa regla real: monto, fecha, numero_operacion y titular son obligatorios. De cuenta destino alcanza con **CBU/CVU O alias**, uno de los dos. Casi ningun comprobante trae los dos.\n\n**`motivo`** dice por que no, en una sola palabra.",
        "height": 340,
        "width": 380,
        "color": 4
      },
      "id": "7e418dc1-9c81-43a8-921c-54aa6dc12c6f",
      "name": "Sticky Note e48d8a84",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        640,
        96
      ]
    },
    {
      "parameters": {
        "content": "### El chequeo barato va primero\n\nEl filtro de formato es una REGLA y corre antes de bajar el archivo.\n\nUn audio o un sticker nunca son un comprobante. Descargarlos y mandarlos al modelo es gastar tiempo y tokens en algo que ya sabemos que va a fallar.",
        "height": 280,
        "width": 360,
        "color": 5
      },
      "id": "97625a95-e7f1-4e19-a06d-3f194e7d385f",
      "name": "Sticky Note bf87f793",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -912,
        -416
      ]
    },
    {
      "parameters": {
        "content": "### Cuidado con los arrays en modo ejemplo\n\nEl parser infiere el tipo mirando el ejemplo, y ese esquema viaja a Gemini como **function declaration**.\n\nUn array vacio en el ejemplo:\n\n`\"campos_ilegibles\": []`\n\nno le dice a nadie que hay adentro. n8n emite `{type: array}` sin `items`, y Gemini rechaza el request entero con un 400, antes de llamar al modelo.\n\n**Siempre dejar al menos un elemento de muestra** en un array del ejemplo. El valor no obliga al modelo a devolver eso, solo tipa el campo.\n\nPor eso el ejemplo dice `[\"monto\"]` aunque lo normal sea que venga vacio.",
        "height": 572,
        "width": 400,
        "color": 3
      },
      "id": "7de7c36a-2e9a-4e01-94fd-ff5681d496e2",
      "name": "Nota · El ejemplo del esquema",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -16,
        528
      ]
    }
  ],
  "connections": {
    "Entrada · datos del adjunto": {
      "main": [
        [
          {
            "node": "Gate · Formato procesable",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gate · Formato procesable": {
      "main": [
        [
          {
            "node": "Descargar el adjunto",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Salida · formato no soportado",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Descargar el adjunto": {
      "main": [
        [
          {
            "node": "Leer el comprobante",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Salida · no se pudo descargar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Leer el comprobante": {
      "main": [
        [
          {
            "node": "Salida · comprobante leido",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Modelo de lectura": {
      "ai_languageModel": [
        [
          {
            "node": "Leer el comprobante",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Esquema del comprobante": {
      "ai_outputParser": [
        [
          {
            "node": "Leer el comprobante",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate",
    "availableInMCP": true
  },
  "versionId": "d5298d8b-81a8-4c10-8a7c-3a081d3a97e7",
  "meta": {
    "aiBuilderAssisted": true,
    "builderVariant": "mcp",
    "instanceId": "5368e3d42db5094d7b9c43512651646c73789011a338d7142afe9f0fc528d5ec"
  },
  "nodeGroups": [],
  "id": "tkxQt52xVrWUM3j9",
  "tags": []
}
