using Admin.NET.Plugin.AiDOP.DataPlatform; using Microsoft.Extensions.Logging; namespace Admin.NET.Plugin.AiDOP.Order; /// /// 从 165(DOPDEMORQ_SQLSERVER)批量读取实时可用库存。 /// /// 只读、只查 InvMaster;连接经 MdpSourceScopeFactory 走 mdp_source 配置,不新开连接串。 /// 口径与本库旧实现逐字对齐(跨全部 Location 求和、COALESCE(AvailStatusQty, QtyOnHand, 0)、 /// 不过滤 IsActive),本包只换数据新鲜度,不动口径。 /// 分块 IN 查询,避免逐物料跨库往返。 /// public sealed class Mes165StockReader : ITransient { private const string SourceCode = "DOPDEMORQ_SQLSERVER"; private readonly MdpSourceScopeFactory _scopeFactory; private readonly ILogger _logger; public Mes165StockReader(MdpSourceScopeFactory scopeFactory, ILoggerFactory loggerFactory) { _scopeFactory = scopeFactory; _logger = loggerFactory.CreateLogger(nameof(Mes165StockReader)); } /// 按物料号批量取可用库存;返回不含未命中的物料(调用方按 0 处理)。 public async Task> LoadAvailableQtyAsync( IReadOnlyList itemNumbers, string domain, int batchSize = 500, CancellationToken ct = default) { var result = new Dictionary(StringComparer.OrdinalIgnoreCase); if (itemNumbers.Count == 0) return result; var remote = await _scopeFactory.GetScopeAsync(SourceCode, ct); var size = batchSize <= 0 ? 500 : batchSize; for (var offset = 0; offset < itemNumbers.Count; offset += size) { ct.ThrowIfCancellationRequested(); var chunk = itemNumbers.Skip(offset).Take(size).ToList(); var names = new List(chunk.Count); var pars = new List { new("@Domain", domain) }; for (var i = 0; i < chunk.Count; i++) { names.Add($"@i{i}"); pars.Add(new SugarParameter($"@i{i}", chunk[i])); } var sql = $""" SELECT ItemNum AS ItemNum, SUM(COALESCE(AvailStatusQty, QtyOnHand, 0)) AS Qty FROM InvMaster WHERE Domain = @Domain AND ItemNum IN ({string.Join(",", names)}) GROUP BY ItemNum """; var rows = await remote.Ado.SqlQueryAsync(sql, pars); foreach (var r in rows) { if (string.IsNullOrWhiteSpace(r.ItemNum)) continue; result[r.ItemNum.Trim()] = r.Qty; } } _logger.LogInformation( "[Mes165StockReader] domain={Domain} requested={Requested} matched={Matched}", domain, itemNumbers.Count, result.Count); return result; } private sealed class StockRow { public string? ItemNum { get; set; } public decimal Qty { get; set; } } }