Skip to content

About

纯本地电子发票整理、查重与报销汇总工具。不联网、不上传、不依赖 AI/OCR。Local-first e-invoice organizer: dedup & expense reports, zero cloud, zero OCR.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

FapiaoVault logo

FapiaoVault · 发票管家

纯本地电子发票整理、查重与报销汇总工具

不联网 · 不上传 · 不用 AI · 不用 OCR

CI License: MIT Python 3.9+ Code style: ruff

中文 · English


把一堆乱七八糟的发票文件(PDF / OFD / XML)丢进一个文件夹,一条命令得到: 去重后的归档 + 报销汇总表 + 一份可以离线打开的报告。

fapiao scan ./我的发票 --archive

终端演示

报告长这样

双击 发票报告.html 即可离线打开——搜索、筛选、汇总、风险标红,全部内置, 不加载任何外部资源:

HTML 报告预览


为什么需要它

每个月底报销的人都在重复同样的事:

  • 邮箱里、微信里、支付宝里下载的发票,文件名全是乱码(dzfp_25512000000012345678_20260901.pdf)
  • 同一张发票下载了两次,自己根本发现不了 —— 而重复报销是财务红线
  • 报销前才发现抬头写错了,被打回重开
  • 手工把金额一张张填进 Excel,加错一个数字就要全部重来

现有工具的普遍做法是:把发票图片上传到云端大模型做 OCR。这意味着你的 发票(含公司名、税号、消费金额、行程)离开了你的电脑,而且识别结果还带概率误差。

但这件事根本不需要 AI。 现在的电子发票(数电票)PDF / OFD / XML 都自带文本层, 字段是确定性的,用规则解析可以做到准确、可复现、可验证,而且完全离线。

验证方法:断网,工具照样工作;打开任务管理器,全程零网络请求。


和现有工具的区别

FapiaoVault 云端 OCR 类工具 纯手动整理
数据是否离开本机 从不 图片会上传 否
需要 API Key / 联网 不需要 需要 不需要
识别方式 文本层确定性解析 大模型/OCR(有误差) 人眼
需要配置邮箱授权码 不需要(仅可选的邮箱抓取功能) 通常需要 不需要
发票查重 批内 + 跨期台账 少见 靠记性
抬头/税号合规校验 支持(含校验位) 少见 靠人眼
处理速度 毫秒级 受网络与额度限制 按小时算
安装体积 几百 KB 常需下载几百 MB 运行时 —

快速开始

1. 安装

git clone https://github.com/dfhhvc/fapiao-vault.git
cd fapiao-vault
pip install -e ".[pdf,excel]"
  • pdf:解析 PDF 发票(唯一的第三方依赖,OFD 与 XML 用标准库即可解析)
  • excel:导出 .xlsx(不装会自动降级为 CSV,功能不受影响)

2. Windows 一键运行

双击项目根目录下的 一键整理发票.bat(首次运行会自动安装 pypdf): 把任意发票文件夹拖到它的图标上,就会扫描该文件夹;直接双击则扫描 samples 示例目录。 扫描完成后会自动打开 HTML 报告。

开启抬头校验(推荐):把 报销配置.example.txt 复制一份、重命名为 报销配置.txt (与 bat 同目录),用记事本把第一行改成你的公司全称、第二行改成 18 位税号。 之后每次扫描都会自动核对抬头与税号,开错的发票会被单独标红提示; 不放置该文件也完全能用,只是跳过抬头校验。

3. 命令行

# 扫描 + 生成报表
fapiao scan ./我的发票

# 扫描 + 按月份归档重命名(原文件保留,只做复制)
fapiao scan ./我的发票 --archive

# 从邮箱一键抓取发票附件(可选联网功能,抓完接 scan 即可)
# 授权码用环境变量传入,避免进入 shell 历史
$env:FAPIAO_IMAP_PASSWORD = "你的授权码"      # bash: export FAPIAO_IMAP_PASSWORD=...
fapiao fetch --host imap.qq.com --user me@qq.com --dir ./我的发票 --password-env FAPIAO_IMAP_PASSWORD
fapiao scan ./我的发票 --archive

# 带上公司抬头,自动检查每张票的抬头和税号是否会报销被退回
fapiao scan ./我的发票 --company "某某科技有限公司" --tax-id "91330100MA2XXXXXX2"

# 校验一个统一社会信用代码是否合法
fapiao verify 91330100MA2XXXXXX2

扫描后会生成 _报表/ 目录:

文件 用途
发票报告.html 双击即可离线打开的可视化报告,有搜索、筛选、汇总
发票汇总.xlsx 三个工作表:发票明细 / 报销汇总 / 重复发票
发票明细.csv 带 UTF-8 BOM,Excel 双击不乱码
台账.json 历史台账,下次扫描自动读取,用于发现跨月重复报销

