124 lines
3.4 KiB
Go
124 lines
3.4 KiB
Go
package smashegg
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"math/big"
|
|
"strings"
|
|
"time"
|
|
|
|
"chatapp3-golang/internal/integration"
|
|
"chatapp3-golang/internal/model"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type newbieEligibility struct {
|
|
Eligible bool
|
|
Remaining int
|
|
}
|
|
|
|
func (item newbieEligibility) remainingAfterUse(poolType string) int {
|
|
if normalizePoolType(poolType) != poolTypeNewbie {
|
|
return item.Remaining
|
|
}
|
|
if item.Remaining <= 0 {
|
|
return 0
|
|
}
|
|
return item.Remaining - 1
|
|
}
|
|
|
|
func (s *Service) resolveRewardPool(ctx context.Context, bundle *configBundle, user AuthUser) (string, []model.SmashEggRewardConfig, newbieEligibility, error) {
|
|
eligibility := newbieEligibility{}
|
|
if bundle == nil || bundle.Config == nil {
|
|
return poolTypeGeneral, nil, eligibility, nil
|
|
}
|
|
generalRewards := rewardsForPool(bundle.Rewards, poolTypeGeneral)
|
|
if !bundle.Config.NewbiePoolEnabled || user.UserID <= 0 {
|
|
return poolTypeGeneral, generalRewards, eligibility, nil
|
|
}
|
|
newbieRewards := rewardsForPool(bundle.Rewards, poolTypeNewbie)
|
|
if len(newbieRewards) == 0 {
|
|
return poolTypeGeneral, generalRewards, eligibility, nil
|
|
}
|
|
resolved, err := s.resolveNewbieEligibility(ctx, bundle.Config, user)
|
|
if err != nil {
|
|
return "", nil, eligibility, err
|
|
}
|
|
if !resolved.Eligible {
|
|
return poolTypeGeneral, generalRewards, resolved, nil
|
|
}
|
|
return poolTypeNewbie, newbieRewards, resolved, nil
|
|
}
|
|
|
|
func (s *Service) resolveNewbieEligibility(ctx context.Context, configRow *model.SmashEggConfig, user AuthUser) (newbieEligibility, error) {
|
|
result := newbieEligibility{}
|
|
if configRow == nil || !configRow.NewbiePoolEnabled || user.UserID <= 0 {
|
|
return result, nil
|
|
}
|
|
|
|
windowDays := effectiveNewbieWindowDays(configRow.NewbieWindowDays)
|
|
maxDrawCount := effectiveNewbieMaxDrawCount(configRow.NewbieMaxDrawCount, true)
|
|
if maxDrawCount <= 0 {
|
|
return result, nil
|
|
}
|
|
|
|
var userInfo model.UserBaseInfo
|
|
err := s.db.WithContext(ctx).Where("id = ?", user.UserID).First(&userInfo).Error
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return result, nil
|
|
}
|
|
if err != nil {
|
|
return result, err
|
|
}
|
|
if userInfo.CreateTime.IsZero() {
|
|
return result, nil
|
|
}
|
|
if time.Since(userInfo.CreateTime) > time.Duration(windowDays)*24*time.Hour {
|
|
return result, nil
|
|
}
|
|
|
|
var used int64
|
|
if err := s.db.WithContext(ctx).Model(&model.SmashEggDrawRecord{}).
|
|
Where("sys_origin = ? AND user_id = ? AND pool_type = ? AND status IN ?", normalizeSysOrigin(user.SysOrigin), user.UserID, poolTypeNewbie, []string{drawStatusPending, drawStatusSuccess}).
|
|
Distinct("draw_no").
|
|
Count(&used).Error; err != nil {
|
|
return result, err
|
|
}
|
|
remaining := maxDrawCount - int(used)
|
|
if remaining <= 0 {
|
|
return result, nil
|
|
}
|
|
|
|
if configRow.NewbieMinRechargeAmount > 0 {
|
|
if s.java == nil {
|
|
return result, nil
|
|
}
|
|
rechargeMap, err := s.java.MapUserTotalRecharge(ctx, []int64{user.UserID})
|
|
if err != nil {
|
|
return result, nil
|
|
}
|
|
if !totalRechargeAtLeast(rechargeMap[user.UserID], configRow.NewbieMinRechargeAmount) {
|
|
return result, nil
|
|
}
|
|
}
|
|
|
|
result.Eligible = true
|
|
result.Remaining = remaining
|
|
return result, nil
|
|
}
|
|
|
|
func totalRechargeAtLeast(items []integration.UserTotalRecharge, threshold int64) bool {
|
|
if threshold <= 0 {
|
|
return true
|
|
}
|
|
total := new(big.Rat)
|
|
for _, item := range items {
|
|
if strings.EqualFold(strings.TrimSpace(item.Type), "REFUND") {
|
|
continue
|
|
}
|
|
total.Add(total, parseDecimalRat(item.Amount))
|
|
}
|
|
return total.Cmp(new(big.Rat).SetInt64(threshold)) >= 0
|
|
}
|