Initial commit

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 13:57:10 +08:00
co-authored by Claude Opus 5
commit 8679200f41
1897 changed files with 257900 additions and 0 deletions
+476
View File
@@ -0,0 +1,476 @@
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
}