🧩 andy-invoice-xlsx · 发票整理成 Excel
> ANDY 自有技能(andy- 前缀 = 安迪为老板王照民自建,非第三方来源),可随时按老板习惯修改。
> 真源:E:\WorkBuddy_skills\andy-invoice-xlsx
一、整理范围(先确认再动手)
- 来源 = 工作区文件夹里的发票 PDF + 老板在对话中上传的发票,两者都算。
- 具体整理哪几张,以老板当次指令为准;老板没点名时,默认取工作区内全部发票。
- 开工前先列出待整理清单(工作区文件 + 上传件),必要时向老板复述一遍,别漏、别多。
二、执行流程
Step 1 确认清单 列出发票文件(工作区 + 上传),与老板对齐
Step 2 读取发票 跑 scripts/invoice_pdf.py 取文本层;扫描件无文本层则渲染 PNG 后用视觉识别
Step 3 判断与填数 按下方规则判类型、抽字段,写 data.json
Step 4 生成 Excel 跑 scripts/build_excel.py
Step 5 交付前校验 跑 scripts/verify.py,全绿才交付
Step 2 读取发票
# 取文本层要素(票号/日期/金额/税额/价税合计/税率/购销方)
python scripts/invoice_pdf.py "F:/路径/发票目录" --json
# 扫描件/图片型 PDF:渲染成 PNG,再用 Read 工具看图识别
python scripts/invoice_pdf.py "F:/路径/发票目录" --render
- 有文本层的电子发票:直接读文本,比 OCR 准。
- 文本层为空 = 扫描件/照片:渲染 PNG 后用 Read 看图,别瞎猜。
Step 3 填 data.json
结构见 assets/sample.json:
{"task_date":"2026年9月30日","rows":[
{"type":"机票费","no":"20位发票号","date":"2026-09-28",
"buyer":"购买方名称","buyer_tax":"购买方纳税人识别号",
"seller":"销售方名称","seller_tax":"销售方纳税人识别号",
"item":"项目名称","amount":679.25,"rate":"6%","tax":40.75,"total":720.00,
"memo":"备注","uncertain":[],"start":""}
]}
uncertain:填列序号(1 起,1=发票类型 … 13=备注),该单元格自动标黄。start:打车费的起始地点(老板 2026-10-19 要求)。任一行非空即自动在"价税合计"与"备注"之间插入「起始地点」列;非打车费行留空自动填"—"。起点取票面手写(如"保利悦府→凤凰机场"取起点"保利悦府",终点写进备注)。- 识别不清的字段一律填
"待补充",自动标黄,禁止猜测。 - 一张票多个项目 → 拆成多行;发票号重复的保留所有行,不合并。
Step 4 生成
python scripts/build_excel.py --data data.json \
--out "F:/WorkBuddy_Financedata/发票管理/发票整理_2026年9月30日.xlsx" \
--date "2026年9月30日"
Step 5 校验(必做)
python scripts/verify.py --pdf-dir "F:/路径/发票目录" --xlsx "F:/路径/发票整理_2026年9月30日.xlsx"
校验项:发票号与 PDF 对得上、每行金额/税额/价税合计能在 PDF 原文数字中找到、行内自洽、逐行加总 = 小计 = 总计 = 分类汇总、张数按票号去重。有 ❌ 必须改完再交付。
二·五、交付前强制自我复核(老板 2026-10-08 确立,通用纪律)
> 老板铁律:凡是涉及金额、数字复核、计算、交叉验证、稽核、汇总等任务,完成主流程后,必须自己再独立检查一遍,确认金额与数字计算正确,才能交付。
本技能场景的落实方式:
- 主流程 Step 5 的
verify.py是"第一道校验",跑完不算完。 - 再做一次"独立复核":换一条不依赖本技能解析代码的路径(如纯 pymupdf + 正则重新抽取每张发票的 金额/税额/价税合计,与 Excel 逐票比对),确认:
- 每张:金额 + 税额 = 价税合计;
- 逐行加总 = 类型小计 = 总计 = 分类汇总表;
- PDF 原文数字与 Excel 完全一致。 - 两条路径结果一致、且行内/交叉自洽,才算"已复核无误"。
- 若任务本身不是发票(其他财务计算/汇总),也须在交付前用独立口径重算一遍对账。
- 任何不一致必须先改完再交付,不得带疑交付。
三、发票类型分类
| 类型 | 判定 |
|---|---|
| 住宿费 | 酒店、宾馆、民宿等住宿类 |
| 打车费 | 出租车、网约车(滴滴、高德等)市内打车 |
| 火车费 | 火车票、高铁票 |
| 机票费 | 航空运输电子客票行程单、代订机票费 |
| 餐饮费 | 餐饮、餐费 |
| 其他 | 以上都不属于 → 归"其他",必须在备注列注明具体内容 |
排布顺序:住宿费 → 打车费 → 火车费 → 机票费 → 餐饮费 → 其他;同类型按开票日期先后。
四、表格规范
列(基础 13 列):发票类型、发票号码、开票日期、购买方名称、购买方纳税人识别号、销售方名称、销售方纳税人识别号、项目名称、金额(不含税)、税率、税额、价税合计(小写)、备注
起始地点列(打车费专用,2026-10-19 起):本批含打车费且票面有起讫信息时,在「价税合计」与「备注」之间插入「起始地点」列(共 14 列);非打车费行填"—"。出租车票无购买方/销售方/税率信息的,相应列填"—"(票面本就没有,不算"待补充"),金额=价税合计、税额 0.00。
字体:中文 微软雅黑;发票号/日期/税号/金额/税率/税额等纯数字与英文列 Times New Roman;表头 黑体 + 加粗。金额统一 #,##0.00 两位小数。
汇总:明细表每种类型一行小计(加粗)+ 末尾总计行;第二个工作表「分类汇总」= 发票类型 | 张数 | 金额合计 | 税额合计 | 价税合计。张数按发票号去重统计。
命名:发票整理_XXXX年X月X日.xlsx,日期取执行任务当天,不加方括号,保存到工作区根目录。
五、踩过的坑(务必避开)
- PDF 文本流不按视觉顺序:项目名因列宽折行时,第二行的字会被排到金额之后(实测
*生产生活服务*代订机票+费→ 文本流里"费"出现在40.75\n费\n合计)。拼接还原后再写,别把"代订机票费"写成"代订机票"。 import pymupdf,不是fitz:fitz 会告警且将废弃。- 数电票金额/税额在"合计"行是
¥xxx\n¥yyy两连;价税合计小写在大写金额之后。 - 免税票税率为"免税"、税额 0,行内"金额+税额=价税合计"仍应成立;多项目票可能不等,属正常,人工确认。
- 已证实可用主体:购买方 中免集团三亚市内免税店有限公司 / 91460200687274162U;机票代订方 阿斯兰航空服务(上海)有限公司 / 913101150529904218。
六、依赖
pymupdf、openpyxl。先安装依赖:pip install pymupdf openpyxl。
用任意已装好这两个包的 Python 运行脚本(跨平台通用,不绑定本机路径):
python scripts/invoice_pdf.py "发票目录" --json
python scripts/build_excel.py --data data.json --out "发票整理_2026年9月30日.xlsx" --date "2026年9月30日"
python scripts/verify.py --pdf-dir "发票目录" --xlsx "发票整理_2026年9月30日.xlsx"
> WorkBuddy 用户可直接用托管 venv 的 python(路径因机而异,一般在 …/binaries/python/envs/default/Scripts/python.exe),其余用户用系统 python 即可。