docs: 补齐 REV-005 发票闭环设计与任务台账

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
tangweijie 2026-03-17 00:45:21 +08:00
parent a26f65a3d8
commit 82d307bda6
13 changed files with 1240 additions and 62 deletions

View File

@ -116,6 +116,8 @@
> 说明:本表中的历史记录按当时原始表述保留;当前正式数据库口径统一以“达梦数据库 8.0+”为准。
| 2026-03-17 | REV-005 结果回写与客户侧电子发票消费闭环US3 | 1更新 `12_REV_Detailed.md``01_Database_Design.md``03_Interface_Design.md`,补齐结果回写、账单关联、客户侧查询/下载/推送电子发票规则2扩展 `InvoiceController.java``InvoiceServiceImpl.java``InvoiceMapper.java` 与相关 VO/DO落地客户归属校验、`SUCCESS + fileUrl` 消费前置校验、账单开票状态联动、推送状态回写3执行 `make validate-file FILE=docs/design/03_Technical_Design/01_Database_Design.md``make validate-file FILE=docs/design/03_Technical_Design/03_Interface_Design.md``mvn -f backend/sw-business/sw-business-server/pom.xml -DskipTests compile` 验证通过。 | 用户要求沿 `/speckit.implement` 持续推进 REV-005 US3不中断实现链路直接完成结果回写、账单关联与客户侧电子票消费闭环。 | 正面影响REV-005 已形成“回写落账 + 账单状态联动 + 客户侧查询/下载/推送 + 最小编译验证”闭环,后续可继续衔接作废、红冲与更多电子发票渠道扩展。 |
| 2026-03-16 | REV-005 后台发票申请与校验闭环US1 | 1`backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/invoice/InvoiceController.java` 增加后台发票申请入口2`service/invoice/InvoiceServiceImpl.java` 实现客户、客户开票信息、账单与税率校验确保仅已收费未开票账单允许申请3补齐 `applicationNo``custId + chargeIds` 幂等控制、申请单号生成与申请记录落库4执行 `mvn -f backend/sw-business/pom.xml -pl sw-business-server -am -DskipTests compile` 最小编译验证并通过。 | 用户要求继续推进 REV-005 implement优先完成后台发票申请、开票校验与 US1 收尾,不中断当前实现链路。 | 正面影响REV-005 已形成“后台申请入口 + 关键校验 + 幂等受理 + 最小编译验证”闭环,后续可在此基础上继续推进 SYS-008 调用、开票结果回写、账单状态联动与电子发票推送下载能力。 |
| 2026-03-12 | OMX 任务路由样例落地 | 1新增 `docs/design/00_Management/17_OMX_Task_Routing_Examples.md`,给出 `REV-004``REV-003` 与正式文档修订三类任务的 leader / explorer / executor / verifier 分工模板2补充各 lane 的提示词模板、推荐执行顺序与不建议的并行方式3更新 `00_Management/README.md` 收录该文档入口。 | 用户希望在治理层之外,再拿到针对当前项目可以直接复用的多 Agent 分工模板,而不是只看抽象原则。 | 正面影响OMX 从“有规则”变成“可直接照着分工执行”;后续在 `REV-004``REV-003` 等闭环中可直接套用 lane 拆分,减少 leader 临时编排成本。 |
| 2026-03-12 | OMX 多 Agent 治理层落地 | 1在根 `AGENTS.md` 中新增 OMX 多 Agent 协作补充,明确分层 AGENTS、任务路由矩阵、写冲突规则、范围控制基线与 worktree/tmux 约定2新增 `backend/AGENTS.md`,固化 backend 开发边界、最小实现策略与 BPM 接入规则3新增 `docs/design/04_Appendix/Archive/AGENTS.md`,明确 Archive 默认只读与来源回写规则4新增 `docs/design/00_Management/16_OMX_Multi_Agent_Guide.md`,统一 leader / writer / executor / verifier 分工与协作拓扑5更新 `00_Management/README.md` 收录新指南入口。 | 用户明确准备采用 `oh-my-codex` 进行多 Agent 开发,需要对现有 AGENTS 体系做分层化和路由化改造,避免现有规则在 Team Mode 下失效。 | 正面影响,当前项目从“单 agent 规则完备”提升为“多 agent 可控协作”;后续接入 OMX 时,目录级职责、写权限边界、范围基线与会话约定已经成型,可显著降低并发改稿和多 worker 写冲突风险。 |
| 2026-03-12 | REV-004 一期执行手册与 worktree/tmux 启动脚本落地 | 1新增 `docs/guides/REV004_ACCOUNTING_EXECUTION_PLAYBOOK.md`,将 `REV-004` 一期的范围、现状差距、最小改动方案、任务拆解、Codex Prompt 与验收清单固化为可执行手册2新增 `scripts/start-backend-codex-session.sh`,支持在 `backend/` 上创建或复用 worktree并拉起 `tmux + codex` 三窗口开发会话3更新 `scripts/README.md` 记录脚本用途。 | 用户要求不仅给建议,还要把“如何规划执行、如何进入 worktree、如何在 tmux 场景下协作”落成可直接使用的资产。 | 正面影响,开发启动动作从“口头建议”变为“可复制执行”;后续围绕 `REV-004/REV-003/REV-008` 的闭环开发可直接复用该脚本和手册,降低 worktree、tmux、Codex 协作的起步成本与操作偏差。 |

View File

@ -175,6 +175,21 @@
- [x] 执行手册已明确后续任务拆解顺序:执行手册闭环 → 支撑产物同步 → 台账按触发条件更新 ✅
- [x] 独立验收入口已限定为 `REV004_ACCOUNTING_EXECUTION_PLAYBOOK.md``01_Project_Progress.md``03_Task_Checklist.md` 三份文件 ✅
- [x] 最小校验动作与 tracked task 完成条件已明确,可继续按后续 tasks 拆解推进 ✅
- [x] **完成 REV-005 后台发票申请与校验闭环US1** ✅ (2026-03-16)
- [x] 在 `InvoiceController.java` 增加后台发票申请入口,形成后台单笔/批量发票申请受理入口 ✅
- [x] 在 `InvoiceServiceImpl.java` 完成客户、客户开票信息、账单与税率校验,确保仅已收费未开票账单允许申请 ✅
- [x] 实现 `applicationNo``custId + chargeIds` 幂等控制、申请单号生成与申请记录落库 ✅
- [x] 执行 `mvn -f backend/sw-business/pom.xml -pl sw-business-server -am -DskipTests compile` 最小编译验证并通过,完成 US1 收尾 ✅
- [x] **完成 REV-005 查询兜底与异步协同闭环US2** ✅ (2026-03-17)
- [x] 后台查询接口新增补偿查询触发入口,支持按申请单号/受理号复用查询逻辑 ✅
- [x] 发票对象、Mapper 与查询 VO 已补齐 `sysRequestNo``lastTryTime``nextTryTime``tryCount``latestResult``latestError` 字段 ✅
- [x] 发票服务已实现受理号生成、回写落账、查询补偿留痕与成功状态不被失败结果覆盖 ✅
- [x] 已完成 `mvn -f backend/sw-business/pom.xml -pl sw-business-server -am -DskipTests compile` 最小编译验证 ✅
- [x] **完成 REV-005 结果回写与客户侧电子发票消费闭环US3** ✅ (2026-03-17)
- [x] 已补齐 `12_REV_Detailed.md``01_Database_Design.md``03_Interface_Design.md` 的结果回写、账单关联与客户侧消费口径 ✅
- [x] `InvoiceController.java``InvoiceServiceImpl.java``InvoiceMapper.java` 与相关 VO/DO 已完成客户归属校验、下载/推送前置校验、账单状态联动与推送状态回写 ✅
- [x] 已完成 `make validate-file FILE=docs/design/03_Technical_Design/01_Database_Design.md``make validate-file FILE=docs/design/03_Technical_Design/03_Interface_Design.md` 文档校验 ✅
- [x] 已完成 `mvn -f backend/sw-business/sw-business-server/pom.xml -DskipTests compile` 最小编译验证 ✅
### 📋 工作范围基线对齐

View File

@ -356,27 +356,73 @@ flowchart TD
### 功能说明
负责发票申请、开票校验、开票结果回写、发票查询、作废与红冲处理,作为营收业务对发票服务的业务接入层
负责一期正常开票闭环的业务接入与状态落账,覆盖后台发票申请、开票校验、`SYS-008` 异步协同、查询兜底、结果回写、账单关联以及客户侧已开票电子发票查询/下载/推送;作废与红冲仅保留后续扩展入口
### 业务流程
```mermaid
flowchart TD
A[提交发票申请] --> B[校验账单与开票信息]
A[后台提交发票申请] --> B[校验账单、客户开票信息、税率与限额]
B --> C{是否满足开票条件}
C -->|否| D[返回不可开票原因]
C -->|是| E[生成发票申请记录]
E --> F[调用SYS-008发票服务]
F --> G[接收开票结果回写]
G --> H[更新发票与账单关联状态]
C -->|是| E[生成申请单号并写入SUBMITTED]
E --> F[调用SYS-008发起异步开票]
F --> G[记录受理号并转为PENDING]
G --> H[系统轮询或后台查询兜底]
H --> I{开票结果}
I -->|成功| J[回写SUCCESS并更新账单-发票关联]
I -->|失败| K[回写FAIL并记录失败原因]
J --> L[客户侧查询/下载/推送电子发票]
```
### 状态说明
- `SUBMITTED`:后台申请已受理,已完成本地校验并生成申请单。
- `PENDING`:已提交 `SYS-008`,等待异步结果或查询补偿结果。
- `SUCCESS`:已取得有效发票代码、号码或电子票地址,且账单关联已完成更新。
- `FAIL`:开票失败,需保留失败原因、最近查询结果与后续人工核查依据。
- `INVALID`:发票已作废,作为后续能力预留状态。
- `RED_INK`:发票已红冲,作为后续能力预留状态。
### 关键规则
1. 发票申请以客户信息、缴费记录、账单信息、税率配置为基础。
2. 个人与企业开票均通过客户开票信息与税率表完成合法性校验。
3. 发票开具、作废、红冲由 `SYS-008` 统一承接SYS-002 负责业务上下文传递与结果落账。
4. 电子发票可通过客户服务渠道推送或下载。
1. 一期采用“后台申请开票 + 客户侧查询下载推送”的入口模式,客户侧不直接发起开票申请。
2. 发票申请以客户信息、已收费未开票账单、税率配置和开票限额为基础;原始单账单不支持直接任意部分金额开票。
3. 个人与企业开票均通过客户开票信息与税率表完成合法性校验;如需多张发票,沿用拆账/分账后的账单分别开票口径。
4. `SYS-008` 采用“异步申请 + 查询兜底”模式,成功状态不得被后续失败查询结果覆盖。
5. 电子发票仅在 `SUCCESS` 且存在票据文件地址时允许客户侧下载或推送。
6. 发票作废、红冲由 `SYS-008` 统一承接,当前阶段仅保留状态与文档入口,不纳入一期正常闭环实现范围。
### 后台申请入口与校验补充
- 后台支持营业收费员、财务人员按单笔或批量已收费账单发起开票申请。
- 申请时至少校验:账单收费状态、开票状态、客户开票信息完整性、票种适配性、开票限额、账单集合是否属于同一客户。
- 企业抬头场景重点校验纳税人识别号;电子发票场景重点校验邮箱/手机号;不满足条件时直接返回不可开票原因。
- 申请成功后生成申请单号并进入 `SUBMITTED/PENDING` 状态流转,失败校验场景不进入外部协同。
- 幂等控制以 `applicationNo``custId + chargeIds` 为主,避免相同账单组合重复申请。
### SYS-008 异步协同与查询补偿
- 本地申请校验通过后,`SYS-002` 先写入 `biz_invoice` 申请记录,再向 `SYS-008` 发起异步开票请求,并记录 `sysRequestNo` 作为后续查询与回写的协同主键。
- `SYS-008` 返回“已受理”后,发票状态转为 `PENDING`;若仅完成本地受理但尚未拿到受理号,则保留 `SUBMITTED` 并进入待补偿查询状态。
- 查询补偿采用“回写优先、主动查询兜底”原则:`IF-EXT-007` 回写为首选结果来源,后台人工查询与系统定时补偿查询共用同一结果落账逻辑。
- 系统补偿查询至少保留最近查询时间、下次计划查询时间、累计查询次数、最近一次返回结果摘要与异常原因,便于问题追踪和人工核查。
- 后台按申请单号或受理号触发查询时,应同步刷新查询上下文;查询仍未取得终态时,仅更新补偿上下文,不得伪造成功或失败结论。
### 终态保护与异常核查
- `SUCCESS` 属于正常开票闭环终态,一旦已取得有效发票代码、发票号码或电子票据地址,后续失败查询结果不得覆盖成功状态。
- `FAIL` 仅在 `SYS-008` 明确返回失败结论或多次补偿查询确认失败时写入,并同步保留失败原因、最近查询结果与人工核查依据。
- 当后台人工查询、系统补偿查询与外部回写结果不一致时,应以最新有效外部凭据为准,并记录差异说明,不允许直接覆盖既有成功票据关键信息。
- 每次提交协同、主动查询、状态变更和异常分支均应写入操作留痕,确保能够追溯责任人、触发来源、状态前后值与异常说明。
### 结果回写、账单关联与客户侧消费
- `IF-EXT-007` 回写成功结果时,除更新 `biz_invoice.invoice_status``invoice_code``invoice_number``file_url` 外,还应同步刷新账单快照、账单关联状态与推送状态初值。
- 账单关联以 `biz_invoice.charge_id` + `charge_ids_snapshot` 记录本次开票覆盖账单集合,并同步把对应 `biz_charge.invoice_state` 更新为“开票完成”,保留失败原因与开票时间,便于账单明细、收费记录和客户侧结果统一展示。
- 客户侧查询仅允许按本人 `custId` 访问已存在的发票记录;可通过 `invoiceId``applicationNo``sysRequestNo` 定位,但都必须命中同一客户名下记录。
- 客户侧下载与推送前必须校验发票状态为 `SUCCESS``fileUrl` 非空;不满足条件时仅返回不可下载/推送原因,不得伪造文件地址。
- 推送动作应记录推送渠道、目标邮箱/手机号与结果状态;成功后更新 `pushStatus=PUSHED`,失败则写入 `FAIL` 并保留失败原因供人工处理。
### 核心数据
@ -392,8 +438,9 @@ flowchart TD
### 接口映射
- `IF-REV-008`:营收侧发票申请与票据状态查询。
- `IF-CS-004`:客户侧电子发票申请入口,复用发票申请链路。
- `IF-REV-008`:后台发票申请接口,负责单笔/批量申请、幂等控制与受理号生成。
- `IF-REV-009`:发票结果查询接口,负责后台按申请单号/受理号查询以及系统补偿查询。
- `IF-CS-004`:客户侧电子发票消费接口,负责已开票结果查看、下载、推送。
- `IF-EXT-007`:发票结果回写协同接口(由发票服务侧回传)。
### 落地边界

