package rule import ( "code.fnuoos.com/EggPlanet/egg_models.git/src/implement" "code.fnuoos.com/EggPlanet/egg_models.git/src/model" zhios_order_relate_utils "code.fnuoos.com/EggPlanet/egg_models.git/utils" "code.fnuoos.com/EggPlanet/egg_system_rules.git/md" "code.fnuoos.com/EggPlanet/egg_system_rules.git/svc" "code.fnuoos.com/EggPlanet/egg_system_rules.git/utils/cache" "errors" "fmt" "github.com/shopspring/decimal" "time" "xorm.io/xorm" ) // DealUserWallet 处理给用户金额 func DealUserWallet(session *xorm.Session, req md.DealUserWalletReq) (err error) { if req.Amount < 0 { req.Amount = 0 } //1、分布式锁阻拦 requestIdPrefix := fmt.Sprintf(md.UserWalletRedisKey, req.Uid) cb, err := svc.HandleDistributedLockForUserWallet(zhios_order_relate_utils.Int64ToStr(req.Uid), requestIdPrefix) if err != nil { return err } if cb != nil { defer cb() // 释放锁 } //2、计算&&组装数据 now := time.Now() userAmount, err := GetUserWalletAmount(session, req.Uid) if err != nil { return err } amountValue := decimal.NewFromFloat(req.Amount).RoundFloor(4) beforeAmountValue, _ := decimal.NewFromString(userAmount) var userWalletFlow model.UserWalletFlow userWalletFlow.Uid = req.Uid userWalletFlow.Title = req.Title userWalletFlow.Kind = req.Kind userWalletFlow.BeforeAmount = userAmount userWalletFlow.Amount = amountValue.String() userWalletFlow.CreateAt = now.Format("2006-01-02 15:04:05") if req.Direction == "add" { userWalletFlow.Direction = 1 userWalletFlow.AfterAmount = beforeAmountValue.Add(amountValue).RoundFloor(2).String() } else if req.Direction == "sub" { userWalletFlow.Direction = 2 userWalletFlow.AfterAmount = beforeAmountValue.Sub(amountValue).RoundFloor(2).String() if zhios_order_relate_utils.StrToFloat64(userWalletFlow.AfterAmount) < 0 { return errors.New("用户钱包余额不足") } } else { err = errors.New("错误的Direction类型") return err } //3、插入 `user_wallet_flow` 记录 userWalletFlowDb := implement.NewUserWalletFlowDb(session.Engine()) _, err = userWalletFlowDb.UserWalletFlowInsertBySession(session, &userWalletFlow) if err != nil { return err } //4、修改 `user_wallet`的amount值 && 及缓存 err = SetUserWalletAmount(session, userWalletFlow.AfterAmount, req.Uid, true) if err != nil { return err } return nil } // GetUserWalletAmount 获取用户钱包余额 func GetUserWalletAmount(session *xorm.Session, uid int64) (amount string, err error) { redisKey := fmt.Sprintf(md.UserWalletRedisKey, uid) amount, err = cache.GetString(redisKey) if err != nil { if err.Error() == "redigo: nil returned" { userWalletDb := implement.NewUserWalletDb(session.Engine()) userVirtualAmount, err := userWalletDb.GetUserVirtualWallet(uid) if err != nil { return amount, err } if userVirtualAmount == nil { amount = "0" } else { amount = userVirtualAmount.Amount } //将获取到的余额值缓存至redis _ = SetUserWalletAmount(session, amount, uid, false) return amount, nil } return amount, err } return amount, nil } // SetUserWalletAmount 设置缓存的用户虚拟币积分余额 func SetUserWalletAmount(session *xorm.Session, amount string, uid int64, isUpdateDb bool) error { redisKey := fmt.Sprintf(md.UserWalletRedisKey, uid) if isUpdateDb { _, err := session.Where("uid=?", uid).Update(model.UserWallet{ Uid: uid, Amount: amount, }) if err != nil { return err } } //TODO::默认缓存1小时 (先调整为 20 min) _, err := cache.SetEx(redisKey, zhios_order_relate_utils.StrToFloat64(amount), 60*20) if err != nil { return err } return nil }