Browse Source

修改 注塑发料

dev_DY_CC
郑勃旭 1 year ago
parent
commit
ad8511a277
  1. 3
      be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application.Contracts/ProductLineItems/IProductionLineItemAppService.cs
  2. 10
      be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application/ProductionLineItems/ProductionLineItemAppService.cs
  3. 8
      be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application.Contracts/Balances/IBalanceAppService.cs
  4. 312
      be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application/Balances/BalanceAppService.cs
  5. 107
      be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/BalanceManager.cs
  6. 29
      be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/IBalanceManager.cs
  7. 4
      be/Modules/Shared/src/Win_in.Sfs.Shared.Domain.Shared/Enums/Store/EnumIssueType.cs
  8. 1
      be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/InjectionJobs/Inputs/InjectionJobEditInput.cs
  9. 2
      be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/InjectionRequests/InjectionRequestManager.cs
  10. 170
      be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/Requests/InjectionRequestEventHandler.cs
  11. 2
      be/WZC2.sln.DotSettings

3
be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application.Contracts/ProductLineItems/IProductionLineItemAppService.cs

@ -13,4 +13,7 @@ public interface IProductionLineItemAppService
{ {
Task<List<ProductionLineItemDTO>> GetByProductLineCodeAsync(string productLineCode); Task<List<ProductionLineItemDTO>> GetByProductLineCodeAsync(string productLineCode);
Task<ProductionLineItemDTO> GetByProductLineCodeAndItemCodeAsync(string productLineCode,
string itemCode);
} }

10
be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application/ProductionLineItems/ProductionLineItemAppService.cs

@ -17,6 +17,7 @@ public class ProductionLineItemAppService :
ProductionLineItemEditInput, ProductionLineItemImportInput>, IProductionLineItemAppService ProductionLineItemEditInput, ProductionLineItemImportInput>, IProductionLineItemAppService
{ {
private new readonly IProductionLineItemRepository _repository; private new readonly IProductionLineItemRepository _repository;
public ProductionLineItemAppService( public ProductionLineItemAppService(
IProductionLineItemRepository repository IProductionLineItemRepository repository
, IDistributedCache<ProductionLineItemDTO> cache , IDistributedCache<ProductionLineItemDTO> cache
@ -53,4 +54,13 @@ public class ProductionLineItemAppService :
var entityList = await _repository.GetListAsync(p => p.ProdLineCode == productLineCode).ConfigureAwait(false); var entityList = await _repository.GetListAsync(p => p.ProdLineCode == productLineCode).ConfigureAwait(false);
return ObjectMapper.Map<List<ProductionLineItem>, List<ProductionLineItemDTO>>(entityList); return ObjectMapper.Map<List<ProductionLineItem>, List<ProductionLineItemDTO>>(entityList);
} }
[HttpPost("get-by-product-item")]
public virtual async Task<ProductionLineItemDTO> GetByProductLineCodeAndItemCodeAsync(string productLineCode,
string itemCode)
{
var entityList = await _repository
.FindAsync(p => p.ProdLineCode == productLineCode && p.ItemCode == itemCode).ConfigureAwait(false);
return ObjectMapper.Map<ProductionLineItem, ProductionLineItemDTO>(entityList);
}
} }

8
be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application.Contracts/Balances/IBalanceAppService.cs

@ -166,4 +166,12 @@ public interface IBalanceAppService
Task<List<BalanceDTO>> GetListByErpLocationCodeAndItemCodeAsync(string erplocationCode, string itemCode); Task<List<BalanceDTO>> GetListByErpLocationCodeAndItemCodeAsync(string erplocationCode, string itemCode);
Task<List<BalanceDTO>> GetRecommendBalancesByLocationsAsync(RecommendBalanceRequestInput input); Task<List<BalanceDTO>> GetRecommendBalancesByLocationsAsync(RecommendBalanceRequestInput input);
Task<PagedResultDto<BalanceDTO>> GetBalancePagedListByFilterAsync(SfsInventoryRequestInputBase sfsRequestInput, bool includeDetails = false, CancellationToken cancellationToken = default); Task<PagedResultDto<BalanceDTO>> GetBalancePagedListByFilterAsync(SfsInventoryRequestInputBase sfsRequestInput, bool includeDetails = false, CancellationToken cancellationToken = default);
/// <summary>
/// 获取可用库存列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
Task<List<BalanceDTO>> GetUsableListAsync(RecommendBalanceRequestInput input);
} }

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

