using Admin.NET.Plugin.AiDOP.MaterialWarehouse; using Furion.Schedule; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace Admin.NET.Plugin.AiDOP.Job; /// S5 库存余额每周全量校准(清理 165 已删除行)。 [JobDetail("job_s5_inventory_reconcile", Description = "S5库存余额每周全量校准", GroupName = "default", Concurrent = false)] [Cron("30 2 * * 0", TriggerId = "trigger_s5_inventory_reconcile", Description = "每周日 02:30")] public sealed class S5InventoryReconcileJob : IJob { private readonly IServiceScopeFactory _scopeFactory; private readonly ILogger _logger; public S5InventoryReconcileJob(IServiceScopeFactory scopeFactory, ILoggerFactory loggerFactory) { _scopeFactory = scopeFactory; _logger = loggerFactory.CreateLogger(nameof(S5InventoryReconcileJob)); } public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken) { using var scope = _scopeFactory.CreateScope(); var sync = scope.ServiceProvider.GetRequiredService(); try { var result = await sync.RunReconcileFullAsync(stoppingToken); _logger.LogInformation("[S5InventoryReconcileJob] done skipped={Skipped} invStd={Inv}", result.Skipped, result.InventoryStdRows); } catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested) { throw; } catch (Exception ex) { _logger.LogError(ex, "[S5InventoryReconcileJob] failed; keep previous std"); } } }