package proxyser import ( "91porn-server/app/service/taskser" "91porn-server/common/timeutil" "91porn-server/models/v/dailytaskmod" "91porn-server/models/v/rchgordmod" "91porn-server/models/v/taskmod" "errors" "strconv" "strings" "time" "91porn-server/app/appg" "91porn-server/common" "91porn-server/common/constant" "91porn-server/common/db" "91porn-server/common/log" "91porn-server/common/stderr" "91porn-server/models/v/prdcthsomod" "91porn-server/models/v/proxymod" "91porn-server/models/v/proxyrecordmod" "91porn-server/models/v/sourcemod" "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" ) var PerformanceConvRat = []int64{100, 25, 15, 10} // 推广 func Invite(inv *proxyrecordmod.InvitationRecord) (err error) { u, err := usermod.FindUserByUID(inv.UID) if err != nil || u == nil { return } p := sourcemod.GetRandomPromotionURL() inv.PromotionCode = u.PromCode inv.URL = common.BindUrl(p, constant.PromotionField+u.PromCode) if err = proxyrecordmod.InsertInvitationRecord(inv); err != nil { return } return } // InviteLog 推广绑定记录 func InviteLog(uid uint64, pageNumber int, pageSize int) (res []*proxymod.InvitationRes, hasNext bool, err error) { data, hasNext, err := proxymod.GetInvitationByUID(uid, int64(pageNumber), int64(pageSize)) if err != nil { return } if len(data) <= 0 { res = make([]*proxymod.InvitationRes, 0) return } res = make([]*proxymod.InvitationRes, len(data)) for idx, v := range data { i := proxymod.InvitationRes{} i.Invitation = *v i.IsBoughtVIP, err = prdcthsomod.IsBoughtVIP(v.Invitee) if err != nil { return } res[idx] = &i } return } type Invitation = proxymod.Invitation // InviteBind 推广绑定 func InviteBind(uid uint64, parentdisc string, isBind bool) stderr.Code { now := time.Now() //查询推广用户 user, err := usermod.FindUserByUID(uid) if err != nil { log.Warn("InviteBind FindUserByUID error", log.E(err), log.Any("uid", uid)) return stderr.Failure } if user == nil { return stderr.ErrParamError } // 通过推广str查询父级用户 parent, err := findUserByPromotionStr(parentdisc) if err != nil { switch err.(type) { case PromStrInvalidError: return stderr.InvalidPromotionCode default: return stderr.ErrDbQueryError } } // 判断推广是否合法 if err = canInvite(user, parent); err != nil { switch err.(type) { case SelfInvError: return stderr.SelfPromotionCode case proxymod.LoopInviteError: return stderr.PromoteHasBind default: return stderr.NotInvitedUsers } } i := Invitation{ UID: parent.UID, Invitee: uid, InviteePortrait: user.Portrait, InviteCode: parentdisc, CreatedAt: now, InviteeName: user.Name, IsRecharge: false, } if isBind { i.InviteTime = now } //invitation表插入记录 if err := proxymod.InsertOne(i); err != nil { switch err.(type) { case proxymod.LoopInviteError: return stderr.PromoteHasBind default: return stderr.ErrDbInsertError } } common.Go(func() { // 限制同ip注册不增加vip时间 if user.RegisterIP != parent.RegisterIP { // 同一用户, 一天最多增加3个人的分享vip天数 startTime, endTime := timeutil.EarlyLastDay(time.Now()) maxCount, _ := proxymod.GetInviteesCount([]uint64{parent.UID}, startTime, endTime) if maxCount < 3 { _ = addFreeTime(*parent, 1*24*60*60) } log.Info("InviteBind addFreeTime", log.Any("uid", uid), log.Any("parentUid", parent.UID), log.Any("maxCount", maxCount), log.Any("startTime", startTime), log.Any("endTime", endTime)) } }) go func() { _ = taskser.CompleteDailyTask(nil, parent.UID, dailytaskmod.DailyTaskTypeUserInvite) maxCount, _ := proxymod.CountByUID(parent.UID) taskser.CompleteGrowthTask(parent.UID, taskmod.GrowthBuyInviteUser, maxCount) _ = taskser.ReSignCallBack(parent.UID) }() return stderr.Success } // addFreeTime 增加Vip FreeTime func addFreeTime(user usermod.User, freeSecond int64) error { freeTime := time.Unix(time.Now().Unix()+freeSecond, 0) if user.VipExpireDate.After(time.Now()) { freeTime = time.Unix(user.VipExpireDate.Unix()+freeSecond, 0) } upd := usermod.UserSelector{VipExpireDate: &freeTime} if user.VipLevel == 0 { l := 1 upd.VipLevel = &l } _, err := usermod.Update(user.UID, upd) return err } func canInvite(user, parent *usermod.User) error { if user == nil || parent == nil { return errors.New("user is nil!") } //不能自我推广 if user.UID == parent.UID { return SelfInvError{user.UID} } if user.CreatedAt.AddDate(0, 0, 1).Before(time.Now()) { return errors.New("time is expire") } if user.CreatedAt.Before(parent.CreatedAt) { return errors.New("invaild invite") } // 推广用户只能是离散节点,不允许闭环推广 count, err := proxymod.CountByUID(user.UID) if err != nil { return err } if count != 0 { return proxymod.LoopInviteError{Parent: parent.UID, UID: user.UID} } return nil } func GetInv(uid uint64) (uint64, error) { return proxymod.GetInvrLv1(uid) } func findUserByPromotionStr(promoCode string) (*usermod.User, error) { parent, err := usermod.FindUserPromotionCode(promoCode) if err != nil { return nil, err } if parent == nil { log.Warn("userser InviteBind fail: invalid promotion code", log.Any("promoCode", promoCode)) return nil, PromStrInvalidError{promoCode} } return parent, nil } // GetInveUsers 获取下级代理 func GetInveUsers(uid uint64) (invMap map[string][]*usermod.User, err error) { invMap = make(map[string][]*usermod.User, 0) var MaxLv = 4 var flag = 0 ids := []uint64{uid} usersChan := make(chan map[string][]*usermod.User, MaxLv) for i := 1; i <= MaxLv; i++ { flag += 1 uids, _, err := proxymod.GetInveNext(ids) if err != nil || len(ids) <= 0 { break } go func(ids []uint64, lv int, datachan chan map[string][]*usermod.User) { var users []*usermod.User m := make(map[string][]*usermod.User) users, _ = usermod.FindUsersByUID(ids) m["lv"+strconv.Itoa(lv)] = users datachan <- m }(uids, i, usersChan) ids = uids } for i := 0; i < flag; i++ { um, ok := <-usersChan if !ok { break } for k, v := range um { invMap[k] = v } } return } func StatCenterIncPerformance(t *db.MongoTool, uid uint64, proxyUserId uint64, incomeAmount int64, orderId string) error { u, err := usermod.FindUserByUID(uid) if err != nil { if err.Error() == "empty user" { return nil } return errors.New("invalid user") } if u == nil { return nil } orderIdV1 := strings.Replace(orderId, "CZ-DSP-", "", -1) objId, err := primitive.ObjectIDFromHex(orderIdV1) if err != nil { log.Error("StatCenterIncPerformance ObjectIDFromHex err", log.E(err)) return err } income := incomeAmount // 金币 pIncome := income creditPlan := walletmod.CreditPlan{ Income: &income, ProxyIncome: &pIncome, } wallet, err := walletmod.Credit(t, creditPlan, uid) if err != nil { return err } desc := "推广用户充值返现" transacton := txnmod.TransactionLog{ UID: uid, TransNo: objId, Amount: income, ActualAmount: float64(income), TranType: txnmod.ProxyIncome.Key(), TranTypeInt: int64(txnmod.ProxyIncome), Desc: desc, RechargeId: proxyUserId, RealAmount: walletmod.GetRealAmount(wallet), } return txnmod.InsertTransactionLog(t, &transacton) } type WaLiPromoteSettleSyncDataReq struct { Size int `json:"size"` ID []primitive.ObjectID `json:"id" bson:"_id,omitempty"` SetDate []time.Time `json:"setDate" bson:"setDate"` //结算日期 Money []decimal.Decimal `json:"money" bson:"money"` //收益金额 元 AppId []int `json:"appId" bson:"appId"` //appid UID []uint64 `json:"uid" bson:"uid"` //用户id NoticeStatus []int `json:"noticeStatus" bson:"noticeStatus"` //通知状态 } type WaLiPromoteSettleSyncDataRes struct { ID []primitive.ObjectID `json:"id" bson:"_id,omitempty"` } func StatCenterIncPerformanceWaLi(req WaLiPromoteSettleSyncDataReq) (res WaLiPromoteSettleSyncDataRes) { successIDSlice := make([]primitive.ObjectID, 0) for i := 0; i < req.Size; i++ { income := req.Money[i].Shift(1).IntPart() // 金币 pIncome := float64(income) //金币 cp := walletmod.CreditPlan{ Income: &income, WaLiProxyIncome: &pIncome, } flag := 1 _ = appg.VideoDB.Trans(func(t *db.MongoTool) error { wallet, err := walletmod.Credit(t, cp, req.UID[i]) if err != nil { flag = 2 return err } transacton := txnmod.TransactionLog{ UID: req.UID[i], UniqueOrder: req.ID[i].Hex(), Amount: income, ActualAmount: float64(income), TranType: txnmod.WaLiProxyIncome.Key(), TranTypeInt: int64(txnmod.WaLiProxyIncome), Desc: "游戏推广用户充值返现", RealAmount: walletmod.GetRealAmount(wallet), } if err = txnmod.InsertTransactionLog(t, &transacton); err != nil { if stderr.IsEqual(err, stderr.InsertExistError) { return err } flag = 2 return err } return nil }) if flag == 2 { continue } successIDSlice = append(successIDSlice, req.ID[i]) } res.ID = successIDSlice return } // GetInveUserList 获取下级代理列表 func GetInveUserList(uid, pageNumber, pageSize uint64) (list []*proxymod.Invitation, total int64, err error) { //查询用户推广列表 total, list, err = proxymod.FindManyByApp(uid, pageNumber, pageSize) if err != nil { log.Error("HandelProxyRechargeCommission proxymod.FindManyByApp err", log.E(err), log.Any("uid", uid)) return list, 0, nil } if len(list) == 0 { log.Warn("HandelProxyRechargeCommission len(list) == 0", log.Any("uid", uid)) return list, 0, nil } return list, total, nil } // HandelProxyRechargeCommission 处理代理充值分成 func HandelProxyRechargeCommission(t *db.MongoTool, orderId string, payMoney int64) { //return // 充值订单用户id var uid uint64 = 0 // 截取订单号 orderIdV1 := strings.Replace(orderId, "CZ-91PO-", "", -1) // 验证充值订单 order, err := rchgordmod.FindRechargeOrderByID(orderIdV1) if err != nil { log.Error("HandelProxyRechargeCommission rchgordmod.FindRechargeOrderByID err", log.E(err), log.Any("orderId", orderId)) return } uid = order.UID if order.Status != rchgordmod.SUCCESS { log.Warn("HandelProxyRechargeCommission order.Status != rchgordmod.SUCCESS", log.Any("uid", uid), log.Any("orderId", orderId)) return } // 棋牌订单不参与分成 if order.ProductType == 1 { log.Info("HandelProxyRechargeCommission order.ProductType == 1", log.Any("uid", uid), log.Any("orderId", orderId)) return } // 金币订单不参与分成 if order.Category == 0 { log.Info("HandelProxyRechargeCommission order.Category == 0", log.Any("uid", uid), log.Any("orderId", orderId)) return } // 查询用户上级id proxyUserId, err := proxymod.GetInvrLv1(uid) if err != nil { log.Error("HandelProxyRechargeCommission proxymod.GetInvrLv1 err", log.E(err), log.Any("uid", uid), log.Any("proxyUserId", proxyUserId), log.Any("orderId", orderId)) return } if proxyUserId == 0 { log.Warn("HandelProxyRechargeCommission proxyUserId == 0", log.E(err), log.Any("uid", uid), log.Any("proxyUserId", proxyUserId), log.Any("orderId", orderId)) return } // 查询当前订单是否已经分成 if txnmod.IsProxyExist(proxyUserId, order.ID) { log.Warn("HandelProxyRechargeCommission txnmod.IsProxyExist == true", log.Any("uid", uid), log.Any("proxyUserId", proxyUserId), log.Any("orderId", orderId)) return } // 查询用户信息 u, err := usermod.FindUserByUID(proxyUserId) if err != nil { log.Error("HandelProxyRechargeCommission usermod.FindUserByUID err", log.E(err), log.Any("uid", uid), log.Any("proxyUserId", proxyUserId), log.Any("orderId", orderId)) return } if u == nil { log.Warn("HandelProxyRechargeCommission u == nil", log.Any("uid", uid), log.Any("proxyUserId", proxyUserId), log.Any("orderId", orderId)) return } // 查询代理用户钱包 proxyUserWallet, err := walletmod.GetWallet(proxyUserId) if err != nil { log.Error("HandelProxyRechargeCommission walletmod.GetWallet err", log.E(err), log.Any("uid", uid), log.Any("proxyUserId", proxyUserId), log.Any("orderId", orderId)) return } if proxyUserWallet == nil { log.Warn("HandelProxyRechargeCommission proxyUserWallet == nil", log.Any("uid", uid), log.Any("proxyUserId", proxyUserId), log.Any("orderId", orderId)) return } //分成收益计算,单位:金币个数 var incomeAmount int64 = 0 //代理推广用户累计充值 var proxyConsumption int64 = (proxyUserWallet.ProxyConsumption + payMoney) / 100 var money int64 = payMoney / 100 if proxyConsumption < 2000 { //充值2000元以内, 返利50% incomeAmount = money * 50 / 10 } else if proxyConsumption > 2000 && proxyConsumption < 10000 { //充值2000—10000元以内, 返利60% incomeAmount = money * 60 / 10 } else if proxyConsumption > 10000 && proxyConsumption < 30000 { //充值10000—30000元以内, 返利65% incomeAmount = money * 65 / 10 } else if proxyConsumption > 30000 { //充值大于30000元, 返利70% incomeAmount = money * 70 / 10 } // 事务处理, 增加流水日志、代理收益 _ = appg.VideoDB.Trans(func(t *db.MongoTool) error { //增加收益余额 pIncome := incomeAmount creditPlan := walletmod.CreditPlan{ Income: &incomeAmount, ProxyIncome: &pIncome, ProxyConsumption: &payMoney, } wallet, err := walletmod.Credit(t, creditPlan, proxyUserId) if err != nil { log.Warn("HandelProxyRechargeCommission walletmod.Credit err", log.E(err), log.Any("uid", uid), log.Any("proxyUserId", proxyUserId), log.Any("orderId", orderId)) return err } //新增流水日志 transacton := txnmod.TransactionLog{ UID: proxyUserId, TransNo: order.ID, Amount: incomeAmount, ActualAmount: float64(incomeAmount), TranType: txnmod.ProxyIncome.Key(), TranTypeInt: int64(txnmod.ProxyIncome), Desc: "推广用户充值返现", RechargeId: uid, RealAmount: walletmod.GetRealAmount(wallet), } err = txnmod.InsertTransactionLog(t, &transacton) if err != nil { log.Warn("HandelProxyRechargeCommission txnmod.InsertTransactionLog err", log.E(err), log.Any("uid", uid), log.Any("proxyUserId", proxyUserId), log.Any("orderId", orderId)) return err } err = proxymod.UpdateByUid(t, uid, proxyUserId) if err != nil { log.Warn("HandelProxyRechargeCommission proxymod.UpdateByUid err", log.E(err), log.Any("uid", uid), log.Any("proxyUserId", proxyUserId), log.Any("orderId", orderId)) return err } return nil }) return }