package business import ( "context" "errors" "strings" "time" "gorm.io/gorm" "kra/internal/biz/business" ) // OA 表只读,不由新商务的系统迁移创建或改写。 type activationPO struct { ID uint64 `gorm:"primaryKey"` PromoteID *uint64 PlatformName, PromoteAccount, BusierAccount, ApplicantOA, Status string AccumAmount *string BindAt, UnbindAt, ReachAt, DeletedAt *time.Time } func (activationPO) TableName() string { return "sys_promote_active_pool_bind" } func toBizActivation(po activationPO) *business.Activation { amount := "0.00" if po.AccumAmount != nil { amount = *po.AccumAmount } return &business.Activation{ID: po.ID, PromoteID: po.PromoteID, PlatformName: po.PlatformName, PromoteAccount: po.PromoteAccount, BusierAccount: po.BusierAccount, ApplicantOA: po.ApplicantOA, Status: po.Status, AccumAmount: amount, BindAt: po.BindAt, UnbindAt: po.UnbindAt, ReachAt: po.ReachAt} } type activationRepo struct { data Provider databases PlatformProvider } func NewActivationRepo(data Provider, databases PlatformProvider) business.ActivationRepo { return &activationRepo{data: data, databases: databases} } func (r *activationRepo) OwnAccounts(ctx context.Context, id uint) ([]business.ActivationAccount, error) { var rows []struct{ SourceDB, Account string } err := r.data.DB().WithContext(ctx).Table("sys_user_bind_platform").Where("user_id = ? AND status = ? AND platform_busier_account IS NOT NULL", id, "0").Distinct("source_db,platform_busier_account AS account").Scan(&rows).Error accounts := make([]business.ActivationAccount, 0, len(rows)) for _, row := range rows { accounts = append(accounts, business.ActivationAccount{SourceDB: row.SourceDB, Account: row.Account}) } return accounts, storageError(err) } func (r *activationRepo) oa(ctx context.Context) (*gorm.DB, error) { db, err := r.databases.Database("oa") if err != nil || db == nil { return nil, business.ErrActivationSource } db = db.WithContext(ctx) available, err := businessTableAvailable(db, "sys_promote_active_pool_bind") if err != nil || !available { return nil, business.ErrActivationSource } return db, nil } func (r *activationRepo) List(ctx context.Context, scope business.ActivationScope, filter business.ActivationFilter, options ...business.ListOption) (*business.ActivationPage, error) { page := &business.ActivationPage{Rows: []*business.Activation{}, Available: true} if !scope.All && len(scope.Accounts) == 0 { return page, nil } db, err := r.oa(ctx) if err != nil { page.Available = false return page, nil } q := db.Model(&activationPO{}).Where("deleted_at IS NULL") if !scope.All { accounts := make([][]any, 0, len(scope.Accounts)) for _, account := range scope.Accounts { accounts = append(accounts, []any{strings.ToLower(account.SourceDB), strings.ToLower(account.Account)}) } q = q.Where("(LOWER(platform_name),LOWER(busier_account)) IN ?", accounts) } if len(filter.PlatformNames) > 0 { q = q.Where("platform_name IN ?", filter.PlatformNames) } if len(filter.Statuses) > 0 { q = q.Where("status IN ?", filter.Statuses) } if filter.PromoteAccount != "" { q = q.Where("promote_account LIKE ?", "%"+filter.PromoteAccount+"%") } if filter.BusierAccount != "" { q = q.Where("busier_account LIKE ?", "%"+filter.BusierAccount+"%") } if err := q.Count(&page.Total).Error; err != nil { return nil, business.ErrActivationSource } o := business.NewListOptions(options...) var pos []activationPO if err := q.Order("id DESC").Offset(o.Offset).Limit(o.Limit).Find(&pos).Error; err != nil { return nil, business.ErrActivationSource } for _, po := range pos { page.Rows = append(page.Rows, toBizActivation(po)) } return page, nil } func (r *activationRepo) Find(ctx context.Context, id uint64) (*business.Activation, error) { db, err := r.oa(ctx) if err != nil { return nil, err } var po activationPO if err := db.Where("id = ? AND deleted_at IS NULL", id).Take(&po).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, business.ErrActivationNotFound } return nil, business.ErrActivationSource } return toBizActivation(po), nil } func (r *activationRepo) Spend(ctx context.Context, query business.ActivationSpendQuery) ([]*business.ActivationSpendItem, error) { db := r.data.DB().WithContext(ctx) available, err := businessTableAvailable(db, "tab_promote") if err != nil { return nil, err } if !available { return nil, business.ErrActivationMetrics } tree := func() *gorm.DB { return db.Table("tab_promote p").Where("p.source_db = ? AND (p.id = ? OR p.top_promote_id = ? OR p.parent_id = ?)", query.PlatformName, query.PromoteID, query.PromoteID, query.PromoteID) } var count int64 if err := tree().Count(&count).Error; err != nil { return nil, business.ErrStorage } items := []*business.ActivationSpendItem{} if count == 0 { return items, nil } available, err = businessTableAvailable(db, "tab_spend") if err != nil { return nil, err } if !available { return nil, business.ErrActivationMetrics } q := db.Table("tab_spend s").Where("s.source_db = ? AND s.pay_status = ? AND s.pay_time >= ?", query.PlatformName, 1, query.Start).Where("EXISTS (?)", tree().Select("1").Where("p.id=s.promote_id")) if query.End != nil { q = q.Where("s.pay_time <= ?", *query.End) } var rows []struct { GameID uint64 GameName, Amount string } if err := q.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("amount DESC,s.game_id").Scan(&rows).Error; err != nil { return nil, business.ErrStorage } for _, row := range rows { items = append(items, &business.ActivationSpendItem{GameName: row.GameName, Amount: row.Amount}) } return items, nil }