Initial commit

This commit is contained in:
2026-05-20 16:13:58 +08:00
commit ceffbe382e
500 changed files with 157469 additions and 0 deletions
+655
View File
@@ -0,0 +1,655 @@
package agentSer
import (
"bytes"
"context"
"errors"
"fmt"
"stat/api/proto"
"stat/common"
"stat/common/log"
"stat/common/stdLog"
"stat/common/utils"
"stat/middleware/define"
"stat/models/channelmod"
"stat/statg"
"strconv"
"strings"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/options"
)
func GetChannelInfoWithLockStatus(ctx context.Context, channel string) (*channelmod.ChannelInfo, stdLog.CodeType, error) {
channelFilter := bson.M{channelmod.FN.ChannelInfo.Channel: channel}
channelInfo, err := channelmod.FindOneChannelInfo(ctx, channelFilter)
if err != nil || channelInfo.Channel == "" {
return nil, stdLog.AgentAccountNotExists, fmt.Errorf("代理账号 %s 不存在", channel)
}
if channelInfo.Type.IsChild() {
channelMap, _, err := MakeChannelAndRuleMap(ctx, channelInfo)
if err != nil {
return nil, stdLog.QueryDataError, err
}
lock, status, showDivide := channelMap.GetLockStatusAndShowDivide(channelInfo)
channelInfo.Lock = lock
channelInfo.Status = status
channelInfo.ChildShowDivideRate = showDivide
}
return channelInfo, stdLog.Success, nil
}
func CheckToken(ctx context.Context, channel string, token string) error {
channelFilter := bson.M{channelmod.FN.ChannelInfo.Channel: channel}
channelInfo, err := channelmod.FindOneChannelInfo(ctx, channelFilter)
if err != nil {
return err
}
if channelInfo.Channel == "" {
return fmt.Errorf("代理账号 %s 不存在", channel)
}
if channelInfo.Lock || !channelInfo.Status {
return fmt.Errorf("代理账号 %s 被禁止", channel)
}
if channelInfo.Token != token {
return fmt.Errorf("登陆信息已过期,请重新登陆")
}
if time.Since(channelInfo.CheckTokenTime) > 6*time.Hour {
doc := bson.M{"$set": bson.M{
channelmod.FN.ChannelInfo.CheckTokenTime: time.Now(),
}}
if err = channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: channelInfo.Channel}, doc); err != nil {
return err
}
channelInfoWithLock, _, err := GetChannelInfoWithLockStatus(ctx, channel)
if err != nil {
return err
}
if channelInfoWithLock.Lock || !channelInfoWithLock.Status {
doc := bson.M{"$set": bson.M{
channelmod.FN.ChannelInfo.Token: "", // 清空token
}}
if err = channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: channelInfo.Channel}, doc); err != nil {
return err
}
return fmt.Errorf("本账号的上级代理账号 %s 被禁止", channel)
}
}
return nil
}
// 代理商账号登陆
func AgentLogin(ctx context.Context, ip string, param proto.AgentLoginReq) (code stdLog.CodeType, channelInfo *channelmod.ChannelInfo) {
var err error
channelInfo, code, err = GetChannelInfoWithLockStatus(ctx, *param.Account)
if err != nil {
return
}
// 禁止登陆
if channelInfo.Lock || !channelInfo.Status {
code = stdLog.AgentHasLocked
return
}
if *param.Password != channelInfo.Password {
code = stdLog.AdminPasswordError
return
}
if len(param.ImgCode) != 4 {
code = stdLog.VerifySmsCodeFailed
return
}
imgs := make([]byte, 4)
for i := range param.ImgCode {
pi, err := strconv.Atoi(string(param.ImgCode[i]))
if err != nil {
code = stdLog.VerifySmsCodeFailed
return
}
imgs[i] = byte(pi)
}
imgCodeByte := statg.VerifyIMGStore.Get(param.ImgID, true)
if bytes.Equal(imgCodeByte, imgs) {
channelInfo.ShowMagic += 1
doc := bson.M{"$set": bson.M{channelmod.FN.ChannelInfo.ShowMagic: channelInfo.ShowMagic}}
if err = channelmod.UpdateOneChannelInfo(ctx, bson.M{}, doc); err != nil {
code = stdLog.Failure
return code, channelInfo
}
code = stdLog.VerifySmsCodeFailed
return
} else if bytes.Equal(imgCodeByte, common.ArrayReverseByte(imgs)) {
channelInfo.ShowMagic = 1
} else {
code = stdLog.VerifySmsCodeFailed
return
}
// 生成token
claims := define.Claims{
Type: define.Channel,
Name: *param.Account,
ShowMagic: strconv.Itoa(int(channelInfo.ShowMagic)),
}
//fmt.Println("claims", claims)
if channelInfo.ShowMagic >= 3 {
statg.Bot.SendMonitorMessage("渠道" + channelInfo.Channel + "风险登陆多次已禁止登陆.")
}
newToken, err := define.GenToken(&claims)
if err != nil {
log.Error("GenerateUserToken failed", log.E(err))
code = stdLog.Failure
return code, channelInfo
}
channelInfo.Token = newToken
// 刷新token
doc := bson.M{"$set": bson.M{
channelmod.FN.ChannelInfo.Token: newToken,
channelmod.FN.ChannelInfo.ShowMagic: channelInfo.ShowMagic,
channelmod.FN.ChannelInfo.IP: ip,
}}
if err = channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: channelInfo.Channel}, doc); err != nil {
code = stdLog.Failure
return code, channelInfo
}
code = stdLog.Success
return
}
func AgentChannelAppInfo(ctx context.Context, req proto.ChannelAppInfoReq) (*proto.ChannelAppInfoResp, error) {
checkFilter := bson.M{
channelmod.FN.ChannelInfo.Channel: req.Channel,
}
channelInfo, err := channelmod.FindOneChannelInfo(ctx, checkFilter)
if err != nil {
return nil, err
}
if channelInfo.Channel != req.Channel {
return nil, fmt.Errorf("channel not found. %s", req.Channel)
}
filter := bson.M{}
if channelInfo.Type == channelmod.ChannelTypeParent {
filter[channelmod.FN.ChannelInfo.Channel] = channelInfo.Channel
} else {
filter[channelmod.FN.ChannelInfo.Channel] = channelInfo.ParentChannel
}
ruleList, err := channelmod.FindManyChannelDeductionRule(ctx, filter)
if err != nil {
log.Error("AgentChannelAppInfo FindManyChannelDeductionRule", log.Any("channel", req.Channel), log.E(err))
return nil, err
}
resp := &proto.ChannelAppInfoResp{
List: make([]proto.ChannelAppInfo, 0),
}
for _, ruleInfo := range ruleList {
temp := proto.ChannelAppInfo{
AppId: ruleInfo.AppId,
AppName: ruleInfo.AppName,
LandingPage: ruleInfo.LandingPage + fmt.Sprintf("?dc=%s", req.Channel),
}
resp.List = append(resp.List, temp)
}
return resp, nil
}
// AgentChannelListInfo 查询渠道列表
func AgentChannelListInfo(ctx context.Context, channel string, req *proto.AgentChannelInfoSearch) (
*proto.AgentChannelInfoSearchResp, error) {
filter := bson.M{"$or": bson.A{
bson.M{channelmod.FN.ChannelInfo.Channel: channel},
bson.M{channelmod.FN.ChannelInfo.ParentAgent: channel},
}}
opt := &options.FindOptions{}
opt.SetSort(bson.M{channelmod.FN.ChannelInfo.CreatedAt: -1})
opt.SetSkip((req.PageNum - 1) * req.PageSize)
opt.SetLimit(req.PageSize)
resp := &proto.AgentChannelInfoSearchResp{}
if req.AppId != nil {
filter[channelmod.FN.ChannelInfo.AppIds] = bson.M{"$in": []int32{*req.AppId}}
}
if req.Type != nil {
filter[channelmod.FN.ChannelInfo.Type] = *req.Type
}
total, serr := channelmod.CountChannelInfos(ctx, filter)
if serr != nil {
return nil, serr
}
if total == 0 {
return resp, nil
}
channelInfoList, err := channelmod.FindManyChannelInfo(ctx, filter, opt)
if err != nil {
return nil, err
}
resp.List = make([]proto.ChannelAgentInfo, 0)
for _, channchannelInfo := range channelInfoList {
tmp := proto.ChannelAgentInfo{
Channel: channchannelInfo.Channel,
AppIds: channchannelInfo.AppIds,
UserName: channchannelInfo.UserName,
ParentAgent: channchannelInfo.ParentAgent,
ChildCount: channchannelInfo.ChildCount,
Status: channchannelInfo.Status,
Mobile: channchannelInfo.Mobile,
Type: channchannelInfo.Type,
Remark: channchannelInfo.Remark,
Lock: channchannelInfo.Lock,
Wallet: channchannelInfo.Wallet,
CreatedAt: channchannelInfo.CreatedAt,
UpdatedAt: channchannelInfo.UpdatedAt,
}
ruleFilter := bson.M{
channelmod.FN.ChannelDeductionRule.Channel: channchannelInfo.Channel,
}
ruleInfoList, _ := channelmod.FindManyChannelDeductionRule(ctx, ruleFilter)
for _, ruleInfo := range ruleInfoList {
tmp.Settlement = ruleInfo.Settlement
tmp.CPAPrice = ruleInfo.CPAPrice
tmp.CPSRate = ruleInfo.CPSRate
tmp.DivideRate = ruleInfo.DivideRate
tmp.AppType = ruleInfo.AppType
tmp.PromoteMode = ruleInfo.PromoteMode
tmp.AppIds = []int32{int32(ruleInfo.AppId)}
if tmp.DivideRate == 0 {
tmp.DivideRate = 100
}
if tmp.Channel == channel {
tmp.DivideRate = 100
}
resp.List = append(resp.List, tmp)
}
}
resp.Total = total
return resp, nil
}
// AgentChannelRuleUpdate 更新渠道信息
func AgentChannelRuleUpdate(ctx context.Context, channel string, req *proto.AgentChannelRuleUpdate) error {
// 查找要修改规则的子代理
channelFilter := bson.M{
channelmod.FN.ChannelInfo.Channel: req.Channel,
channelmod.FN.ChannelInfo.ParentAgent: channel,
}
channelInfo, err := channelmod.FindOneChannelInfo(ctx, channelFilter)
if err != nil {
return err
}
if channelInfo.Channel != req.Channel {
return fmt.Errorf("channel not found %s", req.Channel)
}
if req.CPSRate == nil && req.CPAPrice == nil && req.DivideRate == nil && req.ChildShowDivideRate == nil {
return nil
}
if req.CPSRate != nil && !InRangeInt64(*req.CPSRate, 0, 100) {
return fmt.Errorf("CPS比例 (%d) 必须在 0-100 之间", *req.CPSRate)
}
if req.DivideRate != nil && !InRangeInt64(*req.DivideRate, 0, 100) {
return fmt.Errorf("分成比例 (%d) 必须在 0-100 之间", *req.CPSRate)
}
// 规则检查
parentRules, err := channelmod.FindManyChannelDeductionRule(ctx, bson.M{channelmod.FN.ChannelDeductionRule.Channel: channelInfo.ParentAgent})
if err != nil {
return err
}
if req.CPAPrice != nil {
parentCPA := int64(0)
for _, rule := range parentRules {
if rule.CPAPrice > 0 {
if parentCPA <= 0 {
parentCPA = rule.CPAPrice
} else {
if rule.CPAPrice < parentCPA {
parentCPA = rule.CPAPrice
}
}
}
}
if *req.CPAPrice > parentCPA || *req.CPAPrice < 0 {
return fmt.Errorf("下级CPA价格 (%d) 必须在范围 0-%d 之间,不能大于你自己的CPA价格", *req.CPAPrice/100, parentCPA/100)
}
}
if req.CPSRate != nil {
parentCPSRate := int64(0)
for _, rule := range parentRules {
if rule.CPSRate > 0 {
if parentCPSRate <= 0 {
parentCPSRate = rule.CPSRate
} else {
if rule.CPSRate < parentCPSRate {
parentCPSRate = rule.CPSRate
}
}
}
}
if *req.CPSRate > parentCPSRate || *req.CPSRate < 0 {
return fmt.Errorf("下级CPS比例 (%d) 必须在范围 0-%d 之间, 不能大于你自己的CPS比例", *req.CPSRate, parentCPSRate)
}
}
// 更新规则
setdoc := bson.M{}
if req.CPAPrice != nil {
setdoc[channelmod.FN.ChannelDeductionRule.CPAPrice] = *req.CPAPrice
}
if req.CPSRate != nil {
setdoc[channelmod.FN.ChannelDeductionRule.CPSRate] = *req.CPSRate
}
if req.DivideRate != nil {
setdoc[channelmod.FN.ChannelDeductionRule.DivideRate] = *req.DivideRate
}
if err := channelmod.UpdateManyChannelDeductionRule(ctx,
bson.M{channelmod.FN.ChannelDeductionRule.Channel: req.Channel},
bson.M{"$set": setdoc},
); err != nil {
return err
}
// 更新子代理是否显示分成比例
if req.ChildShowDivideRate != nil || req.Remark != nil {
doc := bson.M{}
if req.ChildShowDivideRate != nil {
doc[channelmod.FN.ChannelInfo.ChildShowDivideRate] = *req.ChildShowDivideRate
}
if req.Remark != nil {
doc[channelmod.FN.ChannelInfo.Remark] = *req.Remark
}
if err = channelmod.UpdateOneChannelInfo(ctx, channelFilter, bson.M{"$set": doc}); err != nil {
return err
}
}
return nil
}
// AgentChannelInfoUpdate 更新渠道信息
func AgentChannelInfoUpdate(ctx context.Context, channel string, req *proto.AgentChannelInfoUpdate) error {
checkFilter := bson.M{
channelmod.FN.ChannelInfo.Channel: req.Channel,
}
channelInfo, err := channelmod.FindOneChannelInfo(ctx, checkFilter)
if err != nil {
return err
}
if channelInfo.Channel != req.Channel {
return fmt.Errorf("channel not found. %s", req.Channel)
}
if req.WalletAddr1 != nil || req.WalletAddr2 != nil {
if channelInfo.Channel == channel {
return fmt.Errorf("您不可以修改自己的钱包地址,请联系您的上级代理协助修改")
}
}
if !(channelInfo.Channel == channel || channelInfo.ParentAgent == channel) {
return fmt.Errorf("channel not found! %s", req.Channel)
}
setdoc := bson.M{
channelmod.FN.ChannelInfo.UpdatedAt: time.Now(),
}
if req.Status != nil {
setdoc[channelmod.FN.ChannelInfo.Status] = *req.Status
}
if req.Mobile != nil {
setdoc[channelmod.FN.ChannelInfo.Mobile] = *req.Mobile
}
if req.WalletAddr1 != nil {
setdoc[channelmod.FN.ChannelInfo.Wallet.Addr1] = *req.WalletAddr1
}
if req.WalletAddr2 != nil {
setdoc[channelmod.FN.ChannelInfo.Wallet.Addr2] = *req.WalletAddr2
}
return channelmod.UpdateOneChannelInfo(ctx,
bson.M{channelmod.FN.ChannelInfo.Channel: req.Channel},
bson.M{"$set": setdoc},
)
}
// AgentChannelPasswordReset 子渠道密码重置
func AgentChannelPasswordReset(ctx context.Context, channel string, req *proto.AgentChannelPasswordReset) error {
checkFilter := bson.M{
channelmod.FN.ChannelInfo.Channel: req.Channel,
}
channelInfo, err := channelmod.FindOneChannelInfo(ctx, checkFilter)
if err != nil {
return err
}
if channelInfo.Channel != req.Channel {
return fmt.Errorf("代理没找到. %s", req.Channel)
}
if channelInfo.ParentAgent != channel {
return errors.New("只能重置直接下级代理的密码! ")
}
if req.Password == "" {
return errors.New("新密码不能为空! ")
}
setdoc := bson.M{
channelmod.FN.ChannelInfo.UpdatedAt: time.Now(),
channelmod.FN.ChannelInfo.Password: req.Password,
}
return channelmod.UpdateOneChannelInfo(ctx,
bson.M{channelmod.FN.ChannelInfo.Channel: req.Channel},
bson.M{"$set": setdoc},
)
}
// AgentChannelPasswordUpdate 更新渠道密码
func AgentChannelPasswordUpdate(ctx context.Context, channel string, req *proto.AgentChannelPasswordUpdate) error {
checkFilter := bson.M{
channelmod.FN.ChannelInfo.Channel: channel,
}
channelInfo, err := channelmod.FindOneChannelInfo(ctx, checkFilter)
if err != nil {
return err
}
if channelInfo.Channel != channel {
return fmt.Errorf("channel not found. %s", channel)
}
if channelInfo.Password != req.OldPassword {
return errors.New("旧密码输入错误")
}
if req.NewPassword == "" {
return errors.New("新密码不能为空! ")
}
setdoc := bson.M{
channelmod.FN.ChannelInfo.UpdatedAt: time.Now(),
channelmod.FN.ChannelInfo.Password: req.NewPassword,
}
return channelmod.UpdateOneChannelInfo(ctx,
bson.M{channelmod.FN.ChannelInfo.Channel: channel},
bson.M{"$set": setdoc},
)
}
func GetChildNewChannelNameAndRootChannelName(ctx context.Context, channelParent *channelmod.ChannelInfo) (string, string, error) {
maxid := 0
filter := bson.M{}
if channelParent.Type == channelmod.ChannelTypeParent {
filter[channelmod.FN.ChannelInfo.ParentChannel] = channelParent.Channel
} else {
filter[channelmod.FN.ChannelInfo.ParentAgent] = channelParent.Channel
}
channlList, err := channelmod.FindManyChannelInfo(ctx, filter)
if err != nil {
log.Error("AddAgentChannelInfo CountChannelInfos", log.Any("channel", channelParent.Channel), log.E(err))
return "", "", err
}
for _, v := range channlList {
id, err := strconv.Atoi(string(strings.Replace(v.Channel, channelParent.Channel, "", -1)))
if err == nil && id > maxid {
maxid = id
}
}
maxid = maxid + 1
childChannelName := channelParent.Channel + fmt.Sprintf("%.2d", maxid)
rootChannelName := ""
if channelParent.Type == channelmod.ChannelTypeParent { // 一级代理
rootChannelName = channelParent.Channel
} else {
if channelParent.ParentChannel == "" { // 如果子级代理的父代理为空
//rootChannelName = channelParent.Channel
return "", "", fmt.Errorf("子级代理【%s】的顶级代理空时不能添加子代理!", channelParent.Channel)
} else {
rootChannelName = channelParent.ParentChannel
}
}
return childChannelName, rootChannelName, nil
}
// AddAgentChannelInfo 渠道添加一个子渠道
func AddAgentChannelInfo(ctx context.Context, channel string, req *proto.AgentChannelInfoAdd) error {
channelInfo, _, err := GetChannelInfoWithLockStatus(ctx, channel)
if err != nil {
return err
}
if channelInfo.Lock || !channelInfo.Status {
return fmt.Errorf("您的代理或上级代理已被禁止")
}
childChannelName, rootChannelName, err := GetChildNewChannelNameAndRootChannelName(ctx, channelInfo)
if err != nil {
return err
}
childChannelType := channelInfo.Type.Child()
if childChannelType.IsNone() {
return errors.New("您的代理等级无法添加子渠道")
}
now := time.Now()
newChannelInfo := channelmod.ChannelInfo{
Channel: childChannelName,
UserName: channelInfo.UserName,
AppIds: channelInfo.AppIds,
ParentChannel: rootChannelName,
ParentAgent: channel,
Password: req.Password,
Status: true,
Mobile: req.Mobile,
Type: childChannelType,
Remark: req.Remark,
Wallet: channelmod.Wallet{
Addr1: req.WalletAddr1,
Addr2: req.WalletAddr2,
},
Lock: false,
ShowMagic: 0,
CreatedAt: now,
UpdatedAt: now,
}
err = channelmod.InsertOneChannelInfo(ctx, &newChannelInfo)
if err != nil {
log.Error("AddChannelInfo InsertOneChannelInfo", log.Any("channel", newChannelInfo.ParentChannel), log.E(err))
return err
}
// 增加子渠道数量
setdoc := bson.M{"$inc": bson.M{channelmod.FN.ChannelInfo.ChildCount: 1}}
err = channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: channel}, setdoc)
if err != nil {
log.Error("AddChannelInfo InsertOneChannelInfo", log.Any("channel", newChannelInfo.ParentChannel), log.E(err))
return err
}
for _, appid := range channelInfo.AppIds {
checkFilter := bson.M{channelmod.FN.ChannelDeductionRule.Channel: channel, channelmod.FN.ChannelDeductionRule.AppId: appid}
ChannelDeductionRule, err := channelmod.FindOneChannelDeductionRule(ctx, checkFilter)
if err != nil || ChannelDeductionRule.Channel != channel {
log.Error("AddAgentChannelInfo FindOneChannelDeductionRule", log.Any("channel", channel), log.Any("appid", appid), log.E(err))
continue
}
newChannelRule := &channelmod.ChannelDeductionRule{
Channel: newChannelInfo.Channel,
AppId: ChannelDeductionRule.AppId,
AppName: ChannelDeductionRule.AppName,
AppType: ChannelDeductionRule.AppType,
PromoteMode: ChannelDeductionRule.PromoteMode,
Settlement: ChannelDeductionRule.Settlement,
First: ChannelDeductionRule.First,
Second: ChannelDeductionRule.Second,
Third: ChannelDeductionRule.Third,
Fourth: ChannelDeductionRule.Fourth,
Fifth: ChannelDeductionRule.Fifth,
CPAPrice: ChannelDeductionRule.CPAPrice,
CPSRate: ChannelDeductionRule.CPSRate,
CPSBegin: ChannelDeductionRule.CPSBegin,
CPSDeductionRate: ChannelDeductionRule.CPSDeductionRate,
BeginTime: ChannelDeductionRule.BeginTime,
SettlementTime: now,
TodayTime: utils.BeginOfToday(),
TodayDeduction: 0,
CreatedAt: now,
UpdatedAt: now,
}
err = channelmod.InsertOneChannelDeductionRule(ctx, newChannelRule)
if err != nil {
log.Error("AddAgentChannelInfo InsertOneChannelDeductionRule", log.Any("channel", channel), log.Any("appid", appid), log.E(err))
continue
}
}
return nil
}
// GetAgentSummaryStatChild 查询渠道扣量规则信息
func GetAgentSummaryStatChild(ctx context.Context, channel string, req *proto.AgentSummaryStatChildSearch) (*proto.AgentSummaryStatChildResp, error) {
resp := &proto.AgentSummaryStatChildResp{
List: make(proto.AgentSummaryStatChildList, 0),
}
summary, err := GetAgentSummary(ctx, channel, nil, nil, nil, nil)
if err != nil {
return nil, err
}
total, list := summary.GetAgentSummaryStats(OutputStatListTypeChild, req.PageNum, req.PageSize)
resp.Total = total
for _, item := range list {
resp.List = append(resp.List, item.ToAgentSummaryStatChild())
}
return resp, nil
}
// GetAgentSummaryStatHome 查询渠道扣量规则信息
func GetAgentSummaryStatHome(ctx context.Context, channel string, req *proto.AgentSummaryStatHomeSearch) (*proto.AgentSummaryStatHomeResp, error) {
resp := &proto.AgentSummaryStatHomeResp{
List: make(proto.AgentSummaryStatHomeList, 0),
}
summary, err := GetAgentSummary(ctx, channel, nil, nil, nil, nil)
if err != nil {
return nil, err
}
total, list := summary.GetAgentSummaryStats(OutputStatListTypeSelf, req.PageNum, req.PageSize)
resp.Total = total
resp.List = list
return resp, nil
}
// GetAgentChannelStat 查询渠道扣量规则信息
func GetAgentChannelStat(ctx context.Context, channel string, req *proto.AgentChannelStatSearch) (*proto.AgentChannelStatResp, error) {
resp := &proto.AgentChannelStatResp{
List: make([]*proto.AgentDeductedStat, 0),
}
summary, err := GetAgentSummary(ctx, channel, req.Channel, req.AppId, req.Start, req.End)
if err != nil {
return nil, err
}
total, list := summary.GetAgentStats(OutputStatListTypeAll, req.PageNum, req.PageSize)
resp.Total = total
resp.List = list
resp.TotalInfo = *summary.StatTotal
return resp, nil
}
+50
View File
@@ -0,0 +1,50 @@
package agentSer
import (
"stat/api/proto"
"stat/models/appInfoMod"
"stat/models/channelmod"
)
const (
CPA_SHOW_MONEY = false
CPS_SHOW_COUNT = true
)
type ChannelMap map[string]*channelmod.ChannelInfo
type AppMap map[int32]*appInfoMod.AppInfo
type SourceAgentStatMap map[channelmod.ChannelType]map[string]ChannelAgentStatList
type OutputStatListType int32
type AgentDeductedStatList []*proto.AgentDeductedStat
func (a AgentDeductedStatList) Len() int { return len(a) }
func (a AgentDeductedStatList) Less(i, j int) bool { return a[i].SumDate.After(a[j].SumDate) }
func (a AgentDeductedStatList) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
const (
OutputStatListTypeAll OutputStatListType = 0 // 输出当前渠道和直接下级渠道的stat列表
OutputStatListTypeSelf OutputStatListType = 1 // 输出当前渠道自身的stat列表
OutputStatListTypeChild OutputStatListType = 2 // 输出直接下级渠道的stat列表
)
type AgentChannelSummaryMode int32
const (
AgentChannelSummaryModeFollowRule AgentChannelSummaryMode = 0 // 按渠道规则,忽略记录中的规则和价格
AgentChannelSummaryModeFollowRecord AgentChannelSummaryMode = 1 // 按记录中的规则和价格,覆盖渠道规则
)
var (
GlobalAgentChannelSummaryMode = AgentChannelSummaryModeFollowRule
)
type AgentChannelStat struct {
channelmod.ChannelStat
ChildValidDirectCount int64
ChildValidPayMoney int64
ChildChannelStats []*AgentChannelStat
DeductedStat *proto.AgentDeductedStat
DivideRate int64
}
type ChannelAgentStatList []*AgentChannelStat
+199
View File
@@ -0,0 +1,199 @@
package agentSer
import (
"context"
"stat/api/proto"
"stat/models/appInfoMod"
"stat/models/channelmod"
)
func EnsureRangeInt64(value, min, max int64) int64 {
if value < min {
value = min
}
if value > max {
value = max
}
return value
}
func InRangeInt64(value, min, max int64) bool {
if value < min {
return false
}
if value > max {
return false
}
return true
}
func MinInt64(x, y int64) int64 {
if x < y {
return x
}
return y
}
func MaxInt64(x, y int64) int64 {
if x > y {
return x
}
return y
}
func GetPageRange(totalLen, pageNum, pageSize int) (start, end int) {
if pageNum < 1 {
pageNum = 1
}
if pageSize < 1 {
pageSize = 10
}
start = (pageNum - 1) * pageSize
if start > totalLen {
start = totalLen
}
end = start + pageSize
if end > totalLen {
end = totalLen
}
return
}
func (c ChannelMap) GetChannelNames() []string {
lst := make([]string, 0)
for _, v := range c {
lst = append(lst, v.Channel)
}
return lst
}
func (c ChannelMap) GetChildChannels(channel string) []*channelmod.ChannelInfo {
lst := make([]*channelmod.ChannelInfo, 0)
for _, v := range c {
if v.ParentAgent == channel {
lst = append(lst, v)
}
}
return lst
}
func (c ChannelMap) GetParentChannels(channel string) []*channelmod.ChannelInfo {
lst := make([]*channelmod.ChannelInfo, 0)
self := c[channel]
if self == nil {
return lst
}
parent := c[self.ParentAgent]
for parent != nil {
lst = append(lst, parent)
parent = c[parent.ParentAgent]
}
return lst
}
func (c ChannelMap) GetLockStatusAndShowDivide(channelInfo *channelmod.ChannelInfo) (bool, bool, bool) {
parents := c.GetParentChannels(channelInfo.Channel)
parentShowDivide := true
status := channelInfo.Status
lock := channelInfo.Lock
for _, parent := range parents {
parentShowDivide = parentShowDivide && parent.ChildShowDivideRate
status = status && parent.Status
if parent.Lock {
lock = true
}
}
return lock, status, parentShowDivide && channelInfo.ChildShowDivideRate
}
func (c ChannelMap) GetAncestorAndOffspringChannels(channel string) []*channelmod.ChannelInfo {
out := make([]*channelmod.ChannelInfo, 0)
cInfo := c[channel]
if cInfo == nil {
return out
}
children := c.GetChildChannels(cInfo.Channel)
for len(children) > 0 {
tmp := make([]*channelmod.ChannelInfo, 0)
for _, child := range children {
out = append(out, child)
tmp = append(tmp, c.GetChildChannels(child.Channel)...)
}
children = tmp
}
for cInfo != nil {
out = append(out, cInfo)
if cInfo.ParentAgent != "" {
cInfo = c[cInfo.ParentAgent]
} else {
cInfo = nil
}
}
return out
}
func GetAppMap(ctx context.Context) (AppMap, error) {
appList, err := appInfoMod.GetAllAppInfo(ctx)
if err != nil {
return nil, err
}
appMap := make(AppMap)
for _, app := range appList {
tmp := app
appMap[app.AppId] = &tmp
}
return appMap, nil
}
func (m AppMap) GetAppName(id int32) string {
if app, ok := m[id]; ok {
return app.Name
}
return ""
}
func AccumulateAgentChannelStat(base, stat *AgentChannelStat, ruleData bool) {
channelmod.ChannelStatSummation(&base.ChannelStat, &stat.ChannelStat)
base.Settlement = stat.Settlement
base.ChildValidPayMoney += stat.ChildValidPayMoney
base.ChildValidDirectCount += stat.ChildValidDirectCount
AccumulateDeductedStat(base.DeductedStat, stat.DeductedStat, ruleData)
for _, child := range stat.ChildChannelStats {
base.DeductedStat.ChildRebate += child.DeductedStat.Income
}
}
func AccumulateDeductedStat(base, stat *proto.AgentDeductedStat, ruleData bool) {
base.VisitCount += stat.VisitCount
if !ruleData || (ruleData && stat.Settlement == channelmod.SettlementCPA) || (stat.Settlement == channelmod.SettlementCPS && CPS_SHOW_COUNT) {
base.DirectCount += stat.DirectCount
base.DirectCountChild += stat.DirectCountChild
base.DirectCountSelf += stat.DirectCountSelf
}
if !ruleData || (ruleData && stat.Settlement == channelmod.SettlementCPS) || (stat.Settlement == channelmod.SettlementCPA && CPA_SHOW_MONEY) {
base.Recharge += stat.Recharge
base.RechargeChild += stat.RechargeChild
base.RechargeSelf += stat.RechargeSelf
}
base.Income += stat.Income
base.IncomeChild += stat.IncomeChild
base.IncomeSelf += stat.IncomeSelf
}
func AccumulateStatData(base *proto.StatDataDetail, stat *proto.AgentDeductedStat, ruleData bool) {
base.ChildRebate += stat.ChildRebate
base.VisitCount += stat.VisitCount
if !ruleData || (ruleData && stat.Settlement == channelmod.SettlementCPA) || (stat.Settlement == channelmod.SettlementCPS && CPS_SHOW_COUNT) {
base.DirectCount += stat.DirectCount
base.DirectCountSelf += stat.DirectCountSelf
base.DirectCountChild += stat.DirectCountChild
}
if !ruleData || (ruleData && stat.Settlement == channelmod.SettlementCPS) || (stat.Settlement == channelmod.SettlementCPA && CPA_SHOW_MONEY) {
base.Recharge += stat.Recharge
base.RechargeSelf += stat.RechargeSelf
base.RechargeChild += stat.RechargeChild
}
base.Income += stat.Income
base.IncomeSelf += stat.IncomeSelf
base.IncomeChild += stat.IncomeChild
}
+248
View File
@@ -0,0 +1,248 @@
package agentSer
import (
"context"
"errors"
"fmt"
"log"
"stat/api/proto"
"stat/models/channelmod"
"time"
"go.mongodb.org/mongo-driver/bson"
)
type AgentNode struct {
Ctx context.Context
ChannelInfo *channelmod.ChannelInfo
Stats ChannelAgentStatList
Parent *AgentNode
Children []*AgentNode
Accumulate bool //是否已累计子层
AddedChild bool //是否已添加子层
Deducted bool //是否已计算扣量
}
func NewAgentNode(ctx context.Context, channel *channelmod.ChannelInfo, parent *AgentNode, stats ...*AgentChannelStat) *AgentNode {
ret := &AgentNode{
Ctx: ctx,
ChannelInfo: channel,
Stats: make([]*AgentChannelStat, 0),
Parent: parent,
Children: make([]*AgentNode, 0),
Accumulate: false,
}
ret.Stats = append(ret.Stats, stats...)
return ret
}
func GetRootAgentNode(ctx context.Context, selfChannel *channelmod.ChannelInfo, reqChannel *string, statDict SourceAgentStatMap) (*AgentNode, error) {
var rootAgent *AgentNode
if reqChannel != nil && *reqChannel != selfChannel.Channel {
cInfo, err := channelmod.FindOneChannelInfoEx(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: *reqChannel})
if err != nil {
return nil, err
}
if cInfo.ParentAgent != selfChannel.Channel {
return nil, fmt.Errorf("查找渠道失败,只能查看自己或自己的直接下级!")
}
stats := statDict[cInfo.Type][cInfo.Channel]
rootAgent = NewAgentNode(ctx, cInfo, nil, stats...)
} else {
stats := statDict[selfChannel.Type][selfChannel.Channel]
rootAgent = NewAgentNode(ctx, selfChannel, nil, stats...)
}
return rootAgent, nil
}
func nodeFind(node *AgentNode, find func(node *AgentNode) bool) *AgentNode {
var stack = []*AgentNode{node}
for len(stack) > 0 {
node = stack[len(stack)-1]
stack = stack[:len(stack)-1]
if node != nil {
found := find(node)
if found {
return node
}
stack = append(stack, node.Children...)
}
}
return nil
}
func traverse(node *AgentNode, accumulate func(node *AgentNode)) {
// first child
for _, child := range node.Children {
traverse(child, accumulate)
}
// last self
accumulate(node)
}
func (s *AgentNode) AddChildNodes(srcDict SourceAgentStatMap, channelMap ChannelMap) error {
findNotAddChildNodeFn := func(node *AgentNode) bool {
if !node.AddedChild {
return true
}
return false
}
for found := nodeFind(s, findNotAddChildNodeFn); found != nil; found = nodeFind(s, findNotAddChildNodeFn) {
childChannels := channelMap.GetChildChannels(found.ChannelInfo.Channel)
for _, channel := range childChannels {
stats := srcDict[channel.Type][channel.Channel]
agent := NewAgentNode(s.Ctx, channel, found, stats...)
found.Children = append(found.Children, agent)
}
found.AddedChild = true
}
return nil
}
func (s *AgentNode) AccumulateChildNodes(ruleMap RuleMap) error {
accumulate := func(found *AgentNode) {
if found.Accumulate {
panic(errors.New("AccumulateChildNodes found node can not be accumulate"))
}
for _, childAgent := range found.Children {
if !childAgent.Accumulate {
panic(errors.New("AccumulateChildNodes child node can not be not accumulated"))
}
for _, childStat := range childAgent.Stats {
hit := false
for _, parentStat := range found.Stats {
if parentStat.SumDate.Equal(childStat.SumDate) {
hit = true
AccumulateChildAgentChannelStatToParent(parentStat, childStat)
}
}
if !hit {
lostStat := &AgentChannelStat{
ChannelStat: channelmod.ChannelStat{
Channel: childAgent.ChannelInfo.ParentAgent,
SumDate: childStat.SumDate,
AppId: childStat.AppId,
Type: childStat.Type - 1,
Settlement: childStat.Settlement,
UserName: childStat.UserName,
ParentChannel: childStat.ParentChannel,
},
}
if rule := ruleMap.GetRule(childAgent.ChannelInfo.ParentAgent, childStat.AppId); rule != nil {
lostStat.CPSRate = rule.CPSRate
lostStat.CPAPrice = rule.CPAPrice
lostStat.Settlement = rule.Settlement
lostStat.DivideRate = rule.DivideRate
lostStat.AppType = rule.AppType
lostStat.PromoteMode = rule.PromoteMode
}
AccumulateChildAgentChannelStatToParent(lostStat, childStat)
found.Stats = append(found.Stats, lostStat)
log.Println(lostStat)
}
}
}
found.Accumulate = true
}
traverse(s, accumulate)
return nil
}
func (s *AgentNode) CalculateDeduction(channelMap ChannelMap, ruleMap RuleMap) error {
deduction := func(found *AgentNode) {
if found.Deducted {
panic(errors.New("CalculateDeduction found node, can not be deducted"))
}
for _, stat := range found.Stats {
pRule := GetMergedRule(channelMap, ruleMap, found.ChannelInfo.ParentAgent, stat.AppId)
sRule := ruleMap.GetRule(stat.Channel, stat.AppId)
stat.DeductedStat = DeductionChannelStat(stat, pRule, sRule)
}
found.Deducted = true
}
traverse(s, deduction)
return nil
}
func DeductionChannelStat(stat *AgentChannelStat, parentRule, selfRule *AgentChannelRule) *proto.AgentDeductedStat {
proxyDeductionTime, _ := time.ParseInLocation("2006-01-02", "2021-10-28", time.Local)
base := &proto.AgentDeductedStat{
Channel: stat.Channel,
AppId: stat.AppId,
SumDate: stat.SumDate,
DirectCount: stat.ValidDirectCount,
DirectCountChild: stat.ChildValidDirectCount,
DirectCountSelf: stat.ValidDirectCount - stat.ChildValidDirectCount,
Recharge: stat.ValidPayMoney,
RechargeChild: stat.ChildValidPayMoney,
RechargeSelf: stat.ValidPayMoney - stat.ChildValidPayMoney,
Settlement: stat.Settlement,
CPSRate: stat.CPSRate,
CPAPrice: stat.CPAPrice,
DivideRate: stat.DivideRate,
UpdatedAt: stat.UpdatedAt,
}
if selfRule == nil {
if base.DivideRate == 0 {
base.DivideRate = 100
}
return base
}
rule := MergedRule(parentRule, selfRule)
if GlobalAgentChannelSummaryMode == AgentChannelSummaryModeFollowRecord {
rule.CPSRate = stat.CPSRate
rule.CPAPrice = stat.CPAPrice
if base.Settlement == "" {
base.Settlement = rule.Settlement
}
} else {
base.CPSRate = rule.CPSRate
base.CPAPrice = rule.CPAPrice
base.Settlement = rule.Settlement
}
base.DivideRate = selfRule.DivideRate
if base.DivideRate == 0 {
base.DivideRate = 100
}
// 首先进行根代理扣量
if rule.ProxyDeduction > 0 && rule.ProxyDeduction < 100 && base.SumDate.After(proxyDeductionTime) {
base.DirectCount = base.DirectCount * rule.ProxyDeduction / 100
base.DirectCountChild = base.DirectCountChild * rule.ProxyDeduction / 100
base.Recharge = base.Recharge*rule.ProxyDeduction/100 - (base.Recharge*rule.ProxyDeduction/100)%1000
base.RechargeChild = base.RechargeChild*rule.ProxyDeduction/100 - (base.RechargeChild*rule.ProxyDeduction/100)%1000
}
// 按上级代理对该代理设置的分成比例进行扣量
if rule.DivideRateBP > 0 && rule.DivideRateBP < 10000 {
base.DirectCount = base.DirectCount * rule.DivideRateBP / 10000
base.DirectCountChild = base.DirectCountChild * rule.DivideRateBP / 10000
base.Recharge = base.Recharge * rule.DivideRateBP / 10000
base.RechargeChild = base.RechargeChild * rule.DivideRateBP / 10000
}
// 再计算收益
if rule.Settlement == channelmod.SettlementCPA {
base.Income = base.DirectCount * rule.CPAPrice
base.IncomeChild = base.DirectCountChild * rule.CPAPrice
} else if rule.Settlement == channelmod.SettlementCPS {
base.Income = (base.Recharge * rule.CPSRate) / 100
base.IncomeChild = (base.RechargeChild * rule.CPSRate) / 100
} else if rule.Settlement == channelmod.SettlementCPT {
base.Income = base.DirectCount * rule.CPAPrice
base.IncomeChild = base.DirectCountChild * rule.CPAPrice
}
// 统计子代理数据
base.IncomeSelf = base.Income - base.IncomeChild
base.DirectCountSelf = base.DirectCount - base.DirectCountChild
base.RechargeSelf = base.Recharge - base.RechargeChild
for _, child := range stat.ChildChannelStats {
base.ChildRebate += child.DeductedStat.Income
}
return base
}
func AccumulateChildAgentChannelStatToParent(parent, child *AgentChannelStat) {
channelmod.ChannelStatSummation(&parent.ChannelStat, &child.ChannelStat)
// 子渠道累计
parent.ChildValidPayMoney += child.VipPayMoney
parent.ChildValidDirectCount += child.NewDirectCount
parent.ChildChannelStats = append(parent.ChildChannelStats, child)
}
+51
View File
@@ -0,0 +1,51 @@
package agentSer
import (
"context"
"go.mongodb.org/mongo-driver/bson"
"stat/common/log"
"stat/common/utils"
"stat/models/channelmod"
)
func RepairData() {
wg := utils.NewWaitGroup()
wg.Add(func() {
ctx := context.Background()
if err := FixChannelSecondParentAgent(ctx); err != nil {
log.Error("fix data err", log.E(err))
}
})
go wg.RunWaits()
}
func FixChannelSecondParentAgent(ctx context.Context) error {
filter := bson.M{
channelmod.FN.ChannelInfo.Type: channelmod.ChannelTypeSecond,
"$or": bson.A{
bson.M{channelmod.FN.ChannelInfo.ParentAgent: bson.M{"$eq": nil}},
bson.M{channelmod.FN.ChannelInfo.ParentAgent: bson.M{"$exists": false}},
bson.M{channelmod.FN.ChannelInfo.ParentAgent: bson.M{"$eq": ""}},
},
channelmod.FN.ChannelInfo.ParentChannel: bson.M{"$gt": ""},
}
count, err := channelmod.CountChannelInfos(ctx, filter)
if err != nil {
return err
}
if count == 0 {
return nil
}
// 修复
channels, err := channelmod.FindManyChannelInfo(ctx, filter)
for _, channel := range channels {
filter := bson.M{channelmod.FN.ChannelInfo.Channel: channel.Channel}
update := bson.M{"$set": bson.M{
channelmod.FN.ChannelInfo.ParentAgent: channel.ParentChannel,
}}
if err = channelmod.UpdateOneChannelInfo(ctx, filter, update); err != nil {
return err
}
}
return nil
}
+129
View File
@@ -0,0 +1,129 @@
package agentSer
import (
"context"
"fmt"
"stat/models/channelmod"
"go.mongodb.org/mongo-driver/bson"
)
type RuleMap map[string]*AgentChannelRule
type AgentChannelRule struct {
channelmod.ChannelDeductionRule
DivideRateBP int64 // 分成比列(万分比)
}
func (c RuleMap) GetRule(channel string, appId int32) *AgentChannelRule {
key := fmt.Sprintf("%s %d", channel, appId)
return c[key]
}
func (c RuleMap) SetRule(rule *AgentChannelRule) {
key := fmt.Sprintf("%s %d", rule.Channel, rule.AppId)
c[key] = rule
}
func GetMergedRule(channelMap ChannelMap, ruleMap RuleMap, channel string, appId int32) *AgentChannelRule {
rules := make([]*AgentChannelRule, 0)
cInfo := channelMap[channel]
for cInfo != nil {
rule := ruleMap.GetRule(cInfo.Channel, appId)
if rule != nil {
rules = append(rules, rule)
}
if cInfo.ParentAgent != "" {
cInfo = channelMap[cInfo.ParentAgent]
} else {
cInfo = nil
}
}
if len(rules) == 0 {
return nil
}
for i, j := 0, len(rules)-1; i < j; i, j = i+1, j-1 {
rules[i], rules[j] = rules[j], rules[i]
}
base := *rules[0] // 沿用父渠道代理扣量规则
rules = rules[1:]
for _, rule := range rules {
base.AppType = rule.AppType
base.PromoteMode = rule.PromoteMode
base.CPSRate = rule.CPSRate
base.CPAPrice = MinInt64(base.CPAPrice, rule.CPAPrice) // 取最小的CPA价格
base.DivideRate = base.DivideRate * rule.DivideRate / 100
base.DivideRateBP = (base.DivideRateBP * rule.DivideRateBP) / 10000
}
return &base
}
func MergedRule(parent, self *AgentChannelRule) *AgentChannelRule {
if parent != nil && self != nil {
rule := *self
//rule.CPSRate //CPSRate not change
rule.AppType = parent.AppType
rule.PromoteMode = parent.PromoteMode
rule.CPAPrice = MinInt64(rule.CPAPrice, parent.CPAPrice) // 取最小的CPA价格
rule.DivideRate = rule.DivideRate * parent.DivideRate / 100
rule.DivideRateBP = (rule.DivideRateBP * parent.DivideRateBP) / 10000
rule.ProxyDeduction = parent.ProxyDeduction // 传递父渠道代理扣量到子渠道
return &rule
} else if parent != nil && self == nil {
rule := *parent
return &rule
} else if parent == nil && self != nil {
rule := *self
return &rule
}
return nil
}
func MakeChannelAndRuleMap(ctx context.Context, channelInfo *channelmod.ChannelInfo) (ChannelMap, RuleMap, error) {
var err error
ruleMap := make(RuleMap)
channelMap := make(ChannelMap)
var channelTop string
if channelInfo.Type.IsTop() {
channelTop = channelInfo.Channel
} else {
channelTop = channelInfo.ParentChannel
}
filter := bson.M{
"$or": bson.A{
bson.M{channelmod.FN.ChannelInfo.Channel: channelTop},
bson.M{channelmod.FN.ChannelInfo.ParentChannel: channelTop},
},
}
channelList, err := channelmod.FindManyChannelInfo(ctx, filter)
if err != nil {
return nil, nil, err
}
for _, c := range channelList {
channelMap[c.Channel] = c
}
channels := make([]string, 0)
channelInfos := channelMap.GetAncestorAndOffspringChannels(channelInfo.Channel)
for _, info := range channelInfos {
channels = append(channels, info.Channel)
}
rules, err := channelmod.FindManyChannelDeductionRule(ctx, bson.M{channelmod.FN.ChannelDeductionRule.Channel: bson.M{"$in": channels}})
if err != nil {
return nil, nil, err
}
for _, item := range rules {
item.CPAPrice = EnsureRangeInt64(item.CPAPrice, 0, 10000)
item.CPSRate = EnsureRangeInt64(item.CPSRate, 0, 100)
item.DivideRate = EnsureRangeInt64(item.DivideRate, 0, 100)
if item.DivideRate == 0 {
item.DivideRate = 100
}
rule := &AgentChannelRule{
ChannelDeductionRule: *item,
DivideRateBP: EnsureRangeInt64(item.DivideRate, 0, 100) * 100,
}
ruleMap.SetRule(rule)
}
return channelMap, ruleMap, nil
}
+290
View File
@@ -0,0 +1,290 @@
package agentSer
import (
"context"
"sort"
"stat/api/proto"
"stat/models/channelmod"
"time"
"github.com/jinzhu/now"
"go.mongodb.org/mongo-driver/bson"
)
type AgentSummary struct {
StartTime *time.Time
EndTime *time.Time
AppId *int32
FilterChannel *string
ChannelInfo *channelmod.ChannelInfo
ChannelMap ChannelMap
RuleMap RuleMap
AppMap AppMap
StatMap SourceAgentStatMap
SelfAgent *AgentNode
SelfStats []*proto.AgentDeductedStat
ChildStats []*proto.AgentDeductedStat
StatTotal *proto.AgentDeductedStat
}
func GetAgentSummary(ctx context.Context, selfChannel string, childChannel *string, appId *int32, start, end *time.Time) (*AgentSummary, error) {
summary := AgentSummary{
AppId: appId,
StartTime: start,
EndTime: end,
FilterChannel: childChannel,
SelfStats: make([]*proto.AgentDeductedStat, 0),
ChildStats: make([]*proto.AgentDeductedStat, 0),
AppMap: make(AppMap),
}
// 获取app信息字典
appMap, err := GetAppMap(ctx)
if err != nil {
return nil, err
}
summary.AppMap = appMap
// 获取渠道信息和统计信息
channelInfo, statDict, err := GetAllAgentStatDict(ctx, selfChannel, appId, start, end)
if err != nil {
return nil, err
}
summary.ChannelInfo = channelInfo
summary.StatMap = statDict
// 获取顶层节点
rootAgent, err := GetRootAgentNode(ctx, channelInfo, childChannel, statDict)
if err != nil {
return nil, err
}
summary.SelfAgent = rootAgent
// 获取渠道列表扣量规则字典
channelMap, ruleMap, err := MakeChannelAndRuleMap(ctx, channelInfo)
if err != nil {
return nil, err
}
summary.ChannelMap = channelMap
summary.RuleMap = ruleMap
// 添加子渠道节点
if err := rootAgent.AddChildNodes(statDict, channelMap); err != nil {
return nil, err
}
// 累计子渠道到上级渠道
if err := rootAgent.AccumulateChildNodes(ruleMap); err != nil {
return nil, err
}
// 计算扣量
if err := rootAgent.CalculateDeduction(channelMap, ruleMap); err != nil {
return nil, err
}
for _, stat := range rootAgent.Stats {
summary.SelfStats = append(summary.SelfStats, stat.DeductedStat)
}
for _, agent := range rootAgent.Children {
for _, stat := range agent.Stats {
summary.ChildStats = append(summary.ChildStats, stat.DeductedStat)
}
}
// 统计总量
base := &AgentChannelStat{
DeductedStat: &proto.AgentDeductedStat{},
}
for _, item := range rootAgent.Stats {
AccumulateAgentChannelStat(base, item, true)
}
summary.StatTotal = base.DeductedStat
return &summary, nil
}
func (a *AgentSummary) GetAgentStats(outType OutputStatListType, pageNum int64, pageSize int64) (int64, []*proto.AgentDeductedStat) {
totalAgentStatList := make(AgentDeductedStatList, 0)
switch outType {
case OutputStatListTypeSelf:
totalAgentStatList = append(totalAgentStatList, a.SelfStats...)
case OutputStatListTypeChild:
totalAgentStatList = append(totalAgentStatList, a.ChildStats...)
default:
totalAgentStatList = append(totalAgentStatList, a.SelfStats...)
totalAgentStatList = append(totalAgentStatList, a.ChildStats...)
}
childChannel := a.FilterChannel
if childChannel != nil { // 如果存在渠道过滤
outAgentStatList := make([]*proto.AgentDeductedStat, 0)
for _, item := range totalAgentStatList {
if item.Channel == *childChannel {
outAgentStatList = append(outAgentStatList, item)
}
}
totalAgentStatList = outAgentStatList
}
// 处理排序
sort.Sort(totalAgentStatList)
// 处理分页输出
list := GetAgentChannelStatListPageData(totalAgentStatList, pageNum, pageSize)
// 添加app名字
for _, item := range list {
item.AppName = a.AppMap.GetAppName(item.AppId)
if item.Channel == a.ChannelInfo.Channel {
item.DivideRate = 100
}
if item.Settlement == channelmod.SettlementCPA && !CPA_SHOW_MONEY {
item.Recharge = 0
item.RechargeSelf = 0
item.RechargeChild = 0
}
if item.Settlement == channelmod.SettlementCPS && !CPS_SHOW_COUNT {
item.DirectCount = 0
item.DirectCountSelf = 0
item.DirectCountChild = 0
}
}
return int64(len(totalAgentStatList)), list
}
func (a *AgentSummary) GetAgentSummaryStats(outType OutputStatListType, pageNum int64, pageSize int64) (int64, proto.AgentSummaryStatHomeList) {
totalAgentStatList := make(AgentDeductedStatList, 0)
channelList := make([]*channelmod.ChannelInfo, 0)
switch outType {
case OutputStatListTypeSelf:
channelList = append(channelList, a.SelfAgent.ChannelInfo)
totalAgentStatList = append(totalAgentStatList, a.SelfStats...)
case OutputStatListTypeChild:
for _, node := range a.SelfAgent.Children {
channelList = append(channelList, node.ChannelInfo)
}
totalAgentStatList = append(totalAgentStatList, a.ChildStats...)
default:
channelList = append(channelList, a.SelfAgent.ChannelInfo)
for _, node := range a.SelfAgent.Children {
channelList = append(channelList, node.ChannelInfo)
}
totalAgentStatList = append(totalAgentStatList, a.SelfStats...)
totalAgentStatList = append(totalAgentStatList, a.ChildStats...)
}
// 按渠道进行汇总
summaryList := make(proto.AgentSummaryStatHomeList, 0)
for _, channel := range channelList {
summary := &proto.AgentSummaryStatHome{
Channel: channel.Channel,
ParentAgent: channel.ParentAgent,
ChildCount: channel.ChildCount,
TotalStat: &proto.StatDataDetail{},
TodayStat: &proto.StatDataDetail{},
WeekStat: &proto.StatDataDetail{},
MonthStat: &proto.StatDataDetail{},
YearStat: &proto.StatDataDetail{},
}
summaryList = append(summaryList, summary)
}
// 统计日周月年数据
nowTime := time.Now()
for _, summary := range summaryList {
for _, stat := range totalAgentStatList {
if summary.Channel == stat.Channel {
AccumulateSummaryStat(summary, stat, nowTime, true)
}
}
}
// 处理排序,收益多的靠前
sort.Sort(summaryList)
// 处理分页输出
list := GetAgentSummaryStatListPageData(summaryList, pageNum, pageSize)
// 添加app名字,CAP屏蔽充值,CPS屏蔽新增
for _, item := range list {
item.AppName = a.AppMap.GetAppName(item.AppId)
if item.Channel == a.ChannelInfo.Channel {
item.DivideRate = 100
}
}
return int64(len(summaryList)), list
}
func AccumulateSummaryStat(base *proto.AgentSummaryStatHome, stat *proto.AgentDeductedStat, today time.Time, ruleData bool) {
// 时间范围
now.WeekStartDay = time.Monday
Now := now.With(today.In(time.Local))
todayBegin := Now.BeginningOfDay()
todayEnd := Now.EndOfDay()
weekBegin := Now.BeginningOfWeek()
monthBegin := Now.BeginningOfMonth()
yearBegin := Now.BeginningOfYear()
// 复制信息
base.AppId = stat.AppId
base.AppName = stat.AppName
base.Settlement = stat.Settlement
base.CPAPrice = stat.CPAPrice
base.CPSRate = stat.CPSRate
base.DivideRate = stat.DivideRate
// 全部数据累加
AccumulateStatData(base.TotalStat, stat, ruleData)
if (stat.SumDate.Equal(todayBegin) || stat.SumDate.After(todayBegin)) && (stat.SumDate.Equal(todayEnd) || stat.SumDate.Before(todayEnd)) {
AccumulateStatData(base.TodayStat, stat, ruleData)
}
if (stat.SumDate.Equal(weekBegin) || stat.SumDate.After(weekBegin)) && (stat.SumDate.Equal(todayEnd) || stat.SumDate.Before(todayEnd)) {
AccumulateStatData(base.WeekStat, stat, ruleData)
}
if (stat.SumDate.Equal(monthBegin) || stat.SumDate.After(monthBegin)) && (stat.SumDate.Equal(todayEnd) || stat.SumDate.Before(todayEnd)) {
AccumulateStatData(base.MonthStat, stat, ruleData)
}
if (stat.SumDate.Equal(yearBegin) || stat.SumDate.After(yearBegin)) && (stat.SumDate.Equal(todayEnd) || stat.SumDate.Before(todayEnd)) {
AccumulateStatData(base.YearStat, stat, ruleData)
}
}
func GetAgentChannelStatListPageData(list []*proto.AgentDeductedStat, pageNum int64, pageSize int64) []*proto.AgentDeductedStat {
start, end := GetPageRange(len(list), int(pageNum), int(pageSize))
return list[start:end]
}
func GetAgentSummaryStatListPageData(list proto.AgentSummaryStatHomeList, pageNum int64, pageSize int64) proto.AgentSummaryStatHomeList {
start, end := GetPageRange(len(list), int(pageNum), int(pageSize))
return list[start:end]
}
func GetAllAgentStatDict(ctx context.Context, channel string, appId *int32, startTime, endTime *time.Time) (*channelmod.ChannelInfo, SourceAgentStatMap, error) {
// 获取渠道信息
checkFilter := bson.M{channelmod.FN.ChannelInfo.Channel: channel}
channelInfo, err := channelmod.FindOneChannelInfo(ctx, checkFilter)
if err != nil || channelInfo.Channel != channel {
return nil, nil, err
}
// 获取一级渠道的所有子孙数据
var channelTop string
if channelInfo.Type.IsTop() {
channelTop = channelInfo.Channel
} else {
channelTop = channelInfo.ParentChannel
}
srcfilter := bson.M{
channelmod.FN.ChannelStat.Type: bson.M{"$gte": channelInfo.Type},
"$or": bson.A{
bson.M{channelmod.FN.ChannelStat.Channel: channelTop},
bson.M{channelmod.FN.ChannelStat.ParentChannel: channelTop},
}}
if appId != nil {
srcfilter[channelmod.FN.ChannelStat.AppId] = *appId
}
if startTime != nil && endTime != nil {
srcfilter[channelmod.FN.ChannelStat.SumDate] = bson.M{"$gte": *startTime, "$lte": *endTime}
}
srcList, err := channelmod.FindManyChannelStat(ctx, srcfilter)
if err != nil {
return nil, nil, err
}
srcDict := make(SourceAgentStatMap)
types := channelmod.GetAllChannelTypes()
for _, t := range types {
srcDict[t] = make(map[string]ChannelAgentStatList)
}
for _, stat := range srcList {
stat.CorrectValidData()
stat.CalcIncomeRate()
aStat := &AgentChannelStat{
ChannelStat: *stat,
ChildValidDirectCount: 0,
ChildValidPayMoney: 0,
ChildChannelStats: make([]*AgentChannelStat, 0),
}
srcDict[stat.Type][stat.Channel] = append(srcDict[stat.Type][stat.Channel], aStat)
}
return channelInfo, srcDict, nil
}