From 82d307bda6525bfbb94746b9fd8f773015f3d0d5 Mon Sep 17 00:00:00 2001 From: tangweijie <877588133@qq.com> Date: Tue, 17 Mar 2026 00:45:21 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=A1=A5=E9=BD=90=20REV-005=20?= =?UTF-8?q?=E5=8F=91=E7=A5=A8=E9=97=AD=E7=8E=AF=E8=AE=BE=E8=AE=A1=E4=B8=8E?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=8F=B0=E8=B4=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../00_Management/01_Project_Progress.md | 2 + .../design/00_Management/03_Task_Checklist.md | 15 ++ .../02_Detailed_Design/12_REV_Detailed.md | 71 +++++- .../03_Technical_Design/01_Database_Design.md | 11 +- .../03_Interface_Design.md | 146 ++++++++---- .../if-rev-008-invoice-application.md | 68 ++++++ .../contracts/if-rev-009-invoice-query.md | 65 ++++++ specs/002-rev005-invoice-flow/data-model.md | 170 ++++++++++++++ specs/002-rev005-invoice-flow/plan.md | 185 +++++++++++++++ specs/002-rev005-invoice-flow/quickstart.md | 111 +++++++++ specs/002-rev005-invoice-flow/research.md | 50 +++++ specs/002-rev005-invoice-flow/spec.md | 197 ++++++++++++++++ specs/002-rev005-invoice-flow/tasks.md | 211 ++++++++++++++++++ 13 files changed, 1240 insertions(+), 62 deletions(-) create mode 100644 specs/002-rev005-invoice-flow/contracts/if-rev-008-invoice-application.md create mode 100644 specs/002-rev005-invoice-flow/contracts/if-rev-009-invoice-query.md create mode 100644 specs/002-rev005-invoice-flow/data-model.md create mode 100644 specs/002-rev005-invoice-flow/plan.md create mode 100644 specs/002-rev005-invoice-flow/quickstart.md create mode 100644 specs/002-rev005-invoice-flow/research.md create mode 100644 specs/002-rev005-invoice-flow/spec.md create mode 100644 specs/002-rev005-invoice-flow/tasks.md diff --git a/docs/design/00_Management/01_Project_Progress.md b/docs/design/00_Management/01_Project_Progress.md index ddb4321..1919ad2 100644 --- a/docs/design/00_Management/01_Project_Progress.md +++ b/docs/design/00_Management/01_Project_Progress.md @@ -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 协作的起步成本与操作偏差。 | diff --git a/docs/design/00_Management/03_Task_Checklist.md b/docs/design/00_Management/03_Task_Checklist.md index dab7502..5ad7acf 100644 --- a/docs/design/00_Management/03_Task_Checklist.md +++ b/docs/design/00_Management/03_Task_Checklist.md @@ -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` 最小编译验证 ✅ ### 📋 工作范围基线对齐 diff --git a/docs/design/02_Detailed_Design/12_REV_Detailed.md b/docs/design/02_Detailed_Design/12_REV_Detailed.md index 49eb820..88fd9f5 100644 --- a/docs/design/02_Detailed_Design/12_REV_Detailed.md +++ b/docs/design/02_Detailed_Design/12_REV_Detailed.md @@ -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`:发票结果回写协同接口(由发票服务侧回传)。 ### 落地边界 diff --git a/docs/design/03_Technical_Design/01_Database_Design.md b/docs/design/03_Technical_Design/01_Database_Design.md index df33731..b62ebe5 100644 --- a/docs/design/03_Technical_Design/01_Database_Design.md +++ b/docs/design/03_Technical_Design/01_Database_Design.md @@ -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 (操作留痕表) | 表名 | 关键字段 | 说明 | | :--- | :--- | :--- | diff --git a/docs/design/03_Technical_Design/03_Interface_Design.md b/docs/design/03_Technical_Design/03_Interface_Design.md index 78f3784..410c532 100644 --- a/docs/design/03_Technical_Design/03_Interface_Design.md +++ b/docs/design/03_Technical_Design/03_Interface_Design.md @@ -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 | 是 | 开票关联账单 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 | 是 | 发送渠道列表,如 `SMS`、`WECHAT`、`APP` | 消息参数 | -| customerScope | Array | 否 | 指定客户范围 | `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 | 是 | 开票关联账单 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: 返回申请结果或供后续查询 ``` diff --git a/specs/002-rev005-invoice-flow/contracts/if-rev-008-invoice-application.md b/specs/002-rev005-invoice-flow/contracts/if-rev-008-invoice-application.md new file mode 100644 index 0000000..959e366 --- /dev/null +++ b/specs/002-rev005-invoice-flow/contracts/if-rev-008-invoice-application.md @@ -0,0 +1,68 @@ +# Contract: IF-REV-008 发票申请接口 + +## 1. 合同定位 + +本合同用于固化 REV-005 一期后台发票申请 / 单笔与批量开票接口口径,服务于后续正式接口文档修订、任务拆解与 backend 实施。 + +## 2. 适用范围 + +适用场景: +- 后台营业收费员 / 财务人员发起单笔开票 +- 后台按已收费账单集合批量发起开票 +- 生成发票申请记录并提交 `SYS-008` + +不适用范围: +- 客户侧直接申请开票 +- 原始单账单直接任意部分金额开票 +- 复杂拆分/合并开票策略配置 + +## 3. 请求合同 + +| 字段 | 类型 | 必填 | 说明 | 约束 | +|------|------|------|------|------| +| applicationNo | String | 否 | 发票申请单号 | 服务端生成,作为幂等主键之一 | +| chargeIds | Array | 是 | 关联账单 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` 查询兜底模式一致 diff --git a/specs/002-rev005-invoice-flow/contracts/if-rev-009-invoice-query.md b/specs/002-rev005-invoice-flow/contracts/if-rev-009-invoice-query.md new file mode 100644 index 0000000..5799041 --- /dev/null +++ b/specs/002-rev005-invoice-flow/contracts/if-rev-009-invoice-query.md @@ -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. 验收关注点 + +- 是否支持后台按申请单号 / 受理号查询结果 +- 是否支持系统任务轮询补偿 +- 是否支持客户侧查看、下载、推送已开票电子发票 +- 是否避免客户侧越权查询和重复推送 diff --git a/specs/002-rev005-invoice-flow/data-model.md b/specs/002-rev005-invoice-flow/data-model.md new file mode 100644 index 0000000..1deb4f3 --- /dev/null +++ b/specs/002-rev005-invoice-flow/data-model.md @@ -0,0 +1,170 @@ +# Data Model: REV-005 发票业务流实现 + +## 建模原则 + +- 以“逻辑实体 + 现有在线主表承接 + 历史关系快照”三层表达,避免把旧系统全部 IV_* 细表误写为当前已落地在线表。 +- 后台开票、客户侧查询下载、`SYS-008` 查询兜底、结果回写统一围绕单一发票申请主线建模。 +- 一期不支持原始单账单直接任意部分开票,但关系模型需兼容拆账/分账后的多账单、多发票映射扩展。 + +## 实体一:InvoiceApplication(发票申请单) + +### 作用 +统一承接后台单笔/批量已收费账单的发票申请输入,是 `IF-REV-008` 的主业务对象。 + +### 核心字段 + +| 字段 | 类型 | 说明 | +|------|------|------| +| applicationNo | String | 发票申请单号 / 协同请求号 | +| chargeIds | Array | 关联账单 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 时优先保证正常开票闭环。 +- 旧发票明细、营业账开票关系、配置快照对象在当前阶段仅作为历史参照和追溯来源,不表述为已确认新增在线独立表。 diff --git a/specs/002-rev005-invoice-flow/plan.md b/specs/002-rev005-invoice-flow/plan.md new file mode 100644 index 0000000..49c2429 --- /dev/null +++ b/specs/002-rev005-invoice-flow/plan.md @@ -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 违规项,无需豁免说明。 diff --git a/specs/002-rev005-invoice-flow/quickstart.md b/specs/002-rev005-invoice-flow/quickstart.md new file mode 100644 index 0000000..4acd849 --- /dev/null +++ b/specs/002-rev005-invoice-flow/quickstart.md @@ -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 实施边界已分清 diff --git a/specs/002-rev005-invoice-flow/research.md b/specs/002-rev005-invoice-flow/research.md new file mode 100644 index 0000000..74f6668 --- /dev/null +++ b/specs/002-rev005-invoice-flow/research.md @@ -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 现状仅覆盖开票配置 CRUD,REV-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 现状:会导致后续任务拆解失真。 diff --git a/specs/002-rev005-invoice-flow/spec.md b/specs/002-rev005-invoice-flow/spec.md new file mode 100644 index 0000000..8206846 --- /dev/null +++ b/specs/002-rev005-invoice-flow/spec.md @@ -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` - 执行开发 diff --git a/specs/002-rev005-invoice-flow/tasks.md b/specs/002-rev005-invoice-flow/tasks.md new file mode 100644 index 0000000..8f16e79 --- /dev/null +++ b/specs/002-rev005-invoice-flow/tasks.md @@ -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 验证任务,若当前环境无法完成统计验证,应至少产出明确的验证记录与剩余风险说明