All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m0s
新增功能: - 代理在后台使用 wallet 支付时,订单直接完成(扣款 + 激活套餐) - 支持代理自购和代理代购场景 - 新增订单角色追踪字段(operator_id、operator_type、actual_paid_amount、purchase_role) - 订单查询支持 OR 逻辑(buyer_id 或 operator_id) - 钱包流水记录交易子类型和关联店铺 - 佣金逻辑调整:代理代购不产生佣金 数据库变更: - 订单表新增 4 个字段和 2 个索引 - 钱包流水表新增 2 个字段 - 包含迁移脚本和回滚脚本 文档: - 功能总结文档 - 部署指南 - OpenAPI 文档更新 - Specs 同步(新增 agent-order-role-tracking capability) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
13 KiB
13 KiB
1. 数据库结构变更
- 1.1 创建订单表字段迁移脚本(
migrations/xxx_add_operator_fields_to_orders.up.sql),新增operator_id、operator_type、actual_paid_amount、purchase_role字段,添加字段注释 - 1.2 在迁移脚本中创建索引(
idx_orders_operator_id、idx_orders_purchase_role),使用 CONCURRENTLY 避免锁表 - 1.3 创建钱包流水表字段迁移脚本(
migrations/xxx_add_transaction_subtype_to_wallet_transaction.up.sql),检查并添加transaction_subtype和related_shop_id字段(如果不存在) - 1.4 创建数据回滚迁移脚本(
*.down.sql),包含 DROP INDEX 和 DROP COLUMN 语句 - 1.5 在测试环境执行迁移,验证字段创建成功,检查
\d tb_order和\d tb_agent_wallet_transaction输出
2. Model 层:订单角色追踪
- 2.1 在
internal/model/order.go中的Order结构体添加新字段:OperatorID、OperatorType、ActualPaidAmount、PurchaseRole,添加 gorm 标签和中文注释 - 2.2 在
internal/model/order.go中定义订单角色枚举常量(PurchaseRoleSelfPurchase、PurchaseRolePurchasedByParent、PurchaseRolePurchasedByPlatform、PurchaseRolePurchaseForSubordinate),添加中文注释 - 2.3 在
internal/model/agent_wallet.go中确认AgentWalletTransaction结构体包含TransactionSubtype和RelatedShopID字段(如果不存在则添加) - 2.4 运行
go build ./...验证编译通过
3. 常量定义:钱包流水子类型
- 3.1 在
pkg/constants/wallet.go中新增钱包交易子类型常量(WalletTransactionSubtypeSelfPurchase、WalletTransactionSubtypePurchaseForSubordinate),添加中文注释 - 3.2 运行
go build ./...验证编译通过
4. DTO 层:订单请求和响应
- 4.1 在
internal/model/dto/order_dto.go的OrderResponse中添加新字段:OperatorID、OperatorType、OperatorName、ActualPaidAmount、PurchaseRole、IsPurchasedByParent、PurchaseRemark,添加 JSON 标签和 description 注释 - 4.2 在
internal/model/dto/order_dto.go的OrderListRequest中添加PurchaseRole筛选字段,添加验证标签(validate:"omitempty,oneof=self_purchase purchased_by_parent purchased_by_platform purchase_for_subordinate") - 4.3 运行
go build ./...验证编译通过
5. Store 层:订单查询 OR 逻辑
- 5.1 修改
internal/store/postgres/order_store.go的List()方法,支持shop_id筛选时使用 OR 查询:WHERE (buyer_type = 'agent' AND buyer_id = ?) OR operator_id = ? - 5.2 在
List()方法中添加purchase_role精确匹配筛选支持 - 5.3 运行
go build ./...验证编译通过 - 5.4 使用 PostgreSQL MCP 工具验证查询逻辑:创建测试订单,执行
SELECT * FROM tb_order WHERE (buyer_id = X) OR (operator_id = X)并检查 EXPLAIN 输出
6. Service 层:成本价查询辅助方法
- 6.1 在
internal/service/order/service.go中新增getCostPrice(ctx, shopID, packageID)方法,通过ShopPackageAllocation查询店铺对套餐的成本价 - 6.2 添加错误处理:如果查询失败,返回
errors.New(errors.CodeInvalidParam, "店铺没有该套餐的分配配置") - 6.3 运行
go build ./...验证编译通过
7. Service 层:钱包流水创建方法
- 7.1 在
internal/service/order/service.go中新增createWalletTransaction(ctx, tx, walletID, orderID, amount, purchaseRole, relatedShopID)方法 - 7.2 在方法中根据
purchaseRole确定transaction_subtype和remark:自购场景填充"购买套餐",代购场景查询下级店铺名称填充"为下级代理【XX】购买套餐" - 7.3 创建
AgentWalletTransaction记录,设置TransactionType=AgentTransactionTypeDeduct,TransactionSubtype、Amount(负数)、RelatedShopID、Remark - 7.4 运行
go build ./...验证编译通过
8. Service 层:钱包支付订单创建方法
- 8.1 在
internal/service/order/service.go中新增createOrderWithWalletPayment(ctx, order, items, operatorShopID, buyerShopID)方法 - 8.2 在方法开头(事务外)检查钱包余额,如果余额不足返回错误
- 8.3 开启 GORM 事务,在事务中依次执行:创建订单(
tx.Create(order))、创建订单明细(tx.CreateInBatches(items, 100)) - 8.4 在事务中扣减钱包余额,使用乐观锁:
WHERE id = ? AND balance >= ? AND version = ?,更新balance = balance - ?和version = version + 1 - 8.5 检查
RowsAffected,如果为 0 返回errors.New(errors.CodeInsufficientBalance, "余额不足或并发冲突") - 8.6 在事务中调用
createWalletTransaction()创建钱包流水 - 8.7 在事务中调用
activatePackage()激活套餐 - 8.8 事务外判断是否入队佣金计算:
if order.OperatorID == nil { s.enqueueCommissionCalculation() }(平台代购才入队) - 8.9 运行
go build ./...验证编译通过
9. Service 层:订单创建流程重构
- 9.1 在
internal/service/order/service.go的Create()方法中,在幂等性检查后添加场景判断逻辑 - 9.2 提取资源所属店铺 ID(从
validationResult.Card.ShopID或validationResult.Device.ShopID) - 9.3 处理
offline场景:设置operator_id = nil、operator_type = "platform"、purchase_role = "purchased_by_platform",调用resolvePurchaseOnBehalfInfo()获取买家成本价,保持现有逻辑调用createOrderWithActivation() - 9.4 处理
wallet场景:获取操作者店铺 ID,判断资源是否属于操作者 - 9.5 如果资源属于操作者(自购):设置
buyer = operator、purchase_role = "self_purchase"、is_purchase_on_behalf = false,调用getCostPrice()获取成本价,total_amount = actual_paid_amount = 操作者成本价 - 9.6 如果资源不属于操作者(代购):设置
buyer = 资源所属者、operator = 操作者、purchase_role = "purchase_for_subordinate"、is_purchase_on_behalf = true,分别调用getCostPrice()获取买家和操作者成本价,total_amount = 买家成本价、actual_paid_amount = 操作者成本价 - 9.7
wallet场景调用createOrderWithWalletPayment()而不是orderStore.Create() - 9.8 运行
go build ./...验证编译通过
10. Service 层:订单响应构建方法
- 10.1 在
internal/service/order/service.go的buildOrderResponse()方法中添加新字段映射:OperatorID、OperatorType、ActualPaidAmount、PurchaseRole - 10.2 添加
OperatorName字段逻辑:如果operator_type = "agent"且operator_id不为空,查询Shop表获取店铺名称 - 10.3 添加
IsPurchasedByParent派生字段:purchase_role == "purchased_by_parent" - 10.4 添加
PurchaseRemark派生字段:根据purchase_role和operator_name生成备注文本(如"由上级代理【XX】购买"、"由平台代购") - 10.5 运行
go build ./...验证编译通过
11. Handler 层:权限检查调整
- 11.1 在
internal/handler/admin/order.go的Create()方法中,修改wallet支付方式的权限检查,允许代理、平台、超管使用 - 11.2 保持
offline支付方式只允许平台和超管使用的限制 - 11.3 运行
go build ./...验证编译通过
12. Handler 层:订单查询参数传递
- 12.1 在
internal/handler/admin/order.go的List()方法中,从查询参数解析purchase_role - 12.2 将
purchase_role传递给 Service 层的List()方法 - 12.3 运行
go build ./...验证编译通过
13. 文档生成器更新(OpenAPI)
- 13.1 确认
cmd/api/docs.go和cmd/gendocs/main.go中的Handlers结构体已包含OrderHandler(如果不存在则添加) - 13.2 运行
go run cmd/gendocs/main.go生成 OpenAPI 文档 - 13.3 检查生成的文档中订单创建和列表接口的请求/响应字段是否包含新字段
14. 集成测试:代理自购场景
- 14.1 使用 PostgreSQL MCP 工具创建测试数据:创建代理账号、代理钱包(余额 10000 分)、IoT 卡(shop_id = 代理店铺 ID)、套餐分配配置(成本价 8000 分)
- 14.2 使用 Postman/curl 调用后台订单创建 API,代理账号创建订单,支付方式 wallet,选择自己的卡和套餐
- 14.3 验证响应:
payment_status= 2,operator_id= 代理店铺 ID,buyer_id= 代理店铺 ID,purchase_role= "self_purchase",total_amount= 8000,actual_paid_amount= 8000 - 14.4 使用 PostgreSQL MCP 查询订单表,验证订单记录正确
- 14.5 使用 PostgreSQL MCP 查询钱包表,验证余额扣减:
balance= 2000(10000 - 8000) - 14.6 使用 PostgreSQL MCP 查询钱包流水表,验证流水记录:
transaction_subtype= "self_purchase",amount= -8000,remark= "购买套餐" - 14.7 使用 PostgreSQL MCP 查询套餐使用表(
tb_package_usage),验证套餐已激活:status= 1
15. 集成测试:代理代购场景
- 15.1 使用 PostgreSQL MCP 工具创建测试数据:一级代理(成本价 8000)、二级代理(成本价 10000,parent_shop_id = 一级代理)、一级代理钱包(余额 10000)、IoT 卡(shop_id = 二级代理店铺 ID)、套餐分配配置
- 15.2 使用 Postman/curl 调用后台订单创建 API,一级代理账号创建订单,支付方式 wallet,选择二级代理的卡和套餐
- 15.3 验证响应:
payment_status= 2,operator_id= 一级代理店铺 ID,buyer_id= 二级代理店铺 ID,purchase_role= "purchase_for_subordinate",total_amount= 10000,actual_paid_amount= 8000 - 15.4 使用 PostgreSQL MCP 查询订单表,验证订单记录正确
- 15.5 使用 PostgreSQL MCP 查询一级代理钱包,验证余额扣减:
balance= 2000(10000 - 8000) - 15.6 使用 PostgreSQL MCP 查询钱包流水表,验证流水记录:
transaction_subtype= "purchase_for_subordinate",amount= -8000,related_shop_id= 二级代理店铺 ID,remark包含二级代理店铺名称 - 15.7 使用 PostgreSQL MCP 查询套餐使用表,验证套餐已激活
- 15.8 使用 PostgreSQL MCP 查询佣金表,验证未产生佣金记录(代理代购不产生佣金)
16. 集成测试:平台代购场景(回归测试)
- 16.1 使用 PostgreSQL MCP 工具创建测试数据:代理、IoT 卡(shop_id = 代理店铺 ID)、套餐分配配置(成本价 10000)
- 16.2 使用 Postman/curl 调用后台订单创建 API,平台账号创建订单,支付方式 offline,选择代理的卡和套餐
- 16.3 验证响应:
payment_status= 2,operator_id= NULL,operator_type= "platform",buyer_id= 代理店铺 ID,purchase_role= "purchased_by_platform",total_amount= 10000,actual_paid_amount= NULL - 16.4 使用 PostgreSQL MCP 查询订单表,验证订单记录正确
- 16.5 使用 PostgreSQL MCP 查询套餐使用表,验证套餐已激活
- 16.6 验证平台代购逻辑未被破坏(不扣款、立即激活、产生佣金)
17. 集成测试:订单查询场景
- 17.1 使用 PostgreSQL MCP 工具创建测试数据:一级代理、二级代理、多个订单(自购、代购、被代购)
- 17.2 使用 Postman/curl 调用后台订单列表 API,一级代理账号查询订单列表(不指定 purchase_role)
- 17.3 验证响应包含:buyer_id = 一级代理的订单 + operator_id = 一级代理的订单
- 17.4 使用 Postman/curl 调用后台订单列表 API,一级代理账号查询订单列表,指定
purchase_role=self_purchase - 17.5 验证响应只包含自购订单
- 17.6 使用 Postman/curl 调用后台订单列表 API,一级代理账号查询订单列表,指定
purchase_role=purchase_for_subordinate - 17.7 验证响应只包含为下级代理购买的订单
18. 集成测试:边界场景
- 18.1 测试钱包余额不足:代理钱包余额 5000,创建订单金额 8000,验证返回错误"余额不足"
- 18.2 测试并发扣款:模拟两个请求同时为同一钱包扣款,验证乐观锁生效,只有一个请求成功
- 18.3 测试幂等性:同一买家对同一载体的同一套餐组合短时间内重复创建订单,验证返回相同订单 ID,不重复扣款
- 18.4 测试 H5 端 wallet 订单:使用 H5 端 API 创建 wallet 订单,验证订单状态为待支付(
payment_status= 1),不影响后台逻辑
19. 数据回填(可选)
- 19.1 编写数据回填脚本,将现有
payment_method = 'offline'且is_purchase_on_behalf = true的订单回填purchase_role = 'purchased_by_platform'和operator_type = 'platform' - 19.2 在测试环境执行回填脚本,验证历史订单可正常查询
20. 文档更新
- 20.1 更新接口文档说明订单创建 API 的行为变更(后台 wallet 支付一步完成)
- 20.2 更新接口文档说明订单响应新增字段的含义
- 20.3 更新接口文档说明订单列表 API 新增
purchase_role查询参数
21. 生产环境部署准备
- 21.1 在测试环境充分验证所有场景通过
- 21.2 准备生产环境迁移脚本和回滚脚本
- 21.3 准备灰度发布计划:代码部署 → 观察日志 → 验证核心功能 → 全量发布
- 21.4 准备监控指标:订单创建成功率、钱包扣款成功率、错误日志(余额不足、并发冲突)