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.AppId == childStat.AppId && 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) }