提案
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 56s

This commit is contained in:
Break
2026-06-04 09:39:20 +08:00
parent 5089a71764
commit 27fba9160c
14 changed files with 1341 additions and 0 deletions

View File

@@ -0,0 +1,135 @@
## MODIFIED Requirements
### Requirement: ExchangeOrder 换货单模型定义
系统 SHALL 定义 `ExchangeOrder` 模型并映射到 `tb_exchange_order`,用于承载客户端换货完整生命周期。
模型字段 MUST 至少包含:
- 基础:`id``created_at``updated_at``deleted_at``creator``updater`
- 单号:`exchange_no`
- 流程:`flow_type`
- 旧资产:`old_asset_type``old_asset_id``old_asset_identifier`
- 新资产:`new_asset_type``new_asset_id``new_asset_identifier`
- 收货:`recipient_name``recipient_phone``recipient_address`
- 物流:`express_company``express_no`
- 迁移:`migrate_data``migration_completed``migration_balance`
- 时间:`shipped_at``completed_at`
- 业务:`exchange_reason``remark``status`
- 多租户:`shop_id`
`flow_type` MUST 使用字符串枚举,至少支持:
- `shipping`:需要客户填写收货地址、后台发货、后台确认完成
- `direct`:创建时直接完成,不经过客户填写地址和后台发货
`flow_type` MUST 在数据库层设置默认值 `shipping`,用于兼容历史记录与旧创建请求。
`ExchangeOrder` SHALL 嵌入 `BaseModel` 并实现 `TableName() string`,返回 `tb_exchange_order`
#### Scenario: 创建 shipping 换货单模型实例
- **WHEN** 系统创建新的 `shipping` 换货单记录
- **THEN** 记录 MUST 包含旧资产快照、流程类型 `flow_type=shipping`、收货信息占位、迁移状态字段和多租户字段
#### Scenario: 创建 direct 换货单模型实例
- **WHEN** 系统创建新的 `direct` 换货单记录
- **THEN** 记录 MUST 包含旧资产快照、新资产快照、流程类型 `flow_type=direct`
- **AND** 记录在创建成功时即可具备 `completed_at`
---
### Requirement: 换货状态常量定义
系统 MUST 使用 int 常量定义换货状态:
- `1` 待填写信息
- `2` 待发货
- `3` 已发货待确认
- `4` 已完成
- `5` 已取消
系统 MUST 使用独立的字符串常量定义换货流程类型:
- `shipping`
- `direct`
#### Scenario: 状态与流程常量一致性
- **WHEN** Service、Store、Handler 读取或更新换货状态与流程类型
- **THEN** 各层 MUST 使用统一常量值,禁止硬编码散落魔法数字和字符串
---
### Requirement: 换货状态机流转规则
系统 SHALL 执行以下状态机:
- `shipping`
- 创建换货单后:`status=1`
- 客户填写收货信息后:`1 -> 2`
- 后台发货后:`2 -> 3`
- 后台确认完成后:`3 -> 4`
- 取消:仅允许 `1/2 -> 5`
- `direct`
- 创建换货单并完成后:`status=4`
- 不经过 `1/2/3`
- 不走客户端填写收货地址
- 不走后台发货
- 不进入取消状态机
- 任一步失败时不保留半成品 `direct` 单据
系统 MUST 禁止非法流转(如 `3 -> 5``4 -> 2``direct 进入 2`)。
#### Scenario: shipping 已发货不可取消
- **WHEN** `shipping` 换货单状态为 `3` 且请求取消
- **THEN** 系统 MUST 拒绝并返回状态流转非法错误
#### Scenario: direct 创建即完成
- **WHEN** 后台以 `flow_type=direct` 创建换货单且所有校验通过
- **THEN** 系统 MUST 直接创建 `status=4` 的换货单
- **AND** MUST 写入 `completed_at`
#### Scenario: direct 失败不落半成品状态
- **WHEN** 后台以 `flow_type=direct` 创建换货单但完成事务失败
- **THEN** 系统 MUST 回滚创建
- **AND** MUST NOT 产生 `flow_type=direct AND status IN (1,2,3)` 的换货单
#### Scenario: direct 不允许进入发货阶段
- **WHEN** `direct` 换货单请求执行发货或填写收货地址
- **THEN** 系统 MUST 拒绝并返回流程类型不支持该操作的错误
---
### Requirement: 换货单号生成规则
系统 MUST 为每个换货单生成全局可追踪单号,格式为:`EXC + 时间戳片段 + 随机数片段`
生成规则 SHALL 满足:
- 前缀固定为 `EXC`
- 包含日期/时间信息用于人工排查
- 包含随机片段降低并发冲突概率
#### Scenario: 生成换货单号
- **WHEN** 后台发起换货并创建新单
- **THEN** 系统 MUST 生成形如 `EXC20260319XXXXXX` 的单号并写入 `exchange_no`
---
### Requirement: 换货关键业务时间字段语义
系统 SHALL 使用独立的业务时间字段表达发货完成和换货完成,而不是复用 `updated_at`
字段语义 MUST 满足:
- `shipped_at`:仅在 `shipping` 流程发货成功后写入
- `completed_at`:仅在换货完成成功后写入,`shipping``direct` 共用
- `direct` 流程 MUST 保持 `shipped_at` 为空
- 历史已完成单据若 `completed_at` 为空,查询与追溯层 MUST 回退使用 `updated_at`
#### Scenario: shipping 写入发货时间
- **WHEN** `shipping` 换货单执行后台发货成功
- **THEN** 系统 MUST 记录 `shipped_at=当前时间`
#### Scenario: direct 不写发货时间
- **WHEN** `direct` 换货单创建并完成成功
- **THEN** 系统 MUST 保持 `shipped_at` 为空
- **AND** MUST 写入 `completed_at=当前时间`
#### Scenario: 历史单据完成时间兼容
- **WHEN** 查询历史已完成换货单且 `completed_at` 为空
- **THEN** 系统 MUST 在追溯展示中回退使用 `updated_at` 作为兼容完成时间