From c129f2056fdb70f2fdde9709e7aaaed931d7a26d Mon Sep 17 00:00:00 2001 From: dengbiao Date: Tue, 27 Aug 2024 13:56:19 +0800 Subject: [PATCH] update --- app/db/dao/original_wx_ad_data_dao.go | 5 + .../original_wx_ad_data_implement.go | 14 ++ app/hdl/hdl_demo.go | 44 +++- app/hdl/hdl_set_center.go | 1 - app/lib/wechat/md/wechat_api_md.go | 23 ++ app/lib/wechat/wechat_api.go | 32 +++ app/md/md_generate_wx_ad_data.go | 15 ++ app/router/router.go | 1 + app/svc/svc_wx_data.go | 197 ++++++++++++++++++ app/utils/convert.go | 3 + go.mod | 2 +- 11 files changed, 326 insertions(+), 11 deletions(-) create mode 100644 app/db/dao/original_wx_ad_data_dao.go create mode 100644 app/db/implement/original_wx_ad_data_implement.go create mode 100644 app/md/md_generate_wx_ad_data.go create mode 100644 app/svc/svc_wx_data.go diff --git a/app/db/dao/original_wx_ad_data_dao.go b/app/db/dao/original_wx_ad_data_dao.go new file mode 100644 index 0000000..9b18654 --- /dev/null +++ b/app/db/dao/original_wx_ad_data_dao.go @@ -0,0 +1,5 @@ +package dao + +type OriginalWxAdDataDao interface { + //TODO:: You can add specific method definitions here +} diff --git a/app/db/implement/original_wx_ad_data_implement.go b/app/db/implement/original_wx_ad_data_implement.go new file mode 100644 index 0000000..57b1705 --- /dev/null +++ b/app/db/implement/original_wx_ad_data_implement.go @@ -0,0 +1,14 @@ +package implement + +import ( + "applet/app/db/dao" + "xorm.io/xorm" +) + +func NewOriginalWxAdDataDb(engine *xorm.Engine) dao.OriginalWxAdDataDao { + return &OriginalWxAdDataDb{Db: engine} +} + +type OriginalWxAdDataDb struct { + Db *xorm.Engine +} diff --git a/app/hdl/hdl_demo.go b/app/hdl/hdl_demo.go index 877a8a8..d7dfada 100644 --- a/app/hdl/hdl_demo.go +++ b/app/hdl/hdl_demo.go @@ -2,24 +2,50 @@ package hdl import ( "applet/app/e" + "applet/app/lib/wechat" "applet/app/svc" "applet/app/utils" - "fmt" + db "code.fnuoos.com/zhimeng/model.git/src" + "code.fnuoos.com/zhimeng/model.git/src/super/implement" "github.com/gin-gonic/gin" ) func Demo(c *gin.Context) { - mediumId := utils.GenerateUniqueRandomNumbers(8) - fmt.Println(mediumId) - var args interface{} - err := c.ShouldBindJSON(&args) + appId := c.DefaultQuery("app_id", "") + masterId := svc.GetMasterId(c) + adUnitId := c.DefaultQuery("adunit_id", "") + + //1、查找对应 user_wx_applet_list 记录 + userWxAppletListDb := implement.NewUserWxAppletListDb(db.Db) + UserWxAppletList, err := userWxAppletListDb.GetUserWxAppletList(masterId) if err != nil { - err = svc.HandleValidateErr(err) - err1 := err.(e.E) - e.OutErr(c, err1.Code, err1.Error()) + e.OutErr(c, e.ERR_DB_ORM, err.Error()) + return + } + if UserWxAppletList == nil { + e.OutErr(c, e.ERR_NO_DATA, "未查询到对应记录") + return + } + wxOpenThirdPartyAppListDb := implement.NewWxOpenThirdPartyAppListDb(db.Db) + wxOpenThirdPartyAppList, err := wxOpenThirdPartyAppListDb.GetWxOpenThirdPartyAppList(utils.StrToInt(masterId)) + if err != nil { + e.OutErr(c, e.ERR, err.Error()) + return + } + if wxOpenThirdPartyAppList == nil { + e.OutErr(c, e.ERR_NOT_FAN, "未查询到对应三方应用记录") + return + } + wxApiService, err := wechat.NewWxApiService(masterId, wxOpenThirdPartyAppList.Appid, wxOpenThirdPartyAppList.AppSecret) + if err != nil { + e.OutErr(c, e.ERR, err.Error()) + return + } + err, args := wxApiService.GetAdposDetail(appId, 1, 10, "2024-08-19", "2024-08-23", adUnitId) + if err != nil { + e.OutErr(c, e.ERR, err.Error()) return } - e.OutSuc(c, map[string]interface{}{ "args": args, }, nil) diff --git a/app/hdl/hdl_set_center.go b/app/hdl/hdl_set_center.go index 2978e70..a180d61 100644 --- a/app/hdl/hdl_set_center.go +++ b/app/hdl/hdl_set_center.go @@ -417,7 +417,6 @@ func AppletUnauthorized(c *gin.Context) { e.OutErr(c, e.ERR_NOT_FAN, "未查询到对应三方应用记录") return } - wxApiService, err := wechat.NewWxApiService(masterId, wxOpenThirdPartyAppList.Appid, wxOpenThirdPartyAppList.AppSecret) if err != nil { e.OutErr(c, e.ERR, err.Error()) diff --git a/app/lib/wechat/md/wechat_api_md.go b/app/lib/wechat/md/wechat_api_md.go index c5e9fd6..d4b7411 100644 --- a/app/lib/wechat/md/wechat_api_md.go +++ b/app/lib/wechat/md/wechat_api_md.go @@ -60,3 +60,26 @@ type GetAdunitList struct { } `json:"ad_unit"` TotalNum int `json:"total_num" example:"总广告单元数据量"` } + +type GetAdposDetail struct { + Ret int `json:"ret" example:"错误码"` + ErrMsg string `json:"err_msg" example:"错误信息"` + List []struct { + AdUnitId string `json:"ad_unit_id" example:"广告单元ID"` + AdUnitName string `json:"ad_unit_name" example:"广告单元名称"` + AppId string `json:"appid" example:"授权方 appid"` + StatItem struct { + AdSlot string `json:"ad_slot" example:"广告位类型名称"` + Date string `json:"date" example:"数据日期"` + ExposureCount int64 `json:"exposure_count" example:"曝光量"` + ReqSuccCount int64 `json:"req_succ_count" example:"拉取量"` + PublisherIncome int64 `json:"publisher_income" example:"小程序分账收入(分)"` + ClickCount int64 `json:"click_count" example:"点击量"` + Income float64 `json:"income"` + Ecpm float64 `json:"ecpm" example:"广告千次曝光收益(分)"` + ExposureRate float64 `json:"exposure_rate" example:"曝光率"` + ClickRate float64 `json:"click_rate" example:"点击量"` + } `json:"stat_item"` + } `json:"list"` + TotalNum int `json:"total_num" example:"请求返回总数"` +} diff --git a/app/lib/wechat/wechat_api.go b/app/lib/wechat/wechat_api.go index ff4fe89..6e79ebf 100644 --- a/app/lib/wechat/wechat_api.go +++ b/app/lib/wechat/wechat_api.go @@ -320,3 +320,35 @@ func (wxApiService *WxApiService) GetAdunitList(appId string, page, pageSize int } return } + +/* +GetAdposDetail 获取小程序广告细分数据 +*/ +func (wxApiService *WxApiService) GetAdposDetail(appId string, page, pageSize int, startDate, endDate, adUnitId string) (err error, resp md.GetAdposDetail) { // set方法 + apiAuthorizerToken, err := wxApiService.GetAuth(appId) + if err != nil { + return + } + url := "https://api.weixin.qq.com/wxa/operationams?action=agency_get_adunit_general&access_token=" + apiAuthorizerToken + params := map[string]interface{}{ + "page": page, + "page_size": pageSize, + "ad_unit_id": adUnitId, + "start_date": startDate, + "end_date": endDate, + } + fmt.Println(utils.SerializeStr(params)) + postBody, err := utils.CurlPost(url, utils.SerializeStr(params), nil) + if err != nil { + return + } + + err = json.Unmarshal(postBody, &resp) + if err != nil { + return + } + if resp.Ret != 0 { + err = errors.New(resp.ErrMsg) + } + return +} diff --git a/app/md/md_generate_wx_ad_data.go b/app/md/md_generate_wx_ad_data.go new file mode 100644 index 0000000..fc56bdd --- /dev/null +++ b/app/md/md_generate_wx_ad_data.go @@ -0,0 +1,15 @@ +package md + +type GenerateWxAdData struct { + GenerateDataId int `json:"generate_data_id" example:"原始数据id"` + OriginalExposureCount int `json:"original_exposure_count" example:"原-曝光量"` + OriginalEcpm string `json:"original_ecpm" example:"原-广告千次曝光收益(分)"` + NowExposureCount int `json:"now_exposure_count" example:"现-曝光量"` + NowEcpm string `json:"now_ecpm" example:"现-广告千次曝光收益(分)"` +} + +type ClacEcpmReq struct { + OriginalExposureCount int `json:"original_exposure_count" example:"原-曝光量"` + OriginalEcpm string `json:"original_ecpm" example:"原-广告千次曝光收益(分)"` + GenerateDataId int `json:"generate_data_id" example:"原始数据id"` +} diff --git a/app/router/router.go b/app/router/router.go index 1a14e8e..8ba0239 100644 --- a/app/router/router.go +++ b/app/router/router.go @@ -51,6 +51,7 @@ func Init() *gin.Engine { func route(r *gin.RouterGroup) { r.GET("/test", hdl.Demo) + r.GET("/authorize", hdl.AppletAuthorize) r.Use(mw.DB) // 以下接口需要用到数据库 { diff --git a/app/svc/svc_wx_data.go b/app/svc/svc_wx_data.go new file mode 100644 index 0000000..2dea3ad --- /dev/null +++ b/app/svc/svc_wx_data.go @@ -0,0 +1,197 @@ +package svc + +import ( + "applet/app/md" + "applet/app/utils" + db "code.fnuoos.com/zhimeng/model.git/src" + "code.fnuoos.com/zhimeng/model.git/src/super/implement" + "code.fnuoos.com/zhimeng/model.git/src/super/model" + "errors" + "time" +) + +func GenerateWxAdData(req md.GenerateWxAdData) (err error, generateWxAdData model.GenerateWxAdData) { + //1、查找原始数据记录 + originalWxAdDataDb := implement.NewOriginalWxAdDataDb(db.Db) + originalWxAdData, err := originalWxAdDataDb.GetOriginalWxAdData(req.GenerateDataId) + if err != nil { + return + } + if originalWxAdData == nil { + err = errors.New("未查询到原始数据记录") + return + } + + //2、查询对应媒体、代理的分成策略 + mediumDivisionStrategyDb := implement.NewMediumDivisionStrategyDb(db.Db) + mediumDivisionStrategy, err := mediumDivisionStrategyDb.GetOriginalWxAdDataByMediumId(originalWxAdData.MediumId) + if err != nil { + return + } + if mediumDivisionStrategy == nil { + err = errors.New("未查询到对应代理的分成策略") + return + } + mediumDivisionStrategyWithAgentFlowDb := implement.NewMediumDivisionStrategyWithAgentFlowDb(db.Db) + mediumDivisionStrategyWithAgentFlows, err := mediumDivisionStrategyWithAgentFlowDb.FindMediumDivisionStrategyWithAgentFlowByStrategyId(mediumDivisionStrategy.MediumId) + if err != nil { + return + } + + //3、计算媒体、代理收益、平台留存、佣金留存、协议分成、协议总分成 + publisherIncome := originalWxAdData.PublisherIncome + mediaRevenue := publisherIncome * mediumDivisionStrategy.MediaRevenueRate / 100 //媒体收益 + agentRevenue := publisherIncome * mediumDivisionStrategy.AgentRevenueRate / 100 //代理收益 + platformRetention := publisherIncome * mediumDivisionStrategy.PlatformRetentionRate / 100 //平台留存 + commissionRetention := publisherIncome * mediumDivisionStrategy.CommissionRetentionRate / 100 //佣金留存 + agreementSharingTotal := (mediaRevenue + agentRevenue) / (100 - mediumDivisionStrategy.AgreementSharingRate) //协议总分成(倒推) + agreementSharing := agreementSharingTotal - (mediaRevenue + agentRevenue) //协议分成 + + //3、判断是否有调价留存 + var priceAdjustmentRetention int + if req.NowEcpm != req.OriginalEcpm || req.NowExposureCount != req.OriginalExposureCount { + tmpMediaRevenue := int(utils.StrToFloat64(req.NowEcpm) * float64(req.NowExposureCount) / 1000) + priceAdjustmentRetention = tmpMediaRevenue - mediaRevenue + mediaRevenue = tmpMediaRevenue + } + + //4、计算各代理收益 + var extraRevenue int + var agentRevenueFlows []struct { + AgentId int `json:"agent_id"` + AgentRevenueRate int `json:"agent_revenue_rate"` + ExtraRevenueRate int `json:"extra_revenue_rate"` + AgentRevenue int `json:"agent_revenue"` + ExtraRevenue int `json:"extra_revenue"` + } + for _, v := range *mediumDivisionStrategyWithAgentFlows { + tmpAgentRevenue := agentRevenue * v.AgentRevenueRate / 100 + tmpExtraRevenue := commissionRetention * v.ExtraRevenueRate / 100 + extraRevenue += tmpExtraRevenue + agentRevenueFlows = append(agentRevenueFlows, struct { + AgentId int `json:"agent_id"` + AgentRevenueRate int `json:"agent_revenue_rate"` + ExtraRevenueRate int `json:"extra_revenue_rate"` + AgentRevenue int `json:"agent_revenue"` + ExtraRevenue int `json:"extra_revenue"` + }{ + AgentId: v.AgentId, + AgentRevenueRate: v.AgentRevenueRate, + ExtraRevenueRate: v.ExtraRevenueRate, + AgentRevenue: tmpAgentRevenue, + ExtraRevenue: tmpExtraRevenue, + }) + } + + //5、插入 generate_wx_ad_data 、generate_wx_ad_data_with_agent_flow 数据 + session := db.Db.NewSession() + defer session.Close() + session.Begin() + + now := time.Now() + generateWxAdData = model.GenerateWxAdData{ + Uuid: originalWxAdData.Uuid, + AppId: originalWxAdData.AppId, + GenerateDataId: originalWxAdData.Id, + SlotId: originalWxAdData.SlotId, + AdSlot: originalWxAdData.AdSlot, + Date: originalWxAdData.Date, + ReqSuccCount: originalWxAdData.ReqSuccCount, + ExposureCount: req.NowExposureCount, //现-曝光量 + ExposureRate: originalWxAdData.ExposureRate, + ClickCount: originalWxAdData.ClickCount, + ClickRate: originalWxAdData.ClickRate, + Ecpm: req.NowEcpm, //现-ecpm + PlatformRetention: platformRetention, + CommissionRetention: commissionRetention, + PriceAdjustmentRetention: priceAdjustmentRetention, + MediaRevenue: mediaRevenue, + AgentRevenue: agentRevenue, + ExtraRevenue: extraRevenue, + AgreementSharing: agreementSharing, + AgreementSharingTotal: agreementSharingTotal, + PlatformRetentionRate: mediumDivisionStrategy.PlatformRetentionRate, + CommissionRetentionRate: mediumDivisionStrategy.CommissionRetentionRate, + MediaRevenueRate: mediumDivisionStrategy.MediaRevenueRate, + AgentRevenueRate: mediumDivisionStrategy.AgentRevenueRate, + ExtraRevenueRate: mediumDivisionStrategy.ExtraRevenueRate, + AgreementSharingRate: mediumDivisionStrategy.AgreementSharingRate, + IsGenerateReport: 0, + CreateAt: now.Format("2006-01-02 15:04:05"), + UpdateAt: now.Format("2006-01-02 15:04:05"), + } + generateWxAdDataDb := implement.NewGenerateWxAdDataDb(db.Db) + _, err = generateWxAdDataDb.GenerateWxAdDataInsertBySession(session, &generateWxAdData) + if err != nil { + _ = session.Rollback() + return + } + + var generateWxAdDataWithAgentFlows []*model.GenerateWxAdDataWithAgentFlow + for _, v := range agentRevenueFlows { + generateWxAdDataWithAgentFlows = append(generateWxAdDataWithAgentFlows, &model.GenerateWxAdDataWithAgentFlow{ + Uuid: generateWxAdData.Uuid, + AppId: generateWxAdData.AppId, + AgentId: v.AgentId, + GenerateDataId: generateWxAdData.Id, + SlotId: generateWxAdData.SlotId, + AdSlot: generateWxAdData.AdSlot, + Date: generateWxAdData.Date, + AgentRevenue: v.AgentRevenue, + AgentRevenueRate: v.AgentRevenueRate, + ExtraRevenue: v.ExtraRevenue, + ExtraRevenueRate: v.ExtraRevenueRate, + CreateAt: now.Format("2006-01-02 15:04:05"), + UpdateAt: now.Format("2006-01-02 15:04:05"), + }) + } + generateWxAdDataWithAgentFlowDb := implement.NewGenerateWxAdDataWithAgentFlowDb(db.Db) + _, err = generateWxAdDataWithAgentFlowDb.BatchAddGenerateWxAdDataWithAgentFlow(session, generateWxAdDataWithAgentFlows) + if err != nil { + _ = session.Rollback() + return + } + + //6、修改 original_wx_ad_data 记录中的 is_apply(是否已应用(0:未 1:已) ) + originalWxAdData.IsApply = 1 + _, err = originalWxAdDataDb.UpdateOriginalWxAdDataBySession(session, originalWxAdData, "is_apply") + if err != nil { + _ = session.Rollback() + return + } + return session.Commit(), generateWxAdData +} + +func ClacEcpm(req md.ClacEcpmReq) (err error, ecpm string) { + //1、查找原始数据记录 + originalWxAdDataDb := implement.NewOriginalWxAdDataDb(db.Db) + originalWxAdData, err := originalWxAdDataDb.GetOriginalWxAdData(req.GenerateDataId) + if err != nil { + return + } + if originalWxAdData == nil { + err = errors.New("未查询到原始数据记录") + return + } + + //2、查询对应媒体分成策略 + mediumDivisionStrategyDb := implement.NewMediumDivisionStrategyDb(db.Db) + mediumDivisionStrategy, err := mediumDivisionStrategyDb.GetOriginalWxAdDataByMediumId(originalWxAdData.MediumId) + if err != nil { + return + } + if mediumDivisionStrategy == nil { + err = errors.New("未查询到对应代理的分成策略") + return + } + + //3、计算媒体、代理收益、协议总分成 + publisherIncome := originalWxAdData.PublisherIncome + mediaRevenue := publisherIncome * mediumDivisionStrategy.MediaRevenueRate / 100 //媒体收益 + agentRevenue := publisherIncome * mediumDivisionStrategy.AgentRevenueRate / 100 //代理收益 + agreementSharingTotal := (mediaRevenue + agentRevenue) / (100 - mediumDivisionStrategy.AgreementSharingRate) //协议总分成(倒推) + + //4、倒退出当前ecpm值 + ecpm = utils.Float64ToStrPrec4(float64(agreementSharingTotal) / (float64(originalWxAdData.ExposureCount) / 1000)) + return +} diff --git a/app/utils/convert.go b/app/utils/convert.go index a638d37..c398317 100644 --- a/app/utils/convert.go +++ b/app/utils/convert.go @@ -276,6 +276,9 @@ func Float64ToStr(f float64) string { func Float64ToStrPrec1(f float64) string { return strconv.FormatFloat(f, 'f', 1, 64) } +func Float64ToStrPrec4(f float64) string { + return strconv.FormatFloat(f, 'f', 1, 64) +} func Float32ToStr(f float32) string { return Float64ToStr(float64(f)) diff --git a/go.mod b/go.mod index d291ab6..34be2df 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 //replace code.fnuoos.com/zhimeng/model.git => E:/company/ad/models require ( - code.fnuoos.com/zhimeng/model.git v0.0.3-0.20240822030431-bf682f937fb0 + code.fnuoos.com/zhimeng/model.git v0.0.3-0.20240827055504-c124d0031bf7 github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 github.com/boombuler/barcode v1.0.1 github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5