Browse Source

添加接口库位推荐方法

master
lvzb 1 year ago
parent
commit
fd4e62e948
  1. 5
      be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application.Contracts/Balances/Inputs/RecommendBalanceRequestInput.cs
  2. 11
      be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application/Balances/BalanceAppService.cs
  3. 153
      be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/BalanceManager.cs
  4. 1
      be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/IBalanceManager.cs

5
be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application.Contracts/Balances/Inputs/RecommendBalanceRequestInput.cs

@ -28,6 +28,11 @@ public class RecommendBalanceRequestInput
[Display(Name = "库区域")]
public List<string> LocationAreas { get; set; }
/// <summary>
/// 库位
/// </summary>
[Display(Name = "库位")]
public List<string> Locations { get; set; }
/// <summary>
/// 库存状态
/// </summary>
[Display(Name = "库存状态")]

11
be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application/Balances/BalanceAppService.cs

@ -465,23 +465,22 @@ public class BalanceAppService
}
/// <summary>
/// 根据发料任务需求,算出推荐的库存 (在获取时 已经添加预占用)
/// 根据发料任务需求的库位,算出推荐的库存 (在获取时 已经添加预占用)
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
[HttpGet("recommend-list-location")]
public virtual async Task<List<BalanceDTO>> GetRecommendBalancesAsync1(RecommendBalanceRequestInput input)
[HttpGet("recommend-list-location-by-locations")]
public virtual async Task<List<BalanceDTO>> GetRecommendBalancesByLocationsAsync(RecommendBalanceRequestInput input)
{
var traceId = GuidGenerator.Create();
var itemCode = input.ItemCode;
var qty = input.Qty;
var locationTypes = input.LocationTypes;
var locationAreas = input.LocationAreas;
var locations = input.Locations;
var statuses = input.Statuses;
Logger.LogDebug(traceId + "|Input:" + input);
var balances = await _balanceManager.GetRecommendBalancesAsync(traceId, itemCode, qty, locationTypes, locationAreas, statuses).ConfigureAwait(false);
var balances = await _balanceManager.GetRecommendBalancesByLocationAsync(traceId, itemCode, qty, locations, statuses).ConfigureAwait(false);
var dtos = ObjectMapper.Map<List<Balance>, List<BalanceDTO>>(balances);

153
be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/BalanceManager.cs

@ -436,6 +436,159 @@ public class BalanceManager : DomainService, IBalanceManager
#region GetRecommendList
/// <summary>
/// 根据库位获取推荐库位
/// </summary>
/// <param name="traceId"></param>
/// <param name="itemCode"></param>
/// <param name="requestQty"></param>
/// <param name="validLocationTypes"></param>
/// <param name="validLocationAreas"></param>
/// <param name="validStatuses"></param>
/// <returns></returns>
/// <exception cref="UserFriendlyException"></exception>
public virtual async Task<List<Balance>> GetRecommendBalancesByLocationAsync(Guid traceId, string itemCode,
decimal requestQty, List<string> validLocations,
List<EnumInventoryStatus> validStatuses)
{
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);
}
//筛选有效库区 2023-6-29 李智慧 王旭 袁静雯 确认不需要做区域校验
//if (validLocationAreas.Any())
//{
// if (!string.IsNullOrEmpty(validLocationAreas[0]))
// {
// expression = expression.And(p => validLocationAreas.Contains(p.LocationArea));
// }
//}
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();
Logger.LogDebug(traceId + "|Locations:" + locationCodes.JoinAsString(","));
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();
Logger.LogDebug(traceId + "|LocationsInStoreRelation:" + locationCodes.JoinAsString(","));
var usableBalances = allBalances.Where(p => locationCodes.Contains(p.LocationCode)).ToList();
LogDebug(traceId, usableBalances, "Balances");
if (!usableBalances.Any())
{
return recommendBalances;
}
//读取该itemCode的预占用库存
var expectOuts = await
(await _expectOutRepository.GetDbSetAsync().ConfigureAwait(false))
.AsNoTracking()
.Where(p => p.ItemCode == itemCode
&& locationCodes.Contains(p.LocationCode)
&& validStatuses.Contains(p.Status))
.ToListAsync().ConfigureAwait(false);
LogDebug(traceId, expectOuts, "ExpectOut");
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();
LogDebug(traceId, usableBalances, "AvailableBalances");
var usableBalanceQueue = new Queue<Balance>(usableBalances);
var remainQty = requestQty;
while (usableBalanceQueue.TryDequeue(out var usableBalance))
{
if (usableBalance.Qty <= 0)
{
continue;
}
var location = locations.First(p => p.Code == usableBalance.LocationCode);
var itemStoreRelation = itemStoreRelationDict[usableBalance.LocationCode];
var recommendBalance = new Balance(usableBalance);
var recommendQty =
GetRecommendQty(traceId, requestQty, remainQty, usableBalance, location, itemStoreRelation);
recommendBalance.Qty = recommendQty;
recommendBalances.Add(recommendBalance);
remainQty -= recommendQty;
//如果剩余数量小于等于零, 说明所有请求数量已满足, 退出循环
if (remainQty <= 0)
{
break;
}
}
return recommendBalances;
#region Old
// var availableQty = GetAvailableQty(traceId, requestQty, 0, usableBalances, itemStoreRelationDict, locations, recommendBalances);
//
// if (availableQty >= requestQty)
// {
// return recommendBalances;
// }
// var availableBalanceQty = usableBalances.Sum(p => p.Qty);
// throw new UserFriendlyException($"物料 {itemCode} 的可用库存余额 {availableBalanceQty} 不足");
#endregion
}
/// <summary>
/// 获取推荐库位
/// </summary>

1
be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/IBalanceManager.cs

@ -33,4 +33,5 @@ public interface IBalanceManager : IDomainService
Task<List<string>> GetItemCodesOfLocationAsync(string locationCode);
Task<Balance> ModifyAsync(Balance balance);
Task<List<Balance>> GetListByLocationTypeAndInventoryStatusAsync(string itemCode, EnumInventoryStatus enumInventoryStatus, List<EnumLocationType> enumLocationTypes);
Task<List<Balance>> GetRecommendBalancesByLocationAsync(Guid traceId, string itemCode, decimal requestQty, List<string> validLocations, List<EnumInventoryStatus> validStatuses);
}

Loading…
Cancel
Save