View File

@ -1107,9 +1107,18 @@ retrieval_priority: P0
### biz_invoice / biz_invoice_taxrate (发票主表与税率表)
| 表名 | 关键字段 | 说明 |
| :--- | :--- | :--- |
| `biz_invoice` | `code`, `cust_id`, `charge_id`, `invoice_status`, `invoice_amount` | 发票主表 |
| `biz_invoice` | `code`, `cust_id`, `charge_id`, `invoice_status`, `invoice_amount` | 发票主表,统一承接申请单号、账单关联、受理号、开票结果与电子票地址等核心状态 |
| `biz_invoice_taxrate` | `tax_code`, `tax_name`, `tax_rate`, `status` | 税率基础配置 |
#### REV-005 发票承接口径
| 对象 | 已有字段 | 待补字段 | 仅快照/历史只读字段 |
| :--- | :--- | :--- | :--- |
| `biz_invoice` 发票申请/结果主对象 | `code``cust_id``charge_id``invoice_status``invoice_amount` | `application_no``sys_request_no``invoice_type``invoice_title``tax_no``email``mobile``source_channel``fail_reason``invoice_code``invoice_number``file_url``last_try_time``next_try_time``try_count``push_status``charge_ids_snapshot``charge_bind_status` | 旧开票批次号、旧配置版本号、旧平台扩展回执 |
| `biz_cust_invoice` 客户开票信息 | `cust_id``invoice_title``tax_no``email``mobile` | 企业/个人抬头类型、默认推送方式等扩展属性按后续实现补齐 | 旧抬头版本、历史修改快照 |
| `biz_invoice_taxrate` 税率配置 | `tax_code``tax_name``tax_rate``status` | 税率生效区间、适用票种范围等扩展控制字段 | 旧税率版本快照 |
| 账单-发票关系快照 | 当前主模型通过 `biz_invoice``biz_charge*` 关联承接 | `charge_ids_snapshot`、账单集合来源、客户侧身份匹配结果、操作留痕标识 | 旧营业账开票关系表、旧发票明细表 |
### biz_operat_log / biz_operat_log_detail (操作留痕表)
| 表名 | 关键字段 | 说明 |
| :--- | :--- | :--- |

View File

