|
|
@@ -9,8 +9,9 @@ namespace Kitty_Fall.Woker.Services
|
|
|
public class GameMonthlyWinnerWorker : BackgroundService
|
|
|
{
|
|
|
private const byte DrawStatusNew = 0;
|
|
|
- private const byte DrawStatusTicketReady = 1;
|
|
|
- private const byte DrawStatusWinnerDraft = 2;
|
|
|
+ private const byte DrawStatusLocked = 1;
|
|
|
+ private const byte DrawStatusDrawing = 2;
|
|
|
+ private const byte DrawStatusCompleted = 3;
|
|
|
|
|
|
private const byte WinnerStatusDraft = 0;
|
|
|
private const byte WinnerStatusAnnounced = 1;
|
|
|
@@ -58,12 +59,22 @@ namespace Kitty_Fall.Woker.Services
|
|
|
var monthKey = targetMonth.Year * 100 + targetMonth.Month;
|
|
|
|
|
|
var draw = await EnsureDrawAsync(dbContext, monthKey, cancellationToken);
|
|
|
+ if (draw.Status >= DrawStatusCompleted)
|
|
|
+ {
|
|
|
+ log.Debug($"Monthly winner already completed. monthKey={monthKey}, drawId={draw.DrawId}");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
await EnsureTicketsAsync(dbContext, draw, cancellationToken);
|
|
|
|
|
|
if (GetBool("MonthlyWinner:AutoSelectDraftWinners", true))
|
|
|
{
|
|
|
await EnsureDraftWinnersAsync(dbContext, draw, cancellationToken);
|
|
|
}
|
|
|
+ else
|
|
|
+ {
|
|
|
+ await MarkDrawCompletedAsync(dbContext, draw, cancellationToken);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private async Task<GameMonthlyDraw> EnsureDrawAsync(ModelContext dbContext, int monthKey, CancellationToken cancellationToken)
|
|
|
@@ -92,10 +103,18 @@ namespace Kitty_Fall.Woker.Services
|
|
|
|
|
|
private async Task EnsureTicketsAsync(ModelContext dbContext, GameMonthlyDraw draw, CancellationToken cancellationToken)
|
|
|
{
|
|
|
+ if (draw.Status >= DrawStatusLocked) return;
|
|
|
+
|
|
|
var hasTicket = await dbContext.GameMonthlyDrawTickets
|
|
|
.AsNoTracking()
|
|
|
.AnyAsync(x => x.DrawId == draw.DrawId, cancellationToken);
|
|
|
- if (hasTicket) return;
|
|
|
+ if (hasTicket)
|
|
|
+ {
|
|
|
+ draw.Status = DrawStatusLocked;
|
|
|
+ draw.UpdatedTime = DateTime.Now;
|
|
|
+ await dbContext.SaveChangesAsync(cancellationToken);
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
var now = DateTime.Now;
|
|
|
// Chi user dat diem toi thieu moi duoc sinh ticket tham gia giai thang.
|
|
|
@@ -159,7 +178,7 @@ namespace Kitty_Fall.Woker.Services
|
|
|
|
|
|
draw.TotalEligible = totalEligible;
|
|
|
draw.TotalTicket = totalTicket;
|
|
|
- draw.Status = DrawStatusTicketReady;
|
|
|
+ draw.Status = DrawStatusLocked;
|
|
|
draw.UpdatedTime = now;
|
|
|
|
|
|
await dbContext.SaveChangesAsync(cancellationToken);
|
|
|
@@ -167,20 +186,34 @@ namespace Kitty_Fall.Woker.Services
|
|
|
|
|
|
private async Task EnsureDraftWinnersAsync(ModelContext dbContext, GameMonthlyDraw draw, CancellationToken cancellationToken)
|
|
|
{
|
|
|
+ if (draw.Status >= DrawStatusCompleted) return;
|
|
|
+
|
|
|
var prizeConfigs = await dbContext.GameMonthlyPrizeConfigs
|
|
|
.AsNoTracking()
|
|
|
.Where(x => x.Status != false)
|
|
|
.OrderBy(x => x.DisplayOrder)
|
|
|
.ThenBy(x => x.PrizeConfigId)
|
|
|
.ToListAsync(cancellationToken);
|
|
|
- if (prizeConfigs.Count == 0) return;
|
|
|
+ if (prizeConfigs.Count == 0)
|
|
|
+ {
|
|
|
+ await MarkDrawCompletedAsync(dbContext, draw, cancellationToken);
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
var tickets = await dbContext.GameMonthlyDrawTickets
|
|
|
.AsNoTracking()
|
|
|
.Where(x => x.DrawId == draw.DrawId)
|
|
|
.OrderBy(x => x.TicketNo)
|
|
|
.ToListAsync(cancellationToken);
|
|
|
- if (tickets.Count == 0) return;
|
|
|
+ if (tickets.Count == 0)
|
|
|
+ {
|
|
|
+ await MarkDrawCompletedAsync(dbContext, draw, cancellationToken);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ draw.Status = DrawStatusDrawing;
|
|
|
+ draw.UpdatedTime = DateTime.Now;
|
|
|
+ await dbContext.SaveChangesAsync(cancellationToken);
|
|
|
|
|
|
var excludedMsisdns = await GetRecentWinnerMsisdnsAsync(dbContext, draw.MonthKey, cancellationToken);
|
|
|
var existingWinners = await dbContext.GameMonthlyWinners
|
|
|
@@ -234,11 +267,27 @@ namespace Kitty_Fall.Woker.Services
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- draw.Status = DrawStatusWinnerDraft;
|
|
|
+ draw.Status = DrawStatusCompleted;
|
|
|
draw.DrawTime = now;
|
|
|
draw.UpdatedTime = now;
|
|
|
|
|
|
await dbContext.SaveChangesAsync(cancellationToken);
|
|
|
+ log.Info($"Monthly winner completed. monthKey={draw.MonthKey}, drawId={draw.DrawId}, totalEligible={draw.TotalEligible}, totalTicket={draw.TotalTicket}");
|
|
|
+ }
|
|
|
+
|
|
|
+ private static async Task MarkDrawCompletedAsync(
|
|
|
+ ModelContext dbContext,
|
|
|
+ GameMonthlyDraw draw,
|
|
|
+ CancellationToken cancellationToken)
|
|
|
+ {
|
|
|
+ if (draw.Status >= DrawStatusCompleted) return;
|
|
|
+
|
|
|
+ var now = DateTime.Now;
|
|
|
+ draw.Status = DrawStatusCompleted;
|
|
|
+ draw.DrawTime ??= now;
|
|
|
+ draw.UpdatedTime = now;
|
|
|
+ await dbContext.SaveChangesAsync(cancellationToken);
|
|
|
+ log.Info($"Monthly winner completed without auto selection. monthKey={draw.MonthKey}, drawId={draw.DrawId}, totalEligible={draw.TotalEligible}, totalTicket={draw.TotalTicket}");
|
|
|
}
|
|
|
|
|
|
private async Task<HashSet<string>> GetRecentWinnerMsisdnsAsync(
|