193 lines
5.8 KiB
Go
193 lines
5.8 KiB
Go
package business
|
|
|
|
import (
|
|
"context"
|
|
"gorm.io/gorm"
|
|
"kra/internal/biz/business"
|
|
"math/big"
|
|
"sort"
|
|
"time"
|
|
)
|
|
|
|
func (r *activationRepo) applyTransferEnd(ctx context.Context, row *business.Activation) error {
|
|
if row.BindAt == nil || row.PromoteID == nil || (row.Status != "reached" && row.ReachAt == nil) {
|
|
return nil
|
|
}
|
|
db, err := r.databases.Database(row.PlatformName)
|
|
if err != nil || db == nil {
|
|
return nil
|
|
}
|
|
db = db.WithContext(ctx)
|
|
ok, err := businessTableAvailable(db, "tab_promote_business_event")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !ok {
|
|
return nil
|
|
}
|
|
begin := *row.BindAt
|
|
if row.ReachAt != nil && row.ReachAt.After(begin) {
|
|
begin = *row.ReachAt
|
|
}
|
|
q := db.Table("tab_promote_business_event").Where("kind='transfer' AND promote_id=? AND occurred_at>=?", *row.PromoteID, begin)
|
|
if row.BusierID > 0 {
|
|
q = q.Where("old_busier_id=?", row.BusierID)
|
|
} else {
|
|
q = q.Where("LOWER(old_busier_account)=LOWER(?)", row.BusierAccount)
|
|
}
|
|
var rows []struct{ OccurredAt time.Time }
|
|
if err := q.Select("occurred_at").Order("occurred_at,id").Limit(1).Find(&rows).Error; err != nil {
|
|
return business.ErrActivationSource
|
|
}
|
|
if len(rows) > 0 {
|
|
row.EndOnTransfer(rows[0].OccurredAt)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func activationMetricQuery(row *business.Activation) business.ActivationSpendQuery {
|
|
q := business.ActivationSpendQuery{PlatformName: row.PlatformName, Channels: row.Channels, Start: row.BindAt.Unix()}
|
|
if row.PromoteID != nil {
|
|
q.PromoteID = *row.PromoteID
|
|
}
|
|
if end := row.EndAt(); end != nil {
|
|
n := end.Unix()
|
|
q.End = &n
|
|
}
|
|
return q
|
|
}
|
|
func sumActivationMoney(values []string) (string, error) {
|
|
total := new(big.Rat)
|
|
for _, v := range values {
|
|
n, ok := new(big.Rat).SetString(v)
|
|
if !ok {
|
|
return "", business.ErrStorage
|
|
}
|
|
total.Add(total, n)
|
|
}
|
|
return total.FloatString(2), nil
|
|
}
|
|
|
|
// 激活数据与 OA 使用同一 SDK 数据源,避免商务报表副本延迟/测试副本不同导致金额不一致。
|
|
func activationRoots(q business.ActivationSpendQuery) map[string][]uint64 {
|
|
roots := map[string][]uint64{}
|
|
keys := q.Channels
|
|
if len(keys) == 0 {
|
|
keys = []business.ChannelKey{{SourceDB: q.PlatformName, ID: q.PromoteID}}
|
|
}
|
|
for _, key := range keys {
|
|
if key.ID > 0 {
|
|
roots[key.SourceDB] = append(roots[key.SourceDB], key.ID)
|
|
}
|
|
}
|
|
return roots
|
|
}
|
|
func (r *activationRepo) activationMetricsAvailable(ctx context.Context, q business.ActivationSpendQuery) (bool, error) {
|
|
for source := range activationRoots(q) {
|
|
db, err := r.databases.Database(source)
|
|
if err != nil || db == nil {
|
|
return false, nil
|
|
}
|
|
ok, err := businessTablesAvailable(db.WithContext(ctx), "tab_promote", "tab_spend")
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if !ok {
|
|
return false, nil
|
|
}
|
|
}
|
|
return true, nil
|
|
}
|
|
func nativeActivationTree(db *gorm.DB, roots []uint64) *gorm.DB {
|
|
return db.Table("tab_promote p").Where("p.id IN ? OR p.top_promote_id IN ? OR p.parent_id IN ?", roots, roots, roots)
|
|
}
|
|
func (r *activationRepo) Spend(ctx context.Context, q business.ActivationSpendQuery) ([]*business.ActivationSpendItem, error) {
|
|
out := []*business.ActivationSpendItem{}
|
|
for source, roots := range activationRoots(q) {
|
|
db, err := r.databases.Database(source)
|
|
if err != nil || db == nil {
|
|
return nil, business.ErrActivationMetrics
|
|
}
|
|
db = db.WithContext(ctx)
|
|
tree := nativeActivationTree(db, roots)
|
|
var n int64
|
|
if err := tree.Count(&n).Error; err != nil {
|
|
return nil, business.ErrActivationMetrics
|
|
}
|
|
if n == 0 {
|
|
continue
|
|
}
|
|
query := db.Table("tab_spend s").Where("s.pay_status=1 AND s.pay_time>=?", q.Start).Where("EXISTS (?)", tree.Select("1").Where("p.id=s.promote_id"))
|
|
if q.End != nil {
|
|
query = query.Where("s.pay_time<=?", *q.End)
|
|
}
|
|
var rows []struct {
|
|
GameID uint64
|
|
GameName, Amount string
|
|
}
|
|
if err := query.Select("s.game_id,COALESCE(MAX(s.game_name),'') AS game_name,COALESCE(SUM(s.pay_amount),0) AS amount").Group("s.game_id").Order("s.game_id").Scan(&rows).Error; err != nil {
|
|
return nil, business.ErrActivationMetrics
|
|
}
|
|
for _, row := range rows {
|
|
out = append(out, &business.ActivationSpendItem{PlatformName: source, GameName: row.GameName, Amount: row.Amount})
|
|
}
|
|
}
|
|
sort.SliceStable(out, func(i, j int) bool {
|
|
a, okA := new(big.Rat).SetString(out[i].Amount)
|
|
b, okB := new(big.Rat).SetString(out[j].Amount)
|
|
if okA && okB && a.Cmp(b) != 0 {
|
|
return a.Cmp(b) > 0
|
|
}
|
|
if out[i].PlatformName != out[j].PlatformName {
|
|
return out[i].PlatformName < out[j].PlatformName
|
|
}
|
|
return out[i].GameName < out[j].GameName
|
|
})
|
|
return out, nil
|
|
}
|
|
func (r *activationRepo) registered(ctx context.Context, q business.ActivationSpendQuery, dedup bool) (*int64, error) {
|
|
total := int64(0)
|
|
identities := map[string]bool{}
|
|
for source, roots := range activationRoots(q) {
|
|
db, err := r.databases.Database(source)
|
|
if err != nil || db == nil {
|
|
return nil, nil
|
|
}
|
|
db = db.WithContext(ctx)
|
|
ok, err := businessTablesAvailable(db, "tab_user", "tab_promote")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !ok {
|
|
return nil, nil
|
|
}
|
|
cast := "CAST(r.register_time AS INTEGER)"
|
|
if db.Dialector.Name() == "mysql" {
|
|
cast = "CAST(r.register_time AS UNSIGNED)"
|
|
}
|
|
query := db.Table("tab_user r").Where("r.puid=0 AND "+cast+">=?", q.Start).Where("EXISTS (?)", nativeActivationTree(db, roots).Select("1").Where("p.id=r.promote_id"))
|
|
if q.End != nil {
|
|
query = query.Where(cast+"<=?", *q.End)
|
|
}
|
|
if dedup {
|
|
var cards []string
|
|
if err := query.Where("TRIM(COALESCE(r.idcard,''))<>''").Distinct("TRIM(r.idcard)").Pluck("TRIM(r.idcard)", &cards).Error; err != nil {
|
|
return nil, business.ErrActivationMetrics
|
|
}
|
|
for _, card := range cards {
|
|
identities[card] = true
|
|
}
|
|
} else {
|
|
var count int64
|
|
if err := query.Distinct("r.id").Count(&count).Error; err != nil {
|
|
return nil, business.ErrActivationMetrics
|
|
}
|
|
total += count
|
|
}
|
|
}
|
|
if dedup {
|
|
total = int64(len(identities))
|
|
}
|
|
return &total, nil
|
|
}
|