Files
junhong_cmp_fiber/openspec/changes/archive/2026-04-07-asset-historical-orders/tasks.md
huang 80c6f6c756
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m21s
feat: 资产标识符标准化、资产历史订单查询及导入虚拟号强制验证
主要变更:
- 新增 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>
2026-04-07 17:39:36 +08:00

3.7 KiB
Raw Blame History

1. 前置确认

  • 1.1 确认提案一asset-identifier-standardization已完成tb_order.asset_identifier 字段存在B 端资产路由已统一为 :identifier

2. 数据层ExchangeOrder Store 扩展

  • 2.1 在 internal/store/postgres/exchange_order_store.go 新增 FindByNewAssetID(ctx, assetType, assetID) (*model.ExchangeOrder, error) 方法:查询 WHERE new_asset_id = ? AND new_asset_type = ?,返回该资产的换货来源记录(找不到则返回 nil表示无前代

3. DTO 层:新增响应结构

  • 3.1 在 internal/model/dto/asset_dto.go 新增以下结构体:
    • AssetOrdersRequest:路径参数 identifierquery 参数 pagepage_sizeinclude_previous
    • AssetOrderItem单条订单项order_no、order_type、payment_status、payment_status_text、total_amount、payment_method、paid_at、generation、items、created_at
    • GenerationOrders单代订单块generation、identifier、asset_type、total、page、page_size、items
    • PreviousGenerationOrders前代订单块generation、identifier、asset_type、exchange_no、exchanged_at、total、items
    • AssetOrdersResponse完整响应current_generation、previous_generations、truncated

4. 服务层GetOrders 方法

  • 4.1 在 internal/service/asset/service.go 新增 GetOrders(ctx, identifier, page, pageSize, includePrevious bool) (*dto.AssetOrdersResponse, error) 方法:
    • 调用 Resolve() 得到 asset_type 和 asset_id
    • 查询本代订单:orderStore.ListByAssetIdentifier(ctx, identifier, page, pageSize)
    • includePrevious=true:循环调用 exchangeOrderStore.FindByNewAssetID() 追溯换货链(最多 10 代);每代查询前代 old_asset_identifier 对应的订单(最多 20 条,无分页)
    • 组装 AssetOrdersResponse 返回
  • 4.2 在 internal/store/postgres/order_store.go 新增 ListByAssetIdentifier(ctx, identifier, page, pageSize) ([]*model.Order, int64, error) 方法:查询 WHERE asset_identifier = ?,分页,倒序

5. Handler 层:新增 Orders Handler

  • 5.1 在 internal/handler/admin/asset.go 新增 Orders(c *fiber.Ctx) error handler
    • 从路径参数读取 identifier;从 query 读取 pagepage_sizeinclude_previous
    • 调用 assetService.GetOrders()
    • 返回 response.Success(c, result)
    • 注释:// Orders 查询资产历史订单(支持跨代追溯) + // GET /api/admin/assets/:identifier/orders

6. 路由层:注册新路由

  • 6.1 在 internal/routes/asset.go 注册:assets.Get("/:identifier/orders", h.Asset.Orders)(注意路由顺序,避免与 /resolve/:identifier 冲突)

7. 文档生成器更新

  • 7.1 在 cmd/api/docs.gocmd/gendocs/main.gohandlers 结构体中确认 AssetHandler 已包含新的 Orders 方法(检查是否需要更新 handler 注册)
  • 7.2 执行 go run cmd/gendocs/main.go 重新生成 OpenAPI 文档,验证新接口体现

8. 验证

  • 8.1 构建验证:go build ./... 无编译错误
  • 8.2 LSP 诊断:对所有修改文件运行 lsp_diagnostics无错误/警告
  • 8.3 接口验证(使用 PostgreSQL MCP + curl
    • 查询有订单的资产:GET /api/admin/assets/:identifier/orders 返回正确订单列表,含 generation 字段
    • 查询无订单资产:返回 items: [], total: 0
    • 查询不存在的 identifier返回 404
    • 查询换货资产(带 include_previous=trueprevious_generations 包含前代订单,附带 exchange_no 和 exchanged_at
    • 查询无前代的资产(带 include_previous=trueprevious_generations 为空数组
    • 代理查询无权限资产:返回 403