Initial commit
This commit is contained in:
@@ -0,0 +1,602 @@
|
||||
package statminute
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"stat/common/log"
|
||||
"stat/common/statutils"
|
||||
"stat/common/topicmessage"
|
||||
"stat/common/utils"
|
||||
"stat/models/accessmod"
|
||||
"stat/models/channelmod"
|
||||
"stat/models/downloadinfo"
|
||||
"stat/models/rechargegamemod"
|
||||
"stat/models/rechargemod"
|
||||
"stat/models/registermod"
|
||||
"stat/models/syncvip"
|
||||
"stat/models/versionMod"
|
||||
"stat/models/withdrawGameOrdermod"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
const (
|
||||
ChannelStat string = "visitInfo" // 渠道统计
|
||||
)
|
||||
|
||||
func defaultTimeMap(defaultStatDate time.Time) map[string]time.Time {
|
||||
return map[string]time.Time{
|
||||
ChannelStat: defaultStatDate, // 渠道统计
|
||||
}
|
||||
}
|
||||
|
||||
// 获取统计方法
|
||||
type StatMethod = func(ctx context.Context, start time.Time, end time.Time, appIds []int32) error
|
||||
|
||||
// 统计方法汇总
|
||||
var statMethodMap = map[string]StatMethod{
|
||||
ChannelStat: ChannelSettlementMethod, // 渠道统计
|
||||
}
|
||||
|
||||
func canUserDeduction(ruleInfo *channelmod.ChannelDeductionRule, index int, incomeRate float64, isDirect bool) bool {
|
||||
rate := int32(0) // 扣量比例
|
||||
if ruleInfo.Settlement == channelmod.SettlementCPA || ruleInfo.Settlement == channelmod.SettlementCPS {
|
||||
//自动扣量
|
||||
if ruleInfo.Settlement == channelmod.SettlementCPA && ruleInfo.AutoDeduction && incomeRate > 0.0 && ruleInfo.LessIncomeRate > incomeRate {
|
||||
rate = 80
|
||||
} else {
|
||||
if index < 1 { // 一阶
|
||||
rate = ruleInfo.First
|
||||
} else if index <= 3 { // 二阶
|
||||
rate = ruleInfo.Second
|
||||
} else if index <= 6 { // 三阶
|
||||
rate = ruleInfo.Third
|
||||
} else if index <= 10 { // 四阶
|
||||
rate = ruleInfo.Fourth
|
||||
} else {
|
||||
rate = ruleInfo.Fifth
|
||||
}
|
||||
}
|
||||
if isDirect && int32(rand.Intn(100)) < rate { // rate扣量比例
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func deductionCountMethod(ctx context.Context, ruleInfo *channelmod.ChannelDeductionRule, settlement *channelmod.ChannelSettlement, registerList []*registermod.RegisterMod, incomeRate float64) error {
|
||||
deductionUserIds := make([]int64, 0)
|
||||
// 先计算扣量
|
||||
for index, item := range registerList {
|
||||
item.IsDeduction = false
|
||||
if canUserDeduction(ruleInfo, index, incomeRate, item.IsDirect) {
|
||||
item.IsDeduction = true
|
||||
deductionUserIds = append(deductionUserIds, int64(item.UserId))
|
||||
}
|
||||
}
|
||||
// 统计IP
|
||||
ipDict := make(map[string]int64)
|
||||
for _, item := range registerList {
|
||||
if item.IP != "" {
|
||||
ipDict[item.IP]++
|
||||
}
|
||||
}
|
||||
// 1.统计这段时间内的注册用户
|
||||
stat := &statutils.Stat{}
|
||||
uniqueStat := &statutils.Stat{}
|
||||
for _, item := range registerList {
|
||||
client := statutils.GetClientInfo(item.SysType, item.DevType, item.DistrictCode, item.IsDirect, item.IsDeduction, item.IsFormal)
|
||||
stat.Add(1, client)
|
||||
if _, exists := ipDict[item.IP]; exists {
|
||||
uniqueStat.Add(1, client)
|
||||
}
|
||||
}
|
||||
settlement.NewTotalIpCount += uniqueStat.Count()
|
||||
settlement.NewTotalCount += stat.Total.Count()
|
||||
settlement.NewDirectCount += stat.Total.Direct.Count()
|
||||
settlement.NewFissionCount += stat.Total.Fission.Count
|
||||
settlement.NewDeductionCount += stat.Total.Deduction.Count
|
||||
settlement.NewLightCount += stat.Light.Count()
|
||||
settlement.NewLightDirectCount += stat.Light.Total.Direct.Count()
|
||||
settlement.NewLightFissionCount += stat.Light.Total.Fission.Count
|
||||
settlement.NewLightDeductionCount += stat.Light.Total.Deduction.Count
|
||||
settlement.NewLightNaturalCount += stat.Light.Total.Direct.Natural.Count
|
||||
settlement.NewLightGuestCount += stat.Light.Guest.Count()
|
||||
settlement.NewLightGuestDirectCount += stat.Light.Guest.Direct.Count()
|
||||
settlement.NewLightGuestFissionCount += stat.Light.Guest.Fission.Count
|
||||
settlement.NewLightGuestDeductionCount += stat.Light.Guest.Deduction.Count
|
||||
settlement.NewLightFormalCount += stat.Light.Formal.Count()
|
||||
settlement.NewLightFormalDirectCount += stat.Light.Formal.Direct.Count()
|
||||
settlement.NewLightFormalFissionCount += stat.Light.Formal.Fission.Count
|
||||
settlement.NewLightFormalDeductionCount += stat.Light.Formal.Deduction.Count
|
||||
settlement.NewAndroidCount += stat.Android.Count()
|
||||
settlement.NewAndroidDirectCount += stat.Android.Direct.Count()
|
||||
settlement.NewAndroidFissionCount += stat.Android.Fission.Count
|
||||
settlement.NewAndroidDeductionCount += stat.Android.Deduction.Count
|
||||
settlement.NewIosCount += stat.Ios.Count()
|
||||
settlement.NewIosDirectCount += stat.Ios.Direct.Count()
|
||||
settlement.NewIosFissionCount += stat.Ios.Fission.Count
|
||||
settlement.NewIosDeductionCount += stat.Ios.Deduction.Count
|
||||
settlement.NewH5Count += stat.H5.Count()
|
||||
settlement.NewH5DirectCount += stat.H5.Total.Direct.Count()
|
||||
settlement.NewH5FissionCount += stat.H5.Total.Fission.Count
|
||||
settlement.NewH5DeductionCount += stat.H5.Total.Deduction.Count
|
||||
settlement.NewH5AndroidCount += stat.H5.Android.Count()
|
||||
settlement.NewH5IosCount += stat.H5.Ios.Count()
|
||||
settlement.NewH5PcCount += stat.H5.Pc.Count()
|
||||
settlement.NewH5FormalCount += stat.H5.Formal.Count()
|
||||
settlement.NewH5FormalDirectCount += stat.H5.Formal.Direct.Count()
|
||||
settlement.NewH5FormalFissionCount += stat.H5.Formal.Fission.Count
|
||||
settlement.NewH5FormalDeductionCount += stat.H5.Formal.Deduction.Count
|
||||
|
||||
// 5 更新扣量用户
|
||||
if len(deductionUserIds) > 0 {
|
||||
setdoc := bson.M{"$set": bson.M{"isDeduction": true}}
|
||||
filter := bson.M{
|
||||
"appId": ruleInfo.AppId,
|
||||
"userId": bson.M{"$in": deductionUserIds},
|
||||
}
|
||||
err := registermod.UpdateManyRegister(ctx, filter, setdoc)
|
||||
if err != nil {
|
||||
log.Error("NewCountMethod UpdateManyRegister ", log.E(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func channelChannelStatMethod(ctx context.Context, ruleInfo *channelmod.ChannelDeductionRule, settlement *channelmod.ChannelSettlement, visitList accessmod.VisitInfoList,
|
||||
start, end time.Time, appid int32) error {
|
||||
|
||||
stat := &statutils.Stat{}
|
||||
for _, item := range visitList {
|
||||
client := statutils.GetClientInfo(item.SysType, item.DevType, item.DistrictCode, item.IsDirect, false, item.IsFormalUser)
|
||||
stat.Add(1, client)
|
||||
}
|
||||
settlement.TotalVisitCount = stat.Count()
|
||||
settlement.DirectVisitCount = stat.Total.Direct.Count()
|
||||
settlement.FissionVisitCount = stat.Total.Fission.Count
|
||||
settlement.AndroidVisitCount = stat.Android.Count()
|
||||
settlement.IosVisitCount = stat.Ios.Count()
|
||||
settlement.LightVisitCount = stat.Light.Count()
|
||||
settlement.LightVisitDirectCount = stat.Light.Total.Direct.Count()
|
||||
settlement.LightVisitFissionCount = stat.Light.Total.Fission.Count
|
||||
settlement.LightVisitDeductionCount = stat.Light.Total.Deduction.Count
|
||||
settlement.LightVisitNaturalCount = stat.Light.Total.Direct.Natural.Count
|
||||
settlement.H5VisitCount = stat.H5.Count()
|
||||
settlement.H5AndroidVisitCount = stat.H5.Android.Count()
|
||||
settlement.H5IosVisitCount = stat.H5.Ios.Count()
|
||||
settlement.H5PcVisitCount = stat.H5.Pc.Count()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func channelVipMethod(ctx context.Context, ruleInfo *channelmod.ChannelDeductionRule, settlement *channelmod.ChannelSettlement, VipList syncvip.SyncVipList,
|
||||
start, end time.Time, appid int32) error {
|
||||
deductionVipOrderIds := make([]primitive.ObjectID, 0)
|
||||
for _, buyInfo := range VipList {
|
||||
// 统计渠道信息
|
||||
if buyInfo.IsDirect && buyInfo.BuyVIPType == topicmessage.BuyVIPTypeMoney {
|
||||
if ruleInfo.Settlement == channelmod.SettlementCPS {
|
||||
if ruleInfo.TodayTime != utils.BeginWithTime(start) {
|
||||
ruleInfo.TodayDeduction = 0
|
||||
ruleInfo.TodayTime = utils.BeginWithTime(start)
|
||||
}
|
||||
ruleInfo.TodayDeduction += buyInfo.Money
|
||||
if ruleInfo.CPSBegin < ruleInfo.TodayDeduction {
|
||||
if int32(rand.Intn(100)) < int32(ruleInfo.CPSDeductionRate) {
|
||||
deductionVipOrderIds = append(deductionVipOrderIds, buyInfo.ID)
|
||||
settlement.VipPayDeduction += buyInfo.Money
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 统计信息
|
||||
if buyInfo.IsDirect {
|
||||
if buyInfo.BuyVIPType == topicmessage.BuyVIPTypeMoney {
|
||||
settlement.VipPayMoney += buyInfo.Money
|
||||
} else {
|
||||
settlement.VipPayCoin += buyInfo.Amount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(deductionVipOrderIds) > 0 {
|
||||
settlement.VipPayMoney = settlement.VipPayMoney - settlement.VipPayDeduction
|
||||
|
||||
setdoc := bson.M{"$set": bson.M{syncvip.FN.SyncVip.IsDeduction: true}}
|
||||
filter := bson.M{
|
||||
syncvip.FN.SyncVip.ID: bson.M{"$in": deductionVipOrderIds},
|
||||
syncvip.FN.SyncVip.AppId: ruleInfo.AppId,
|
||||
}
|
||||
err := syncvip.UpdateOneSyncVip(ctx, filter, setdoc)
|
||||
if err != nil {
|
||||
log.Error("channelRechargeCountMethod UpdateManyRecharge ", log.E(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func channelRechargeCountMethod(ctx context.Context, ruleInfo *channelmod.ChannelDeductionRule, settlement *channelmod.ChannelSettlement, rechargeList rechargemod.RechargeInfoList,
|
||||
start, end time.Time, appid int32) error {
|
||||
|
||||
stat := &statutils.Stat{}
|
||||
statNew := statutils.Stat{}
|
||||
for _, item := range rechargeList {
|
||||
client := statutils.GetClientInfo(item.SysType, item.DevType, item.DistrictCode, item.IsDirect, false, item.IsFormalUser)
|
||||
stat.Add(item.Money, client)
|
||||
if item.RegisterTime.After(item.SuccessAt.AddDate(0, 0, -1)) {
|
||||
statNew.Add(item.Money, client)
|
||||
}
|
||||
}
|
||||
settlement.TotalAmount = stat.Value()
|
||||
settlement.DirectAmount = stat.Total.Direct.Value()
|
||||
settlement.DirectAmountCount = stat.Total.Direct.Count()
|
||||
settlement.FissionAmount = stat.Total.Fission.Value
|
||||
settlement.FissionAmountCount = stat.Total.Fission.Count
|
||||
settlement.NaturalAmount = stat.Total.Direct.Natural.Value
|
||||
settlement.NaturalAmountCount = stat.Total.Direct.Natural.Count
|
||||
settlement.DeductionAmount = stat.Total.Deduction.Value
|
||||
settlement.DeductionAmountCount = stat.Total.Deduction.Count
|
||||
settlement.AndroidAmount = stat.Android.Value()
|
||||
settlement.AndroidAmountCount = stat.Android.Count()
|
||||
settlement.IosAmount = stat.Ios.Value()
|
||||
settlement.IosAmountCount = stat.Ios.Count()
|
||||
settlement.H5Amount = stat.H5.Value()
|
||||
settlement.H5AmountCount = stat.H5.Count()
|
||||
settlement.LightAmount = stat.Light.Value()
|
||||
settlement.LightAmountCount = stat.Light.Count()
|
||||
settlement.LightDirectAmount = stat.Light.Total.Direct.Value()
|
||||
settlement.LightDirectAmountCount = stat.Light.Total.Direct.Count()
|
||||
settlement.LightFissionAmount = stat.Light.Total.Fission.Value
|
||||
settlement.LightFissionAmountCount = stat.Light.Total.Fission.Count
|
||||
settlement.LightDeductionAmount = stat.Light.Total.Deduction.Value
|
||||
settlement.LightDeductionAmountCount = stat.Light.Total.Deduction.Count
|
||||
settlement.LightNaturalAmount = stat.Light.Total.Direct.Natural.Value
|
||||
settlement.LightNaturalAmountCount = stat.Light.Total.Direct.Natural.Count
|
||||
settlement.NewRechargeAmount = statNew.Value()
|
||||
return nil
|
||||
}
|
||||
|
||||
// GameRechargeMethod 游戏充值
|
||||
func channelGameRechargeMethod(ctx context.Context, ruleInfo *channelmod.ChannelDeductionRule,
|
||||
rechageList rechargegamemod.GameRechargeInfoList, withdrawList []withdrawGameOrdermod.GameWithdrawOrder,
|
||||
settlement *channelmod.ChannelSettlement,
|
||||
start, end time.Time, appid int32) error {
|
||||
|
||||
for _, withdrawInfo := range withdrawList {
|
||||
if ruleInfo.Channel == withdrawInfo.DistrictCode {
|
||||
settlement.GameWithdrawAmount += withdrawInfo.Money
|
||||
}
|
||||
}
|
||||
|
||||
for _, rechageInfo := range rechageList {
|
||||
if ruleInfo.Channel == rechageInfo.DistrictCode {
|
||||
settlement.GameRechageAmount += rechageInfo.Money
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// channelLandPageMethod 落地页访问
|
||||
func channelLandPageMethod(ctx context.Context, settlement *channelmod.ChannelSettlement, start, end time.Time, appid int32) error {
|
||||
itemList, err := downloadinfo.GetChannelDownloadPageListByTime(ctx, settlement.Channel, appid, start, end)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
androidClick := int64(0)
|
||||
appstoreClick := int64(0)
|
||||
iosAtherClick := int64(0)
|
||||
lightClick := int64(0)
|
||||
|
||||
for _, downloadInfo := range itemList {
|
||||
if downloadInfo.SysType == "android" {
|
||||
androidClick += 1
|
||||
} else if strings.Contains(downloadInfo.SysType, "ios") || strings.Contains(downloadInfo.SysType, "light") {
|
||||
if downloadInfo.PackageType == versionMod.Shop {
|
||||
appstoreClick += 1
|
||||
} else if downloadInfo.PackageType == versionMod.Enterprise {
|
||||
iosAtherClick += 1
|
||||
} else if downloadInfo.PackageType == versionMod.Light {
|
||||
lightClick += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
settlement.LandPageVisitCount = int64(len(itemList))
|
||||
settlement.LandpageAndroidClick = androidClick
|
||||
settlement.LandpageIosAppstoreClick = appstoreClick
|
||||
settlement.LandpageIosAthorClick = iosAtherClick
|
||||
settlement.LandpageIosH5Click = lightClick
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChannelSettlementMethod 渠道计算
|
||||
func ChannelSettlementMethod(ctx context.Context, start time.Time, end time.Time, appIds []int32) error {
|
||||
for _, appid := range appIds {
|
||||
channelDeductionRules, err := channelmod.FindManyChannelDeductionRule(ctx, bson.M{channelmod.FN.ChannelDeductionRule.AppId: appid})
|
||||
if err != nil {
|
||||
log.Error("ChannelSettlementMethod FindManyChannelDeductionRule", log.E(err))
|
||||
return err
|
||||
}
|
||||
|
||||
channnels := make([]string, 0)
|
||||
for _, channnelInfo := range channelDeductionRules {
|
||||
channnels = append(channnels, channnelInfo.Channel)
|
||||
}
|
||||
channelInfolist, err := channelmod.FindManyChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: bson.M{"$in": channnels}})
|
||||
if err != nil {
|
||||
log.Error("ChannelSettlementMethod FindManyChannelInfo", log.E(err))
|
||||
return err
|
||||
}
|
||||
registerList, err := registermod.RegisterUsersInfoByTime(ctx, appid, start, end)
|
||||
if err != nil {
|
||||
log.Error("NewCountMethod RegisterUsersInfoByDistrict ", log.E(err))
|
||||
return err
|
||||
}
|
||||
|
||||
registerFormalList, err := registermod.RegisterFormalsInfoByTime(ctx, appid, start, end)
|
||||
if err != nil {
|
||||
log.Error("NewCountMethod RegisterUsersInfoByDistrict ", log.E(err))
|
||||
return err
|
||||
}
|
||||
|
||||
vipfilter := bson.M{
|
||||
syncvip.FN.SyncVip.AppId: appid,
|
||||
syncvip.FN.SyncVip.SuccessAt: bson.M{"$gte": start, "$lt": end},
|
||||
}
|
||||
|
||||
VipList, err := syncvip.FindManySyncVip(ctx, vipfilter)
|
||||
if err != nil {
|
||||
log.Error("ChannelChannelStatMethod FindManyVisitInfo ", log.E(err))
|
||||
return err
|
||||
}
|
||||
|
||||
visitFilter := bson.M{"appId": appid, "visitAt": bson.M{"$gte": start, "$lt": end}}
|
||||
visitList, _ := accessmod.FindManyVisitInfo(ctx, visitFilter)
|
||||
|
||||
rechargeFilter := bson.M{"appId": appid, "successAt": bson.M{"$gte": start, "$lt": end}}
|
||||
rechargeList, _ := rechargemod.FindManyRechargeInfo(ctx, rechargeFilter)
|
||||
|
||||
for _, ruleInfo := range channelDeductionRules {
|
||||
if ruleInfo.CreatedAt.After(start) {
|
||||
continue
|
||||
}
|
||||
//fmt.Println("channelDeductionRules", ruleInfo.Channel)
|
||||
settlement := &channelmod.ChannelSettlement{
|
||||
SumDate: start,
|
||||
AppId: appid,
|
||||
AppType: ruleInfo.AppType,
|
||||
PromoteMode: ruleInfo.PromoteMode,
|
||||
Channel: ruleInfo.Channel,
|
||||
}
|
||||
for _, channelInfo := range channelInfolist {
|
||||
if channelInfo.Channel == ruleInfo.Channel {
|
||||
settlement.Type = channelInfo.Type
|
||||
settlement.ParentChannel = channelInfo.ParentChannel
|
||||
settlement.UserName = channelInfo.UserName
|
||||
}
|
||||
}
|
||||
if ruleInfo.SettlementTime == start {
|
||||
// 已经结算
|
||||
continue
|
||||
}
|
||||
|
||||
statFilter := bson.M{
|
||||
channelmod.FN.ChannelStat.Channel: ruleInfo.Channel,
|
||||
channelmod.FN.ChannelStat.SumDate: utils.BeginWithTime(start),
|
||||
channelmod.FN.ChannelStat.AppId: appid,
|
||||
}
|
||||
|
||||
channelStatInfo, err := channelmod.FindOneChannelStat(ctx, statFilter)
|
||||
if err != nil {
|
||||
log.Error("ChannelSettlementMethod CountChannelStats", log.E(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 统计新增情况
|
||||
userDict := make(map[uint64]bool)
|
||||
channelRegisterList := make([]*registermod.RegisterMod, 0)
|
||||
for _, v := range registerFormalList {
|
||||
if v.IsFormal && statutils.IsClientH5OrLight(v.SysType, v.DevType) {
|
||||
if v.DistrictCode == ruleInfo.Channel {
|
||||
userDict[v.UserId] = true
|
||||
channelRegisterList = append(channelRegisterList, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, v := range registerList {
|
||||
if v.DistrictCode == ruleInfo.Channel {
|
||||
if _, exists := userDict[v.UserId]; !exists {
|
||||
userDict[v.UserId] = true
|
||||
channelRegisterList = append(channelRegisterList, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
oldIncomeRate := float64(0)
|
||||
if channelStatInfo != nil {
|
||||
oldIncomeRate = channelStatInfo.IncomeRate
|
||||
}
|
||||
deductionCountMethod(ctx, ruleInfo, settlement, channelRegisterList, oldIncomeRate)
|
||||
|
||||
// 统计访问量
|
||||
channelAccessList := make(accessmod.VisitInfoList, 0)
|
||||
for _, v := range visitList {
|
||||
if v.DistrictCode == ruleInfo.Channel {
|
||||
channelAccessList = append(channelAccessList, v)
|
||||
}
|
||||
}
|
||||
channelChannelStatMethod(ctx, ruleInfo, settlement, channelAccessList, start, end, appid)
|
||||
|
||||
// 统计充值数据
|
||||
channelRechargeList := make(rechargemod.RechargeInfoList, 0)
|
||||
for _, v := range rechargeList {
|
||||
if v.DistrictCode == ruleInfo.Channel {
|
||||
channelRechargeList = append(channelRechargeList, v)
|
||||
}
|
||||
}
|
||||
channelRechargeCountMethod(ctx, ruleInfo, settlement, channelRechargeList, start, end, appid)
|
||||
|
||||
// 统计VIP购买
|
||||
channelVipList := make(syncvip.SyncVipList, 0)
|
||||
for _, v := range VipList {
|
||||
if v.DistrictCode == ruleInfo.Channel {
|
||||
channelVipList = append(channelVipList, v)
|
||||
}
|
||||
}
|
||||
channelVipMethod(ctx, ruleInfo, settlement, channelVipList, start, end, appid)
|
||||
|
||||
channelLandPageMethod(ctx, settlement, start, end, appid)
|
||||
|
||||
// 更新渠道信息
|
||||
ruleFilter := bson.M{channelmod.FN.ChannelDeductionRule.ID: ruleInfo.ID}
|
||||
ruleSet := bson.M{"$set": bson.M{
|
||||
channelmod.FN.ChannelDeductionRule.SettlementTime: start,
|
||||
channelmod.FN.ChannelDeductionRule.TodayTime: ruleInfo.TodayTime,
|
||||
channelmod.FN.ChannelDeductionRule.TodayDeduction: ruleInfo.TodayDeduction,
|
||||
}}
|
||||
|
||||
err = channelmod.UpdateManyChannelDeductionRule(ctx, ruleFilter, ruleSet)
|
||||
if err != nil {
|
||||
log.Error("ChannelSettlementMethod UpdateManyChannelDeductionRule", log.E(err))
|
||||
return err
|
||||
}
|
||||
|
||||
settlement.CorrectValidData()
|
||||
|
||||
//插入数据
|
||||
err = channelmod.InsertOneChannelSettlement(ctx, settlement)
|
||||
if err != nil {
|
||||
log.Error("ChannelSettlementMethod InsertOneChannelSettlement", log.E(err))
|
||||
return err
|
||||
}
|
||||
|
||||
if channelStatInfo.Channel != ruleInfo.Channel {
|
||||
channelStatInfo.Channel = ruleInfo.Channel
|
||||
channelStatInfo.SumDate = utils.BeginWithTime(start)
|
||||
channelStatInfo.AppId = appid
|
||||
channelStatInfo.Type = settlement.Type
|
||||
channelStatInfo.UserName = settlement.UserName
|
||||
channelStatInfo.Settlement = ruleInfo.Settlement
|
||||
channelStatInfo.CPAPrice = ruleInfo.CPAPrice
|
||||
channelStatInfo.CPSRate = ruleInfo.CPSRate
|
||||
channelStatInfo.AppType = ruleInfo.AppType
|
||||
channelStatInfo.PromoteMode = ruleInfo.PromoteMode
|
||||
channelStatInfo.ParentChannel = settlement.ParentChannel
|
||||
channelStatInfo.IsPay = false
|
||||
// 数据赋值
|
||||
settlement.AssignmentTo(channelStatInfo)
|
||||
// 插入记录
|
||||
err = channelmod.InsertOneChannelStat(ctx, channelStatInfo)
|
||||
if err != nil {
|
||||
log.Error("ChannelSettlementMethod InsertOneChannelStat", log.E(err))
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// 数据累加
|
||||
settlement.AccumulateTo(channelStatInfo)
|
||||
// 更新记录
|
||||
setdoc := bson.M{"$set": channelStatInfo}
|
||||
err = channelmod.UpdateOneChannelStat(ctx, statFilter, setdoc)
|
||||
if err != nil {
|
||||
log.Error("ChannelSettlementMethod UpdateOneChannelStat", log.E(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 更新渠道数据
|
||||
func ChannelSettlementUpdateByHour() error {
|
||||
ctx := context.Background()
|
||||
nowHour := utils.BeginOfHour()
|
||||
|
||||
statFilter := bson.M{
|
||||
channelmod.FN.ChannelStat.SumDate: utils.BeginWithTime(nowHour.Add(-30 * time.Minute)), // 确保:0点是获取上一天数据
|
||||
"$or": bson.A{
|
||||
bson.M{channelmod.FN.ChannelStat.NewDirectCount: bson.M{"$gt": 0}},
|
||||
bson.M{channelmod.FN.ChannelStat.DirectAmount: bson.M{"$gt": 0}},
|
||||
},
|
||||
}
|
||||
statList, err := channelmod.FindManyChannelStat(ctx, statFilter)
|
||||
if err != nil {
|
||||
log.Error("ChannelSettlementUpdateByHour FindManyChannelStat", log.E(err))
|
||||
return err
|
||||
}
|
||||
|
||||
yesterdayFilter := bson.M{
|
||||
channelmod.FN.ChannelStatYestoday.SumDate: nowHour.AddDate(0, 0, -1),
|
||||
}
|
||||
|
||||
statYesterdayList, _ := channelmod.FindManyChannelStatYestoday(ctx, yesterdayFilter)
|
||||
|
||||
for _, channelStatInfo := range statList {
|
||||
channelStatInfoYesterday := &channelmod.ChannelStatYesterday{
|
||||
// base
|
||||
Channel: channelStatInfo.Channel,
|
||||
SumDate: nowHour,
|
||||
AppId: channelStatInfo.AppId,
|
||||
ParentChannel: channelStatInfo.ParentChannel,
|
||||
Settlement: channelStatInfo.Settlement,
|
||||
UpdatedAt: time.Now(),
|
||||
CreatedAt: time.Now(),
|
||||
// new
|
||||
NewCount: channelStatInfo.NewTotalCount,
|
||||
NewDirectCount: channelStatInfo.NewDirectCount,
|
||||
NewFissionCount: channelStatInfo.NewFissionCount,
|
||||
NewAndroidCount: channelStatInfo.NewAndroidCount,
|
||||
NewIosCount: channelStatInfo.NewIosCount,
|
||||
NewH5Count: channelStatInfo.NewH5Count,
|
||||
NewH5FormalCount: channelStatInfo.NewH5FormalCount,
|
||||
NewLightGuestCount: channelStatInfo.NewLightGuestCount,
|
||||
NewLightFormalCount: channelStatInfo.NewLightFormalCount,
|
||||
// recharge
|
||||
RechargeAmount: channelStatInfo.TotalAmount,
|
||||
DirectAmount: channelStatInfo.DirectAmount,
|
||||
FissionAmount: channelStatInfo.FissionAmount,
|
||||
AndroidRechargeAmount: channelStatInfo.AndroidAmount,
|
||||
IosRechargeAmount: channelStatInfo.IosAmount,
|
||||
LightRechargeAmount: channelStatInfo.LightAmount,
|
||||
H5RechargeAmount: channelStatInfo.H5Amount,
|
||||
// other
|
||||
VipPayCoin: channelStatInfo.VipPayCoin,
|
||||
VipPayMoney: channelStatInfo.VipPayMoney,
|
||||
VipPayDeduction: channelStatInfo.VipPayDeduction,
|
||||
}
|
||||
|
||||
for _, yesterdayStatInfo := range statYesterdayList {
|
||||
// 获取昨天数据
|
||||
if yesterdayStatInfo.Channel == channelStatInfo.Channel && yesterdayStatInfo.AppId == channelStatInfo.AppId {
|
||||
newYesterday := yesterdayStatInfo.NewCount
|
||||
newToday := channelStatInfo.NewTotalCount
|
||||
channelStatInfoYesterday.NewIncreaseCount = newToday - newYesterday
|
||||
if newYesterday != 0 {
|
||||
channelStatInfoYesterday.NewIncreaseRate = fmt.Sprintf("%.2f", float64(newToday-newYesterday)*100/float64(newYesterday)) + "%"
|
||||
}
|
||||
rechargeYesterday := yesterdayStatInfo.RechargeAmount
|
||||
rechargeToday := channelStatInfo.TotalAmount
|
||||
channelStatInfoYesterday.RechargeIncreaseAmount = rechargeToday - rechargeYesterday
|
||||
if rechargeYesterday != 0 {
|
||||
channelStatInfoYesterday.RechargeIncreaseRate = fmt.Sprintf("%.2f", float64(rechargeToday-rechargeYesterday)*100/float64(rechargeYesterday)) + "%"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err := channelmod.InsertOneChannelStatYestoday(ctx, channelStatInfoYesterday)
|
||||
if err != nil {
|
||||
log.Error("ChannelSettlementMethod InsertOneChannelStatYestoday", log.E(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package statminute
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"stat/common/log"
|
||||
"stat/common/statutils"
|
||||
"stat/common/utils"
|
||||
"stat/models/appInfoMod"
|
||||
statrecordmod "stat/models/statrecord"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
* 主要统计任务:
|
||||
* 按5分钟一个点,记录实时数据 app(新增、访问数....)。(曲线图)
|
||||
*/
|
||||
|
||||
// RunStat 任务1:统计每天日活
|
||||
func RunStat(defaultStatDate time.Time) error {
|
||||
log.Info("channel deduction ......")
|
||||
ctx := context.Background()
|
||||
recordMap := defaultTimeMap(defaultStatDate)
|
||||
|
||||
// 1.获取统计项上次统计的时候(每天执行)
|
||||
recoredResult, err := statrecordmod.LastRecordTimeMap(ctx, statrecordmod.ChannelDeduction) //第一次从默认记录时间开始统计
|
||||
if err != nil {
|
||||
log.Error("channel deduction ", log.E(err))
|
||||
return err
|
||||
}
|
||||
for _, record := range recoredResult {
|
||||
recordMap[record.Item] = record.RecordTime
|
||||
}
|
||||
|
||||
now := time.Now().Add(time.Minute * -5) // 延迟2分钟,数据同步完成
|
||||
statFrq := 15 * time.Minute // 统计频率
|
||||
curStatTime := utils.RecentMinute(now, 15) // 按15分钟对齐
|
||||
|
||||
appIds, err := appInfoMod.GetAppIds(ctx)
|
||||
if err != nil {
|
||||
log.Error("channel deduction GetAppIds failed!", log.E(err))
|
||||
return err
|
||||
}
|
||||
|
||||
for item, lastStatAt := range recordMap {
|
||||
_lastStatAt := lastStatAt
|
||||
|
||||
for curStatTime.After(_lastStatAt) {
|
||||
end := _lastStatAt.Add(statFrq)
|
||||
// 超过本次统计结束时间,则结束
|
||||
if end.After(curStatTime) {
|
||||
end = curStatTime
|
||||
}
|
||||
// 根据时间段统计数据
|
||||
fmt.Println("channel deduction ", _lastStatAt, end)
|
||||
err := runStatMethod(ctx, item, _lastStatAt, end, appIds)
|
||||
if err != nil {
|
||||
log.Error("channel deduction runStatMethod failed!", log.E(err), log.Any("item", item))
|
||||
return err
|
||||
}
|
||||
|
||||
_lastStatAt = end
|
||||
}
|
||||
recordMap[item] = _lastStatAt
|
||||
}
|
||||
log.Info("channel deduction ")
|
||||
return err
|
||||
}
|
||||
|
||||
// runStatMethod 调用统计项方法
|
||||
func runStatMethod(ctx context.Context, item string, start, end time.Time, appIds []int32) (err error) {
|
||||
// 1.获取统计方法
|
||||
statMethod, ok := statMethodMap[item]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 调用统计方法,获取数据
|
||||
err = statutils.ServerMon.RunWithName(func() error {
|
||||
return statMethod(ctx, start, end, appIds)
|
||||
}, statutils.GetFuncName(statMethod))
|
||||
|
||||
if err != nil {
|
||||
log.Error("channel deduction statMethod failed!", log.Any("statItem", item), log.E(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 3.更新记录
|
||||
if err := statrecordmod.UpsertItemRecord(ctx, statrecordmod.ChannelDeduction, item, end); err != nil {
|
||||
log.Error("channel deduction commit UpsertItemRecord failed!", log.E(err))
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user