docs: 归档 asset-wallet-interface OpenSpec 提案,更新卡钱包 spec
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
## 1. 数据库迁移(先行)
|
||||
|
||||
- [x] 1.1 创建迁移文件:`tb_card_wallet` → `tb_asset_wallet`,`tb_card_wallet_transaction` → `tb_asset_wallet_transaction`,`tb_card_recharge_record` → `tb_asset_recharge_record`(三张表在同一个迁移文件中完成)
|
||||
- [x] 1.2 创建迁移文件:`tb_asset_wallet_transaction.reference_id (bigint, nullable)` → `reference_no (varchar 50, nullable)`(ALTER TABLE RENAME COLUMN + ALTER COLUMN TYPE)
|
||||
- [x] 1.3 执行全部迁移,使用 PostgreSQL MCP 确认三张表改名成功,`reference_no` 字段类型为 varchar(50)
|
||||
|
||||
## 2. Model 层全量重命名
|
||||
|
||||
- [x] 2.1 重命名 `internal/model/card_wallet.go` → `internal/model/asset_wallet.go`,文件内所有类型改名:
|
||||
- `CardWallet` → `AssetWallet`,`TableName()` 返回 `"tb_asset_wallet"`
|
||||
- `CardWalletTransaction` → `AssetWalletTransaction`,`TableName()` 返回 `"tb_asset_wallet_transaction"`
|
||||
- `CardRechargeRecord` → `AssetRechargeRecord`,`TableName()` 返回 `"tb_asset_recharge_record"`
|
||||
- [x] 2.2 更新 `AssetWalletTransaction` 结构体字段:`CardWalletID uint json:"card_wallet_id"` → `AssetWalletID uint json:"asset_wallet_id"`(GORM column tag 同步更新为 `column:asset_wallet_id`);`ReferenceID *uint json:"reference_id,omitempty"` → `ReferenceNo *string json:"reference_no,omitempty"`(GORM column tag 改为 `column:reference_no;type:varchar(50)`)
|
||||
- [x] 2.3 更新 `AssetRechargeRecord` 结构体字段:`CardWalletID uint json:"card_wallet_id"` → `AssetWalletID uint json:"asset_wallet_id"`(GORM column tag 同步更新)
|
||||
- [x] 2.4 运行 `go build ./...` 确认 Model 层无编译错误
|
||||
|
||||
## 3. Store 层全量重命名
|
||||
|
||||
- [x] 3.1 重命名 `internal/store/postgres/card_wallet_store.go` → `asset_wallet_store.go`,类型 `CardWalletStore` → `AssetWalletStore`,构造函数 `NewCardWalletStore` → `NewAssetWalletStore`,方法内 `model.CardWallet` → `model.AssetWallet`
|
||||
- [x] 3.2 重命名 `internal/store/postgres/card_wallet_transaction_store.go` → `asset_wallet_transaction_store.go`,类型 `CardWalletTransactionStore` → `AssetWalletTransactionStore`,构造函数及方法内 Model 引用同步更新
|
||||
- [x] 3.3 重命名 `internal/store/postgres/card_recharge_store.go` → `asset_recharge_store.go`,类型 `CardRechargeStore` → `AssetRechargeStore`,构造函数及方法内 Model 引用同步更新
|
||||
- [x] 3.4 运行 `go build ./...` 确认 Store 层无编译错误
|
||||
|
||||
## 4. Bootstrap 层更新
|
||||
|
||||
- [x] 4.1 更新 `internal/bootstrap/stores.go`:字段名 `CardWallet` → `AssetWallet`,`CardWalletTransaction` → `AssetWalletTransaction`,`CardRecharge` → `AssetRecharge`;构造函数调用同步更新为 `NewAssetWalletStore`、`NewAssetWalletTransactionStore`、`NewAssetRechargeStore`
|
||||
- [x] 4.2 更新 `internal/bootstrap/services.go`:依赖注入中所有 `s.CardWallet*` 引用改为 `s.AssetWallet*`、`s.CardRecharge` 改为 `s.AssetRecharge`
|
||||
- [x] 4.3 运行 `go build ./...` 确认 bootstrap 层无编译错误
|
||||
|
||||
## 5. 常量层更新
|
||||
|
||||
- [x] 5.1 更新 `pkg/constants/redis.go`:`RedisCardWalletBalanceKey` → `RedisAssetWalletBalanceKey`,函数体不变,仅函数名改变
|
||||
- [x] 5.2 全局搜索 `RedisCardWalletBalanceKey` 调用处(card_wallet_store.go),替换为 `RedisAssetWalletBalanceKey`
|
||||
|
||||
## 6. Service 层适配:order service
|
||||
|
||||
- [x] 6.1 更新 `internal/service/order/service.go`:结构体字段 `cardWalletStore *postgres.CardWalletStore` → `assetWalletStore *postgres.AssetWalletStore`,构造函数参数及所有调用点同步更新
|
||||
- [x] 6.2 在 `WalletPay` 卡钱包支付路径(`resourceType != "shop"` 分支)中,扣款成功后在同一事务内补写 `AssetWalletTransaction` 扣款流水:
|
||||
- 在事务内扣款前记录 `balanceBefore = wallet.Balance`
|
||||
- 扣款成功(`RowsAffected == 1`)后,`INSERT` 一条 `AssetWalletTransaction`:`AssetWalletID=wallet.ID`、`ResourceType=resourceType`、`ResourceID=resourceID`、`UserID=buyerID`、`TransactionType="deduct"`、`Amount=-order.TotalAmount`、`BalanceBefore=balanceBefore`、`BalanceAfter=balanceBefore-order.TotalAmount`、`Status=1`、`ReferenceType=strPtr("order")`、`ReferenceNo=&order.OrderNo`、`Remark=strPtr("钱包支付套餐")`、`ShopIDTag=wallet.ShopIDTag`、`EnterpriseIDTag=wallet.EnterpriseIDTag`
|
||||
- [x] 6.3 运行 `go build ./...` 确认 order service 无编译错误
|
||||
|
||||
## 7. Service 层适配:recharge service
|
||||
|
||||
- [x] 7.1 更新 `internal/service/recharge/service.go`:结构体字段及构造函数 `cardWalletStore` → `assetWalletStore`,`cardWalletTransactionStore` → `assetWalletTransactionStore`;所有 Model 引用 `model.CardWallet*` → `model.AssetWallet*`
|
||||
- [x] 7.2 更新充值回调写入流水记录处(约第 320 行):`ReferenceID: &recharge.ID` → `ReferenceNo: &recharge.RechargeNo`(同时删除原 `ReferenceID` 字段赋值)
|
||||
- [x] 7.3 运行 `go build ./...` 确认 recharge service 无编译错误
|
||||
|
||||
## 8. DTO 新增
|
||||
|
||||
- [x] 8.1 新建 `internal/model/dto/asset_wallet_dto.go`,定义以下 DTO(含所有字段及 `description` tag):
|
||||
|
||||
**AssetWalletResponse**(钱包概况响应):
|
||||
- `wallet_id uint`、`resource_type string`、`resource_id uint`
|
||||
- `balance int64`、`frozen_balance int64`、`available_balance int64`
|
||||
- `currency string`、`status int`、`status_text string`
|
||||
- `created_at time.Time`、`updated_at time.Time`
|
||||
|
||||
**AssetWalletTransactionListRequest**(流水列表请求,查询参数):
|
||||
- `page int`(默认 1)、`page_size int`(默认 20,最大 100)
|
||||
- `transaction_type *string`(可选,oneof=recharge deduct refund)
|
||||
- `start_time *time.Time`(可选)、`end_time *time.Time`(可选)
|
||||
|
||||
**AssetWalletTransactionItem**(单条流水):
|
||||
- `id uint`
|
||||
- `transaction_type string`、`transaction_type_text string`
|
||||
- `amount int64`、`balance_before int64`、`balance_after int64`
|
||||
- `reference_type *string`、`reference_no *string`
|
||||
- `remark *string`
|
||||
- `created_at time.Time`
|
||||
|
||||
**AssetWalletTransactionListResponse**(流水列表响应):
|
||||
- `list []*AssetWalletTransactionItem`
|
||||
- `total int64`、`page int`、`page_size int`、`total_pages int`
|
||||
|
||||
- [x] 8.2 运行 `lsp_diagnostics` 确认 DTO 无错误
|
||||
|
||||
## 9. AssetWalletService 新增
|
||||
|
||||
- [x] 9.1 新建 `internal/service/asset_wallet/service.go`,定义 `Service` 结构体,依赖注入:`AssetWalletStore`、`AssetWalletTransactionStore`
|
||||
- [x] 9.2 实现 `GetWallet(ctx, assetType string, assetID uint) (*dto.AssetWalletResponse, error)`:
|
||||
- 将 `assetType`(`card`/`device`)映射到 `resourceType`(`iot_card`/`device`)
|
||||
- 调用 `AssetWalletStore.GetByResourceTypeAndID(ctx, resourceType, assetID)`
|
||||
- 组装 `AssetWalletResponse`(计算 `available_balance = balance - frozen_balance`,翻译 `status_text`)
|
||||
- 钱包不存在时返回 `errors.New(errors.CodeNotFound, "该资产暂无钱包记录")`
|
||||
- [x] 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_text`(recharge→充值 / deduct→扣款 / refund→退款),计算 `total_pages`
|
||||
- 如有 `transaction_type` 过滤参数,在 Store 层新增对应过滤方法(或在 Service 层 in-memory 过滤——推荐 Store 层)
|
||||
- [x] 9.4 运行 `lsp_diagnostics` 确认 Service 无错误
|
||||
|
||||
## 10. Store 层新增查询方法
|
||||
|
||||
- [x] 10.1 在 `AssetWalletTransactionStore` 中新增 `ListByResourceIDWithFilter(ctx, resourceType string, resourceID uint, transactionType *string, startTime, endTime *time.Time, offset, limit int) ([]*model.AssetWalletTransaction, error)` 方法,支持 `transaction_type`、时间范围过滤,应用 `ApplyShopTagFilter` 数据权限
|
||||
- [x] 10.2 在 `AssetWalletTransactionStore` 中新增 `CountByResourceIDWithFilter(ctx, resourceType string, resourceID uint, transactionType *string, startTime, endTime *time.Time) (int64, error)` 方法
|
||||
- [x] 10.3 运行 `lsp_diagnostics` 确认 Store 无错误
|
||||
|
||||
## 11. AssetWalletHandler 新增
|
||||
|
||||
- [x] 11.1 新建 `internal/handler/admin/asset_wallet.go`,定义 `AssetWalletHandler` 结构体(依赖 `*assetWalletSvc.Service`),实现两个 Handler 方法:
|
||||
|
||||
**GetWallet**(`GET /api/admin/assets/:asset_type/:id/wallet`):
|
||||
- 检查企业账号:`user_type == UserTypeEnterprise` → 返回 403
|
||||
- 解析路径参数 `asset_type`(校验为 `card` 或 `device`)和 `id`(校验为正整数)
|
||||
- 调用 `assetWalletSvc.GetWallet(ctx, assetType, id)` → 返回 `response.Success`
|
||||
|
||||
**ListTransactions**(`GET /api/admin/assets/:asset_type/:id/wallet/transactions`):
|
||||
- 检查企业账号:同上
|
||||
- 解析路径参数和查询参数(`QueryParser` 绑定 `AssetWalletTransactionListRequest`)
|
||||
- 参数验证:`page_size` 最大 100,`transaction_type` 需为合法枚举值
|
||||
- 调用 `assetWalletSvc.ListTransactions(ctx, assetType, id, &req)` → 返回 `response.Success`
|
||||
|
||||
- [x] 11.2 运行 `lsp_diagnostics` 确认 Handler 无编译错误
|
||||
|
||||
## 12. 路由注册
|
||||
|
||||
- [x] 12.1 在 `internal/routes/asset.go` 的 `registerAssetRoutes` 函数末尾追加两条路由(需传入 `*admin.AssetWalletHandler` 参数):
|
||||
|
||||
```go
|
||||
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,
|
||||
})
|
||||
```
|
||||
|
||||
- [x] 12.2 更新 `registerAssetRoutes` 函数签名,增加 `walletHandler *admin.AssetWalletHandler` 参数
|
||||
- [x] 12.3 更新 `internal/routes/routes.go` 中 `registerAssetRoutes` 的调用处,传入 `AssetWalletHandler`
|
||||
|
||||
## 13. Bootstrap 层注册新 Handler/Service
|
||||
|
||||
- [x] 13.1 更新 `internal/bootstrap/types.go`:`Handlers` 结构体新增 `AssetWallet *admin.AssetWalletHandler`;`Services` 结构体新增 `AssetWallet *assetWalletSvc.Service`(如需独立 service 包则导入)
|
||||
- [x] 13.2 更新 `internal/bootstrap/services.go`:实例化 `assetWalletSvc.New(s.AssetWallet, s.AssetWalletTransaction)`
|
||||
- [x] 13.3 更新 `internal/bootstrap/handlers.go`:实例化 `admin.NewAssetWalletHandler(svcs.AssetWallet)`
|
||||
- [x] 13.4 更新 `cmd/api/docs.go` 和 `cmd/gendocs/main.go`:`handlers.AssetWallet = admin.NewAssetWalletHandler(nil)`(文档生成器注册)
|
||||
- [x] 13.5 运行 `go build ./...` 全量确认无编译错误
|
||||
|
||||
## 14. 文档和最终验收
|
||||
|
||||
- [x] 14.1 运行 `go run cmd/gendocs/main.go` 确认两个新接口(资产钱包概况、资产钱包流水列表)出现在 OpenAPI 文档中
|
||||
- [x] 14.2 使用 PostgreSQL MCP 验证三张表改名成功:`tb_asset_wallet`、`tb_asset_wallet_transaction`(含 `reference_no varchar(50)` 字段)、`tb_asset_recharge_record`
|
||||
- [x] 14.3 使用 PostgreSQL MCP 或 curl 验证:H5 充值接口 `GET /api/h5/wallets/recharges/:id` 响应中 `wallet_id` 字段仍正常返回
|
||||
- [x] 14.4 运行 `go build ./...` 全量确认无编译错误
|
||||
- [x] 14.5 tasks.md 全部任务标记完成
|
||||
Reference in New Issue
Block a user