@ -262,8 +262,8 @@ retrieval_priority: P0
| IF-REV-005 | 账单生成接口 | REV-002 | 根据抄表结果、价格模板和费用组成生成账单 | `biz_charge``biz_charge_detail``biz_price_template``biz_cost_component` |
| IF-REV-006 | 缴费处理接口 | REV-003 | 创建收费记录、核销账单、回写收款结果 | `biz_collection``biz_charge``bk_transaction` |
| IF-REV-007 | 账务调整接口 | REV-004 | 发起金额调整、退款、冲正、坏账等业务处理 | `biz_charge``biz_charge_detail``biz_operat_log` |
| IF-REV-008 | 发票申请接口 | REV-005 | 发起开票申请并接收票据状态回写 | `biz_invoice``biz_invoice_taxrate``biz_cust_invoice` |
| IF-REV-009 | 催缴任务接口 | REV-006 | 生成催缴名单并提交消息触达请求 | `biz_charge`、`biz_operat_log` |
| IF-REV-008 | 发票申请接口 | REV-005 | 后台发起单笔/批量开票申请并生成受理主键 | `biz_invoice``biz_invoice_taxrate``biz_cust_invoice` |
| IF-REV-009 | 发票结果查询接口 | REV-005 | 按申请单号/受理号查询开票结果并执行补偿查询 | `biz_invoice`、`biz_operat_log` |
| IF-REV-010 | 统计查询接口 | REV-007 | 查询营收、收费、欠费、渠道、客户统计结果 | 聚合视图 / 统计结果集 |
| IF-REV-011 | 银行代收协同接口 | REV-008 | 发起代扣、回盘、对账、结算协同 | `biz_withholding``bk_reconcile_batch``bk_settlement_batch` |
| IF-REV-012 | 业务参数配置接口 | REV-009 | 查询和维护价格模板、优惠方案、业务参数配置 | `biz_parameter_settings``biz_price_*``biz_page_settings*` |
@ -275,7 +275,7 @@ retrieval_priority: P0
| IF-CS-001 | 账户绑定接口 | CS-001 | 绑定、解绑、切换默认客户 | `biz_cust_app_binds``biz_cust` |
| IF-CS-002 | 历史账单查询接口 | CS-002 | 查询账单、欠费、用水历史、缴费记录 | `biz_charge``biz_charge_detail``biz_reading_data` |
| IF-CS-003 | 在线支付下单接口 | CS-003 | 创建微信/支付宝线上支付订单 | `biz_charge``biz_collection``bk_transaction` |
| IF-CS-004 | 发票申请接口 | CS-004 | 提交电子发票申请、查询发票状态 | `biz_invoice``biz_cust_invoice` |
| IF-CS-004 | 电子发票消费接口 | CS-004 | 查询、下载、推送本人已开具电子发票 | `biz_invoice``biz_cust_invoice` |
| IF-CS-005 | 网点与业务办理接口 | CS-005 | 查询营业网点、预约信息、可办事项 | `biz_outlets``biz_business_types` |
| IF-CS-006 | 业务办理进度接口 | CS-006 | 提交业务申请、查询办理进度与附件 | `biz_process``biz_process_transfer``biz_content_attach` |
| IF-CS-007 | 柜面扫码支付接口 | CS-007 | 创建柜面扫码支付订单并回写结果 | `biz_collection``bk_transaction``biz_charge` |
@ -410,23 +410,24 @@ retrieval_priority: P0
| 归属模块 | REV-005 |
| 请求方式 | POST |
| 请求路径 | `/admin-api/revenue/invoice/apply` |
| 功能描述 | 发起电子发票或纸质发票申请,并调用 SYS-008 |
| 功能描述 | 后台对已收费未开票账单发起单笔/批量开票申请,生成申请单号并调用 `SYS-008` |
| 核心表 | `biz_invoice``biz_invoice_taxrate``biz_cust_invoice` |
边界约束:
- 发票开具、作废、红冲能力由 `SYS-008` 统一承接。
- `SYS-002` 仅负责业务单据归集、申请发起与结果落账。
- 一期仅支持后台营业收费员/财务人员发起申请,客户侧不直接调用本接口。
- 发票开具、作废、红冲能力由 `SYS-008` 统一承接,`SYS-002` 仅负责业务单据归集、申请发起、查询补偿与结果落账。
- 原始单账单不支持直接任意部分金额开票;如需多张发票,应基于拆账/分账后的账单集合申请。
### IF-REV-009 催缴任务接口
### IF-REV-009 发票结果查询接口
| 项目 | 说明 |
|------|------|
| 接口编号 | IF-REV-009 |
| 归属模块 | REV-006 |
| 归属模块 | REV-005 |
| 请求方式 | POST |
| 请求路径 | `/admin-api/revenue/arrears/remind-task/create` |
| 功能描述 | 生成催缴名单、调用消息服务并回写催缴任务执行结果 |
| 核心表 | `biz_charge`、`biz_charge_detail`、`biz_operat_log` |
| 请求路径 | `/admin-api/revenue/invoice/query` |
| 功能描述 | 后台按申请单号/受理号查询开票结果,并支持系统补偿查询兜底 |
| 核心表 | `biz_invoice`、`biz_operat_log` |
### IF-REV-011 银行代收协同接口
@ -487,15 +488,15 @@ retrieval_priority: P0
- 支付通道、支付回调、对账流水由 `SYS-009` 负责。
- `SYS-002` 负责校验待缴账单、生成业务订单、更新核销结果。
### IF-CS-004 发票申请接口
### IF-CS-004 电子发票消费接口
| 项目 | 说明 |
|------|------|
| 接口编号 | IF-CS-004 |
| 归属模块 | CS-004 |
| 请求方式 | POST |
| 请求路径 | `/app-api/customer/invoice/apply` |
| 功能描述 | 面向客户渠道提交电子发票申请并查询开票状态 |
| 请求方式 | GET / POST |
| 请求路径 | `/app-api/customer/invoice` |
| 功能描述 | 面向客户渠道查询、下载、推送本人已具电子发票 |
| 核心表 | `biz_invoice``biz_cust_invoice``biz_invoice_taxrate` |
### IF-CS-006 业务办理进度接口
@ -766,6 +767,7 @@ retrieval_priority: P0
| 字段 | 类型 | 必填 | 说明 | 主要来源/去向 |
|------|------|------|------|---------------|
| applicationNo | String | 否 | 发票申请单号 | 服务端生成,作为幂等主键之一 |
| custId | Long | 是 | 客户 ID | `biz_invoice.cust_id` |
| chargeIds | Array<Long> | 是 | 开票关联账单 ID 列表 | 业务单据关联 |
| invoiceType | String | 是 | 发票类型:`ELECTRONIC``PAPER` | `biz_invoice.invoice_type` |
@ -773,45 +775,63 @@ retrieval_priority: P0
| taxNo | String | 否 | 税号 | `biz_cust_invoice.tax_no` |
| email | String | 否 | 电子发票接收邮箱 | `biz_cust_invoice.email` |
| mobile | String | 否 | 接收手机号 | `biz_cust_invoice.mobile` |
| taxRateCode | String | 否 | 税率编码 | `biz_invoice_taxrate.tax_code` |
| sourceChannel | String | 是 | 来源渠道:`COUNTER``FINANCE_BACKOFFICE` | 业务来源 |
| remark | String | 否 | 申请备注 | 操作留痕 |
#### 响应参数
| 字段 | 类型 | 说明 | 主要来源 |
|------|------|------|----------|
| invoiceId | Long | 发票申请记录 ID | `biz_invoice.id` |
| invoiceCode | String | 发票申请编号 | `biz_invoice.code` |
| invoiceStatus | String | 状态:`INIT``APPLYING``SUCCESS``FAIL` | `biz_invoice.invoice_status` |
| requestNo | String | 发往 SYS-008 的请求号 | 协同流水 |
| fileUrl | String | 发票文件地址,成功后返回 | 结果回写 |
| applicationNo | String | 发票申请单号 | `biz_invoice.application_no` |
| invoiceStatus | String | 状态:`SUBMITTED``PENDING``REJECTED` | `biz_invoice.invoice_status` |
| sysRequestNo | String | 发往 `SYS-008` 的受理号 | 协同流水 |
| msg | String | 处理说明 | 返回消息 |
### IF-REV-009 催缴任务接口
#### 申请校验与幂等约束
- 所有关联账单必须满足“已收费、未开票、未作废”。
- 一期不支持原始单账单直接任意部分金额开票;如需多张发票,必须基于拆账/分账后的账单集合发起申请。
- 企业抬头场景应校验 `taxNo` 完整性;电子发票场景优先校验 `email``mobile` 至少一项可用。
- 幂等键优先使用 `applicationNo`,未传入时按 `custId + chargeIds` 组合控制重复申请。
- 申请成功后必须创建查询补偿上下文,不依赖回调作为唯一结果来源。
### IF-REV-009 发票结果查询接口
#### 请求参数
| 字段 | 类型 | 必填 | 说明 | 主要来源/去向 |
|------|------|------|------|---------------|
| taskType | String | 是 | 任务类型:`AUTO``MANUAL` | 任务参数 |
| billPeriod | String | 否 | 账期范围 | `biz_charge.bill_period` |
| minArrearsAmount | Decimal | 否 | 最小欠费金额 | 任务筛选条件 |
| overdueDays | Integer | 否 | 最小逾期天数 | 任务筛选条件 |
| templateCode | String | 是 | 消息模板编码 | 模板参数 |
| channelList | Array<String> | 是 | 发送渠道列表,如 `SMS``WECHAT``APP` | 消息参数 |
| customerScope | Array<Long> | 否 | 指定客户范围 | `biz_charge.cust_id` |
| operatorId | Long | 否 | 发起人 ID | 操作上下文 |
| applicationNo | String | 否 | 发票申请单号,与 `sysRequestNo` 二选一 | `biz_invoice.application_no` |
| sysRequestNo | String | 否 | `SYS-008` 受理号,与 `applicationNo` 二选一 | `biz_invoice.sys_request_no` |
| querySource | String | 是 | 查询来源:`MANUAL``AUTO_COMPENSATE``CALLBACK_VERIFY` | 查询触发上下文 |
#### 响应参数
| 字段 | 类型 | 说明 | 主要来源 |
|------|------|------|----------|
| taskNo | String | 催缴任务编号 | 业务流水 |
| generateCount | Integer | 生成催缴对象数量 | 汇总结果 |
| sendCount | Integer | 已发送数量 | 消息结果 |
| failCount | Integer | 发送失败数量 | 消息结果 |
| pendingReviewCount | Integer | 待人工复核数量 | 业务判断 |
| invoiceId | Long | 发票主记录 ID | `biz_invoice.id` |
| applicationNo | String | 发票申请单号 | `biz_invoice.application_no` |
| sysRequestNo | String | `SYS-008` 受理号 | `biz_invoice.sys_request_no` |
| invoiceStatus | String | 状态:`SUBMITTED``PENDING``SUCCESS``FAIL` | `biz_invoice.invoice_status` |
| invoiceCode | String | 发票代码 | `biz_invoice.invoice_code` |
| invoiceNumber | String | 发票号码 | `biz_invoice.invoice_number` |
| fileUrl | String | 电子发票文件地址 | `biz_invoice.file_url` |
| failReason | String | 失败原因 | `biz_invoice.fail_reason` |
| pushStatus | String | 电子发票推送状态 | `biz_invoice.push_status` |
| lastQueryTime | DateTime | 最近一次查询时间 | `biz_invoice.last_try_time` |
| tryCount | Integer | 累计查询次数 | `biz_invoice.try_count` |
| latestResult | String | 最近一次查询结果摘要 | `biz_invoice.latest_result` |
| latestError | String | 最近一次查询异常说明 | `biz_invoice.latest_error` |
| msg | String | 处理说明 | 返回消息 |
#### 查询补偿与状态流转约束
- 查询入口同时服务于后台人工查询与系统补偿查询,两类触发必须复用同一状态落账规则。
- 当 `querySource=AUTO_COMPENSATE` 时,接口语义表示由系统补偿任务触发一次兜底查询,并刷新最近查询时间、下次计划时间与累计次数。
- 查询结果若确认开票成功,应回写票号、票据地址与账单-发票关联状态;若仍处理中,仅维持 `PENDING` 并更新补偿上下文。
- 已进入 `SUCCESS` 的发票记录不得被后续失败查询结果覆盖;若外部返回异常,应记录到操作留痕并保留人工核查入口。
### IF-REV-011 银行代收协同接口
#### 请求参数
@ -913,30 +933,48 @@ retrieval_priority: P0
| list[].payStatus | String | 缴费状态 | 业务状态 |
| list[].invoiceStatus | String | 开票状态 | `biz_invoice.invoice_status` |
### IF-CS-004 发票申请接口
### IF-CS-004 电子发票消费接口
#### 请求参数
#### 查询/下载请求参数
| 字段 | 类型 | 必填 | 说明 | 主要来源/去向 |
|------|------|------|------|---------------|
| custId | Long | 是 | 客户 ID | `biz_invoice.cust_id` |
| chargeIds | Array<Long> | 是 | 开票关联账单 ID | 业务单据关联 |
| invoiceTitle | String | 是 | 发票抬头 | `biz_cust_invoice.invoice_title` |
| taxNo | String | 否 | 税号 | `biz_cust_invoice.tax_no` |
| email | String | 否 | 电子发票邮箱 | `biz_cust_invoice.email` |
| mobile | String | 否 | 接收手机号 | `biz_cust_invoice.mobile` |
| invoiceType | String | 否 | 默认 `ELECTRONIC` | `biz_invoice.invoice_type` |
| invoiceId | Long | 否 | 发票记录 ID三选一优先键 | `biz_invoice.id` |
| applicationNo | String | 否 | 发票申请单号 | `biz_invoice.application_no` |
| sysRequestNo | String | 否 | `SYS-008` 受理号 | `biz_invoice.sys_request_no` |
#### 推送请求参数
| 字段 | 类型 | 必填 | 说明 | 主要来源/去向 |
|------|------|------|------|---------------|
| custId | Long | 是 | 客户 ID | `biz_invoice.cust_id` |
| invoiceId | Long | 是 | 发票记录 ID | `biz_invoice.id` |
| applicationNo | String | 否 | 发票申请单号 | `biz_invoice.application_no` |
| pushChannel | String | 是 | 推送方式:`EMAIL``SMS` | 推送动作 |
| pushEmail | String | 否 | 推送邮箱,`EMAIL` 时优先使用 | 目标地址 |
| pushMobile | String | 否 | 推送手机号,`SMS` 时优先使用 | 目标地址 |
#### 响应参数
| 字段 | 类型 | 说明 | 主要来源 |
|------|------|------|----------|
| invoiceId | Long | 发票申请 ID | `biz_invoice.id` |
| invoiceCode | String | 发票申请编号 | `biz_invoice.code` |
| invoiceId | Long | 发票记录 ID | `biz_invoice.id` |
| applicationNo | String | 发票申请单号 | `biz_invoice.application_no` |
| invoiceStatus | String | 当前状态 | `biz_invoice.invoice_status` |
| fileUrl | String | 发票下载地址 | 结果回写 |
| invoiceCode | String | 发票代码 | `biz_invoice.invoice_code` |
| invoiceNumber | String | 发票号码 | `biz_invoice.invoice_number` |
| fileUrl | String | 发票下载地址 | `biz_invoice.file_url` |
| pushStatus | String | 推送状态:`NONE``PUSHED``FAIL` | `biz_invoice.push_status` |
| chargeBindStatus | String | 账单关联状态:`UNBOUND``BOUND` | `biz_invoice.charge_bind_status` |
| msg | String | 处理说明 | 返回消息 |
#### 客户侧消费约束
- 客户侧仅允许访问本人 `custId` 名下发票记录,`invoiceId``applicationNo``sysRequestNo` 任一定位成功后仍需再次校验客户归属。
- 下载与推送前必须校验 `invoiceStatus=SUCCESS``fileUrl` 非空;不满足条件时返回不可消费原因。
- 推送成功后回写 `pushStatus=PUSHED`;失败则更新为 `FAIL` 并记录失败原因。
### IF-CS-003 在线支付下单接口
#### 请求参数
@ -1206,7 +1244,7 @@ sequenceDiagram
SYS002-->>Client: 查询订单时返回最新支付状态
```
### 2. 电子发票申请与回写时序
### 2. 电子发票申请、查询补偿与回写时序
```mermaid
sequenceDiagram
@ -1215,15 +1253,25 @@ sequenceDiagram
participant SYS002 as SYS-002营收系统
participant SYS008 as SYS-008发票服务
participant Tax as 税控/开票平台
participant Job as 查询补偿任务
Counter->>SYS002: 提交发票申请(IF-REV-008/IF-CS-004)
SYS002->>SYS002: 校验客户、账单、开票抬头与金额
SYS002->>SYS002: 生成发票申请记录biz_invoice
SYS002->>SYS002: 生成发票申请记录biz_invoice(SUBMITTED)
SYS002->>SYS008: 发起开票协同(IF-EXT-006)
SYS008->>Tax: 调用税控或电子发票平台
Tax-->>SYS008: 返回受理结果/票号/文件地址
SYS008-->>SYS002: 回写开票结果(IF-EXT-007)
SYS002->>SYS002: 更新biz_invoice状态与票据地址
SYS008-->>SYS002: 返回受理号或异步结果
SYS002->>SYS002: 记录sysRequestNo并更新为PENDING
alt 发票服务主动回写
SYS008-->>SYS002: 回写开票结果(IF-EXT-007)
SYS002->>SYS002: 更新biz_invoice状态、票据地址与账单关联
else 未收到终态结果
Job->>SYS002: 触发补偿查询(IF-REV-009)
SYS002->>SYS008: 按申请单号/受理号查询结果
SYS008-->>SYS002: 返回处理中/成功/失败
SYS002->>SYS002: 刷新查询上下文并按终态规则落账
end
SYS002-->>Counter: 返回申请结果或供后续查询
```

View File

@ -0,0 +1,68 @@
# Contract: IF-REV-008 发票申请接口
## 1. 合同定位
本合同用于固化 REV-005 一期后台发票申请 / 单笔与批量开票接口口径,服务于后续正式接口文档修订、任务拆解与 backend 实施。
## 2. 适用范围
适用场景:
- 后台营业收费员 / 财务人员发起单笔开票
- 后台按已收费账单集合批量发起开票
- 生成发票申请记录并提交 `SYS-008`
不适用范围:
- 客户侧直接申请开票
- 原始单账单直接任意部分金额开票
- 复杂拆分/合并开票策略配置
## 3. 请求合同
| 字段 | 类型 | 必填 | 说明 | 约束 |
|------|------|------|------|------|
| applicationNo | String | 否 | 发票申请单号 | 服务端生成,作为幂等主键之一 |
| chargeIds | Array<Long> | 是 | 关联账单 ID 列表 | 所有账单必须已收费且未开票 |
| custId | Long | 是 | 客户 ID | 必须存在可用开票信息 |
| invoiceType | String | 是 | 发票类型 | `ELECTRONIC` / `PAPER` |
| invoiceTitle | String | 是 | 发票抬头 | 来自 `biz_cust_invoice` 或后台确认输入 |
| taxNo | String | 否 | 纳税人识别号 | 企业抬头场景建议必填 |
| email | String | 否 | 接收邮箱 | 电子发票场景优先使用 |
| mobile | String | 否 | 接收手机号 | 推送或通知场景使用 |
| sourceChannel | String | 是 | 来源渠道 | `COUNTER` / `FINANCE_BACKOFFICE` |
| remark | String | 否 | 申请备注 | 进入操作留痕 |
## 4. 响应合同
| 字段 | 类型 | 说明 | 约束 |
|------|------|------|------|
| invoiceId | Long | 发票申请记录 ID | 对应 `biz_invoice.id` |
| applicationNo | String | 发票申请单号 | 后续查询与幂等主键 |
| invoiceStatus | String | 当前状态 | `SUBMITTED` / `PENDING` / `REJECTED` |
| sysRequestNo | String | `SYS-008` 受理号 | 异步查询主键 |
| msg | String | 处理说明 | 不可开票时返回明确原因 |
## 5. 共性规则
1. 所有账单必须处于“已收费、未开票、未作废”状态。
2. 一期不支持对原始单账单直接任意部分金额开票。
3. 如需多张发票,需来源于拆账/分账后的账单集合。
4. 幂等控制可采用 `applicationNo``custId + chargeIds` 组合。
5. 申请成功后必须生成查询补偿任务,不可依赖回调作为唯一结果来源。
6. 所有申请动作必须写入操作留痕。
## 6. 物理承接口径
| 逻辑对象 | 物理承接 |
|---------|----------|
| 发票申请主对象 | `biz_invoice` |
| 客户开票信息 | `biz_cust_invoice` |
| 税率配置 | `biz_invoice_taxrate` |
| 关联账单 | `biz_charge*` |
| 操作留痕 | `biz_operat_log*` |
## 7. 验收关注点
- 是否支持后台单笔 / 批量已收费账单开票
- 是否拒绝原始单账单直接部分金额开票
- 是否生成申请单号与查询主键
- 是否与 `SYS-008` 查询兜底模式一致

View File

@ -0,0 +1,65 @@
# Contract: IF-REV-009 发票结果查询与客户侧消费接口
## 1. 合同定位
本合同用于固化 REV-005 一期发票结果查询、查询兜底补偿以及客户侧查看/下载/推送已开票电子发票的统一口径。
## 2. 适用范围
适用场景:
- 后台按申请单号 / 受理号查询发票最终状态
- 系统定时轮询 `SYS-008` 获取开票结果
- 客户侧查看已开具电子发票
- 客户侧下载、推送电子发票
不适用范围:
- 客户侧直接发起开票申请
- 发票作废 / 红冲全流程深度处理
## 3. 查询请求合同
| 字段 | 类型 | 必填 | 说明 | 约束 |
|------|------|------|------|------|
| applicationNo | String | 否 | 发票申请单号 | 与 `sysRequestNo` 二选一 |
| sysRequestNo | String | 否 | 外部受理号 | 与 `applicationNo` 二选一 |
| custId | Long | 否 | 客户 ID | 客户侧查询时使用 |
| querySource | String | 是 | 查询来源 | `SYSTEM_JOB` / `ADMIN` / `CUSTOMER` |
| pushEmail | String | 否 | 推送邮箱 | 客户侧推送时使用 |
## 4. 查询响应合同
| 字段 | 类型 | 说明 | 约束 |
|------|------|------|------|
| invoiceId | Long | 发票记录 ID | 对应 `biz_invoice.id` |
| applicationNo | String | 发票申请单号 | 幂等主键 |
| invoiceStatus | String | 发票状态 | `PENDING` / `SUCCESS` / `FAIL` / `INVALID` / `RED_INK` |
| invoiceCode | String | 发票代码 | 成功后返回 |
| invoiceNumber | String | 发票号码 | 成功后返回 |
| fileUrl | String | 电子票下载地址 | 成功后返回 |
| failReason | String | 失败原因 | 失败时返回 |
| pushStatus | String | 推送状态 | `NONE` / `PUSHED` / `FAIL` |
| lastQueryTime | DateTime | 最近查询时间 | 用于补偿追踪 |
## 5. 共性规则
1. 查询兜底是开票结果获取的必备路径,不可省略。
2. 已成功开票状态不得被后续失败结果覆盖。
3. 客户侧只允许查询、下载、推送属于当前客户的已开票电子发票。
4. 下载/推送前必须校验发票状态为 `SUCCESS` 且存在 `fileUrl`
5. 查询补偿任务需记录 `lastTryTime``nextTryTime``tryCount` 等信息。
## 6. 物理承接口径
| 逻辑对象 | 物理承接 |
|---------|----------|
| 发票结果主对象 | `biz_invoice` |
| 客户查询身份与资料 | `biz_cust_invoice` |
| 查询补偿与结果留痕 | `biz_invoice` 扩展字段 + `biz_operat_log*` |
| 账单发票摘要展示 | `biz_charge*` + 历史关系快照 |
## 7. 验收关注点
- 是否支持后台按申请单号 / 受理号查询结果
- 是否支持系统任务轮询补偿
- 是否支持客户侧查看、下载、推送已开票电子发票
- 是否避免客户侧越权查询和重复推送

View File

@ -0,0 +1,170 @@
# Data Model: REV-005 发票业务流实现
## 建模原则
- 以“逻辑实体 + 现有在线主表承接 + 历史关系快照”三层表达,避免把旧系统全部 IV_* 细表误写为当前已落地在线表。
- 后台开票、客户侧查询下载、`SYS-008` 查询兜底、结果回写统一围绕单一发票申请主线建模。
- 一期不支持原始单账单直接任意部分开票,但关系模型需兼容拆账/分账后的多账单、多发票映射扩展。
## 实体一InvoiceApplication发票申请单
### 作用
统一承接后台单笔/批量已收费账单的发票申请输入,是 `IF-REV-008` 的主业务对象。
### 核心字段
| 字段 | 类型 | 说明 |
|------|------|------|
| applicationNo | String | 发票申请单号 / 协同请求号 |
| chargeIds | Array<Long> | 关联账单 ID 列表 |
| custId | Long | 客户 ID |
| invoiceType | Enum | `ELECTRONIC` / `PAPER` |
| invoiceTitle | String | 发票抬头 |
| taxNo | String | 纳税人识别号 |
| invoiceAmount | Decimal | 本次申请开票总金额 |
| receiverEmail | String | 电子票接收邮箱 |
| receiverMobile | String | 电子票接收手机号 |
| sourceChannel | Enum | `COUNTER` / `FINANCE_BACKOFFICE` |
| applyStatus | Enum | `SUBMITTED` / `ACCEPTED` / `REJECTED` |
| appliedAt | DateTime | 申请时间 |
### 校验规则
- `chargeIds``custId``invoiceType``invoiceTitle` 必填。
- 账单必须满足“已收费、未开票、未作废”。
- 原始单账单不允许直接任意部分金额开票;如需多张发票应来源于拆账/分账后的账单集合。
- 对同一账单组合的重复申请需按 `applicationNo``custId + chargeIds` 做幂等控制。
### 物理承接
- 主承接:`biz_invoice`
- 关联输入:`biz_cust_invoice``biz_charge*`
## 实体二InvoiceRecord发票记录
### 作用
描述发票服务受理、开具成功/失败、票号回写、电子票文件地址等结果信息。
### 核心字段
| 字段 | 类型 | 说明 |
|------|------|------|
| invoiceId | Long | 发票记录 ID |
| applicationNo | String | 对应申请单号 |
| sysRequestNo | String | `SYS-008` 受理号 / 外部请求号 |
| invoiceStatus | Enum | `PENDING` / `SUCCESS` / `FAIL` / `INVALID` / `RED_INK` |
| invoiceCode | String | 发票代码 |
| invoiceNumber | String | 发票号码 |
| invoiceDate | DateTime | 开票日期 |
| fileUrl | String | 电子发票下载地址 |
| failReason | String | 开票失败原因 |
| pushStatus | Enum | `NONE` / `PUSHED` / `FAIL` |
| updatedAt | DateTime | 最近状态更新时间 |
### 状态关系
- `PENDING` 表示已提交给 `SYS-008` 但尚未确认最终结果。
- `SUCCESS` 后允许客户侧查询、下载、推送电子发票。
- `FAIL` 记录失败原因并进入异常核查或人工重试。
### 物理承接
- 主承接:`biz_invoice`
- 历史参照:旧 `IV_INVOICE_INFOS`
## 实体三ChargeInvoiceRelation账单-发票关联)
### 作用
承接账单与发票的映射关系,支持单票对应多账单、拆账后分别开票和后续合并开票扩展。
### 核心字段
| 字段 | 类型 | 说明 |
|------|------|------|
| relationId | Long | 关联记录 ID |
| chargeId | Long | 账单 ID |
| invoiceId | Long | 发票 ID |
| applicationNo | String | 申请单号 |
| relationType | Enum | `FULL_AMOUNT` / `SPLIT_BILL` / `MERGED_BILL` |
| invoiceAmount | Decimal | 当前账单对应开票金额 |
| relationStatus | Enum | `PENDING` / `BOUND` / `FAILED` |
| snapshotVersion | String | 开票配置/税率快照版本 |
### 关键规则
- 一期默认 `relationType=FULL_AMOUNT``SPLIT_BILL`(来自拆账后的账单),不支持对原始单账单直接自由部分金额开票。
- 发票成功后必须把关系状态更新为 `BOUND`,并可供账单详情查询。
### 物理承接
- 在线主承接:`biz_invoice` + 历史关系快照
- 历史参照:旧 `IV_CHARGE_INVOICES``IV_CHARGE_INVOICE_MAPPINGS`
## 实体四InvoiceQueryTask开票查询补偿任务
### 作用
支持异步申请后的轮询查询、超时补偿和人工兜底查询,是“查询兜底”模式的核心对象。
### 核心字段
| 字段 | 类型 | 说明 |
|------|------|------|
| queryTaskId | Long | 查询任务 ID |
| applicationNo | String | 申请单号 |
| sysRequestNo | String | 外部受理号 |
| lastTryTime | DateTime | 最后一次查询时间 |
| nextTryTime | DateTime | 下一次查询时间 |
| tryCount | Integer | 已查询次数 |
| queryStatus | Enum | `WAITING` / `RUNNING` / `DONE` / `FAILED` |
| latestResult | String | 最近一次查询结果摘要 |
| latestError | String | 最近一次查询错误 |
### 关键规则
- 申请成功后默认生成查询任务。
- 查询到终态后任务进入 `DONE`
- 查询异常不应覆盖已成功开票状态,只记录异常并等待人工或系统补偿。
### 物理承接
- 主承接:`biz_invoice` 扩展字段或关联查询日志对象
- 历史参照:旧发票表中的 `last_try_time``next_try_time``try_count`
## 实体五InvoiceResultWriteBack结果回写
### 作用
统一描述 `SYS-008` 查询结果或主动回传结果进入营收域后的状态变更、幂等控制和操作留痕。
### 核心字段
| 字段 | 类型 | 说明 |
|------|------|------|
| writeBackNo | String | 回写流水号 |
| applicationNo | String | 申请单号 |
| invoiceStatus | Enum | 发票状态 |
| writeBackStatus | Enum | `SUCCESS` / `IGNORE_REPEAT` / `FAIL` |
| invoiceCode | String | 发票代码 |
| invoiceNumber | String | 发票号码 |
| fileUrl | String | 下载地址 |
| rawPayload | String | 原始回写/查询响应 |
| processedAt | DateTime | 处理时间 |
| processedBy | String | 系统任务 / 人工处理人 |
### 关键规则
- 按 `applicationNo + invoiceStatus` 做幂等控制。
- 已成功开票后收到失败结果,不覆盖成功状态,转入异常核查。
- 所有回写处理必须记录到操作留痕对象。
### 物理承接
- 主承接:`biz_invoice` + `biz_operat_log*`
## 关系总览
```text
InvoiceApplication --> InvoiceRecord
InvoiceApplication --> ChargeInvoiceRelation
InvoiceApplication --> InvoiceQueryTask
InvoiceRecord --> InvoiceResultWriteBack
ChargeInvoiceRelation --> biz_charge* (N:1)
InvoiceApplication --> biz_cust_invoice
InvoiceApplication --> biz_invoice_taxrate
InvoiceResultWriteBack --> biz_operat_log*
```
## 状态与边界说明
- 一期默认后台申请、客户侧结果消费,不定义客户侧直接申请状态机。
- 作废、红冲作为 REV-005 后续能力保留在数据模型中,但 implement 时优先保证正常开票闭环。
- 旧发票明细、营业账开票关系、配置快照对象在当前阶段仅作为历史参照和追溯来源,不表述为已确认新增在线独立表。

View File

@ -0,0 +1,185 @@
# Implementation Plan: REV-005 发票业务流实现
**Branch**: `002-rev005-invoice-flow` | **Date**: 2026-03-16 | **Spec**: `/specs/002-rev005-invoice-flow/spec.md`
**Input**: Feature specification from `/specs/002-rev005-invoice-flow/spec.md`
## Summary
本轮围绕 `REV-005` 发票业务流补齐从已收费账单到电子发票结果落账的业务闭环,形成可直接指导 backend 实施与正式文档修订的 planning 产物。计划目标是在既有 `biz_invoice``biz_cust_invoice``biz_invoice_taxrate` 基础上,明确发票申请、后台批量/单笔开票、`SYS-008` 异步协同与查询兜底、结果回写、账单-发票关联、客户侧查询下载推送的实现口径。
本次计划输出以 spec 澄清结果为准:一期采用“后台开票 + 客户侧查询下载”模式;`SYS-008` 对接采用“异步申请 + 轮询查询兜底”;不支持原始单账单直接任意部分金额开票,如需多张发票沿用老系统拆账/分账后的账单分别开票;正式主文档需回写 `12_REV_Detailed.md``03_Interface_Design.md``01_Database_Design.md`backend 侧则在现有 `InvoiceController.java``InvoiceServiceImpl.java` 基础上扩展业务接口与服务能力。
## Technical Context
**Primary Work Product**: REV-005 planning 设计产物,包括实施计划、研究结论、数据模型、接口合同与最小校验说明。
**Source of Truth Documents**:
- `specs/002-rev005-invoice-flow/spec.md`
- `.specify/memory/constitution.md`
- `docs/design/02_Detailed_Design/12_REV_Detailed.md`
- `docs/design/03_Technical_Design/03_Interface_Design.md`
- `docs/design/03_Technical_Design/01_Database_Design.md`
**Reference Sources**:
- `docs/guides/BACKEND_CURRENT_STATUS.md`
- `docs/guides/BACKEND_TABLE_MAPPING.md`
- `docs/design/04_Appendix/Archive/02_Manuals/营收系统_用户操作手册.md`
- `docs/design/04_Appendix/Archive/02_Manuals/福建水投微网厅操作手册.md`
- `docs/design/04_Appendix/Archive/03_Design_Docs/营业收费管理系统-概要设计说明书20250912.md`
- `docs/design/04_Appendix/Archive/05_Data_Dictionary/营收数据字典.md`
- `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/invoice/InvoiceController.java`
- `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/invoice/InvoiceServiceImpl.java`
**Validation Commands**:
- `make validate-file FILE=docs/design/02_Detailed_Design/12_REV_Detailed.md`
- `make validate-file FILE=docs/design/03_Technical_Design/03_Interface_Design.md`
- `make validate-file FILE=docs/design/03_Technical_Design/01_Database_Design.md`
- `make check-links`
- `make validate-mermaid`
**Target Scope**:
- `REV-005` 正式详细设计补充
- `IF-REV-008`(后台发票申请/开具)与 `IF-CS-004`(客户侧查询下载)口径收敛
- 新增 `IF-REV-009` 发票结果查询/补偿查询口径
- `biz_invoice*``biz_cust_invoice`、账单-发票关联与历史关系快照的承接口径
- backend 发票业务 Service/Controller 扩展边界
**Project Type**: 文档治理仓库(同时为 backend 实施提供 planning 输入)
**Constraints**:
- 不新增平行正式主稿
- 不发明超出主文档与老系统交集的新业务规则
- Archive 仅作核对与追溯来源,不替代正式结论
- 一期默认后台开票,客户侧不直接申请开票
- 一期不支持原始单账单直接任意部分金额开票
- `SYS-008` 结果获取采用查询兜底,不假设回调可用
- 本轮 implement 默认聚焦正常开票闭环,作废/红冲仅保留正式文档与后续任务预留,不作为一期必交付开发范围
- 仓库内引用保持相对路径口径
**Scale/Scope**: 跨文档 + backend 实施 planning覆盖 1 个 feature spec、1 个 implementation plan、1 份 research、1 份 data-model、2 份 contracts、1 份 quickstart并为后续 tasks/implement 提供输入。
## Constitution Check
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
- [x] **主文档归属已确认**:本轮 planning 产物落在 `specs/002-rev005-invoice-flow/`,正式口径将回写既有 `12_REV_Detailed.md``03_Interface_Design.md``01_Database_Design.md`,不新增平行正式稿。
- [x] **范围基线已确认**`REV-005``12_REV_Detailed.md``03_Interface_Design.md`、旧系统操作手册、数据字典中均有明确发票管理/电子发票交集口径,可直接推进;原始单账单任意部分开票未作为一期主能力纳入。
- [x] **Archive 使用方式合规**Archive 仅作为老系统能力、字段与菜单口径来源,正式结论仍以当前主文档与 spec 澄清结果为准。
- [x] **一致性影响已列出**:已识别 `IF-REV-008` / `IF-CS-004` / 发票查询补偿接口编号、`biz_invoice*` 承接口径、旧“回调”改为“查询兜底”、后台/客户侧入口边界等一致性项。
- [x] **校验与台账动作已规划**已明确正式文档最小校验命令plan 阶段仅生成 planning 产物,不强制更新 `01_Project_Progress.md` / `03_Task_Checklist.md`,待正式主文档修订或任务闭环后再回写。
### Post-Design Re-check
- [x] 设计产物保持“主文档修订 + backend 实施 planning”定位没有绕开单一真源另写平行正式稿。
- [x] `data-model.md` 采用逻辑实体 + 现有物理承接 + 历史关系快照三层表达,没有把旧系统全部细表表述为当前已落地在线表。
- [x] `contracts/` 中接口合同统一回扣后台开票、客户侧查询下载、`SYS-008` 查询兜底与幂等回写口径。
- [x] `quickstart.md` 仅定义评审入口、最小校验与 backend 验证建议,不引入超范围部署/发布动作。
- [x] 结果获取方式统一为“异步申请 + 查询兜底”,不再保留与航信接口事实冲突的“直接回调”口径。
## Project Structure
### Documentation (this feature)
```text
specs/002-rev005-invoice-flow/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│ ├── if-rev-008-invoice-application.md
│ └── if-rev-009-invoice-query.md
└── tasks.md
```
### Repository Touchpoints
```text
docs/design/
├── 00_Management/
│ ├── 01_Project_Progress.md
│ ├── 02_Delivery_Standards.md
│ └── 03_Task_Checklist.md
├── 02_Detailed_Design/
│ └── 12_REV_Detailed.md
├── 03_Technical_Design/
│ ├── 01_Database_Design.md
│ └── 03_Interface_Design.md
└── 04_Appendix/Archive/
backend/sw-business/sw-business-server/
├── src/main/java/cn/com/emsoft/sw/business/controller/admin/invoice/InvoiceController.java
└── src/main/java/cn/com/emsoft/sw/business/service/invoice/InvoiceServiceImpl.java
```
**Structure Decision**:
- `specs/002-rev005-invoice-flow/spec.md`:作为 REV-005 范围、澄清结果与验收边界总源。
- `specs/002-rev005-invoice-flow/plan.md`:承接当前计划阶段的实施组织、门禁与结构决策。
- `specs/002-rev005-invoice-flow/research.md`:沉淀异步查询兜底、后台/客户侧边界、老系统对齐与物理承接口径等关键选择。
- `specs/002-rev005-invoice-flow/data-model.md`:固化发票申请、发票记录、账单发票关联、查询补偿与结果回写对象。
- `specs/002-rev005-invoice-flow/contracts/if-rev-008-invoice-application.md`:统一后台发票申请/批量开票合同。
- `specs/002-rev005-invoice-flow/contracts/if-rev-009-invoice-query.md`:统一查询兜底、结果查询与客户侧查询下载合同。
- `specs/002-rev005-invoice-flow/quickstart.md`:提供文档评审、最小校验与 backend 验证入口。
- `docs/design/02_Detailed_Design/12_REV_Detailed.md`:后续正式补充 REV-005 业务规则、状态流转和旧系统对齐说明。
- `docs/design/03_Technical_Design/03_Interface_Design.md`:后续正式补充 `IF-REV-008``IF-REV-009` 与客户侧查询下载口径。
- `docs/design/03_Technical_Design/01_Database_Design.md`:后续正式补充 `biz_invoice*`、账单-发票关联快照与历史关系承接口径。
- `InvoiceController.java` / `InvoiceServiceImpl.java`:后续实现阶段扩展后台申请、查询、回写与批量开票能力,不再仅限配置 CRUD。
## Phase 0 Research Summary
1. 一期采用“后台开票 + 客户侧查询下载推送”的入口策略,后台营业收费员/财务人员负责申请和开具,客户侧不直接发起开票申请。
2. `SYS-008` 对接采用“异步申请 + 轮询查询兜底”模式,适配航信等不提供稳定回调的开票服务现状。
3. 一期不支持原始单账单直接任意部分金额开票;如需多张发票,沿用老系统拆账/分账后分别开票的口径,并保留批量开票能力。
4. 当前 backend 已有 `InvoiceController.java``InvoiceServiceImpl.java`,但实际只覆盖开票配置/模板 CRUD未实现发票申请、查询、回写、账单关联闭环。
5. 在线主模型以 `biz_invoice``biz_invoice_taxrate``biz_cust_invoice` 为主承接,旧“营业账开票表/发票明细表/开票配置快照”按历史关系快照或辅助映射处理,不机械复制旧表族。
6. 正式文档应同时对齐当前主文档、旧系统操作手册与数据字典,避免只保留“申请 + 回写”而遗漏老系统已有的查询、下载、批量开票与结果导出语义。
## Phase 1 Design Outputs
### Data Model
- `data-model.md` 已定义:
- `InvoiceApplication`
- `InvoiceRecord`
- `ChargeInvoiceRelation`
- `InvoiceQueryTask`
- `InvoiceResultWriteBack`
- 其中明确区分逻辑实体、现有在线主表承接与历史关系快照,兼容后续合并开票/拆账开票扩展。
### Contracts
- `contracts/if-rev-008-invoice-application.md`
- 固化后台发票申请/批量开票的请求字段、响应字段、校验规则与幂等口径。
- `contracts/if-rev-009-invoice-query.md`
- 固化查询兜底、结果补偿查询、客户侧查询下载的请求/响应与状态表达。
### Quickstart
- `quickstart.md` 已给出:
- 范围校验
- 老系统对齐校验
- 文档最小校验命令
- backend 实施前的现状核对点
- 后续 tasks/implement 的最小验收入口
### Agent Context
- 仓库内未找到 `.specify/scripts/**/update-agent-context.sh`;本轮不执行自动 agent context 更新脚本。
- 后续若补齐该脚本,可按仓库统一约定再执行一次上下文同步。
## Implementation Strategy for Next Phase
下一阶段 `/speckit.tasks` 应按以下顺序拆解:
1. **正式文档收敛任务**
- 更新 `12_REV_Detailed.md` 中 REV-005 场景、状态机、入口边界、老系统对齐说明
- 更新 `03_Interface_Design.md``IF-REV-008``IF-REV-009` 与客户侧查询下载口径
- 更新 `01_Database_Design.md``biz_invoice*`、账单-发票关联快照和查询补偿字段说明
2. **backend 基础扩展任务**
- 为现有 `InvoiceController.java` / `InvoiceServiceImpl.java` 增加后台申请、查询、结果写回、批量开票能力
- 增加与账单、客户开票信息、税率配置的校验联动
3. **`SYS-008` 协同与补偿任务**
- 发票申请协同调用
- 查询兜底任务与幂等回写
- 失败原因与异常核查留痕
4. **客户侧结果消费任务**
- 查询已开发票状态
- 下载/推送电子发票
- 与后台开票状态保持一致
5. **校验与闭环任务**
- 文档 `make validate-file` / `make check-links` / `make validate-mermaid`
- backend 核心流程验证
- 必要时回写 `01_Project_Progress.md``03_Task_Checklist.md`
## Complexity Tracking
本计划未发生 Constitution 违规项,无需豁免说明。

View File

@ -0,0 +1,111 @@
# Quickstart: REV-005 发票业务流计划评审与最小校验
## 1. 评审入口
本轮目标是:
- 明确 REV-005 一期发票业务流范围与老系统对齐口径
- 形成 backend 可实施的接口、数据模型与查询兜底方案
- 为后续 `/speckit.tasks``/speckit.implement` 提供直接输入
本轮验收重点检查:
- 范围与老系统操作手册是否一致
- 发票申请 / 查询兜底 / 结果回写 / 客户侧消费口径是否闭环
- planning 产物是否可直接拆解为 backend 开发任务
## 2. 评审步骤
### 步骤一:范围校验
确认一期只覆盖以下核心能力:
- 后台发票申请
- 后台单笔 / 批量开票
- `SYS-008` 异步协同与查询兜底
- 发票结果回写与账单关联
- 客户侧查看 / 下载 / 推送已开票电子发票
同时确认以下内容未被带入:
- 客户侧直接申请开票
- 原始单账单任意部分金额开票
- 复杂拆分合并开票策略一次性做深
- 与税务局直接对接的细节实现
### 步骤二:老系统对齐校验
对照以下来源:
- `营收系统_用户操作手册.md`
- `福建水投微网厅操作手册.md`
- `营收数据字典.md`
确认 planning 已吸收以下能力语义:
- 发票查询
- 发票开具
- 批量开票
- 电子发票查看/下载/推送
- 拆账/分账后分别开票
### 步骤三:单一真源校验
对照以下正式口径:
- `spec.md`
- `12_REV_Detailed.md`
- `03_Interface_Design.md`
- `01_Database_Design.md`
- `.specify/memory/constitution.md`
确认 planning 没有让 Archive 直接替代正式设计结论。
### 步骤四:查询兜底校验
确认以下口径已统一:
- 提交申请后先生成申请单号 / 外部受理号
- 通过查询接口轮询获取开票结果
- 幂等回写以申请单号和状态为主键
- 已成功状态不得被后续失败结果覆盖
### 步骤五backend 现状核对
确认当前 backend 发票模块仍主要是配置 CRUD
- `InvoiceController.java`
- `InvoiceServiceImpl.java`
并确认后续 implement 需要新增:
- 申请接口
- 查询接口
- 结果回写/补偿查询逻辑
- 账单/客户开票信息/税率校验联动
### 步骤六:正式文档修订闭环校验
后续进入正式主文档修订时,统一按以下顺序执行:
1. 先更新 `12_REV_Detailed.md` 的业务规则与状态机。
2. 再更新 `03_Interface_Design.md` 的接口合同与时序。
3. 再更新 `01_Database_Design.md` 的承接口径与关系快照说明。
4. 每修改 1 份目标文档,执行对应 `make validate-file FILE=<目标文件>`
5. 涉及跨文档引用变更时执行 `make check-links`
6. 涉及图表或时序图时执行 `make validate-mermaid`
## 3. 最小校验命令
```bash
make validate-file FILE=docs/design/02_Detailed_Design/12_REV_Detailed.md
make validate-file FILE=docs/design/03_Technical_Design/03_Interface_Design.md
make validate-file FILE=docs/design/03_Technical_Design/01_Database_Design.md
make check-links
make validate-mermaid
```
说明:
- 当前 plan 阶段以正式文档门禁为主,不强制执行 backend 构建或测试。
- backend 相关验证将在 `/speckit.implement` 阶段展开。
## 4. backend 实施前建议核对点
在进入 implement 之前,至少补充核对以下对象:
- 账单对象:`biz_charge*`
- 发票主对象:`biz_invoice`
- 客户开票信息:`biz_cust_invoice`
- 税率配置:`biz_invoice_taxrate`
- 操作留痕:`biz_operat_log*`
- 现有发票 Controller / Service / Mapper / DO / ReqVO / RespVO
## 5. 通过标准
满足以下条件即可进入下一批 tasks 拆解:
- 一期范围、老系统对齐边界、查询兜底策略已明确
- 接口合同和数据模型能直接支撑 backend 任务拆解
- 最小校验动作已明确并可执行
- 后续正式文档修订与 backend 实施边界已分清

View File

@ -0,0 +1,50 @@
# Phase 0 Research: REV-005 发票业务流实现
## Decision 1: 一期入口采用“后台开票 + 客户侧查询下载推送”
- **Decision**: 一期由后台营业收费员/财务人员发起发票申请与开具;客户侧仅支持查看、下载、推送已开具的电子发票,不直接发起开票申请。
- **Rationale**: `营收系统_用户操作手册.md` 明确存在后台【发票管理】-【发票开具】与【发票查询】入口,同时微网厅操作手册更偏向电子发票查看/推送能力;该分层最贴近老系统且风险最低。
- **Alternatives considered**:
- 后台与客户侧都直接发起开票申请:会显著扩大一期鉴权、重复申请与渠道联动范围。
- 仅后台开票、客户侧不提供结果消费:与老系统电子发票查看/下载口径不符。
## Decision 2: `SYS-008` 采用“异步申请 + 查询兜底”协同模式
- **Decision**: 提交开票申请后先返回受理号/申请单号,系统通过定时或主动查询接口获取最终开票结果,不假设发票服务一定通过回调返回。
- **Rationale**: 航信类发票平台常见能力是异步受理 + 查询结果spec clarifications 已明确该模式,且旧数据字典中也存在 `last_try_time``next_try_time``try_count` 等查询补偿字段痕迹。
- **Alternatives considered**:
- 仅依赖回调:与当前外部接口现实不符,容易导致状态悬挂。
- 纯同步开票:不适配电子发票平台与批量开票场景。
## Decision 3: 一期不支持原始单账单直接任意部分开票
- **Decision**: 若需要多张发票,沿用老系统拆账/分账后的账单分别开票;后台可保留单笔或批量选择已收费账单发起开票,但不开放对原始单账单直接输入部分金额开票。
- **Rationale**: 老系统操作手册说明“多张发票”更多依赖分账/拆账结果,数据字典虽然存在映射表和金额字段,但未把“自由部分开票”表达为一期主流程能力;该约束能降低状态和金额校验复杂度。
- **Alternatives considered**:
- 直接支持任意部分金额开票:需额外引入余额、累计开票金额、明细拆分与冲突控制。
- 完全不考虑多票场景:会偏离老系统业务口径。
## Decision 4: 在线主模型复用 `biz_invoice` / `biz_cust_invoice` / `biz_invoice_taxrate`
- **Decision**: 当前在线主模型以 `biz_invoice``biz_cust_invoice``biz_invoice_taxrate` 为主承接发票申请、客户开票资料与税率配置;旧“营业账开票表”“发票明细表”“开票配置表快照”等细粒度对象按历史只读关系快照或辅助映射处理。
- **Rationale**: `01_Database_Design.md``BACKEND_TABLE_MAPPING.md` 已明确当前在线主承接对象,且 backend 现状确实已有发票主表和配置服务;机械复制旧表族会与当前主文档冲突。
- **Alternatives considered**:
- 全量恢复旧 IV_* 表族:超出当前主文档与现状。
- 只保留 `biz_invoice` 不表达关联快照:无法满足老系统查询与审计定位需求。
## Decision 5: backend 现状仅覆盖开票配置 CRUDREV-005 需扩展业务闭环
- **Decision**: 后续 implement 阶段在现有 `InvoiceController.java``InvoiceServiceImpl.java` 基础上扩展业务接口与服务,不另起平行模块。
- **Rationale**: 当前 Controller/Service 仅包含 `/business/invoice/create|update|delete|get|page|list` 等配置 CRUD 与模板枚举查询尚未实现账单校验、申请单生成、SYS-008 协同、查询补偿与结果回写。
- **Alternatives considered**:
- 直接新增独立发票业务模块:会造成配置与业务双轨并行。
- 在当前基础上只补接口文档不改后端:无法支撑后续 implement。
## Decision 6: 正式文档需同时对齐当前主文档与老系统操作手册
- **Decision**: `12_REV_Detailed.md``03_Interface_Design.md``01_Database_Design.md` 后续修订时,除对齐主文档既有口径外,还需显式吸收老系统操作手册中的“发票查询、下载、打印、批量开票、电子发票查看/推送”等稳定能力。
- **Rationale**: 仅依据当前主文档容易把 REV-005 收窄成“申请 + 回写”,而老系统实际交付口径已经包含后台开票、客户侧查看下载与批量处理。
- **Alternatives considered**:
- 只看主文档:会遗漏老系统既有稳定业务能力。
- 只看操作手册:会偏离当前主文档和在线模型口径。
## Decision 7: plan 阶段校验以文档门禁为主backend 只做现状核对
- **Decision**: 当前 plan 阶段的最小校验仍以 `make validate-file``make check-links``make validate-mermaid` 为主backend 只需核实现有 Controller/Service 的能力边界,不引入构建或测试作为当前阶段门禁。
- **Rationale**: 本阶段交付物仍是 planning 设计产物;代码实现验证应在 `/speckit.implement` 阶段展开。
- **Alternatives considered**:
- 现在就引入 backend 构建/测试:会打断 planning 输出节奏。
- 完全忽略 backend 现状:会导致后续任务拆解失真。

View File

@ -0,0 +1,197 @@
# Feature Specification: REV-005 发票业务流实现
**Feature Branch**: `002-rev005-invoice-flow`
**Created**: 2026-03-16
**Status**: Draft
**Input**: 实现 REV-005 发票业务流核心功能:发票申请、开票校验、调用 SYS-008 发票服务、接收开票结果回写、更新发票与账单关联状态。
---
## Document Scope & Sources
- **Target documents**:
- `docs/design/02_Detailed_Design/12_REV_Detailed.md`REV-005 章节补充)
- `docs/design/03_Technical_Design/03_Interface_Design.md`IF-REV-008 发票申请接口、IF-REV-009 发票查询接口定义)
- Backend: `backend/sw-business/sw-business-server` 新增 Service/Controller
- **Primary source of truth**:
- `docs/design/02_Detailed_Design/12_REV_Detailed.md` 中 REV-005 定义
- `docs/guides/BACKEND_CURRENT_STATUS.md`
- `docs/guides/BACKEND_TABLE_MAPPING.md`
- **Reference sources**:
- Archive: `docs/design/04_Appendix/Archive/03_Design_Docs/营业收费管理系统-概要设计说明书20250912.md`
- Existing: `InvoiceController.java`, `InvoiceServiceImpl.java`
- **Scope decision**: 在已有基础数据层(开票配置、客户开票信息、税率配置)之上,补齐发票申请、开具、结果回写的完整业务流程。
---
## User Scenarios & Testing
### User Story 1 - 发票申请与校验 (Priority: P1)
营业收费员或财务人员通过后台系统提交发票申请,系统校验账单状态、开票信息完整性和开票限额,生成发票申请记录。客户侧一期不直接发起开票申请,仅支持查询、下载、推送已开具的电子发票。
**Why this priority**: 发票申请是业务流程入口,必须优先实现。
**Independent Test**: 验证发票申请接口可接收申请,校验规则生效,申请记录正确落库。
**Acceptance Scenarios**:
1. **Given** 账单已缴费且未开票,客户开票信息完整,**When** 提交发票申请,**Then** 生成发票申请记录,返回申请单号
2. **Given** 账单未缴费,**When** 提交发票申请,**Then** 拒绝申请,提示"账单未缴费不可开票"
3. **Given** 账单已开票,**When** 提交发票申请,**Then** 拒绝申请,提示"账单已开票"
4. **Given** 开票金额超过限额,**When** 提交发票申请,**Then** 拒绝申请,提示"超过开票限额"
5. **Given** 同一原始账单被要求直接拆分为多次部分开票,**When** 提交发票申请,**Then** 拒绝直接部分开票,并提示需先按老系统口径完成拆账/分账后再分别开票
---
### User Story 2 - 调用发票服务开票 (Priority: P1)
系统根据申请记录调用 SYS-008 发票服务完成开票,采用“异步申请 + 查询兜底”模式记录受理结果并主动查询最终状态。
**Why this priority**: 核心开票能力,必须实现与外部系统的对接。
**Independent Test**: 验证系统可正确组装开票参数,调用外部服务,处理返回结果。
**Acceptance Scenarios**:
1. **Given** 发票申请已校验通过,**When** 调用 SYS-008 开票接口,**Then** 正确传递账单、客户、税率信息
2. **Given** 外部服务返回开票成功,**When** 系统通过查询获取结果并回写状态,**Then** 更新发票状态为"已开票",记录发票代码号码
3. **Given** 外部服务返回开票失败,**When** 系统通过查询获取结果并回写状态,**Then** 更新发票状态为"开票失败",记录失败原因
4. **Given** 外部服务超时,**When** 发起查询,**Then** 可查询开票结果状态
---
### User Story 3 - 发票结果回写与关联 (Priority: P2)
开票成功后更新账单发票状态,建立发票与账单关联,支持电子发票推送。
**Why this priority**: 保证账单与发票数据一致性,支持后续查询和下载。
**Independent Test**: 验证开票结果正确回写账单状态,关联关系可查。
**Acceptance Scenarios**:
1. **Given** 开票成功,**When** 回写结果,**Then** 账单发票状态更新,建立 invoice-charge 关联
2. **Given** 电子发票生成,**When** 客户请求下载,**Then** 返回电子发票文件或下载链接
3. **Given** 发票已关联账单,**When** 查询账单详情,**Then** 显示关联的发票信息
---
### User Story 4 - 发票作废与红冲预留 (Priority: P3)
为已开发票的作废和红字发票能力保留正式文档与任务入口,但一期 implement 默认不纳入本轮正常开票闭环交付。
**Why this priority**: 业务完整性要求,但优先级低于正常开票流程,当前仅作为后续能力预留。
**Independent Test**: 验证正式文档已明确作废和红冲属于后续阶段能力,不影响一期正常开票流程的实现边界。
**Acceptance Scenarios**:
1. **Given** 一期仅交付正常开票闭环,**When** 审阅 REV-005 范围说明,**Then** 作废与红冲被标记为后续能力,不作为本轮 implement 必选范围
2. **Given** 后续需要扩展作废或红冲,**When** 进入下一轮 planning/implement**Then** 可在既有状态模型上继续补齐能力而不破坏当前范围边界
---
### Edge Cases
- 外部发票服务不可用时的降级处理
- 重复提交同一账单的发票申请(幂等控制)
- 开票过程中账单状态发生变化
- 拆账/分账后的多账单分别开票与原始单账单直接部分开票的边界判定
---
## Requirements
### Functional Requirements
- **FR-001**: 系统 MUST 提供后台发票申请接口接收账单ID、开票类型普票/专票)等参数,并支持单笔或批量选择已收费账单发起开票
- **FR-002**: 系统 MUST 校验账单状态(已缴费、未开票)
- **FR-003**: 系统 MUST 校验客户开票信息完整性
- **FR-004**: 系统 MUST 校验开票限额
- **FR-005**: 系统 MUST 生成发票申请记录,包含申请单号、状态、时间戳
- **FR-006**: 系统 MUST 调用 SYS-008 发票服务完成开票
- **FR-007**: 系统 MUST 支持通过定时查询获取异步开票结果(轮询 SYS-008 查询接口)
- **FR-008**: 系统 MUST 更新发票状态(申请中/已开票/开票失败)
- **FR-009**: 系统 MUST 建立发票与账单的关联关系,并保留兼容老系统拆账/分账后分别开票及后续合并开票扩展的映射能力
- **FR-010**: 系统 MUST 支持客户侧查询、下载、推送已开具的电子发票,但一期不开放客户侧直接申请开票
- **FR-011**: 系统 MUST 记录一期关键操作日志(申请、查询、开票、结果回写、客户侧查询/下载/推送);作废与红冲日志作为后续能力预留
### Key Entities
- **发票申请单** (InvoiceApplication): 申请单号、账单ID、客户ID、申请金额、开票类型、状态
- **发票记录** (InvoiceRecord): 发票ID、申请单号、发票代码、发票号码、开票日期、金额、状态
- **账单发票关联** (ChargeInvoiceRelation): 账单ID、发票ID、关联类型全额/拆账后分别开票/后续合并扩展)
- **开票查询记录** (InvoiceQueryLog): 查询ID、申请单号、查询时间、查询结果、处理状态
---
## Success Criteria
### Measurable Outcomes
- **SC-001**: 发票申请接口响应时间 < 500ms不包含外部服务调用
- **SC-002**: 发票申请校验通过率 > 95%(正常业务场景)
- **SC-003**: 开票结果回写成功率 > 99%
- **SC-004**: 电子发票下载成功率 > 99%
- **SC-005**: 操作日志完整率 100%(所有关键操作均有日志)
### Business Outcomes
- 营业收费员可通过系统完成发票申请到开票的全流程
- 客户可通过渠道查询和下载电子发票
- 财务人员可追溯发票开具全过程
---
## Dependencies & Assumptions
### Dependencies
- SYS-008 发票服务接口已定义IF-REV-008
- 基础数据层已实现biz_invoice, biz_cust_invoice, biz_invoice_taxrate
- 账单系统REV-003已实现
### Assumptions
- SYS-008 提供标准 REST 接口供调用
- 电子发票文件由 SYS-008 生成并提供下载链接
- 开票限额在配置中预定义
### Scope Exclusions
- 不实现发票的物理打印功能
- 不实现与税务局的直接对接(由 SYS-008 承接)
- 不实现复杂的发票拆分合并逻辑MVP 版本)
---
## Risks & Mitigation
| 风险 | 影响 | 缓解措施 |
|-----|-----|---------|
| SYS-008 接口未就绪 | 无法联调 | 先实现 Mock 接口,定义好契约 |
| 发票状态同步异常 | 数据不一致 | 实现补偿机制,支持对账查询 |
| 并发开票冲突 | 重复开票 | 幂等控制,唯一申请单号 |
---
## Clarifications
### Session 2026-03-16
- **Q1**: SYS-008 发票服务结果获取方式 → **A**: 采用"异步+查询兜底"模式。提交开票申请后返回受理号,系统通过定时轮询查询结果接口获取开票状态(航信发票接口不支持回调,需主动查询)。
- **Q2**: 一期是否支持一张原始账单直接分多次部分开票 → **A**: 不支持对原始单账单直接任意部分金额开票;如需多张发票,沿用老系统口径,通过拆账/分账后的账单分别开票,并保留批量开票能力。
- **Q3**: 一期开放给哪些使用入口 → **A**: 采用“后台开票 + 客户侧查询下载”模式。后台营业收费员/财务人员负责申请和开具,客户侧仅支持查看、下载、推送已开票结果,不直接发起开票申请。
---
## Next Steps
1. `/speckit.clarify` - 澄清接口细节和边界情况
2. `/speckit.plan` - 制定技术实现方案
3. `/speckit.tasks` - 拆解开发任务
4. `/speckit.implement` - 执行开发

View File

@ -0,0 +1,211 @@
# Tasks: REV-005 发票业务流实现
**Input**: Design documents from `/specs/002-rev005-invoice-flow/`
**Prerequisites**: `plan.md`, `spec.md`, `research.md`, `data-model.md`, `contracts/`
**Validation**: 正式文档修改必须执行对应 `make validate-file`;涉及跨文档引用执行 `make check-links`;涉及 Mermaid/时序图执行 `make validate-mermaid`。backend 实现阶段需补充最小编译/流程验证。
**Organization**: 任务按用户故事分组,确保每个故事都可以独立实现、独立验证、独立评审。
## Format: `[ID] [P?] [Story] Description`
- **[P]**: 可并行执行(不同文件、无未完成依赖)
- **[Story]**: 所属用户故事(`[US1]``[US2]``[US3]``[US4]`
- 每条任务都包含明确文件路径,便于直接执行
## Path Conventions
- 正式设计文档:`docs/design/02_Detailed_Design/``docs/design/03_Technical_Design/`
- 管理台账:`docs/design/00_Management/`
- planning 产物:`specs/002-rev005-invoice-flow/`
- backend 发票模块:`backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/`
---
## Phase 1: Setup共享准备
**Purpose**: 固化本轮实现边界、目标文件和 backend 触点,避免后续修改偏离单一真源。
- [x] T001 阅读 `docs/design/00_Management/01_Project_Progress.md``docs/design/00_Management/02_Delivery_Standards.md``docs/design/00_Management/03_Task_Checklist.md` 作为本轮正式文档治理前置输入
- [x] T002 阅读并锁定本轮目标文档 `docs/design/02_Detailed_Design/12_REV_Detailed.md``docs/design/03_Technical_Design/03_Interface_Design.md``docs/design/03_Technical_Design/01_Database_Design.md` 的 REV-005 相关章节
- [x] T003 确认本轮源文档边界并在 `specs/002-rev005-invoice-flow/tasks.md` 执行时以 `specs/002-rev005-invoice-flow/spec.md``plan.md``research.md``data-model.md``contracts/if-rev-008-invoice-application.md``contracts/if-rev-009-invoice-query.md` 为直接输入
- [x] T004 [P] 盘点 backend 现有发票模块触点并核对 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/invoice/InvoiceController.java``service/invoice/InvoiceService.java``service/invoice/InvoiceServiceImpl.java``dal/dataobject/invoice/InvoiceDO.java``dal/mysql/invoice/InvoiceMapper.java`
- [x] T005 [P] 盘点客户开票信息与税率依赖并核对 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/custinvoice/CustInvoiceController.java``service/custinvoice/CustInvoiceServiceImpl.java``controller/admin/invoicetaxrate/InvoiceTaxrateController.java``service/invoicetaxrate/InvoiceTaxrateServiceImpl.java`
---
## Phase 2: Foundational共享基础能力
**Purpose**: 先补齐所有用户故事共用的模型、状态、接口骨架与文档统一口径。
- [x] T006 定义共享发票状态与来源口径并更新 `docs/design/02_Detailed_Design/12_REV_Detailed.md` 中 REV-005 状态说明为 `SUBMITTED/PENDING/SUCCESS/FAIL/INVALID/RED_INK`
- [x] T007 定义共享接口编号与职责分工并更新 `docs/design/03_Technical_Design/03_Interface_Design.md``IF-REV-008``IF-REV-009` 与客户侧查询下载相关章节,同时收敛 `IF-CS-004` 与客户侧消费口径的编号/职责边界
- [x] T008 定义共享数据承接口径并更新 `docs/design/03_Technical_Design/01_Database_Design.md``biz_invoice``biz_cust_invoice``biz_invoice_taxrate`、账单-发票关系快照说明,并标明已有字段、待补字段与仅快照字段
- [x] T009 在 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/invoice/InvoiceService.java` 声明 REV-005 共用能力入口(申请、查询、结果回写、客户侧下载/推送、作废/红冲预留)
- [x] T010 在 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/invoice/InvoiceController.java` 预留 REV-005 共用接口路由入口,避免继续仅停留在配置 CRUD
- [x] T011 [P] 新增后台申请与查询基础请求/响应对象到 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/invoice/vo/InvoiceApplyReqVO.java``InvoiceApplyRespVO.java``InvoiceQueryReqVO.java``InvoiceQueryRespVO.java`
- [x] T012 [P] 新增结果回写与客户侧消费基础请求/响应对象到 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/invoice/vo/InvoiceWriteBackReqVO.java``InvoiceCustomerQueryReqVO.java``InvoicePushReqVO.java`
---
## Phase 3: User Story 1 - 发票申请与校验 (Priority: P1) 🎯 MVP
**Goal**: 实现后台单笔/批量发票申请入口,完成账单状态、客户开票信息、税率和限额校验,并生成发票申请记录。
**Independent Test**: 后台提交已收费未开票账单时能生成申请单号;未缴费、已开票、直接部分开票等场景被正确拦截;正式文档与接口合同保持一致。
### Implementation for User Story 1
- [x] T013 [US1] 更新 `docs/design/02_Detailed_Design/12_REV_Detailed.md` 中 REV-005 的后台申请入口、校验规则、批量开票和“禁止原始单账单直接任意部分开票”描述
- [x] T014 [US1] 更新 `docs/design/03_Technical_Design/03_Interface_Design.md``IF-REV-008` 的后台申请/单笔批量开票请求、响应、幂等和失败提示口径
- [x] T015 [US1] 更新 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/invoice/InvoiceController.java` 增加后台发票申请接口
- [x] T016 [US1] 更新 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/invoice/InvoiceService.java``service/invoice/InvoiceServiceImpl.java` 实现发票申请、校验、申请单生成逻辑
- [x] T017 [P] [US1] 扩展 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/invoice/vo/InvoiceApplyReqVO.java``InvoiceApplyRespVO.java` 承接 `chargeIds``custId``invoiceType``invoiceTitle``taxNo``email``mobile``sourceChannel``remark`
- [x] T018 [P] [US1] 更新 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/dal/dataobject/invoice/InvoiceDO.java``dal/mysql/invoice/InvoiceMapper.java` 承接申请单号、受理号、申请状态、限额校验所需字段映射,并与 `docs/design/03_Technical_Design/01_Database_Design.md` 标注保持一致
- [x] T019 [US1] 在 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/invoice/InvoiceServiceImpl.java` 接入 `biz_cust_invoice``biz_invoice_taxrate` 与账单对象校验,确保仅已收费未开票账单可申请
- [x] T020 [US1] 在 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/invoice/InvoiceServiceImpl.java` 实现 `applicationNo``custId + chargeIds` 幂等控制
- [x] T021 [US1] 运行 `make validate-file FILE=docs/design/02_Detailed_Design/12_REV_Detailed.md` 验证 REV-005 详细设计章节
- [x] T022 [US1] 运行 `make validate-file FILE=docs/design/03_Technical_Design/03_Interface_Design.md` 验证 `IF-REV-008` 接口文档
- [x] T023 [US1] 在 `backend/sw-business/sw-business-server/pom.xml` 所在模块执行一次最小 Maven 编译验证(例如以 invoice 相关变更为范围的编译/测试命令),确认 `controller/admin/invoice/InvoiceController.java``service/invoice/InvoiceServiceImpl.java` 的申请链路可编译
- [x] T024 [US1] 更新 `docs/design/00_Management/01_Project_Progress.md` 记录 REV-005 后台申请与校验闭环进展
- [x] T025 [US1] 更新 `docs/design/00_Management/03_Task_Checklist.md` 同步 REV-005 后台申请与校验任务状态
**Checkpoint**: 后台申请与校验链路可独立评审,`IF-REV-008` 与 REV-005 详细设计保持一致。
---
## Phase 4: User Story 2 - 调用 SYS-008 开票并查询兜底 (Priority: P1)
**Goal**: 实现提交开票申请后的异步协同、受理号记录、定时/主动查询兜底,并保证成功状态不被后续失败结果覆盖。
**Independent Test**: 发票申请成功后生成受理号与查询任务;查询接口可按申请单号/受理号返回结果;查询异常不会覆盖既有成功状态。
### Implementation for User Story 2
- [x] T026 [US2] 更新 `docs/design/02_Detailed_Design/12_REV_Detailed.md` 中 REV-005 的 `SYS-008` 异步协同、查询补偿、终态保护和异常核查流程
- [x] T027 [US2] 更新 `docs/design/03_Technical_Design/03_Interface_Design.md``IF-REV-009` 的后台查询、系统补偿查询和状态流转时序
- [x] T028 [US2] 更新 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/invoice/InvoiceController.java` 增加后台查询接口与补偿查询触发入口
- [x] T029 [US2] 更新 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/invoice/InvoiceServiceImpl.java` 实现提交 `SYS-008`、记录 `sysRequestNo`、创建查询任务、按申请单号/受理号查询结果
- [x] T030 [P] [US2] 扩展 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/invoice/vo/InvoiceQueryReqVO.java``InvoiceQueryRespVO.java` 支持 `applicationNo``sysRequestNo``querySource`
- [x] T031 [P] [US2] 扩展 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/dal/dataobject/invoice/InvoiceDO.java``dal/mysql/invoice/InvoiceMapper.java` 承接 `lastTryTime``nextTryTime``tryCount``latestResult``latestError`,并与 `docs/design/03_Technical_Design/01_Database_Design.md` 标注保持一致
- [x] T032 [US2] 在 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/invoice/InvoiceServiceImpl.java` 实现“成功状态不被失败结果覆盖”的幂等保护
- [x] T033 [US2] 在 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/invoice/InvoiceServiceImpl.java` 记录查询补偿与异常留痕到操作日志对象
- [x] T034 [US2] 运行 `make validate-file FILE=docs/design/02_Detailed_Design/12_REV_Detailed.md` 验证 REV-005 异步与补偿流程描述
- [x] T035 [US2] 运行 `make validate-file FILE=docs/design/03_Technical_Design/03_Interface_Design.md` 验证 `IF-REV-009` 查询接口文档
- [x] T036 [US2] 在 `backend/sw-business/sw-business-server/pom.xml` 所在模块执行一次最小 Maven 编译验证,并以受理号/申请单号查询场景确认查询链路可返回 `PENDING/SUCCESS/FAIL` 且保护终态
- [x] T037 [US2] 更新 `docs/design/00_Management/01_Project_Progress.md` 记录 REV-005 查询兜底与异步协同进展
- [x] T038 [US2] 更新 `docs/design/00_Management/03_Task_Checklist.md` 同步 REV-005 查询兜底与异步协同任务状态
**Checkpoint**: `SYS-008` 异步协同与查询兜底链路可独立演示,`IF-REV-009` 口径已稳定。
---
## Phase 5: User Story 3 - 结果回写、账单关联与客户侧消费 (Priority: P2)
**Goal**: 实现开票结果回写、账单-发票关联状态更新,以及客户侧查看/下载/推送已开具电子发票。
**Independent Test**: 开票成功后账单与发票建立关联;客户侧仅能查看属于当前客户且已开具的电子发票;下载/推送前必须校验 `SUCCESS + fileUrl`
### Implementation for User Story 3
- [x] T039 [US3] 更新 `docs/design/02_Detailed_Design/12_REV_Detailed.md` 中 REV-005 的结果回写、账单关联、客户侧查看/下载/推送规则
- [x] T040 [US3] 更新 `docs/design/03_Technical_Design/01_Database_Design.md``biz_invoice`、账单-发票关系快照、客户查询身份与操作留痕承接口径,并标明已有字段、待补字段与仅快照字段
- [x] T041 [US3] 更新 `docs/design/03_Technical_Design/03_Interface_Design.md` 中客户侧查看、下载、推送电子发票的请求/响应约束
- [x] T042 [US3] 更新 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/invoice/InvoiceController.java` 增加结果回写、客户侧查询、下载、推送接口
- [x] T043 [US3] 更新 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/invoice/InvoiceServiceImpl.java` 实现结果回写、账单关联状态更新、客户侧权限校验与电子票文件处理
- [x] T044 [P] [US3] 扩展 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/invoice/vo/InvoiceWriteBackReqVO.java``InvoiceCustomerQueryReqVO.java``InvoicePushReqVO.java` 承接回写与客户侧消费字段
- [x] T045 [P] [US3] 扩展 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/dal/dataobject/invoice/InvoiceDO.java``dal/mysql/invoice/InvoiceMapper.java` 承接 `invoiceCode``invoiceNumber``fileUrl``pushStatus`、关联状态字段,并与 `docs/design/03_Technical_Design/01_Database_Design.md` 标注保持一致
- [x] T046 [US3] 在 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/invoice/InvoiceServiceImpl.java` 实现客户侧仅可访问本人已开具电子发票的鉴权限制
- [x] T047 [US3] 在 `backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/invoice/InvoiceServiceImpl.java` 实现下载/推送前校验 `SUCCESS` 状态与 `fileUrl` 存在性
- [x] T048 [US3] 运行 `make validate-file FILE=docs/design/03_Technical_Design/01_Database_Design.md` 验证数据承接口径
- [x] T049 [US3] 运行 `make validate-file FILE=docs/design/03_Technical_Design/03_Interface_Design.md` 验证客户侧查询下载推送接口文档
- [x] T050 [US3] 在 `backend/sw-business/sw-business-server/pom.xml` 所在模块执行一次最小 Maven 编译验证,并以客户侧查询/下载/推送场景确认结果回写、账单关联与电子票消费链路可调用
- [x] T051 [US3] 更新 `docs/design/00_Management/01_Project_Progress.md` 记录 REV-005 结果回写与客户侧消费进展
- [x] T052 [US3] 更新 `docs/design/00_Management/03_Task_Checklist.md` 同步 REV-005 结果回写与客户侧消费任务状态
**Checkpoint**: 发票结果回写、账单关联和客户侧电子票消费链路可以独立评审并验证。
---
## Phase 6: User Story 4 - 发票作废与红冲预留 (Priority: P3)
**Goal**: 将作废与红冲明确标注为后续阶段能力,只在正式文档和管理台账中保留边界与后续入口,不纳入一期 implement 必选交付。
**Independent Test**: 审阅 spec、plan、tasks 与正式文档后,可确认作废/红冲属于后续能力预留,不要求本轮 backend 代码实现。
### Implementation for User Story 4
- [ ] T053 [US4] 更新 `docs/design/02_Detailed_Design/12_REV_Detailed.md` 标注作废与红冲为后续阶段能力,并说明其与正常开票闭环的边界
- [ ] T054 [US4] 更新 `docs/design/03_Technical_Design/03_Interface_Design.md` 标注作废/红冲接口为预留能力或后续规划,不纳入一期 implement 必选范围
- [ ] T055 [US4] 在 `docs/design/00_Management/01_Project_Progress.md` 记录作废与红冲转为后续阶段能力预留的决策
- [ ] T056 [US4] 在 `docs/design/00_Management/03_Task_Checklist.md` 同步作废与红冲改为后续阶段任务预留的状态说明
**Checkpoint**: 作废与红冲的范围边界已稳定,不再与一期正常开票闭环交付混淆。
---
## Final Phase: Cross-Cutting Closure
**Purpose**: 完成仓库级一致性复核、统一校验、成功标准验证和交付总结。
- [ ] T057 [P] 运行 `make check-links` 复核 `docs/design/02_Detailed_Design/12_REV_Detailed.md``docs/design/03_Technical_Design/03_Interface_Design.md``docs/design/03_Technical_Design/01_Database_Design.md` 的交叉引用
- [ ] T058 [P] 运行 `make validate-mermaid` 复核 REV-005 相关 Mermaid/时序图在 `docs/design/02_Detailed_Design/12_REV_Detailed.md``docs/design/03_Technical_Design/03_Interface_Design.md` 中的可用性
- [ ] T059 根据 `specs/002-rev005-invoice-flow/spec.md``SC-001``backend/sw-business/sw-business-server/pom.xml` 所在模块补充并执行发票申请接口响应时延验证,并将命令、样本说明与结果记录到 `specs/002-rev005-invoice-flow/verification.md`
- [ ] T060 根据 `specs/002-rev005-invoice-flow/spec.md``SC-002``SC-003``SC-004``SC-005` 补充统计脚本或验证记录,明确数据来源、样本范围、统计口径,并将校验通过率、回写成功率、下载成功率、日志完整率结果写入 `specs/002-rev005-invoice-flow/verification.md`
- [ ] T061 汇总最终交付说明并在 `specs/002-rev005-invoice-flow/tasks.md` 执行完成后输出修改文件、验证结果、剩余风险与下一步建议
---
## Dependencies & Execution Order
### Phase Dependencies
- **Setup**: 无依赖,但必须先完成,作为正式文档与 backend 触点的统一基线
- **Foundational**: 依赖 Setup必须在用户故事前完成
- **US1**: 依赖 Foundational是 MVP 的最小闭环入口
- **US2**: 依赖 US1需要复用申请单和受理号
- **US3**: 依赖 US2需要复用终态结果与查询补偿数据
- **US4**: 依赖 US3仅做范围预留与文档/台账标注
- **Final Phase**: 依赖所有已选择的用户故事完成
### Within Each User Story
- 先更新正式文档,再更新 backend 接口与服务
- 先补请求/响应对象和数据映射,再实现服务逻辑
- 先完成内容编辑,再运行验证命令
- 先完成验证,再更新管理台账
### Parallel Opportunities
- `T004``T005` 可并行盘点 backend 依赖
- `T011``T012` 可并行新增 VO 骨架
- US1 中 `T017``T018` 可并行
- US2 中 `T030``T031` 可并行
- US3 中 `T044``T045` 可并行
- `T057``T058` 可并行执行
---
## Implementation Strategy
### MVP First
1. 完成 Phase 1-2统一正式文档与 backend 触点基线
2. 优先交付 **US1 发票申请与校验**,形成最小可用后台入口
3. 再交付 **US2 异步协同与查询兜底**,完成 `SYS-008` 结果获取闭环
4. 再交付 **US3 结果回写、账单关联与客户侧消费**,形成一期完整业务闭环
5. **US4 作废与红冲预留** 仅保留文档与台账入口,不纳入本轮 backend 实现
### Independent Test Criteria by Story
- **US1**: 后台发票申请成功生成申请单号,非法账单/直接部分开票被拦截
- **US2**: 查询接口可按申请单号或受理号返回结果,成功终态不被失败覆盖
- **US3**: 结果回写后账单与发票关联可查,客户侧只能查看并下载/推送本人已开票电子票
- **US4**: 作废与红冲被稳定标注为后续阶段能力,不与一期实现范围冲突
### Notes
- 本任务集同时覆盖正式文档收敛与 backend 实施准备,执行时应始终以 `specs/002-rev005-invoice-flow/spec.md` 为单一需求总源
- Archive 文档仅用于校验与追溯,不作为正式交付主稿直接替代
- 仓库内未找到 `.specify/scripts/bash/check-prerequisites.sh`,本轮按现有 planning artifacts 手工推进 Speckit 任务流
- Success Criteria 已显式映射到 Final Phase 验证任务,若当前环境无法完成统计验证,应至少产出明确的验证记录与剩余风险说明