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; }
}
}