415 lines
14 KiB
Go
415 lines
14 KiB
Go
package active2023ser
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"91porn-server/app/appg"
|
|
"91porn-server/common/db"
|
|
"91porn-server/models/commod"
|
|
"91porn-server/models/v/active2023mod"
|
|
"91porn-server/models/v/goldextramod"
|
|
"91porn-server/models/v/prdcthsomod"
|
|
"91porn-server/models/v/productmod"
|
|
"91porn-server/models/v/txnmod"
|
|
"91porn-server/models/v/usermod"
|
|
"91porn-server/models/v/videocoupon"
|
|
"91porn-server/models/v/videodiscountmod"
|
|
"91porn-server/models/v/walletmod"
|
|
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
)
|
|
|
|
func Lottery(userInfo *usermod.User, req LotteryReq) error {
|
|
wallet, err := walletmod.GetWallet(userInfo.UID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if wallet == nil {
|
|
return errors.New("钱包信息未找到")
|
|
}
|
|
isLottery := true // 默认为抽奖
|
|
desc := "2023新春抽奖"
|
|
if req.Gold == 0 && req.Count == 0 { // 不使用免费抽奖次数又不消耗金币, 则为领取保底福利
|
|
isLottery = false
|
|
desc = "2023新春福利"
|
|
}
|
|
return appg.VideoDB.Trans(func(t *db.MongoTool) error {
|
|
var transactionLogs []txnmod.TransactionLog // 用户所有抽奖花费金, 获奖金币以及游戏币发放记录
|
|
if isLottery {
|
|
if req.Gold == 0 { // 使用免费抽奖次数
|
|
if err = active2023mod.UseLotteryCountFree(t, int64(userInfo.UID), int64(req.Count)); err != nil {
|
|
return err
|
|
}
|
|
} else { // 使用金币抽奖
|
|
if err = walletmod.DebitAmountDefault(t, int64(userInfo.UID), int64(req.Gold)); err != nil {
|
|
return err
|
|
}
|
|
wallet.Amount -= int64(req.Gold)
|
|
if err = active2023mod.UserLotteryCountPay(t, int64(userInfo.UID), int64(req.Count)); err != nil {
|
|
return err
|
|
}
|
|
transactionType := txnmod.Active2023Cost
|
|
transactionLogs = []txnmod.TransactionLog{txnmod.TransactionLog{
|
|
TransNo: primitive.NewObjectID(),
|
|
UID: userInfo.UID,
|
|
Amount: -int64(req.Gold),
|
|
ActualAmount: -float64(req.Gold),
|
|
TranType: transactionType.Key(),
|
|
TranTypeInt: int64(transactionType),
|
|
Desc: fmt.Sprintf("%s-金币[%d个]", transactionType.Key(), req.Gold),
|
|
RealAmount: walletmod.GetRealAmount(wallet),
|
|
}}
|
|
}
|
|
}
|
|
var totalGold, totalVipDates uint64 // totalGold: 用户总获奖金币数; totalVipDates: 用户总获奖vip天数
|
|
var pzs []active2023mod.Prize // 用户所有奖励, 用以存库
|
|
var videoCoupons []videocoupon.UserGoldVideoCoupon // 用户所有获视频折扣券
|
|
var goldExtras []goldextramod.GoldExtra // 用户所有获奖金币加购券
|
|
var videoDiscounts []productmod.Product // 用户所有获奖视频折扣券
|
|
var vipCards []productmod.Product // 用户所有获奖vip卡
|
|
now := time.Now()
|
|
pzs = make([]active2023mod.Prize, len(req.Prizes))
|
|
for i, pz := range req.Prizes {
|
|
pzs[i] = active2023mod.Prize{
|
|
UID: int64(userInfo.UID),
|
|
Type: int64(pz.Type),
|
|
Name: pz.Name,
|
|
Unit: int64(pz.Price),
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
switch pz.Type {
|
|
case active2023mod.PrizeTypeGold: // 金币
|
|
if pz.Price <= 0 {
|
|
return errors.New("金币数量设置错误")
|
|
}
|
|
totalGold += pz.Price
|
|
transactionType := txnmod.Active2023Reward
|
|
wallet.Amount += int64(pz.Price)
|
|
transactionLogs = append(transactionLogs, txnmod.TransactionLog{
|
|
TransNo: primitive.NewObjectID(),
|
|
UID: userInfo.UID,
|
|
Amount: int64(pz.Price),
|
|
ActualAmount: float64(pz.Price),
|
|
TranType: transactionType.Key(),
|
|
TranTypeInt: int64(transactionType),
|
|
Desc: fmt.Sprintf("%s-金币[%d个]", transactionType.Key(), pz.Price),
|
|
RealAmount: walletmod.GetRealAmount(wallet),
|
|
})
|
|
case active2023mod.PrizeTypeGameGold: // 游戏币
|
|
return errors.New("瓦力游戏已下架")
|
|
case active2023mod.PrizeTypeProduct: // 现有产品
|
|
if pz.Param1 == "" {
|
|
return errors.New("产品id为空")
|
|
}
|
|
productID, err := primitive.ObjectIDFromHex(pz.Param1)
|
|
if err != nil {
|
|
return errors.New("无效的产品id")
|
|
}
|
|
p, err := productmod.FindProduct(productID, "")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if p == nil {
|
|
return errors.New("产品不存在")
|
|
}
|
|
pzs[i].ProductID = &productID
|
|
switch p.ProductType {
|
|
case commod.VideoDiscount: // 视频折扣卡
|
|
videoDiscounts = append(videoDiscounts, *p)
|
|
case commod.VIP: // 会员卡
|
|
vipCards = append(vipCards, *p)
|
|
default:
|
|
return errors.New("不支持的产品类型")
|
|
}
|
|
case active2023mod.PrizeTypeVIPDate: // 会员日期
|
|
if pz.Price <= 0 {
|
|
return errors.New("vip天数设置错误")
|
|
}
|
|
transactionType := txnmod.Active2023Reward
|
|
transactionLogs = append(transactionLogs, txnmod.TransactionLog{
|
|
UID: userInfo.UID,
|
|
Amount: 0,
|
|
ActualAmount: 0,
|
|
TranType: transactionType.Key(),
|
|
TranTypeInt: int64(transactionType),
|
|
TransNo: primitive.NilObjectID,
|
|
Desc: fmt.Sprintf("%s获得VIP天数%d天", desc, pz.Price),
|
|
DiscDoc: userInfo.DiscDoc,
|
|
SysType: userInfo.SysType,
|
|
RealAmount: walletmod.GetRealAmount(wallet),
|
|
})
|
|
totalVipDates += pz.Price
|
|
case active2023mod.PrizeTypeGoldCoinBonus: // 金币加赠券
|
|
if pz.Price <= 0 {
|
|
return errors.New("金币加赠券面值设置错误")
|
|
}
|
|
expired := now.Add(time.Hour * 24 * 7) // 默认一周过期
|
|
if pz.ValidDate > 0 {
|
|
expired = now.Add(time.Hour * 24 * time.Duration(pz.ValidDate))
|
|
}
|
|
goldExtras = append(goldExtras, goldextramod.GoldExtra{
|
|
Uid: userInfo.UID,
|
|
Name: "金币加赠券",
|
|
Amount: pz.Price,
|
|
Expired: expired,
|
|
Used: false,
|
|
Desc: "充值加送金币",
|
|
Source: desc,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
})
|
|
case active2023mod.PrizeTypeGoldWatch: // 金币观影券
|
|
if pz.Price <= 0 {
|
|
return errors.New("会员观影券面值设置错误")
|
|
}
|
|
videoCoupons = append(videoCoupons, videocoupon.UserGoldVideoCoupon{
|
|
UID: userInfo.UID,
|
|
Num: int(pz.Price),
|
|
Source: videocoupon.GoldVideoCouponSource(desc),
|
|
Used: false,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
})
|
|
case active2023mod.PrizeTypeInKind: // 实物奖励
|
|
default:
|
|
return fmt.Errorf("不支持的奖品类型: %d", pz.Type)
|
|
}
|
|
}
|
|
needRefreshUserCache := false
|
|
if totalGold > 0 {
|
|
if wallet, err = walletmod.CreditAmount(t, int64(totalGold), userInfo.UID); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if totalVipDates > 0 {
|
|
vipLevel := 1 // 默认vip等级为1
|
|
start := time.Now()
|
|
discount := userInfo.PayVidDiscount
|
|
if userInfo.VipExpireDate.After(start) { // 如果用户VIP未过期, 则VIP等级和视频折扣等级需要参考用户现在的情况
|
|
start = userInfo.VipExpireDate
|
|
if userInfo.VipLevel > vipLevel {
|
|
vipLevel = userInfo.VipLevel
|
|
}
|
|
}
|
|
vipExpireDate := start.Add(time.Hour * 24 * time.Duration(totalVipDates))
|
|
sel := usermod.UserSelector{VipExpireDate: &vipExpireDate, VipLevel: &vipLevel, PayVidDiscount: &discount}
|
|
if err := usermod.UpdateVIP(t, userInfo.UID, userInfo.VipExpireDate, sel); err != nil {
|
|
return err
|
|
}
|
|
userInfo.VipExpireDate = vipExpireDate
|
|
userInfo.VipLevel = vipLevel
|
|
needRefreshUserCache = true
|
|
}
|
|
if len(videoCoupons) > 0 {
|
|
if err = videocoupon.InsertManyTrans(t, videoCoupons); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if len(transactionLogs) > 0 {
|
|
if err = txnmod.InsertManyTransactionLog(t, transactionLogs); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if len(goldExtras) > 0 {
|
|
if err = goldextramod.InsertGoldExtras(t, &goldExtras); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if len(videoDiscounts) > 0 {
|
|
if err = dealVideoDiscardCards(t, userInfo, videoDiscounts, desc); err != nil {
|
|
return err
|
|
}
|
|
needRefreshUserCache = true
|
|
}
|
|
if len(vipCards) > 0 {
|
|
if err = dealVipCards(t, userInfo, vipCards, desc); err != nil {
|
|
return err
|
|
}
|
|
needRefreshUserCache = true
|
|
}
|
|
ids, err := active2023mod.InsertUserPrizes(t, &pzs)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := active2023mod.InsertUserLottery(t, &active2023mod.UserLottery{
|
|
UID: int64(userInfo.UID),
|
|
Count: int64(req.Count),
|
|
UseGold: int64(req.Gold),
|
|
Prizes: ids,
|
|
Desc: desc,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
if needRefreshUserCache {
|
|
go func() { _, _ = usermod.RefreshCacheAndGetUser(userInfo.UID) }()
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func dealVideoDiscardCards(t *db.MongoTool, userInfo *usermod.User, products []productmod.Product, desc string) error {
|
|
productIDsLen := len(products)
|
|
if productIDsLen == 0 {
|
|
return nil
|
|
}
|
|
videoDiscountLog, err := videodiscountmod.GetByUID(userInfo.UID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// 最终过期时间
|
|
var videoDiscountTotal int // 最终折扣
|
|
var totalDates int // 总增加天数
|
|
// 所有视频折扣卡都加入日志
|
|
// 计算出最后用户的折扣和过期时间, 只更新一次用户配置
|
|
if videoDiscountLog != (videodiscountmod.VideoDiscountLog{}) { // 当存在用户配置时, 需要跟用户配置做对比
|
|
if videoDiscountLog.VideoDiscount > 0 && videoDiscountLog.VideoDiscount < 10 { // 如果用户有有效现有折扣
|
|
videoDiscountTotal = videoDiscountLog.VideoDiscount // 默认折扣取用户折扣
|
|
}
|
|
}
|
|
productHistorys := make([]prdcthsomod.ProductHistory, productIDsLen)
|
|
transactionLogs := make([]txnmod.TransactionLog, productIDsLen)
|
|
for i, p := range products {
|
|
// 查找视频折扣卡详情
|
|
if p.Duration <= 0 || p.VideoDiscount >= 10 || p.VideoDiscount <= 0 {
|
|
return errors.New("视频折扣卡配置不正确")
|
|
}
|
|
// 添加记录
|
|
historyID := primitive.NewObjectID()
|
|
productHistorys[i] = prdcthsomod.ProductHistory{
|
|
ID: historyID,
|
|
UID: userInfo.UID,
|
|
ProductID: p.ID,
|
|
Name: p.Name,
|
|
ProductType: commod.VideoDiscount,
|
|
DiscDoc: userInfo.DiscDoc,
|
|
SysType: userInfo.SysType,
|
|
ProductSnapShot: &p,
|
|
}
|
|
transactionLogs[i] = txnmod.TransactionLog{
|
|
UID: userInfo.UID,
|
|
Amount: -p.DiscountedPrice,
|
|
ActualAmount: 0,
|
|
TranType: txnmod.VideoDiscount.Key(),
|
|
TranTypeInt: int64(txnmod.VideoDiscount),
|
|
TransNo: historyID,
|
|
Desc: desc + "获得-" + p.Name,
|
|
DiscDoc: userInfo.DiscDoc,
|
|
SysType: userInfo.SysType,
|
|
}
|
|
if p.Duration <= 0 {
|
|
p.Duration = 7 // 如果没有设置有效过期时间, 则默认为7天
|
|
}
|
|
totalDates += p.Duration
|
|
videoDiscount := p.VideoDiscount // 默认折扣: 产品折扣
|
|
// 最终取折扣值比较小的(折扣值越小说明享受的折扣越大)
|
|
if videoDiscountTotal == 0 {
|
|
videoDiscountTotal = videoDiscount
|
|
} else if videoDiscountTotal > videoDiscount {
|
|
videoDiscountTotal = videoDiscount
|
|
}
|
|
}
|
|
// 写入历史纪录
|
|
if err = prdcthsomod.InsertManyProductHistory(t, productHistorys); err != nil {
|
|
return err
|
|
}
|
|
if err = txnmod.InsertManyTransactionLog(t, transactionLogs); err != nil {
|
|
return err
|
|
}
|
|
now := time.Now()
|
|
start := now
|
|
if videoDiscountLog != (videodiscountmod.VideoDiscountLog{}) { // 当存在用户配置时, 需要跟用户配置做对比
|
|
if videoDiscountLog.Expiration.After(now) { // 如果用户现有折扣未过期, 则过期时间从用户现有折扣过期时间算起去加折扣卡有效期
|
|
start = videoDiscountLog.Expiration
|
|
}
|
|
}
|
|
expireAt := start.Add(time.Hour * 24 * time.Duration(totalDates))
|
|
// 修改用户折扣
|
|
set := videodiscountmod.EditSelector{
|
|
UID: &userInfo.UID,
|
|
Expiration: &expireAt,
|
|
VideoDiscount: &videoDiscountTotal,
|
|
}
|
|
return videodiscountmod.Upsert(t, &set)
|
|
}
|
|
|
|
// 抽奖中的vip卡只计算等级, 天数和视频折扣三种权益
|
|
// 不计算vip卡配置中附赠的金币和游戏币
|
|
func dealVipCards(t *db.MongoTool, userInfo *usermod.User, products []productmod.Product, desc string) error {
|
|
productIDsLen := len(products)
|
|
if productIDsLen == 0 {
|
|
return nil
|
|
}
|
|
productHistorys := make([]prdcthsomod.ProductHistory, productIDsLen)
|
|
transactionLogs := make([]txnmod.TransactionLog, productIDsLen)
|
|
totalDuration := 0 // 所有VIP卡增加的天数总和
|
|
lowestDiscount := 10 // 所有VIP卡最大打折, 10表示原价不打折
|
|
hightestVipLevel := 1 // 最高VIP等级
|
|
for i, p := range products {
|
|
if p.PayVidDiscount <= 0 || p.PayVidDiscount > 10 {
|
|
return errors.New("VIP卡配置不正确")
|
|
}
|
|
if lowestDiscount > p.PayVidDiscount {
|
|
lowestDiscount = p.PayVidDiscount
|
|
}
|
|
if hightestVipLevel < p.VipLevel {
|
|
hightestVipLevel = p.VipLevel
|
|
}
|
|
totalDuration += p.Duration
|
|
// 添加记录
|
|
historyID := primitive.NewObjectID()
|
|
productHistorys[i] = prdcthsomod.ProductHistory{
|
|
ID: historyID,
|
|
UID: userInfo.UID,
|
|
ProductID: p.ID,
|
|
Name: p.Name,
|
|
ProductType: commod.VIP,
|
|
DiscDoc: userInfo.DiscDoc,
|
|
SysType: userInfo.SysType,
|
|
ProductSnapShot: &p,
|
|
}
|
|
transactionLogs[i] = txnmod.TransactionLog{
|
|
UID: userInfo.UID,
|
|
Amount: -p.DiscountedPrice,
|
|
ActualAmount: 0,
|
|
TranType: txnmod.Active2023VIP.Key(),
|
|
TranTypeInt: int64(txnmod.Active2023VIP),
|
|
TransNo: historyID,
|
|
Desc: desc + "获得-" + p.Name,
|
|
DiscDoc: userInfo.DiscDoc,
|
|
SysType: userInfo.SysType,
|
|
}
|
|
}
|
|
// 写入历史纪录
|
|
if err := prdcthsomod.InsertManyProductHistory(t, productHistorys); err != nil {
|
|
return err
|
|
}
|
|
if err := txnmod.InsertManyTransactionLog(t, transactionLogs); err != nil {
|
|
return err
|
|
}
|
|
start := time.Now()
|
|
if userInfo.VipExpireDate.After(start) { // 如果用户VIP未过期, 则VIP等级和视频折扣等级需要参考用户现在的情况
|
|
start = userInfo.VipExpireDate
|
|
}
|
|
vipExpireDate := start.Add(time.Hour * 24 * time.Duration(totalDuration))
|
|
if userInfo.VipLevel > hightestVipLevel {
|
|
hightestVipLevel = userInfo.VipLevel
|
|
}
|
|
if (userInfo.PayVidDiscount > 0 && userInfo.PayVidDiscount < 10) && userInfo.PayVidDiscount < lowestDiscount {
|
|
lowestDiscount = userInfo.PayVidDiscount
|
|
}
|
|
|
|
sel := usermod.UserSelector{VipExpireDate: &vipExpireDate, VipLevel: &hightestVipLevel, PayVidDiscount: &lowestDiscount}
|
|
if err := usermod.UpdateVIP(t, userInfo.UID, userInfo.VipExpireDate, sel); err != nil {
|
|
return err
|
|
}
|
|
userInfo.VipExpireDate = vipExpireDate
|
|
userInfo.VipLevel = hightestVipLevel
|
|
userInfo.PayVidDiscount = lowestDiscount
|
|
return nil
|
|
}
|