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>
9.3 KiB
9.3 KiB
1. DTO 层变更
- 1.1 新增
ShopFundSummaryItem(含main_balance、main_frozen_balance及原有佣金字段),新增ShopFundSummaryListReq、ShopFundSummaryPageResult;删除旧的ShopCommissionSummaryItem/ShopCommissionSummaryListReq/ShopCommissionSummaryPageResult - 1.2 新增主钱包流水 DTO:
MainWalletTransactionItem、MainWalletTransactionListRequest、MainWalletTransactionListResponse - 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 层变更
- 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的防御式过滤 - 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 统计
- 2.3 删除
AgentWalletTransactionStore.ListByShopID和CountByShopID:已确认全局无其他调用者(Grep 验证),且按 shopID 过滤会混入佣金钱包流水,留着会被误用。删除前再次grep -rn "ListByShopID\|CountByShopID" --include="*.go"确认
3. Service 层变更(ShopCommissionService 扩展)
- 3.0 更新
ShopCommissionService.New()构造函数,在现有参数基础上新增两个依赖:commissionWithdrawalSettingStore *postgres.CommissionWithdrawalSettingStore(task 3.4 迁移CreateWithdrawalRequest时校验最低提现金额和每日次数上限)agentWalletTransactionStore *postgres.AgentWalletTransactionStore(task 3.5 新增ListMainWalletTransactions使用)
- 3.1 将
ListShopCommissionSummary改造为ListShopFundSummary:删除原方法,方法签名/返回类型切换至ShopFundSummaryListReq/ShopFundSummaryPageResult;调用GetShopMainWalletBatch批量拉取主钱包余额,合并到ShopFundSummaryItem中;主钱包不存在时main_balance/main_frozen_balance返回 0 - 3.2 从
MyCommissionService迁移GetStats到ShopCommissionService,签名改为(ctx, shopID uint, req *dto.CommissionStatsRequest);方法入口第一行调用middleware.CanManageShop(ctx, shopID),失败直接返回 - 3.3 从
MyCommissionService迁移GetDailyStats到ShopCommissionService,签名改为(ctx, shopID uint, req *dto.DailyCommissionStatsRequest);同样入口加CanManageShop - 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 >= ?")并发保护
- 必须
- 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(已删除)
- 入口第一行调用
- 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)
- 4.1 全局 grep 确认
MyCommissionService/myCommissionService/my_commission的所有引用(Handler、bootstrap、routes、cmd) - 4.2 删除
internal/service/my_commission/service.go及整个my_commission目录
5. Handler 层变更(ShopCommissionHandler 扩展)
- 5.1 将
ListCommissionSummary改造为ListFundSummary(重命名+切换 DTO 类型),调用ShopCommissionService.ListShopFundSummary。方法只在 Handler 层做参数解析,不写权限逻辑 - 5.2 新增
GetCommissionStats方法,从路径参数取shop_id,调用迁移后的GetStats(权限校验在 Service 层) - 5.3 新增
GetCommissionDailyStats方法,从路径参数取shop_id,调用迁移后的GetDailyStats - 5.4 新增
CreateWithdrawal方法,从路径参数取shop_id,调用迁移后的CreateWithdrawalRequest - 5.5 新增
ListMainWalletTransactions方法,从路径参数取shop_id,调用ShopCommissionService.ListMainWalletTransactions - 5.6 Handler 注释同步更新(HTTP 方法和路径),遵循 comment-standards
6. Handler 层删除(MyCommissionHandler)
- 6.1 删除
internal/handler/admin/my_commission.go
7. 路由层变更
- 7.1 在
registerShopCommissionRoutes中:将GET /commission-summary改为GET /fund-summary,更新 Summary 为 "代理商资金概况",更新 Tags、Input(ShopFundSummaryListReq)、Output(ShopFundSummaryPageResult) - 7.2 在
registerShopCommissionRoutes中新增四条路由:GET /:shop_id/main-wallet/transactions→ListMainWalletTransactionsGET /:shop_id/commission-stats→GetCommissionStatsGET /:shop_id/commission-daily-stats→GetCommissionDailyStatsPOST /:shop_id/withdrawal-requests→CreateWithdrawal
- 7.3 删除
internal/routes/my_commission.go - 7.4 在路由注册入口(
internal/routes/admin.go或 registry)中移除registerMyCommissionRoutes的调用
8. Bootstrap 变更
- 8.1 在
internal/bootstrap/types.go的Handlers结构体中:删除MyCommissionHandler字段,确认ShopCommissionHandler字段存在 - 8.2 在
internal/bootstrap/services.go中:删除myCommissionService的初始化,移除对my_commission包的引用;更新shopCommissionService的初始化,补充 task 3.0 新增的两个依赖(stores.CommissionWithdrawalSetting、stores.AgentWalletTransaction) - 8.3 在
internal/bootstrap/handlers.go中删除MyCommissionHandler的初始化
9. 文档生成器更新
- 9.1 在
cmd/api/docs.go中:删除NewMyCommissionHandler(nil)相关行,确认ShopCommissionHandler已包含新方法 - 9.2 在
cmd/gendocs/main.go中做同样清理
10. 编译与验证
- 10.1 执行
go build ./...,确保无编译错误 - 10.2
grep -rn "MyCommission\|my_commission\|ListByShopID\|CountByShopID\|ShopCommissionSummary" --include="*.go"确认无残留引用 - 10.3 使用 PostgreSQL MCP 验证
GET /shops/fund-summary返回的main_balance与tb_agent_wallet中对应记录一致(shop_id=1: balance=50000, shop_id=9: balance=20000,主钱包批量查询逻辑正确) - 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"仅代理商用户可发起提现"
- 代理账号 A 请求
- 10.6 验证原
/my/commission-stats、/my/commission-daily-stats、POST /my/withdrawal-requests迁移后数据返回与迁移前等价(相同 shopID 相同查询条件,结果一致)