核心变更: - 钱包表:删除 user_id,添加 resource_type/resource_id(绑定资源而非用户) - 标签表:添加 enterprise_id/shop_id(实现三级隔离:全局/企业/店铺) - GORM Callback:自动数据权限过滤 - 迁移脚本:可重复执行,已验证回滚功能 钱包归属重构原因: - 旧设计:钱包绑定用户账号,个人客户卡/设备转手后新用户无法使用余额 - 新设计:钱包绑定资源(卡/设备/店铺),余额随资源流转 标签三级隔离: - 平台全局标签:所有用户可见 - 企业标签:仅该企业可见(企业内唯一) - 店铺标签:该店铺及下级可见(店铺内唯一) 测试覆盖: - 9 个单元测试验证标签多租户过滤(全部通过) - 迁移和回滚功能测试通过(测试环境) - OpenSpec 验证通过 变更 ID: fix-wallet-tag-multi-tenant 迁移版本: 000008 参考: openspec/changes/archive/2026-01-13-fix-wallet-tag-multi-tenant/
100 lines
6.0 KiB
Go
100 lines
6.0 KiB
Go
package model
|
||
|
||
import (
|
||
"database/sql/driver"
|
||
"encoding/json"
|
||
"time"
|
||
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// Wallet 钱包模型
|
||
// 个人客户和代理商的资金账户,支持充值、消费、提现等操作
|
||
// 使用乐观锁(version字段)防止并发余额冲突
|
||
// 钱包归属资源(卡/设备/店铺),支持资源转手场景
|
||
type Wallet struct {
|
||
gorm.Model
|
||
BaseModel `gorm:"embedded"`
|
||
ResourceType string `gorm:"column:resource_type;type:varchar(20);not null;uniqueIndex:idx_wallet_resource_type_currency,priority:1;index:idx_wallet_resource,priority:1;comment:资源类型 iot_card-物联网卡 device-设备 shop-店铺" json:"resource_type"`
|
||
ResourceID uint `gorm:"column:resource_id;not null;uniqueIndex:idx_wallet_resource_type_currency,priority:2;index:idx_wallet_resource,priority:2;comment:资源ID" json:"resource_id"`
|
||
WalletType string `gorm:"column:wallet_type;type:varchar(20);not null;uniqueIndex:idx_wallet_resource_type_currency,priority:3;comment:钱包类型 main-主钱包 commission-分佣钱包" json:"wallet_type"`
|
||
Balance int64 `gorm:"column:balance;type:bigint;not null;default:0;comment:余额(分)" json:"balance"`
|
||
FrozenBalance int64 `gorm:"column:frozen_balance;type:bigint;not null;default:0;comment:冻结余额(分)" json:"frozen_balance"`
|
||
Currency string `gorm:"column:currency;type:varchar(10);not null;default:'CNY';uniqueIndex:idx_wallet_resource_type_currency,priority:4;comment:币种" json:"currency"`
|
||
Status int `gorm:"column:status;type:int;not null;default:1;index:idx_wallet_status;comment:钱包状态 1-正常 2-冻结 3-关闭" json:"status"`
|
||
Version int `gorm:"column:version;type:int;not null;default:0;comment:版本号(乐观锁)" json:"version"`
|
||
}
|
||
|
||
// TableName 指定表名
|
||
func (Wallet) TableName() string {
|
||
return "tb_wallet"
|
||
}
|
||
|
||
// WalletMetadata 钱包交易扩展信息
|
||
// 用于存储交易相关的额外数据(JSONB格式)
|
||
type WalletMetadata map[string]interface{}
|
||
|
||
// Value 实现 driver.Valuer 接口
|
||
func (m WalletMetadata) Value() (driver.Value, error) {
|
||
return json.Marshal(m)
|
||
}
|
||
|
||
// Scan 实现 sql.Scanner 接口
|
||
func (m *WalletMetadata) Scan(value interface{}) error {
|
||
if value == nil {
|
||
*m = make(WalletMetadata)
|
||
return nil
|
||
}
|
||
bytes, ok := value.([]byte)
|
||
if !ok {
|
||
return nil
|
||
}
|
||
return json.Unmarshal(bytes, m)
|
||
}
|
||
|
||
// WalletTransaction 钱包交易记录模型
|
||
// 记录所有钱包余额变动,包含变动前后余额用于对账
|
||
// 支持关联业务对象(订单、分佣、提现等)
|
||
type WalletTransaction struct {
|
||
gorm.Model
|
||
WalletID uint `gorm:"column:wallet_id;not null;index:idx_wallet_tx_wallet;comment:钱包ID" json:"wallet_id"`
|
||
UserID uint `gorm:"column:user_id;not null;index:idx_wallet_tx_user;comment:用户ID" json:"user_id"`
|
||
TransactionType string `gorm:"column:transaction_type;type:varchar(20);not null;comment:交易类型 recharge-充值 deduct-扣款 refund-退款 commission-分佣 withdrawal-提现" json:"transaction_type"`
|
||
Amount int64 `gorm:"column:amount;type:bigint;not null;comment:变动金额(分)正数为增加 负数为减少" json:"amount"`
|
||
BalanceBefore int64 `gorm:"column:balance_before;type:bigint;not null;comment:变动前余额(分)" json:"balance_before"`
|
||
BalanceAfter int64 `gorm:"column:balance_after;type:bigint;not null;comment:变动后余额(分)" json:"balance_after"`
|
||
Status int `gorm:"column:status;type:int;not null;default:1;comment:交易状态 1-成功 2-失败 3-处理中" json:"status"`
|
||
ReferenceType *string `gorm:"column:reference_type;type:varchar(50);index:idx_wallet_tx_ref,priority:1;comment:关联业务类型 order/commission/withdrawal/topup" json:"reference_type,omitempty"`
|
||
ReferenceID *uint `gorm:"column:reference_id;type:bigint;index:idx_wallet_tx_ref,priority:2;comment:关联业务ID" json:"reference_id,omitempty"`
|
||
Remark *string `gorm:"column:remark;type:text;comment:备注" json:"remark,omitempty"`
|
||
Metadata WalletMetadata `gorm:"column:metadata;type:jsonb;comment:扩展信息" json:"metadata,omitempty"`
|
||
Creator uint `gorm:"column:creator;comment:创建人ID" json:"creator"`
|
||
}
|
||
|
||
// TableName 指定表名
|
||
func (WalletTransaction) TableName() string {
|
||
return "tb_wallet_transaction"
|
||
}
|
||
|
||
// RechargeRecord 充值记录模型
|
||
// 用户和代理的钱包充值订单,记录支付流程和状态
|
||
type RechargeRecord struct {
|
||
gorm.Model
|
||
BaseModel `gorm:"embedded"`
|
||
UserID uint `gorm:"column:user_id;not null;index:idx_recharge_user;comment:用户ID" json:"user_id"`
|
||
WalletID uint `gorm:"column:wallet_id;not null;comment:钱包ID" json:"wallet_id"`
|
||
RechargeNo string `gorm:"column:recharge_no;type:varchar(50);not null;uniqueIndex:idx_recharge_no;comment:充值订单号" json:"recharge_no"`
|
||
Amount int64 `gorm:"column:amount;type:bigint;not null;comment:充值金额(分)" json:"amount"`
|
||
PaymentMethod string `gorm:"column:payment_method;type:varchar(20);not null;comment:支付方式 alipay-支付宝 wechat-微信 bank-银行转账 offline-线下" json:"payment_method"`
|
||
PaymentChannel *string `gorm:"column:payment_channel;type:varchar(50);comment:支付渠道" json:"payment_channel,omitempty"`
|
||
PaymentTransactionID *string `gorm:"column:payment_transaction_id;type:varchar(100);comment:第三方支付交易号" json:"payment_transaction_id,omitempty"`
|
||
Status int `gorm:"column:status;type:int;not null;default:1;index:idx_recharge_status;comment:充值状态 1-待支付 2-已支付 3-已完成 4-已关闭 5-已退款" json:"status"`
|
||
PaidAt *time.Time `gorm:"column:paid_at;comment:支付时间" json:"paid_at,omitempty"`
|
||
CompletedAt *time.Time `gorm:"column:completed_at;comment:完成时间" json:"completed_at,omitempty"`
|
||
}
|
||
|
||
// TableName 指定表名
|
||
func (RechargeRecord) TableName() string {
|
||
return "tb_recharge_record"
|
||
}
|