Files
stat_center/service/agentSer/node.go
T
2026-05-20 16:13:58 +08:00

249 lines
8.2 KiB
Go

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)
}