|
|
@ -1026,6 +1026,112 @@ public class BalanceManager : DomainService, IBalanceManager |
|
|
|
return usableBalances; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 获取无箱码可用库存列表
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="itemCode"></param>
|
|
|
|
/// <param name="validLocations"></param>
|
|
|
|
/// <param name="validStatuses"></param>
|
|
|
|
/// <param name="isRemovePackingCode"></param>
|
|
|
|
/// <returns></returns>
|
|
|
|
public virtual async Task<List<Balance>> GetNoPackCodeUsableListAsync(string itemCode, |
|
|
|
List<string> validLocations, |
|
|
|
List<EnumInventoryStatus> validStatuses, bool isRemovePackingCode) |
|
|
|
{ |
|
|
|
var recommendBalances = new List<Balance>();//返回可使用的推荐库存余额
|
|
|
|
|
|
|
|
var item = await _itemBasicAclService.GetByCodeAsync(itemCode).ConfigureAwait(false); |
|
|
|
if (item == null) //物品是否存在
|
|
|
|
{ |
|
|
|
// throw new UserFriendlyException($"未找到代码为 {itemCode} 的物料记录");
|
|
|
|
return recommendBalances; |
|
|
|
} |
|
|
|
|
|
|
|
//构造查询条件
|
|
|
|
Expression<Func<Balance, bool>> expression = p => p.ItemCode == itemCode; |
|
|
|
expression = expression.And(p => validStatuses.Contains(p.Status)); |
|
|
|
expression = expression.And(p => p.IsActive); |
|
|
|
|
|
|
|
//如果物品的有效期不是无限的, 要过滤掉过期库存
|
|
|
|
if (item.ValidityUnit != EnumValidityUnit.Infinite) |
|
|
|
{ |
|
|
|
expression = expression.And(p => p.ExpireDate > DateTime.Now); |
|
|
|
} |
|
|
|
//排除有箱码库存
|
|
|
|
if (isRemovePackingCode) |
|
|
|
{ |
|
|
|
expression = expression.And(p => string.IsNullOrEmpty(p.PackingCode)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var allBalances = await |
|
|
|
(await _balanceRepository.GetDbSetAsync().ConfigureAwait(false)) |
|
|
|
.Where(expression) |
|
|
|
.AsNoTracking() |
|
|
|
.ToListAsync().ConfigureAwait(false); |
|
|
|
|
|
|
|
var balanceLocationCodes = allBalances.Select(p => p.LocationCode).Distinct().ToList(); |
|
|
|
var locations = await _locationAclService.GetByCodesAsync(balanceLocationCodes).ConfigureAwait(false); |
|
|
|
//筛选有效库位类型
|
|
|
|
if (validLocations.Any()) |
|
|
|
{ |
|
|
|
locations = locations.Where(p => validLocations.Contains(p.Code)).ToList(); |
|
|
|
} |
|
|
|
var locationCodes = locations.Where(p => p.EnablePick).Select(p => p.Code).ToList(); |
|
|
|
|
|
|
|
if (!locationCodes.Any()) |
|
|
|
{ |
|
|
|
return recommendBalances; |
|
|
|
} |
|
|
|
//获取物品存储关系
|
|
|
|
var itemStoreRelationDict = await GetItemStoreRelationDictAsync(itemCode, locationCodes).ConfigureAwait(false); |
|
|
|
//过滤掉无用的库位代码
|
|
|
|
locationCodes = itemStoreRelationDict.Keys.ToList(); |
|
|
|
locations = locations.Where(p => locationCodes.Contains(p.Code)).ToList(); |
|
|
|
|
|
|
|
var usableBalances = allBalances.Where(p => locationCodes.Contains(p.LocationCode)).ToList(); |
|
|
|
|
|
|
|
if (!usableBalances.Any()) |
|
|
|
{ |
|
|
|
return recommendBalances; |
|
|
|
} |
|
|
|
|
|
|
|
//读取该itemCode项目为空的预占用库存
|
|
|
|
var expectOuts = await |
|
|
|
(await _expectOutRepository.GetDbSetAsync().ConfigureAwait(false)) |
|
|
|
.AsNoTracking() |
|
|
|
.Where(p => p.ItemCode == itemCode |
|
|
|
&& locationCodes.Contains(p.LocationCode) && string.IsNullOrEmpty(p.PackingCode) |
|
|
|
&& validStatuses.Contains(p.Status)) |
|
|
|
.ToListAsync().ConfigureAwait(false); |
|
|
|
|
|
|
|
var containerCodes = usableBalances |
|
|
|
.Where(p => !string.IsNullOrEmpty(p.ContainerCode)) |
|
|
|
.Select(p => p.ContainerCode) |
|
|
|
.ToList(); |
|
|
|
|
|
|
|
var expectOutContainerCodes = await |
|
|
|
(await _expectOutRepository.GetDbSetAsync().ConfigureAwait(false)) |
|
|
|
.Where(p => containerCodes.Contains(p.ContainerCode)) |
|
|
|
.GroupBy(p => p.ContainerCode) |
|
|
|
.Select(d => d.Key) |
|
|
|
.ToListAsync().ConfigureAwait(false); |
|
|
|
|
|
|
|
usableBalances |
|
|
|
//扣减已占用库存
|
|
|
|
.DecreaseExpectOutQty(expectOuts, locations) |
|
|
|
//去除不可拆箱 拆托的且有预占用的库存余额
|
|
|
|
.IgnoreExpectOutOfSameContainer(expectOutContainerCodes, itemStoreRelationDict, locations) |
|
|
|
//过滤掉不允许拣料的库位
|
|
|
|
.FilterLocationEnablePickAsync(locations) |
|
|
|
//排序库存余额 最终可用的余额集合
|
|
|
|
.SortByFifo(); |
|
|
|
usableBalances = usableBalances.Where(p => p.Qty != 0).ToList(); |
|
|
|
|
|
|
|
return usableBalances; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private decimal GetRecommendQty(Guid traceId, decimal requestQty, decimal remainingQty, Balance usableBalance, LocationDTO location, ItemStoreRelationDTO itemStoreRelation) |
|
|
|
{ |
|
|
|
var balanceQty = usableBalance.Qty; |
|
|
|