package services import ( "encoding/json" "fmt" "github.com/shopspring/decimal" "platform/web/core" bill2 "platform/web/domains/bill" trade2 "platform/web/domains/trade" g "platform/web/globals" m "platform/web/models" q "platform/web/queries" ) 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(bill2.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() trade2.Type { return trade2.TypeRecharge } func (r *RechargeProductInfo) GetSubject() string { return fmt.Sprintf("账户充值 - " + 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 trade2.Type) (trade2.ProductInfo, bool) { if t == trade2.TypeRecharge { return &RechargeProductInfo{}, true } return nil, false } func (u UserOnTradeComplete) OnTradeComplete(info trade2.ProductInfo, trade *m.Trade) error { return User.UpdateBalanceByTrade(trade.UserID, info.(*RechargeProductInfo), trade) }