2026-09-15 · 原文发布日
供应商发票自动核对与异常退回
n8n监视Gmail指定标签下的发票邮件,筛出PDF提取文本后由OpenAI转成供应商、发票号、PO号、税额、明细行等结构化字段,再对照Google Sheets里的供应商主数据、未结采购订单与已入账记录跑八项检查(重复、税额、PO匹配、日期合理性等);全过且金额在限额内直接入账,超额发Slack求人工签核,不合格则记入异常表并把问题清单回邮供应商。
原文要点
原模板由Hamza Jamal Janjua发布,流程为:Gmail指定标签收到带附件邮件触发,过滤PDF并提取文本,OpenAI把发票文本转成供应商、发票号、PO号、日期、币种、总额与明细行等结构化字段;再从Google Sheets读SupplierMaster、OpenPurchaseOrders、Ledger三表跑重复、税额、PO匹配、日期合理性等八项检查。全过且金额低于限额写入Ledger,超额发Slack求人工签核,任一失败写入Exceptions并把编号问题清单回邮供应商。阈值集中在Code节点顶部:小计加税的舍入容差、超PO比例、发票最大账龄、签核限额、合法税率(默认0和5,面向阿联酋)。
这次做成什么
在本站练成一套可跑通的发票自动核对流程:从收信、提取、八项校验到入账/签核/退回三分支全部连通,并用一张合成测试发票验证三条路径各自走到正确出口。
准备什么
- 一个可收信的Gmail账号,并建好专门接收发票的标签,记住其标签ID
- OpenAI API凭据,用于发票文本结构化提取
- 一个Google Sheets,含SupplierMaster、OpenPurchaseOrders、Ledger、Exceptions四个分页且列名齐全
- 一个Slack工作区及应付账款频道,用于超额签核与异常告警
- n8n实例(自托管或云)并能配置Gmail Trigger
具体怎么做
接触发器并限定标签
新建工作流,放Gmail Trigger,绑定Gmail凭据,把Label IDs设为发票专用标签ID,选项里打开附件下载。手工把一封带PDF的测试邮件打上该标签,点Execute previous node确认能拿到邮件与附件二进制。
过滤PDF并提取文本
接IF节点判断附件mimeType等于application/pdf,非PDF直接忽略;PDF分支接Extract from File节点读取文本。输出应为整段发票纯文本,若为空说明PDF是扫描件,需要另接OCR,这是本流程的已知边界。
OpenAI结构化提取
用OpenAI节点,提示词要求只返回JSON:supplier_name、invoice_number、po_number、invoice_date、currency、subtotal、tax_amount、total、line_items数组。后面接Set或Code节点把JSON.parse结果铺平成字段,供校验使用。
读三表跑八项检查
用三个Google Sheets节点分别读SupplierMaster(supplier_name、supplier_email、po_required、default_approver)、OpenPurchaseOrders(po_number、remaining_value、currency、approver_email)、Ledger(已入账记录)。接Code节点,把阈值常量写在顶部,依次检查:发票号是否已在Ledger重复、小计加税是否等于总额(容差内)、税率是否在VALID_TAX_RATES内、PO是否存在、金额是否超PO剩余值过多、发票日期是否过老、供应商是否在主数据、必填字段是否缺失;每条失败push进failures数组。
三分支输出
Code节点后接Switch:failures为空且total≤APPROVAL_LIMIT走Ledger分支,用Google Sheets追加一行入账;failures为空但超额走Slack分支,向应付频道发含发票号、金额、default_approver的签核请求;failures非空走异常分支,先追加到Exceptions表,再用Gmail节点按supplier_email回邮,正文把failures编号列出请供应商更正。
用合成数据端到端验证
先用金额低于限额且PO完全匹配的测试发票跑一遍,确认Ledger多一行;再把金额改到限额以上重跑,确认Slack收到消息;最后把税率改成VALID_TAX_RATES之外的值重跑,确认Exceptions新增记录且供应商邮箱收到编号问题清单。
可直接复制的材料
Code节点顶部阈值配置(独立示例)
本站独立编写的示例骨架,非原模板文件;具体字段名与节点连接需对照原模板核对。
// 站点独立编写的阈值示例,数值请按本公司财务政策替换
const ROUNDING_TOLERANCE = 0.02; // 小计+税与总额允许差
const PO_OVERSHOOT_PCT = 0.05; // 发票可超PO剩余值的比例
const MAX_INVOICE_AGE_DAYS = 90; // 发票最大账龄
const APPROVAL_LIMIT = 5000; // 超过此金额需Slack人工签核
const VALID_TAX_RATES = [0, 5]; // 原模板默认面向阿联酋,改成本国税率
const failures = [];
// 检查示例:把每个不通过项push进failures,将成为回邮中的一行
if (Math.abs(inv.subtotal + inv.tax_amount - inv.total) > ROUNDING_TOLERANCE) {
failures.push('小计加税不等于发票总额,差额超出容差');
}
if (!VALID_TAX_RATES.includes(inv.tax_rate)) {
failures.push('税率 ' + inv.tax_rate + '% 不在合法税率清单内');
}
return [{ json: { ...inv, failures } }];SupplierMaster与OpenPurchaseOrders合成测试数据
全部为虚构合成数据,仅用于测试;邮箱域名请勿用于真实发送。
SupplierMaster 分页(CSV):
supplier_name,supplier_email,po_required,default_approver
绿洲办公用品公司,ap@oasis-example.com,true,finance-li@example.com
北辰印刷服务,billing@beichen-example.com,false,finance-li@example.com
OpenPurchaseOrders 分页(CSV):
po_number,remaining_value,currency,approver_email
PO-2026-0118,12000,AED,procurement@example.com
PO-2026-0131,3500,AED,procurement@example.com发票结构化提取提示词(独立编写)
本站独立编写,字段名需与后续Code节点一致;{{ $json.pdfText }}按你实际的字段引用调整。
你是发票信息提取器。阅读下面的发票文本,只输出一个JSON对象,不要任何解释、不要代码块标记。字段:supplier_name(字符串)、invoice_number(字符串)、po_number(字符串,无则空字符串)、invoice_date(YYYY-MM-DD)、currency(三字母代码)、subtotal(数字)、tax_rate(数字,百分数)、tax_amount(数字)、total(数字)、line_items(数组,每项含description、quantity、unit_price、amount)。金额一律用数字不带千分位。无法确定的字段用空字符串或0。
发票文本:
{{ $json.pdfText }}输入与输出示例
本站虚构演示,非原作者运行结果;分支走向取决于你设定的APPROVAL_LIMIT。
输入
测试邮件附件invoice-A.pdf文本:绿洲办公用品公司,发票号INV-8841,PO号PO-2026-0118,日期2026-09-10,币种AED,小计8000.00,税率5%,税额400.00,总额8400.00,明细2行。APPROVAL_LIMIT设为5000。对应输出
检查全部通过但total=8400>APPROVAL_LIMIT=5000,走Slack分支。Slack消息示意:「请签核发票 INV-8841 / 绿洲办公用品公司 / AED 8400.00 / PO-2026-0118 / 默认签核人 finance-li@example.com」。Ledger不新增行,Exceptions不新增行。做完检查这些
- 过滤后只有PDF进入提取,非PDF附件被静默跳过且不产生异常记录
- 低于限额且全过的发票在Ledger追加一行,字段与提取结果一致
- 超额发票在Slack频道产生一条含发票号与金额的签核消息,且Ledger不写入
- 含非法税率的测试发票进入Exceptions,且supplier_email收到带编号问题清单的回邮
- Ledger中已存在的发票号再次提交时被重复检查拦截
容易卡住的地方
- 扫描件PDF提取不出文本,流程会拿到空字符串,需另加OCR节点,原模板未覆盖
- VALID_TAX_RATES默认是阿联酋的0和5,不改成适用税率会批量误判
- Gmail标签ID不是标签显示名,填错会导致触发器一直静默不触发
- Google Sheets四个分页的列名必须与节点映射一致,改名后追加会失败或错列
- 回邮节点直接发给supplier_email,测试阶段务必用合成邮箱,避免把问题清单发给真实供应商
本站借助AI整理来源事实,独立编写中文操作指南与示例。示例不代表实际运行结果;来源效果尚未由本站独立复现。付费模板与模型、服务费用分别计算。
- 原文标题
- Check supplier invoices from Gmail using OpenAI, Google Sheets and Slack
- 原作者
- Hamza Jamal Janjua
- 原始发布日期
- 2026-09-15T01:46:12.172Z
- 来源
- https://n8n.io/workflows/19597