using Admin.NET.Plugin.AiDOP.Supply;
using Furion.Schedule;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Admin.NET.Plugin.AiDOP.Job;
///
/// S8 Stage-3 采购完成态周期性全量对账。
///
/// 这是正确性主路径,不是优化项。 HotWatch 只覆盖活动中的采购单:实测 5 个
/// PUR_ORDER 关注中 3 个已提前终止(且无一是因采购完成而终止,全部走 IQC 路径终止),
/// 终止后 Status=1 的关注永不再轮询;另有 88/98 条源行根本没有对应关注。
/// 因此仅靠增量必然漏判完成与回退,全量对账不可省。
///
/// 周期取 30 分钟:与 S5InventoryInboundJob 的既有半小时级节奏一致。
/// 源侧 Status 是收货过程产物,30 分钟的对账延迟对 Stage-3 口径可接受;
/// 若日后接入 HotWatch 增量钩子,延迟会降到关注轮询级,但本 Job 仍必须保留。
///
[JobDetail("job_s3_po_completion_mdp_sync", Description = "S3 采购完成态(Source B)全量对账", GroupName = "default", Concurrent = false)]
[Period(1800000, TriggerId = "trigger_s3_po_completion_mdp_sync", Description = "每30分钟执行")]
public class S3PoCompletionMdpSyncJob : IJob
{
private readonly IServiceScopeFactory _scopeFactory;
private readonly ILogger _logger;
public S3PoCompletionMdpSyncJob(IServiceScopeFactory scopeFactory, ILoggerFactory loggerFactory)
{
_scopeFactory = scopeFactory;
_logger = loggerFactory.CreateLogger(nameof(S3PoCompletionMdpSyncJob));
}
public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
{
using var scope = _scopeFactory.CreateScope();
try
{
var svc = scope.ServiceProvider.GetRequiredService();
var r = await svc.RunFullAsync(0, "AUTO", stoppingToken);
_logger.LogInformation(
"S3PoCompletionMdpSyncJob 完成 batch={Batch} source={Src} rows={Rows} written={Written} "
+ "completed={Completed} notCompleted={NotCompleted} unknown={Unknown} skipped={Skipped} stale={Stale}",
r.BatchId, r.SourceCode, r.SourceRows, r.WrittenRows,
r.CompletedRows, r.NotCompletedRows, r.UnknownStatusRows, r.SkippedRows, r.StaleRemoved);
}
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("S3PoCompletionMdpSyncJob 收到停止信号,结束本轮对账");
}
catch (Exception ex)
{
// 源绑定不合法(未配置 / 指向 DEV 源 / 源被禁用)会走到这里:
// 运行日志已在 Service 内标 FAILED,这里只保证调度线程不被打断、也不吞掉异常信息。
_logger.LogError(ex, "S3PoCompletionMdpSyncJob 执行失败");
}
}
}