package services import ( "encoding/json" "fmt" "platform/web/core" g "platform/web/globals" m "platform/web/models" q "platform/web/queries" "github.com/shopspring/decimal" ) var User = &userService{} type userService struct{} func (s *userService) UpdateBalanceByTrade(uid int32, info *RechargeProductInfo, trade *m.Trade) (err error) { err = g.Redsync.WithLock(userBalanceKey(uid), func() error { return q.Q.Transaction(func(q *q.Query) error { err = updateBalance(q, uid, info) if err != nil { return err } // 生成账单 subject, err := info.GetSubject() if err != nil { return err } amount, err := info.GetAmount() if err != nil { return err } err = q.Bill.Create(newForRecharge(uid, Bill.GenNo(), subject, amount, trade)) if err != nil { return core.NewServErr("生成账单失败", err) } return nil }) }) if err != nil { return core.NewServErr("更新用户余额失败") } return nil } func updateBalance(q *q.Query, uid int32, info *RechargeProductInfo) error { user, err := q.User. Where(q.User.ID.Eq(uid)).Take() if err != nil { return core.NewServErr("查询用户失败", err) } amount, err := info.GetAmount() if err != nil { return err } balance := user.Balance.Add(amount) if balance.IsNegative() { return core.NewServErr("用户余额不足") } _, err = q.User. Where(q.User.ID.Eq(user.ID)). UpdateSimple(q.User.Balance.Value(balance)) if err != nil { return core.NewServErr("更新用户余额失败", err) } return nil } func userBalanceKey(uid int32) string { return fmt.Sprintf("user:%d:balance", uid) } type RechargeProductInfo struct { Amount int `json:"amount"` } func (r *RechargeProductInfo) GetType() m.TradeType { return m.TradeTypeRecharge } func (r *RechargeProductInfo) GetSubject() (string, error) { amount, _ := r.GetAmount() return fmt.Sprintf("账户充值 - %s元", amount.StringFixed(2)), nil } func (r *RechargeProductInfo) GetAmount() (decimal.Decimal, error) { return decimal.NewFromInt(int64(r.Amount)).Div(decimal.NewFromInt(100)), nil } func (r *RechargeProductInfo) Serialize() (string, error) { bytes, err := json.Marshal(r) return string(bytes), err } func (r *RechargeProductInfo) Deserialize(str string) error { return json.Unmarshal([]byte(str), r) } type UserOnTradeComplete struct{} func (u UserOnTradeComplete) Check(t m.TradeType) (ProductInfo, bool) { if t == m.TradeTypeRecharge { return &RechargeProductInfo{}, true } return nil, false } func (u UserOnTradeComplete) OnTradeComplete(info ProductInfo, trade *m.Trade) error { return User.UpdateBalanceByTrade(trade.UserID, info.(*RechargeProductInfo), trade) }