forked from all_user/stat_center
Initial commit
This commit is contained in:
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user