Files
junhong_cmp_fiber/openspec/changes/archive/2026-03-16-asset-wallet-interface/tasks.md

12 KiB
Raw Blame History

1. 数据库迁移(先行)

  • 1.1 创建迁移文件:tb_card_wallettb_asset_wallettb_card_wallet_transactiontb_asset_wallet_transactiontb_card_recharge_recordtb_asset_recharge_record(三张表在同一个迁移文件中完成)
  • 1.2 创建迁移文件:tb_asset_wallet_transaction.reference_id (bigint, nullable)reference_no (varchar 50, nullable)ALTER TABLE RENAME COLUMN + ALTER COLUMN TYPE
  • 1.3 执行全部迁移,使用 PostgreSQL MCP 确认三张表改名成功,reference_no 字段类型为 varchar(50)

2. Model 层全量重命名

  • 2.1 重命名 internal/model/card_wallet.gointernal/model/asset_wallet.go,文件内所有类型改名:
    • CardWalletAssetWalletTableName() 返回 "tb_asset_wallet"
    • CardWalletTransactionAssetWalletTransactionTableName() 返回 "tb_asset_wallet_transaction"
    • CardRechargeRecordAssetRechargeRecordTableName() 返回 "tb_asset_recharge_record"
  • 2.2 更新 AssetWalletTransaction 结构体字段:CardWalletID uint json:"card_wallet_id"AssetWalletID uint json:"asset_wallet_id"GORM column tag 同步更新为 column:asset_wallet_idReferenceID *uint json:"reference_id,omitempty"ReferenceNo *string json:"reference_no,omitempty"GORM column tag 改为 column:reference_no;type:varchar(50)
  • 2.3 更新 AssetRechargeRecord 结构体字段:CardWalletID uint json:"card_wallet_id"AssetWalletID uint json:"asset_wallet_id"GORM column tag 同步更新)
  • 2.4 运行 go build ./... 确认 Model 层无编译错误

3. Store 层全量重命名

  • 3.1 重命名 internal/store/postgres/card_wallet_store.goasset_wallet_store.go,类型 CardWalletStoreAssetWalletStore,构造函数 NewCardWalletStoreNewAssetWalletStore,方法内 model.CardWalletmodel.AssetWallet
  • 3.2 重命名 internal/store/postgres/card_wallet_transaction_store.goasset_wallet_transaction_store.go,类型 CardWalletTransactionStoreAssetWalletTransactionStore,构造函数及方法内 Model 引用同步更新
  • 3.3 重命名 internal/store/postgres/card_recharge_store.goasset_recharge_store.go,类型 CardRechargeStoreAssetRechargeStore,构造函数及方法内 Model 引用同步更新
  • 3.4 运行 go build ./... 确认 Store 层无编译错误

4. Bootstrap 层更新

  • 4.1 更新 internal/bootstrap/stores.go:字段名 CardWalletAssetWalletCardWalletTransactionAssetWalletTransactionCardRechargeAssetRecharge;构造函数调用同步更新为 NewAssetWalletStoreNewAssetWalletTransactionStoreNewAssetRechargeStore
  • 4.2 更新 internal/bootstrap/services.go:依赖注入中所有 s.CardWallet* 引用改为 s.AssetWallet*s.CardRecharge 改为 s.AssetRecharge
  • 4.3 运行 go build ./... 确认 bootstrap 层无编译错误

5. 常量层更新

  • 5.1 更新 pkg/constants/redis.goRedisCardWalletBalanceKeyRedisAssetWalletBalanceKey,函数体不变,仅函数名改变
  • 5.2 全局搜索 RedisCardWalletBalanceKey 调用处card_wallet_store.go替换为 RedisAssetWalletBalanceKey

