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" md2 "code.fnuoos.com/EggPlanet/egg_system_rules.git/rule/egg_energy/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" "strconv" "time" "xorm.io/xorm" ) // DealUserVirtualCoin 处理给用户虚拟币积分 func DealUserVirtualCoin(session *xorm.Session, req md.DealUserVirtualCoinReq) (err error) { if req.Amount < 0 { req.Amount = 0 } //1、分布式锁阻拦 requestIdPrefix := fmt.Sprintf(md2.DealUserCoinRequestIdPrefix, req.CoinId, req.Uid) cb, err := svc.HandleDistributedLock(zhios_order_relate_utils.Int64ToStr(req.Uid), strconv.Itoa(req.CoinId), requestIdPrefix) if err != nil { return err } if cb != nil { defer cb() // 释放锁 } //2、计算&&组装数据 now := time.Now() coinAmount, err := GetUserCoinAmount(session, req.CoinId, req.Uid) if err != nil { return err } coinAmountValue := decimal.NewFromFloat(zhios_order_relate_utils.StrToFloat64(coinAmount)) amountValue := decimal.NewFromFloat(req.Amount).RoundFloor(4) var userVirtualCoinFlow model.UserVirtualCoinFlow userVirtualCoinFlow.CoinId = req.CoinId userVirtualCoinFlow.Title = req.Title userVirtualCoinFlow.TransferType = req.TransferType userVirtualCoinFlow.Uid = req.Uid userVirtualCoinFlow.BeforeAmount = coinAmount userVirtualCoinFlow.Amount = amountValue.String() userVirtualCoinFlow.CreateAt = now.Format("2006-01-02 15:04:05") if req.Kind == "add" { userVirtualCoinFlow.Direction = 1 userVirtualCoinFlow.AfterAmount = coinAmountValue.Add(amountValue).RoundFloor(8).String() } else if req.Kind == "sub" { userVirtualCoinFlow.Direction = 2 userVirtualCoinFlow.AfterAmount = coinAmountValue.Sub(amountValue).RoundFloor(8).String() if zhios_order_relate_utils.StrToFloat64(userVirtualCoinFlow.AfterAmount) < 0 { var coin model.VirtualCoin _, err = session.Where("id = ?", req.CoinId).Get(&coin) if err != nil { return err } zhios_order_relate_utils.FilePutContents("virtual_coin_not", zhios_order_relate_utils.SerializeStr(map[string]interface{}{ "uid": userVirtualCoinFlow.Uid, "amount": userVirtualCoinFlow.Amount, "before_amount": userVirtualCoinFlow.BeforeAmount, "after_amount": userVirtualCoinFlow.AfterAmount, "coin_id": userVirtualCoinFlow.CoinId, })) return errors.New("用户" + zhios_order_relate_utils.Int64ToStr(userVirtualCoinFlow.Uid) + "的" + coin.Name + "不足") } } else { err = errors.New("错误的kind类型") return err } //3、插入 `user_virtual_coin_flow` 记录 userVirtualCoinFlowDb := implement.NewUserVirtualCoinFlowDb(session.Engine()) _, err = userVirtualCoinFlowDb.UserVirtualCoinFlowInsertBySession(session, &userVirtualCoinFlow) if err != nil { return err } //4、修改 `user_virtual_amount`的amount值 && 及缓存 err = SetCacheUserVirtualAmount(session, userVirtualCoinFlow.AfterAmount, req.CoinId, req.Uid, true) if err != nil { return err } return nil } // GetUserCoinAmount 获取用户虚拟积分余额 func GetUserCoinAmount(session *xorm.Session, coinId int, uid int64) (amount string, err error) { redisKey := fmt.Sprintf(md.UserVirtualAmountRedisKey, coinId, uid) amount, err = cache.GetString(redisKey) if err != nil { if err.Error() == "redigo: nil returned" { userVirtualAmountDb := implement.NewUserVirtualAmountDb(session.Engine()) userVirtualAmount, err := userVirtualAmountDb.GetUserVirtualWalletBySession(uid, coinId) if err != nil { return amount, err } if userVirtualAmount == nil { amount = "0" } else { amount = userVirtualAmount.Amount } //将获取到的余额值缓存至redis _ = SetCacheUserVirtualAmount(session, amount, coinId, uid, false) return amount, nil } return amount, err } return amount, nil } // SetCacheUserVirtualAmount 设置缓存的用户虚拟币积分余额 func SetCacheUserVirtualAmount(session *xorm.Session, amount string, coinId int, uid int64, isUpdateDb bool) error { redisKey := fmt.Sprintf(md.UserVirtualAmountRedisKey, coinId, uid) if isUpdateDb { _, err := session.Where("uid=?", uid).And("coin_id=?", coinId).Update(model.UserVirtualAmount{ Uid: uid, CoinId: coinId, 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 }