All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m17s
## 变更概述 将统一钱包系统拆分为代理钱包和卡钱包两个独立系统,实现数据表和代码层面的完全隔离。 ## 数据库变更 - 新增 6 张表:tb_agent_wallet、tb_agent_wallet_transaction、tb_agent_recharge_record、tb_card_wallet、tb_card_wallet_transaction、tb_card_recharge_record - 删除 3 张旧表:tb_wallet、tb_wallet_transaction、tb_recharge_record - 代理钱包:按 (shop_id, wallet_type) 唯一标识,支持主钱包和分佣钱包 - 卡钱包:按 (resource_type, resource_id) 唯一标识,支持物联网卡和设备 ## 代码变更 - Model 层:新增 AgentWallet、AgentWalletTransaction、AgentRechargeRecord、CardWallet、CardWalletTransaction、CardRechargeRecord 模型 - Store 层:新增 6 个独立 Store,支持事务、乐观锁、Redis 缓存 - Service 层:重构 commission_calculation、commission_withdrawal、order、recharge 等 8 个服务 - Bootstrap 层:更新 Store 和 Service 依赖注入 - 常量层:按钱包类型重新组织常量和 Redis Key 生成函数 ## 技术特性 - 乐观锁:使用 version 字段防止并发冲突 - 多租户:支持 shop_id_tag 和 enterprise_id_tag 过滤 - 事务管理:所有余额变动使用事务保证 ACID - 缓存策略:Cache-Aside 模式,余额变动后删除缓存 ## 业务影响 - 代理钱包和卡钱包业务完全隔离,互不影响 - 为独立监控、优化、扩展打下基础 - 提升代理钱包的稳定性和独立性 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
17 KiB
17 KiB
钱包系统分离 - 实施任务清单
1. 数据库迁移 - 创建新表结构
- 1.1 创建代理钱包主表迁移文件(
tb_agent_wallet),包含 shop_id、wallet_type、balance、frozen_balance、version 等字段,添加唯一索引和多租户索引 - 1.2 创建代理钱包交易记录表迁移文件(
tb_agent_wallet_transaction),包含 agent_wallet_id、shop_id、transaction_type、amount、balance_before、balance_after 等字段,添加 4 个查询索引 - 1.3 创建代理充值记录表迁移文件(
tb_agent_recharge_record),包含 recharge_no、amount、payment_method、status 等字段,添加状态和店铺索引 - 1.4 创建卡钱包主表迁移文件(
tb_card_wallet),包含 resource_type、resource_id、balance、frozen_balance、version 等字段,添加唯一索引和多租户索引 - 1.5 创建卡钱包交易记录表迁移文件(
tb_card_wallet_transaction),包含 card_wallet_id、resource_type、resource_id、transaction_type、amount 等字段,添加 4 个查询索引 - 1.6 创建卡充值记录表迁移文件(
tb_card_recharge_record),包含 recharge_no、amount、payment_method、status 等字段,添加状态和资源索引 - 1.7 执行数据库迁移,验证 6 张新表创建成功,检查索引和约束
2. 代理钱包系统 - Model 层实现
- 2.1 创建
internal/model/agent_wallet.go,定义 AgentWallet 结构体,包含 ShopID、WalletType、Balance、FrozenBalance、Version、BaseModel 等字段 - 2.2 在
agent_wallet.go中定义 AgentWalletTransaction 结构体,包含 AgentWalletID、ShopID、TransactionType、Amount、BalanceBefore、BalanceAfter 等字段 - 2.3 在
agent_wallet.go中定义 AgentRechargeRecord 结构体,包含 UserID、AgentWalletID、ShopID、RechargeNo、Amount、PaymentMethod、Status 等字段 - 2.4 为所有 Model 实现 TableName() 方法,返回对应的表名(tb_agent_wallet、tb_agent_wallet_transaction、tb_agent_recharge_record)
- 2.5 添加中文注释说明每个字段的用途和约束
- 2.6 编译验证 Model 定义正确,无语法错误
3. 代理钱包系统 - Store 层实现
- 3.1 创建
internal/store/postgres/agent_wallet_store.go,定义 AgentWalletStore 结构体,包含 db 和 redis 字段 - 3.2 实现
NewAgentWalletStore构造函数 - 3.3 实现
GetCommissionWallet(ctx, shopID)方法,查询店铺的分佣钱包 - 3.4 实现
GetMainWallet(ctx, shopID)方法,查询店铺的主钱包 - 3.5 实现
GetByShopIDAndType(ctx, shopID, walletType)方法,根据店铺 ID 和钱包类型查询 - 3.6 实现
GetByID(ctx, id)方法,根据钱包 ID 查询 - 3.7 实现
DeductFrozenBalanceWithTx(ctx, tx, walletID, amount)方法,从冻结余额扣款(带事务) - 3.8 实现
UnfreezeBalanceWithTx(ctx, tx, walletID, amount)方法,解冻余额到可用余额(带事务) - 3.9 实现
FreezeBalanceWithTx(ctx, tx, walletID, amount, version)方法,冻结余额(带事务,使用乐观锁) - 3.10 实现
GetShopCommissionSummaryBatch(ctx, shopIDs)方法,批量获取店铺佣金钱包汇总 - 3.11 创建
internal/store/postgres/agent_wallet_transaction_store.go,定义 AgentWalletTransactionStore 结构体 - 3.12 实现
CreateWithTx(ctx, tx, transaction)方法,创建代理钱包交易记录(带事务) - 3.13 实现
ListByShopID(ctx, shopID, offset, limit)方法,按店铺查询交易记录(支持分页) - 3.14 创建
internal/store/postgres/agent_recharge_store.go,定义 AgentRechargeStore 结构体 - 3.15 实现充值记录的 CRUD 方法(Create、GetByRechargeNo、UpdateStatus 等)
- 3.16 编译验证 Store 层代码正确,无语法错误
4. 卡钱包系统 - Model 层实现
- 4.1 创建
internal/model/card_wallet.go,定义 CardWallet 结构体,包含 ResourceType、ResourceID、Balance、FrozenBalance、Version、BaseModel 等字段 - 4.2 在
card_wallet.go中定义 CardWalletTransaction 结构体,包含 CardWalletID、ResourceType、ResourceID、TransactionType、Amount、BalanceBefore、BalanceAfter 等字段 - 4.3 在
card_wallet.go中定义 CardRechargeRecord 结构体,包含 UserID、CardWalletID、ResourceType、ResourceID、RechargeNo、Amount、PaymentMethod、Status 等字段 - 4.4 为所有 Model 实现 TableName() 方法,返回对应的表名(tb_card_wallet、tb_card_wallet_transaction、tb_card_recharge_record)
- 4.5 添加中文注释说明每个字段的用途和约束
- 4.6 编译验证 Model 定义正确,无语法错误
5. 卡钱包系统 - Store 层实现
- 5.1 创建
internal/store/postgres/card_wallet_store.go,定义 CardWalletStore 结构体,包含 db 和 redis 字段 - 5.2 实现
NewCardWalletStore构造函数 - 5.3 实现
GetByResourceTypeAndID(ctx, resourceType, resourceID)方法,根据资源类型和 ID 查询钱包 - 5.4 实现
GetByID(ctx, id)方法,根据钱包 ID 查询 - 5.5 实现
DeductBalanceWithTx(ctx, tx, walletID, amount, version)方法,扣款(带事务,使用乐观锁) - 5.6 实现
AddBalanceWithTx(ctx, tx, walletID, amount)方法,增加余额(带事务) - 5.7 创建
internal/store/postgres/card_wallet_transaction_store.go,定义 CardWalletTransactionStore 结构体 - 5.8 实现
CreateWithTx(ctx, tx, transaction)方法,创建卡钱包交易记录(带事务) - 5.9 实现
ListByResourceID(ctx, resourceType, resourceID, offset, limit)方法,按资源查询交易记录(支持分页) - 5.10 创建
internal/store/postgres/card_recharge_store.go,定义 CardRechargeStore 结构体 - 5.11 实现充值记录的 CRUD 方法(Create、GetByRechargeNo、UpdateStatus 等)
- 5.12 编译验证 Store 层代码正确,无语法错误
6. 常量定义更新
- 6.1 更新
pkg/constants/wallet.go,按钱包类型重新组织常量定义 - 6.2 添加代理钱包专用常量(AgentRechargeOrderPrefix、AgentRechargeMinAmount、AgentRechargeMaxAmount)
- 6.3 添加卡钱包专用常量(CardWalletResourceTypeIotCard、CardWalletResourceTypeDevice、CardRechargeOrderPrefix、CardRechargeMinAmount、CardRechargeMaxAmount)
- 6.4 定义 Redis Key 生成函数:
RedisAgentWalletBalanceKey(shopID, walletType) - 6.5 定义 Redis Key 生成函数:
RedisAgentWalletLockKey(shopID, walletType) - 6.6 定义 Redis Key 生成函数:
RedisCardWalletBalanceKey(resourceType, resourceID) - 6.7 定义 Redis Key 生成函数:
RedisCardWalletLockKey(resourceType, resourceID) - 6.8 为所有常量和函数添加中文注释
- 6.9 编译验证常量定义正确,无语法错误
7. Bootstrap 层 - 注册新 Store
- 7.1 在
internal/bootstrap/stores.go中添加 AgentWalletStore 字段到 Stores 结构体 - 7.2 在
internal/bootstrap/stores.go中添加 AgentWalletTransactionStore 字段到 Stores 结构体 - 7.3 在
internal/bootstrap/stores.go中添加 AgentRechargeStore 字段到 Stores 结构体 - 7.4 在
internal/bootstrap/stores.go中添加 CardWalletStore 字段到 Stores 结构体 - 7.5 在
internal/bootstrap/stores.go中添加 CardWalletTransactionStore 字段到 Stores 结构体 - 7.6 在
internal/bootstrap/stores.go中添加 CardRechargeStore 字段到 Stores 结构体 - 7.7 在
NewStores()函数中初始化所有新 Store 实例(调用 NewXxxStore 构造函数) - 7.8 编译验证 Bootstrap 层代码正确,无语法错误
8. Service 层重构 - 佣金相关服务
- 8.1 更新
internal/service/commission_calculation/service.go,将WalletStore依赖改为AgentWalletStore - 8.2 更新
internal/service/commission_calculation/service.go中所有调用钱包的方法,使用新的 AgentWalletStore API - 8.3 更新
internal/service/commission_withdrawal/service.go,将WalletStore依赖改为AgentWalletStore - 8.4 更新
internal/service/commission_withdrawal/service.go中所有调用钱包的方法,使用新的 AgentWalletStore API - 8.5 更新
internal/service/shop_commission/service.go,将WalletStore依赖改为AgentWalletStore - 8.6 更新
internal/service/shop_commission/service.go中所有调用钱包的方法,使用新的 AgentWalletStore API - 8.7 更新
internal/service/my_commission/service.go,将WalletStore依赖改为AgentWalletStore - 8.8 更新
internal/service/my_commission/service.go中所有调用钱包的方法,使用新的 AgentWalletStore API - 8.9 编译验证所有佣金相关服务重构正确,无语法错误
9. Service 层重构 - 订单服务
- 9.1 更新
internal/service/order/service.go,将WalletStore依赖改为AgentWalletStore和CardWalletStore - 9.2 更新
internal/service/order/service.go中的WalletPay()方法,使用新的 AgentWalletStore 和 CardWalletStore API(根据买家类型分别处理) - 9.3 更新
internal/service/order/service.go中的HandlePaymentCallback()方法,使用新的钱包 API - 9.4 更新
internal/service/order/service.go中所有其他调用钱包的方法,使用新的钱包 Store API - 9.5 编译验证订单服务重构正确,无语法错误
10. Service 层重构 - 充值服务(注:实际采用原地重构方案,未拆分为两个独立服务)
- 10.1 更新
internal/service/recharge/service.go,将依赖从 WalletStore 改为 CardWalletStore、CardWalletTransactionStore、CardRechargeStore - 10.2 更新 Service 构造函数 New(),注入新的 CardWallet 相关 Store
- 10.3 更新
Create()方法,使用 CardRechargeStore 创建充值订单,使用 CardWalletStore 查询钱包 - 10.4 更新
HandlePaymentCallback()方法,使用 CardRechargeStore 和 CardWalletStore 处理支付回调 - 10.5 更新
buildRechargeResponse()方法,适配 CardRechargeRecord 模型 - 10.6 更新
List()方法,使用 CardRechargeStore.List() 查询充值记录 - 10.7 更新
GetByID()方法,使用 CardRechargeStore.GetByID() 查询充值订单 - 10.8 更新所有佣金触发逻辑,使用 AgentWalletStore 处理佣金入账
- 10.9 在 CardRechargeStore 中添加 List()、UpdatePaymentInfo()、UpdateStatusWithOptimisticLock() 方法
- 10.10 更新 bootstrap/services.go,注入 CardRecharge、CardWallet、CardWalletTransaction Store
- 10.11 编译验证充值服务重构正确,无语法错误
11. Bootstrap 层 - 更新 Service 依赖注入
- 11.1 在
internal/bootstrap/services.go中更新 CommissionCalculationService,注入 AgentWalletStore 和 AgentWalletTransactionStore - 11.2 在
internal/bootstrap/services.go中更新 CommissionWithdrawalService,注入 AgentWalletStore 和 AgentWalletTransactionStore - 11.3 在
internal/bootstrap/services.go中更新 ShopCommissionService,注入 AgentWalletStore - 11.4 在
internal/bootstrap/services.go中更新 MyCommissionService,注入 AgentWalletStore 和 AgentWalletTransactionStore - 11.5 在
internal/bootstrap/services.go中更新 OrderService,注入 AgentWalletStore 和 CardWalletStore - 11.6 在
internal/bootstrap/services.go中更新 RechargeService,注入 CardRechargeStore、CardWalletStore、CardWalletTransactionStore - 11.7 在
internal/bootstrap/worker_services.go中更新 CommissionCalculationService,注入 AgentWalletStore 和 AgentWalletTransactionStore - 11.8 在
pkg/queue/types.go中更新 WorkerStores,添加 AgentWallet 和 AgentWalletTransaction 字段 - 11.9 编译验证 Service 依赖注入更新正确,无语法错误
12. 清理旧代码 - 删除旧 Model 和 Store
- 12.1 删除
internal/model/wallet.go文件(包含 Wallet、WalletTransaction、RechargeRecord、WalletMetadata) - 12.2 删除
internal/store/postgres/wallet_store.go文件 - 12.3 删除
internal/store/postgres/wallet_transaction_store.go文件 - 12.4 从
internal/bootstrap/stores.go中移除 WalletStore 和 WalletTransactionStore 字段 - 12.5 从
internal/bootstrap/stores.go的NewStores()函数中移除 WalletStore 和 WalletTransactionStore 初始化 - 12.6 编译检查,确保无旧代码引用残留
13. 数据库迁移 - 删除旧表
- 13.1 创建删除旧表的迁移文件(DROP TABLE tb_wallet、tb_wallet_transaction、tb_recharge_record)
- 13.2 执行数据库迁移,验证旧表删除成功
- 13.3 检查数据库中只剩下新的 6 张表
14. 手动测试 - 代理钱包核心流程
- 14.1 测试代理钱包创建:为店铺 ID 10 创建主钱包和分佣钱包
- 14.2 测试代理钱包充值:主钱包充值 100000 分(1000 元),验证余额正确
- 14.3 测试代理钱包扣款:主钱包扣款 30000 分(300 元),验证余额正确,创建交易记录
- 14.4 测试余额不足场景:尝试扣款超过可用余额,验证返回"余额不足"错误
- 14.5 测试冻结余额:分佣钱包冻结 50000 分用于提现,验证 frozen_balance 增加,可用余额减少
- 14.6 测试解冻余额:取消提现,验证冻结余额减少,可用余额恢复
- 14.7 测试并发扣款:模拟两个并发请求同时扣款,验证乐观锁生效(一个成功,一个失败重试)
- 14.8 测试交易记录查询:按店铺 ID 查询交易历史,验证分页和排序正确
15. 手动测试 - 卡钱包核心流程
- 15.1 测试卡钱包创建:为物联网卡(resource_type=iot_card, resource_id=100)创建钱包
- 15.2 测试卡钱包充值:卡钱包充值 10000 分(100 元),验证余额正确
- 15.3 测试卡钱包扣款:购买套餐扣款 3000 分(30 元),验证余额正确,创建交易记录
- 15.4 测试订单退款:退款 3000 分,验证余额恢复,创建退款交易记录
- 15.5 测试余额不足场景:尝试扣款超过可用余额,验证返回"余额不足"错误
- 15.6 测试设备钱包:为设备(resource_type=device, resource_id=200)创建钱包,验证设备的多张卡共享钱包
- 15.7 测试并发扣款:模拟两个并发请求同时扣款,验证乐观锁生效
- 15.8 测试交易记录查询:按资源 ID 查询交易历史,验证分页和排序正确
16. 手动测试 - 充值流程
- 16.1 测试代理充值最小金额限制:尝试充值 50 元,验证返回"充值金额不能低于 100 元"错误
- 16.2 测试代理充值订单创建:创建充值订单,验证生成唯一的 recharge_no(ARCH 前缀),状态为"待支付"
- 16.3 测试代理充值支付完成:模拟支付回调,验证状态从"待支付"变为"已支付"
- 16.4 测试代理充值到账:处理充值到账,验证钱包余额增加,状态变为"已完成",创建交易记录
- 16.5 测试卡充值最小金额限制:尝试充值 0.5 元,验证返回"充值金额不能低于 1 元"错误
- 16.6 测试卡充值订单创建:创建充值订单,验证生成唯一的 recharge_no(CRCH 前缀),状态为"待支付"
- 16.7 测试卡充值支付完成:模拟支付回调,验证状态从"待支付"变为"已支付"
- 16.8 测试卡充值到账:处理充值到账,验证钱包余额增加,状态变为"已完成",创建交易记录
17. 数据一致性验证
- 17.1 验证代理钱包交易记录的 balance_before 和 balance_after 准确性:查询所有交易记录,计算余额变动,与实际余额对比
- 17.2 验证卡钱包交易记录的 balance_before 和 balance_after 准确性:查询所有交易记录,计算余额变动,与实际余额对比
- 17.3 验证乐观锁 version 字段在并发场景下的有效性:模拟高并发扣款,验证 version 正确递增,无丢失更新
- 17.4 验证 Redis 缓存一致性:余额变动后,检查缓存是否被正确删除,下次查询是否重新加载
18. 最终验证和清理
- 18.1 运行
go build ./...编译整个项目,确保无编译错误 - 18.2 运行
go mod tidy清理未使用的依赖 - 18.3 检查所有文件的中文注释是否完整
- 18.4 检查所有常量是否定义在
pkg/constants/中,无硬编码 - 18.5 检查所有错误返回是否使用
errors.New()或errors.Wrap(),无fmt.Errorf() - 18.6 使用
gofmt -w .格式化所有代码 - 18.7 检查 git status,确认所有变更符合预期
- 18.8 准备提交代码,编写 Git Commit 信息(中文)
注意事项:
- 任务顺序不可颠倒:必须先完成数据库迁移和 Model 层,再实现 Store 层,最后重构 Service 层
- 逐项标记完成:每完成一个任务,将
[ ]改为[x] - 遇到问题时停止:如果某个任务无法完成或发现设计问题,立即停止并与团队讨论
- 编译验证:每个阶段完成后必须编译验证,确保无语法错误
- 手动测试不可跳过:所有核心流程必须手动测试验证,确保功能正确