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 } // 生成账单 err = q.Bill.Create(newForRecharge(uid, Bill.GenNo(), info.GetSubject(), info.GetAmount(), 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) (err error) { // 更新余额 user, err := q.User. Where(q.User.ID.Eq(uid)).Take() if err != nil { return core.NewServErr("查询用户失败", err) } var amount = user.Balance.Add(info.GetAmount()) if amount.IsNegative() { return core.NewServErr("用户余额不足") } _, err = q.User. Where(q.User.ID.Eq(user.ID)). UpdateSimple(q.User.Balance.Value(amount)) 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 { return fmt.Sprintf("账户充值 - %s元", r.GetAmount().StringFixed(2)) } func (r *RechargeProductInfo) GetAmount() decimal.Decimal { return decimal.NewFromInt(int64(r.Amount)).Div(decimal.NewFromInt(100)) } 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) }