275 lines
8.3 KiB
Go
275 lines
8.3 KiB
Go
package rechargereward
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
var personalMonthlyRechargeTypes = []string{
|
|
"UNDEFINED",
|
|
"HUAWEI",
|
|
"GOOGLE",
|
|
"APPLE",
|
|
"PAYER_MAX",
|
|
"SHIPPING_AGENT",
|
|
"STRIPE",
|
|
"SALARY_EXCHANGE",
|
|
"PAY_PAL",
|
|
"CLIPSPAY",
|
|
"SELLER_AGENT",
|
|
}
|
|
|
|
type rechargeRewardClaimRecordRow struct {
|
|
UserID int64 `gorm:"column:user_id"`
|
|
RechargeAmount string `gorm:"column:recharge_amount"`
|
|
LastRechargeTime string `gorm:"column:last_recharge_time"`
|
|
Account string `gorm:"column:account"`
|
|
UserAvatar string `gorm:"column:user_avatar"`
|
|
UserNickname string `gorm:"column:user_nickname"`
|
|
CountryCode string `gorm:"column:country_code"`
|
|
CountryName string `gorm:"column:country_name"`
|
|
}
|
|
|
|
// PageClaimRecords 分页返回当前配置下已达到充值奖励档位的用户。
|
|
func (s *Service) PageClaimRecords(ctx context.Context, sysOrigin string, month string, userID int64, cursor int, limit int) (*RechargeRewardClaimRecordPageResponse, error) {
|
|
sysOrigin = s.normalizeSysOrigin(sysOrigin)
|
|
cursor, limit = NormalizePage(cursor, limit)
|
|
|
|
bundle, err := s.loadConfigBundle(ctx, sysOrigin)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
location := s.location
|
|
if bundle.Config != nil {
|
|
location = resolveLocation(bundle.Config.Timezone, s.location)
|
|
}
|
|
rechargeDate, displayMonth, err := normalizeRechargeRewardRecordMonth(month, time.Now().In(location))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
levels := enabledRechargeRewardLevels(bundle.Levels)
|
|
if len(levels) == 0 {
|
|
return emptyRechargeRewardClaimRecordPage(displayMonth, rechargeDate, location.String(), cursor, limit), nil
|
|
}
|
|
minThresholdCents := levels[0].RechargeAmountCents
|
|
minThresholdAmount := float64(minThresholdCents) / 100
|
|
|
|
var total int64
|
|
countSQL := `
|
|
SELECT COUNT(1)
|
|
FROM (
|
|
SELECT recharge.user_id
|
|
FROM user_monthly_recharge_v2 AS recharge
|
|
INNER JOIN user_base_info AS user ON user.id = recharge.user_id
|
|
WHERE recharge.recharge_date = ?
|
|
AND recharge.type IN ?
|
|
AND user.origin_sys = ?
|
|
AND (? = 0 OR recharge.user_id = ?)
|
|
GROUP BY recharge.user_id
|
|
HAVING SUM(recharge.amount) >= ?
|
|
) AS qualified`
|
|
if err := s.db.WithContext(ctx).Raw(
|
|
countSQL,
|
|
rechargeDate,
|
|
personalMonthlyRechargeTypes,
|
|
sysOrigin,
|
|
userID,
|
|
userID,
|
|
minThresholdAmount,
|
|
).Scan(&total).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
records := make([]RechargeRewardClaimRecordView, 0)
|
|
if total > 0 {
|
|
var rows []rechargeRewardClaimRecordRow
|
|
listSQL := `
|
|
SELECT
|
|
recharge.user_id,
|
|
SUM(recharge.amount) AS recharge_amount,
|
|
MAX(recharge.update_time) AS last_recharge_time,
|
|
user.account,
|
|
user.user_avatar,
|
|
user.user_nickname,
|
|
user.country_code,
|
|
user.country_name
|
|
FROM user_monthly_recharge_v2 AS recharge
|
|
INNER JOIN user_base_info AS user ON user.id = recharge.user_id
|
|
WHERE recharge.recharge_date = ?
|
|
AND recharge.type IN ?
|
|
AND user.origin_sys = ?
|
|
AND (? = 0 OR recharge.user_id = ?)
|
|
GROUP BY recharge.user_id, user.account, user.user_avatar, user.user_nickname, user.country_code, user.country_name
|
|
HAVING SUM(recharge.amount) >= ?
|
|
ORDER BY SUM(recharge.amount) DESC, recharge.user_id ASC
|
|
LIMIT ? OFFSET ?`
|
|
if err := s.db.WithContext(ctx).Raw(
|
|
listSQL,
|
|
rechargeDate,
|
|
personalMonthlyRechargeTypes,
|
|
sysOrigin,
|
|
userID,
|
|
userID,
|
|
minThresholdAmount,
|
|
limit,
|
|
(cursor-1)*limit,
|
|
).Scan(&rows).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
rewardItems := s.loadRewardItemsMap(ctx, levels)
|
|
records = make([]RechargeRewardClaimRecordView, 0, len(rows))
|
|
for _, row := range rows {
|
|
records = append(records, rechargeRewardClaimRecordView(row, displayMonth, rechargeDate, levels, rewardItems))
|
|
}
|
|
}
|
|
|
|
return &RechargeRewardClaimRecordPageResponse{
|
|
Month: displayMonth,
|
|
RechargeDate: rechargeDate,
|
|
Timezone: location.String(),
|
|
Records: records,
|
|
Total: total,
|
|
Current: cursor,
|
|
Size: limit,
|
|
}, nil
|
|
}
|
|
|
|
func emptyRechargeRewardClaimRecordPage(month string, rechargeDate int, timezone string, cursor int, limit int) *RechargeRewardClaimRecordPageResponse {
|
|
return &RechargeRewardClaimRecordPageResponse{
|
|
Month: month,
|
|
RechargeDate: rechargeDate,
|
|
Timezone: timezone,
|
|
Records: []RechargeRewardClaimRecordView{},
|
|
Total: 0,
|
|
Current: cursor,
|
|
Size: limit,
|
|
}
|
|
}
|
|
|
|
func normalizeRechargeRewardRecordMonth(raw string, now time.Time) (int, string, error) {
|
|
value := strings.TrimSpace(raw)
|
|
if value == "" {
|
|
value = now.Format("2006-01")
|
|
}
|
|
if len(value) == 6 && !strings.Contains(value, "-") {
|
|
value = value[:4] + "-" + value[4:]
|
|
}
|
|
parsed, err := time.Parse("2006-01", value)
|
|
if err != nil {
|
|
return 0, "", NewAppError(http.StatusBadRequest, "invalid_month", "month must be YYYY-MM")
|
|
}
|
|
rechargeDate := parsed.Year()*100 + int(parsed.Month())
|
|
return rechargeDate, parsed.Format("2006-01"), nil
|
|
}
|
|
|
|
func enabledRechargeRewardLevels(levels []rechargeRewardLevelSnapshot) []rechargeRewardLevelSnapshot {
|
|
result := make([]rechargeRewardLevelSnapshot, 0, len(levels))
|
|
for _, level := range levels {
|
|
if !level.Enabled || level.RechargeAmountCents <= 0 {
|
|
continue
|
|
}
|
|
result = append(result, level)
|
|
}
|
|
sortLevels(result)
|
|
return result
|
|
}
|
|
|
|
func rechargeRewardClaimRecordView(
|
|
row rechargeRewardClaimRecordRow,
|
|
month string,
|
|
rechargeDate int,
|
|
levels []rechargeRewardLevelSnapshot,
|
|
rewardItems map[int64][]RechargeRewardRewardItem,
|
|
) RechargeRewardClaimRecordView {
|
|
rechargeCents := parseIntegrationAmountCents(integrationAmount(row.RechargeAmount))
|
|
reached := reachedRechargeRewardLevels(levels, rewardItems, rechargeCents)
|
|
return RechargeRewardClaimRecordView{
|
|
RecordKey: fmt.Sprintf("%d-%d", row.UserID, rechargeDate),
|
|
UserID: row.UserID,
|
|
Account: strings.TrimSpace(row.Account),
|
|
UserAvatar: strings.TrimSpace(row.UserAvatar),
|
|
UserNickname: strings.TrimSpace(row.UserNickname),
|
|
CountryCode: strings.TrimSpace(row.CountryCode),
|
|
CountryName: strings.TrimSpace(row.CountryName),
|
|
RechargeMonth: month,
|
|
RechargeDate: rechargeDate,
|
|
RechargeAmount: formatAmountCents(rechargeCents),
|
|
RechargeAmountCents: rechargeCents,
|
|
ReachedLevels: reached,
|
|
ClaimedRewards: rechargeRewardClaimedRewards(reached),
|
|
LastRechargeTime: formatRechargeRewardRecordTime(row.LastRechargeTime),
|
|
}
|
|
}
|
|
|
|
func reachedRechargeRewardLevels(
|
|
levels []rechargeRewardLevelSnapshot,
|
|
rewardItems map[int64][]RechargeRewardRewardItem,
|
|
rechargeCents int64,
|
|
) []RechargeRewardLevelPayload {
|
|
result := make([]RechargeRewardLevelPayload, 0)
|
|
for _, level := range levels {
|
|
if rechargeCents < level.RechargeAmountCents {
|
|
continue
|
|
}
|
|
var items []RechargeRewardRewardItem
|
|
if level.RewardGroupID != nil {
|
|
items = rewardItems[*level.RewardGroupID]
|
|
}
|
|
result = append(result, RechargeRewardLevelPayload{
|
|
ID: level.ID,
|
|
Level: level.Level,
|
|
RechargeAmount: formatAmountCents(level.RechargeAmountCents),
|
|
RechargeAmountCents: level.RechargeAmountCents,
|
|
RewardGold: level.RewardGold,
|
|
RewardGroupID: level.RewardGroupID,
|
|
RewardGroupName: level.RewardGroupName,
|
|
RewardItems: items,
|
|
Enabled: level.Enabled,
|
|
Reached: true,
|
|
})
|
|
}
|
|
return result
|
|
}
|
|
|
|
func rechargeRewardClaimedRewards(levels []RechargeRewardLevelPayload) []RechargeRewardClaimedRewardPayload {
|
|
result := make([]RechargeRewardClaimedRewardPayload, 0, len(levels))
|
|
for _, level := range levels {
|
|
result = append(result, RechargeRewardClaimedRewardPayload{
|
|
Level: level.Level,
|
|
RechargeAmount: level.RechargeAmount,
|
|
RechargeAmountCents: level.RechargeAmountCents,
|
|
RewardGold: level.RewardGold,
|
|
RewardGroupID: level.RewardGroupID,
|
|
RewardGroupName: level.RewardGroupName,
|
|
RewardItems: level.RewardItems,
|
|
})
|
|
}
|
|
return result
|
|
}
|
|
|
|
func formatRechargeRewardRecordTime(raw string) string {
|
|
value := strings.TrimSpace(raw)
|
|
if value == "" {
|
|
return ""
|
|
}
|
|
for _, layout := range []string{
|
|
"2006-01-02 15:04:05.999999999-07:00",
|
|
"2006-01-02 15:04:05.999999999",
|
|
"2006-01-02 15:04:05",
|
|
time.RFC3339Nano,
|
|
time.RFC3339,
|
|
} {
|
|
if parsed, err := time.Parse(layout, value); err == nil {
|
|
return formatDateTime(parsed)
|
|
}
|
|
}
|
|
if len(value) > len("2006-01-02 15:04:05") {
|
|
return value[:len("2006-01-02 15:04:05")]
|
|
}
|
|
return value
|
|
}
|