6. Service 层适配order service

  • 6.1 更新 internal/service/order/service.go:结构体字段 cardWalletStore *postgres.CardWalletStoreassetWalletStore *postgres.AssetWalletStore,构造函数参数及所有调用点同步更新
  • 6.2 在 WalletPay 卡钱包支付路径(resourceType != "shop" 分支)中,扣款成功后在同一事务内补写 AssetWalletTransaction 扣款流水:
    • 在事务内扣款前记录 balanceBefore = wallet.Balance
    • 扣款成功(RowsAffected == 1)后,INSERT 一条 AssetWalletTransactionAssetWalletID=wallet.IDResourceType=resourceTypeResourceID=resourceIDUserID=buyerIDTransactionType="deduct"Amount=-order.TotalAmountBalanceBefore=balanceBeforeBalanceAfter=balanceBefore-order.TotalAmountStatus=1ReferenceType=strPtr("order")ReferenceNo=&order.OrderNoRemark=strPtr("钱包支付套餐")ShopIDTag=wallet.ShopIDTagEnterpriseIDTag=wallet.EnterpriseIDTag
  • 6.3 运行 go build ./... 确认 order service 无编译错误

7. Service 层适配recharge service

  • 7.1 更新 internal/service/recharge/service.go:结构体字段及构造函数 cardWalletStoreassetWalletStorecardWalletTransactionStoreassetWalletTransactionStore;所有 Model 引用 model.CardWallet*model.AssetWallet*
  • 7.2 更新充值回调写入流水记录处(约第 320 行):ReferenceID: &recharge.IDReferenceNo: &recharge.RechargeNo(同时删除原 ReferenceID 字段赋值)
  • 7.3 运行 go build ./... 确认 recharge service 无编译错误

