feat: 资产标识符标准化、资产历史订单查询及导入虚拟号强制验证
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m21s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m21s
主要变更: - 新增 AssetIdentifier 模型及 Store,统一管理资产标识符(ICCID/IMEI/SN 等) - 新增迁移:asset_identifier 表、order 表新增 asset_identifier 字段、iot_card.virtual_no NOT NULL 约束 - 资产 Handler/Service/Route 全面重构,支持标识符路由查询与解析 - 新增资产历史订单查询接口,支持跨设备/卡/钱包维度的订单聚合 - 设备与物联卡导入任务强制校验虚拟号,缺失时直接拒绝 - Excel 工具函数优化,前端导入指引文档同步更新 - 归档三个 OpenSpec 提案:asset-identifier-standardization、asset-historical-orders、import-mandatory-virtual-no - 更新 OpenAPI 文档及相关 DTO Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -26,7 +26,21 @@
|
||||
|
||||
### Requirement: 创建套餐购买订单
|
||||
|
||||
系统 SHALL 允许买家创建套餐购买订单。订单类型分为单卡购买和设备购买。创建前 MUST 验证购买权限和强充要求。**后台订单接口 MUST 支持 `payment_method` 字段(wallet/offline),根据支付方式自动设置 `is_purchase_on_behalf` 标识**。
|
||||
系统 SHALL 允许买家创建套餐购买订单。**[BREAKING]** 请求体改为使用资产标识符(identifier),废弃 `iot_card_id`/`device_id` 主键字段;`order_type` 字段由系统根据 identifier 解析结果自动填入,请求体不再接受。创建前 MUST 验证购买权限和强充要求。**后台订单接口 MUST 支持 `payment_method` 字段(wallet/offline),根据支付方式自动设置 `is_purchase_on_behalf` 标识**。
|
||||
|
||||
**后台订单创建请求(CreateAdminOrderRequest)**:
|
||||
```json
|
||||
{
|
||||
"identifier": "string(资产标识符,ICCID 或 VirtualNo,必填)",
|
||||
"package_ids": "[uint](套餐 ID 列表,必填,1-10 个)",
|
||||
"payment_method": "string(wallet|offline,必填)"
|
||||
}
|
||||
```
|
||||
|
||||
**废弃字段**:
|
||||
- `iot_card_id`(原用于单卡购买)
|
||||
- `device_id`(原用于设备购买)
|
||||
- `order_type`(改为系统自动推断)
|
||||
|
||||
**支付方式和订单类型映射**:
|
||||
- `payment_method = "wallet"`:扣买家钱包,`is_purchase_on_behalf = false`(普通订单)
|
||||
@@ -72,6 +86,22 @@
|
||||
- **WHEN** 买家尝试购买已下架的套餐
|
||||
- **THEN** 系统返回错误 "该套餐已下架"
|
||||
|
||||
#### Scenario: 使用 VirtualNo 创建设备订单
|
||||
- **WHEN** 管理员请求体携带 `{ identifier: "DEV-001", package_ids: [5], payment_method: "wallet" }`
|
||||
- **THEN** 系统解析 identifier 为设备,自动设置 `order_type = device`,创建设备购买订单
|
||||
|
||||
#### Scenario: 使用 ICCID 创建单卡订单
|
||||
- **WHEN** 管理员请求体携带 `{ identifier: "898600XXXXX", package_ids: [5], payment_method: "wallet" }`
|
||||
- **THEN** 系统解析 identifier 为独立 IoT 卡(`is_standalone = true`),自动设置 `order_type = single_card`,创建单卡购买订单
|
||||
|
||||
#### Scenario: 使用绑定设备的卡 ICCID 创建订单被拒
|
||||
- **WHEN** 管理员请求体携带 `{ identifier: "898600XXXXX" }` 但该卡 `is_standalone = false`
|
||||
- **THEN** 系统返回错误"该卡已绑定设备,请前往设备页面购买套餐",订单不创建
|
||||
|
||||
#### Scenario: identifier 不存在
|
||||
- **WHEN** 请求的 identifier 无法解析到任何资产
|
||||
- **THEN** 返回错误"资产不存在",订单不创建
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 查询订单列表
|
||||
@@ -224,3 +254,36 @@
|
||||
#### Scenario: 后台管理端可为未实名载体购买
|
||||
- **WHEN** 管理员通过后台为未实名载体购买套餐
|
||||
- **THEN** 系统创建订单成功,PackageUsage status=0, pending_realname_activation=true
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 订单响应包含资产标识符
|
||||
|
||||
订单响应(OrderResponse)SHALL 包含资产标识符字段,前端无需额外请求即可展示资产信息。
|
||||
|
||||
**新增响应字段**:
|
||||
- `asset_identifier`:下单时资产的标识符快照(ICCID 或 VirtualNo)
|
||||
- `asset_type`:资产类型(`single_card` 对应 `iot_card`,`device` 对应 `device`)
|
||||
|
||||
#### Scenario: 查看订单详情时展示资产标识符
|
||||
- **WHEN** 管理员查询订单详情 `GET /api/admin/orders/:id`
|
||||
- **THEN** 响应中包含 `asset_identifier`(如 "DEV-001")和 `asset_type`(如 "device")
|
||||
- **THEN** 即使原资产已被删除,`asset_identifier` 仍可读(快照字段)
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 订单列表支持按资产标识符过滤
|
||||
|
||||
系统 SHALL 在订单列表查询(OrderListRequest)中支持 `identifier` 过滤参数,按照资产标识符精确匹配订单(匹配 `asset_identifier` 快照字段)。
|
||||
|
||||
#### Scenario: 按 ICCID 查询该卡的历史订单
|
||||
- **WHEN** 管理员查询 `GET /api/admin/orders?identifier=898600XXXXX`
|
||||
- **THEN** 返回 `asset_identifier = "898600XXXXX"` 的所有订单(分页)
|
||||
|
||||
#### Scenario: 按设备 VirtualNo 查询该设备的历史订单
|
||||
- **WHEN** 管理员查询 `GET /api/admin/orders?identifier=DEV-001`
|
||||
- **THEN** 返回 `asset_identifier = "DEV-001"` 的所有订单(分页)
|
||||
|
||||
#### Scenario: 标识符无匹配订单
|
||||
- **WHEN** 管理员查询不存在订单的 identifier
|
||||
- **THEN** 返回空列表(`items: []`,`total: 0`),不返回错误
|
||||
|
||||
Reference in New Issue
Block a user