归档结果长这样(自动按月份分目录、自动去重命名、不覆盖已有文件):

_归档/
└── 2026-09/
    ├── 2026-09-01_示例出行有限公司_42.50元_25117000000000000001_普通发票.pdf
    ├── 2026-09-03_示例酒店有限公司_123.60元_25117000000000000002_普通发票.ofd
    └── 2026-09-01_示例出行有限公司_42.50元_25117000000000000001_普通发票_2.pdf   ← 重复件

它能检查出什么问题

工具在解析后会做这些校验,并把问题写进报告:

  • 跨期重复报销(最高风险):本次扫描的票号已存在于历史台账且月份不同 —— 这是财务最警惕的场景,会与批内查重分开单独标红
  • 重复报销风险(高风险):同一张发票号出现在不同月份的扫描批次内
  • 同一张票重复收集:同批次内票号相同,或文件内容完全一致(sha256)
  • 抬头不符:购买方名称与你公司的抬头不一致
  • 税号错误:购买方税号与公司税号不符,或校验位算不过(GB 32100-2015)
  • 金额不勾稽:金额 + 税额 ≠ 价税合计(超过 1 分钱)
  • 大小写金额不一致:中文大写与小写对不上,这是发票被涂改的信号
  • 发票号码格式异常:数电票应为 20 位且无发票代码;传统票为 12 位代码 + 8 位号码

支持的格式与边界

格式 支持 说明
PDF(数电票 / 增值税电子发票) ✅ 读文本层,无需 OCR
OFD ✅ 纯标准库解析(OFD 本质是 ZIP + XML)
XML(数电票原件) ✅ 结构化字段直读,零误差
图片(jpg / png / 扫描件) ❌ 刻意不做 OCR,会被识别出来并提示你改用原始电子发票

工具只处理自带文本层的电子发票。绝大多数来自邮箱、微信、支付宝、电商平台的 发票下载件都属于这一类。真正的纸质扫描件不在射程内——这是刻意的边界, 因为要把它们做对就必须上 OCR,那会破坏"离线 + 确定性"这两个核心承诺。

票种覆盖:数电票全票种——普通发票 / 专用发票 / 铁路电子客票 / 航空运输电子客票行程单(后两种票面没有销售方区块,解析时不会误报), 以及增值税电子普通 / 专用发票等老版式。


工作原理

发票文件
   │
   ├─ .pdf ─→ pypdf 抽取文本层 ─┐
   ├─ .ofd ─→ 解 ZIP,遍历 XML 文字节点 ─┤
   └─ .xml ─→ 直接读结构化字段 ──────────┤
                                          ▼
                              字段抽取(正则 + 版式规则)
                                          │
                     ┌────────────────────┼────────────────────┐
                     ▼                    ▼                    ▼
                 合规校验              三级查重              置信度评估
              (税号校验位/            (票号 →             (字段完整度
               金额勾稽/抬头)          文件指纹 →            + 问题数量)
                                          内容键)
                                          │
                                          ▼
                     归档重命名 + HTML/Excel/CSV/JSON 报表

两个值得一提的工程细节:

  1. 文本层版式兼容。数电票的购买方/销售方用纵向标签(购/买/方/信/息), PDF 抽取后这些字会与字段值粘连(…有限公司买)。工具用"分区切分 + 出现顺序兜底" 双路径识别,两种版式都有测试样例锁定。
  2. 查重不误报。完全没解析出内容的文件(既无号码也无金额)不参与内容级查重, 否则一堆"解析失败"的文件会被误报成互相重复。

隐私承诺

承诺 你自己怎么验证
scan 不发起任何网络请求 断网运行,或开抓包工具全程观察
fetch 只连接你自己填写的 IMAP 服务器 抓取模块仅用标准库 imaplib,源码可全文审阅;授权码走环境变量或交互输入,不进命令行历史、不落盘
不上传发票内容给任何第三方 代码里没有 requests / urllib / httpx 等网络调用
不改动你的原始文件 归档是复制不是移动;重名自动加序号,绝不覆盖
不写注册表、不留后台 纯命令行/库,跑完即退出

唯一会写文件的地方:你指定的输出目录(默认 _报表/ 与 _归档/)。


测试

python -m unittest discover -s tests

