Files
Break 27fba9160c
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 56s
提案
2026-06-04 09:39:20 +08:00

9.7 KiB
Raw Blame History

MODIFIED Requirements

Requirement: H1 发起换货单

系统 SHALL 提供 POST /api/admin/exchanges(需后台认证 Auth=true),用于发起换货单。

请求体 MUST 包含:old_asset_typeold_identifierexchange_reason,可选 flow_typeremark

flow_type 未传或为空时,系统 MUST 按 shipping 处理,以兼容旧后台调用;传入非空且不属于 shipping/direct 时,系统 MUST 返回参数错误。

flow_type=shipping 时:

  • 请求体 MUST NOT 要求 new_identifier
  • 请求体 MUST NOT 要求 migrate_data
  • 系统创建成功后 SHALL 返回新建换货单信息(含 idexchange_noflow_type=shippingstatus=1

flow_type=direct 时:

  • 请求体 MUST 额外包含 new_identifier
  • 请求体 MAY 包含 migrate_data;未传时 MUST 按 false 处理
  • 系统 MUST 在创建接口内完成新资产校验与换货完成事务
  • 创建成功后 SHALL 返回新建换货单信息(含 idexchange_noflow_type=directstatus=4completed_at
  • 任一步失败时 MUST 回滚整个事务,且 MUST NOT 保留半成品 direct 换货单

系统 MUST 校验:

  • 旧资产存在且当前用户有权限
  • 旧资产当前 asset_status=2(已销售)
  • 同一资产不存在进行中的 shipping 换货单(status IN (1,2,3)
  • direct 场景下新资产存在
  • direct 场景下新资产当前用户有权限
  • direct 场景下新旧资产类型必须一致(卡换卡/设备换设备)
  • direct 场景下新资产必须 asset_status=1(在库)
  • direct 场景下新旧资产 shop_id 必须一致(含二者同为平台库存 NULL
  • 若旧资产存在客户绑定,则 direct 场景下新资产必须可承接绑定关系
  • direct 场景下新资产不得存在 status=1 的有效客户绑定
  • direct 场景下新资产不得已被其他 shipping + status=3 换货单占用

错误响应 MUST 至少包含:参数错误、资产不存在或无权限、旧资产状态不允许换货、存在进行中换货单、新资产不存在、资产类型不匹配、新资产非在库、新旧资产归属不一致、新资产已被占用、绑定无法承接、钱包冻结余额未处理、迁移失败。

Scenario: shipping 正常创建

  • WHEN 后台以 flow_type=shipping 或未传 flow_type 发起换货,且旧资产为已销售并无进行中单据
  • THEN 系统 MUST 创建 status=1 的换货单

Scenario: direct 创建即完成

  • WHEN 后台以 flow_type=direct 发起换货且新旧资产校验通过
  • THEN 系统 MUST 在同一事务内创建换货单并完成换货
  • AND 返回结果 MUST 为 status=4

Scenario: direct 缺少新资产标识

  • WHEN 后台以 flow_type=direct 发起换货但未传 new_identifier
  • THEN 系统 MUST 拒绝创建并返回参数错误

Scenario: direct 迁移标记未传

  • WHEN 后台以 flow_type=direct 发起换货且未传 migrate_data
  • THEN 系统 MUST 按 migrate_data=false 创建并完成换货

Scenario: direct 完成失败不留半成品单据

  • WHEN 后台以 flow_type=direct 发起换货,但完成事务中的绑定承接或迁移步骤失败
  • THEN 系统 MUST 回滚整笔事务
  • AND MUST NOT 查询到本次请求创建的半成品 direct 换货单

Scenario: 资产已有进行中 shipping 换货单

  • WHEN 后台为同一资产重复发起 shipping 换货
  • THEN 系统 MUST 拒绝创建并返回“存在进行中的换货单”

Scenario: 旧资产非已销售禁止换货

  • WHEN 旧资产 asset_status != 2
  • THEN 系统 MUST 拒绝创建并返回资产状态不允许换货

Requirement: H2 换货单列表

系统 SHALL 提供 GET /api/admin/exchangesAuth=true),支持分页与条件查询。

查询条件 SHOULD 支持:statusflow_typeidentifier(资产标识搜索)、created_at_startcreated_at_end、分页参数。

响应 SHALL 返回列表与分页元数据。 响应项 MUST 返回:旧/新资产标识、flow_typestatusshipped_atcompleted_at

Scenario: 按流程类型查询 direct 已完成单

  • WHEN 运营查询 flow_type=directstatus=4
  • THEN 系统返回所有 direct 已完成换货单并按创建时间倒序

Requirement: H3 换货单详情

系统 SHALL 提供 GET /api/admin/exchanges/:idAuth=true)查询换货单详情。

响应 MUST 返回旧/新资产信息、流程类型、收货信息、物流信息、迁移状态信息、shipped_atcompleted_at

错误响应 MUST 至少包含:换货单不存在或无权限。

Scenario: 查询 direct 换货单详情

  • WHEN 查询一张 flow_type=direct 的已完成换货单
  • THEN 响应 MUST 返回 flow_type=direct
  • AND 收货信息与物流信息可以为空
  • AND completed_at 必须存在

Requirement: H4 发货

系统 SHALL 提供 POST /api/admin/exchanges/:id/shipAuth=true)。

请求体 MUST 包含:express_companyexpress_nonew_identifiermigrate_data

系统 MUST 校验:

  • 换货单 flow_type 必须为 shipping
  • 当前状态必须为 2
  • 旧资产当前必须仍为 asset_status=2(已销售)
  • 新旧资产类型必须一致(卡换卡/设备换设备)
  • 新资产必须 asset_status=1(在库)
  • 新资产当前用户有权限
  • 新旧资产 shop_id 必须一致(含二者同为平台库存 NULL
  • 新资产不得存在 status=1 的有效客户绑定
  • 新资产不得已被其他 shipping + status=3 换货单占用
  • 系统 MUST 通过条件更新、行锁或等效机制确保发货成功时新资产仍满足在库且未被占用

成功后 SHALL

  • 更新新资产信息
  • 更新物流信息
  • 写入 migrate_data
  • 记录 shipped_at
  • 将状态改为 3
  • 将新资产视为被当前换货单占用;在确认完成前不改变新资产 asset_status

错误响应 MUST 至少包含:非法状态、流程类型不支持发货、旧资产状态不允许换货、资产类型不匹配、新资产非在库、新旧资产归属不一致、新资产已被占用、资产不存在或无权限。

Scenario: direct 单据禁止发货

  • WHEN flow_type=direct 的换货单调用发货接口
  • THEN 系统 MUST 拒绝并返回流程类型不支持该操作的错误

Scenario: 新资产类型不一致

  • WHEN 旧资产为 iot_card 且新资产为 device
  • THEN 系统 MUST 拒绝发货并返回“换货资产类型必须一致”

Scenario: 新资产已被其他换货单占用

  • WHEN 新资产已经作为其他 shipping + status=3 换货单的新资产
  • THEN 系统 MUST 拒绝发货并返回新资产已被占用

Requirement: H5 确认完成

系统 SHALL 提供 POST /api/admin/exchanges/:id/completeAuth=true)。

系统 MUST 校验:

  • 换货单 flow_type 必须为 shipping
  • 当前状态必须为 3

系统 MUST 在单一数据库事务中执行完成换货动作。该事务至少包括:

  • 校验新资产快照完整且新资产仍满足换货条件
  • 校验旧资产仍为 asset_status=2(已销售)
  • 校验新资产仍为 asset_status=1(在库),且未被当前换货单之外的有效记录占用
  • 旧资产 asset_status -> 3
  • 新资产 asset_status -> 2
  • 若旧资产存在 PersonalCustomerDevice 绑定,则绑定切换到新资产资产绑定键
  • migrate_data=true,执行全量迁移事务(见 exchange-data-migration 能力)
  • 写入 completed_at
  • 换货单状态更新为 4

成功后 SHALL

  • migration_completed=true(若执行迁移)
  • 换货单状态更新为 4

错误响应 MUST 至少包含:非法状态、流程类型不支持确认完成、旧资产状态不允许换货、新资产状态不允许换货、迁移失败、绑定无法承接、钱包冻结余额未处理、换货单不存在或无权限。

Scenario: 需要迁移并完成

  • WHEN shipping 换货单状态为 3migrate_data=true
  • THEN 系统 MUST 在同一事务成功后将状态变为 4 并记录迁移结果

Scenario: 不迁移也必须完成切换

  • WHEN shipping 换货单状态为 3migrate_data=false
  • THEN 系统 MUST 仍然在事务内完成旧资产状态切换、新资产状态切换、绑定切换和单据完成

Requirement: H6 取消换货

系统 SHALL 提供 POST /api/admin/exchanges/:id/cancelAuth=true)。

