@@ -0,0 +1,414 @@
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package active2023ser
|
||||
|
||||
type LotteryReq struct {
|
||||
Count uint64 `form:"count" json:"count"` // 抽奖次数
|
||||
Gold uint64 `form:"gold" json:"gold"` // 抽奖花费金币. 如果使用的是免费次数, 该值为0
|
||||
Prizes []Prize `form:"prizes" json:"prizes" binding:"required,min=1,max=10"` // 奖品情况
|
||||
}
|
||||
|
||||
type Prize struct {
|
||||
Param1 string `json:"param1"` // 附加字段. 目前仅用于视频折扣卡, 表示视频折扣卡id
|
||||
Type uint64 `form:"prizeType" json:"prizeType" binding:"required"` // 奖品类型
|
||||
Name string `form:"name" json:"name"` // 奖品名称. 非实物奖品可以不传
|
||||
Price uint64 `form:"price" json:"price"` // 奖品面值, 配合奖品类型代表具体奖品. 金币: 金币数量; 金币加购券: 加购券金币面值; 观影券: 观影券抵扣面值; 会员礼包: 会员延续天数
|
||||
ValidDate uint64 `form:"validDate" json:"validDate"` // 有效期(单位: 天)
|
||||
}
|
||||
Reference in New Issue
Block a user