namespace Admin.NET.Plugin.AiDOP.Supply; /// S4 采购闭环后读路径一致性检查(运行表 vs DWD)。 public class S4ReadPathConsistencyService : ITransient { private readonly ISqlSugarClient _db; public S4ReadPathConsistencyService(ISqlSugarClient db) { _db = db; } public async Task CheckTenantAsync(long tenantId) { var runtimePr = await CountAsync( """ SELECT COUNT(*) FROM srm_pr_main WHERE tenant_id = @TenantId AND IFNULL(IsDeleted, 0) = 0 """, tenantId); var runtimePo = await CountAsync( """ SELECT COUNT(*) FROM PurOrdMaster WHERE tenant_id = @TenantId AND IFNULL(IsActive, 1) = 1 """, tenantId); var runtimeDelivery = await CountAsync( """ SELECT COUNT(*) FROM srm_polist_ds WHERE tenant_id = @TenantId AND IFNULL(isactive, 1) = 1 """, tenantId); var dwdExecution = await SafeCountAsync( """ SELECT COUNT(*) FROM dwd_s4_purchase_execution WHERE tenant_id = @TenantId """, tenantId); var dwdPoTrans = await SafeCountAsync( """ SELECT COUNT(*) FROM dwd_po_trans WHERE tenant_id = @TenantId """, tenantId); var dwdDelivery = await SafeCountAsync( """ SELECT COUNT(*) FROM dwd_supplier_delivery WHERE tenant_id = @TenantId """, tenantId); var checks = new List { BuildCheck("runtime_pr", runtimePr, null, runtimePr >= 0), BuildCheck("runtime_po", runtimePo, dwdPoTrans, dwdPoTrans is null || runtimePo <= dwdPoTrans + 50), BuildCheck("runtime_delivery", runtimeDelivery, dwdDelivery, dwdDelivery is null || runtimeDelivery <= dwdDelivery + 50), BuildCheck("dwd_purchase_execution", runtimePo, dwdExecution, dwdExecution is null || dwdExecution > 0 || runtimePo == 0) }; return new S4ReadPathConsistencyResult { TenantId = tenantId, Checks = checks, Ok = checks.All(x => x.Ok) }; } private static S4ReadPathCheckItem BuildCheck(string name, int runtime, int? dwd, bool ok) => new() { Name = name, RuntimeCount = runtime, DwdCount = dwd, Ok = ok }; private async Task CountAsync(string sql, long tenantId) => await _db.Ado.GetIntAsync(sql, new SugarParameter("@TenantId", tenantId)); private async Task SafeCountAsync(string sql, long tenantId) { try { return await CountAsync(sql, tenantId); } catch { return null; } } } public sealed class S4ReadPathConsistencyResult { public long TenantId { get; set; } public bool Ok { get; set; } public List Checks { get; set; } = new(); } public sealed class S4ReadPathCheckItem { public string Name { get; set; } = string.Empty; public int RuntimeCount { get; set; } public int? DwdCount { get; set; } public bool Ok { get; set; } }