tangweijie 82d307bda6 docs: 补齐 REV-005 发票闭环设计与任务台账
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 00:45:21 +08:00

198 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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` - 执行开发