feat: 钱包系统分离 - 代理钱包与卡钱包完全隔离
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m17s
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:
@@ -1,54 +1,89 @@
|
||||
package constants
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ========================================
|
||||
// 钱包系统常量定义
|
||||
// ========================================
|
||||
|
||||
// 钱包资源类型
|
||||
// ========== 代理钱包常量 ==========
|
||||
|
||||
// 代理钱包类型
|
||||
const (
|
||||
WalletResourceTypeIotCard = "iot_card" // 物联网卡钱包(个人客户)
|
||||
WalletResourceTypeDevice = "device" // 设备钱包(个人客户,多卡共享)
|
||||
WalletResourceTypeShop = "shop" // 店铺钱包(代理商)
|
||||
AgentWalletTypeMain = "main" // 主钱包
|
||||
AgentWalletTypeCommission = "commission" // 分佣钱包
|
||||
)
|
||||
|
||||
// 钱包类型
|
||||
// 代理钱包状态
|
||||
const (
|
||||
WalletTypeMain = "main" // 主钱包
|
||||
WalletTypeCommission = "commission" // 分佣钱包
|
||||
AgentWalletStatusNormal = 1 // 正常
|
||||
AgentWalletStatusFrozen = 2 // 冻结
|
||||
AgentWalletStatusClosed = 3 // 关闭
|
||||
)
|
||||
|
||||
// 钱包状态
|
||||
// 代理钱包交易类型
|
||||
const (
|
||||
WalletStatusNormal = 1 // 正常
|
||||
WalletStatusFrozen = 2 // 冻结
|
||||
WalletStatusClosed = 3 // 关闭
|
||||
AgentTransactionTypeRecharge = "recharge" // 充值
|
||||
AgentTransactionTypeDeduct = "deduct" // 扣款
|
||||
AgentTransactionTypeRefund = "refund" // 退款
|
||||
AgentTransactionTypeCommission = "commission" // 分佣
|
||||
AgentTransactionTypeWithdrawal = "withdrawal" // 提现
|
||||
)
|
||||
|
||||
// 交易类型
|
||||
// 代理充值订单号前缀
|
||||
const (
|
||||
TransactionTypeRecharge = "recharge" // 充值
|
||||
TransactionTypeDeduct = "deduct" // 扣款
|
||||
TransactionTypeRefund = "refund" // 退款
|
||||
TransactionTypeCommission = "commission" // 分佣
|
||||
TransactionTypeWithdrawal = "withdrawal" // 提现
|
||||
AgentRechargeOrderPrefix = "ARCH" // 代理充值订单号前缀
|
||||
)
|
||||
|
||||
// 交易状态
|
||||
// 代理充值金额限制(单位:分)
|
||||
const (
|
||||
AgentRechargeMinAmount = 10000 // 最小充值金额(100元)
|
||||
AgentRechargeMaxAmount = 100000000 // 最大充值金额(1000000元)
|
||||
)
|
||||
|
||||
// ========== 卡钱包常量 ==========
|
||||
|
||||
// 卡钱包资源类型
|
||||
const (
|
||||
CardWalletResourceTypeIotCard = "iot_card" // 物联网卡钱包
|
||||
CardWalletResourceTypeDevice = "device" // 设备钱包(多卡共享)
|
||||
)
|
||||
|
||||
// 卡钱包状态
|
||||
const (
|
||||
CardWalletStatusNormal = 1 // 正常
|
||||
CardWalletStatusFrozen = 2 // 冻结
|
||||
CardWalletStatusClosed = 3 // 关闭
|
||||
)
|
||||
|
||||
// 卡钱包交易类型
|
||||
const (
|
||||
CardTransactionTypeRecharge = "recharge" // 充值
|
||||
CardTransactionTypeDeduct = "deduct" // 扣款
|
||||
CardTransactionTypeRefund = "refund" // 退款
|
||||
)
|
||||
|
||||
// 卡充值订单号前缀
|
||||
const (
|
||||
CardRechargeOrderPrefix = "CRCH" // 卡充值订单号前缀
|
||||
)
|
||||
|
||||
// 卡充值金额限制(单位:分)
|
||||
const (
|
||||
CardRechargeMinAmount = 100 // 最小充值金额(1元)
|
||||
CardRechargeMaxAmount = 10000000 // 最大充值金额(100000元)
|
||||
)
|
||||
|
||||
// ========== 通用常量 ==========
|
||||
|
||||
// 交易状态(代理钱包和卡钱包通用)
|
||||
const (
|
||||
TransactionStatusSuccess = 1 // 成功
|
||||
TransactionStatusFailed = 2 // 失败
|
||||
TransactionStatusProcessing = 3 // 处理中
|
||||
)
|
||||
|
||||
// 关联业务类型
|
||||
const (
|
||||
ReferenceTypeOrder = "order" // 订单
|
||||
ReferenceTypeCommission = "commission" // 分佣
|
||||
ReferenceTypeWithdrawal = "withdrawal" // 提现
|
||||
ReferenceTypeTopup = "topup" // 充值
|
||||
)
|
||||
|
||||
// 充值状态
|
||||
// 充值状态(代理钱包和卡钱包通用)
|
||||
const (
|
||||
RechargeStatusPending = 1 // 待支付
|
||||
RechargeStatusPaid = 2 // 已支付
|
||||
@@ -61,17 +96,96 @@ const (
|
||||
const (
|
||||
RechargeMethodAlipay = "alipay" // 支付宝
|
||||
RechargeMethodWechat = "wechat" // 微信
|
||||
RechargeMethodBank = "bank" // 银行转账
|
||||
RechargeMethodOffline = "offline" // 线下
|
||||
RechargeMethodBank = "bank" // 银行转账(仅代理钱包支持)
|
||||
RechargeMethodOffline = "offline" // 线下(仅代理钱包支持)
|
||||
)
|
||||
|
||||
// 充值订单号前缀
|
||||
// 关联业务类型
|
||||
const (
|
||||
RechargeOrderPrefix = "RCH" // 充值订单号前缀
|
||||
ReferenceTypeOrder = "order" // 订单
|
||||
ReferenceTypeCommission = "commission" // 分佣
|
||||
ReferenceTypeWithdrawal = "withdrawal" // 提现
|
||||
ReferenceTypeTopup = "topup" // 充值
|
||||
)
|
||||
|
||||
// 充值金额限制(单位:分)
|
||||
const (
|
||||
RechargeMinAmount = 100 // 最小充值金额(1元)
|
||||
RechargeMaxAmount = 10000000 // 最大充值金额(100000元)
|
||||
)
|
||||
// ========== Redis Key 生成函数 ==========
|
||||
|
||||
// RedisAgentWalletBalanceKey 代理钱包余额缓存 Key
|
||||
// 格式:agent_wallet:balance:{shop_id}:{wallet_type}
|
||||
// TTL:300 秒(5 分钟)
|
||||
func RedisAgentWalletBalanceKey(shopID uint, walletType string) string {
|
||||
return fmt.Sprintf("agent_wallet:balance:%d:%s", shopID, walletType)
|
||||
}
|
||||
|
||||
// RedisAgentWalletLockKey 代理钱包分布式锁 Key
|
||||
// 格式:agent_wallet:lock:{shop_id}:{wallet_type}
|
||||
// TTL:10 秒
|
||||
func RedisAgentWalletLockKey(shopID uint, walletType string) string {
|
||||
return fmt.Sprintf("agent_wallet:lock:%d:%s", shopID, walletType)
|
||||
}
|
||||
|
||||
// RedisCardWalletBalanceKey 卡钱包余额缓存 Key
|
||||
// 格式:card_wallet:balance:{resource_type}:{resource_id}
|
||||
// TTL:180 秒(3 分钟)
|
||||
func RedisCardWalletBalanceKey(resourceType string, resourceID uint) string {
|
||||
return fmt.Sprintf("card_wallet:balance:%s:%d", resourceType, resourceID)
|
||||
}
|
||||
|
||||
// RedisCardWalletLockKey 卡钱包分布式锁 Key
|
||||
// 格式:card_wallet:lock:{resource_type}:{resource_id}
|
||||
// TTL:10 秒
|
||||
func RedisCardWalletLockKey(resourceType string, resourceID uint) string {
|
||||
return fmt.Sprintf("card_wallet:lock:%s:%d", resourceType, resourceID)
|
||||
}
|
||||
|
||||
// ========== 兼容性别名(待清理)==========
|
||||
|
||||
// 以下常量保留用于向后兼容,待旧代码清理后删除
|
||||
|
||||
// WalletTypeMain 主钱包(已废弃,使用 AgentWalletTypeMain)
|
||||
const WalletTypeMain = AgentWalletTypeMain
|
||||
|
||||
// WalletTypeCommission 分佣钱包(已废弃,使用 AgentWalletTypeCommission)
|
||||
const WalletTypeCommission = AgentWalletTypeCommission
|
||||
|
||||
// WalletResourceTypeIotCard 物联网卡钱包(已废弃,使用 CardWalletResourceTypeIotCard)
|
||||
const WalletResourceTypeIotCard = CardWalletResourceTypeIotCard
|
||||
|
||||
// WalletResourceTypeDevice 设备钱包(已废弃,使用 CardWalletResourceTypeDevice)
|
||||
const WalletResourceTypeDevice = CardWalletResourceTypeDevice
|
||||
|
||||
// WalletResourceTypeShop 店铺钱包(已废弃,代理钱包不再使用 resource_type)
|
||||
const WalletResourceTypeShop = "shop"
|
||||
|
||||
// WalletStatusNormal 钱包状态-正常(已废弃,使用 AgentWalletStatusNormal 或 CardWalletStatusNormal)
|
||||
const WalletStatusNormal = AgentWalletStatusNormal
|
||||
|
||||
// WalletStatusFrozen 钱包状态-冻结(已废弃,使用 AgentWalletStatusFrozen 或 CardWalletStatusFrozen)
|
||||
const WalletStatusFrozen = AgentWalletStatusFrozen
|
||||
|
||||
// WalletStatusClosed 钱包状态-关闭(已废弃,使用 AgentWalletStatusClosed 或 CardWalletStatusClosed)
|
||||
const WalletStatusClosed = AgentWalletStatusClosed
|
||||
|
||||
// TransactionTypeRecharge 交易类型-充值(已废弃,使用 AgentTransactionTypeRecharge 或 CardTransactionTypeRecharge)
|
||||
const TransactionTypeRecharge = AgentTransactionTypeRecharge
|
||||
|
||||
// TransactionTypeDeduct 交易类型-扣款(已废弃,使用 AgentTransactionTypeDeduct 或 CardTransactionTypeDeduct)
|
||||
const TransactionTypeDeduct = AgentTransactionTypeDeduct
|
||||
|
||||
// TransactionTypeRefund 交易类型-退款(已废弃,使用 AgentTransactionTypeRefund 或 CardTransactionTypeRefund)
|
||||
const TransactionTypeRefund = AgentTransactionTypeRefund
|
||||
|
||||
// TransactionTypeCommission 交易类型-分佣(已废弃,使用 AgentTransactionTypeCommission)
|
||||
const TransactionTypeCommission = AgentTransactionTypeCommission
|
||||
|
||||
// TransactionTypeWithdrawal 交易类型-提现(已废弃,使用 AgentTransactionTypeWithdrawal)
|
||||
const TransactionTypeWithdrawal = AgentTransactionTypeWithdrawal
|
||||
|
||||
// RechargeOrderPrefix 充值订单号前缀(已废弃,使用 AgentRechargeOrderPrefix 或 CardRechargeOrderPrefix)
|
||||
const RechargeOrderPrefix = "RCH"
|
||||
|
||||
// RechargeMinAmount 最小充值金额(已废弃,使用 AgentRechargeMinAmount 或 CardRechargeMinAmount)
|
||||
const RechargeMinAmount = CardRechargeMinAmount
|
||||
|
||||
// RechargeMaxAmount 最大充值金额(已废弃,使用 AgentRechargeMaxAmount 或 CardRechargeMaxAmount)
|
||||
const RechargeMaxAmount = CardRechargeMaxAmount
|
||||
|
||||
@@ -117,20 +117,20 @@ const (
|
||||
CodeForceRechargeAmountMismatch = 1141 // 强充金额不匹配
|
||||
|
||||
// 轮询系统相关错误 (1150-1169)
|
||||
CodePollingConfigNotFound = 1150 // 轮询配置不存在
|
||||
CodePollingConfigNameExists = 1151 // 轮询配置名称已存在
|
||||
CodePollingQueueFull = 1152 // 轮询队列已满
|
||||
CodePollingConcurrencyLimit = 1153 // 并发数已达上限
|
||||
CodePollingAlertRuleNotFound = 1154 // 告警规则不存在
|
||||
CodePollingConfigNotFound = 1150 // 轮询配置不存在
|
||||
CodePollingConfigNameExists = 1151 // 轮询配置名称已存在
|
||||
CodePollingQueueFull = 1152 // 轮询队列已满
|
||||
CodePollingConcurrencyLimit = 1153 // 并发数已达上限
|
||||
CodePollingAlertRuleNotFound = 1154 // 告警规则不存在
|
||||
CodePollingCleanupConfigNotFound = 1155 // 数据清理配置不存在
|
||||
CodePollingManualTriggerLimit = 1156 // 手动触发次数已达上限
|
||||
CodePollingManualTriggerLimit = 1156 // 手动触发次数已达上限
|
||||
|
||||
// 套餐相关错误 (1160-1179)
|
||||
CodeNoAvailablePackage = 1160 // 没有可用套餐
|
||||
CodePackageActivationConflict = 1161 // 套餐正在激活中
|
||||
CodeNoMainPackage = 1162 // 必须有主套餐才能购买加油包
|
||||
CodeRealnameRequired = 1163 // 设备/卡必须先完成实名认证才能购买套餐
|
||||
CodeMixedOrderForbidden = 1164 // 同订单不能同时购买正式套餐和加油包
|
||||
CodeNoAvailablePackage = 1160 // 没有可用套餐
|
||||
CodePackageActivationConflict = 1161 // 套餐正在激活中
|
||||
CodeNoMainPackage = 1162 // 必须有主套餐才能购买加油包
|
||||
CodeRealnameRequired = 1163 // 设备/卡必须先完成实名认证才能购买套餐
|
||||
CodeMixedOrderForbidden = 1164 // 同订单不能同时购买正式套餐和加油包
|
||||
|
||||
// 服务端错误 (2000-2999) -> 5xx HTTP 状态码
|
||||
CodeInternalError = 2001 // 内部服务器错误
|
||||
|
||||
@@ -21,8 +21,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
|
||||
@@ -32,6 +30,9 @@ type WorkerStores struct {
|
||||
PollingAlertHistory *postgres.PollingAlertHistoryStore
|
||||
DataCleanupConfig *postgres.DataCleanupConfigStore
|
||||
DataCleanupLog *postgres.DataCleanupLogStore
|
||||
// 新增代理钱包 Store
|
||||
AgentWallet *postgres.AgentWalletStore
|
||||
AgentWalletTransaction *postgres.AgentWalletTransactionStore
|
||||
}
|
||||
|
||||
// WorkerServices Worker 侧所有 Service 的集合
|
||||
|
||||
Reference in New Issue
Block a user