8
n8n 中文网amn8n.com

发票处理系统用于提交

高级

这是一个Invoice Processing, AI Summarization领域的自动化工作流,包含 24 个节点。主要使用 If, Code, Xero, Gmail, Slack 等节点。 通过 Gmail、OCR.space、Slack 和 Xero 实现发票处理的自动化

前置要求
  • Google 账号和 Gmail API 凭证
  • Slack Bot Token 或 Webhook URL
  • 可能需要目标 API 的认证凭证
  • Google Sheets API 凭证
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "id": "QHTTTSIjepK3ipPO",
  "meta": {
    "instanceId": "a9990cea8ba499cd2caa870c8ec5e719a88b31e6ed62907b6084053e5dc1857a",
    "templateCredsSetupCompleted": true
  },
  "name": "发票处理系统用于提交",
  "tags": [
    {
      "id": "CMJL1dF3mMlRu0Jb",
      "name": "Invoice Processing",
      "createdAt": "2025-10-11T20:13:04.997Z",
      "updatedAt": "2025-10-11T20:13:04.997Z"
    }
  ],
  "nodes": [
    {
      "id": "189e9199-b377-4acc-a0e7-d5769e69a762",
      "name": "Gmail 触发器",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        -96,
        16
      ],
      "parameters": {
        "simple": false,
        "filters": {
          "q": "has:attachment filename:pdf"
        },
        "options": {
          "downloadAttachments": true
        },
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        }
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "d2kfFLUV2qlW2o43",
          "name": "Gmail account"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "7c5278ea-c32f-4f55-9ba4-4448c06c21f0",
      "name": "JavaScript 代码",
      "type": "n8n-nodes-base.code",
      "position": [
        80,
        16
      ],
      "parameters": {
        "jsCode": "// Get email data\nconst email = $input.item.json;\nconst binary = $input.item.binary;\n\n// Check if we have binary attachments\nif (!binary || Object.keys(binary).length === 0) {\n  return { \n    json: { \n      error: 'No invoice attachment found',\n      emailId: email.id,\n      emailSubject: email.subject\n    } \n  };\n}\n\n// Find first PDF or image attachment\nlet invoiceFile = null;\nlet invoiceKey = null;\n\nfor (const key in binary) {\n  const file = binary[key];\n  if (file.mimeType?.includes('pdf') || \n      file.mimeType?.includes('image') ||\n      file.mimeType?.includes('png') ||\n      file.mimeType?.includes('jpg')) {\n    invoiceFile = file;\n    invoiceKey = key;\n    break;\n  }\n}\n\nif (!invoiceFile) {\n  return { \n    json: { \n      error: 'No PDF or image attachment found',\n      emailId: email.id,\n      emailSubject: email.subject\n    } \n  };\n}\n\n// The binary data in n8n is already base64 encoded\n// Just use it directly without re-encoding\nlet base64Data = invoiceFile.data;\n\n// If it's a Buffer, convert to base64 string\nif (Buffer.isBuffer(base64Data)) {\n  base64Data = base64Data.toString('base64');\n}\n\n// Build the data URL for OCR.space\nconst dataUrl = `data:${invoiceFile.mimeType};base64,${base64Data}`;\n\nreturn {\n  json: {\n    emailId: email.id,\n    emailSubject: email.subject,\n    emailFrom: email.from,\n    emailDate: email.date,\n    attachmentData: base64Data,\n    attachmentName: invoiceFile.fileName,\n    mimeType: invoiceFile.mimeType,\n    dataUrl: dataUrl\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "4ddb1479-1b7f-4f8d-ad41-1a92654c98c8",
      "name": "在表格中追加或更新行",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1296,
        -48
      ],
      "parameters": {
        "columns": {
          "value": {
            "Amount": "={{ $json.amount }}",
            "Status": "Pending",
            "Vendor": "={{ $json.vendor }}",
            "Currency": "={{ $json.currency }}",
            "Due Date": "={{ $json.dueDate }}",
            "Email ID": "={{ $node[\"Code in JavaScript\"].json.emailId }}",
            "Timestamp": "={{ $now.format('yyyy-MM-dd HH:mm:ss') }}",
            "Description": "={{ $json.description }}",
            "Invoice Date": "={{ $json.invoiceDate }}",
            "Invoice Number": "={{ $json.invoiceNumber }}"
          },
          "schema": [
            {
              "id": "Invoice Number",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Invoice Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Vendor",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Vendor",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Currency",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Currency",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Invoice Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Invoice Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Due Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Due Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Description",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Processed By",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Processed By",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Invoice Number"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1TWE856dG0g0bSRr3M4SKPcpnJ32veWlq3m_DWJoSaTQ/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "=\"YOUR_SPREADSHEET_ID\""
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "hVo2bSobLUbf5b3a",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "abea5730-c60f-47f4-83b3-50cb42c6c9e0",
      "name": "Slack 审批请求",
      "type": "n8n-nodes-base.slack",
      "position": [
        1904,
        -48
      ],
      "webhookId": "4f4fa1f8-f072-4ceb-b802-68904622847d",
      "parameters": {
        "select": "channel",
        "message": "=🧾 *New Invoice Requires Approval*\n\n*Vendor:* {{ $json.vendor }}\n*Amount:* ${{ $json.amount }} {{ $json.currency }}\n*Invoice #:* {{ $json.invoiceNumber }}\n*Due Date:* {{ $json.dueDate }}\n*Description:* {{ $json.description }}",
        "options": {},
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C09LDKZJGBB",
          "cachedResultName": "invoice-approvals"
        },
        "operation": "sendAndWait",
        "authentication": "oAuth2",
        "approvalOptions": {
          "values": {
            "approvalType": "double"
          }
        }
      },
      "credentials": {
        "slackOAuth2Api": {
          "id": "plTTzKNjrWG2CYjh",
          "name": "Slack account"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "955f6439-8d79-4f9f-b35c-7bf3e39f6aad",
      "name": "Slack 拒绝消息",
      "type": "n8n-nodes-base.slack",
      "position": [
        1296,
        144
      ],
      "webhookId": "e4b6a100-ab6c-4908-8909-a37c5c210aad",
      "parameters": {
        "text": "=Channel: #invoice-approvals\n\nText:\n❌ *Invoice Auto-Rejected*\n\nAn invoice was rejected by AI analysis:\n\n- From: {{ $node[\"Code in JavaScript\"].json.emailFrom }}\n- Subject: {{ $node[\"Code in JavaScript\"].json.emailSubject }}\n- Reason: Did not pass qualification checks\n- Confidence: {{ $json.confidence }}%\n- Red Flags: {{ $json.redFlags.join(', ') }}\n\nThe email has been labeled \"Rejected\" in Gmail.",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C09LDKZJGBB",
          "cachedResultName": "invoice-approvals"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "id": "plTTzKNjrWG2CYjh",
          "name": "Slack account"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "424382f8-ff99-457e-9714-569c83e29157",
      "name": "检查资格",
      "type": "n8n-nodes-base.if",
      "position": [
        1040,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "1237bc0c-6f1a-4a3b-98ff-45369c8ebc06",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.qualified }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "be9d4c45-2bb3-4ca4-944e-65045fa75a60",
      "name": "解析发票数据",
      "type": "n8n-nodes-base.code",
      "position": [
        720,
        0
      ],
      "parameters": {
        "jsCode": "// Get OCR result\nconst ocrResult = $json;\n\n// Extract the text\nlet extractedText = '';\n\nif (ocrResult.ParsedResults && ocrResult.ParsedResults[0]) {\n  extractedText = ocrResult.ParsedResults[0].ParsedText;\n} else {\n  return {\n    json: {\n      error: 'OCR failed to extract text',\n      qualified: false,\n      redFlags: ['Could not read invoice text']\n    }\n  };\n}\n\n// Helper function to parse dates correctly without timezone issues\nfunction parseDate(dateString) {\n  // Try to parse dates like \"October 1, 2025\"\n  const date = new Date(dateString + ' 12:00:00 UTC'); // Add noon UTC to avoid timezone shifts\n  \n  if (!isNaN(date)) {\n    const year = date.getUTCFullYear();\n    const month = String(date.getUTCMonth() + 1).padStart(2, '0');\n    const day = String(date.getUTCDate()).padStart(2, '0');\n    return `${year}-${month}-${day}`;\n  }\n  \n  return '';\n}\n\n// Parse invoice fields using regex\nconst invoiceData = {\n  qualified: true,\n  vendor: '',\n  invoiceNumber: '',\n  amount: 0,\n  currency: 'USD',\n  invoiceDate: '',\n  dueDate: '',\n  description: '',\n  confidence: 100,\n  redFlags: []\n};\n\n// Extract Vendor (line after \"From:\")\nconst vendorMatch = extractedText.match(/From:\\s*([^\\n]+)/i);\nif (vendorMatch) {\n  invoiceData.vendor = vendorMatch[1].trim();\n}\n\n// Extract Invoice Number\nconst invoiceNumMatch = extractedText.match(/Invoice Number:\\s*([^\\n]+)/i);\nif (invoiceNumMatch) {\n  invoiceData.invoiceNumber = invoiceNumMatch[1].trim();\n}\n\n// Extract Amount (from \"Total:\" line) - CRITICAL!\nconst totalMatch = extractedText.match(/Total:\\s*\\$\\s*([0-9,]+\\.?[0-9]*)/i);\nif (totalMatch) {\n  invoiceData.amount = parseFloat(totalMatch[1].replace(/,/g, ''));\n}\n\n// If Total not found, try Amount line\nif (invoiceData.amount === 0) {\n  const amountMatch = extractedText.match(/Amount:\\s*\\$\\s*([0-9,]+\\.?[0-9]*)/i);\n  if (amountMatch) {\n    invoiceData.amount = parseFloat(amountMatch[1].replace(/,/g, ''));\n  }\n}\n\n// Extract Currency\nconst currencyMatch = extractedText.match(/(USD|EUR|GBP|CAD)/i);\nif (currencyMatch) {\n  invoiceData.currency = currencyMatch[1].toUpperCase();\n}\n\n// Extract Invoice Date - FIXED!\nconst dateMatch = extractedText.match(/Date:\\s*([^\\n]+)/i);\nif (dateMatch) {\n  const dateStr = dateMatch[1].trim();\n  invoiceData.invoiceDate = parseDate(dateStr);\n}\n\n// Extract Due Date - FIXED!\nconst dueMatch = extractedText.match(/Due Date:\\s*([^\\n]+)/i);\nif (dueMatch) {\n  const dateStr = dueMatch[1].trim();\n  invoiceData.dueDate = parseDate(dateStr);\n}\n\n// Extract Description\nconst descMatch = extractedText.match(/Description:\\s*([^\\n]+)/i);\nif (descMatch) {\n  invoiceData.description = descMatch[1].trim();\n}\n\n// Validation checks\nif (!invoiceData.vendor) {\n  invoiceData.qualified = false;\n  invoiceData.redFlags.push('Missing vendor name');\n}\n\nif (!invoiceData.invoiceNumber) {\n  invoiceData.qualified = false;\n  invoiceData.redFlags.push('Missing invoice number');\n}\n\nif (invoiceData.amount === 0) {\n  invoiceData.qualified = false;\n  invoiceData.redFlags.push('Missing or invalid amount');\n}\n\nif (invoiceData.amount > 10000) {\n  invoiceData.qualified = false;\n  invoiceData.redFlags.push('Amount exceeds $10,000');\n}\n\nreturn {\n  json: invoiceData\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "36afc95e-af94-4c98-a458-744e9bfd1139",
      "name": "格式化用于 Slack",
      "type": "n8n-nodes-base.code",
      "position": [
        1504,
        -48
      ],
      "parameters": {
        "jsCode": "const sheetData = $node[\"Append or update row in sheet\"].json;\n\nreturn {\n  json: {\n    vendor: sheetData.Vendor,\n    amount: sheetData.Amount,\n    currency: sheetData.Currency,\n    invoiceNumber: sheetData[\"Invoice Number\"],\n    invoiceDate: sheetData[\"Invoice Date\"],  // ← ADD THIS LINE!\n    dueDate: sheetData[\"Due Date\"],\n    description: sheetData.Description\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "b524a093-e827-4049-b0c9-809dc839465e",
      "name": "拒绝消息",
      "type": "n8n-nodes-base.slack",
      "position": [
        2896,
        16
      ],
      "webhookId": "019dcb52-375d-4fff-9e0d-d4d5b4ac0282",
      "parameters": {
        "text": "❌ Invoice rejected",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C09LDKZJGBB",
          "cachedResultName": "invoice-approvals"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "id": "plTTzKNjrWG2CYjh",
          "name": "Slack account"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "afcf2f08-41ec-4ce5-bb32-98733317379f",
      "name": "成功消息",
      "type": "n8n-nodes-base.slack",
      "position": [
        3248,
        -176
      ],
      "webhookId": "ae7fc4b9-99a3-41ad-ba4e-4e4a15a52303",
      "parameters": {
        "text": "✅ Invoice posted to Xero",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C09LDKZJGBB",
          "cachedResultName": "invoice-approvals"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "id": "plTTzKNjrWG2CYjh",
          "name": "Slack account"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "2a70f5c0-db5f-44eb-8eb8-24c978892049",
      "name": "更新拒绝状态",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2704,
        16
      ],
      "parameters": {
        "columns": {
          "value": {
            "Status": "Rejected",
            "Invoice Number": "={{ $('Clean Invoice Payload').item.json.invoiceNumber }}"
          },
          "schema": [
            {
              "id": "Invoice Number",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Invoice Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Vendor",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Vendor",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Currency",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Currency",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Invoice Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Invoice Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Due Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Due Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Description",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Processed By",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Processed By",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Invoice Number"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1TWE856dG0g0bSRr3M4SKPcpnJ32veWlq3m_DWJoSaTQ/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "=\"YOUR_SPREADSHEET_ID\""
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "hVo2bSobLUbf5b3a",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "f775d6e5-a97b-4aea-be73-f6a3030cbfc3",
      "name": "更新批准状态",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3024,
        -176
      ],
      "parameters": {
        "columns": {
          "value": {
            "Status": "Approved",
            "Invoice Number": "={{ $('Clean Invoice Payload').item.json.invoiceNumber }}"
          },
          "schema": [
            {
              "id": "Invoice Number",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Invoice Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Vendor",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Vendor",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Currency",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Currency",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Invoice Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Invoice Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Due Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Due Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Description",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Processed By",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Processed By",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Invoice Number"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "=Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "=\"YOUR_SPREADSHEET_ID\""
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "hVo2bSobLUbf5b3a",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "b062f234-61a1-4913-8135-be9d9be322a8",
      "name": "添加已处理标签",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2832,
        -176
      ],
      "webhookId": "a5cbed4c-0c43-4bf0-8114-e8fbbf987e9e",
      "parameters": {
        "labelIds": [
          "Label_3710233975993850496"
        ],
        "messageId": "={{$node[\"Code in JavaScript\"].json.emailId}}",
        "operation": "addLabels"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "d2kfFLUV2qlW2o43",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "854afcd4-6559-4753-b75d-2a65766c492d",
      "name": "添加已拒绝标签",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2432,
        16
      ],
      "webhookId": "2e5f020d-ed42-438c-8744-4fdd602145c7",
      "parameters": {
        "labelIds": [
          "Label_8899302689673155790"
        ],
        "messageId": "={{$node[\"Code in JavaScript\"].json.emailId}}",
        "operation": "addLabels"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "d2kfFLUV2qlW2o43",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "025efb16-32dd-4a7e-8349-baef18b32040",
      "name": "获取多个联系人",
      "type": "n8n-nodes-base.xero",
      "position": [
        2416,
        -176
      ],
      "parameters": {
        "limit": 1,
        "options": {},
        "resource": "contact",
        "operation": "getAll",
        "organizationId": "=9a46b4a9-feac-446e-a04d-4e7421565898"
      },
      "credentials": {
        "xeroOAuth2Api": {
          "id": "XfSNoqDEDyivPRYX",
          "name": "Xero account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b43a1017-8ecb-4c39-b92f-8865349ccec2",
      "name": "清理发票有效载荷",
      "type": "n8n-nodes-base.code",
      "position": [
        1696,
        -48
      ],
      "parameters": {
        "jsCode": "const invoiceData = { ...$node[\"Format for Slack\"].json };\n\n// Strip off any vendor or itemCode field that might be passed\ndelete invoiceData.vendor;\ndelete invoiceData.itemCode;\ndelete invoiceData[\"Item Code Name or ID\"]; // Just in case\n\nreturn [{ json: invoiceData }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "a77a3860-e69a-428f-b74e-d926859c83e3",
      "name": "创建发票",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2624,
        -176
      ],
      "parameters": {
        "url": "https://api.xero.com/api.xro/2.0/Invoices",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"Type\": \"ACCPAY\",\n  \"Contact\": {\n    \"ContactID\": \"{{$node[\"Get many contacts\"].json.ContactID}}\"\n  },\n  \"Date\": \"{{$node[\"Format for Slack\"].json.invoiceDate}}\",\n  \"DueDate\": \"{{$node[\"Format for Slack\"].json.dueDate}}\",\n  \"InvoiceNumber\": \"{{$node[\"Format for Slack\"].json.invoiceNumber}}\",\n  \"Reference\": \"{{$node[\"Format for Slack\"].json.invoiceNumber}}\",\n  \"Status\": \"DRAFT\",\n  \"LineAmountTypes\": \"Exclusive\",\n  \"LineItems\": [\n    {\n      \"Description\": \"{{$node[\"Format for Slack\"].json.description}}\",\n      \"Quantity\": 1,\n      \"UnitAmount\": {{$node[\"Format for Slack\"].json.amount}},\n      \"AccountCode\": \"463\",\n      \"TaxType\": \"INPUT2\"\n    }\n  ]\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Accept",
              "value": "application/json"
            },
            {
              "name": "xero-tenant-id",
              "value": "=\"{{$credentials.xero.apiKey}}\""
            }
          ]
        },
        "nodeCredentialType": "xeroOAuth2Api"
      },
      "credentials": {
        "xeroOAuth2Api": {
          "id": "XfSNoqDEDyivPRYX",
          "name": "Xero account"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "270ea877-b081-4704-8137-3cbcf62606fb",
      "name": "有有效附件吗?",
      "type": "n8n-nodes-base.if",
      "position": [
        288,
        16
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5b78e677-d068-411a-8c43-e41a9725f370",
              "operator": {
                "type": "number",
                "operation": "notExists",
                "singleValue": true
              },
              "leftValue": "={{$json.error}}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4128986d-09d7-44b5-a9f5-5f8a532c1712",
      "name": "是否已批准?",
      "type": "n8n-nodes-base.if",
      "position": [
        2128,
        -48
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "b58f3729-809c-4b21-9210-6c581dbeed50",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.data.approved }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "8400ed04-51ba-4cc6-92cc-abb03a09e258",
      "name": "提取文本",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        544,
        0
      ],
      "parameters": {
        "url": "https://api.ocr.space/parse/image",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"name\": \"apikey\",\n  \"value\": \"{{$credentials.ocrspaceApi.apiKey}}\"\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "d132fdec-f017-49f6-a4bc-8a938df37d98",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -912,
        -464
      ],
      "parameters": {
        "width": 608,
        "height": 1696,
        "content": "### 使用 Gmail、OCR.space、Slack 和 Xero 自动化发票处理"
      },
      "typeVersion": 1
    },
    {
      "id": "b16d6e58-0125-4735-b939-040945fcc89b",
      "name": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1008,
        -336
      ],
      "parameters": {
        "width": 1248,
        "height": 640,
        "content": "## 2. 在 Slack 中批准或拒绝发票"
      },
      "typeVersion": 1
    },
    {
      "id": "af22b982-18c5-4adc-9e88-d7ecf53f357c",
      "name": "便签2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -144,
        -336
      ],
      "parameters": {
        "width": 1120,
        "height": 640,
        "content": "## 1. 从 Gmail 提取和解析发票"
      },
      "typeVersion": 1
    },
    {
      "id": "422c5b66-d77a-4224-b689-e4b57152373e",
      "name": "便签3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2288,
        -336
      ],
      "parameters": {
        "width": 1168,
        "height": 640,
        "content": "## 3. 将结果同步到 Xero 并通知"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "a1d9da45-06e7-460c-9c56-bc430ee568b6",
  "connections": {
    "Extract Text": {
      "main": [
        [
          {
            "node": "Parse Invoice Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail Trigger": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Was Approved?": {
      "main": [
        [
          {
            "node": "Get many contacts",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Add Rejected label",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create invoice": {
      "main": [
        [
          {
            "node": "Add Processed label",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format for Slack": {
      "main": [
        [
          {
            "node": "Clean Invoice Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get many contacts": {
      "main": [
        [
          {
            "node": "Create invoice",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Rejected label": {
      "main": [
        [
          {
            "node": "Update Rejected Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Has Valid Attachment?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Invoice Data": {
      "main": [
        [
          {
            "node": "Check Qualification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Processed label": {
      "main": [
        [
          {
            "node": "Update Approved Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Qualification": {
      "main": [
        [
          {
            "node": "Append or update row in sheet",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Slack Rejection message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Clean Invoice Payload": {
      "main": [
        [
          {
            "node": "Slack Approval Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Valid Attachment?": {
      "main": [
        [
          {
            "node": "Extract Text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack Approval Request": {
      "main": [
        [
          {
            "node": "Was Approved?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Approved Status": {
      "main": [
        [
          {
            "node": "Success message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Rejected Status": {
      "main": [
        [
          {
            "node": "Rejection message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append or update row in sheet": {
      "main": [
        [
          {
            "node": "Format for Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

高级 - 发票处理, AI 摘要总结

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
高级
节点数量24
分类2
节点类型9
难度说明

适合高级用户,包含 16+ 个节点的复杂工作流

作者
Abi Odedeyi

Abi Odedeyi

@abiodedeyi

Automation Builder with extensive experience helping businesses streamline processes and generate revenue.

外部链接
在 n8n.io 查看

分享此工作流