@ -1,16 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using DocumentFormat.OpenXml.Office2016.Drawing.ChartDrawing;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Win_in.Sfs.Basedata.Application.Contracts; using Win_in.Sfs.Basedata.Application.Contracts;
using Win_in.Sfs.Shared.Application.Contracts; using Win_in.Sfs.Shared.Application.Contracts;
@ -21,12 +19,11 @@ using Win_in.Sfs.Wms.Inventory.Domain;
using Win_in.Sfs.Wms.Inventory.Domain.Acl.ItemBasic; using Win_in.Sfs.Wms.Inventory.Domain.Acl.ItemBasic;
using Win_in.Sfs.Wms.Inventory.Domain.Acl.Location; using Win_in.Sfs.Wms.Inventory.Domain.Acl.Location;
using Win_in.Sfs.Wms.Inventory.Domain.Shared; using Win_in.Sfs.Wms.Inventory.Domain.Shared;
using JsonSerializer = System.Text.Json.JsonSerializer;
namespace Win_in.Sfs.Wms.Inventory.Application; namespace Win_in.Sfs.Wms.Inventory.Application;
/// <summary> /// <summary>
/// 库存余额 /// 库存余额
/// </summary> /// </summary>
[Authorize] [Authorize]
[Route($"{InventoryConsts.RootPath}inventory-balance")] [Route($"{InventoryConsts.RootPath}inventory-balance")]
@ -58,13 +55,55 @@ public class BalanceAppService
_locationAclService = locationAclService; _locationAclService = locationAclService;
_itemBasicAclService = itemBasicAclService; _itemBasicAclService = itemBasicAclService;
_itemBasicAppService = itemBasicAppService; _itemBasicAppService = itemBasicAppService;
_stdCostPriceSheetAppService= stdCostPriceSheetAppService; _stdCostPriceSheetAppService = stdCostPriceSheetAppService;
} }
#region Update #region Update
/// <summary>
/// 库存余额更新物品基础信息
/// </summary>
[HttpPost("update/item-basic-info")]
public async Task UpdateItemBasicInfoAsync(BalanceUpdateItemBasicInfoDto balanceUpdateItemBasicInfoDto)
{
//停用,可能用其他处理方案
return;
// 物品编码
var itemCodes = balanceUpdateItemBasicInfoDto.BalanceUpdateItemBasicInfos?.Select(c => c.ItemCode);
itemCodes = itemCodes?.Where(t => string.IsNullOrWhiteSpace(t) == false);
if (itemCodes == null || itemCodes.Any() == false)
{
return;
}
// 获取库存余额
var entitys = await _repository.GetListAsync(p =>
itemCodes.Contains(p.ItemCode)).ConfigureAwait(false);
if (entitys.Count <= 0)
{
return;
}
// 库存余额更新物品基础信息
var entitysGroup = entitys.GroupBy(t => t.ItemCode);
foreach (var entity in entitysGroup)
{
var balanceUpdateItemBasicInfo =
balanceUpdateItemBasicInfoDto.BalanceUpdateItemBasicInfos.FirstOrDefault(t => t.ItemCode == entity.Key);
foreach (var item in entity)
{
item.ItemName = balanceUpdateItemBasicInfo.ItemName ?? item.ItemName;
item.ItemDesc1 = balanceUpdateItemBasicInfo.ItemDesc1 ?? item.ItemDesc1;
item.ItemDesc2 = balanceUpdateItemBasicInfo.ItemDesc2 ?? item.ItemDesc2;
}
}
await _repository.UpdateManyAsync(entitys).ConfigureAwait(false);
}
/// <summary> /// <summary>
/// 修改批次 /// 修改批次
/// </summary> /// </summary>
/// <param name="id"></param> /// <param name="id"></param>
/// <param name="lot"></param> /// <param name="lot"></param>
@ -74,19 +113,22 @@ public class BalanceAppService
/// <param name="expireDate"></param> /// <param name="expireDate"></param>
/// <returns></returns> /// <returns></returns>
[HttpPost("update/batch")] [HttpPost("update/batch")]
public virtual async Task UpdateBatchAsync(Guid id, string lot, string supplierBatch, DateTime arriveDate, DateTime produceDate, DateTime expireDate) public virtual async Task UpdateBatchAsync(Guid id, string lot, string supplierBatch, DateTime arriveDate,
DateTime produceDate, DateTime expireDate)
{ {
var entity = await _repository.FindAsync(id).ConfigureAwait(false); var entity = await _repository.FindAsync(id).ConfigureAwait(false);
Check.NotNull(entity, EntityClassName); Check.NotNull(entity, EntityClassName);
var worker = CurrentUser.GetUserName(); var worker = CurrentUser.GetUserName();
var jobNumber = ""; var jobNumber = "";
var docNumber = ""; var docNumber = "";
await _transferLogManager.ChangeBatchAsync(entity, lot, supplierBatch, arriveDate, produceDate, expireDate, worker, jobNumber, docNumber).ConfigureAwait(false); await _transferLogManager
.ChangeBatchAsync(entity, lot, supplierBatch, arriveDate, produceDate, expireDate, worker, jobNumber,
docNumber).ConfigureAwait(false);
await _repository.UpdateAsync(entity).ConfigureAwait(false); await _repository.UpdateAsync(entity).ConfigureAwait(false);
} }
/// <summary> /// <summary>
/// 修改序号 /// 修改序号
/// </summary> /// </summary>
/// <param name="id"></param> /// <param name="id"></param>
/// <param name="serialNumber"></param> /// <param name="serialNumber"></param>
@ -101,7 +143,7 @@ public class BalanceAppService
} }
/// <summary> /// <summary>
/// 修改库位 /// 修改库位
/// </summary> /// </summary>
/// <param name="id"></param> /// <param name="id"></param>
/// <param name="warehouseCode"></param> /// <param name="warehouseCode"></param>
@ -109,7 +151,8 @@ public class BalanceAppService
/// <param name="containerCode"></param> /// <param name="containerCode"></param>
/// <returns></returns> /// <returns></returns>
[HttpPost("update/location")] [HttpPost("update/location")]
public virtual async Task UpdateLocationAsync(Guid id, string warehouseCode, string locationCode, string containerCode) public virtual async Task UpdateLocationAsync(Guid id, string warehouseCode, string locationCode,
string containerCode)
{ {
var entity = await _repository.FindAsync(id).ConfigureAwait(false); var entity = await _repository.FindAsync(id).ConfigureAwait(false);
Check.NotNull(entity, EntityClassName); Check.NotNull(entity, EntityClassName);
@ -122,7 +165,7 @@ public class BalanceAppService
} }
/// <summary> /// <summary>
/// 修改状态 /// 修改状态
/// </summary> /// </summary>
/// <param name="id"></param> /// <param name="id"></param>
/// <param name="status"></param> /// <param name="status"></param>
@ -140,7 +183,7 @@ public class BalanceAppService
} }
/// <summary> /// <summary>
/// 修改过期日期 /// 修改过期日期
/// </summary> /// </summary>
/// <param name="id"></param> /// <param name="id"></param>
/// <param name="expireDate"></param> /// <param name="expireDate"></param>
@ -155,7 +198,7 @@ public class BalanceAppService
} }
/// <summary> /// <summary>
/// 修改托盘标签 /// 修改托盘标签
/// </summary> /// </summary>
/// <param name="id"></param> /// <param name="id"></param>
/// <param name="containerCode"></param> /// <param name="containerCode"></param>
@ -170,7 +213,7 @@ public class BalanceAppService
} }
/// <summary> /// <summary>
/// 可用 /// 可用
/// </summary> /// </summary>
/// <param name="id"></param> /// <param name="id"></param>
/// <returns></returns> /// <returns></returns>
@ -184,7 +227,7 @@ public class BalanceAppService
} }
/// <summary> /// <summary>
/// 不可用 /// 不可用
/// </summary> /// </summary>
/// <param name="id"></param> /// <param name="id"></param>
/// <returns></returns> /// <returns></returns>
@ -198,7 +241,7 @@ public class BalanceAppService
} }
/// <summary> /// <summary>
/// 设置为不可用 根据 库位 零件 箱码 批次 状态 /// 设置为不可用 根据 库位 零件 箱码 批次 状态
/// </summary> /// </summary>
/// <param name="packingCode"></param> /// <param name="packingCode"></param>
/// <param name="itemCode"></param> /// <param name="itemCode"></param>
@ -227,7 +270,7 @@ public class BalanceAppService
} }
/// <summary> /// <summary>
/// 设置为可用 根据 库位 零件 箱码 批次 状态 /// 设置为可用 根据 库位 零件 箱码 批次 状态
/// </summary> /// </summary>
/// <param name="packingCode"></param> /// <param name="packingCode"></param>
/// <param name="itemCode"></param> /// <param name="itemCode"></param>
@ -258,27 +301,30 @@ public class BalanceAppService
#endregion Update #endregion Update
#region Get #region Get
/// <summary> /// <summary>
/// 获取库存余额带标准价格得 /// 获取库存余额带标准价格得
/// </summary> /// </summary>
/// <param name="sfsRequestInput"></param> /// <param name="sfsRequestInput"></param>
/// <param name="includeDetails"></param> /// <param name="includeDetails"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
[HttpPost("get-list")] [HttpPost("get-list")]
public virtual async Task<PagedResultDto<BalanceDTO>> GetBalancePagedListByFilterAsync(SfsInventoryRequestInputBase sfsRequestInput, bool includeDetails = false, public virtual async Task<PagedResultDto<BalanceDTO>> GetBalancePagedListByFilterAsync(
CancellationToken cancellationToken = default) SfsInventoryRequestInputBase sfsRequestInput, bool includeDetails = false,
CancellationToken cancellationToken = default)
{ {
var result =await base.GetPagedListByFilterAsync(sfsRequestInput, includeDetails, cancellationToken); var result = await base.GetPagedListByFilterAsync(sfsRequestInput, includeDetails, cancellationToken);
foreach (var item in result.Items) foreach (var item in result.Items)
{ {
var std = await _stdCostPriceSheetAppService.GetByItemCode(item.ItemCode).ConfigureAwait(false); var std = await _stdCostPriceSheetAppService.GetByItemCode(item.ItemCode).ConfigureAwait(false);
item.StdCostPrice = std == null ? 0 : std.StdCostPrice; item.StdCostPrice = std == null ? 0 : std.StdCostPrice;
} }
return result; return result;
} }
/// <summary> /// <summary>
///
/// </summary> /// </summary>
/// <param name="input"></param> /// <param name="input"></param>
/// <returns></returns> /// <returns></returns>
@ -304,11 +350,11 @@ public class BalanceAppService
dto.ItemDesc2 = item.Desc2; dto.ItemDesc2 = item.Desc2;
dto.Uom = item.BasicUom; dto.Uom = item.BasicUom;
} }
return dtos; return dtos;
} }
/// <summary> /// <summary>
///
/// </summary> /// </summary>
/// <param name="packingCode"></param> /// <param name="packingCode"></param>
/// <param name="itemCode"></param> /// <param name="itemCode"></param>
@ -317,20 +363,23 @@ public class BalanceAppService
/// <exception cref="NotImplementedException"></exception> /// <exception cref="NotImplementedException"></exception>
[HttpGet("item-status")] [HttpGet("item-status")]
[AllowAnonymous] [AllowAnonymous]
public virtual async Task<BalanceDTO> GetByItemLocationAndPackingAsync(string packingCode, string itemCode, string locationCode) public virtual async Task<BalanceDTO> GetByItemLocationAndPackingAsync(string packingCode, string itemCode,
string locationCode)
{ {
var entity = await _repository.FirstOrDefaultAsync(c => var entity = await _repository.FirstOrDefaultAsync(c =>
c.PackingCode == packingCode && c.ItemCode == itemCode && c.LocationCode == locationCode).ConfigureAwait(false); c.PackingCode == packingCode && c.ItemCode == itemCode && c.LocationCode == locationCode)
.ConfigureAwait(false);
if (entity == null) if (entity == null)
{ {
throw new UserFriendlyException($"未找到箱码为 {packingCode},物料代码为 {itemCode},库位代码为 {locationCode} 的库存"); throw new UserFriendlyException($"未找到箱码为 {packingCode},物料代码为 {itemCode},库位代码为 {locationCode} 的库存");
} }
var dto = ObjectMapper.Map<Balance, BalanceDTO>(entity); var dto = ObjectMapper.Map<Balance, BalanceDTO>(entity);
return dto; return dto;
} }
/// <summary> /// <summary>
/// 获取对应的库存 /// 获取对应的库存
/// </summary> /// </summary>
/// <param name="packingCode"></param> /// <param name="packingCode"></param>
/// <param name="itemCode"></param> /// <param name="itemCode"></param>
@ -339,14 +388,17 @@ public class BalanceAppService
/// <returns></returns> /// <returns></returns>
/// <exception cref="NotImplementedException"></exception> /// <exception cref="NotImplementedException"></exception>
[HttpGet("item-loc-packing-status")] [HttpGet("item-loc-packing-status")]
public virtual async Task<BalanceDTO> GetByItemLocationPackingAndStatusAsync(string packingCode, string itemCode, string locationCode, EnumInventoryStatus status) public virtual async Task<BalanceDTO> GetByItemLocationPackingAndStatusAsync(string packingCode, string itemCode,
string locationCode, EnumInventoryStatus status)
{ {
var entity = await _repository.FirstOrDefaultAsync(c => var entity = await _repository.FirstOrDefaultAsync(c =>
c.PackingCode == packingCode && c.ItemCode == itemCode && c.LocationCode == locationCode && c.Status == status).ConfigureAwait(false); c.PackingCode == packingCode && c.ItemCode == itemCode && c.LocationCode == locationCode &&
c.Status == status).ConfigureAwait(false);
if (entity == null) if (entity == null)
{ {
throw new UserFriendlyException($"未找到箱码为 {packingCode},物料代码为 {itemCode},库位代码为 {locationCode} 的库存"); throw new UserFriendlyException($"未找到箱码为 {packingCode},物料代码为 {itemCode},库位代码为 {locationCode} 的库存");
} }
var dto = ObjectMapper.Map<Balance, BalanceDTO>(entity); var dto = ObjectMapper.Map<Balance, BalanceDTO>(entity);
return dto; return dto;
} }
@ -407,14 +459,16 @@ public class BalanceAppService
&& p.Status == status).ConfigureAwait(false); && p.Status == status).ConfigureAwait(false);
if (entity == null) if (entity == null)
{ {
throw new UserFriendlyException($"未找到箱码为 {packingCode},物料代码为 {itemCode},库位代码为 {locationCode},状态为为 {status} 的库存"); throw new UserFriendlyException(
$"未找到箱码为 {packingCode},物料代码为 {itemCode},库位代码为 {locationCode},状态为为 {status} 的库存");
} }
var dto = ObjectMapper.Map<Balance, BalanceDTO>(entity); var dto = ObjectMapper.Map<Balance, BalanceDTO>(entity);
return dto; return dto;
} }
/// <summary> /// <summary>
/// 查找可用物品的库存(此物品库存状态为合格) /// 查找可用物品的库存(此物品库存状态为合格)
/// </summary> /// </summary>
/// <param name="itemCode"></param> /// <param name="itemCode"></param>
/// <returns></returns> /// <returns></returns>
@ -436,35 +490,39 @@ public class BalanceAppService
} }
/// <summary> /// <summary>
/// 获取【库存】根据 库位代码 和 物品代码 /// 获取【库存】根据 库位代码 和 物品代码
/// </summary> /// </summary>
/// <param name="locationCode"></param> /// <param name="locationCode"></param>
/// <param name="itemCode"></param> /// <param name="itemCode"></param>
/// <returns></returns> /// <returns></returns>
[HttpGet("list/by-location-and-item")] [HttpGet("list/by-location-and-item")]
public virtual async Task<List<BalanceDTO>> GetListByLocationCodeAndItemCodeAsync(string locationCode, string itemCode) public virtual async Task<List<BalanceDTO>> GetListByLocationCodeAndItemCodeAsync(string locationCode,
string itemCode)
{ {
var entitys = await _repository.GetListAsync(p => p.LocationCode == locationCode && p.ItemCode == itemCode).ConfigureAwait(false); var entitys = await _repository.GetListAsync(p => p.LocationCode == locationCode && p.ItemCode == itemCode)
.ConfigureAwait(false);
var dtos = ObjectMapper.Map<List<Balance>, List<BalanceDTO>>(entitys); var dtos = ObjectMapper.Map<List<Balance>, List<BalanceDTO>>(entitys);
return dtos; return dtos;
} }
/// <summary> /// <summary>
/// 获取【库存】根据 库位代码 和 物品代码 /// 获取【库存】根据 库位代码 和 物品代码
/// </summary> /// </summary>
/// <param name="erplocationCode"></param> /// <param name="erplocationCode"></param>
/// <param name="itemCode"></param> /// <param name="itemCode"></param>
/// <returns></returns> /// <returns></returns>
[HttpGet("list/by-erplocation-and-item")] [HttpGet("list/by-erplocation-and-item")]
public virtual async Task<List<BalanceDTO>> GetListByErpLocationCodeAndItemCodeAsync(string erplocationCode, string itemCode) public virtual async Task<List<BalanceDTO>> GetListByErpLocationCodeAndItemCodeAsync(string erplocationCode,
string itemCode)
{ {
var entitys = await _repository.GetListAsync(p => p.LocationErpCode == erplocationCode && p.ItemCode == itemCode).ConfigureAwait(false); var entitys = await _repository
.GetListAsync(p => p.LocationErpCode == erplocationCode && p.ItemCode == itemCode).ConfigureAwait(false);
var dtos = ObjectMapper.Map<List<Balance>, List<BalanceDTO>>(entitys); var dtos = ObjectMapper.Map<List<Balance>, List<BalanceDTO>>(entitys);
return dtos; return dtos;
} }
/// <summary> /// <summary>
/// 根据发料任务需求,算出推荐的库存 (在获取时 已经添加预占用) /// 根据发料任务需求,算出推荐的库存 (在获取时 已经去除了预占用)
/// </summary> /// </summary>
/// <param name="input"></param> /// <param name="input"></param>
/// <returns></returns> /// <returns></returns>
@ -480,7 +538,9 @@ public class BalanceAppService
var statuses = input.Statuses; var statuses = input.Statuses;
Logger.LogDebug(traceId + "|Input:" + input); Logger.LogDebug(traceId + "|Input:" + input);
var balances = await _balanceManager.GetRecommendBalancesAsync(traceId, itemCode, qty, locationTypes, locationAreas, statuses).ConfigureAwait(false); var balances = await _balanceManager
.GetRecommendBalancesAsync(traceId, itemCode, qty, locationTypes, locationAreas, statuses)
.ConfigureAwait(false);
var dtos = ObjectMapper.Map<List<Balance>, List<BalanceDTO>>(balances); var dtos = ObjectMapper.Map<List<Balance>, List<BalanceDTO>>(balances);
@ -488,7 +548,7 @@ public class BalanceAppService
} }
/// <summary> /// <summary>
/// 根据发料任务需求的库位,算出推荐的库存 (在获取时 已经添加预占用) /// 根据发料任务需求的库位,算出推荐的库存 (在获取时 已经去除了预占用)
/// </summary> /// </summary>
/// <param name="input"></param> /// <param name="input"></param>
/// <returns></returns> /// <returns></returns>
@ -506,21 +566,26 @@ public class BalanceAppService
var locationDto = await _locationAclService.GetByCodeAsync(location).ConfigureAwait(false); var locationDto = await _locationAclService.GetByCodeAsync(location).ConfigureAwait(false);
if (locationDto != null) if (locationDto != null)
{ {
if(input.LocationAreas==null) if (input.LocationAreas == null)
{ {
input.LocationAreas = new List<string>(); input.LocationAreas = new List<string>();
} }
input.LocationAreas.Add(locationDto.AreaCode); input.LocationAreas.Add(locationDto.AreaCode);
if (input.LocationTypes == null) if (input.LocationTypes == null)
{ {
input.LocationTypes = new List<EnumLocationType>(); input.LocationTypes = new List<EnumLocationType>();
} }
input.LocationTypes.Add(locationDto.Type); input.LocationTypes.Add(locationDto.Type);
} }
} }
Logger.LogDebug(traceId + "|Input:" + input); Logger.LogDebug(traceId + "|Input:" + input);
var balances = await _balanceManager.GetRecommendBalancesByLocationAsync(traceId, itemCode, qty, locations, statuses, input.IsPackingCode).ConfigureAwait(false); var balances = await _balanceManager
.GetRecommendBalancesByLocationAsync(traceId, itemCode, qty, locations, statuses, input.IsPackingCode)
.ConfigureAwait(false);
var dtos = ObjectMapper.Map<List<Balance>, List<BalanceDTO>>(balances); var dtos = ObjectMapper.Map<List<Balance>, List<BalanceDTO>>(balances);
@ -528,7 +593,24 @@ public class BalanceAppService
} }
/// <summary> /// <summary>
/// pda发料执行查询使用 /// 获取可用库存列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
[HttpGet("usable-list")]
public virtual async Task<List<BalanceDTO>> GetUsableListAsync(RecommendBalanceRequestInput input)
{
var inventoryBalances = await _balanceManager
.GetUsableListAsync(input.ItemCode, input.Locations, input.Statuses, true).ConfigureAwait(false);
var dtos = ObjectMapper.Map<List<Balance>, List<BalanceDTO>>(inventoryBalances);
return dtos;
}
/// <summary>
/// pda发料执行查询使用
/// </summary> /// </summary>
/// <param name="input"></param> /// <param name="input"></param>
/// <returns></returns> /// <returns></returns>
@ -539,7 +621,8 @@ public class BalanceAppService
//可以领料 //可以领料
if (input.IsEnablePick != null) if (input.IsEnablePick != null)
{ {
var locations = await _locationAclService.GetListByEnablePickAsync((bool)input.IsEnablePick).ConfigureAwait(false); var locations = await _locationAclService.GetListByEnablePickAsync((bool)input.IsEnablePick)
.ConfigureAwait(false);
var codes = JsonSerializer.Serialize(locations.Select(c => c.Code)); var codes = JsonSerializer.Serialize(locations.Select(c => c.Code));
input.Condition.Filters.Add(new Filter("LocationCode", codes, "In")); input.Condition.Filters.Add(new Filter("LocationCode", codes, "In"));
} }
@ -552,48 +635,51 @@ public class BalanceAppService
input.Condition.Filters.Add(new Filter("LocationCode", codes, "In")); input.Condition.Filters.Add(new Filter("LocationCode", codes, "In"));
} }
var dtos = await GetPagedListByFilterAsync(input, false).ConfigureAwait(false); var dtos = await GetPagedListByFilterAsync(input).ConfigureAwait(false);
return dtos; return dtos;
} }
/// <summary> /// <summary>
/// 查询库存余额 根据 状态集合 库位类别集合 物品代码 箱码 托码 批次 库位 /// 查询库存余额 根据 状态集合 库位类别集合 物品代码 箱码 托码 批次 库位
/// </summary> /// </summary>
/// <param name="balanceManyParameterRequestInput"></param> /// <param name="balanceManyParameterRequestInput"></param>
/// <returns></returns> /// <returns></returns>
[HttpPost("get-by-item-location-packing-container-lot-locationtype-status")] [HttpPost("get-by-item-location-packing-container-lot-locationtype-status")]
public virtual async Task<List<BalanceDTO>> GetListByManyParameter(BalanceManyParameterRequestInput balanceManyParameterRequestInput) public virtual async Task<List<BalanceDTO>> GetListByManyParameter(
BalanceManyParameterRequestInput balanceManyParameterRequestInput)
{ {
var input = new SfsInventoryRequestInputBase() var input = new SfsInventoryRequestInputBase
{ {
MaxResultCount = 1000, MaxResultCount = 1000,
SkipCount = 0, SkipCount = 0,
Sorting = string.Empty, Sorting = string.Empty,
Condition = new Condition() Condition = new Condition { Filters = new List<Filter>() }
{
Filters = new List<Filter>()
}
}; };
if (!string.IsNullOrWhiteSpace(balanceManyParameterRequestInput.ItemCode)) if (!string.IsNullOrWhiteSpace(balanceManyParameterRequestInput.ItemCode))
{ {
input.Condition.Filters.Add(new Filter("ItemCode", balanceManyParameterRequestInput.ItemCode)); input.Condition.Filters.Add(new Filter("ItemCode", balanceManyParameterRequestInput.ItemCode));
} }
if (!string.IsNullOrWhiteSpace(balanceManyParameterRequestInput.LocationCode)) if (!string.IsNullOrWhiteSpace(balanceManyParameterRequestInput.LocationCode))
{ {
input.Condition.Filters.Add(new Filter("LocationCode", balanceManyParameterRequestInput.LocationCode)); input.Condition.Filters.Add(new Filter("LocationCode", balanceManyParameterRequestInput.LocationCode));
} }
if (!string.IsNullOrWhiteSpace(balanceManyParameterRequestInput.PackingCode)) if (!string.IsNullOrWhiteSpace(balanceManyParameterRequestInput.PackingCode))
{ {
input.Condition.Filters.Add(new Filter("PackingCode", balanceManyParameterRequestInput.PackingCode)); input.Condition.Filters.Add(new Filter("PackingCode", balanceManyParameterRequestInput.PackingCode));
} }
if (!string.IsNullOrWhiteSpace(balanceManyParameterRequestInput.ContainerCode)) if (!string.IsNullOrWhiteSpace(balanceManyParameterRequestInput.ContainerCode))
{ {
input.Condition.Filters.Add(new Filter("ContainerCode", balanceManyParameterRequestInput.ContainerCode)); input.Condition.Filters.Add(new Filter("ContainerCode", balanceManyParameterRequestInput.ContainerCode));
} }
if (!string.IsNullOrWhiteSpace(balanceManyParameterRequestInput.Lot)) if (!string.IsNullOrWhiteSpace(balanceManyParameterRequestInput.Lot))
{ {
input.Condition.Filters.Add(new Filter("Lot", balanceManyParameterRequestInput.Lot)); input.Condition.Filters.Add(new Filter("Lot", balanceManyParameterRequestInput.Lot));
} }
//筛选库存状态 //筛选库存状态
if (balanceManyParameterRequestInput.InventoryStatuses.Count > 0) if (balanceManyParameterRequestInput.InventoryStatuses.Count > 0)
{ {
@ -601,6 +687,7 @@ public class BalanceAppService
balanceManyParameterRequestInput.InventoryStatuses); balanceManyParameterRequestInput.InventoryStatuses);
input.Condition.Filters.Add(new Filter("Status", Statuses, "In")); input.Condition.Filters.Add(new Filter("Status", Statuses, "In"));
} }
//筛选库位类型 //筛选库位类型
if (balanceManyParameterRequestInput.LocationTypes.Count > 0) if (balanceManyParameterRequestInput.LocationTypes.Count > 0)
{ {
@ -617,91 +704,115 @@ public class BalanceAppService
} }
/// <summary> /// <summary>
/// 查询库存余额 根据 物品 库位 库位类型 库存状态 批次 /// 查询库存余额 根据 物品 库位 库位类型 库存状态 批次
/// </summary> /// </summary>
/// <param name="listInput"></param> /// <param name="listInput"></param>
/// <returns></returns> /// <returns></returns>
[HttpPost("by-balances-request-many-parameter")] [HttpPost("by-balances-request-many-parameter")]
public async Task<PagedResultDto<BalanceDTO>> GetListByLocationTypeAndInventoryStatusAsync(BalanceListByIssueInputByInventoryStatusAndLocationType listInput) public async Task<PagedResultDto<BalanceDTO>> GetListByLocationTypeAndInventoryStatusAsync(
BalanceListByIssueInputByInventoryStatusAndLocationType listInput)
{ {
var input = new SfsInventoryRequestInputBase() var input = new SfsInventoryRequestInputBase
{ {
MaxResultCount = listInput.pageSize, MaxResultCount = listInput.pageSize,
SkipCount = (listInput.pageIndex - 1) * listInput.pageSize, SkipCount = (listInput.pageIndex - 1) * listInput.pageSize,
Sorting = listInput.sortBy, Sorting = listInput.sortBy,
Condition = new Condition() Condition = new Condition { Filters = new List<Filter>() }
{
Filters = new List<Filter>()
}
}; };
if (!string.IsNullOrWhiteSpace(listInput.itemCode)) if (!string.IsNullOrWhiteSpace(listInput.itemCode))
{ {
input.Condition.Filters.Add(new Filter("ItemCode", listInput.itemCode)); input.Condition.Filters.Add(new Filter("ItemCode", listInput.itemCode));
} }
if (!string.IsNullOrWhiteSpace(listInput.locationCode)) if (!string.IsNullOrWhiteSpace(listInput.locationCode))
{ {
input.Condition.Filters.Add(new Filter("LocationCode", listInput.locationCode)); input.Condition.Filters.Add(new Filter("LocationCode", listInput.locationCode));
} }
if (!string.IsNullOrWhiteSpace(listInput.lot)) if (!string.IsNullOrWhiteSpace(listInput.lot))
{ {
input.Condition.Filters.Add(new Filter("Lot", listInput.lot)); input.Condition.Filters.Add(new Filter("Lot", listInput.lot));
} }
if (!string.IsNullOrWhiteSpace(listInput.packingCode)) if (!string.IsNullOrWhiteSpace(listInput.packingCode))
{ {
input.Condition.Filters.Add(new Filter("PackingCode", listInput.packingCode)); input.Condition.Filters.Add(new Filter("PackingCode", listInput.packingCode));
} }
if (!string.IsNullOrWhiteSpace(listInput.containerCode)) if (!string.IsNullOrWhiteSpace(listInput.containerCode))
{ {
input.Condition.Filters.Add(new Filter("ContainerCode", listInput.containerCode)); input.Condition.Filters.Add(new Filter("ContainerCode", listInput.containerCode));
} }
if (listInput.locationTypes != null && listInput.locationTypes.Any()) if (listInput.locationTypes != null && listInput.locationTypes.Any())
{ {
var locationCodes = (await _locationAclService.GetListByTypesAsync(listInput.locationTypes).ConfigureAwait(false)).Select(t => t.Code).ToList(); var locationCodes =
(await _locationAclService.GetListByTypesAsync(listInput.locationTypes).ConfigureAwait(false))
.Select(t => t.Code).ToList();
if (locationCodes.Any()) if (locationCodes.Any())
{ {
input.Condition.Filters.Add(new Filter("LocationCode", JsonSerializer.Serialize(locationCodes), "In")); input.Condition.Filters.Add(new Filter("LocationCode", JsonSerializer.Serialize(locationCodes), "In"));
} }
} }
if (listInput.inventoryStatuses != null && listInput.inventoryStatuses.Any()) if (listInput.inventoryStatuses != null && listInput.inventoryStatuses.Any())
{ {
input.Condition.Filters.Add(new Filter("Status", JsonSerializer.Serialize(listInput.inventoryStatuses), "In")); input.Condition.Filters.Add(new Filter("Status", JsonSerializer.Serialize(listInput.inventoryStatuses),
"In"));
} }
var balanceDTOs = await GetPagedListByFilterAsync(input, false).ConfigureAwait(false);
var balanceDTOs = await GetPagedListByFilterAsync(input).ConfigureAwait(false);
return balanceDTOs; return balanceDTOs;
} }
/// <summary> /// <summary>
/// 获取 隔离库位 不合格 库存 /// 获取 隔离库位 不合格 库存
/// </summary> /// </summary>
/// <param name="sfsRequestDTO"></param> /// <param name="sfsRequestDTO"></param>
/// <param name="includeDetails"></param> /// <param name="includeDetails"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
[HttpPost("by-hold-location-code-and-no-ok")] [HttpPost("by-hold-location-code-and-no-ok")]
public async Task<PagedResultDto<BalanceDTO>> GetByHoldLocationCodeAndNoOkAsync(SfsInventoryRequestInputBase sfsRequestDTO, bool includeDetails = false, public async Task<PagedResultDto<BalanceDTO>> GetByHoldLocationCodeAndNoOkAsync(
SfsInventoryRequestInputBase sfsRequestDTO, bool includeDetails = false,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var locationInfo = await _locationAclService.GetFirstByTypeAsync(EnumLocationType.HOLD).ConfigureAwait(false); var locationInfo = await _locationAclService.GetFirstByTypeAsync(EnumLocationType.HOLD).ConfigureAwait(false);
sfsRequestDTO.Condition.Filters.Add(new Sfs.Shared.Domain.Filter() { Action = "==", Column = "LocationCode", Logic = EnumFilterLogic.And.ToString(), Value = locationInfo.Code }); sfsRequestDTO.Condition.Filters.Add(new Filter
sfsRequestDTO.Condition.Filters.Add(new Sfs.Shared.Domain.Filter() { Action = "==", Column = "Status", Logic = EnumFilterLogic.And.ToString(), Value = ((int)EnumInventoryStatus.NOK).ToString(), }); {
Action = "==",
Column = "LocationCode",
Logic = EnumFilterLogic.And.ToString(),
Value = locationInfo.Code
});
sfsRequestDTO.Condition.Filters.Add(new Filter
{
Action = "==",
Column = "Status",
Logic = EnumFilterLogic.And.ToString(),
Value = ((int)EnumInventoryStatus.NOK).ToString()
});
Expression<Func<Balance, bool>> expression = sfsRequestDTO.Condition.Filters?.Count > 0 var expression = sfsRequestDTO.Condition.Filters?.Count > 0
? sfsRequestDTO.Condition.Filters.ToLambda<Balance>() ? sfsRequestDTO.Condition.Filters.ToLambda<Balance>()
: p => true; : p => true;
return await GetPagedListAsync(expression, sfsRequestDTO.SkipCount, sfsRequestDTO.MaxResultCount, sfsRequestDTO.Sorting, includeDetails, cancellationToken).ConfigureAwait(false); return await GetPagedListAsync(expression, sfsRequestDTO.SkipCount, sfsRequestDTO.MaxResultCount,
sfsRequestDTO.Sorting, includeDetails, cancellationToken).ConfigureAwait(false);
} }
/// <summary> /// <summary>
/// 获取 【实际库存余额】(不包含预计入,抛出预计出) /// 获取 【实际库存余额】(不包含预计入,抛出预计出)
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[HttpPost("get-real-qty-by-packing-and-item-and-location-and-status")] [HttpPost("get-real-qty-by-packing-and-item-and-location-and-status")]
public async Task<BalanceDTO> GetRealQtyByPackingCodeAndItemCodeAndLocationCodeAndStatusAsync(string packingCode, string itemCode, string locationCode, EnumInventoryStatus status) public async Task<BalanceDTO> GetRealQtyByPackingCodeAndItemCodeAndLocationCodeAndStatusAsync(string packingCode,
string itemCode, string locationCode, EnumInventoryStatus status)
{ {
var entity = await _repository.FirstOrDefaultAsync(c => var entity = await _repository.FirstOrDefaultAsync(c =>
c.PackingCode == packingCode && c.ItemCode == itemCode && c.LocationCode == locationCode && c.Status == status).ConfigureAwait(false); c.PackingCode == packingCode && c.ItemCode == itemCode && c.LocationCode == locationCode &&
c.Status == status).ConfigureAwait(false);
if (entity == null) if (entity == null)
{ {
throw new UserFriendlyException($"未找到箱码为 {packingCode},物料代码为 {itemCode},库位代码为 {locationCode} 的库存"); throw new UserFriendlyException($"未找到箱码为 {packingCode},物料代码为 {itemCode},库位代码为 {locationCode} 的库存");
@ -714,7 +825,8 @@ public class BalanceAppService
} }
[HttpGet("list-by-location-status")] [HttpGet("list-by-location-status")]
public async Task<List<BalanceDTO>> GetListByLocationCodeAndStatusAsync(string locationCode, EnumInventoryStatus status) public async Task<List<BalanceDTO>> GetListByLocationCodeAndStatusAsync(string locationCode,
EnumInventoryStatus status)
{ {
var entities = await _repository.GetListAsync( var entities = await _repository.GetListAsync(
c => c.LocationCode == locationCode && c.Status == status c => c.LocationCode == locationCode && c.Status == status
@ -728,17 +840,18 @@ public class BalanceAppService
#endregion Get #endregion Get
#region export #region export
/// <summary> /// <summary>
/// 导出数据 /// 导出数据
/// </summary> /// </summary>
[HttpPost("export")] [HttpPost("export")]
public override async Task<IActionResult> ExportAsync(SfsInventoryRequestInputBase input) public override async Task<IActionResult> ExportAsync(SfsInventoryRequestInputBase input)
{ {
var expression = input.Condition.Filters?.Count > 0 var expression = input.Condition.Filters?.Count > 0
? input.Condition.Filters.ToLambda<Balance>() ? input.Condition.Filters.ToLambda<Balance>()
: p => true; : p => true;
var entities = await _repository.GetPagedListAsync(expression, input.SkipCount, input.MaxResultCount, var entities = await _repository.GetPagedListAsync(expression, input.SkipCount, input.MaxResultCount,
input.Sorting, true).ConfigureAwait(false); input.Sorting, true).ConfigureAwait(false);
var list = ObjectMapper.Map<List<Balance>, List<BalanceDTO>>(entities); var list = ObjectMapper.Map<List<Balance>, List<BalanceDTO>>(entities);
//var hasDetails = typeof(TEntity) is SfsMasterAggregateRootBase<TDetail> detailEntity; //var hasDetails = typeof(TEntity) is SfsMasterAggregateRootBase<TDetail> detailEntity;
@ -760,47 +873,6 @@ public class BalanceAppService
return ExportImportService.Export(list, detailsProptyName: hasDetails ? nameof(EmptyDetail) : null); return ExportImportService.Export(list, detailsProptyName: hasDetails ? nameof(EmptyDetail) : null);
} }
#endregion
/// <summary>
/// 库存余额更新物品基础信息
/// </summary>
[HttpPost("update/item-basic-info")]
public async Task UpdateItemBasicInfoAsync(BalanceUpdateItemBasicInfoDto balanceUpdateItemBasicInfoDto)
{
//停用,可能用其他处理方案
return;
// 物品编码
var itemCodes = balanceUpdateItemBasicInfoDto.BalanceUpdateItemBasicInfos?.Select(c => c.ItemCode);
itemCodes = itemCodes?.Where(t => string.IsNullOrWhiteSpace(t) == false);
if (itemCodes == null || itemCodes.Any() == false)
{
return;
}
// 获取库存余额
var entitys = await _repository.GetListAsync(p =>
itemCodes.Contains(p.ItemCode)).ConfigureAwait(false);
if (entitys.Count <= 0)
{
return;
}
// 库存余额更新物品基础信息
var entitysGroup = entitys.GroupBy(t => t.ItemCode);
foreach (var entity in entitysGroup)
{
var balanceUpdateItemBasicInfo = balanceUpdateItemBasicInfoDto.BalanceUpdateItemBasicInfos.FirstOrDefault(t => t.ItemCode == entity.Key);
foreach (var item in entity)
{
item.ItemName = balanceUpdateItemBasicInfo.ItemName ?? item.ItemName;
item.ItemDesc1 = balanceUpdateItemBasicInfo.ItemDesc1 ?? item.ItemDesc1;
item.ItemDesc2 = balanceUpdateItemBasicInfo.ItemDesc2 ?? item.ItemDesc2;
}
}
await _repository.UpdateManyAsync(entitys).ConfigureAwait(false);
}
#endregion
} }

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

@ -459,15 +459,13 @@ public class BalanceManager : DomainService, IBalanceManager
#region GetRecommendList #region GetRecommendList
/// <summary> /// <summary>
/// 根据库位获取推荐库位 /// 根据库位获取推荐库位
/// </summary> /// </summary>
/// <param name="traceId"></param> /// <param name="traceId"></param>
/// <param name="itemCode"></param> /// <param name="itemCode"></param>
/// <param name="requestQty"></param> /// <param name="requestQty"></param>
/// <param name="validLocationTypes"></param> /// <param name="validLocations"></param>
/// <param name="validLocationAreas"></param>
/// <param name="validStatuses"></param> /// <param name="validStatuses"></param>
/// <returns></returns> /// <returns></returns>
/// <exception cref="UserFriendlyException"></exception> /// <exception cref="UserFriendlyException"></exception>
@ -770,6 +768,109 @@ public class BalanceManager : DomainService, IBalanceManager
#endregion #endregion
} }
/// <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>> GetUsableListAsync(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)
&& 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();
return usableBalances;
}
private decimal GetRecommendQty(Guid traceId, decimal requestQty, decimal remainingQty, Balance usableBalance, LocationDTO location, ItemStoreRelationDTO itemStoreRelation) private decimal GetRecommendQty(Guid traceId, decimal requestQty, decimal remainingQty, Balance usableBalance, LocationDTO location, ItemStoreRelationDTO itemStoreRelation)
{ {
var balanceQty = usableBalance.Qty; var balanceQty = usableBalance.Qty;

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

@ -9,22 +9,23 @@ namespace Win_in.Sfs.Wms.Inventory.Domain;
public interface IBalanceManager : IDomainService public interface IBalanceManager : IDomainService
{ {
/// <summary> /// <summary>
/// 入库 /// 入库
/// </summary> /// </summary>
/// <param name="transaction"></param> /// <param name="transaction"></param>
/// <returns></returns> /// <returns></returns>
Task<Balance> InboundAsync(Transaction transaction, ItemBasicDTO item, LocationDTO location); Task<Balance> InboundAsync(Transaction transaction, ItemBasicDTO item, LocationDTO location);
/// <summary> /// <summary>
/// 出库 /// 出库
/// </summary> /// </summary>
/// <param name="transaction"></param> /// <param name="transaction"></param>
/// <returns></returns> /// <returns></returns>
Task<Balance> OutboundAsync(Transaction transaction, ItemBasicDTO item, LocationDTO location); Task<Balance> OutboundAsync(Transaction transaction, ItemBasicDTO item, LocationDTO location);
Task<List<Balance>> GetRecommendBalancesAsync(Guid traceId, string itemCode, decimal requestQty, Task<List<Balance>> GetRecommendBalancesAsync(Guid traceId, string itemCode, decimal requestQty,
List<EnumLocationType> validLocationTypes, List<string> validLocationAreas, List<EnumInventoryStatus> validStatuses); List<EnumLocationType> validLocationTypes, List<string> validLocationAreas,
List<EnumInventoryStatus> validStatuses);
Task<List<Balance>> GetListByLocationAsync(string locationCode); Task<List<Balance>> GetListByLocationAsync(string locationCode);
@ -32,6 +33,22 @@ public interface IBalanceManager : IDomainService
Task<List<Balance>> GetListByItemAndLocationAsync(string itemCode, string locationCode); Task<List<Balance>> GetListByItemAndLocationAsync(string itemCode, string locationCode);
Task<List<string>> GetItemCodesOfLocationAsync(string locationCode); Task<List<string>> GetItemCodesOfLocationAsync(string locationCode);
Task<Balance> ModifyAsync(Balance balance); 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,bool ispackingcode); 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, bool ispackingcode);
/// <summary>
/// 获取可用库存列表
/// </summary>
/// <param name="itemCode"></param>
/// <param name="validLocations"></param>
/// <param name="validStatuses"></param>
/// <param name="isRemovePackingCode"></param>
/// <returns></returns>
Task<List<Balance>> GetUsableListAsync(string itemCode,
List<string> validLocations,
List<EnumInventoryStatus> validStatuses, bool isRemovePackingCode);
} }

4
be/Modules/Shared/src/Win_in.Sfs.Shared.Domain.Shared/Enums/Store/EnumIssueType.cs

@ -12,10 +12,10 @@ public enum EnumIssueType
/// <summary> /// <summary>
/// 按箱 叫料 /// 按箱 叫料
/// </summary> /// </summary>
Box=1, BoxQty=1,
/// <summary> /// <summary>
/// 按数量 叫料 /// 按数量 叫料
/// </summary> /// </summary>
Num=2, Qty=2,
} }