8. DTO 新增

  • 8.1 新建 internal/model/dto/asset_wallet_dto.go,定义以下 DTO含所有字段及 description tag

    AssetWalletResponse(钱包概况响应):

    • wallet_id uintresource_type stringresource_id uint
    • balance int64frozen_balance int64available_balance int64
    • currency stringstatus intstatus_text string
    • created_at time.Timeupdated_at time.Time

    AssetWalletTransactionListRequest(流水列表请求,查询参数):

    • page int(默认 1page_size int(默认 20最大 100
    • transaction_type *string可选oneof=recharge deduct refund
    • start_time *time.Time(可选)、end_time *time.Time(可选)

    AssetWalletTransactionItem(单条流水):

    • id uint
    • transaction_type stringtransaction_type_text string
    • amount int64balance_before int64balance_after int64
    • reference_type *stringreference_no *string
    • remark *string
    • created_at time.Time

    AssetWalletTransactionListResponse(流水列表响应):

    • list []*AssetWalletTransactionItem
    • total int64page intpage_size inttotal_pages int
  • 8.2 运行 lsp_diagnostics 确认 DTO 无错误

9. AssetWalletService 新增

  • 9.1 新建 internal/service/asset_wallet/service.go,定义 Service 结构体,依赖注入:AssetWalletStoreAssetWalletTransactionStore
  • 9.2 实现 GetWallet(ctx, assetType string, assetID uint) (*dto.AssetWalletResponse, error)
    • assetTypecard/device)映射到 resourceTypeiot_card/device
    • 调用 AssetWalletStore.GetByResourceTypeAndID(ctx, resourceType, assetID)
    • 组装 AssetWalletResponse(计算 available_balance = balance - frozen_balance,翻译 status_text
    • 钱包不存在时返回 errors.New(errors.CodeNotFound, "该资产暂无钱包记录")
  • 9.3 实现 ListTransactions(ctx, assetType string, assetID uint, req *dto.AssetWalletTransactionListRequest) (*dto.AssetWalletTransactionListResponse, error)
    • assetType 映射为 resourceType
    • 调用 AssetWalletTransactionStore.ListByResourceID(ctx, resourceType, assetID, offset, limit)CountByResourceID 获取分页数据
    • 组装响应:翻译 transaction_type_textrecharge→充值 / deduct→扣款 / refund→退款计算 total_pages
    • 如有 transaction_type 过滤参数,在 Store 层新增对应过滤方法(或在 Service 层 in-memory 过滤——推荐 Store 层)
  • 9.4 运行 lsp_diagnostics 确认 Service 无错误

10. Store 层新增查询方法

  • 10.1 在 AssetWalletTransactionStore 中新增 ListByResourceIDWithFilter(ctx, resourceType string, resourceID uint, transactionType *string, startTime, endTime *time.Time, offset, limit int) ([]*model.AssetWalletTransaction, error) 方法,支持 transaction_type、时间范围过滤,应用 ApplyShopTagFilter 数据权限
  • 10.2 在 AssetWalletTransactionStore 中新增 CountByResourceIDWithFilter(ctx, resourceType string, resourceID uint, transactionType *string, startTime, endTime *time.Time) (int64, error) 方法
  • 10.3 运行 lsp_diagnostics 确认 Store 无错误

11. AssetWalletHandler 新增

  • 11.1 新建 internal/handler/admin/asset_wallet.go,定义 AssetWalletHandler 结构体(依赖 *assetWalletSvc.Service),实现两个 Handler 方法:

    GetWalletGET /api/admin/assets/:asset_type/:id/wallet

    • 检查企业账号:user_type == UserTypeEnterprise → 返回 403
    • 解析路径参数 asset_type(校验为 carddevice)和 id(校验为正整数)
    • 调用 assetWalletSvc.GetWallet(ctx, assetType, id) → 返回 response.Success

    ListTransactionsGET /api/admin/assets/:asset_type/:id/wallet/transactions

    • 检查企业账号:同上
    • 解析路径参数和查询参数(QueryParser 绑定 AssetWalletTransactionListRequest
    • 参数验证:page_size 最大 100transaction_type 需为合法枚举值
    • 调用 assetWalletSvc.ListTransactions(ctx, assetType, id, &req) → 返回 response.Success
  • 11.2 运行 lsp_diagnostics 确认 Handler 无编译错误

12. 路由注册

  • 12.1 在 internal/routes/asset.goregisterAssetRoutes 函数末尾追加两条路由(需传入 *admin.AssetWalletHandler 参数):

    Register(assets, doc, groupPath, "GET", "/:asset_type/:id/wallet", walletHandler.GetWallet, RouteSpec{
        Summary:     "资产钱包概况",
        Description: "查询指定卡或设备的钱包余额概况。企业账号禁止调用。",
        Tags:        []string{"资产管理"},
        Input:       new(dto.AssetTypeIDRequest),
        Output:      new(dto.AssetWalletResponse),
        Auth:        true,
    })
    
    Register(assets, doc, groupPath, "GET", "/:asset_type/:id/wallet/transactions", walletHandler.ListTransactions, RouteSpec{
        Summary:     "资产钱包流水列表",
        Description: "分页查询指定资产的钱包收支流水,含充值/扣款来源编号。企业账号禁止调用。",
        Tags:        []string{"资产管理"},
        Input:       new(dto.AssetWalletTransactionListRequest),
        Output:      new(dto.AssetWalletTransactionListResponse),
        Auth:        true,
    })
    
  • 12.2 更新 registerAssetRoutes 函数签名,增加 walletHandler *admin.AssetWalletHandler 参数

  • 12.3 更新 internal/routes/routes.goregisterAssetRoutes 的调用处,传入 AssetWalletHandler

13. Bootstrap 层注册新 Handler/Service

  • 13.1 更新 internal/bootstrap/types.goHandlers 结构体新增 AssetWallet *admin.AssetWalletHandlerServices 结构体新增 AssetWallet *assetWalletSvc.Service(如需独立 service 包则导入)
  • 13.2 更新 internal/bootstrap/services.go:实例化 assetWalletSvc.New(s.AssetWallet, s.AssetWalletTransaction)
  • 13.3 更新 internal/bootstrap/handlers.go:实例化 admin.NewAssetWalletHandler(svcs.AssetWallet)
  • 13.4 更新 cmd/api/docs.gocmd/gendocs/main.gohandlers.AssetWallet = admin.NewAssetWalletHandler(nil)(文档生成器注册)
  • 13.5 运行 go build ./... 全量确认无编译错误

14. 文档和最终验收

  • 14.1 运行 go run cmd/gendocs/main.go 确认两个新接口(资产钱包概况、资产钱包流水列表)出现在 OpenAPI 文档中
  • 14.2 使用 PostgreSQL MCP 验证三张表改名成功:tb_asset_wallettb_asset_wallet_transaction(含 reference_no varchar(50) 字段)、tb_asset_recharge_record
  • 14.3 使用 PostgreSQL MCP 或 curl 验证H5 充值接口 GET /api/h5/wallets/recharges/:id 响应中 wallet_id 字段仍正常返回
  • 14.4 运行 go build ./... 全量确认无编译错误
  • 14.5 tasks.md 全部任务标记完成