944 lines
28 KiB
Go
944 lines
28 KiB
Go
/*
|
|
* @Description: In User Settings Edit
|
|
* @Author: your name
|
|
* @Date: 2019-08-29 19:55:45
|
|
* @LastEditTime: 2019-08-30 19:39:56
|
|
* @LastEditors: Please set LastEditors
|
|
*/
|
|
package walletmod
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"91porn-server/common/db"
|
|
"91porn-server/common/log"
|
|
"91porn-server/models"
|
|
|
|
"github.com/shopspring/decimal"
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
"go.mongodb.org/mongo-driver/mongo"
|
|
"go.mongodb.org/mongo-driver/mongo/options"
|
|
)
|
|
|
|
var (
|
|
ErrDownloadRequestConflict = errors.New("download request id belongs to another resource")
|
|
ErrDownloadCountNotEnough = errors.New("download count is not enough")
|
|
ErrDownloadAuthorizationRace = errors.New("download authorization changed concurrently")
|
|
)
|
|
|
|
const maxDownloadRequestHistory = 1000
|
|
|
|
var mutex sync.Mutex
|
|
|
|
const table = models.Wallet
|
|
|
|
func coll(t *db.MongoTool) *db.MongoTool {
|
|
if t == nil {
|
|
return mdb.Coll(table)
|
|
}
|
|
return t.Coll(table)
|
|
}
|
|
|
|
func initIndex() {
|
|
many := []mongo.IndexModel{
|
|
{
|
|
Keys: bson.D{{Key: "uid", Value: 1}},
|
|
Options: options.Index().SetUnique(true),
|
|
},
|
|
}
|
|
if _, err := coll(nil).CreateIndex(many); err != nil {
|
|
panic(fmt.Sprintf("wallet model set index err ==>[%+v]", err))
|
|
}
|
|
}
|
|
|
|
func InsertWallet(t *db.MongoTool, w *Wallet) error {
|
|
if _, err := coll(t).InsertOne(w); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "InsertWallet", table, "InsertOne", err),
|
|
log.Any("w", w),
|
|
)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetWallet 通过uid,查找用户余额
|
|
func GetWallet(uid uint64) (w *Wallet, err error) {
|
|
w = &Wallet{}
|
|
if err = coll(nil).FindOne(w, bson.M{"uid": uid}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetWallet", table, "FindOne", err),
|
|
log.Any("uid", uid),
|
|
)
|
|
}
|
|
return
|
|
}
|
|
|
|
func GetWalletMap(uidList []uint64) (map[uint64]Wallet, error) {
|
|
if len(uidList) == 0 {
|
|
return make(map[uint64]Wallet), nil
|
|
}
|
|
filter := bson.M{
|
|
"uid": bson.M{
|
|
"$in": uidList,
|
|
},
|
|
}
|
|
walletList := make([]Wallet, 0, len(uidList))
|
|
if err := coll(nil).Find(&walletList, filter); err != nil {
|
|
return nil, err
|
|
}
|
|
walletMap := make(map[uint64]Wallet, len(walletList))
|
|
for _, wallet := range walletList {
|
|
walletMap[wallet.UID] = wallet
|
|
}
|
|
return walletMap, nil
|
|
}
|
|
|
|
// CreditAmount 货币增加(虚拟货币)
|
|
func CreditAmount(t *db.MongoTool, amt int64, uid uint64) (*Wallet, error) {
|
|
w := Wallet{}
|
|
if err := coll(t).FindOneAndUpsert(&w, bson.M{"uid": uid}, bson.M{
|
|
"$inc": bson.M{"amount": amt},
|
|
}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditAmount", table, "FindOneAndUpsert", err),
|
|
log.Any("amt", amt),
|
|
log.Any("uid", uid),
|
|
)
|
|
return nil, err
|
|
}
|
|
return &w, nil
|
|
}
|
|
|
|
// DebitAmount 货币扣除(虚拟货币)
|
|
func DebitAmount(t *db.MongoTool, amt int64, uid uint64) (*Wallet, error) {
|
|
mutex.Lock()
|
|
defer mutex.Unlock()
|
|
w := Wallet{}
|
|
if err := coll(t).FindOneAndUpdate(&w, bson.M{"uid": uid, "amount": bson.M{"$gte": amt}}, bson.M{
|
|
"$inc": bson.M{"amount": -amt}}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitAmount", table, "FindOneAndUpdate", err),
|
|
log.Any("amt", amt),
|
|
log.Any("uid", uid),
|
|
)
|
|
return nil, err
|
|
}
|
|
if w.ID.IsZero() {
|
|
return nil, errors.New("not enough balance")
|
|
}
|
|
return &w, nil
|
|
}
|
|
|
|
// CreditIntegral 新增积分
|
|
func CreditIntegral(t *db.MongoTool, integral int64, uid uint64) (*Wallet, error) {
|
|
w := Wallet{}
|
|
if err := coll(t).FindOneAndUpsert(&w, bson.M{"uid": uid}, bson.M{
|
|
"$inc": bson.M{"integral": integral},
|
|
}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditIntegral", table, "FindOneAndUpsert", err),
|
|
log.Any("integral", integral),
|
|
log.Any("uid", uid),
|
|
)
|
|
return nil, err
|
|
}
|
|
return &w, nil
|
|
}
|
|
|
|
// DebitIntegral 扣除积分
|
|
func DebitIntegral(t *db.MongoTool, integral int64, uid uint64) (*Wallet, error) {
|
|
mutex.Lock()
|
|
defer mutex.Unlock()
|
|
w := Wallet{}
|
|
if err := coll(t).FindOneAndUpdate(&w, bson.M{"uid": uid, "integral": bson.M{"$gte": integral}}, bson.M{
|
|
"$inc": bson.M{"integral": -integral}}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitIntegral", table, "FindOneAndUpdate", err),
|
|
log.Any("integral", integral),
|
|
log.Any("uid", uid),
|
|
)
|
|
return nil, err
|
|
}
|
|
if w.ID.IsZero() {
|
|
return nil, errors.New("not enough balance")
|
|
}
|
|
return &w, nil
|
|
}
|
|
|
|
// 扣除金币
|
|
// 金币不足则报错
|
|
func DebitAmountAndCheck(t *db.MongoTool, uid int64, amt int64) error {
|
|
mutex.Lock()
|
|
defer mutex.Unlock()
|
|
result, err := coll(t).UpdateOne(bson.M{"uid": uid, "amount": bson.M{"$gte": amt}}, bson.M{
|
|
"$inc": bson.M{"amount": -amt}})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if result.ModifiedCount != 1 {
|
|
return errors.New("金币余额不足")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 扣除金币
|
|
// 金币不足则报错
|
|
// 包括普通金币和可提现金币
|
|
// 先扣除普通金币, 再扣除可提现金币
|
|
// t 必须已经开启事务!!!
|
|
func DebitAmountDefault(t *db.MongoTool, uid int64, amt int64) error {
|
|
mutex.Lock()
|
|
defer mutex.Unlock()
|
|
var wallet Wallet
|
|
if err := coll(t).FindOne(&wallet, bson.M{"uid": uid}); err != nil {
|
|
return err
|
|
}
|
|
if wallet.Amount+wallet.Income < amt {
|
|
return errors.New("金币余额不足")
|
|
}
|
|
if wallet.Amount >= amt {
|
|
result, err := coll(t).UpdateOne(bson.M{"uid": uid, "amount": bson.M{"$gte": amt}}, bson.M{
|
|
"$inc": bson.M{"amount": -amt}})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if result.ModifiedCount != 1 {
|
|
return errors.New("金币余额不足")
|
|
}
|
|
return nil
|
|
}
|
|
useIncome := amt - wallet.Amount
|
|
result, err := coll(t).UpdateOne(bson.M{"uid": uid, "amount": wallet.Amount, "income": bson.M{"$gte": useIncome}}, bson.M{
|
|
"$inc": bson.M{"amount": -wallet.Amount, "income": -useIncome}})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if result.ModifiedCount != 1 {
|
|
return errors.New("金币余额不足")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetAmount 获取金币
|
|
func GetAmount(t *db.MongoTool, uid uint64) (int64, error) {
|
|
w := &Wallet{}
|
|
if err := coll(t).FindOne(w, bson.M{"uid": uid}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetAmount", table, "FindOne", err),
|
|
log.Any("uid", uid),
|
|
)
|
|
return 0, err
|
|
}
|
|
return w.Amount, nil
|
|
}
|
|
|
|
// GetAmount 获取果币
|
|
func GetFruitAmount(t *db.MongoTool, uid uint64) (int64, error) {
|
|
w := &Wallet{}
|
|
if err := coll(t).FindOne(w, bson.M{"uid": uid}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetAmount", table, "FindOne", err),
|
|
log.Any("uid", uid),
|
|
)
|
|
return 0, err
|
|
}
|
|
return w.FruitCoin, nil
|
|
}
|
|
|
|
// GetAiMateBalance 获取ai伴侣币余额
|
|
func GetAiMateBalance(t *db.MongoTool, uid uint64) (float64, error) {
|
|
w := &Wallet{}
|
|
if err := coll(t).FindOne(w, bson.M{"uid": uid}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetAmount", table, "FindOne", err),
|
|
log.Any("uid", uid),
|
|
)
|
|
return 0, err
|
|
}
|
|
return w.AiMateBalance, nil
|
|
}
|
|
|
|
// SetAmount 设置货币(虚拟货币)
|
|
func SetAmount(t *db.MongoTool, amt int64, uid uint64) error {
|
|
//写入数据库,待完成
|
|
if _, err := coll(t).UpdateOne(bson.M{"uid": uid}, bson.M{
|
|
"$set": bson.M{"amount": amt},
|
|
}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "SetAmount", table, "UpdateOne", err),
|
|
log.Any("amt", amt),
|
|
log.Any("uid", uid),
|
|
)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 返回更新前的值 被删除的商人无法更新
|
|
func FindUpdate(tool *db.MongoTool, uid uint64, amt int64) (*Wallet, error) {
|
|
w := Wallet{}
|
|
opt := &options.FindOneAndUpdateOptions{}
|
|
opt.SetReturnDocument(options.Before)
|
|
if err := coll(tool).FindOneAndUpdate(&w, bson.M{"uid": uid}, bson.M{"$set": bson.M{"amount": amt}}, opt); err != nil {
|
|
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "FindUpdate", table, "FindOneAndUpdate", err))
|
|
return nil, err
|
|
}
|
|
if w.ID.IsZero() {
|
|
return nil, errors.New("wallet not found")
|
|
}
|
|
return &w, nil
|
|
}
|
|
|
|
func Debit(t *db.MongoTool, p *DebitPlan, uid uint64) (*Wallet, error) {
|
|
if p == nil {
|
|
return nil, errors.New("wallet nil DebitPlan")
|
|
}
|
|
w := &Wallet{}
|
|
var err error
|
|
if p.Amount != 0 {
|
|
w, err = DebitAmount(t, p.Amount, uid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
if p.Income != 0 {
|
|
w, err = DebitIncome(t, p.Income, uid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
if p.Consumption != 0 {
|
|
err = CreditConsumption(t, p.Consumption, uid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
if p.DownloadCount != 0 {
|
|
err = CreditDownloadCount(t, p.DownloadCount, uid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
if p.AiUndressFreeTimes != 0 {
|
|
w, err = DebitAiFreeTimes(t, p.AiUndressFreeTimes, uid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
if p.LotteryTimes != 0 {
|
|
w, err = DebitLotteryTimes(t, p.LotteryTimes, uid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
if !w.ID.IsZero() {
|
|
return w, nil
|
|
}
|
|
if err = coll(t).FindOne(w, bson.M{"uid": uid}); err != nil {
|
|
return nil, err
|
|
}
|
|
if w.ID.IsZero() {
|
|
return nil, errors.New("wallet not found")
|
|
}
|
|
return w, nil
|
|
}
|
|
|
|
// CreditIncomeBasePot
|
|
func CreditIncomeBasePot(t *db.MongoTool, incomeInt int64, income float64, pot float64, uid uint64) (*Wallet, error) {
|
|
mutex.Lock()
|
|
defer mutex.Unlock()
|
|
var wallet Wallet
|
|
if err := coll(t).FindOneAndUpsert(&wallet, bson.M{"uid": uid}, bson.M{
|
|
"$set": bson.M{"incomePot": pot, "vidIncome": income},
|
|
"$inc": bson.M{"income": incomeInt},
|
|
}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditIncome", table, "FindOneAndUpdate", err),
|
|
log.Any("income", income),
|
|
log.Any("incomePot", pot),
|
|
log.Any("uid", uid),
|
|
)
|
|
return nil, err
|
|
}
|
|
return &wallet, nil
|
|
}
|
|
|
|
// CreditIncomeBasePotWithReward
|
|
func CreditIncomeBasePotWithReward(t *db.MongoTool, incomeInt int64, rewardIncome decimal.Decimal, pot float64, uid uint64) (*Wallet, error) {
|
|
var w Wallet
|
|
if err := coll(t).FindOneAndUpsert(&w, bson.M{"uid": uid}, bson.M{
|
|
"$set": bson.M{"incomePot": pot},
|
|
"$inc": bson.M{"income": incomeInt, "rewardIncome": rewardIncome},
|
|
}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditIncome", table, "FindOneAndUpsert", err),
|
|
log.Any("income", incomeInt),
|
|
log.Any("incomePot", pot),
|
|
log.Any("uid", uid),
|
|
)
|
|
return nil, err
|
|
}
|
|
return &w, nil
|
|
}
|
|
|
|
// CreditDebIncome 累计扣量金币 增加
|
|
func CreditDebIncome(t *db.MongoTool, income string, uid uint64) error {
|
|
debIncr, _ := primitive.ParseDecimal128(income)
|
|
//写入数据库,待完成
|
|
res, err := coll(t).UpsertOne(bson.M{"uid": uid}, bson.M{
|
|
"$inc": bson.M{"dedIncome": debIncr},
|
|
})
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditDebIncome", table, "UpsertOne", err),
|
|
log.Any("income", income),
|
|
log.Any("uid", uid),
|
|
)
|
|
return err
|
|
}
|
|
if res.UpsertedCount != 1 && res.ModifiedCount != 1 {
|
|
return errors.New("Invalid account")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CreditIncome 货币增加
|
|
func CreditIncome(t *db.MongoTool, income int64, uid uint64) (*Wallet, error) {
|
|
var w Wallet
|
|
if err := coll(t).FindOneAndUpsert(&w, bson.M{"uid": uid}, bson.M{
|
|
"$inc": bson.M{"income": income},
|
|
}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditIncome", table, "FindOneAndUpsert", err),
|
|
log.Any("income", income),
|
|
log.Any("uid", uid),
|
|
)
|
|
return nil, err
|
|
}
|
|
return &w, nil
|
|
}
|
|
|
|
// DebitIncome 货币扣除
|
|
func DebitIncome(t *db.MongoTool, income int64, uid uint64) (*Wallet, error) {
|
|
var w Wallet
|
|
if err := coll(t).FindOneAndUpdate(&w, bson.M{"uid": uid, "income": bson.M{"$gte": income}}, bson.M{
|
|
"$inc": bson.M{"income": -income},
|
|
}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitIncome", table, "FindOneAndUpdate", err),
|
|
log.Any("income", income),
|
|
log.Any("uid", uid),
|
|
)
|
|
return nil, err
|
|
}
|
|
if w.ID.IsZero() {
|
|
return nil, errors.New("wallet not found")
|
|
}
|
|
return &w, nil
|
|
}
|
|
|
|
// CreditFruitCoin 果币增加
|
|
func CreditFruitCoin(t *db.MongoTool, uid uint64, fruitCoin int64) (*Wallet, error) {
|
|
var item *Wallet
|
|
if err := coll(t).FindOneAndUpsert(&item, bson.M{"uid": uid}, bson.M{"$inc": bson.M{"fruitCoin": fruitCoin}}); err != nil {
|
|
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditFruitCoin", table, "FindOneAndUpsert", err),
|
|
log.Any("fruitCoin", fruitCoin),
|
|
log.Any("uid", uid),
|
|
)
|
|
return nil, err
|
|
}
|
|
return item, nil
|
|
}
|
|
|
|
// UpdateAiMateBalance ai伴侣币修改
|
|
func UpdateAiMateBalance(t *db.MongoTool, uid uint64, aiMateBalance float64) (*Wallet, error) {
|
|
var item *Wallet
|
|
if err := coll(t).FindOneAndUpsert(&item, bson.M{"uid": uid}, bson.M{"$set": bson.M{"aiMateBalance": aiMateBalance}}); err != nil {
|
|
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "UpdateAiMateBalance", table, "FindOneAndUpsert", err),
|
|
log.Any("aiMateBalance", aiMateBalance),
|
|
log.Any("uid", uid),
|
|
)
|
|
return nil, err
|
|
}
|
|
return item, nil
|
|
}
|
|
|
|
// DebitFruitCoin 果币减少
|
|
func DebitFruitCoin(t *db.MongoTool, uid uint64, fruitCoin int64) (*Wallet, error) {
|
|
var item *Wallet
|
|
if err := coll(t).FindOneAndUpsert(&item, bson.M{"uid": uid}, bson.M{"$inc": bson.M{"fruitCoin": -fruitCoin}}); err != nil {
|
|
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitFruitCoin", table, "FindOneAndUpsert", err),
|
|
log.Any("fruitCoin", -fruitCoin),
|
|
log.Any("uid", uid),
|
|
)
|
|
return nil, err
|
|
}
|
|
return item, nil
|
|
}
|
|
|
|
// CreditNudeChatIncome 裸聊收益增加
|
|
func CreditNudeChatIncome(t *db.MongoTool, uid uint64, nudeChatIncome int64) (*Wallet, error) {
|
|
var item *Wallet
|
|
if err := coll(t).FindOneAndUpsert(&item, bson.M{"uid": uid}, bson.M{"$inc": bson.M{
|
|
"nudeChatIncome": decimal.NewFromInt(nudeChatIncome),
|
|
"income": nudeChatIncome,
|
|
}}); err != nil {
|
|
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditNudeChatIncome", table, "FindOneAndUpsert", err),
|
|
log.Any("nudeChatIncome", nudeChatIncome),
|
|
log.Any("uid", uid),
|
|
)
|
|
return nil, err
|
|
}
|
|
return item, nil
|
|
}
|
|
|
|
// DebitNudeChatIncome 裸聊收益减少
|
|
func DebitNudeChatIncome(t *db.MongoTool, uid uint64, nudeChatIncome int64) (*Wallet, error) {
|
|
var item *Wallet
|
|
if err := coll(t).FindOneAndUpsert(&item, bson.M{"uid": uid}, bson.M{"$inc": bson.M{
|
|
"nudeChatIncome": decimal.NewFromInt(-nudeChatIncome),
|
|
"income": -nudeChatIncome,
|
|
}}); err != nil {
|
|
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitNudeChatIncome", table, "FindOneAndUpsert", err),
|
|
log.Any("nudeChatIncome", nudeChatIncome),
|
|
log.Any("uid", uid),
|
|
)
|
|
return nil, err
|
|
}
|
|
return item, nil
|
|
}
|
|
|
|
// CreditMoney 货币增加
|
|
func CreditMoney(t *db.MongoTool, money int64, uid uint64) error {
|
|
//写入数据库,待完成
|
|
res, err := coll(t).UpsertOne(bson.M{"uid": uid}, bson.M{
|
|
"$inc": bson.M{"money": money},
|
|
})
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditMoney", table, "UpsertOne", err),
|
|
log.Any("money", money),
|
|
log.Any("uid", uid),
|
|
)
|
|
return err
|
|
}
|
|
if res.UpsertedCount != 1 && res.ModifiedCount != 1 {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditMoney", table, "errors.New", "Invalid account"),
|
|
log.Any("money", money),
|
|
log.Any("uid", uid),
|
|
)
|
|
return errors.New("Invalid account")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DebitMoney 货币扣除
|
|
func DebitMoney(t *db.MongoTool, money int64, uid uint64) (*Wallet, error) {
|
|
w := Wallet{}
|
|
if err := coll(t).FindOneAndUpdate(&w, bson.M{"uid": uid, "money": bson.M{"$gte": money}}, bson.M{
|
|
"$inc": bson.M{"money": -money},
|
|
}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitMoney", table, "FindOneAndUpdate", err),
|
|
log.Any("money", money),
|
|
log.Any("uid", uid),
|
|
)
|
|
return nil, err
|
|
}
|
|
if w.ID.IsZero() {
|
|
return nil, errors.New("not enough balance")
|
|
}
|
|
return &w, nil
|
|
}
|
|
|
|
// CreditConsumption 总充值增加
|
|
func CreditConsumption(t *db.MongoTool, money int64, uid uint64) error {
|
|
res, err := coll(t).UpsertOne(bson.M{
|
|
"uid": uid,
|
|
}, bson.M{
|
|
"$inc": bson.M{
|
|
"consumption": money,
|
|
},
|
|
})
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditConsumption", table, "UpsertOne", err),
|
|
log.Any("money", money),
|
|
log.Any("uid", uid),
|
|
)
|
|
return err
|
|
}
|
|
if res.UpsertedCount != 1 && res.ModifiedCount != 1 {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditConsumption", table, "errors.New", "Invalid account"),
|
|
log.Any("money", money),
|
|
log.Any("uid", uid),
|
|
)
|
|
return errors.New("Invalid account")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CreditDownloadCount 总下载次数加
|
|
func CreditDownloadCount(t *db.MongoTool, downloadCount int64, uid uint64) error {
|
|
res, err := coll(t).UpsertOne(bson.M{"uid": uid}, bson.M{"$inc": bson.M{"downloadCount": -downloadCount}})
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditDownloadCount", table, "UpsertOne", err),
|
|
log.Any("downloadCount", downloadCount),
|
|
log.Any("uid", uid),
|
|
)
|
|
return err
|
|
}
|
|
if res.UpsertedCount != 1 && res.ModifiedCount != 1 {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditDownloadCount", table, "errors.New", "Invalid account"),
|
|
log.Any("downloadCount", downloadCount),
|
|
log.Any("uid", uid),
|
|
)
|
|
return errors.New("update DownloadCount err")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func Find(filter bson.M) ([]*Wallet, error) {
|
|
ws := make([]*Wallet, 0)
|
|
if err := coll(nil).Find(&ws, filter); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "Find", table, "Find", err),
|
|
log.Any("filter", filter),
|
|
)
|
|
return nil, err
|
|
}
|
|
return ws, nil
|
|
}
|
|
|
|
// Credit 货币增加(虚拟货币)
|
|
func Credit(t *db.MongoTool, creditPlan CreditPlan, uid uint64) (*Wallet, error) {
|
|
w := Wallet{}
|
|
if err := coll(t).FindOneAndUpsert(&w, bson.M{"uid": uid}, bson.M{
|
|
"$inc": creditPlan,
|
|
}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditAmount", table, "FindOneAndUpsert", err),
|
|
log.Any("creditPlan", creditPlan),
|
|
log.Any("uid", uid),
|
|
)
|
|
return nil, err
|
|
}
|
|
return &w, nil
|
|
}
|
|
|
|
// DescCredit 货币扣除(虚拟货币)
|
|
func DescCredit(t *db.MongoTool, creditPlan CreditPlan, uid uint64) (wallet *Wallet, err error) {
|
|
filter := bson.M{"uid": uid}
|
|
if creditPlan.Income != nil {
|
|
filter["income"] = bson.M{"$gte": creditPlan.Income}
|
|
}
|
|
if creditPlan.Amount != nil {
|
|
filter["amount"] = bson.M{"$gte": creditPlan.Amount}
|
|
}
|
|
if creditPlan.LotteryTimes != nil {
|
|
filter["lotteryTimes"] = bson.M{"$gte": creditPlan.LotteryTimes}
|
|
}
|
|
err = coll(t).FindOneAndUpsert(&wallet, filter, bson.M{
|
|
"$inc": creditPlan,
|
|
})
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DescCredit", table, "FindOneAndUpsert", err),
|
|
log.Any("creditPlan", creditPlan),
|
|
log.Any("uid", uid),
|
|
)
|
|
}
|
|
return
|
|
}
|
|
|
|
// 抽奖预扣
|
|
func AddFreeze(userId uint64, amt int64) (*Wallet, error) {
|
|
filter := bson.M{
|
|
"uid": userId,
|
|
"amount": bson.M{"$gte": amt},
|
|
}
|
|
inc := bson.M{
|
|
"amount": -amt,
|
|
"freezeAmount": amt,
|
|
}
|
|
w := Wallet{}
|
|
if err := coll(nil).FindOneAndUpdate(&w, filter, bson.M{"$inc": inc}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DrawFreeze", table, "FindOneAndUpdate", err),
|
|
log.Any("uid", userId),
|
|
log.Any("amt", amt),
|
|
)
|
|
return nil, err
|
|
}
|
|
if w.ID.IsZero() {
|
|
return nil, errors.New("not enough balance")
|
|
}
|
|
return &w, nil
|
|
}
|
|
|
|
// 扣除预扣
|
|
func CutFreeze(t *db.MongoTool, userId uint64, amt, amount int64) (*Wallet, error) {
|
|
filter := bson.M{
|
|
"uid": userId,
|
|
"freezeAmount": bson.M{"$gte": amt},
|
|
}
|
|
inc := bson.M{
|
|
"freezeAmount": -amt,
|
|
"amount": amount,
|
|
}
|
|
w := Wallet{}
|
|
if err := coll(nil).FindOneAndUpdate(&w, filter, bson.M{"$inc": inc}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CutFreeze", table, "FindOneAndUpdate", err),
|
|
log.Any("uid", userId),
|
|
log.Any("amt", amt),
|
|
)
|
|
return nil, err
|
|
}
|
|
if w.ID.IsZero() {
|
|
return nil, errors.New("not enough balance")
|
|
}
|
|
return &w, nil
|
|
}
|
|
|
|
func (w *Wallet) RealAmount() decimal.Decimal {
|
|
return decimal.NewFromInt(w.Amount).Add(decimal.NewFromInt(w.Income)).
|
|
Add(decimal.NewFromFloat(w.IncomePot)).Add(decimal.NewFromInt(w.Money))
|
|
}
|
|
|
|
func GetRealAmount(w *Wallet) decimal.Decimal {
|
|
if w == nil {
|
|
return decimal.Decimal{}
|
|
}
|
|
return decimal.NewFromInt(w.Amount).Add(decimal.NewFromInt(w.Income)).
|
|
Add(decimal.NewFromFloat(w.IncomePot)).Add(decimal.NewFromInt(w.Money))
|
|
}
|
|
|
|
func (w *Wallet) RealIntegral() decimal.Decimal {
|
|
if w != nil && w.Integral != 0 {
|
|
return decimal.NewFromInt(w.Integral)
|
|
} else {
|
|
return decimal.NewFromInt(0)
|
|
}
|
|
}
|
|
|
|
func UpsertOne(t *db.MongoTool, filter bson.M, update bson.M) error {
|
|
if _, err := coll(t).UpsertOne(filter, update); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "update", table, "updateOne", err))
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func BulkWrite(t *db.MongoTool, models []mongo.WriteModel, opts ...*options.BulkWriteOptions) error {
|
|
if _, err := coll(t).Bulk(models, opts...); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "update", table, "updateOne", err))
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// IncUsdtAmount usdt可提现额度加减
|
|
func IncUsdtAmount(userId uint64, usdtAmount int64) (*Wallet, error) {
|
|
filter := bson.M{"uid": userId}
|
|
if usdtAmount < 0 {
|
|
filter["usdtAmount"] = bson.M{"$gte": 0}
|
|
}
|
|
inc := bson.M{"usdtAmount": usdtAmount}
|
|
var w Wallet
|
|
if err := coll(nil).FindOneAndUpdate(&w, filter, bson.M{"$inc": inc}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "IncUsdtAmount", table, "FindOneAndUpdate", err),
|
|
log.Any("uid", userId),
|
|
log.Any("amt", usdtAmount),
|
|
)
|
|
return nil, err
|
|
}
|
|
if w.ID.IsZero() {
|
|
return nil, errors.New("wallet not found")
|
|
}
|
|
return &w, nil
|
|
}
|
|
|
|
// AddUsdtAmount 增加usdt可提现额度
|
|
func AddUsdtAmount(t *db.MongoTool, userId uint64, usdtAmount int64) error {
|
|
result, err := coll(t).UpdateOne(bson.M{"uid": userId}, bson.M{"$inc": bson.M{"usdtAmount": usdtAmount}})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if result.ModifiedCount == 0 {
|
|
return errors.New("result.ModifiedCount is 0")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// IsRechargeUser 是否充值用户
|
|
func IsRechargeUser(t *db.MongoTool, uid uint64) bool {
|
|
w := &Wallet{}
|
|
if err := coll(t).FindOne(w, bson.M{"uid": uid}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "IsRechargeUser", table, "FindOne", err),
|
|
log.Any("uid", uid),
|
|
)
|
|
return false
|
|
}
|
|
if w.ID.IsZero() || w.Consumption <= 0 {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// DebitAmountAndIncome 货币扣除(虚拟货币)
|
|
func DebitAmountAndIncome(t *db.MongoTool, amt, income int64, uid uint64) (wallet *Wallet, err error) {
|
|
mutex.Lock()
|
|
defer mutex.Unlock()
|
|
filter := bson.M{"uid": uid}
|
|
update := bson.M{}
|
|
if amt > 0 {
|
|
filter["amount"] = bson.M{"$gte": amt}
|
|
update["amount"] = -amt
|
|
}
|
|
if income > 0 {
|
|
filter["income"] = bson.M{"$gte": income}
|
|
update["income"] = -income
|
|
}
|
|
|
|
err = coll(t).FindOneAndUpdate(&wallet, filter, bson.M{"$inc": update})
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitAmountAndIncome", table, "FindOneAndUpdate", err),
|
|
log.Any("filter", filter),
|
|
log.Any("update", update),
|
|
log.Any("uid", uid),
|
|
)
|
|
}
|
|
return
|
|
}
|
|
|
|
// ReturnAmountAndIncome 货币返回(虚拟货币)
|
|
func ReturnAmountAndIncome(t *db.MongoTool, amt, income int64, uid uint64) (wallet *Wallet, err error) {
|
|
mutex.Lock()
|
|
defer mutex.Unlock()
|
|
filter := bson.M{"uid": uid}
|
|
update := bson.M{}
|
|
if -amt > 0 {
|
|
update["amount"] = -amt
|
|
}
|
|
if -income > 0 {
|
|
update["income"] = -income
|
|
}
|
|
|
|
err = coll(t).FindOneAndUpdate(&wallet, filter, bson.M{"$inc": update})
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "ReturnAmountAndIncome", table, "FindOneAndUpdate", err),
|
|
log.Any("filter", filter),
|
|
log.Any("update", update),
|
|
log.Any("uid", uid),
|
|
)
|
|
}
|
|
return
|
|
}
|
|
|
|
// DebitAiFreeTimes 扣出AI脱衣次数
|
|
func DebitAiFreeTimes(t *db.MongoTool, freeTimes int64, uid uint64) (wallet *Wallet, err error) {
|
|
filter := bson.M{"uid": uid}
|
|
if freeTimes > 0 {
|
|
filter["aiUndressFreeTimes"] = bson.M{"$gte": freeTimes}
|
|
}
|
|
err = coll(t).FindOneAndUpsert(&wallet, filter, bson.M{"$inc": bson.M{"aiUndressFreeTimes": -freeTimes}})
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitAiFreeTimes", table, "FindOneAndUpdate", err),
|
|
log.Any("freeTimes", freeTimes),
|
|
log.Any("uid", uid),
|
|
)
|
|
}
|
|
return
|
|
}
|
|
|
|
// DebitDownloadCounts 扣出下载次数
|
|
func DebitDownloadCounts(t *db.MongoTool, downloadCount int64, uid uint64) (wallet *Wallet, err error) {
|
|
filter := bson.M{"uid": uid}
|
|
if downloadCount > 0 {
|
|
filter["downloadCount"] = bson.M{"$gte": downloadCount}
|
|
}
|
|
err = coll(t).FindOneAndUpsert(&wallet, filter, bson.M{"$inc": bson.M{"downloadCount": -downloadCount}})
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitAiDownloadCount", table, "FindOneAndUpdate", err),
|
|
log.Any("downloadCount", downloadCount),
|
|
log.Any("uid", uid),
|
|
)
|
|
}
|
|
return
|
|
}
|
|
|
|
// AuthorizeDramaDownload atomically records one idempotency key and debits one
|
|
// shared download count. The bounded wallet history covers retries even if an
|
|
// App instance or Redis cache restarts.
|
|
func AuthorizeDramaDownload(t *db.MongoTool, uid uint64, requestKey, fingerprint string, now time.Time) (*Wallet, bool, error) {
|
|
wallet := &Wallet{}
|
|
if err := coll(t).FindOne(wallet, bson.M{"uid": uid}); err != nil {
|
|
return nil, false, err
|
|
}
|
|
for _, request := range wallet.DownloadRequests {
|
|
if request.RequestKey != requestKey {
|
|
continue
|
|
}
|
|
if request.Fingerprint != fingerprint {
|
|
return nil, false, ErrDownloadRequestConflict
|
|
}
|
|
return wallet, false, nil
|
|
}
|
|
if wallet.DownloadCount <= 0 {
|
|
return nil, false, ErrDownloadCountNotEnough
|
|
}
|
|
record := DownloadRequest{RequestKey: requestKey, Fingerprint: fingerprint, CreatedAt: now}
|
|
filter := bson.M{
|
|
"uid": uid, "downloadCount": bson.M{"$gte": 1},
|
|
"downloadRequests.requestKey": bson.M{"$ne": requestKey},
|
|
}
|
|
update := bson.M{
|
|
"$inc": bson.M{"downloadCount": -1},
|
|
"$push": bson.M{"downloadRequests": bson.M{
|
|
"$each": []DownloadRequest{record}, "$slice": -maxDownloadRequestHistory,
|
|
}},
|
|
}
|
|
updated := &Wallet{}
|
|
if err := coll(t).FindOneAndUpdate(updated, filter, update); err != nil {
|
|
return nil, false, err
|
|
}
|
|
if updated.UID == 0 {
|
|
return nil, false, ErrDownloadAuthorizationRace
|
|
}
|
|
return updated, true, nil
|
|
}
|
|
|
|
// DebitLotteryTimes 扣出抽奖次数
|
|
func DebitLotteryTimes(t *db.MongoTool, lotteryTimes int64, uid uint64) (wallet *Wallet, err error) {
|
|
filter := bson.M{"uid": uid}
|
|
if lotteryTimes > 0 {
|
|
filter["lotteryTimes"] = bson.M{"$gte": lotteryTimes}
|
|
}
|
|
err = coll(t).FindOneAndUpsert(&wallet, filter, bson.M{"$inc": bson.M{"lotteryTimes": -lotteryTimes}})
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitAiDownloadCount", table, "FindOneAndUpdate", err),
|
|
log.Any("downloadCount", lotteryTimes),
|
|
log.Any("uid", uid),
|
|
)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Credit ai伴侣货币增加(虚拟货币)
|
|
func CreditAiMate(t *db.MongoTool, amt float64, uid uint64, aiMateOrderId string) (wallet *Wallet, err error) {
|
|
update := bson.M{"$inc": bson.M{"aiMateBalance": amt}}
|
|
if amt < 0 && aiMateOrderId != "" {
|
|
update["$set"] = bson.M{"lastAiMateRecordId": aiMateOrderId}
|
|
}
|
|
if err = coll(t).FindOneAndUpsert(&wallet, bson.M{"uid": uid}, update); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-CreditAmount]==> Model %s FindOneAndUpsert fail error:%+v:", table, err),
|
|
log.Any("aiMateBalance", amt),
|
|
log.Any("uid", uid),
|
|
)
|
|
}
|
|
return
|
|
}
|
|
|
|
// 重新设置用户ai积分
|
|
func SetAiMateBalance(t *db.MongoTool, uid uint64, aiMateBalance float64) error {
|
|
mutex.Lock()
|
|
defer mutex.Unlock()
|
|
_, err := coll(t).UpsertOne(bson.M{"uid": uid}, bson.M{"$set": bson.M{"aiMateBalance": aiMateBalance}})
|
|
return err
|
|
}
|
|
|
|
// GetIntegral 获取积分
|
|
func GetIntegral(t *db.MongoTool, uid uint64) (int64, error) {
|
|
w := &Wallet{}
|
|
if err := coll(t).FindOne(w, bson.M{"uid": uid}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetAmount", table, "FindOne", err),
|
|
log.Any("uid", uid),
|
|
)
|
|
return 0, err
|
|
}
|
|
return w.Integral, nil
|
|
}
|