1
be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application.Contracts/Jobs/IssueJobs/InjectionJobs/Inputs/InjectionJobEditInput.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Win_in.Sfs.Shared.Domain; using Win_in.Sfs.Shared.Domain;
using Win_in.Sfs.Shared.Domain.Shared; using Win_in.Sfs.Shared.Domain.Shared;
using Win_in.Sfs.Shared.Domain.Shared.Enums.Store;
namespace Win_in.Sfs.Wms.Store.Application.Contracts; namespace Win_in.Sfs.Wms.Store.Application.Contracts;

2
be/Modules/Store/src/Win_in.Sfs.Wms.Store.Domain/Requests/MaterialRequests/InjectionRequests/InjectionRequestManager.cs

@ -42,7 +42,7 @@ public class InjectionRequestManager
entity.Submit(); entity.Submit();
entity.Agree(); entity.Agree();
entity.RequestStatus = EnumRequestStatus.Partial; entity.RequestStatus = EnumRequestStatus.Partial;
await LocalEventBus.PublishAsync(new SfsHandledEntityEventData<InjectionRequest>(entity), false) await LocalEventBus.PublishAsync(new SfsHandledEntityEventData<InjectionRequest>(entity),false)
.ConfigureAwait(false); .ConfigureAwait(false);
await _repository.InsertAsync(entity).ConfigureAwait(false); await _repository.InsertAsync(entity).ConfigureAwait(false);
return entity; return entity;

