diff --git a/services/activity-service/internal/storage/mysql/lucky_gift_repository.go b/services/activity-service/internal/storage/mysql/lucky_gift_repository.go index 1c37c011..12962498 100644 --- a/services/activity-service/internal/storage/mysql/lucky_gift_repository.go +++ b/services/activity-service/internal/storage/mysql/lucky_gift_repository.go @@ -663,6 +663,9 @@ type luckyDrawPoolStatDelta struct { BaseRewardCoins int64 RoomAtmosphereRewardCoins int64 ActivitySubsidyCoins int64 + PendingDraws int64 + GrantedDraws int64 + FailedDraws int64 UserIDs map[int64]struct{} RoomIDs map[string]struct{} } @@ -713,14 +716,17 @@ func (r *Repository) upsertLuckyDrawPoolStatsSnapshotDelta(ctx context.Context, unique_users = unique_users + VALUES(unique_users), unique_rooms = unique_rooms + VALUES(unique_rooms), total_spent_coins = total_spent_coins + VALUES(total_spent_coins), - total_reward_coins = total_reward_coins + VALUES(total_reward_coins), - base_reward_coins = base_reward_coins + VALUES(base_reward_coins), - room_atmosphere_reward_coins = room_atmosphere_reward_coins + VALUES(room_atmosphere_reward_coins), - activity_subsidy_coins = activity_subsidy_coins + VALUES(activity_subsidy_coins), - updated_at_ms = VALUES(updated_at_ms)`, + total_reward_coins = total_reward_coins + VALUES(total_reward_coins), + base_reward_coins = base_reward_coins + VALUES(base_reward_coins), + room_atmosphere_reward_coins = room_atmosphere_reward_coins + VALUES(room_atmosphere_reward_coins), + activity_subsidy_coins = activity_subsidy_coins + VALUES(activity_subsidy_coins), + pending_draws = pending_draws + VALUES(pending_draws), + granted_draws = granted_draws + VALUES(granted_draws), + failed_draws = failed_draws + VALUES(failed_draws), + updated_at_ms = VALUES(updated_at_ms)`, key.AppCode, key.PoolID, key.GiftID, delta.TotalDraws, uniqueUsers, uniqueRooms, delta.TotalSpentCoins, delta.TotalRewardCoins, delta.BaseRewardCoins, delta.RoomAtmosphereRewardCoins, delta.ActivitySubsidyCoins, - int64(0), int64(0), int64(0), nowMS, nowMS, + delta.PendingDraws, delta.GrantedDraws, delta.FailedDraws, nowMS, nowMS, ) return err } @@ -742,6 +748,7 @@ type luckyDrawStatsRecord struct { BaseRewardCoins int64 RoomAtmosphereRewardCoins int64 ActivitySubsidyCoins int64 + RewardStatus string CreatedAtMS int64 } @@ -775,7 +782,8 @@ func (r *Repository) RefreshLuckyGiftAdminStatsSnapshots(ctx context.Context, no rows, err := tx.QueryContext(ctx, ` SELECT app_code, draw_id, pool_id, gift_id, user_id, room_id, coin_spent, - total_reward_coins, base_reward_coins, room_atmosphere_reward_coins, activity_subsidy_coins, + effective_reward_coins, base_reward_coins, room_atmosphere_reward_coins, activity_subsidy_coins, + reward_status, created_at_ms FROM lucky_draw_records FORCE INDEX (idx_lucky_draw_created) WHERE app_code = ? @@ -791,7 +799,7 @@ func (r *Repository) RefreshLuckyGiftAdminStatsSnapshots(ctx context.Context, no var record luckyDrawStatsRecord if err := rows.Scan(&record.AppCode, &record.DrawID, &record.PoolID, &record.GiftID, &record.UserID, &record.RoomID, &record.TotalSpentCoins, &record.TotalRewardCoins, &record.BaseRewardCoins, - &record.RoomAtmosphereRewardCoins, &record.ActivitySubsidyCoins, &record.CreatedAtMS); err != nil { + &record.RoomAtmosphereRewardCoins, &record.ActivitySubsidyCoins, &record.RewardStatus, &record.CreatedAtMS); err != nil { return 0, err } records = append(records, record) @@ -824,6 +832,14 @@ func (r *Repository) RefreshLuckyGiftAdminStatsSnapshots(ctx context.Context, no delta.BaseRewardCoins += record.BaseRewardCoins delta.RoomAtmosphereRewardCoins += record.RoomAtmosphereRewardCoins delta.ActivitySubsidyCoins += record.ActivitySubsidyCoins + switch record.RewardStatus { + case domain.StatusPending: + delta.PendingDraws++ + case domain.StatusGranted: + delta.GrantedDraws++ + case domain.StatusFailed: + delta.FailedDraws++ + } if record.UserID > 0 { delta.UserIDs[record.UserID] = struct{}{} } @@ -1818,7 +1834,8 @@ func (r *Repository) getLuckyGiftDrawSummaryFromStats(ctx context.Context, query summary.PoolID = query.PoolID err := r.db.QueryRowContext(ctx, ` SELECT total_draws, unique_users, unique_rooms, total_spent_coins, total_reward_coins, - base_reward_coins, room_atmosphere_reward_coins, activity_subsidy_coins + base_reward_coins, room_atmosphere_reward_coins, activity_subsidy_coins, + pending_draws, granted_draws, failed_draws FROM lucky_draw_pool_stats WHERE app_code = ? AND pool_id = ? AND gift_id = ?`, appcode.FromContext(ctx), query.PoolID, strings.TrimSpace(query.GiftID), @@ -1831,6 +1848,9 @@ func (r *Repository) getLuckyGiftDrawSummaryFromStats(ctx context.Context, query &summary.BaseRewardCoins, &summary.RoomAtmosphereRewardCoins, &summary.ActivitySubsidyCoins, + &summary.PendingDraws, + &summary.GrantedDraws, + &summary.FailedDraws, ) if errors.Is(err, sql.ErrNoRows) { return summary, nil @@ -1838,9 +1858,6 @@ func (r *Repository) getLuckyGiftDrawSummaryFromStats(ctx context.Context, query if err != nil { return domain.DrawSummary{}, err } - if err := r.loadLuckyGiftDrawStatusCounts(ctx, query, &summary); err != nil { - return domain.DrawSummary{}, err - } if summary.TotalSpentCoins > 0 { summary.ActualRTPPPM = summary.TotalRewardCoins * luckyPPMScale / summary.TotalSpentCoins } diff --git a/services/activity-service/internal/storage/mysql/lucky_gift_repository_test.go b/services/activity-service/internal/storage/mysql/lucky_gift_repository_test.go index a2cb3aa0..e8909bd6 100644 --- a/services/activity-service/internal/storage/mysql/lucky_gift_repository_test.go +++ b/services/activity-service/internal/storage/mysql/lucky_gift_repository_test.go @@ -115,6 +115,7 @@ func TestRefreshLuckyGiftAdminStatsSnapshotsAdvancesCursorByBatch(t *testing.T) t.Fatalf("first refresh should process one row, got %d", processed) } assertLuckyStatsTotal(t, repository, "", 1, 100, 300) + assertLuckyStatsStatus(t, repository, "", 0, 1, 0) assertLuckyStatsCursor(t, repository, 100, "draw_001") processed, err = repository.RefreshLuckyGiftAdminStatsSnapshots(ctx, 400, 10) @@ -125,6 +126,7 @@ func TestRefreshLuckyGiftAdminStatsSnapshotsAdvancesCursorByBatch(t *testing.T) t.Fatalf("second refresh should process remaining row, got %d", processed) } assertLuckyStatsTotal(t, repository, "", 2, 250, 300) + assertLuckyStatsStatus(t, repository, "", 1, 1, 0) assertLuckyStatsCursor(t, repository, 200, "draw_002") } @@ -166,6 +168,21 @@ func assertLuckyStatsTotal(t *testing.T, repository *Repository, giftID string, } } +func assertLuckyStatsStatus(t *testing.T, repository *Repository, giftID string, wantPending int64, wantGranted int64, wantFailed int64) { + t.Helper() + var pending, granted, failed int64 + if err := repository.db.QueryRowContext(context.Background(), ` + SELECT pending_draws, granted_draws, failed_draws + FROM lucky_draw_pool_stats + WHERE app_code = 'lalu' AND pool_id = 'lucky' AND gift_id = ?`, giftID, + ).Scan(&pending, &granted, &failed); err != nil { + t.Fatalf("read stats status: %v", err) + } + if pending != wantPending || granted != wantGranted || failed != wantFailed { + t.Fatalf("stats status mismatch: pending=%d granted=%d failed=%d want pending=%d granted=%d failed=%d", pending, granted, failed, wantPending, wantGranted, wantFailed) + } +} + func assertLuckyStatsCursor(t *testing.T, repository *Repository, wantCreatedAtMS int64, wantDrawID string) { t.Helper() var createdAtMS int64