All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m10s
- 将 GET /shops/commission-summary 重命名为 GET /shops/fund-summary, 响应新增 main_balance、main_frozen_balance 两个预充值钱包字段 - 新增 GET /shops/:id/main-wallet/transactions 预充值钱包流水接口 - 将佣金统计、每日统计、发起提现从 /my/ 路径迁移至 /shops/:id/ 路径: GET /shops/:id/commission-stats GET /shops/:id/commission-daily-stats POST /shops/:id/withdrawal-requests - 删除 MyCommissionService、MyCommissionHandler 及全部 /my/ 路由 - 补齐 ListShopWithdrawalRequests、ListShopCommissionRecords 的 CanManageShop 越权校验(安全修复) - 提现接口增加严格权限:仅代理账号本人可为自己店铺发起提现 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
91 lines
9.3 KiB
Markdown
91 lines
9.3 KiB
Markdown
## 1. DTO 层变更
|
||
|
||
- [x] 1.1 新增 `ShopFundSummaryItem`(含 `main_balance`、`main_frozen_balance` 及原有佣金字段),新增 `ShopFundSummaryListReq`、`ShopFundSummaryPageResult`;删除旧的 `ShopCommissionSummaryItem` / `ShopCommissionSummaryListReq` / `ShopCommissionSummaryPageResult`
|
||
- [x] 1.2 新增主钱包流水 DTO:`MainWalletTransactionItem`、`MainWalletTransactionListRequest`、`MainWalletTransactionListResponse`
|
||
- [x] 1.3 删除废弃 DTO:`MyCommissionSummaryResp`、`MyWithdrawalListReq`、`MyCommissionRecordListReq`、`MyCommissionRecordItem`、`MyCommissionRecordPageResult`(确认无其他引用后删除)
|
||
- **保留**:`CommissionStatsRequest`、`DailyCommissionStatsRequest` / `CommissionStatsResponse` / `DailyCommissionStatsResponse` — 迁移后的 `/shops/:id/commission-stats` 和 `/shops/:id/commission-daily-stats` 继续复用
|
||
- **保留**:`CreateMyWithdrawalReq`、`CreateMyWithdrawalResp` — 迁移后的 `POST /shops/:id/withdrawal-requests` 继续复用
|
||
|
||
## 2. Store 层变更
|
||
|
||
- [x] 2.1 在 `AgentWalletStore` 新增 `GetShopMainWalletBatch(ctx context.Context, shopIDs []uint) (map[uint]*model.AgentWallet, error)` 方法:`WHERE shop_id IN (?) AND wallet_type = 'main'` 单次查询,内部调用 `middleware.ApplyShopFilter` 对齐现有 `GetShopCommissionSummaryBatch` 的防御式过滤
|
||
- [x] 2.2 在 `AgentWalletTransactionStore` 新增过滤结构体 `AgentWalletTransactionListFilters`(字段:`TransactionType string`、`StartDate string`、`EndDate string`),以及以下两个方法:
|
||
- `ListByWalletIDWithFilters(ctx, walletID uint, opts *store.QueryOptions, filters *AgentWalletTransactionListFilters) ([]*model.AgentWalletTransaction, error)`:在 `WHERE agent_wallet_id = ?` 基础上叠加 transaction_type / 日期过滤,按 `created_at DESC` 排序
|
||
- `CountByWalletID(ctx, walletID uint, filters *AgentWalletTransactionListFilters) (int64, error)`:与列表方法过滤条件一致,用于分页 total 统计
|
||
- [x] 2.3 删除 `AgentWalletTransactionStore.ListByShopID` 和 `CountByShopID`:已确认全局无其他调用者(Grep 验证),且按 shopID 过滤会混入佣金钱包流水,留着会被误用。删除前再次 `grep -rn "ListByShopID\|CountByShopID" --include="*.go"` 确认
|
||
|
||
## 3. Service 层变更(ShopCommissionService 扩展)
|
||
|
||
- [x] 3.0 更新 `ShopCommissionService.New()` 构造函数,在现有参数基础上新增两个依赖:
|
||
- `commissionWithdrawalSettingStore *postgres.CommissionWithdrawalSettingStore`(task 3.4 迁移 `CreateWithdrawalRequest` 时校验最低提现金额和每日次数上限)
|
||
- `agentWalletTransactionStore *postgres.AgentWalletTransactionStore`(task 3.5 新增 `ListMainWalletTransactions` 使用)
|
||
- [x] 3.1 将 `ListShopCommissionSummary` 改造为 `ListShopFundSummary`:删除原方法,方法签名/返回类型切换至 `ShopFundSummaryListReq` / `ShopFundSummaryPageResult`;调用 `GetShopMainWalletBatch` 批量拉取主钱包余额,合并到 `ShopFundSummaryItem` 中;主钱包不存在时 `main_balance` / `main_frozen_balance` 返回 0
|
||
- [x] 3.2 从 `MyCommissionService` 迁移 `GetStats` 到 `ShopCommissionService`,签名改为 `(ctx, shopID uint, req *dto.CommissionStatsRequest)`;**方法入口第一行**调用 `middleware.CanManageShop(ctx, shopID)`,失败直接返回
|
||
- [x] 3.3 从 `MyCommissionService` 迁移 `GetDailyStats` 到 `ShopCommissionService`,签名改为 `(ctx, shopID uint, req *dto.DailyCommissionStatsRequest)`;同样入口加 `CanManageShop`
|
||
- [x] 3.4 从 `MyCommissionService` 迁移 `CreateWithdrawalRequest` 到 `ShopCommissionService`,签名改为 `(ctx, shopID uint, req *dto.CreateMyWithdrawalReq)`;**入口权限校验严于其他方法**:
|
||
- 必须 `middleware.GetUserTypeFromContext(ctx) == constants.UserTypeAgent`,否则返回 403"仅代理商用户可发起提现"
|
||
- 必须 `shopID == middleware.GetShopIDFromContext(ctx)`,否则返回 403"仅可为本人店铺发起提现"
|
||
- **不使用 `CanManageShop`**(默认会放行整个下级层级,业务上不允许顶级代理替下级提现)
|
||
- 保留原有的条件更新 `Where("id = ? AND balance - frozen_balance >= ?")` 并发保护
|
||
- [x] 3.5 在 `ShopCommissionService` 新增 `ListMainWalletTransactions(ctx, shopID uint, req *dto.MainWalletTransactionListRequest)` 方法:
|
||
- **入口第一行**调用 `middleware.CanManageShop(ctx, shopID)`
|
||
- 通过 `AgentWalletStore.GetMainWallet(ctx, shopID)` 获取主钱包;不存在则返回空列表(`total=0`)不报错
|
||
- 调用 `ListByWalletIDWithFilters` / `CountByWalletID`(task 2.2 新增)查询流水
|
||
- **不得**使用 `ListByShopID`(已删除)
|
||
- [x] 3.6 **补齐已有方法的越权校验**(回归漏洞修复):
|
||
- `ListShopWithdrawalRequests`:方法入口加 `middleware.CanManageShop(ctx, shopID)`
|
||
- `ListShopCommissionRecords`:方法入口加 `middleware.CanManageShop(ctx, shopID)`
|
||
- 理由:`/my/withdrawal-requests` 和 `/my/commission-records` 废弃后代理改用 `/shops/:shop_id/...`,若不补校验,代理只要猜到其他 shopID 就能读取他人佣金明细和提现记录
|
||
|
||
## 4. Service 层删除(MyCommissionService)
|
||
|
||
- [x] 4.1 全局 grep 确认 `MyCommissionService` / `myCommissionService` / `my_commission` 的所有引用(Handler、bootstrap、routes、cmd)
|
||
- [x] 4.2 删除 `internal/service/my_commission/service.go` 及整个 `my_commission` 目录
|
||
|
||
## 5. Handler 层变更(ShopCommissionHandler 扩展)
|
||
|
||
- [x] 5.1 将 `ListCommissionSummary` 改造为 `ListFundSummary`(重命名+切换 DTO 类型),调用 `ShopCommissionService.ListShopFundSummary`。方法只在 Handler 层做参数解析,不写权限逻辑
|
||
- [x] 5.2 新增 `GetCommissionStats` 方法,从路径参数取 `shop_id`,调用迁移后的 `GetStats`(权限校验在 Service 层)
|
||
- [x] 5.3 新增 `GetCommissionDailyStats` 方法,从路径参数取 `shop_id`,调用迁移后的 `GetDailyStats`
|
||
- [x] 5.4 新增 `CreateWithdrawal` 方法,从路径参数取 `shop_id`,调用迁移后的 `CreateWithdrawalRequest`
|
||
- [x] 5.5 新增 `ListMainWalletTransactions` 方法,从路径参数取 `shop_id`,调用 `ShopCommissionService.ListMainWalletTransactions`
|
||
- [x] 5.6 Handler 注释同步更新(HTTP 方法和路径),遵循 comment-standards
|
||
|
||
## 6. Handler 层删除(MyCommissionHandler)
|
||
|
||
- [x] 6.1 删除 `internal/handler/admin/my_commission.go`
|
||
|
||
## 7. 路由层变更
|
||
|
||
- [x] 7.1 在 `registerShopCommissionRoutes` 中:将 `GET /commission-summary` 改为 `GET /fund-summary`,更新 Summary 为 "代理商资金概况",更新 Tags、Input(`ShopFundSummaryListReq`)、Output(`ShopFundSummaryPageResult`)
|
||
- [x] 7.2 在 `registerShopCommissionRoutes` 中新增四条路由:
|
||
- `GET /:shop_id/main-wallet/transactions` → `ListMainWalletTransactions`
|
||
- `GET /:shop_id/commission-stats` → `GetCommissionStats`
|
||
- `GET /:shop_id/commission-daily-stats` → `GetCommissionDailyStats`
|
||
- `POST /:shop_id/withdrawal-requests` → `CreateWithdrawal`
|
||
- [x] 7.3 删除 `internal/routes/my_commission.go`
|
||
- [x] 7.4 在路由注册入口(`internal/routes/admin.go` 或 registry)中移除 `registerMyCommissionRoutes` 的调用
|
||
|
||
## 8. Bootstrap 变更
|
||
|
||
- [x] 8.1 在 `internal/bootstrap/types.go` 的 `Handlers` 结构体中:删除 `MyCommissionHandler` 字段,确认 `ShopCommissionHandler` 字段存在
|
||
- [x] 8.2 在 `internal/bootstrap/services.go` 中:删除 `myCommissionService` 的初始化,移除对 `my_commission` 包的引用;更新 `shopCommissionService` 的初始化,补充 task 3.0 新增的两个依赖(`stores.CommissionWithdrawalSetting`、`stores.AgentWalletTransaction`)
|
||
- [x] 8.3 在 `internal/bootstrap/handlers.go` 中删除 `MyCommissionHandler` 的初始化
|
||
|
||
## 9. 文档生成器更新
|
||
|
||
- [x] 9.1 在 `cmd/api/docs.go` 中:删除 `NewMyCommissionHandler(nil)` 相关行,确认 `ShopCommissionHandler` 已包含新方法
|
||
- [x] 9.2 在 `cmd/gendocs/main.go` 中做同样清理
|
||
|
||
## 10. 编译与验证
|
||
|
||
- [x] 10.1 执行 `go build ./...`,确保无编译错误
|
||
- [x] 10.2 `grep -rn "MyCommission\|my_commission\|ListByShopID\|CountByShopID\|ShopCommissionSummary" --include="*.go"` 确认无残留引用
|
||
- [x] 10.3 使用 PostgreSQL MCP 验证 `GET /shops/fund-summary` 返回的 `main_balance` 与 `tb_agent_wallet` 中对应记录一致(shop_id=1: balance=50000, shop_id=9: balance=20000,主钱包批量查询逻辑正确)
|
||
- [x] 10.4 使用 PostgreSQL MCP 验证 `GET /shops/:id/main-wallet/transactions` 返回的流水与 `tb_agent_wallet_transaction` 中 `wallet_type=main` 钱包 ID 的记录一致(wallet_id=1 有3条记录,wallet_id=17 有2条记录,通过 agent_wallet_id 关联正确)
|
||
- [ ] 10.5 手动验证代理越权:
|
||
- 代理账号 A 请求 `/shops/{B的shop_id}/commission-records` / `/commission-stats` / `/commission-daily-stats` / `/withdrawal-requests` / `/main-wallet/transactions`(B 不是 A 的下级)应全部返回 403
|
||
- 顶级代理 P 请求 `POST /shops/{下级shop_id}/withdrawal-requests` 应返回 403"仅可为本人店铺发起提现"(验证比 `CanManageShop` 更严格的限制)
|
||
- 平台账号请求 `POST /shops/:shop_id/withdrawal-requests` 应返回 403"仅代理商用户可发起提现"
|
||
- [ ] 10.6 验证原 `/my/commission-stats`、`/my/commission-daily-stats`、`POST /my/withdrawal-requests` 迁移后数据返回与迁移前等价(相同 shopID 相同查询条件,结果一致)
|