170
be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/Requests/InjectionRequestEventHandler.cs

@ -76,11 +76,11 @@ public class InjectionRequestEventHandler
switch (entity.Type) switch (entity.Type)
{ {
case nameof(EnumIssueType.Box): case nameof(EnumIssueType.BoxQty):
injectionJobs =await CreateInjectionJobWithBoxQtyTypeAsync(entity).ConfigureAwait(false);
break; break;
case nameof(EnumIssueType.Num): case nameof(EnumIssueType.Qty):
injectionJobs = await CreateInjectionJobWithBoxTypeAsync(entity).ConfigureAwait(false); injectionJobs = await CreateInjectionJobWithQtyTypeAsync(entity).ConfigureAwait(false);
break; break;
} }
@ -123,14 +123,11 @@ public class InjectionRequestEventHandler
/// <param name="injectionRequest"></param> /// <param name="injectionRequest"></param>
/// <returns></returns> /// <returns></returns>
/// <exception cref="UserFriendlyException"></exception> /// <exception cref="UserFriendlyException"></exception>
private async Task<List<InjectionJobEditInput>> CreateInjectionJobWithBoxTypeAsync private async Task<List<InjectionJobEditInput>> CreateInjectionJobWithQtyTypeAsync
(InjectionRequest injectionRequest) (InjectionRequest injectionRequest)
{ {
var jobs = new List<InjectionJobEditInput>(); var jobs = new List<InjectionJobEditInput>();
var transactionType = await TransactionTypeAclService
.GetByTransTypeAsync(EnumTransType.Issue, EnumTransSubType.None).ConfigureAwait(false); //库存事务
var toLocationCodes = injectionRequest.Details.Select(p => p.ToLocationCode).Distinct().ToList(); //所有发送库位的集合 var toLocationCodes = injectionRequest.Details.Select(p => p.ToLocationCode).Distinct().ToList(); //所有发送库位的集合
var toLocations = await _locationAppService.GetByCodesAsync(toLocationCodes).ConfigureAwait(false); //所有库位的集合 var toLocations = await _locationAppService.GetByCodesAsync(toLocationCodes).ConfigureAwait(false); //所有库位的集合
@ -143,7 +140,7 @@ public class InjectionRequestEventHandler
//创建详情 //创建详情
var jobDetails = var jobDetails =
await CreateInjectionJobDetailInputsWithBoxTypeAsync(injectionRequest, injectionRequestDetail, await CreateInjectionJobDetailInputsWithQtyTypeAsync(injectionRequest, injectionRequestDetail,
toLocation.LocationGroupCode).ConfigureAwait(false); toLocation.LocationGroupCode).ConfigureAwait(false);
if (!jobDetails.Any()) if (!jobDetails.Any())
{ {
@ -155,7 +152,7 @@ public class InjectionRequestEventHandler
var job = jobs.FirstOrDefault(p => p.WorkGroupCode == fromLocation?.WorkGroupCode); var job = jobs.FirstOrDefault(p => p.WorkGroupCode == fromLocation?.WorkGroupCode);
if (job == null || job.Details.Any(p => p.ToLocationCode != injectionRequestDetail.ToLocationCode)) if (job == null || job.Details.Any(p => p.ToLocationCode != injectionRequestDetail.ToLocationCode))
{ {
job = await BuildInjectionJobCreateInputWithBoxTypeAsync(injectionRequest, fromLocation).ConfigureAwait(false); job = await BuildInjectionJobCreateInputWithQtyTypeAsync(injectionRequest, fromLocation).ConfigureAwait(false);
jobs.Add(job); jobs.Add(job);
} }
@ -204,7 +201,7 @@ public class InjectionRequestEventHandler
/// <param name="injectionRequest"></param> /// <param name="injectionRequest"></param>
/// <param name="fromLocation"></param> /// <param name="fromLocation"></param>
/// <returns></returns> /// <returns></returns>
private async Task<InjectionJobEditInput> BuildInjectionJobCreateInputWithBoxTypeAsync(InjectionRequest injectionRequest, private async Task<InjectionJobEditInput> BuildInjectionJobCreateInputWithQtyTypeAsync(InjectionRequest injectionRequest,
LocationDTO fromLocation) LocationDTO fromLocation)
{ {
InjectionJobEditInput job; InjectionJobEditInput job;
@ -235,7 +232,7 @@ public class InjectionRequestEventHandler
/// <param name="toLocationGroupCode"></param> /// <param name="toLocationGroupCode"></param>
/// <returns></returns> /// <returns></returns>
/// <exception cref="UserFriendlyException"></exception> /// <exception cref="UserFriendlyException"></exception>
private async Task<List<InjectionJobDetailInput>> CreateInjectionJobDetailInputsWithBoxTypeAsync( private async Task<List<InjectionJobDetailInput>> CreateInjectionJobDetailInputsWithQtyTypeAsync(
InjectionRequest injectionRequest, InjectionRequest injectionRequest,
InjectionRequestDetail injectionRequestDetail, string toLocationGroupCode) InjectionRequestDetail injectionRequestDetail, string toLocationGroupCode)
{ {
@ -269,7 +266,7 @@ public class InjectionRequestEventHandler
foreach (var recommend in recommendList) foreach (var recommend in recommendList)
{ {
//拿走需求量 //拿走需求量
var detail = await BuildInjectionJobDetailWithBoxTypeAsync(injectionRequestDetail, recommend, toLocationGroupCode) var detail = await BuildInjectionJobDetailWithQtyTypeAsync(injectionRequestDetail, recommend, toLocationGroupCode)
.ConfigureAwait(false); .ConfigureAwait(false);
if (injectionRequest.UseOnTheWayLocation) if (injectionRequest.UseOnTheWayLocation)
{ {
@ -297,7 +294,7 @@ public class InjectionRequestEventHandler
/// <param name="balance"></param> /// <param name="balance"></param>
/// <param name="toLocationGroupCode"></param> /// <param name="toLocationGroupCode"></param>
/// <returns></returns> /// <returns></returns>
private async Task<InjectionJobDetailInput> BuildInjectionJobDetailWithBoxTypeAsync( private async Task<InjectionJobDetailInput> BuildInjectionJobDetailWithQtyTypeAsync(
InjectionRequestDetail injectionRequestDetail, BalanceDTO balance, string toLocationGroupCode) InjectionRequestDetail injectionRequestDetail, BalanceDTO balance, string toLocationGroupCode)
{ {
//ProductionLineDTO prodLine = await _productionLineAppService.GetByLocationGroupCodeAsync(toLocationGroupCode).ConfigureAwait(false); //ProductionLineDTO prodLine = await _productionLineAppService.GetByLocationGroupCodeAsync(toLocationGroupCode).ConfigureAwait(false);
@ -340,7 +337,150 @@ public class InjectionRequestEventHandler
#region 按箱叫料 #region 按箱叫料
/// <summary>
/// 创建注塑任务
/// </summary>
/// <param name="injectionRequest"></param>
/// <returns></returns>
/// <exception cref="UserFriendlyException"></exception>
private async Task<List<InjectionJobEditInput>> CreateInjectionJobWithBoxQtyTypeAsync
(InjectionRequest injectionRequest)
{
var inputJobs = new List<InjectionJobEditInput>();
//已用的库存的箱码集合
var useBalanceList = new List<string>();
var groupByItemCodeAndLocationCode =
injectionRequest.Details.GroupBy(p => new { p.ItemCode, p.ToLocationCode });
foreach (var locationCodeItemCodeGroup in groupByItemCodeAndLocationCode)
{
var inputDetails = injectionRequest.Details.Where(p =>
p.ItemCode == locationCodeItemCodeGroup.Key.ItemCode &&
p.ToLocationCode == locationCodeItemCodeGroup.Key.ToLocationCode);
var inputDetailTemplate = inputDetails.First();
//获取请求下 这个零件和这个库位一个需要多少箱
var sumBoxQty = inputDetails.Sum(p => p.BoxQty);
//获取生产线
var productionLineDto = await _productionLineAppService
.GetByLocationCodeAsync(inputDetails.First().ToLocationCode).ConfigureAwait(false);
if (productionLineDto == null)
{
throw new UserFriendlyException($"库位【{inputDetailTemplate.ToLocationCode}】没有对应的【生产线】");
}
var productLineCodeAndItemCode = (await _productionLineItemAppService
.GetByProductLineCodeAndItemCodeAsync(productionLineDto.Code, inputDetailTemplate.ItemCode)
.ConfigureAwait(false));
if (productLineCodeAndItemCode == null)
{
throw new UserFriendlyException(
$"物品代码【{inputDetailTemplate.ItemCode}】在生产线【{productionLineDto.Code}】中没有对应的【生产线物品关系】");
}
//获取可用库存
var input = new RecommendBalanceRequestInput
{
ItemCode = locationCodeItemCodeGroup.Key.ItemCode,
Qty = decimal.MaxValue,
Statuses = new EditableList<EnumInventoryStatus> { EnumInventoryStatus.OK },
Locations = JsonSerializer.Deserialize<List<string>>(productLineCodeAndItemCode
.RawLocationCodeListJson)
};
//所有可用库存
var usableList = await _balanceAppService.GetUsableListAsync(input).ConfigureAwait(false);
usableList=usableList.Where(p => !useBalanceList.Contains(p.PackingCode)).ToList();
var firstUsable = usableList.First();
useBalanceList.Add(firstUsable.PackingCode);
usableList.Remove(firstUsable);
for (int i = 0; i < sumBoxQty; i++)
{
var injectionJobEditInput =
await BuildInjectionJobCreateInputWithBoxQtyTypeAsync(injectionRequest, inputDetailTemplate,
firstUsable)
.ConfigureAwait(false);
inputJobs.Add(injectionJobEditInput);
}
}
return inputJobs;
}
/// <summary>
/// 构造注塑任务
/// </summary>
/// <param name="injectionRequest"></param>
/// <param name="injectionRequestDetail"></param>
/// <param name="balanceDtos"></param>
/// <returns></returns>
private async Task<InjectionJobEditInput> BuildInjectionJobCreateInputWithBoxQtyTypeAsync(InjectionRequest injectionRequest,
InjectionRequestDetail injectionRequestDetail,BalanceDTO balanceDtos)
{
InjectionJobEditInput job;
job = ObjectMapper.Map<InjectionRequest, InjectionJobEditInput>(injectionRequest);
job.JobType = EnumJobType.IssueJob;
job.JobStatus = EnumJobStatus.Open;
job.WorkGroupCode = injectionRequestDetail.ToLocationGroup;
job.WarehouseCode = injectionRequestDetail.ToWarehouseCode;
job.ProdLine = injectionRequestDetail.ProdLine;
job.Worker = injectionRequest.Worker;
job.InjectionRequestNumber = injectionRequest.Number;
job.Details.Add(await BuildInjectionJobDetailWithBoxQtyTypeAsync(injectionRequestDetail, balanceDtos).ConfigureAwait(false));
await Task.CompletedTask.ConfigureAwait(false);
return job;
}
/// <summary>
/// 构造注塑任务明细
/// </summary>
/// <param name="injectionRequestDetail"></param>
/// <param name="balance"></param>
/// <param name="toLocationGroupCode"></param>
/// <returns></returns>
private async Task<InjectionJobDetailInput> BuildInjectionJobDetailWithBoxQtyTypeAsync(
InjectionRequestDetail injectionRequestDetail, BalanceDTO balance)
{
//ProductionLineDTO prodLine = await _productionLineAppService.GetByLocationGroupCodeAsync(toLocationGroupCode).ConfigureAwait(false);
var detail = ObjectMapper.Map<BalanceDTO, InjectionJobDetailInput>(balance);
detail.RequestLocationCode = injectionRequestDetail.ToLocationCode;
detail.WorkStation = injectionRequestDetail.WorkStation;
detail.ExpiredTime = injectionRequestDetail.ExpiredTime;
detail.PositionCode = injectionRequestDetail.PositionCode;
detail.RecommendType = injectionRequestDetail.RecommendType;
detail.RecommendPackingCode = balance.PackingCode;
detail.RecommendContainerCode = balance.ContainerCode;
detail.RecommendSupplierBatch = balance.SupplierBatch;
detail.RecommendProduceDate = balance.ProduceDate;
detail.RecommendExpireDate = balance.ExpireDate;
detail.RecommendLot = balance.Lot;
detail.RecommendProduceDate = balance.ProduceDate;
detail.RecommendArriveDate = balance.ArriveDate;
detail.RecommendFromLocationArea = balance.LocationArea;
detail.RecommendFromLocationCode = balance.LocationCode;
detail.RecommendFromLocationErpCode = balance.LocationErpCode;
detail.RecommendFromLocationGroup = balance.LocationGroup;
detail.RecommendFromWarehouseCode = balance.WarehouseCode;
detail.RecommendQty = balance.Qty;
detail.Uom = balance.Uom;
detail.ToLocationCode = injectionRequestDetail.ToLocationCode;
detail.ToLocationErpCode = injectionRequestDetail.ToLocationErpCode;
detail.ToLocationArea = injectionRequestDetail.ToLocationArea;
detail.ToWarehouseCode = injectionRequestDetail.ToWarehouseCode;
//detail.ProdLine = prodLine == null ? toLocationGroupCode : prodLine.Code;
detail.ProdLine = injectionRequestDetail.ToLocationCode;
await Task.CompletedTask.ConfigureAwait(false);
return detail;
}
#endregion #endregion

2
be/WZC2.sln.DotSettings

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeEditing/SuppressNullableWarningFix/Enabled/@EntryValue">False</s:Boolean></wpf:ResourceDictionary>
Loading…
Cancel
Save