{
  "name": "1 - Emision y Autorizacion en Tiempo Real",
  "nodes": [
    {
      "parameters": {
        "url": "={{ $('Preparar Respuesta Final').item.json.urlRide }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file",
              "outputPropertyName": "rideData"
            }
          }
        }
      },
      "id": "7f2a18f7-017f-420b-84d7-297eb9d266f3",
      "name": "Descargar RIDE (PDF)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        320,
        -496
      ],
      "executeOnce": true,
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "url": "={{ $('Preparar Respuesta Final').item.json.urlXml }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file",
              "outputPropertyName": "xmlData"
            }
          }
        }
      },
      "id": "19ac47f6-f468-482f-8fac-fc1998f56762",
      "name": "Descargar XML",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        480,
        -496
      ],
      "executeOnce": false,
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "inputDataFieldName": "rideData",
        "name": "={{ $json.claveAcceso + '_RIDE.pdf' }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "folderId": {
          "__rl": true,
          "value": "1mN1YwRk9Qdgh_V5P0TB3XYh9VGu3xUws",
          "mode": "id"
        },
        "options": {}
      },
      "id": "8e0e466a-9bed-4320-ba60-c1523713e6b4",
      "name": "Respaldar RIDE en Drive",
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        560,
        -272
      ],
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "inputDataFieldName": "xmlData",
        "name": "={{ $json.claveAcceso + '_XML.xml' }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "folderId": {
          "__rl": true,
          "value": "1mN1YwRk9Qdgh_V5P0TB3XYh9VGu3xUws",
          "mode": "id"
        },
        "options": {}
      },
      "id": "9fe64a78-e8c0-4cb9-bd17-958be6056d92",
      "name": "Respaldar XML en Drive",
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        720,
        -272
      ],
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "facturar",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "13c11157-49d1-46e4-85ae-21ebd7ea3dd1",
      "name": "Webhook Recibir Factura",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        -1376,
        -512
      ]
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all();\n\nconst factura = items[0].json.body ?? items[0].json;\n\n// ============================================================\n// MANEJO DEL LOGO\n// ============================================================\n// Conservamos el Data URL completo:\n// data:image/png;base64,XXXX\n// data:image/jpeg;base64,XXXX\n// data:image/webp;base64,XXXX\n//\n// Esto permite que el server.js detecte correctamente el formato.\n// ============================================================\n\nif (!factura.emisor) {\n  factura.emisor = {};\n}\n\nif (factura.emisor.logo) {\n  const logoStr = String(factura.emisor.logo).trim();\n\n  // NO eliminamos \"data:image/...;base64,\"\n  // Se conserva el Data URL completo.\n  factura.emisor.logo = logoStr;\n}\n\n// ============================================================\n// FECHA DE EMISI\u00d3N\n// ============================================================\n\nconst fecha = new Date(\n  factura.fechaEmision || Date.now()\n);\n\nconst dd = String(\n  fecha.getDate()\n).padStart(2, '0');\n\nconst mm = String(\n  fecha.getMonth() + 1\n).padStart(2, '0');\n\nconst yyyy = String(\n  fecha.getFullYear()\n);\n\nconst fechaEmisionStr =\n  `${dd}${mm}${yyyy}`;\n\n// ============================================================\n// DATOS DEL COMPROBANTE\n// ============================================================\n\nconst tipoComprobante = '01';\n\nconst ruc = String(\n  factura.emisor.ruc ||\n  '1792146739001'\n)\n  .padStart(13, '0')\n  .slice(0, 13);\n\nconst ambiente = '1';\n\nconst establecimiento = String(\n  factura.emisor.establecimiento ||\n  '001'\n)\n  .padStart(3, '0');\n\nconst puntoEmision = String(\n  factura.emisor.puntoEmision ||\n  '001'\n)\n  .padStart(3, '0');\n\n// ============================================================\n// SECUENCIAL\n// ============================================================\n\nconst staticData =\n  $getWorkflowStaticData('global');\n\nstaticData.secuencial =\n  (staticData.secuencial || 0) + 1;\n\nconst secuencial = String(\n  staticData.secuencial\n).padStart(9, '0');\n\n// ============================================================\n// C\u00d3DIGO NUM\u00c9RICO\n// ============================================================\n\nconst codigoNumerico = String(\n  Math.floor(\n    Math.random() * 100000000\n  )\n).padStart(8, '0');\n\nconst tipoEmision = '1';\n\n// ============================================================\n// GENERAR CLAVE DE ACCESO DE 48 D\u00cdGITOS\n// ============================================================\n\nconst clave48 =\n  fechaEmisionStr +\n  tipoComprobante +\n  ruc +\n  ambiente +\n  establecimiento +\n  puntoEmision +\n  secuencial +\n  codigoNumerico +\n  tipoEmision;\n\n// ============================================================\n// M\u00d3DULO 11\n// ============================================================\n\nfunction calcularDigitoVerificadorModulo11(clave) {\n\n  const factores = [\n    2,\n    3,\n    4,\n    5,\n    6,\n    7,\n  ];\n\n  let factorIndex = 0;\n  let suma = 0;\n\n  for (\n    let i = clave.length - 1;\n    i >= 0;\n    i--\n  ) {\n\n    const digito = parseInt(\n      clave[i],\n      10\n    );\n\n    suma +=\n      digito *\n      factores[factorIndex];\n\n    factorIndex =\n      (factorIndex + 1) %\n      factores.length;\n  }\n\n  const modulo =\n    suma % 11;\n\n  let verificador =\n    11 - modulo;\n\n  if (verificador === 11) {\n    verificador = 0;\n  }\n\n  if (verificador === 10) {\n    verificador = 1;\n  }\n\n  return String(\n    verificador\n  );\n}\n\n// ============================================================\n// CLAVE DE ACCESO FINAL\n// ============================================================\n\nconst digitoVerificador =\n  calcularDigitoVerificadorModulo11(\n    clave48\n  );\n\nconst claveAcceso =\n  clave48 +\n  digitoVerificador;\n\n// ============================================================\n// VALIDAR LONGITUD\n// ============================================================\n\nif (\n  claveAcceso.length !== 49\n) {\n  throw new Error(\n    `La clave de acceso generada no tiene 49 digitos: ${claveAcceso.length}`\n  );\n}\n\n// ============================================================\n// SALIDA\n// ============================================================\n\nreturn [\n  {\n    json: {\n      claveAcceso,\n      secuencial,\n      factura,\n    },\n  },\n];"
      },
      "id": "1a761dc1-0f79-4e69-bcca-daff604ec2fe",
      "name": "Generar Clave de Acceso",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -1200,
        -512
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://localhost:4000/api/sri/recepcion",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { \"claveAcceso\": $json.claveAcceso, \"factura\": $json.factura } }}",
        "options": {}
      },
      "id": "6aa37cfa-bd80-4059-906a-7489a3d36943",
      "name": "SRI Recepcion",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -1024,
        -512
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 1
          },
          "conditions": [
            {
              "id": "cond-recepcion-ok",
              "leftValue": "={{ $json.estado }}",
              "rightValue": "RECIBIDA",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "ec94f359-2a3c-4f57-8eb7-5df0f9e8cb4b",
      "name": "Recepcion OK?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        -864,
        -496
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://localhost:4000/api/sri/autorizacion",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { \"claveAcceso\": $('Generar Clave de Acceso').item.json.claveAcceso } }}",
        "options": {}
      },
      "id": "234d87f7-63f6-4aa8-bcb8-47d4fbac7044",
      "name": "SRI Autorizacion",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -672,
        -512
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://localhost:4000/api/sri/generar-xml",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { \"claveAcceso\": $('Generar Clave de Acceso').item.json.claveAcceso, \"factura\": $('Generar Clave de Acceso').item.json.factura } }}",
        "options": {}
      },
      "id": "243fa2bf-94cb-4fbb-bcca-16878801ee18",
      "name": "SRI Generar XML",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -512,
        -512
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://localhost:4000/api/sri/generar-ride",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ {\n  \"claveAcceso\": $('Generar Clave de Acceso').item.json.claveAcceso,\n  \"factura\": $('Generar Clave de Acceso').item.json.factura\n} }}",
        "options": {}
      },
      "id": "86580e13-82c3-4517-84d2-1567eb990701",
      "name": "SRI Generar RIDE",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -352,
        -512
      ]
    },
    {
      "parameters": {
        "jsCode": "// Captura segura de datos previos usando .first()\nconst clave = $('Generar Clave de Acceso').first()?.json?.claveAcceso || '';\nconst factura = $('Generar Clave de Acceso').first()?.json?.factura || $('Webhook Recibir Factura').first()?.json?.body || {};\nconst autorizacion = $('SRI Autorizacion').first()?.json || {};\nconst xml = $('SRI Generar XML').first()?.json || {};\nconst ride = $('SRI Generar RIDE').first()?.json || {};\n\n// Capturamos la IA de forma ultra-segura desde el nodo AI Agent\nlet categoriaIa = 'General';\nlet asuntoEmail = '';\nlet cuerpoEmail = '';\n\ntry {\n  const aiItem = $('AI Agent').first()?.json;\n  if (aiItem && aiItem.output) {\n    const aiOutput = aiItem.output;\n    const aiData = typeof aiOutput === 'string' ? JSON.parse(aiOutput) : aiOutput;\n    \n    categoriaIa = aiData.categoria || 'General';\n    asuntoEmail = aiData.asunto_email || '';\n    cuerpoEmail = aiData.cuerpo_email || '';\n  }\n} catch (e) {\n  console.log(\"No se pudo parsear el resultado del AI Agent, usando valores por defecto.\");\n}\n\nreturn [\n  {\n    json: {\n      ok: true,\n      claveAcceso: clave,\n      factura: factura,\n      numeroAutorizacion: autorizacion.numeroAutorizacion || clave,\n      fechaAutorizacion: autorizacion.fechaAutorizacion || new Date().toISOString(),\n      urlRide: ride.urlRide || '',\n      urlXml: xml.urlXml || '',\n      // Enviamos la categor\u00eda en todas sus posibles variantes de nombre:\n      categoria: categoriaIa,\n      categoriaIa: categoriaIa,\n      categoria_ia: categoriaIa,\n      asunto: asuntoEmail || 'Factura Electr\u00f3nica Emitida',\n      mensaje: cuerpoEmail || 'Comprobante autorizado correctamente.',\n    },\n  },\n];"
      },
      "id": "fcae8117-460b-4322-b808-d5c3f94a4793",
      "name": "Preparar Respuesta Final",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        128,
        -624
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ $('Preparar Respuesta Final').item.json }}",
        "options": {}
      },
      "id": "a30ec880-7772-421c-9a56-67f550455ea4",
      "name": "Responder al Cliente",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        304,
        -704
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ { \"ok\": false, \"mensaje\": \"El SRI simulado rechazo el comprobante. Intenta nuevamente.\" } }}",
        "options": {
          "responseCode": 502
        }
      },
      "id": "e3fe27a2-01de-4a9a-92df-f19ed0b66e41",
      "name": "Responder Error",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        -720,
        -336
      ]
    },
    {
      "parameters": {
        "fromEmail": "kam.santana@yavirac.edu.ec",
        "toEmail": "={{ $('Preparar Respuesta Final').first().json.factura.cliente.correo }}",
        "subject": "={{ 'Tu factura electr\u00f3nica - Clave de acceso ' + $('Preparar Respuesta Final').item.json.claveAcceso }}",
        "html": "={{ $('Preparar Respuesta Final').first().json.mensaje }}",
        "options": {
          "attachments": "rideData, xmlData"
        }
      },
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        656,
        -496
      ],
      "id": "bce40f6a-f669-454a-812b-d46927628031",
      "name": "Send an Email",
      "executeOnce": true,
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=Procesa la compra del cliente {{ $('Webhook Recibir Factura').first().json.body.cliente.nombre }} en \"PROVEEDOR FERRETERO PROFERRET S.A.S.\".\n\n\u00cdtems comprados:\n{{ JSON.stringify($('Webhook Recibir Factura').first().json.body.items) }}\n\nDetermina la categor\u00eda (Herramientas, Servicios, Insumos o General) y genera el JSON de salida con el mensaje para el correo.",
        "options": {
          "systemMessage": "Eres el asistente virtual de Inteligencia Artificial de \"PROVEEDOR FERRETERO PROFERRET S.A.S.\". Tu trabajo es analizar los \u00edtems de una factura y generar un JSON con la categor\u00eda de la compra y un mensaje amigable para el correo del cliente.\n\nREGLA OBLIGATORIA: Responde \u00daNICAMENTE un JSON v\u00e1lido sin bloques de c\u00f3digo Markdown (no incluyas ```json ni comillas alrededor del bloque).\n\nEstructura requerida:\n{\n  \"asunto_email\": \"\u00a1Gracias por tu compra en PROFERRET S.A.S.!\",\n  \"cuerpo_email\": \"Estimado/a cliente, adjunto a este correo encontrar\u00e1 su comprobante electr\u00f3nico autorizado por el SRI. \u00a1Agradecemos su preferencia!\",\n  \"categoria\": \"<CATEGORIA>\"\n}\n\nReglas estrictas para <CATEGORIA>:\n- \"Insumos\": Pinturas, brochas, lijas, clavos, tornillos, tubos, cables, cemento, pegamentos o consumibles.\n- \"Herramientas\": Taladros, martillos, alicates, sierras, llaves, herramientas manuales o el\u00e9ctricas.\n- \"Servicios\": Mano de obra, fletes, alquileres, instalaciones.\n- \"General\": Solo si no encaja en las anteriores."
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3.1,
      "position": [
        -192,
        -512
      ],
      "id": "9682437f-8ff7-4752-8055-9a9a1f6e30c7",
      "name": "AI Agent"
    },
    {
      "parameters": {
        "model": "llama-3.1-8b-instant",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGroq",
      "typeVersion": 1,
      "position": [
        -192,
        -272
      ],
      "id": "7ac9ea7b-8027-49b7-b3e4-0b119485484e",
      "name": "Groq Chat Model",
      "credentials": {
        "groqApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://localhost:4000/api/sri/actualizar-ia",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"claveAcceso\": \"{{ $('SRI Autorizacion').first().json.claveAcceso || $('Generar Clave de Acceso').first().json.claveAcceso }}\",\n  \"categoriaIa\": \"{{ (() => { const raw = $json.output || $json.text || ''; if (raw.includes('Herramientas')) return 'Herramientas'; if (raw.includes('Servicios')) return 'Servicios'; if (raw.includes('Insumos')) return 'Insumos'; return 'General'; })() }}\",\n  \"estadoIa\": \"OK\",\n  \"iaOutput\": \"Clasificado exitosamente por el Agente IA Groq\"\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        128,
        -384
      ],
      "id": "ac80de2e-ca03-43c3-94b6-285d0d9212eb",
      "name": "HTTP Request"
    }
  ],
  "connections": {
    "Descargar RIDE (PDF)": {
      "main": [
        [
          {
            "node": "Descargar XML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Descargar XML": {
      "main": [
        [
          {
            "node": "Send an Email",
            "type": "main",
            "index": 0
          },
          {
            "node": "Respaldar RIDE en Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Respaldar RIDE en Drive": {
      "main": [
        [
          {
            "node": "Respaldar XML en Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook Recibir Factura": {
      "main": [
        [
          {
            "node": "Generar Clave de Acceso",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generar Clave de Acceso": {
      "main": [
        [
          {
            "node": "SRI Recepcion",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SRI Recepcion": {
      "main": [
        [
          {
            "node": "Recepcion OK?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Recepcion OK?": {
      "main": [
        [
          {
            "node": "SRI Autorizacion",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Responder Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SRI Autorizacion": {
      "main": [
        [
          {
            "node": "SRI Generar XML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SRI Generar XML": {
      "main": [
        [
          {
            "node": "SRI Generar RIDE",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SRI Generar RIDE": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Preparar Respuesta Final": {
      "main": [
        [
          {
            "node": "Responder al Cliente",
            "type": "main",
            "index": 0
          },
          {
            "node": "Descargar RIDE (PDF)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Respaldar XML en Drive": {
      "main": [
        []
      ]
    },
    "AI Agent": {
      "main": [
        [
          {
            "node": "Preparar Respuesta Final",
            "type": "main",
            "index": 0
          },
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Groq Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Send an Email": {
      "main": [
        []
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate"
  },
  "versionId": "a8c1ea88-7705-44a4-b14f-411bc285d3d4",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "IONb602IFhwXa2W0",
  "tags": []
}