All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m12s
1. 修正 retail_price 架构:
- 删除 batch-pricing 接口的 pricing_target 字段和 retail_price 分支
(上级只能改下级成本价,不能改零售价)
- 新增 PATCH /api/admin/packages/:id/retail-price 接口
(代理自己改自己的零售价,校验 retail_price >= cost_price)
2. 清理旧微信 YAML 配置(已全部迁移到数据库 tb_wechat_config):
- 删除 config.yaml 中 wechat.official_account 配置节
- 删除 NewOfficialAccountApp() 旧工厂函数
- 清理 personal_customer service 中的死代码(旧登录/绑定微信方法)
- 清理 docker-compose.prod.yml 中旧微信环境变量和证书挂载注释
3. 归档四个已完成提案到 openspec/changes/archive/
4. 新增前端接口变更说明文档(docs/前端接口变更说明.md)
5. 修正归档提案和 specs 中关于 pricing_target 的错误描述
128 lines
4.3 KiB
Markdown
128 lines
4.3 KiB
Markdown
# exchange-admin-management Specification
|
||
|
||
## Purpose
|
||
|
||
提供后台换货单管理能力,涵盖换货单的发起、列表查询、详情查看、发货、确认完成、取消及旧资产转新等完整生命周期管理。
|
||
|
||
## Requirements
|
||
|
||
### Requirement: H1 发起换货单
|
||
|
||
系统 SHALL 提供 `POST /api/admin/exchanges`(需后台认证 `Auth=true`),用于发起换货单。
|
||
|
||
请求体 MUST 包含:`old_asset_type`、`old_identifier`、`exchange_reason`,可选 `remark`。
|
||
|
||
系统 MUST 校验:
|
||
- 旧资产存在且当前用户有权限
|
||
- 同一资产不存在进行中的换货单(`status IN (1,2,3)`)
|
||
|
||
成功响应 SHALL 返回新建换货单信息(含 `id`、`exchange_no`、`status=1`)。
|
||
|
||
错误响应 MUST 至少包含:参数错误、资产不存在或无权限、存在进行中换货单。
|
||
|
||
#### Scenario: 资产已有进行中换货单
|
||
- **WHEN** 后台为同一资产重复发起换货
|
||
- **THEN** 系统 MUST 拒绝创建并返回"存在进行中的换货单"
|
||
|
||
---
|
||
|
||
### Requirement: H2 换货单列表
|
||
|
||
系统 SHALL 提供 `GET /api/admin/exchanges`(`Auth=true`),支持分页与条件查询。
|
||
|
||
查询条件 SHOULD 支持:`status`、`identifier`(资产标识搜索)、`created_at_start`、`created_at_end`、分页参数。
|
||
|
||
响应 SHALL 返回列表与分页元数据。
|
||
|
||
#### Scenario: 按状态查询待发货单
|
||
- **WHEN** 运营查询 `status=2`
|
||
- **THEN** 系统返回所有待发货换货单并按创建时间倒序
|
||
|
||
---
|
||
|
||
### Requirement: H3 换货单详情
|
||
|
||
系统 SHALL 提供 `GET /api/admin/exchanges/:id`(`Auth=true`)查询换货单详情。
|
||
|
||
响应 MUST 返回旧/新资产信息、收货信息、物流信息、迁移状态信息。
|
||
|
||
错误响应 MUST 至少包含:换货单不存在或无权限。
|
||
|
||
#### Scenario: 查询不存在换货单
|
||
- **WHEN** 查询不存在的换货单 ID
|
||
- **THEN** 系统 MUST 返回"资源不存在或无权限"
|
||
|
||
---
|
||
|
||
### Requirement: H4 发货
|
||
|
||
系统 SHALL 提供 `POST /api/admin/exchanges/:id/ship`(`Auth=true`)。
|
||
|
||
请求体 MUST 包含:`express_company`、`express_no`、`new_identifier`、`migrate_data`。
|
||
|
||
系统 MUST 校验:
|
||
- 当前状态必须为 `2`
|
||
- 新旧资产类型必须一致(卡换卡/设备换设备)
|
||
- 新资产必须 `asset_status=1`(在库)
|
||
|
||
成功后 SHALL 更新新资产信息、物流信息并将状态改为 `3`。
|
||
|
||
错误响应 MUST 至少包含:非法状态、资产类型不匹配、新资产非在库、资产不存在或无权限。
|
||
|
||
#### Scenario: 新资产类型不一致
|
||
- **WHEN** 旧资产为 iot_card 且新资产为 device
|
||
- **THEN** 系统 MUST 拒绝发货并返回"换货资产类型必须一致"
|
||
|
||
---
|
||
|
||
### Requirement: H5 确认完成
|
||
|
||
系统 SHALL 提供 `POST /api/admin/exchanges/:id/complete`(`Auth=true`)。
|
||
|
||
系统 MUST 校验当前状态为 `3`。当 `migrate_data=true` 时,系统 MUST 执行全量迁移事务(见 `exchange-data-migration` 能力)。
|
||
|
||
成功后 SHALL:
|
||
- `migration_completed=true`(若执行迁移)
|
||
- 换货单状态更新为 `4`
|
||
|
||
错误响应 MUST 至少包含:非法状态、迁移失败、换货单不存在或无权限。
|
||
|
||
#### Scenario: 需要迁移并完成
|
||
- **WHEN** 状态为 `3` 且 `migrate_data=true`
|
||
- **THEN** 系统 MUST 在事务成功后将状态变为 `4` 并记录迁移结果
|
||
|
||
---
|
||
|
||
### Requirement: H6 取消换货
|
||
|
||
系统 SHALL 提供 `POST /api/admin/exchanges/:id/cancel`(`Auth=true`)。
|
||
|
||
系统 MUST 仅允许在 `status IN (1,2)` 时取消,成功后状态更新为 `5`。
|
||
|
||
系统 MUST 禁止已发货单取消(`status=3`)。
|
||
|
||
#### Scenario: 已发货单取消失败
|
||
- **WHEN** 换货单状态为 `3` 发起取消
|
||
- **THEN** 系统 MUST 返回状态非法错误
|
||
|
||
---
|
||
|
||
### Requirement: H7 旧资产转新
|
||
|
||
系统 SHALL 提供 `POST /api/admin/exchanges/:id/renew`(`Auth=true`)。
|
||
|
||
系统 MUST 校验旧资产当前 `asset_status=3`(已换货),并执行:
|
||
- `generation + 1`
|
||
- `asset_status -> 1`
|
||
- 清除累计充值/首充相关状态
|
||
- 清除个人客户绑定
|
||
- 创建新空钱包
|
||
|
||
系统 MUST 保留历史数据,不执行历史删除。
|
||
|
||
错误响应 MUST 至少包含:资产状态不满足转新条件、换货单不存在或无权限。
|
||
|
||
#### Scenario: 旧资产未处于已换货状态
|
||
- **WHEN** 旧资产 `asset_status != 3` 发起转新
|
||
- **THEN** 系统 MUST 拒绝并返回"资产当前状态不允许转新"
|