新增完整换货生命周期管理:后台发起 → 客户端填收货信息 → 后台发货 → 确认完成(含可选全量迁移) → 旧资产转新再销售 后台接口(7个): - POST /api/admin/exchanges(发起换货) - GET /api/admin/exchanges(换货列表) - GET /api/admin/exchanges/:id(换货详情) - POST /api/admin/exchanges/:id/ship(发货) - POST /api/admin/exchanges/:id/complete(确认完成+可选迁移) - POST /api/admin/exchanges/:id/cancel(取消) - POST /api/admin/exchanges/:id/renew(旧资产转新) 客户端接口(2个): - GET /api/c/v1/exchange/pending(查询换货通知) - POST /api/c/v1/exchange/:id/shipping-info(填写收货信息) 核心能力: - ExchangeOrder 模型与状态机(1待填写→2待发货→3已发货→4已完成,1/2可取消→5) - 全量迁移事务(11张表:钱包、套餐、标签、客户绑定等) - 旧资产转新(generation+1、状态重置、新钱包、历史隔离) - 旧 CardReplacementRecord 表改名为 legacy,is_replaced 过滤改为查新表 - 数据库迁移:000085 新建 tb_exchange_order,000086 旧表改名
2.3 KiB
2.3 KiB
ADDED Requirements
Requirement: ExchangeOrder 换货单模型定义
系统 SHALL 定义 ExchangeOrder 模型并映射到 tb_exchange_order,用于承载客户端换货完整生命周期。
模型字段 MUST 至少包含:
- 基础:
id、created_at、updated_at、deleted_at、creator、updater - 单号:
exchange_no - 旧资产:
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 - 业务:
exchange_reason、remark、status - 多租户:
shop_id
ExchangeOrder SHALL 嵌入 BaseModel 并实现 TableName() string,返回 tb_exchange_order。
Scenario: 创建换货单模型实例
- WHEN 系统创建新的换货单记录
- THEN 记录 MUST 同时包含旧资产快照、收货信息占位、迁移状态字段和多租户字段
Requirement: 换货状态常量定义
系统 MUST 使用 int 常量定义换货状态:
1待填写信息2待发货3已发货待确认4已完成5已取消
Scenario: 状态常量一致性
- WHEN Service、Store、Handler 读取或更新换货状态
- THEN 各层 MUST 使用统一常量值,禁止硬编码散落魔法数字
Requirement: 换货状态机流转规则
系统 SHALL 执行以下状态机:
- 创建换货单后:
1 - 客户填写收货信息后:
1 -> 2 - 后台发货后:
2 -> 3 - 后台确认完成后:
3 -> 4 - 取消:仅允许
1/2 -> 5
系统 MUST 禁止非法流转(如 3 -> 5、4 -> 2)。
Scenario: 已发货不可取消
- WHEN 换货单状态为
3且请求取消 - THEN 系统 MUST 拒绝并返回状态流转非法错误
Requirement: 换货单号生成规则
系统 MUST 为每个换货单生成全局可追踪单号,格式为:EXC + 时间戳片段 + 随机数片段。
生成规则 SHALL 满足:
- 前缀固定为
EXC - 包含日期/时间信息用于人工排查
- 包含随机片段降低并发冲突概率
Scenario: 生成换货单号
- WHEN 后台发起换货并创建新单
- THEN 系统 MUST 生成形如
EXC20260319XXXXXX的单号并写入exchange_no