feat: 钱包系统分离 - 代理钱包与卡钱包完全隔离
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>
This commit is contained in:
2026-02-25 09:51:00 +08:00
parent f32d32cd36
commit 18daeae65a
66 changed files with 4420 additions and 1090 deletions

View File

@@ -98,8 +98,8 @@ func initServices(s *stores, deps *Dependencies) *services {
PersonalCustomer: personalCustomerSvc.NewService(s.PersonalCustomer, s.PersonalCustomerPhone, deps.VerificationService, deps.JWTManager, deps.WechatOfficialAccount, deps.Logger),
Shop: shopSvc.New(s.Shop, s.Account, s.ShopRole, s.Role),
Auth: authSvc.New(s.Account, s.AccountRole, s.RolePermission, s.Permission, deps.TokenManager, deps.Logger),
ShopCommission: shopCommissionSvc.New(s.Shop, s.Account, s.Wallet, s.CommissionWithdrawalRequest, s.CommissionRecord),
CommissionWithdrawal: commissionWithdrawalSvc.New(deps.DB, s.Shop, s.Account, s.Wallet, s.WalletTransaction, s.CommissionWithdrawalRequest),
ShopCommission: shopCommissionSvc.New(s.Shop, s.Account, s.AgentWallet, s.CommissionWithdrawalRequest, s.CommissionRecord),
CommissionWithdrawal: commissionWithdrawalSvc.New(deps.DB, s.Shop, s.Account, s.AgentWallet, s.AgentWalletTransaction, s.CommissionWithdrawalRequest),
CommissionWithdrawalSetting: commissionWithdrawalSettingSvc.New(deps.DB, s.Account, s.CommissionWithdrawalSetting),
CommissionCalculation: commissionCalculationSvc.New(
deps.DB,
@@ -110,8 +110,8 @@ func initServices(s *stores, deps *Dependencies) *services {
s.PackageSeries,
s.IotCard,
s.Device,
s.Wallet,
s.WalletTransaction,
s.AgentWallet,
s.AgentWalletTransaction,
s.Order,
s.OrderItem,
s.Package,
@@ -123,7 +123,7 @@ func initServices(s *stores, deps *Dependencies) *services {
EnterpriseCard: enterpriseCardSvc.New(deps.DB, s.Enterprise, s.EnterpriseCardAuthorization),
EnterpriseDevice: enterpriseDeviceSvc.New(deps.DB, s.Enterprise, s.Device, s.DeviceSimBinding, s.EnterpriseDeviceAuthorization, s.EnterpriseCardAuthorization, deps.Logger),
Authorization: enterpriseCardSvc.NewAuthorizationService(s.Enterprise, s.IotCard, s.EnterpriseCardAuthorization, deps.Logger),
MyCommission: myCommissionSvc.New(deps.DB, s.Shop, s.Wallet, s.CommissionWithdrawalRequest, s.CommissionWithdrawalSetting, s.CommissionRecord, s.WalletTransaction),
MyCommission: myCommissionSvc.New(deps.DB, s.Shop, s.AgentWallet, s.CommissionWithdrawalRequest, s.CommissionWithdrawalSetting, s.CommissionRecord, s.AgentWalletTransaction),
IotCard: iotCard,
IotCardImport: iotCardImportSvc.New(deps.DB, s.IotCardImportTask, deps.QueueClient),
Device: deviceSvc.New(deps.DB, s.Device, s.DeviceSimBinding, s.IotCard, s.Shop, s.AssetAllocationRecord, s.ShopPackageAllocation, s.ShopSeriesAllocation, s.PackageSeries),
@@ -140,8 +140,8 @@ func initServices(s *stores, deps *Dependencies) *services {
ShopPackageBatchPricing: shopPackageBatchPricingSvc.New(deps.DB, s.ShopPackageAllocation, s.ShopPackageAllocationPriceHistory, s.Shop),
CommissionStats: commissionStatsSvc.New(s.ShopSeriesCommissionStats),
PurchaseValidation: purchaseValidation,
Order: orderSvc.New(deps.DB, deps.Redis, s.Order, s.OrderItem, s.Wallet, purchaseValidation, s.ShopPackageAllocation, s.ShopSeriesAllocation, s.IotCard, s.Device, s.PackageSeries, s.PackageUsage, s.Package, deps.WechatPayment, deps.QueueClient, deps.Logger),
Recharge: rechargeSvc.New(deps.DB, s.Recharge, s.Wallet, s.WalletTransaction, s.IotCard, s.Device, s.ShopSeriesAllocation, s.PackageSeries, s.CommissionRecord, deps.Logger),
Order: orderSvc.New(deps.DB, deps.Redis, s.Order, s.OrderItem, s.AgentWallet, s.CardWallet, purchaseValidation, s.ShopPackageAllocation, s.ShopSeriesAllocation, s.IotCard, s.Device, s.PackageSeries, s.PackageUsage, s.Package, deps.WechatPayment, deps.QueueClient, deps.Logger),
Recharge: rechargeSvc.New(deps.DB, s.CardRecharge, s.CardWallet, s.CardWalletTransaction, s.IotCard, s.Device, s.ShopSeriesAllocation, s.PackageSeries, s.CommissionRecord, deps.Logger),
PollingConfig: pollingSvc.NewConfigService(s.PollingConfig),
PollingConcurrency: pollingSvc.NewConcurrencyService(s.PollingConcurrencyConfig, deps.Redis),
PollingMonitoring: pollingSvc.NewMonitoringService(deps.Redis),

View File

@@ -15,10 +15,8 @@ type stores struct {
RolePermission *postgres.RolePermissionStore
PersonalCustomer *postgres.PersonalCustomerStore
PersonalCustomerPhone *postgres.PersonalCustomerPhoneStore
Wallet *postgres.WalletStore
CommissionWithdrawalRequest *postgres.CommissionWithdrawalRequestStore
CommissionRecord *postgres.CommissionRecordStore
WalletTransaction *postgres.WalletTransactionStore
CommissionWithdrawalSetting *postgres.CommissionWithdrawalSettingStore
Enterprise *postgres.EnterpriseStore
EnterpriseCardAuthorization *postgres.EnterpriseCardAuthorizationStore
@@ -40,7 +38,6 @@ type stores struct {
ShopSeriesCommissionStats *postgres.ShopSeriesCommissionStatsStore
Order *postgres.OrderStore
OrderItem *postgres.OrderItemStore
Recharge *postgres.RechargeStore
PollingConfig *postgres.PollingConfigStore
PollingConcurrencyConfig *postgres.PollingConcurrencyConfigStore
PollingAlertRule *postgres.PollingAlertRuleStore
@@ -48,6 +45,14 @@ type stores struct {
DataCleanupConfig *postgres.DataCleanupConfigStore
DataCleanupLog *postgres.DataCleanupLogStore
PollingManualTriggerLog *postgres.PollingManualTriggerLogStore
// 代理钱包系统
AgentWallet *postgres.AgentWalletStore
AgentWalletTransaction *postgres.AgentWalletTransactionStore
AgentRecharge *postgres.AgentRechargeStore
// 卡钱包系统
CardWallet *postgres.CardWalletStore
CardWalletTransaction *postgres.CardWalletTransactionStore
CardRecharge *postgres.CardRechargeStore
}
func initStores(deps *Dependencies) *stores {
@@ -62,10 +67,8 @@ func initStores(deps *Dependencies) *stores {
RolePermission: postgres.NewRolePermissionStore(deps.DB, deps.Redis),
PersonalCustomer: postgres.NewPersonalCustomerStore(deps.DB, deps.Redis),
PersonalCustomerPhone: postgres.NewPersonalCustomerPhoneStore(deps.DB),
Wallet: postgres.NewWalletStore(deps.DB, deps.Redis),
CommissionWithdrawalRequest: postgres.NewCommissionWithdrawalRequestStore(deps.DB, deps.Redis),
CommissionRecord: postgres.NewCommissionRecordStore(deps.DB, deps.Redis),
WalletTransaction: postgres.NewWalletTransactionStore(deps.DB, deps.Redis),
CommissionWithdrawalSetting: postgres.NewCommissionWithdrawalSettingStore(deps.DB, deps.Redis),
Enterprise: postgres.NewEnterpriseStore(deps.DB, deps.Redis),
EnterpriseCardAuthorization: postgres.NewEnterpriseCardAuthorizationStore(deps.DB, deps.Redis),
@@ -87,7 +90,6 @@ func initStores(deps *Dependencies) *stores {
ShopSeriesCommissionStats: postgres.NewShopSeriesCommissionStatsStore(deps.DB),
Order: postgres.NewOrderStore(deps.DB, deps.Redis),
OrderItem: postgres.NewOrderItemStore(deps.DB, deps.Redis),
Recharge: postgres.NewRechargeStore(deps.DB, deps.Redis),
PollingConfig: postgres.NewPollingConfigStore(deps.DB),
PollingConcurrencyConfig: postgres.NewPollingConcurrencyConfigStore(deps.DB),
PollingAlertRule: postgres.NewPollingAlertRuleStore(deps.DB),
@@ -95,5 +97,13 @@ func initStores(deps *Dependencies) *stores {
DataCleanupConfig: postgres.NewDataCleanupConfigStore(deps.DB),
DataCleanupLog: postgres.NewDataCleanupLogStore(deps.DB),
PollingManualTriggerLog: postgres.NewPollingManualTriggerLogStore(deps.DB),
// 代理钱包系统
AgentWallet: postgres.NewAgentWalletStore(deps.DB, deps.Redis),
AgentWalletTransaction: postgres.NewAgentWalletTransactionStore(deps.DB, deps.Redis),
AgentRecharge: postgres.NewAgentRechargeStore(deps.DB, deps.Redis),
// 卡钱包系统
CardWallet: postgres.NewCardWalletStore(deps.DB, deps.Redis),
CardWalletTransaction: postgres.NewCardWalletTransactionStore(deps.DB, deps.Redis),
CardRecharge: postgres.NewCardRechargeStore(deps.DB, deps.Redis),
}
}

View File

@@ -30,8 +30,8 @@ func initWorkerServices(stores *queue.WorkerStores, deps *WorkerDependencies) *q
stores.PackageSeries,
stores.IotCard,
stores.Device,
stores.Wallet,
stores.WalletTransaction,
stores.AgentWallet,
stores.AgentWalletTransaction,
stores.Order,
stores.OrderItem,
stores.Package,

View File

@@ -17,8 +17,6 @@ type workerStores struct {
Shop *postgres.ShopStore
ShopSeriesAllocation *postgres.ShopSeriesAllocationStore
PackageSeries *postgres.PackageSeriesStore
Wallet *postgres.WalletStore
WalletTransaction *postgres.WalletTransactionStore
Order *postgres.OrderStore
OrderItem *postgres.OrderItemStore
Package *postgres.PackageStore
@@ -28,6 +26,8 @@ type workerStores struct {
PollingAlertHistory *postgres.PollingAlertHistoryStore
DataCleanupConfig *postgres.DataCleanupConfigStore
DataCleanupLog *postgres.DataCleanupLogStore
AgentWallet *postgres.AgentWalletStore
AgentWalletTransaction *postgres.AgentWalletTransactionStore
}
func initWorkerStores(deps *WorkerDependencies) *queue.WorkerStores {
@@ -43,8 +43,6 @@ func initWorkerStores(deps *WorkerDependencies) *queue.WorkerStores {
Shop: postgres.NewShopStore(deps.DB, deps.Redis),
ShopSeriesAllocation: postgres.NewShopSeriesAllocationStore(deps.DB),
PackageSeries: postgres.NewPackageSeriesStore(deps.DB),
Wallet: postgres.NewWalletStore(deps.DB, deps.Redis),
WalletTransaction: postgres.NewWalletTransactionStore(deps.DB, deps.Redis),
Order: postgres.NewOrderStore(deps.DB, deps.Redis),
OrderItem: postgres.NewOrderItemStore(deps.DB, deps.Redis),
Package: postgres.NewPackageStore(deps.DB),
@@ -54,6 +52,8 @@ func initWorkerStores(deps *WorkerDependencies) *queue.WorkerStores {
PollingAlertHistory: postgres.NewPollingAlertHistoryStore(deps.DB),
DataCleanupConfig: postgres.NewDataCleanupConfigStore(deps.DB),
DataCleanupLog: postgres.NewDataCleanupLogStore(deps.DB),
AgentWallet: postgres.NewAgentWalletStore(deps.DB, deps.Redis),
AgentWalletTransaction: postgres.NewAgentWalletTransactionStore(deps.DB, deps.Redis),
}
return &queue.WorkerStores{
@@ -68,8 +68,6 @@ func initWorkerStores(deps *WorkerDependencies) *queue.WorkerStores {
Shop: stores.Shop,
ShopSeriesAllocation: stores.ShopSeriesAllocation,
PackageSeries: stores.PackageSeries,
Wallet: stores.Wallet,
WalletTransaction: stores.WalletTransaction,
Order: stores.Order,
OrderItem: stores.OrderItem,
Package: stores.Package,
@@ -79,5 +77,7 @@ func initWorkerStores(deps *WorkerDependencies) *queue.WorkerStores {
PollingAlertHistory: stores.PollingAlertHistory,
DataCleanupConfig: stores.DataCleanupConfig,
DataCleanupLog: stores.DataCleanupLog,
AgentWallet: stores.AgentWallet,
AgentWalletTransaction: stores.AgentWalletTransaction,
}
}