/// <summary> /// 为出库单分配库存。 /// </summary> /// <remarks> /// </remarks> /// <param name="outboundOrder">要分配库存的出库单</param> /// <param name="options">分配选项</param> public async Task AllocateAsync(OutboundOrder outboundOrder, AllocatStockOptions options) { if (outboundOrder == null) { throw new ArgumentNullException(nameof(outboundOrder)); } if (outboundOrder.Closed) { throw new InvalidOperationException("出库单已关闭"); } if (options == null) { options = new AllocatStockOptions(); } options.Normalize(); _logger.Information("正在为出库单 {outboundOrderCode} 分配库存", outboundOrder.OutboundOrderCode); _logger.Information("区域:{areas}", options.Areas == null ? "" : string.Join(", ", options.Areas)); //_logger.Information("跳过脱机的巷道:{skipOfflineLaneways}", options.SkipOfflineLaneways); //_logger.Information("排除的巷道:{excludeLanewasys}", string.Join(", ", options.ExcludeLaneways.Select(x => x.LanewayCode))); _logger.Information("包含的托盘:{includePallets}", string.Join(", ", options.IncludePallets)); _logger.Information("排除的托盘:{excludePallets}", string.Join(", ", options.ExcludePallets)); //_logger.Information("跳过禁止出站的货位:{skipLocationsOutboundDisabled}", options.SkipLocationsOutboundDisabled); foreach (var line in outboundOrder.Lines) { await ProcessLineAsync(line, options).ConfigureAwait(false); } }
/// <summary> /// 处理单个出库行 /// </summary> /// <param name="line">出库行</param> /// <param name="laneways">用于分配的货载所在的巷道</param> /// <param name="includeUnitloads">要在分配中包含的货载,这些货载优先参与分配。</param> /// <param name="excludeUnitloads">要在分配中排除的货载,这些货载不会参与分配,即使出现在 includeUnitloads 中,也不参与分配。</param> async Task ProcessLineAsync(OutboundLine line, AllocatStockOptions options) { _logger.Information("正在为出库单明细 {outboundLine} 分配库存", line); { var shortage = line.ComputeShortage(); _logger.Debug("出库单明细 {outboundLine} 的分配欠数是 {shortage}", line, shortage); if (shortage <= 0) { _logger.Debug("不需要分配"); return; } } // 显式包含的货载项 List <UnitloadItem> included = new List <UnitloadItem>(); if (options.IncludePallets.Length > 0) { included = await _session.Query <UnitloadItem>() .Where(x => options.IncludePallets.Contains(x.Unitload.PalletCode) && x.Material == line.Material) .ToListAsync() .ConfigureAwait(false); } // 库内候选项 var candidateItems = _session .Query <UnitloadItem>() .Where(x => included.Contains(x) == false && // 显式包含的货载项已在上面处理过,这里需排除 x.Material == line.Material) .OrderBy(x => x.OutOrdering) .ThenBy(x => x.Unitload.CurrentLocation.Cell.oByShape) .ThenBy(x => x.Unitload.CurrentLocation.Cell.o1) .ThenBy(x => x.Unitload.CurrentLocation.Rack.Deep) .LoadInChunksAsync(options.ChunkSize); await foreach (var item in Union(included, candidateItems)) { if (item.Quantity == 0) { _logger.Warning("货载项 {unitloadItem} 的数量为 0", item); continue; } var taken = await AllocateItemAsync(line, item, options); var shortage = line.ComputeShortage(); _logger.Debug("出库单明细 {outboundLine} 的分配欠数是 {shortage}", line, shortage); if (shortage <= 0) { _logger.Information("出库单明细 {outboundLine} 分配库存完成", line); return; } } _logger.Information("出库单明细 {outboundLine} 分配库存完成", line);