电子发票报销整理
规矩(每次都要遵守)
- 只读发票,不改发票。 脚本只打开发票文件读文字,不改、不删、不移动、不重命名。报销明细、汇总文字、补录表一律另存为新文件,重名自动加 _1、_2,绝不覆盖。
- 先看清单,再出报表。 第一次先跑
scan,把读出来的张数、合计、重复、问题、读不了的文件用大白话告诉用户,用户没意见再跑report生成 Excel。 - 微信里的文件要用户确认。 用户说「发票在微信里」时,先跑
wechat只列出按月份的文件夹和像发票的文件名,请用户确认是哪个月、哪几个文件,再对确认过的位置跑scan。不翻聊天记录,不读确认范围以外的文件。 - 数字以脚本为准。 不心算、不自己改金额;脚本没读到的字段就说「没读到」,不要猜。
- 不查真伪、不给税务建议。 用户问「这张是不是假发票」「能不能抵扣」「要不要交税」:说明本工具只按文件里的字整理,真伪请到「国家税务总局全国增值税发票查验平台」自己查;能不能报、能不能抵扣按单位财务规定或问财务。
- 组件缺了先问再装。 读大多数发票只用 Python 自带功能。脚本提示缺 openpyxl(生成 Excel)或 pypdf(个别特殊 PDF)时,告诉用户缺什么、有什么用、会连接 Python 官方组件仓库下载,用户明确同意后才跑
deps --install 名称 --confirm;不同意也能用(没有 openpyxl 就存成 Excel 能打开的 CSV)。安装时脚本会把要运行的程序和参数原样显示出来。 - 跟用户说话不念命令和参数名,只说「我先读一遍你的发票」「按 9 月 30 日之前的票核对」这类话;但用户问在运行什么,要如实告诉他。
- 把重复分级。 相同文件哈希或相同发票号码按脚本结果识别为确定重复;金额、日期、销售方相同但号码不同的记录只标为疑似重复,保留在合计中,交给人工核对。分别报告确定重复、疑似重复和实际计入合计的张数与金额。
- 给财务复核留线索。 汇总扫描范围、文件名、读取状态、缺字段、重复判定依据、金额校验差异和抬头/税号不一致;无法读取或字段不全的票留在待补录清单,不猜填。单位税号只用于本次核对,不写入示例、日志或发布包。
- 按控制总额复核。 用户提供控制总额或票据清单时,分开列出已读且计入、确定重复已排除、疑似重复仍计入、未读/待补录;差额未解释前标为待复核,不宣称已经核平。
用法
脚本:python {baseDir}/scripts/invoice_reimburse.py <子命令> [文件夹或文件…] [选项],路径有空格要加引号,可写多个文件夹或文件。
| 子命令 | 做什么 | 会不会动文件 |
|---|---|---|
scan 位置… |
读发票、查重、校验,在屏幕上列清单和汇总 | 只读,不生成文件 |
report 位置… |
同上,并生成报销明细 Excel + 汇总文字 | 只读,另存新文件 |
template 位置… |
给读不出来、读不全的发票生成补录表(CSV) | 只读,另存新文件 |
wechat |
列出微信「接收的文件」最近几个月的文件夹和其中像发票的文件名 | 只看文件名 |
deps |
看组件齐不齐;--install 名称 --confirm 才安装 |
不带 --confirm 不安装 |
选项(scan / report / template 通用):
| 选项 | 意思 |
|---|---|
--buyer 单位名称 |
单位抬头,给了才核对购买方名称 |
--taxid 税号 |
单位税号,给了才核对购买方税号 |
--since 2026-07-01 / --until 2026-09-30 |
报销期限起止,开票日期在范围外的标出来 |
--days 180 |
只报最近 180 天内开的票 |
--cat 会议=会议费,会务 |
改类别:新类别名=关键字;已有类别(交通/住宿/餐饮/办公用品/通讯)后面写关键字就是追加;可写多次 |
--fill 补录表.csv |
用填好的补录表补上读不出来的发票 |
--no-recursive |
只看这一层,不进子文件夹(默认会进子文件夹) |
--out 位置 |
仅 report / template:保存位置;不写就存在发票文件夹里(微信文件夹则存桌面) |
--csv |
仅 report:存成 CSV 而不是 Excel |
大白话 → 怎么做
| 用户说 | 怎么做 |
|---|---|
| 「我下载文件夹里一堆发票,帮我整理成报销单」 | 先问清是哪个文件夹(比如「下载\发票」),scan 那个位置,念汇总;用户说好就 report 那个位置 |
| 「发票都在微信里」 | wechat,念出各月份文件夹里像发票的文件,请用户确认哪个月/哪几个,再 scan 确认的位置或文件 |
| 「抬头是某某公司,税号是…,帮我核对一下」 | 加 --buyer 某某公司 --taxid 税号 |
| 「公司只报 9 月 30 号之前、三个月内的票」 | 加 --until 2026-09-30 --days 90(日期按用户说的填) |
| 「有没有重复的」 | scan,把「查重」一段念给他:哪些是同一张票的 PDF 和 OFD、哪些是同一个文件存了两份、哪些是疑似重复要他自己核对 |
| 「会议费单独算一类」「停车费算交通」 | 加 --cat 会议=会议费,会务、--cat 交通=停车(交通默认已含停车、通行费) |
| 「这几张是拍照的/扫描的」 | 脚本会列为「需补录」。能看图的话,打开图片读出各项,跑 template 生成补录表,把读到的数填进去,念给用户核对后再 report … --fill 补录表;看不了图就请用户自己填补录表 |
| 「这张发票是真的吗」 | 不判断;请他到国家税务总局全国增值税发票查验平台输入发票号码等信息自己查 |
| 「这些能抵扣多少税」「要不要交个税」 | 不回答税务问题;可以说出脚本算的税额合计,能不能抵扣请问单位财务 |
报表里有什么
- 汇总说明:几张、价税合计、不含税金额、税额、日期范围、各类别、重复/问题/读不了的数量,以及「不查验真伪」的说明。另存一份同名的汇总文字(.txt)。
- 报销明细:每张一行(类别、开票日期、发票号码、销售方、项目名称、金额、税率、税额、价税合计、购买方名称和税号、发票类型、文件格式、文件名、是否计入合计、提示),最后是合计行和按类别小计。灰字=重复没计入;黄底=没读到要补录;红底=有问题要核对。
- 按类别小计:每类张数、金额、税额、价税合计、占比。
- 查重:号码相同(含同一张票的 PDF/OFD 两种格式、同一个文件存了多份)只保留一份计入合计;金额+日期+销售方都相同但号码不同的列为「疑似重复」,照常计入,请用户核对。
- 校验问题:金额+税额≠价税合计、大写小写对不上、超出报销期限、开票日期比今天晚、负数发票(红字冲销)、抬头或税号不一致。
- 需补录和跳过:扫描件、图片、加密 PDF、不像发票的文件、云盘里还没下载到本机的文件。
读得出 / 读不出
- 读得出:数电票(电子发票 普通发票/增值税专用发票)、增值税电子普通发票、增值税电子专用发票的 PDF(文字可以选中复制的那种);OFD 版式文件(读页面文字和发票自带的结构化数据);数电票 XML。
- 读不出:扫描件、手机拍照、截图(没有文字);加了打开密码的 PDF;老版本纸质发票的照片。这些列入「需补录」,不计入合计,补录后才计入。
- 个别特殊排版的 PDF 内置方法认不出时,脚本会提示可以装 pypdf 再试(先问用户)。
- 发票类型按票面文字判断,铁路电子客票、航空行程单等格式不同的票,部分字段可能读不全,会标「部分识别」。
需要的组件
- 必须:Python 3.8+。读 PDF、OFD、XML 只用 Python 自带功能。
- 可选:openpyxl(生成带格式的 Excel;没有就存 CSV)、pypdf(个别特殊 PDF 的备用读法)。缺了只提示,用户同意后才安装;安装命令是用当前 Python 运行 pip,装在当前用户目录,不需要管理员权限,会连接 pypi.org 和 files.pythonhosted.org。
不做什么
- 不修改、不覆盖、不删除、不移动任何发票文件。
- 不联网、不上传发票信息、不查验发票真伪(唯一联网的情况是用户同意后安装组件)。
- 不做任何税务建议,不判断能否报销或抵扣,不填写或提交任何报销系统。
- 不扫描整个磁盘、系统目录和软件安装目录;不读微信聊天记录;云盘里没下载到本机的文件不碰(读它会触发下载)。
- 不写计划任务、不常驻后台。
- 不把疑似重复当作确定重复;号码不同的记录在人工确认前仍计入总额。
退出码:0 正常;2 输入有误;3 意外错误。出错时固定两行「出错了:…」「下一步:…」,原样转告用户。