# 区块链发票 → 航信电子发票 迁移文档 ## 一、背景 深圳税局已停止微信区块链电子发票接口服务(即系统原有的 `new-tax-control-fapiao` 业务),现有发票功能将全部切换至航信(票慧通)乐企版 v5.1 电子发票平台。 **替换范围**:所有发票开具、查询、下载、状态跟踪功能。 **不受影响**:微信支付、退款、订单管理、充电业务等。 --- ## 二、新旧流程对比 ### 2.1 开票流程 ``` 旧流程(微信区块链发票): 用户选订单 → 获取微信抬头填写URL → 用户在微信小程序填抬头 → 微信回调通知 → 管理员审核开票 → 微信开具 → 微信回调 → 下载 新流程(航信电子发票): 用户选订单 + 填写抬头信息 → 管理员审核 → 航信开具 → 系统轮询结果 → 自动发邮件 / 下载 ``` ### 2.2 关键差异 | 事项 | 旧(微信) | 新(航信) | |------|-----------|-----------| | 抬头收集 | 用户跳转微信小程序填写 → 异步回调 | 用户申请时在 App 内直接填写 | | 开票触发 | 调用微信 `fapiao-applications` API | 调用航信 `openBlueInvoice` API | | 结果获取 | 微信主动回调 `/invoice/notify` | 系统每 5 分钟轮询航信查询 | | 发票文件 | 微信临时链接(30 秒有效) | 永久 PDF / OFD / XML 链接 | | 邮件发送 | 不支持 | 开票成功后自动发送到用户邮箱 | | 发票红冲 | 微信 API | 航信 `openRedInvoice` API | ### 2.3 API 端点变化 | 端点 | 状态 | 说明 | |------|------|------| | `POST /invoice/applyInvoice` | 变更 | 返回值从 TitleUrl 改为 Invoice 对象 | | `POST /invoice/notify` | 移除 | 航信为轮询模式,不再需要回调 | | `POST /invoice/titleWriteNotice` | 移除 | 抬头信息在申请时直接提交 | | `GET /invoice/downloadInvoice/{id}` | 保留 | 改为返回航信 PDF/OFD/XML URL | | `GET /invoice/list` | 不变 | 用户发票列表 | | `GET /finance/handleInvoice/{id}` | 变更 | 后端改为调用航信开票 | | `GET /finance/downloadInvoice/{id}` | 变更 | 改为返回航信下载链接 | | `GET /finance/getUserTitle/{applyId}` | 移除 | 航信无此概念 | | `GET /finance/getInvoice/{applyId}` | 变更 | 改为查询本地 InvoiceDetail 表 | | `GET /finance/listInvoice` | 不变 | 管理端发票列表 | | `GET /finance/export/invoiceList` | 不变 | 发票导出 | | `GET /finance/confirmManualInvoice/{id}` | 不变 | 手动确认开票 | --- ## 三、配置说明 ### 3.1 新增配置 在 `application.yml` 中添加(admin 和 miniapp 模块均需配置): ```yaml huapiaoer: app-secret: 票慧通提供的appsecret nsrsbh: 开票方税号(商家税号) b2cshopid: 商家税号(同 nsrsbh) ``` ### 3.2 保留的旧配置 `wechat.fapiao.*` 配置暂保留但不再使用,后续可清理。 --- ## 四、数据库变更 执行 `database/7.sql`: ```sql -- 发票详情增加下载链接字段 ALTER TABLE charge_admin.t_invoice_detail ADD COLUMN IF NOT EXISTS invoice_url VARCHAR(512) COMMENT '发票PDF下载地址', ADD COLUMN IF NOT EXISTS ofd_url VARCHAR(512) COMMENT '发票OFD下载地址', ADD COLUMN IF NOT EXISTS xml_url VARCHAR(512) COMMENT '发票XML下载地址'; -- 发票抬头管理:增加默认抬头字段 ALTER TABLE charge_app.t_invoice_title ADD COLUMN IF NOT EXISTS is_default TINYINT(1) DEFAULT 0 COMMENT '是否默认抬头'; ``` - `t_invoice` 表结构不变,数据兼容 - 历史发票记录的 `t_invoice_detail` 数据不受影响 --- ## 五、文件变更清单 ### 5.1 新增文件 | 文件 | 说明 | |------|------| | `common/.../config/HuapiaoerProperties.java` | 航信配置属性类 | | `service/.../miniapp/HuapiaoerInvoiceService.java` | 航信开票业务封装 | ### 5.2 修改文件 | 文件 | 变更摘要 | |------|----------| | `service/pom.xml` | 新增 `huapiaoer-sdk:5.1.0` 依赖 | | `admin/.../application-dev.yml` | 新增 `huapiaoer` 配置块 | | `admin/.../application-prod.yml` | 新增 `huapiaoer` 配置块 | | `miniapp/.../application-dev.yml` | 新增 `huapiaoer` 配置块 | | `miniapp/.../application-prod.yml` | 新增 `huapiaoer` 配置块 | | `entity/.../InvoiceDetail.java` | 新增 `invoiceUrl/ofdUrl/xmlUrl` 字段 | | `service/.../InvoiceService.java` | `applyInvoice()` 返回值改为 `Invoice` | | `service/.../InvoiceServiceImpl.java` | 申请时直接保存抬头信息 | | `service/.../InvoiceDetailService.java` | 移除微信 `updateInvoiceDetail` 方法 | | `service/.../InvoiceDetailServiceImpl.java` | 移除微信发票详情更新逻辑 | | `service/.../WxPayService.java` | 移除全部 10 个发票方法声明 | | `service/.../WxPayServiceImpl.java` | 移除全部发票实现及依赖注入 | | `miniapp/.../InvoiceController.java` | 简化接口,移除回调端点 | | `admin/.../FinanceController.java` | 改为调用航信服务 | | `admin/.../InvoiceStatusJob.java` | 轮询航信替代微信,频率 5 分钟 | | `miniapp/.../SaTokenConfigure.java` | 移除 `/invoice/notify` 等免认证路径 | --- ## 六、部署步骤 ### 6.1 部署前准备 1. 向票慧通申请 `appSecret`、确认商家税号(`nsrsbh` / `b2cshopid`) 2. 执行数据库 DDL: ```sql ALTER TABLE charge_admin.t_invoice_detail ADD COLUMN invoice_url VARCHAR(512) COMMENT '发票PDF下载地址', ADD COLUMN ofd_url VARCHAR(512) COMMENT '发票OFD下载地址', ADD COLUMN xml_url VARCHAR(512) COMMENT '发票XML下载地址'; ``` ### 6.2 配置文件 1. 在 4 个 `application-*.yml` 中填写 `huapiaoer.app-secret`、`huapiaoer.nsrsbh`、`huapiaoer.b2cshopid` 2. 生产环境使用真实的航信正式环境 `https://erp.huapiaoer.com`(默认值,无需额外配置) ### 6.3 构建与发布 ```bash # 1. 安装 huapiaoer-sdk 到本地 mvn install -pl huapiaoer-sdk -DskipTests # 2. 编译全部模块 mvn compile -pl huapiaoer-sdk,entity,common,service,admin,miniapp # 3. 打包部署 mvn package -DskipTests ``` ### 6.4 部署后验证 1. **用户申请开票**:在 App 中选择订单申请开票,确认可以直接提交抬头信息 2. **管理端开票**:在后台审核并点击"开具发票",确认调用航信成功 3. **状态轮询**:等待 5 分钟(或手动触发定时任务),确认发票状态更新为"已开票" 4. **下载发票**:确认可以获取 PDF/OFD/XML 下载链接 5. **邮件发送**:确认填写了邮箱的发票自动发送邮件 --- ## 七、回滚方案 如需回退到旧系统(如微信接口恢复): 1. 恢复部署旧版本代码 2. 数据库无需回滚(新字段不影响旧逻辑) --- ## 八、发票抬头管理(新增功能) 替换微信的抬头管理能力,改为充电桩系统自行管理。 ### API 端点 | 端点 | 方法 | 说明 | |------|------|------| | `GET /invoice/title/list` | GET | 当前用户的抬头列表(默认抬头排前) | | `GET /invoice/title/{id}` | GET | 查看单个抬头详情 | | `POST /invoice/title` | POST | 新增抬头 | | `PUT /invoice/title/{id}` | PUT | 修改抬头 | | `DELETE /invoice/title/{id}` | DELETE | 删除抬头 | | `PUT /invoice/title/{id}/default` | PUT | 设为默认抬头 | ### 自动化 - 用户申请开票时,填写的抬头信息自动保存到抬头表(去重) - 用户下次申请开票时可直接从保存的抬头中选择 --- ## 九、定时任务 | 任务 | 旧频率 | 新频率 | 说明 | |------|--------|--------|------| | `InvoiceStatusJob` | 每天 18:00 | 每 5 分钟 | 轮询航信查询开票结果,更新状态并自动发送邮件 | --- ## 九、异常处理 1. **航信 API 返回失败**(`code != "200"`):抛出 `HuapiaoerException`,前端提示错误信息 2. **网络异常**:抛出 `HuapiaoerException`(code=500),定时任务会在下一轮重新处理 3. **定时任务轮询失败**:记录错误日志,下一轮(5 分钟后)继续重试,直到成功 4. **邮件发送失败**:仅记录日志,不影响开票结果