203 lines
11 KiB
Markdown
203 lines
11 KiB
Markdown
# Feature Specification: REV-005 发票业务流实现
|
||
|
||
**Feature Branch**: `002-rev005-invoice-flow`
|
||
**Created**: 2026-03-16
|
||
**Status**: Verification Pending
|
||
**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)
|
||
|
||
对已成功开具的发票提供后台作废与红冲入口,由 `SYS-008` 承接税控侧处理,`SYS-002` 负责发起申请、校验状态、查询补偿、结果回写与账单关联状态同步;客户侧仍仅消费有效电子发票结果,不直接发起作废或红冲。
|
||
|
||
**Why this priority**: 作废与红冲属于已开票后的后处理能力,依赖正常开票闭环,但必须在本轮二期中形成正式设计与 backend 实现入口。
|
||
|
||
**Independent Test**: 验证后台可对满足条件的成功发票发起作废或红冲;`SYS-008` 返回结果后,发票状态正确更新为 `INVALID` 或 `RED_INK`,并保留原票关联、失败原因与操作日志。
|
||
|
||
**Acceptance Scenarios**:
|
||
|
||
1. **Given** 发票状态为 `SUCCESS` 且未作废、未红冲,**When** 后台发起作废申请,**Then** 系统校验通过并调用 `SYS-008`,成功后将发票状态更新为 `INVALID`
|
||
2. **Given** 发票状态为 `SUCCESS` 且业务要求通过红字发票冲销,**When** 后台发起红冲申请,**Then** 系统校验通过并调用 `SYS-008`,成功后将发票状态更新为 `RED_INK`
|
||
3. **Given** 发票已处于 `INVALID` 或 `RED_INK`,**When** 再次发起作废或红冲,**Then** 系统拒绝重复处理并返回明确原因
|
||
4. **Given** `SYS-008` 未立即返回终态,**When** 系统执行主动查询或补偿查询,**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 记录关键操作日志(申请、查询、开票、结果回写、客户侧查询/下载/推送、作废、红冲),并保留触发来源、状态前后值与失败原因
|
||
- **FR-012**: 系统 MUST 提供后台发票作废入口,仅允许对已开票成功且未作废、未红冲的发票发起作废
|
||
- **FR-013**: 系统 MUST 提供后台发票红冲入口,仅允许对已开票成功且未红冲的发票发起红字冲销,并保留原票关联信息
|
||
- **FR-014**: 系统 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. 在可用测试或联调环境中补充 SC-001 的响应时延采样,记录样本量、平均值、P95 与“排除外部调用”的统计口径。
|
||
2. 为 SC-002 ~ SC-004 准备样本集与统计表,将申请通过率、回写成功率、查询/下载/推送成功率沉淀到 `specs/002-rev005-invoice-flow/verification.md`。
|
||
3. 抽取 SC-005 运行态日志样本,核对操作人、客户、状态与日志内容是否与实现态矩阵一致。
|
||
4. 继续跟踪 `biz_invoice` 物理 DDL / migration 来源,并在提测前明确联调、落库与批量后处理风险。
|