package rechargeser import ( "91porn-server/app/service/activityclient" "91porn-server/app/service/adser" "91porn-server/middleware/ua" "91porn-server/models/v/advanceordermod" "context" "encoding/json" "errors" "fmt" "strconv" "sync" "time" "go.mongodb.org/mongo-driver/bson" "91porn-server/app/appg" "91porn-server/app/proto" "91porn-server/app/service" "91porn-server/app/service/productser" "91porn-server/common" "91porn-server/common/constant" "91porn-server/common/constant/redisconst" "91porn-server/common/db" "91porn-server/common/log" "91porn-server/common/rchgutil" "91porn-server/common/stderr" "91porn-server/models/commod" "91porn-server/models/v/currencymod" "91porn-server/models/v/goldcfgmod" "91porn-server/models/v/productmod" "91porn-server/models/v/productposimod" "91porn-server/models/v/rchgamegoldmod" "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" "github.com/shopspring/decimal" "go.mongodb.org/mongo-driver/bson/primitive" ) /* Recharge 充值 返回 充值链接、充值模式、错误 */ func Recharge(ctx context.Context, in *RechargeRequest, ua ua.UA, deduct *ActivityDeduct) (string, string, error) { u, err := usermod.FindUserByUID(in.UID) if err != nil { return "", "", err } if u == nil { return "", "", errors.New("invalid user") } if u.HasLocked { return "", "", errors.New("user is banned") } if err = in.validateAttribution(u.UID); err != nil { return "", "", err } // 创建订单 order, advanceOrder, err := in.CreateOrder(u, ua, deduct) if err != nil { log.ErrorX(ctx, fmt.Sprintf("用户ID[%d] 支付方式[%s] 购买类型[%d] 产品ID[%v] 产品子ID[%v] 创建订单异常[%v]", in.UID, in.RechargeType, in.BuyType, in.ProductID, in.ProductChildID, err)) return "", "", err } if err = rchgordmod.InsertRechargeOrder(order); err != nil { log.ErrorX(ctx, fmt.Sprintf("用户ID[%d] 支付方式[%s] 购买类型[%d] 产品ID[%v] 产品子ID[%v] 保存订单异常[%v]", in.UID, in.RechargeType, in.BuyType, in.ProductID, in.ProductChildID, err)) return "", "", err } if advanceOrder == nil || advanceOrder.ID.IsZero() { advanceOrder.AdvOid = order.ID.Hex() _, err = advanceordermod.CreditOrder(nil, advanceOrder) if err != nil { log.Error("RechargeRequest.CreateOrder 创建预售订单失败", log.Any("advanceOrder", advanceOrder), log.E(err)) return "", "", err } } else if advanceOrder.Status == advanceordermod.AdvanceProcessing { // 修改订单号和预付款 err := advanceordermod.Update(nil, advanceOrder.ID, bson.M{"advOid": order.ID.Hex(), "advanceAmount": advanceOrder.AdvanceAmount, "totalAmount": advanceOrder.TotalAmount}) if err != nil { log.Error("RechargeRequest.CreateOrder 修改预售订单失败", log.Any("advanceOrder.Status", advanceOrder.Status), log.E(err)) return "", "", err } } else if advanceOrder.Status == advanceordermod.AdvanceSUCCESS || advanceOrder.Status == advanceordermod.BalanceProcessing { err := advanceordermod.Update(nil, advanceOrder.ID, bson.M{"status": advanceordermod.BalanceProcessing, "balOid": order.ID.Hex()}) if err != nil { log.Error("RechargeRequest.CreateOrder 修改预售订单失败", log.Any("advanceOrder.Status", advanceOrder.Status), log.E(err)) return "", "", err } } // 下单 now := time.Now() res, err := (&rchgutil.Rchg{ TransNo: order.ID.Hex(), UID: strconv.FormatUint(order.UID, 10), DevID: order.DevID, UserIP: order.UserIP, Name: u.Name, Tel: order.Tel, DevType: order.DevType, Money: order.Money, Channel: "self", CreatedAt: now, PayMethod: order.RechargeType, ProductType: 0, }).ToPayNew(ctx) if err != nil { log.ErrorX(ctx, fmt.Sprintf("用户ID[%d] 支付方式[%s] 购买类型[%d] 产品ID[%v] 产品子ID[%v] 下单请求异常[%v]", in.UID, in.RechargeType, in.BuyType, in.ProductID, in.ProductChildID, err)) return "", "", err } log.InfoX(ctx, fmt.Sprintf("用户ID[%d] 支付方式[%s] 购买类型[%d] 产品ID[%v] 产品子ID[%v] 下单返回信息[%v]", in.UID, in.RechargeType, in.BuyType, in.ProductID, in.ProductChildID, res)) // 更新订单 set := rchgordmod.EditSelector{ Status: rchgordmod.Processing, ProgressAt: &now, OID: &res.OID, Mode: &res.Mode, Channel: &res.CID, Rate: &res.Rate, } if err = rchgordmod.Update(nil, order.ID, set); err != nil { log.ErrorX(ctx, fmt.Sprintf("用户ID[%d] 支付方式[%s] 购买类型[%d] 产品ID[%v] 产品子ID[%v] 更新订单异常[%v]", in.UID, in.RechargeType, in.BuyType, in.ProductID, in.ProductChildID, err)) return "", "", err } log.InfoX(ctx, fmt.Sprintf("用户ID[%d] 支付方式[%s] 购买类型[%d] 产品ID[%v] 产品子ID[%v] 【下单成功】", in.UID, in.RechargeType, in.BuyType, in.ProductID, in.ProductChildID)) // 会员抵扣券:建单成功异步回调活动服占用(active -> used),携实际抵扣额 if order.CouponID != "" { activityclient.NotifyDeductCouponAsync(order.CouponID, order.ID.Hex(), activityclient.DeductCouponStatusUsed, order.DeductAmount) } return res.PayUrl, res.Mode, nil } func Recharge_new(ctx context.Context, rchg *rchgordmod.RechargeOrder) (string, string, error) { u, err := usermod.FindUserByUID(rchg.UID) if err != nil { return "", "", err } if u == nil { return "", "", errors.New("invalid user") } rchg.DevID = u.DevID rchg.Name = u.Name rchg.DiscDoc = u.DiscDoc if rchg.ProductType == 0 { if rchg.VipID.IsZero() { // 金币充值 g, err := rchgamtmod.GetGoldByID(rchg.ProductID) if err != nil { return "", "", err } if g == nil { err = errors.New("invalid productID") return "", "", err } rchg.Amount = g.Coins rchg.Money = g.Price } else { p, err := productmod.FindProduct(rchg.VipID, rchg.DevType) if err != nil { return "", "", err } if p == nil { return "", "", errors.New("invalid productID") } //新用户8折 /*if u.CreatedAt.Add(time.Hour*24).After(time.Now()) && p.ProductType == prdcthsomod.VIP && (p.DiscountedPrice == 5000 || p.DiscountedPrice == 10000) { p.DiscountedPrice = int64(float64(p.DiscountedPrice) * 0.8) }*/ rchg.Amount = p.DiscountedPrice rchg.Money = p.DiscountedPrice * 10 } } if rchg.ProductType == 1 && rchg.Money <= 0 { return "", "", errors.New("invalid money") } now := time.Now() set := rchgordmod.EditSelector{ Status: rchgordmod.Processing, ProgressAt: &now, ProductType: &rchg.ProductType, } statusDesc := rchgordmod.Status(set.Status).Desc() set.StatusDesc = &statusDesc channel := "self" rchg.Channel = channel if err = rchgordmod.InsertRechargeOrder(rchg); err != nil { return "", "", err } var userLevel int if rchg.ProductType == 1 && u.HasFirstChargeWaLi { userLevel = 1 } res, err := (&rchgutil.Rchg{ TransNo: rchg.ID.Hex(), UID: strconv.FormatUint(u.UID, 10), DevID: rchg.DevID, UserIP: rchg.UserIP, Name: rchg.Name, Tel: u.Mobile, DevType: rchg.DevType, Money: rchg.Money, Channel: channel, CreatedAt: now, PayMethod: rchg.RechargeType, ProductType: rchg.ProductType, UserLevel: userLevel, }).ToPayNew(ctx) if err != nil { common.Go(func() { if appg.Bot == nil { return } //判断是否返回 渠道已经关闭 错误,此时商户将该渠道关闭 if err == rchgutil.PAY_CHANNEL_CLOSE_ERROR { return } }) return "", "", err } set.OID = &res.OID payUrl := res.PayUrl mode := res.Mode set.Mode = &mode set.Channel = &res.CID set.Rate = &(res.Rate) return payUrl, mode, rchgordmod.Update(nil, rchg.ID, set) } // GetPayChannel根据充值金额选择支付渠道 func GetPayChannel_new(ctx context.Context, sysType string, proT int) (data []*rchgamtmod.GoldRes, err error) { var golds []*currencymod.Currency // var discounts []*goldcfgmod.DiscountConfig var goldsError error wg := sync.WaitGroup{} wg.Add(1) common.Go(func() { defer wg.Done() golds, goldsError = currencymod.GetCurrencyListByRedis(commod.Gold) if goldsError != nil { return } }) wg.Wait() moneysM := make(map[int64]int) for vsi := range golds { moneysM[golds[vsi].Price] = 1 } moneys := make([]int64, len(moneysM)) mi := 0 for k := range moneysM { moneys[mi] = k mi++ } bc, _ := rchgutil.GetPayType(ctx, moneys, sysType, 0, 0) data = make([]*rchgamtmod.GoldRes, 0, len(golds)) for _, v := range golds { chans := GetPayChannelDetails_new(v.Price, bc, proT) if len(chans) <= 0 { // 没有支付方式的充值金额不展示 continue } data = append(data, &rchgamtmod.GoldRes{ ID: v.ID, RechargeType: chans, Amount: v.Coins, TypeName: v.Name, Money: v.Price, }) } return } func isLegalCurrencyType(t commod.CurrencyType) bool { return t == commod.Gold || t == commod.FruitCoin || t == commod.GameCoin } // CurrencyList 货币列表(新增果币) func CurrencyList(ctx context.Context, uid uint64, sysType string, t commod.CurrencyType) ([]*proto.CurrencyListResponse, stderr.Code) { if !isLegalCurrencyType(t) { log.ErrorX(ctx, "货币类型异常", log.Any("CurrencyType", t)) return nil, stderr.ErrParamError } var ( wg sync.WaitGroup // 同步控制 currencys []currencymod.Currency // 货币列表 moneys []int64 // 金额区间 removeRepeat = make(map[int64]struct{}, 0) // 金额去重 productType int // 产品类型 棋牌:1 站群:0 err error // 错误 isFirstPay bool // 棋牌首次充值 userLevel = 0 ) wg.Add(1) common.Go(func() { defer wg.Done() currencys, err = currencymod.List(t) if err != nil { log.ErrorX(ctx, "货币列表==>获取列表异常", log.Any("CurrencyType", t), log.E(err)) } }) if t == commod.GameCoin { wg.Add(1) productType = 1 common.Go(func() { defer wg.Done() u, err := usermod.FindUserByUID(uid) if err != nil { log.Error(fmt.Sprintf("货币列表==>棋牌首次充值查询异常[%v]", err)) return } if u.HasFirstChargeWaLi { userLevel = 1 } else { isFirstPay = true } }) } wg.Wait() if err != nil { return nil, stderr.ErrNetWorkBusy } for _, c := range currencys { if _, ok := removeRepeat[c.Price]; ok { continue } removeRepeat[c.Price] = struct{}{} moneys = append(moneys, c.Price) } bc, err := rchgutil.GetPayType(ctx, moneys, sysType, productType, userLevel) if err != nil { log.ErrorX(ctx, "获取支付通道列表异常", log.Any("moneys", moneys), log.Any("sysType", sysType), log.Any("productType", productType), log.E(err)) return nil, stderr.ErrNetWorkBusy } data := make([]*proto.CurrencyListResponse, 0, len(currencys)) for _, v := range currencys { if v.Price < 100 { continue } rechargeType := GetPayChannelDetails_new(v.Price, bc, productType) if len(rechargeType) <= 0 { // 无支付方式的充值金额不需要展示 continue } c := proto.CurrencyListResponse{ ID: v.ID, Amount: v.Coins, TypeName: v.Name, Money: v.Price, GiveVipDays: v.GiveVipDays, LouFengUnlockTimes: v.LouFengUnlockTimes, GiveGold: v.GiveGold, } if isFirstPay || v.NotFirst || t == commod.FruitCoin || t == commod.Gold { c.CouponDesc = v.CouponDesc } c.RechargeType = rechargeType data = append(data, &c) } return data, stderr.Success } func getChanByte(pType string) string { switch pType { case "wechat": //微信 return "微信【当前通道拥挤】" case "alipay": //支付宝 //return "支付宝【🔥限时返利15%金币】" return "支付宝【官方强烈推荐】" case "union": //支付宝 return "银联" case "daichong": //代充 return "代充" case "usdt": return "usdt" case "quickUnion": return "快捷银联" } return "" } func GetPayChannelDetails_new(money int64, payTypes []rchgutil.RchgType, proT int) []rchgamtmod.PayChannelRes { chans := make([]rchgamtmod.PayChannelRes, 0) for k := range payTypes { if payTypes[k].Money == money { if payTypes[k].Alipay { pName := getChanByte("alipay") chans = append(chans, rchgamtmod.PayChannelRes{ Type: "alipay", TypeName: pName, Channel: "alipay", }) } if payTypes[k].Wechat { pName := getChanByte("wechat") chans = append(chans, rchgamtmod.PayChannelRes{ Type: "wechat", TypeName: pName, Channel: "wechat", }) } if payTypes[k].DaiChong { pName := getChanByte("daichong") channel := appg.Conf.DaiChong.H5domain if proT == 1 { channel = appg.Conf.DaiChong.H5domainQP } chans = append(chans, rchgamtmod.PayChannelRes{ Type: "daichong", TypeName: pName, Channel: channel, }) } if payTypes[k].USDT { pName := getChanByte("usdt") chans = append(chans, rchgamtmod.PayChannelRes{ Type: "usdt", TypeName: pName, Channel: "usdt", }) } if payTypes[k].QuickUnion { pName := getChanByte("quickUnion") chans = append(chans, rchgamtmod.PayChannelRes{ Type: "quickUnion", TypeName: pName, Channel: "quickUnion", }) } if payTypes[k].Union { pName := getChanByte("union") chans = append(chans, rchgamtmod.PayChannelRes{ Type: "union", TypeName: pName, Channel: "union", }) } break } } return chans } func CallbackAddCoins(ctx context.Context, t *db.MongoTool, amount, decPay int64, desc string, order rchgordmod.RechargeOrder) (err error) { if err != nil { return err } wallet, err1 := walletmod.Credit(t, walletmod.CreditPlan{Amount: &amount, Consumption: &decPay}, order.UID) if err1 != nil { return err1 } tt := txnmod.TransactionLog{ TransNo: order.ID, UID: order.UID, Amount: amount, ActualAmount: float64(amount), TranType: txnmod.Rchg.Key(), TranTypeInt: int64(txnmod.Rchg), ChannelType: order.RechargeType, Desc: desc, DiscDoc: order.DiscDoc, SysType: order.DevType, RealAmount: walletmod.GetRealAmount(wallet), } //插入一条支出流水 if err = txnmod.InsertTransactionLog(t, &tt); err != nil { log.ErrorX(ctx, fmt.Sprintf("rechargeSer CallbackAddCoins Trans fail error:%+v order:%+v", err, order)) return } return } // RechargeCallBack 充值成功回调处理逻辑 func RechargeCallBack(ctx context.Context, oid string, payMoney int64, tradeNo string, code int, paymentAt, successAt time.Time) error { log.InfoX(ctx, "充值回调", log.Any("oid", oid), log.Any("tradeNo", tradeNo)) // 查询订单 r, err := rchgordmod.FindRechargeOrderByID(tradeNo) if err != nil { log.ErrorX(ctx, "充值回调查询订单异常", log.Any("oid", oid), log.Any("tradeNo", tradeNo), log.E(err)) return err } if r.ID.IsZero() { log.WarnX(ctx, "充值回调订单不存在", log.Any("oid", oid), log.Any("tradeNo", tradeNo)) return errors.New("订单不存在") } if r.Status == rchgordmod.SUCCESS { log.WarnX(ctx, "充值回调重复回调", log.Any("oid", oid), log.Any("tradeNo", tradeNo)) return nil } if r.Status == rchgordmod.REFUND { log.WarnX(ctx, "充值回调重复回调,订单已退款", log.Any("oid", oid), log.Any("tradeNo", tradeNo)) return nil } if r.Status != rchgordmod.Processing { log.WarnX(ctx, "充值回调订单状态异常", log.Any("oid", oid), log.Any("tradeNo", tradeNo), log.Any("status", r.Status)) return errors.New("订单状态异常") } if r.ProductType == 1 { return errors.New("瓦力游戏已下架") } // 回调订单号需与下单时支付平台返回的订单号一致 if r.OID != "" && oid != r.OID { log.ErrorX(ctx, "充值回调支付平台订单号不一致", log.Any("oid", oid), log.Any("orderOid", r.OID), log.Any("tradeNo", tradeNo)) return errors.New("oid 错误") } // 新版充值---根据购买类型处理 var ( fn func(*db.MongoTool) error now = time.Now() desc = rchgordmod.Status(rchgordmod.SUCCESS).Desc() csm int // 分成模式 ) switch r.BuyType { case commod.BuyGold: csm = rchgordmod.ChanShareCoin if fn, _, err = service.BuyGold(ctx, r, payMoney); err != nil { log.ErrorX(ctx, "充值回调购买金币异常", log.Any("oid", oid), log.Any("tradeNo", tradeNo), log.E(err)) return err } case commod.BuyGameCoin: if fn, err = service.BuyGameCoin(ctx, r, payMoney); err != nil { log.ErrorX(ctx, "充值回调购买游戏币异常", log.Any("oid", oid), log.Any("tradeNo", tradeNo), log.E(err)) return err } case commod.BuyFruitCoin: if fn, err = service.BuyFruitCoin(ctx, r, payMoney); err != nil { log.ErrorX(ctx, "充值回调购买果币异常", log.Any("oid", oid), log.Any("tradeNo", tradeNo), log.E(err)) return err } case commod.BuyProduct: if fn, csm, _, err = service.BuyProduct(ctx, r, payMoney); err != nil { log.ErrorX(ctx, "充值回调购买商品异常", log.Any("oid", oid), log.Any("tradeNo", tradeNo), log.E(err)) return err } default: // 默认为旧版购买处理 log.InfoX(ctx, "充值回调旧版本处理", log.Any("oid", oid), log.Any("tradeNo", tradeNo)) return errors.New("旧版回调不再支持, 请使用新版回调方式") } // 新版处理 if r.BuyType > 0 { err = appg.VideoDB.Trans(func(t *db.MongoTool) error { if err = rchgordmod.CallBackModifyWithProcessing(ctx, t, r.ID, rchgordmod.EditSelector{ PayMoney: &payMoney, OID: &oid, PaymentAt: &paymentAt, SuccessAt: &successAt, Status: rchgordmod.SUCCESS, StatusDesc: &desc, ChanShareMod: &csm, }); err != nil { return err } return fn(t) }) if err == nil { // ABC广告分组测试 common.Go(func() { user, _ := usermod.FindUserByUID(r.UID) if user != nil { _ = adser.UpsertAdStat(context.Background(), user, time.Now(), 0, 0, payMoney) } }) // 会员抵扣券:支付成功异步回调活动服核销(used -> verified) if r.CouponID != "" { activityclient.NotifyDeductCouponAsync(r.CouponID, r.ID.Hex(), activityclient.DeductCouponStatusVerified, r.DeductAmount) } } return err } id, err := primitive.ObjectIDFromHex(tradeNo) if err != nil { log.ErrorX(ctx, "ObjectIDFromHex fail", log.Any("tradeNo", tradeNo), log.E(err)) return err } set := rchgordmod.EditSelector{ PayMoney: &payMoney, OID: &oid, PaymentAt: &paymentAt, } if stderr.Code(code) != stderr.Success { set.Status = rchgordmod.FAILURE desc := rchgordmod.Status(rchgordmod.FAILURE).Desc() set.StatusDesc = &desc set.FailureAt = &now set.SuccessAt = &successAt return rchgordmod.CallBackModifyWithProcessing(ctx, nil, id, set) } if r.ProductID.IsZero() { //人民币购买会员卡 p, err := productmod.FindProduct(r.VipID, r.DevType) if err != nil { return err } if p == nil { return errors.New("invalid vipID") } disMoney := payMoney - (p.DiscountedPrice * 10) if disMoney < -constant.RechargeAmtTolerance { if payMoney <= 0 { return nil } tdesc := "购买「" + p.Name + "卡」实际支付" + strconv.FormatFloat(float64(payMoney)/100, 'f', 2, 64) + ",全额转为「" + strconv.FormatInt(payMoney/10, 10) + "」金币" return appg.VideoDB.Trans(func(t *db.MongoTool) error { csm := rchgordmod.ChanShareCoin set.ChanShareMod = &csm if err = rchgordmod.CallBackModifyWithProcessing(ctx, t, id, set); err != nil { return err } return CallbackAddCoins(ctx, nil, payMoney/10, payMoney, tdesc, r) }) } //查询金币优惠 localAmount := p.DiscountedPrice giveGold := false var gold int64 disCount, err := goldcfgmod.GetGoldCgfByAmountAndType(ctx, localAmount, r.RechargeType) if disCount != nil && err == nil { giveGold = true if disCount.IncrAmount != 0 { localAmount = disCount.IncrAmount gold = disCount.IncrAmount } else if disCount.IncTax != 0.0 { incr := decimal.NewFromFloat(disCount.IncTax) local := decimal.NewFromInt(localAmount) localAmount = localAmount + local.Mul(incr).IntPart() } } if p.ChanSplitMod == 1 { //正常分成 csm := rchgordmod.ChanShareModVIP set.ChanShareMod = &csm } if err = appg.VideoDB.Trans(func(t *db.MongoTool) error { set.SuccessAt = &successAt set.Status = rchgordmod.SUCCESS desc := rchgordmod.Status(rchgordmod.SUCCESS).Desc() set.StatusDesc = &desc if err = rchgordmod.CallBackModifyWithProcessing(ctx, t, id, set); err != nil { return err } creditPlan := walletmod.CreditPlan{ Consumption: &payMoney, } if giveGold { creditPlan.Amount = &localAmount } if _, err = walletmod.Credit(t, creditPlan, r.UID); err != nil { log.ErrorX(ctx, "walletmod.Credit failed", log.Any("creditPlan", creditPlan), log.Any("uid", r.UID), log.E(err)) return err } fPayMoney := float32(payMoney) if disMoney > 9 { tdesc := "购买「" + p.Name + "卡」实际支付" + strconv.FormatFloat(float64(fPayMoney)/100, 'f', 2, 64) + ",超额部分转为「" + strconv.FormatInt(disMoney/10, 10) + "」金币" if err = CallbackAddCoins(ctx, t, disMoney/10, 0, tdesc, r); err != nil { return err } } if err = RechargeBuy_p(t, r.UID, *p, gold); err != nil { log.ErrorX(ctx, "RechargeBuy_p failed", log.Any("uid", r.UID), log.Any("product", p), log.Any("gold", gold), log.E(err)) return err } return nil }); err != nil { log.ErrorX(ctx, "WalletSer RechargeCallBack Trans fail", log.E(err)) return err } } else { //充值金币 amount := payMoney / 10 g, err := rchgamtmod.GetGoldByID(r.ProductID) if err != nil { return err } if g == nil { return errors.New("invalid productID") } if !r.VipID.IsZero() { if amount > (g.Coins-10) && amount < g.Coins { amount = g.Coins } } else { //充值赠送金币 localAmount := amount giveGold := false disCount, err := goldcfgmod.GetGoldCgfByAmountAndType(ctx, localAmount, r.RechargeType) if disCount != nil && err == nil { giveGold = true if disCount.IncrAmount != 0 { localAmount = disCount.IncrAmount } else if disCount.IncTax != 0.0 { incr := decimal.NewFromFloat(disCount.IncTax) local := decimal.NewFromInt(localAmount) localAmount = localAmount + local.Mul(incr).IntPart() } } if giveGold { amount += localAmount } } csm := rchgordmod.ChanShareCoin set.ChanShareMod = &csm if err = appg.VideoDB.Trans(func(t *db.MongoTool) error { set.SuccessAt = &successAt set.Status = rchgordmod.SUCCESS desc := rchgordmod.Status(rchgordmod.SUCCESS).Desc() set.StatusDesc = &desc if err = rchgordmod.CallBackModifyWithProcessing(ctx, t, id, set); err != nil { return err } if err = walletmod.CreditConsumption(t, payMoney, r.UID); err != nil { return err } wallet, err := walletmod.CreditAmount(t, amount, r.UID) if err != nil { return err } tt := txnmod.TransactionLog{ TransNo: r.ID, UID: r.UID, Amount: amount, ActualAmount: float64(amount), TranType: txnmod.Rchg.Key(), TranTypeInt: int64(txnmod.Rchg), ChannelType: r.RechargeType, Desc: "充值新增-" + strconv.FormatInt(amount, 10), DiscDoc: r.DiscDoc, SysType: r.DevType, RealAmount: walletmod.GetRealAmount(wallet), } //插入一条支出流水 return txnmod.InsertTransactionLog(t, &tt) }); err != nil { log.ErrorX(ctx, "WalletSer RechargeCallBack Trans fail", log.E(err)) return err } } // ABC广告分组测试 common.Go(func() { user, _ := usermod.FindUserByUID(r.UID) if user != nil { _ = adser.UpsertAdStat(context.Background(), user, time.Now(), 0, 0, payMoney) } }) // //用户充值成功时做充值扣量 // executionRechargeDeduction(ctx, tradeNo) return nil } func FindProductByTypeNew(ctx context.Context, uid uint64, sysType string, newUser bool, proT int) (res []proto.ProductList, err error) { redisKey := redisconst.DataCachKey(productmod.RedisSetKey, "FindProductByTypeNew"+sysType+strconv.FormatBool(newUser)) if !appg.Redis.IsExist(redisKey) { var data []productmod.Product var discounts []*goldcfgmod.DiscountConfig var positionM map[string]string var positionL []string var ps map[string]int64 var ( goldsError, discountsError, positionError error ) wg := sync.WaitGroup{} wg.Add(3) //获取金币配置优惠 common.Go(func() { defer wg.Done() discounts, discountsError = goldcfgmod.GetGoldConfigList() }) common.Go(func() { defer wg.Done() flag := true data, goldsError = productmod.FindProductsByProductType(&flag, newUser, sysType) if goldsError != nil { err = goldsError return } }) common.Go(func() { defer wg.Done() positionM, ps, positionL, positionError = productposimod.FindNamesWithStatusTrue() if positionError != nil { err = positionError return } }) wg.Wait() moneysM := make(map[int64]int) for vsi := range data { moneysM[data[vsi].DiscountedPrice*10] = 1 } moneys := make([]int64, len(moneysM)) mi := 0 for k := range moneysM { moneys[mi] = k mi++ } bc, _ := rchgutil.GetPayType(ctx, moneys, sysType, proT, 0) res = make([]proto.ProductList, len(positionL)) for i := range positionL { pl := make([]proto.VIPListRes, 0) res[i] = proto.ProductList{ ShowType: ps[positionL[i]], Position: positionM[positionL[i]], List: pl, PositionID: positionL[i], } } for _, v := range data { price := v.DiscountedPrice * 10 if v.ProductType == productmod.AdvanceCard { price = v.AdvanceAmount * 10 } chans := GetPayChannelDetails_new(price, bc, proT) if v.ProductType == commod.PhysicalGoods { v.Name = "" } temp := proto.VIPListRes{ Product: v, } if discountsError == nil && len(discounts) > 0 { for i := 0; i < len(chans); i++ { for _, d := range discounts { if chans[i].Type == d.Type && v.DiscountedPrice == d.Amount { chans[i].IncrAmount = d.IncrAmount chans[i].IncTax = d.IncTax } } } } temp.RechargeType = chans for k := range res { if positionM[v.Position] == res[k].Position { res[k].List = append(res[k].List, temp) continue } } } jsonBytes, err := json.Marshal(res) if err != nil { return res, err } _ = appg.Redis.Set(redisKey, string(jsonBytes), redisconst.DataCachExpire) } str, err := appg.Redis.Get(redisKey) if err != nil || str == nil { return } if err = json.Unmarshal([]byte(*str), &res); err != nil { return } return } // RechargeBuy 充值回调时购买w func RechargeBuy_p(t *db.MongoTool, uid uint64, p productmod.Product, giveGold int64) error { switch p.ProductType { case productmod.MeetingCard: //约会卡: return productser.BuyMeetingCard_d(t, uid, p) case productmod.OTHER, productmod.PHYSICALGOODS: return productser.BuyOtherCard_d(t, uid, p) case productmod.VIP, productmod.NewUser: return productser.BuyVIP_d(t, uid, p, giveGold) case productmod.VideoFreeCard: return productser.BuyVideoFreeCard_d(t, uid, p) case productmod.VideoDiscount: return productser.BuyVideoDiscountCard_d(t, uid, p) } return errors.New("invalid productType") } func GetPayChannel_qp(ctx context.Context, uid uint64, sysType string) (data []*rchgamtmod.GameGoldRes, err error) { gameGolds, err := rchgamegoldmod.GetGoldListByActiveTrue() if err != nil { return } moneys := make([]int64, len(gameGolds)) for i, v := range gameGolds { moneys[i] = v.Price } if len(gameGolds) == 0 { //@todo:兼容旧版本,以后删除 moneys = []int64{5000, 10000, 28800, 39800, 59600, 100000, 300000, 500000} //单位分 金额50, ... ,5000元 for _, v := range moneys { gameGolds = append(gameGolds, &rchgamegoldmod.Gold{ Coins: v, Price: v, }) } } firstPay := true userLevel := 0 if u, _ := usermod.FindUserByUID(uid); u != nil { if u.HasFirstChargeWaLi { firstPay = false userLevel = 1 } } bc, err := rchgutil.GetPayType(ctx, moneys, sysType, 1, userLevel) if err != nil { return } data = make([]*rchgamtmod.GameGoldRes, 0, len(gameGolds)) for _, v := range gameGolds { chans := GetPayChannelDetails_new(v.Price, bc, 1) if len(chans) <= 0 { // 没有支付方式的充值金额不展示 continue } gold := rchgamtmod.GameGoldRes{ Amount: v.Coins * 100, TypeName: fmt.Sprintf("%d元充值", v.Price/100), Money: v.Price, } if firstPay || v.NotFirst { gold.CouponDesc = v.CouponDesc } gold.RechargeType = chans data = append(data, &gold) } return } func GetUserTransactionDetails(uid, pageNum, pageSize uint64) (total int64, data []proto.TransactionResp, hasNext bool, err error) { //获取用户成功的交易记录 total, rechangeOrders, hasNext, _ := rchgordmod.GetSuccessOrderUidList(uid, pageSize, pageNum) rechangeOrdersLen := len(rechangeOrders) goldProductIds := make([]primitive.ObjectID, 0, rechangeOrdersLen) vipProductIds := make([]primitive.ObjectID, 0, rechangeOrdersLen) productIdMap := make(map[primitive.ObjectID]primitive.ObjectID) for _, v := range rechangeOrders { if _, ok := productIdMap[v.ProductID]; !ok { if v.BuyType == commod.BuyGold || v.BuyType == commod.BuyGameCoin || v.BuyType == commod.BuyFruitCoin { goldProductIds = append(goldProductIds, v.ProductID) } else { vipProductIds = append(vipProductIds, v.ProductID) } productIdMap[v.ProductID] = v.ProductID } } ctx := context.Background() //根据产品id 查询对应的奖品 vipProductMap, err := productmod.ListByIDsMap(vipProductIds) if err != nil { log.ErrorX(ctx, "ListByIDsMap failed", log.Any("vipProductIds", vipProductIds), log.E(err)) return } //根据产品id 查询金币对应的一个奖品 goldProductMap, err := currencymod.ListByIdsMap(goldProductIds) if err != nil { log.ErrorX(ctx, "ListByIdsMap failed", log.Any("goldProductIds", goldProductIds), log.E(err)) return } data = make([]proto.TransactionResp, len(rechangeOrders)) for i, v := range rechangeOrders { resp := proto.TransactionResp{ OrderId: v.OID, Money: v.Money, PaymentAt: v.PaymentAt, CreatedAt: v.CreatedAt, PayType: v.RechargeType, Status: v.Status, } if resp.Status == 3 { resp.Money = v.PayMoney } if v.BuyType == commod.BuyProduct { if p := vipProductMap[v.ProductID]; p != nil { resp.ProductName = p.Name } } else { if p := goldProductMap[v.ProductID]; p != nil { resp.ProductName = p.Name } } data[i] = resp } return }