package rechargeser import ( "context" "errors" "fmt" "strconv" "time" "91porn-server/common" "91porn-server/common/db" "91porn-server/common/log" "91porn-server/common/stderr" "91porn-server/models/v/prdcthsomod" "91porn-server/models/v/productmod" "91porn-server/models/v/rchgamtmod" "91porn-server/models/v/rchgordmod" "91porn-server/models/v/txnmod" "91porn-server/models/v/usermod" "91porn-server/models/v/walletmod" "91porn-server/web/webg" "go.mongodb.org/mongo-driver/bson/primitive" ) // RechargeCallBack 充值成功回调处理逻辑 func RechargeCallBack(ctx context.Context, oid string, payMoney int64, tradeNo string, code int, paymentAt time.Time) error { r, err := rchgordmod.FindRechargeOrderByID(tradeNo) if err != nil { return err } if r.Status == rchgordmod.SUCCESS { return nil } if r.OID != "" && r.OID != oid { log.Error("WalletSer RechargeCallBack ObjectIDFromHex fail error: 1:") return errors.New("1") } if r.Status != rchgordmod.Processing { log.Error(fmt.Sprintf("WalletSer RechargeCallBack status fail data:%+v:", r.Status)) return errors.New("1") } g, err := rchgamtmod.GetGoldByID(r.ProductID) if err != nil { return err } if g == nil { return errors.New("invalid productID") } id, err := primitive.ObjectIDFromHex(tradeNo) if err != nil { log.ErrorX(ctx, "ObjectIDFromHex fail", log.Any("tradeNo", tradeNo), log.E(err)) return err } now := time.Now() set := rchgordmod.EditSelector{ PayMoney: &payMoney, OID: &oid, PaymentAt: &paymentAt, } if stderr.Code(code) != stderr.Success { set.Status = rchgordmod.FAILURE statusDesc := rchgordmod.Status(rchgordmod.FAILURE).Desc() set.StatusDesc = &statusDesc set.FailureAt = &now return rchgordmod.CallBackModifyWithProcessing(ctx, nil, id, set) } if err = webg.VideoDB.Trans(func(t *db.MongoTool) error { set.SuccessAt = &now set.Status = rchgordmod.SUCCESS statusDesc := rchgordmod.Status(rchgordmod.FAILURE).Desc() set.StatusDesc = &statusDesc if err = rchgordmod.CallBackModifyWithProcessing(ctx, t, id, set); err != nil { return err } //默认以实际支付金额上分 amount := payMoney / 10 //实际支付小于订单金额1块,返回错误 if amount < (g.Coins - 10) { log.WarnX(ctx, "invalid;payMoney invalid payMoney value;", log.Any("gold coins", g.Coins), log.Any("amount", amount)) return errors.New("invalid payMoney value;") } //实际支付金额小于订单金额,范围在1块以内,按订单金额上分 if amount < g.Coins { amount = g.Coins } wallet, err := walletmod.CreditAmount(t, amount, r.UID) if err != nil { return err } if err = walletmod.CreditConsumption(t, payMoney, r.UID); err != nil { return err } tt := txnmod.TransactionLog{ TransNo: r.ID, UID: r.UID, Amount: r.Amount, TranType: txnmod.Rchg.Key(), TranTypeInt: int64(txnmod.Rchg), ChannelType: r.RechargeType, Desc: "充值新增-" + strconv.FormatInt(amount, 10), DiscDoc: r.DiscDoc, SysType: r.DevType, ActualAmount: float64(r.Amount), RealAmount: walletmod.GetRealAmount(wallet), } //插入一条支出流水 return txnmod.InsertTransactionLog(t, &tt) }); err != nil { log.ErrorX(ctx, "WalletSer RechargeCallBack Trans fail", log.E(err)) return err } if !r.VipID.IsZero() { common.Go(func() { _ = buyVIP(r.UID, r.VipID, r.DevType) }) } return nil } func checkVipRenew(u *usermod.User, p *productmod.Product) (time.Time, int, int) { now := time.Now() var end time.Time level := p.VipLevel payVidDiscount := p.PayVidDiscount d := time.Hour * 24 * time.Duration(p.Duration) if u.VipExpireDate.After(now) { //renew end = u.VipExpireDate.Add(d) if u.VipLevel > p.VipLevel { //当前用户的vip等级比这次购买的大,使用用户的 level = u.VipLevel } if u.PayVidDiscount > 0 && u.PayVidDiscount < p.PayVidDiscount { payVidDiscount = u.PayVidDiscount } } else { end = now.Add(d) } return end, level, payVidDiscount } func debitPlan(w *walletmod.Wallet, amt int64) *walletmod.DebitPlan { p := walletmod.DebitPlan{} l1 := w.Amount - amt if l1 >= 0 { //amount够了 p.Amount = amt return &p } // l1 < 0 p.Amount = w.Amount //amount 扣完 l2 := w.Income + l1 if l2 >= 0 { p.Income = -l1 return &p } return nil //余额不足 } func getDiscInfo(user *usermod.User) txnmod.DiscDoc { discDoc := txnmod.DiscDoc{} discDoc.IsDirect = user.IsDirect discDoc.DistrictCode = user.DistrictCode discDoc.PromSeqe = user.PromSeqe return discDoc } // BuyProduct 购买产品产生的行为 func buyVIP(uid uint64, productID primitive.ObjectID, sys string) stderr.Code { p, err := productmod.FindProduct(productID, sys) if err != nil || p == nil { return stderr.ErrParamError } u, err := usermod.FindUserByUID(uid) if err != nil || u == nil { return stderr.ErrDbQueryError } w, err := walletmod.GetWallet(uid) if err != nil || w == nil { return stderr.ErrDbQueryError } plan := debitPlan(w, p.DiscountedPrice) if plan == nil { return stderr.InsufficientBalance } vipExpire, vipLevel, payVidDiscount := checkVipRenew(u, p) sel := usermod.UserSelector{VipExpireDate: &vipExpire, VipLevel: &vipLevel, PayVidDiscount: &payVidDiscount} if p.DramaDays > 0 { expire := usermod.RenewDramaExpire(u.DramaExpire, time.Now(), p.DramaDays) sel.DramaExpire = &expire } if err = webg.VideoDB.Trans(func(t *db.MongoTool) error { var err error var wallet *walletmod.Wallet if wallet, err = walletmod.Debit(t, plan, uid); err != nil { //扣钱 return err } history := prdcthsomod.ProductHistory{ //插入商品购买记录 UID: uid, ProductID: productID, Name: p.Name, Amount: plan.Amount, Income: plan.Income, ProductType: prdcthsomod.VIP, DiscDoc: u.DiscDoc, SysType: u.SysType, ProductSnapShot: p, } if err = prdcthsomod.InsertProductHistory(t, &history); err != nil { return err } if err = usermod.UpdateVIP(t, uid, u.VipExpireDate, sel); err != nil { return err } txnLog := txnmod.TransactionLog{UID: uid, Amount: -p.DiscountedPrice, TranType: txnmod.PayVIP.Key(), TranTypeInt: int64(txnmod.PayVIP), TransNo: history.ID, Desc: "购买了" + p.Name, DiscDoc: getDiscInfo(u), SysType: u.SysType, ActualAmount: -float64(p.DiscountedPrice), RealAmount: walletmod.GetRealAmount(wallet)} return txnmod.InsertTransactionLog(t, &txnLog) }); err != nil { return stderr.ErrDbTransError } return stderr.Success }