@@ -0,0 +1,5 @@ | |||||
package dao | |||||
type OriginalWxAdDataDao interface { | |||||
//TODO:: You can add specific method definitions here | |||||
} |
@@ -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 | |||||
} |
@@ -2,24 +2,50 @@ package hdl | |||||
import ( | import ( | ||||
"applet/app/e" | "applet/app/e" | ||||
"applet/app/lib/wechat" | |||||
"applet/app/svc" | "applet/app/svc" | ||||
"applet/app/utils" | "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" | "github.com/gin-gonic/gin" | ||||
) | ) | ||||
func Demo(c *gin.Context) { | 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 { | 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 | return | ||||
} | } | ||||
e.OutSuc(c, map[string]interface{}{ | e.OutSuc(c, map[string]interface{}{ | ||||
"args": args, | "args": args, | ||||
}, nil) | }, nil) | ||||
@@ -417,7 +417,6 @@ func AppletUnauthorized(c *gin.Context) { | |||||
e.OutErr(c, e.ERR_NOT_FAN, "未查询到对应三方应用记录") | e.OutErr(c, e.ERR_NOT_FAN, "未查询到对应三方应用记录") | ||||
return | return | ||||
} | } | ||||
wxApiService, err := wechat.NewWxApiService(masterId, wxOpenThirdPartyAppList.Appid, wxOpenThirdPartyAppList.AppSecret) | wxApiService, err := wechat.NewWxApiService(masterId, wxOpenThirdPartyAppList.Appid, wxOpenThirdPartyAppList.AppSecret) | ||||
if err != nil { | if err != nil { | ||||
e.OutErr(c, e.ERR, err.Error()) | e.OutErr(c, e.ERR, err.Error()) | ||||
@@ -60,3 +60,26 @@ type GetAdunitList struct { | |||||
} `json:"ad_unit"` | } `json:"ad_unit"` | ||||
TotalNum int `json:"total_num" example:"总广告单元数据量"` | 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:"请求返回总数"` | |||||
} |
@@ -320,3 +320,35 @@ func (wxApiService *WxApiService) GetAdunitList(appId string, page, pageSize int | |||||
} | } | ||||
return | 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 | |||||
} |
@@ -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"` | |||||
} |
@@ -51,6 +51,7 @@ func Init() *gin.Engine { | |||||
func route(r *gin.RouterGroup) { | func route(r *gin.RouterGroup) { | ||||
r.GET("/test", hdl.Demo) | r.GET("/test", hdl.Demo) | ||||
r.GET("/authorize", hdl.AppletAuthorize) | |||||
r.Use(mw.DB) // 以下接口需要用到数据库 | r.Use(mw.DB) // 以下接口需要用到数据库 | ||||
{ | { | ||||
@@ -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 | |||||
} |
@@ -276,6 +276,9 @@ func Float64ToStr(f float64) string { | |||||
func Float64ToStrPrec1(f float64) string { | func Float64ToStrPrec1(f float64) string { | ||||
return strconv.FormatFloat(f, 'f', 1, 64) | return strconv.FormatFloat(f, 'f', 1, 64) | ||||
} | } | ||||
func Float64ToStrPrec4(f float64) string { | |||||
return strconv.FormatFloat(f, 'f', 1, 64) | |||||
} | |||||
func Float32ToStr(f float32) string { | func Float32ToStr(f float32) string { | ||||
return Float64ToStr(float64(f)) | return Float64ToStr(float64(f)) | ||||
@@ -5,7 +5,7 @@ go 1.18 | |||||
//replace code.fnuoos.com/zhimeng/model.git => E:/company/ad/models | //replace code.fnuoos.com/zhimeng/model.git => E:/company/ad/models | ||||
require ( | 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/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 | ||||
github.com/boombuler/barcode v1.0.1 | github.com/boombuler/barcode v1.0.1 | ||||
github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5 | github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5 | ||||