119 个测试,零测试依赖(只用标准库 unittest),覆盖:

  • 统一社会信用代码校验位(含手工验算的样例,不循环自证)
  • 中文大写金额解析(元/角/分、万、拾 的边界)
  • 多种真实与对抗性文本层版式(分区完整 / 纵向标签尾部粘连 / 头部粘连 / 逐字打散)
  • 报销高频票种版式:铁路电子客票 / 航空行程单(无销售方区块时不误报)
  • 邮件抓取:MIME 附件提取、中文文件名解码与清洗、重复下载保护(全部本地构造,不联网)
  • PDF / OFD / XML 三种格式的端到端解析(测试样例由代码动态生成)
  • 三级查重、跨期重复、历史台账(含"工具写出的台账必须能被读回"的回归测试)
  • 报表输出(含 HTML 自包含性与 XSS 转义)
  • 归档重命名与不覆盖保证
  • CLI 全命令

CI 在 Ubuntu / Windows × Python 3.9–3.13 十个组合上跑全部测试, 外加一个不装任何 extras 的 core-only 任务,守住"零硬依赖"的承诺。

生成测试样例:

python tools/make_fixtures.py samples

样例中的票号、税号、公司名全部是虚构数据,仅用于测试,不对应任何真实票据。 样例 PDF 由代码用 PDF 规范内置的中文 CID 字体生成,不依赖任何第三方库。


常见问题

Q:为什么不用 AI / OCR? A:因为没必要,而且代价更高。电子发票自带文本层,规则解析是确定性的——同样的输入 永远得到同样的输出,可以写测试,出错能定位到具体规则。OCR 是概率性的,还要求你把 发票图片传给第三方。只有在处理扫描件时才需要 OCR,而那不是本工具的目标场景。

Q:我的发票是图片怎么办? A:去开票平台重新下载原始 PDF/OFD/XML 原件(通常免费且即时),比 OCR 更准。 工具会明确告诉你哪些文件属于这一类。

Q:会不会把我的发票弄丢? A:归档只做复制。原始文件从头到尾不会被移动、改名或删除。

Q:能处理几百张发票吗? A:可以。解析是纯本地字符串处理,速度在毫秒级。

Q:邮箱抓取怎么用?安全吗? A:fapiao fetch 只用 Python 标准库 imaplib 连接你自己填写的 IMAP 服务器, 授权码通过环境变量(--password-env)或交互式输入传入——不进命令行历史、 不落盘,也不会把发票数据发给任何第三方。抓完的附件就在你指定的本地目录, 之后的整理查重照旧离线。授权码获取:QQ 邮箱在网页版「设置-账户」开启 IMAP 并生成授权码;163/126 在「设置-POP3/SMTP/IMAP」开启服务获取授权密码。


项目结构

fapiao-vault/
├── 一键整理发票.bat        # Windows 双击/拖拽入口
├── 报销配置.example.txt    # 抬头校验配置模板(复制为 报销配置.txt 生效)
├── src/fapiao_vault/
│   ├── models.py          # Invoice 数据模型(金额用 Decimal)
│   ├── fields.py          # 字段抽取:三种文本视图 + 版式规则
│   ├── validate.py        # 税号校验位、发票号码格式、抬头合规、金额勾稽
│   ├── dedup.py           # 三级查重引擎 + 历史台账
│   ├── parsers/           # pdf / ofd / xml 三个解析器 + 调度
│   ├── pipeline.py        # 扫描流水线
│   ├── archive.py         # 归档重命名
│   ├── report.py          # HTML / Excel / CSV / JSON 报表
│   ├── mail_fetch.py      # IMAP 邮箱抓取(可选,仅标准库)
│   └── cli.py             # 命令行入口
├── tests/                 # 119 个单元测试(标准库 unittest)
├── tools/make_fixtures.py # 合成测试样例生成器
├── samples/               # 生成的测试样例
└── docs/                  # logo 与 README 演示图

路线图

  • 火车票(铁路电子客票)/ 行程单的专项解析(v1.1.0 已完成,含版式回归测试)
  • IMAP 邮箱一键抓取发票附件(v1.1.0 已完成,纯标准库)
  • 增值税专用发票、出租车票的专项解析规则
  • 按公司报销制度自定义校验规则(如"单张超过 500 元需附明细")
  • 跨年度台账归档与检索
  • 桌面 GUI(保持零依赖、零上传)

贡献

欢迎提交 Issue 和 PR,详见贡献指南。如果遇到解析失败的发票, 请把脱敏后的票面文本(而不是原始票据)附在 Issue 里,那是最有效的反馈方式。

安全漏洞请勿公开 issue,报告方式见安全策略。

许可证

MIT

About

纯本地电子发票整理、查重与报销汇总工具。不联网、不上传、不依赖 AI/OCR。Local-first e-invoice organizer: dedup & expense reports, zero cloud, zero OCR.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages