2026-09-08 · 原文发布日
PDF报表对账:代码校验合计后才入账
这是一个付费模板。核心思路是不让模型自己核数:Gmail指定标签收到带PDF附件的邮件后,提取文本交给OpenAI按结构化schema读出标题、币种、打印合计和全部明细行,再用JavaScript把明细金额加总,与打印合计在设定的绝对和百分比容差内比对;对得上才把明细逐行写入Google Sheets的Line Items,对不上就进Needs Review并发Slack告警。
原文要点
原模板为n8n付费模板,作者Jessy Mariau。流程:Gmail触发器按指定标签监听含附件的新邮件并下载附件;仅保留PDF并转纯文本;OpenAI按结构化schema抽取报表标题、币种、打印合计与全部明细行;JavaScript节点把明细行金额加总,按设定的绝对容差和百分比容差与打印合计比对;对得上才把明细逐行写入Google Sheets的Line Items页,对不上或无打印合计则写入Needs Review页并向Slack频道发告警。需配置Gmail、OpenAI、Google Sheets、Slack四类OAuth2凭据,以及容差与默认币种。
这次做成什么
在n8n里搭一条“PDF报表对账”流程:模型只负责读出数字,核数交给JavaScript代码,合计对得上才入账。由于原模板需购买,以下为按原文思路独立重写的搭建方案,节点名与界面参数需在n8n实际版本中核对,本站未实测。
准备什么
- n8n账号(云或自托管,能添加Gmail/OpenAI/Google Sheets/Slack凭据)
- 一个Gmail标签(如reports-in)用于接收带PDF附件的报表邮件
- 含Line Items与Needs Review两个工作表的Google Sheets文档及编辑权限
- Slack工作区及一个接收告警的频道名
- OpenAI API凭据,结构化输出可用的模型
具体怎么做
配置Gmail触发与PDF过滤
新建工作流,添加Gmail Trigger,事件选收到新邮件,过滤条件填入你创建的报表标签ID;开启附件下载。后接过滤节点,仅放行附件MIME为application/pdf的邮件,其余直接结束分支。
PDF转文本并结构化抽取
用n8n的PDF提取节点把附件转成纯文本。接OpenAI节点,提示词见下方材料“结构化抽取提示词”,要求严格按JSON schema返回title、currency、statedTotal与lineItems数组,禁止模型自己改算合计。
JavaScript核数与容差比对
添加Code节点,粘贴下方“合计校验脚本”:把lineItems各项amount相加得computedSum,与statedTotal做差,绝对差≤absTolerance或相对差≤pctTolerance视为对账通过;statedTotal缺失直接判不通过。容差参数从配置节点读入。
分支写入与告警
用IF节点按校验结果的passed字段分支:true分支把lineItems拆成单行,逐条追加到Sheets的Line Items页;false分支把标题、打印合计、计算合计、差额写入Needs Review页,再接Slack节点向告警频道发送包含差额与邮件主题的消息。
用合成PDF走通全链路
先用下方示例的虚构报表文本粘进测试PDF发到自己邮箱,确认三张去向:能对上的进Line Items、改一个明细金额后进Needs Review并收到Slack消息、无合计的进Needs Review。
可直接复制的材料
结构化抽取提示词
本站按原文schema思路独立编写,{{ $json.pdfText }}为n8n表达式占位,需按你实际字段名替换;模型可能产生API费用。
你是报表数据抽取器。下面是一份PDF报表转出的纯文本。请只输出一个JSON对象,不要输出任何其他文字。格式:{"title": 报表标题字符串, "currency": 三字母币种代码如CNY或USD, "statedTotal": 报表上印刷的合计金额数字,找不到则为null, "lineItems": [{"description": 明细描述, "quantity": 数量数字, "unitPrice": 单价数字, "amount": 该行金额数字}]}。规则:1) 所有金额原样照抄报表上的数字,不要重新计算;2) statedTotal必须取自报表印刷的合计行,不要自己加总;3) 每一行明细都要收录,不得遗漏或合并。
报表文本:
{{ $json.pdfText }}合计校验脚本
本站独立示例,容差默认值是按合理量级设定,非原模板数值;导入前在n8n当前版本核对Code节点写法。
// n8n Code 节点,本站独立编写的独立示例,非原模板代码
const cfg = $json.settings || {};
const absTol = cfg.absTolerance ?? 0.01; // 绝对容差,按需要改
const pctTol = cfg.pctTolerance ?? 0.001; // 百分比容差 0.1%
const extracted = $json.extraction;
const items = extracted.lineItems || [];
const computed = items.reduce((s, r) => s + Number(r.amount || 0), 0);
const stated = extracted.statedTotal;
let passed = false, diff = null;
if (stated !== null && stated !== undefined) {
diff = Math.abs(computed - Number(stated));
const pct = Number(stated) !== 0 ? diff / Math.abs(Number(stated)) : Infinity;
passed = diff <= absTol || pct <= pctTol;
}
return [{ json: {
title: extracted.title,
currency: extracted.currency || cfg.defaultCurrency || 'CNY',
statedTotal: stated,
computedTotal: Number(computed.toFixed(2)),
difference: diff === null ? null : Number(diff.toFixed(2)),
passed,
lineItems: items
} }];流程配置与测试报表文本
本站虚构的配置与测试文本,标签名、表名、频道名均需替换为你自己的。
{
"settings": {
"gmailLabel": "reports-in",
"absTolerance": 0.01,
"pctTolerance": 0.001,
"defaultCurrency": "CNY",
"sheets": { "okTab": "Line Items", "reviewTab": "Needs Review" },
"slackChannel": "#finance-alerts"
},
"samplePdfText": "办公用品采购对账单 2026年3月\n明细:\nA4复印纸 10箱 单价35.00 金额350.00\n黑色签字笔 5盒 单价18.00 金额90.00\n订书钉 20盒 单价2.50 金额50.00\n打印合计:490.00 CNY"
}输入与输出示例
本站虚构演示,非原作者运行结果,未在真实n8n环境执行。
输入
PDF文本含三行明细:350.00、90.00、50.00,印刷合计490.00 CNY,容差设为绝对0.01、百分比0.1%。对应输出
{"title":"办公用品采购对账单 2026年3月","currency":"CNY","statedTotal":490.0,"computedTotal":490.0,"difference":0.0,"passed":true},随后3行明细分别追加到Line Items页;若把某行改成55.00,则computedTotal=495.00、difference=5.00、passed=false,流程改写Needs Review并向Slack发送差额5.00元的告警。做完检查这些
- 对得上的测试PDF:Line Items页新增行数与明细行数完全一致,金额逐行相等
- 改错一行金额的测试PDF:Needs Review页出现一行,差额字段与手算差额一致
- Slack频道收到告警,消息里同时包含印刷合计、计算合计与邮件主题
- 把statedTotal改成null后流程走不通过分支,不再写入Line Items
- Gmail标签外或非PDF附件的邮件不触发任何写入
容易卡住的地方
- 原模板为付费商品,本页是按公开说明独立重搭的方案,界面与参数需在n8n实际版本核对
- 结构化抽取依赖PDF能转成纯文本,扫描件图片型PDF会得到空文本,需另接OCR
- 金额若带千分位逗号或币种符号,脚本里的Number()会得到NaN,需在抽取提示词或脚本中先清洗
- 容差设得过宽会让真实差错漏过,过窄会让四舍五入误差全部进复核,需按自己业务定
- Slack与Sheets的OAuth2授权范围不足时节点会静默失败,需查看执行日志
本站借助AI整理来源事实,独立编写中文操作指南与示例。示例不代表实际运行结果;来源效果尚未由本站独立复现。付费模板与模型、服务费用分别计算。
- 原文标题
- Extract PDF report tables into Google Sheets with Gmail, OpenAI and Slack
- 原作者
- Jessy Mariau
- 原始发布日期
- 2026-09-08T02:04:13.508Z
- 来源
- https://n8n.io/workflows/19346