using GB5Shared.DTO.Framework.Login; using GoodBooks.PAY.PAYBLL.Loyalty; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace GoodBooks.PAY.PAYSL.Services { // ───────────────────────────────────────────────────────────────────────── // LoyaltyPointsExpiryJob // // .NET 9 BackgroundService using PeriodicTimer. // Runs once per day (configurable via PayJobs:LoyaltyExpiryIntervalHours). // Calls ICustomerLoyaltyBLL.ExpirePointsAsync which: // - finds all enrollments with points expiring today // - inserts negative-point compensating TLOYALTYLEDGER rows (append-only) // - decrements TCUSTOMERLOYALTYENROLLMENT.CURRENTPOINTS // ───────────────────────────────────────────────────────────────────────── public sealed class LoyaltyPointsExpiryJob : BackgroundService { private readonly IServiceScopeFactory _scopeFactory; private readonly IConfiguration _config; private readonly ILogger _logger; public LoyaltyPointsExpiryJob( IServiceScopeFactory scopeFactory, IConfiguration config, ILogger logger) { _scopeFactory = scopeFactory; _config = config; _logger = logger; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { int intervalHours = _config.GetValue("PayJobs:LoyaltyExpiryIntervalHours", 24); _logger.LogInformation( "LoyaltyPointsExpiryJob starting — interval {IntervalHours}h", intervalHours); using var timer = new PeriodicTimer(TimeSpan.FromHours(intervalHours)); while (await timer.WaitForNextTickAsync(stoppingToken)) { _logger.LogInformation("LoyaltyPointsExpiryJob tick at {UtcNow:u}", DateTime.UtcNow); try { using var scope = _scopeFactory.CreateScope(); var bll = scope.ServiceProvider.GetRequiredService(); var systemLogin = BuildSystemLogin(); await bll.ExpirePointsAsync(systemLogin, stoppingToken).ConfigureAwait(false); _logger.LogInformation("LoyaltyPointsExpiryJob cycle completed at {UtcNow:u}", DateTime.UtcNow); } catch (Exception ex) when (ex is not OperationCanceledException) { _logger.LogError(ex, "LoyaltyPointsExpiryJob cycle failed."); // Continue — next tick will retry } } } private LoginDTO BuildSystemLogin() => new() { ClientId = _config.GetValue("PayJobs:SystemTenantId", -1), DatabaseName = _config["PayJobs:SystemDatabaseName"] ?? "GoodBooks_Main", UserId = -1 }; } }