package entities import ( "fmt" "time" "github.com/google/uuid" "github.com/shopspring/decimal" "gorm.io/gorm" ) // Wallet 钱包聚合根 // 用户数字钱包的核心信息,支持多种钱包类型和精确的余额管理 // 使用decimal类型确保金额计算的精确性,避免浮点数精度问题 // 支持欠费(余额<0),但只允许扣到小于0一次,之后不能再扣 // 新建钱包时可配置默认额度 type Wallet struct { // 基础标识 ID string `gorm:"primaryKey;type:varchar(36)" json:"id" comment:"钱包唯一标识"` UserID string `gorm:"type:varchar(36);not null;uniqueIndex" json:"user_id" comment:"关联用户ID"` // 钱包状态 - 钱包的基本状态信息 IsActive bool `gorm:"default:true" json:"is_active" comment:"钱包是否激活"` Balance decimal.Decimal `gorm:"type:decimal(20,8);default:0" json:"balance" comment:"钱包余额(精确到8位小数)"` Version int64 `gorm:"default:0" json:"version" comment:"乐观锁版本号"` // 时间戳字段 CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at" comment:"创建时间"` UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at" comment:"更新时间"` DeletedAt gorm.DeletedAt `gorm:"index" json:"-" comment:"软删除时间"` } // TableName 指定数据库表名 func (Wallet) TableName() string { return "wallets" } // IsZeroBalance 检查余额是否为零 func (w *Wallet) IsZeroBalance() bool { return w.Balance.IsZero() } // HasSufficientBalance 检查是否有足够余额(允许透支额度) func (w *Wallet) HasSufficientBalance(amount decimal.Decimal) bool { // 允许扣到额度下限 return w.Balance.Sub(amount).GreaterThanOrEqual(decimal.Zero) } // IsArrears 是否欠费(余额<0) func (w *Wallet) IsArrears() bool { return w.Balance.LessThan(decimal.Zero) } // IsLowBalance 是否余额较低(余额<300) func (w *Wallet) IsLowBalance() bool { return w.Balance.LessThan(decimal.NewFromInt(300)) } // GetBalanceStatus 获取余额状态 func (w *Wallet) GetBalanceStatus() string { if w.IsArrears() { return "arrears" // 欠费 } else if w.IsLowBalance() { return "low" // 余额较低 } else { return "normal" // 正常 } } // AddBalance 增加余额(只做加法,业务规则由服务层控制是否允许充值) func (w *Wallet) AddBalance(amount decimal.Decimal) { w.Balance = w.Balance.Add(amount) } // SubtractBalance 扣减余额,含欠费业务规则 func (w *Wallet) SubtractBalance(amount decimal.Decimal) error { if w.Balance.LessThan(decimal.Zero) { return fmt.Errorf("已欠费,不能再扣款") } newBalance := w.Balance.Sub(amount) w.Balance = newBalance return nil } // GetFormattedBalance 获取格式化的余额字符串 func (w *Wallet) GetFormattedBalance() string { return w.Balance.String() } // BeforeCreate GORM钩子:创建前自动生成UUID func (w *Wallet) BeforeCreate(tx *gorm.DB) error { if w.ID == "" { w.ID = uuid.New().String() } return nil } // NewWallet 工厂方法 func NewWallet(userID string, defaultCreditLimit decimal.Decimal) *Wallet { return &Wallet{ UserID: userID, IsActive: true, Balance: defaultCreditLimit, Version: 0, } }