Files
rootandClaude Opus 5 8679200f41 Initial commit
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 13:57:10 +08:00

460 lines
13 KiB
Go

package couponser
import (
"91porn-server/app/appg"
"91porn-server/common"
"91porn-server/common/db"
"91porn-server/common/log"
"91porn-server/common/stderr"
"91porn-server/models/commod"
"91porn-server/models/v/advanceordermod"
"91porn-server/models/v/backpackmod"
"91porn-server/models/v/coupon_record_mod"
"91porn-server/models/v/prize_record_mod"
"91porn-server/models/v/productmod"
"91porn-server/models/v/txnmod"
"91porn-server/models/v/usermod"
"91porn-server/models/v/walletmod"
"91porn-server/web/service/userser"
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/json"
"fmt"
"time"
"github.com/gin-gonic/gin"
"github.com/shopspring/decimal"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// List 优惠券列表
func List(uid uint64, in *coupon_record_mod.AppListReq) (*coupon_record_mod.QueryAllRes, error) {
var out = &coupon_record_mod.QueryAllRes{}
count, err := coupon_record_mod.QueryAllCount(in.Filter(uid))
if err != nil {
return nil, err
}
if count == 0 {
out.List = []*coupon_record_mod.AppCouponRecordRes{}
out.Total = 0
return out, nil
}
out.Total = count
out.List, err = coupon_record_mod.QueryAllList(in.Filter(uid), in.Options())
if err != nil {
log.Error(fmt.Sprintf("coupon_record_mod.QueryAllList err:%v", err), log.Any("uid", uid), log.Any("params", in))
return nil, stderr.ErrDbQueryError
}
return out, nil
}
// Upload 上传优惠券列表
func Upload(uid uint64, in *prize_record_mod.AppUploadReq) error {
var (
prizes []*prize_record_mod.Prize
transactionLogs []txnmod.TransactionLog
)
// 获取用户信息
u, err := usermod.FindUserByUID(uid)
if err != nil {
return stderr.ErrDbQueryError
}
if u == nil {
return stderr.UserIsNotExists
}
prizes = in.Prizes
if len(prizes) == 0 {
return stderr.PrizeRecordNoExists
}
// 优先使用预售卡权益免费次数
hasPrivilege, advance := advanceordermod.GetUserValidOrder(uid)
if hasPrivilege {
// 获取可用免费次数
validCount := advance.PrepaidPrivilege.LuckyDrawLimitPerDay - advance.TodayUse.LuckyDrawCount
if validCount >= in.Count {
// 扣除免费次数
debitPlan := advanceordermod.DebitPlan{}
debitPlan.LuckyDrawCount = &in.Count
if err := advanceordermod.Debit(nil, uid, debitPlan); err != nil {
return stderr.ErrDbUpdateError
}
in.Count = 0
} else if validCount > 0 {
// 扣除免费次数
debitPlan := advanceordermod.DebitPlan{}
debitPlan.LuckyDrawCount = &validCount
if err := advanceordermod.Debit(nil, uid, debitPlan); err != nil {
return stderr.ErrDbUpdateError
}
in.Count -= validCount
}
}
wal, err := walletmod.GetWallet(uid)
if err != nil {
return stderr.ErrDbQueryError
}
totalMoney := wal.Amount + wal.Income
if totalMoney <= 0 && wal.LotteryTimes < in.Count {
log.Warn(fmt.Sprintf("用户ID:%d;用户余额不足,当前剩余次数:%v;抽奖扣除次数:%v", uid, wal.LotteryTimes, in.Count))
return stderr.InsufficientBalance
}
if in.Gold > 0 && in.Gold > totalMoney {
log.Warn(fmt.Sprintf("用户ID:%d;用户余额不足,当前剩余总余额:%v;抽奖扣除金额:%v", uid, totalMoney, in.Gold))
return stderr.InsufficientBalance
}
if wal.LotteryTimes < in.Count && in.Gold == 0 {
log.Warn(fmt.Sprintf("用户ID:%d;用户余额不足,当前剩余次数:%v;抽奖扣除次数:%v", uid, wal.LotteryTimes, in.Count))
return stderr.InsufficientBalance
}
if in.Count != 0 || in.Gold != 0 {
var creditPlan = walletmod.CreditPlan{}
// 处理扣钱
if in.Count > 0 && in.Gold == 0 {
inc := -in.Count
creditPlan.LotteryTimes = &inc
}
if in.Gold != 0 {
desc := -in.Gold
if wal.Amount < in.Gold {
descAmt := -wal.Amount
creditPlan.Amount = &descAmt
descInc := -(in.Gold - wal.Amount)
creditPlan.Income = &descInc
log.Info(fmt.Sprintf("用户ID:%d;抽奖进入这里扣出income:%v;amount:%v", uid, descInc, descAmt))
} else if wal.Amount >= in.Gold {
creditPlan.Amount = &desc
log.Info(fmt.Sprintf("用户ID:%d;抽奖进入这里扣出;amount:%v", uid, in.Gold))
}
}
if err = appg.VideoDB.Trans(func(t *db.MongoTool) error {
// 增加金币与总充值金额
wal, err = walletmod.DescCredit(t, creditPlan, uid)
if err != nil {
return err
}
if in.Gold > 0 {
out := txnmod.TransactionLog{
TransNo: primitive.NewObjectID(),
UID: uid,
Amount: in.Gold,
ActualAmount: -float64(in.Gold),
TranType: txnmod.RaffleDeduction.Key(),
TranTypeInt: int64(txnmod.RaffleDeduction),
Desc: fmt.Sprintf("%s-金币[%d个]", txnmod.RaffleDeduction.Key(), in.Gold),
RealAmount: wal.RealAmount(),
CreatedAt: time.Now(),
}
transactionLogs = append(transactionLogs, out)
}
if len(transactionLogs) > 0 {
err = txnmod.InsertManyTransactionLog(t, transactionLogs)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;奖品派发资金流水日志插入异常:%v", uid, err))
return err
}
}
return nil
}); err != nil {
return stderr.ErrDbTransError
}
}
common.Go(func() {
_ = HandlePrize(uid, in, u, wal)
})
log.Info(fmt.Sprintf("用户ID:%d;业务处理完成", uid))
return nil
}
func HandlePrize(uid uint64, in *prize_record_mod.AppUploadReq, u *usermod.User, wal *walletmod.Wallet) error {
var (
prizes []*prize_record_mod.Prize
transactionLogs []txnmod.TransactionLog
couponRecords []coupon_record_mod.CouponRecord
goodsList []backpackmod.Backpack
totalInc int64
totalAIUndressInc int64
err error
)
prizes = in.Prizes
vipStatus := false
// 处理同类型
for _, p := range prizes {
log.Info(fmt.Sprintf("--------------开始任务:%+v", p))
if p.PrizeType == prize_record_mod.PrizeTypeVIPCard {
id, _ := primitive.ObjectIDFromHex(p.Param1)
// 查询会员卡详情
productDetail, err := productmod.FindProduct(id, "android")
if err != nil {
continue
}
vipExpire, vipLevel, payVidDiscount := prize_record_mod.CheckVipRenew(u, productDetail)
u.VipExpireDate = vipExpire
u.VipLevel = vipLevel
u.PayVidDiscount = payVidDiscount
vipStatus = true
}
if p.PrizeType == prize_record_mod.PrizeTypeVIP {
if u.VipLevel == 0 {
u.VipLevel = 1
}
vipExpire, vipLevel := userser.CheckVipRenew(u, int(p.Price), u.VipLevel)
u.VipExpireDate = vipExpire
u.VipLevel = vipLevel
vipStatus = true
}
if p.PrizeType == prize_record_mod.PrizeTypeGold {
totalInc += p.Price
transactionLogs = append(transactionLogs, txnmod.TransactionLog{
TransNo: primitive.NewObjectID(),
UID: u.UID,
Amount: p.Price,
ActualAmount: float64(p.Price),
TranType: txnmod.PrizeRecord.Key(),
TranTypeInt: int64(txnmod.PrizeRecord),
Desc: fmt.Sprintf("%s-金币[%d个]", txnmod.PrizeRecord.Key(), p.Price),
RealAmount: wal.RealAmount().Add(decimal.NewFromInt(totalInc)),
})
}
if p.PrizeType == prize_record_mod.PrizeTypeGoldCoinBonus {
cId := prize_record_mod.HandleCId(p.ID)
// 获取观影券是否存在
c, err := coupon_record_mod.FindOneByCId(cId)
if err != nil {
return err
}
if !c.ID.IsZero() {
return stderr.New(400, "coupon_record is exist")
}
// 保存用户优惠券
now := time.Now()
newCo := coupon_record_mod.CouponRecord{
CID: cId,
PID: p.ID,
UID: u.UID,
UserName: u.Name,
Name: p.Name,
Count: p.Count,
Price: p.Price,
Type: coupon_record_mod.PrizeTypeGoldCoinBonus,
Used: false,
IsDelete: false,
ExpireTime: now.Add(time.Hour * 24 * time.Duration(p.ValidDate)),
}
couponRecords = append(couponRecords, newCo)
}
// AI脱衣
if p.PrizeType == prize_record_mod.PrizeTypeAiUndress {
totalAIUndressInc += p.Price
aiLog := txnmod.TransactionLog{
UID: uid,
Amount: p.Price,
ActualAmount: float64(p.Price),
TranType: txnmod.PrizeRecord.Key(),
TranTypeInt: int64(txnmod.PrizeRecord),
TransNo: primitive.NewObjectID(),
Desc: fmt.Sprintf("%s-赠送AI脱衣免费次数[%v次]", txnmod.PrizeRecord.Key(), p.Price),
DiscDoc: u.DiscDoc,
SysType: u.SysType,
}
transactionLogs = append(transactionLogs, aiLog)
}
// AI金币抵扣券
if p.PrizeType == prize_record_mod.PrizeTypeGoldDiscountCoupon {
nowTime := time.Now()
goodsList = append(goodsList, backpackmod.Backpack{
UID: uid,
GoodsName: p.Name,
GoodsType: backpackmod.AiChangeFaceDiscount,
GoodsValue: p.Price,
GoodsOrigin: "抽奖获得AI金币抵扣券",
Status: backpackmod.Unused,
ExpiredTime: nowTime.Add(time.Hour * 24 * time.Duration(p.ValidDate)),
CreateTime: nowTime,
})
}
}
set := usermod.UserSelector{VipExpireDate: &u.VipExpireDate, VipLevel: &u.VipLevel, PayVidDiscount: &u.PayVidDiscount}
// 根据类型处理业务
if err = appg.VideoDB.Trans(func(t *db.MongoTool) error {
if vipStatus {
if err = usermod.UpdateUserById(t, uid, set); err != nil {
log.Error(fmt.Sprintf("用户ID:%d;奖品派发VIP更新异常:%v", uid, err))
return err
}
}
if len(couponRecords) > 0 {
err = coupon_record_mod.InsertManyCouponRecords(t, couponRecords)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;奖品派发加赠券日志插入异常:%v", uid, err))
return err
}
}
if totalInc > 0 {
_, err = walletmod.CreditAmount(t, totalInc, uid)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;奖品派发金币流水异常:%v", uid, err))
return err
}
}
if len(transactionLogs) > 0 {
err = txnmod.InsertManyTransactionLog(t, transactionLogs)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;奖品派发资金流水日志插入异常:%v", uid, err))
return err
}
}
if totalAIUndressInc > 0 {
_, err := walletmod.DebitAiFreeTimes(t, -totalAIUndressInc, uid)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;奖品派发AI免费次数异常:%v", uid, err))
return err
}
}
if len(goodsList) > 0 {
if err := backpackmod.AddGoodsMany(t, uid, goodsList); err != nil {
log.Error(fmt.Sprintf("用户ID:%d;奖品派发AI抵扣券插入异常:%v", uid, err))
return err
}
}
return nil
}); err != nil {
return stderr.ErrDbTransError
}
log.Info(fmt.Sprintf("用户ID:%d;抽奖派发成功", uid))
return nil
}
// Delete 删除优惠券列表
func Delete(uid uint64, in *prize_record_mod.AppDeleteReq) error {
// 获取用户信息
u, err := usermod.FindUserByUID(uid)
if err != nil {
return err
}
if u == nil {
return stderr.UserIsNotExists
}
// 删除成功
if err = coupon_record_mod.Remove(in.Filter()); err != nil {
return err
}
log.Info(fmt.Sprintf("用户ID:%d;优惠券删除发成功", uid))
return nil
}
// Gain 获取用户信息
func Gain(c *gin.Context, uid uint64) (data *coupon_record_mod.AppGainUserInfoRes, err error) {
info := coupon_record_mod.AppGainUserInfoRes{UID: uid, LotteryTimes: 0}
var conAmt int64 = 0
// 获取用户信息
u, err := usermod.FindUserByUID(uid)
if err != nil {
return nil, err
}
if u == nil {
return nil, stderr.UserIsNotExists
}
w, err := walletmod.GetWallet(uid)
if err != nil {
return nil, stderr.ErrDbQueryError
}
if w.Consumption != 0 {
//conAmt = w.Consumption / 10
}
if w.LotteryTimes != 0 {
info.LotteryTimes = w.LotteryTimes
}
// 检查预售权益免费次数
hasPrivilege, advance := advanceordermod.GetUserValidOrder(uid)
if hasPrivilege {
// 获取可用免费次数
validCount := advance.PrepaidPrivilege.LuckyDrawLimitPerDay - advance.TodayUse.LuckyDrawCount
if validCount > 0 {
info.LotteryTimes += validCount
}
}
t := c.Request.Header.Get("authorization")
sReq := coupon_record_mod.AppGainUserInfoReq{
AppID: commod.KFK_APPID,
Token: t,
UserName: u.Name,
UID: uid,
TotalRecharge: conAmt,
Balance: w.Amount + w.Income,
}
ct, _ := json.Marshal(sReq)
log.Info(fmt.Sprintf("Gain userInfo:%+v:", string(ct)))
aesKey := []byte("nU7cLOX7t3yJHq8yeIMCfO9emiOWtdlN")
encrypt, err := AesPCK5Encrypt(ct, aesKey)
if err != nil {
log.Error(fmt.Sprintf("Gain userInfo aes err:%+v:", err))
return nil, err
}
log.Info(fmt.Sprintf("Gain userInfo aes string:%+v:", encrypt))
info.Data = *encrypt
return &info, nil
}
func PKCS5Padding(plaintext []byte, blockSize int) []byte {
padding := blockSize - len(plaintext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(plaintext, padtext...)
}
func PKCS5UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
// AesPCK5Encrypt 加密
func AesPCK5Encrypt(origData, key []byte) (*string, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
origData = PKCS5Padding(origData, blockSize)
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
encrypted := make([]byte, len(origData))
blockMode.CryptBlocks(encrypted, origData)
enData := base64.StdEncoding.EncodeToString(encrypted)
return &enData, nil
}
// 解密
func AesPCK5Decrypt(crypted, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
origData := make([]byte, len(crypted))
blockMode.CryptBlocks(origData, crypted)
origData = PKCS5UnPadding(origData)
return origData, nil
}