系统 MUST 仅允许 flow_type=shippingstatus IN (1,2) 时取消,成功后状态更新为 5

系统 MUST 禁止已发货单取消(status=3)。 系统 MUST 禁止 direct 单据进入取消分支。

Scenario: 已发货单取消失败

  • WHEN shipping 换货单状态为 3 发起取消
  • THEN 系统 MUST 返回状态非法错误

Scenario: direct 单据取消失败

  • WHEN direct 换货单发起取消
  • THEN 系统 MUST 返回流程类型不支持该操作的错误

Requirement: H7 旧资产转新

系统 SHALL 提供 POST /api/admin/exchanges/:id/renewAuth=true)。

系统 MUST 校验旧资产当前 asset_status=3(已换货),并执行:

  • generation + 1
  • asset_status -> 1
  • 清除累计充值/首充相关状态
  • 清除个人客户绑定
  • 创建新空钱包

系统 MUST 保留历史数据,不执行历史删除。 系统 MUST NOT 在换货完成阶段修改旧资产 generationgeneration 仅在 renew 阶段递增。

错误响应 MUST 至少包含:资产状态不满足转新条件、换货单不存在或无权限。

Scenario: 旧资产未处于已换货状态

  • WHEN 旧资产 asset_status != 3 发起转新
  • THEN 系统 MUST 拒绝并返回“资产当前状态不允许转新”