diff --git a/be/DataExchange/Fawtyg/Win_in.Sfs.Wms.DataExchange.Fawtyg.MesAgent/Incoming/MesIncomingBackgroundWorker.cs b/be/DataExchange/Fawtyg/Win_in.Sfs.Wms.DataExchange.Fawtyg.MesAgent/Incoming/MesIncomingBackgroundWorker.cs index 667047a14..3a919536a 100644 --- a/be/DataExchange/Fawtyg/Win_in.Sfs.Wms.DataExchange.Fawtyg.MesAgent/Incoming/MesIncomingBackgroundWorker.cs +++ b/be/DataExchange/Fawtyg/Win_in.Sfs.Wms.DataExchange.Fawtyg.MesAgent/Incoming/MesIncomingBackgroundWorker.cs @@ -45,72 +45,54 @@ public class MesIncomingBackgroundWorker : AsyncPeriodicBackgroundWorkerBase return; } - //Logger.LogInformation($"Read MesOut");//缴库 - //var mesOutReader = workerContext.ServiceProvider.GetRequiredService(); - //var mesOutConverter = workerContext.ServiceProvider.GetRequiredService(); - //var TransferNoteConverter = workerContext.ServiceProvider.GetRequiredService(); - ////读取mes缴库 - //var mesOutsFromExternalList = await mesOutReader.ReadAsync().ConfigureAwait(false); - //var mesOutsFromExternalList_ProductReceipt = mesOutsFromExternalList.Where(r => r.DataType == EnumIncomingDataType.ProductReceipt.ToString()).ToList(); - //var mesOutsFromExternalList_TransferNote = mesOutsFromExternalList.Where(r => r.DataType == EnumIncomingDataType.TransferNote.ToString()).ToList(); - ////转换缴库数据(如果有质量补得数据直接生产移库数据移到客户库位) - //await mesOutConverter.ConvertAsync(mesOutsFromExternalList_ProductReceipt).ConfigureAwait(false); - //if (mesOutsFromExternalList_TransferNote.Count > 0)//如果有质量补则生产储位调拨任务 - //{ - // await TransferNoteConverter.ConvertAsync(mesOutsFromExternalList_TransferNote).ConfigureAwait(false); - //} - - - //上海和安徽无此接口 - //Logger.LogInformation($"Read PullTask");//拉动任务 - //var pullTaskReader = workerContext.ServiceProvider.GetRequiredService(); - //var pullTaskConverter = workerContext.ServiceProvider.GetRequiredService(); - ////读取并保存PullTask - //var pullTaskFromExternalList = await pullTaskReader.ReadAsync().ConfigureAwait(false); - ////转换PullTask - //await pullTaskConverter.ConvertAsync(pullTaskFromExternalList).ConfigureAwait(false); - //Logger.LogInformation($"Read Scrap");//报废 - - //var scrapReader = workerContext.ServiceProvider.GetRequiredService(); - //var scrapConverter = workerContext.ServiceProvider.GetRequiredService(); - ////读取并保存Scrap - //var scrapsFromExternalList = await scrapReader.ReadAsync().ConfigureAwait(false); - ////转换Scrap - //await scrapConverter.ConvertAsync(scrapsFromExternalList).ConfigureAwait(false); - - //上海和安徽无此接口 - //Logger.LogInformation($"Read Issue"); - //var pckHandleService = workerContext.ServiceProvider.GetRequiredService(); - //var pckConverter = workerContext.ServiceProvider.GetRequiredService(); - ////读取并保持Pck - //var pcksFromExternalList = await pckHandleService.ReadAsync().ConfigureAwait(false); - ////转换Pck - //await pckConverter.ConvertAsync(pcksFromExternalList).ConfigureAwait(false); - - //Logger.LogInformation($"Read BackFlush");//耗用单 - //var BackFlushReader = workerContext.ServiceProvider.GetRequiredService(); - //var BackFlushConverter = workerContext.ServiceProvider.GetRequiredService(); - ////读取并保存BackFlush - //var backFlushsFromExternalList = await BackFlushReader.ReadAsync().ConfigureAwait(false); - ////转换BackFlush - //await BackFlushConverter.ConvertAsync(backFlushsFromExternalList).ConfigureAwait(false); - - - //Logger.LogInformation($"Read TransferNote");//储位调拨 - //var TransferNoteReader = workerContext.ServiceProvider.GetRequiredService(); - //// var TransferNoteConverter = workerContext.ServiceProvider.GetRequiredService(); - ////读取并保存TransferNote - //var transferNoteFromExternalList = await TransferNoteReader.ReadAsync().ConfigureAwait(false); - ////转换TransferNote - //await TransferNoteConverter.ConvertAsync(transferNoteFromExternalList).ConfigureAwait(false); + Logger.LogInformation($"Read MesOut");//缴库 + var mesOutReader = workerContext.ServiceProvider.GetRequiredService(); + var mesOutConverter = workerContext.ServiceProvider.GetRequiredService(); + var TransferNoteConverter = workerContext.ServiceProvider.GetRequiredService(); + //读取mes缴库 + var mesOutsFromExternalList = await mesOutReader.ReadAsync().ConfigureAwait(false); + var mesOutsFromExternalList_ProductReceipt = mesOutsFromExternalList.Where(r => r.DataType == EnumIncomingDataType.ProductReceipt.ToString()).ToList(); + var mesOutsFromExternalList_TransferNote = mesOutsFromExternalList.Where(r => r.DataType == EnumIncomingDataType.TransferNote.ToString()).ToList(); + //转换缴库数据(如果有质量补得数据直接生产移库数据移到客户库位) + await mesOutConverter.ConvertAsync(mesOutsFromExternalList_ProductReceipt).ConfigureAwait(false); + if (mesOutsFromExternalList_TransferNote.Count > 0)//如果有质量补则生产储位调拨任务 + { + await TransferNoteConverter.ConvertAsync(mesOutsFromExternalList_TransferNote).ConfigureAwait(false); + } - //Logger.LogInformation($"Read Frozen");//冻结解冻 - //var FrozenReader = workerContext.ServiceProvider.GetRequiredService(); - //var FrozenConverter = workerContext.ServiceProvider.GetRequiredService(); - ////读取并保存Frozen - //var mesNoteFromExternalList = await FrozenReader.ReadAsync().ConfigureAwait(false); - ////转换Frozen - //await FrozenConverter.ConvertAsync(mesNoteFromExternalList).ConfigureAwait(false); + Logger.LogInformation($"Read Scrap");//报废 + var scrapReader = workerContext.ServiceProvider.GetRequiredService(); + var scrapConverter = workerContext.ServiceProvider.GetRequiredService(); + //读取并保存Scrap + var scrapsFromExternalList = await scrapReader.ReadAsync().ConfigureAwait(false); + //转换Scrap + await scrapConverter.ConvertAsync(scrapsFromExternalList).ConfigureAwait(false); + + + Logger.LogInformation($"Read BackFlush");//耗用单 + var BackFlushReader = workerContext.ServiceProvider.GetRequiredService(); + var BackFlushConverter = workerContext.ServiceProvider.GetRequiredService(); + //读取并保存BackFlush + var backFlushsFromExternalList = await BackFlushReader.ReadAsync().ConfigureAwait(false); + //转换BackFlush + await BackFlushConverter.ConvertAsync(backFlushsFromExternalList).ConfigureAwait(false); + + + Logger.LogInformation($"Read TransferNote");//储位调拨 + var TransferNoteReader = workerContext.ServiceProvider.GetRequiredService(); + // var TransferNoteConverter = workerContext.ServiceProvider.GetRequiredService(); + //读取并保存TransferNote + var transferNoteFromExternalList = await TransferNoteReader.ReadAsync().ConfigureAwait(false); + //转换TransferNote + await TransferNoteConverter.ConvertAsync(transferNoteFromExternalList).ConfigureAwait(false); + + Logger.LogInformation($"Read Frozen");//冻结解冻 + var FrozenReader = workerContext.ServiceProvider.GetRequiredService(); + var FrozenConverter = workerContext.ServiceProvider.GetRequiredService(); + //读取并保存Frozen + var mesNoteFromExternalList = await FrozenReader.ReadAsync().ConfigureAwait(false); + //转换Frozen + await FrozenConverter.ConvertAsync(mesNoteFromExternalList).ConfigureAwait(false); Logger.LogInformation($"Read Delivery");//成品发运 @@ -130,7 +112,28 @@ public class MesIncomingBackgroundWorker : AsyncPeriodicBackgroundWorkerBase var callMtlFromExternalList = await CallMtlReader.ReadAsync().ConfigureAwait(false); //转换Delivery await CallMtlConverter.ConvertAsync(callMtlFromExternalList).ConfigureAwait(false); + Logger.LogInformation($"Completed: Handling {Incoming}"); + + #region 未启用接口启用时需要看逻辑修改 + //上海和安徽无此接口 + //Logger.LogInformation($"Read PullTask");//拉动任务 + //var pullTaskReader = workerContext.ServiceProvider.GetRequiredService(); + //var pullTaskConverter = workerContext.ServiceProvider.GetRequiredService(); + ////读取并保存PullTask + //var pullTaskFromExternalList = await pullTaskReader.ReadAsync().ConfigureAwait(false); + ////转换PullTask + //await pullTaskConverter.ConvertAsync(pullTaskFromExternalList).ConfigureAwait(false); + + //上海和安徽无此接口 + //Logger.LogInformation($"Read Issue"); + //var pckHandleService = workerContext.ServiceProvider.GetRequiredService(); + //var pckConverter = workerContext.ServiceProvider.GetRequiredService(); + ////读取并保持Pck + //var pcksFromExternalList = await pckHandleService.ReadAsync().ConfigureAwait(false); + ////转换Pck + //await pckConverter.ConvertAsync(pcksFromExternalList).ConfigureAwait(false); + #endregion } } diff --git a/be/DataExchange/Fawtyg/Win_in.Sfs.Wms.DataExchange.Fawtyg.TyrpAgent/TyrpAgentModule.cs b/be/DataExchange/Fawtyg/Win_in.Sfs.Wms.DataExchange.Fawtyg.TyrpAgent/TyrpAgentModule.cs index 7903cbfe5..ab6456637 100644 --- a/be/DataExchange/Fawtyg/Win_in.Sfs.Wms.DataExchange.Fawtyg.TyrpAgent/TyrpAgentModule.cs +++ b/be/DataExchange/Fawtyg/Win_in.Sfs.Wms.DataExchange.Fawtyg.TyrpAgent/TyrpAgentModule.cs @@ -172,7 +172,7 @@ public class TyrpAgentModule : AbpModule ApplicationInitializationContext context) { - context.AddBackgroundWorkerAsync(); + // context.AddBackgroundWorkerAsync(); context.AddBackgroundWorkerAsync(); } diff --git a/be/DataExchange/Fawtyg/Win_in.Sfs.Wms.DataExchange.Fawtyg.TyrpAgent/appsettings.json b/be/DataExchange/Fawtyg/Win_in.Sfs.Wms.DataExchange.Fawtyg.TyrpAgent/appsettings.json index bc4ac8442..34e4e7d63 100644 --- a/be/DataExchange/Fawtyg/Win_in.Sfs.Wms.DataExchange.Fawtyg.TyrpAgent/appsettings.json +++ b/be/DataExchange/Fawtyg/Win_in.Sfs.Wms.DataExchange.Fawtyg.TyrpAgent/appsettings.json @@ -1,13 +1,13 @@ { "ConnectionStrings": { - "Default": "Server=10.164.113.32,1818\\SHDB;Database=Wms_Dy_ShangHai;uid=ShWmsUser;pwd=Faty@Wms_20230413#SH;TrustServerCertificate=True", - "DataExchange": "Server=10.164.113.32,1818\\SHDB;Database=Wms_DataExchange_Main_Dy_ShangHai;uid=ShWmsUser;pwd=Faty@Wms_20230413#SH;TrustServerCertificate=True", - "TYRP": "Server=10.164.113.32,1818\\SHDB;Database=TYRP;Uid=ShWmsUser;Pwd=Faty@Wms_20230413#SH;TrustServerCertificate=True", + "Default": "Server=dev.ccwin-in.com,13319;Database=WMS_DongYang_Main_CC;uid=ccwin-in;pwd=Microsoft@2022;TrustServerCertificate=True;Encrypt=false", + "DataExchange": "Server=dev.ccwin-in.com,13319;Database=WMS_DongYang_DataExchange_CC;uid=ccwin-in;pwd=Microsoft@2022;TrustServerCertificate=True;Encrypt=false", + "TYRP": "Server=dev.ccwin-in.com,13319;Database=TYRP_CC;Uid=ccwin-in;Pwd=Microsoft@2022;TrustServerCertificate=True", "SYBASE_TYRP": "Data Source=10.164.115.137; Port=5000; Database=mesdb; Uid=sa; Pwd=dawning;Charset=cp850;" //iso_1 }, "AuthServer": { - "Authority": "http://10.164.113.31:60083/", + "Authority": "http://dev.ccwin-in.com:60083/", "RequireHttpsMetadata": "false", "SwaggerClientId": "admin", "SwaggerClientSecret": "1q2w3E*", @@ -26,16 +26,16 @@ "RemoteServices": { "BaseData": { - "BaseUrl": "http://10.164.113.31:60084/" + "BaseUrl": "http://dev.ccwin-in.com:60084/" }, "Store": { - "BaseUrl": "http://10.164.113.31:60085/" + "BaseUrl": "http://dev.ccwin-in.com:60085/" }, "Label": { - "BaseUrl": "http://10.164.113.31:60082/" + "BaseUrl": "http://dev.ccwin-in.com:60082/" }, "Auth": { - "BaseUrl": "http://10.164.113.31:60083/" + "BaseUrl": "http://dev.ccwin-in.com:60083/" } }, "TyrpOptions": { diff --git a/be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application.Contracts/ProductLineItems/IProductionLineItemAppService.cs b/be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application.Contracts/ProductLineItems/IProductionLineItemAppService.cs index e0dfc4b08..bb96f3777 100644 --- a/be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application.Contracts/ProductLineItems/IProductionLineItemAppService.cs +++ b/be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application.Contracts/ProductLineItems/IProductionLineItemAppService.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Win_in.Sfs.Shared.Application.Contracts; +using Win_in.Sfs.Shared.Domain.Shared; namespace Win_in.Sfs.Basedata.Application.Contracts; @@ -16,4 +17,5 @@ public interface IProductionLineItemAppService Task GetByProductLineCodeAndItemCodeAsync(string productLineCode, string itemCode); + Task> GetByProductLineCodeAndItemCodeAndErpLocationCodeAsync(List locationType, string erpLocationCodes, string itemCode); } diff --git a/be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application.Contracts/ProductionLines/IProductionLineAppService.cs b/be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application.Contracts/ProductionLines/IProductionLineAppService.cs index 7f8f0bcdb..d533e6aa7 100644 --- a/be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application.Contracts/ProductionLines/IProductionLineAppService.cs +++ b/be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application.Contracts/ProductionLines/IProductionLineAppService.cs @@ -12,4 +12,5 @@ public interface IProductionLineAppService { Task GetByLocationCodeAsync(string locationCode); Task> GetByLocationCodeAsync(EnumProductionLineType productionLineType); + Task> GetByLocationCodesAsync(List locationCode); } diff --git a/be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application/ProductionLineItems/ProductionLineItemAppService.cs b/be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application/ProductionLineItems/ProductionLineItemAppService.cs index 3b126dc7a..a7f1bbd1f 100644 --- a/be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application/ProductionLineItems/ProductionLineItemAppService.cs +++ b/be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application/ProductionLineItems/ProductionLineItemAppService.cs @@ -1,12 +1,18 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text.Json; using System.Threading.Tasks; +using DocumentFormat.OpenXml.Office2016.Drawing.ChartDrawing; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Volo.Abp; using Volo.Abp.Caching; +using Volo.Abp.ObjectMapping; using Win_in.Sfs.Basedata.Application.Contracts; using Win_in.Sfs.Basedata.Domain; using Win_in.Sfs.Basedata.Domain.Shared; +using Win_in.Sfs.Shared.Domain.Shared; namespace Win_in.Sfs.Basedata.Application; @@ -16,13 +22,17 @@ public class ProductionLineItemAppService : SfsBaseDataAppServiceBase, IProductionLineItemAppService { + private readonly IProductionLineAppService _productionLineAppService ; + private readonly ILocationAppService _locationAppService ; public ProductionLineItemAppService( - IProductionLineItemRepository repository, IDistributedCache cache + IProductionLineItemRepository repository, IDistributedCache cache, IProductionLineAppService productionLineAppService, ILocationAppService locationAppService ) : base(repository, cache) { base.CreatePolicyName = ProductionLineItemPermissions.Create; base.UpdatePolicyName = ProductionLineItemPermissions.Update; base.DeletePolicyName = ProductionLineItemPermissions.Delete; + _productionLineAppService = productionLineAppService; + _locationAppService = locationAppService; } [HttpPost("upsert")] @@ -56,4 +66,27 @@ public class ProductionLineItemAppService : .FindAsync(p => p.ProdLineCode == productLineCode && p.ItemCode == itemCode).ConfigureAwait(false); return ObjectMapper.Map(entityList); } + [HttpPost("get-by-productlinecode-and-itemcode-and-erplocationcode-async")] + public virtual async Task> GetByProductLineCodeAndItemCodeAndErpLocationCodeAsync(List locationType, string erpLocationCodes,string itemCode) + { + + List list = new List(); + var locations= await _locationAppService.GetListByTypesAndErpCodeAsync(locationType, erpLocationCodes).ConfigureAwait(false); + if (locations.Count <= 0) + { + throw new UserFriendlyException($"未维护储位基础信息!"); + } + else + { + var pls= await _productionLineAppService.GetByLocationCodesAsync(locations.Select(r=>r.Code).ToList()).ConfigureAwait(false); + var plscode = pls.Select(r => r.Code).ToList(); + var entitys= await _repository.GetListAsync(r => r.ItemCode == itemCode && plscode.Contains(r.ProdLineCode)).ConfigureAwait(false); + foreach (var entity in entitys) + { + var locationcodes= JsonSerializer.Deserialize>(entity.ProductLocationCodeListJson); + list.AddRange(locationcodes); + } + } + return list; + } } diff --git a/be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application/ProductionLines/ProductionLineAppService.cs b/be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application/ProductionLines/ProductionLineAppService.cs index cf5b04fb8..047b95686 100644 --- a/be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application/ProductionLines/ProductionLineAppService.cs +++ b/be/Modules/BaseData/src/Win_in.Sfs.Basedata.Application/ProductionLines/ProductionLineAppService.cs @@ -60,7 +60,17 @@ public class ProductionLineAppService return ObjectMapper.Map(entity); } + [HttpPost("get-by-locations")] + public virtual async Task> GetByLocationCodesAsync(List locationCode) + { + var entitys = await _repository.GetListAsync(p => locationCode.Contains(p.LocationCode) ).ConfigureAwait(false); + if (entitys == null) + { + throw new UserFriendlyException($"库位不存在"); + } + return ObjectMapper.Map,List< ProductionLineDTO>>(entitys); + } [HttpPost("get-by-type")] public virtual async Task> GetByLocationCodeAsync(EnumProductionLineType productionLineType) { diff --git a/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application.Contracts/Balances/IBalanceAppService.cs b/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application.Contracts/Balances/IBalanceAppService.cs index f5fd91884..5c9adc871 100644 --- a/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application.Contracts/Balances/IBalanceAppService.cs +++ b/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application.Contracts/Balances/IBalanceAppService.cs @@ -175,4 +175,5 @@ public interface IBalanceAppService /// Task GetRealQtyByPackingCodeAndItemCodeAndLocationCodeAndStatusAsync(string packingCode, string itemCode, string locationCode, EnumInventoryStatus status,string lot); + Task> GetRecommendBalancesByLocationsExpectOldBalancesAsync(RecommendBalanceRequestInput input); } diff --git a/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application.Contracts/Balances/Inputs/RecommendBalanceRequestInput.cs b/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application.Contracts/Balances/Inputs/RecommendBalanceRequestInput.cs index 6e5bfdd95..885083272 100644 --- a/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application.Contracts/Balances/Inputs/RecommendBalanceRequestInput.cs +++ b/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application.Contracts/Balances/Inputs/RecommendBalanceRequestInput.cs @@ -43,6 +43,10 @@ public class RecommendBalanceRequestInput /// [Display(Name = "是否必须有箱码")] public bool IsPackingCode { get; set; } = false; + /// + /// 已经用过的库存 + /// + public List OldBalances { get; set; } = new (); //public override string ToString() //{ diff --git a/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application/Balances/BalanceAppService.cs b/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application/Balances/BalanceAppService.cs index fcbccf703..7e81b3b08 100644 --- a/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application/Balances/BalanceAppService.cs +++ b/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Application/Balances/BalanceAppService.cs @@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging; using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.Domain.Repositories; +using Volo.Abp.ObjectMapping; using Win_in.Sfs.Basedata.Application.Contracts; using Win_in.Sfs.Shared.Application.Contracts; using Win_in.Sfs.Shared.Domain; @@ -595,6 +596,51 @@ public class BalanceAppService return dtos; } + /// + /// 根据发料任务需求的库位,算出推荐的库存 (在获取时 已经去除了预占用和已经推荐过的库存) + /// + /// + /// + /// + [HttpGet("recommend-list-location-by-locations-expect-oldbalances")] + public virtual async Task> GetRecommendBalancesByLocationsExpectOldBalancesAsync(RecommendBalanceRequestInput input) + { + var traceId = GuidGenerator.Create(); + var itemCode = input.ItemCode; + var qty = input.Qty; + var locations = input.Locations; + var statuses = input.Statuses; + foreach (var location in locations) + { + var locationDto = await _locationAclService.GetByCodeAsync(location).ConfigureAwait(false); + if (locationDto != null) + { + if (input.LocationAreas == null) + { + input.LocationAreas = new List(); + } + + input.LocationAreas.Add(locationDto.AreaCode); + if (input.LocationTypes == null) + { + input.LocationTypes = new List(); + } + + input.LocationTypes.Add(locationDto.Type); + } + } + + Logger.LogDebug(traceId + "|Input:" + input); + var oldBalances = ObjectMapper.Map, List>(input.OldBalances); + var balances = await _balanceManager + .GetRecommendBalancesByLocationExpectOldBalancesAsync(traceId, itemCode, qty, locations, statuses, input.IsPackingCode, oldBalances) + .ConfigureAwait(false); + + var dtos = ObjectMapper.Map, List>(balances); + + return dtos; + } + /// /// 获取可用库存列表 /// diff --git a/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/BalanceManager.cs b/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/BalanceManager.cs index 8891a9be3..ec2e68842 100644 --- a/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/BalanceManager.cs +++ b/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/BalanceManager.cs @@ -615,7 +615,162 @@ public class BalanceManager : DomainService, IBalanceManager #endregion } + /// + /// 根据库位获取推荐库位 + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> GetRecommendBalancesByLocationExpectOldBalancesAsync(Guid traceId, string itemCode, + decimal requestQty, List validLocations, + List validStatuses, bool ispackingcode,List oldBalances) + { + var recommendBalances = new List();//返回可使用的推荐库存余额 + + var item = await _itemBasicAclService.GetByCodeAsync(itemCode).ConfigureAwait(false); + if (item == null) //物品是否存在 + { + // throw new UserFriendlyException($"未找到代码为 {itemCode} 的物料记录"); + return recommendBalances; + } + + //构造查询条件 + Expression> 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 (ispackingcode) + { + expression = expression.And(p => !string.IsNullOrEmpty(p.PackingCode)); + } + //筛选有效库区 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, oldBalances, locations) + //去除不可拆箱 拆托的且有预占用的库存余额 + .IgnoreExpectOutOfSameContainer(expectOutContainerCodes, itemStoreRelationDict, locations) + //过滤掉不允许拣料的库位 + .FilterLocationEnablePickAsync(locations) + //排序库存余额 最终可用的余额集合 + .SortByFifo(); + + LogDebug(traceId, usableBalances, "AvailableBalances"); + + var usableBalanceQueue = new Queue(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 + } /// /// 获取推荐库位 /// diff --git a/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/BalanceValidateExtension.cs b/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/BalanceValidateExtension.cs index 8915e60c2..f4fe7e33a 100644 --- a/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/BalanceValidateExtension.cs +++ b/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/BalanceValidateExtension.cs @@ -56,7 +56,46 @@ public static class BalanceValidateExtension return balances; } + /// + /// 扣除预计出库存 + /// + /// + /// + /// + /// + public static List DecreaseExpectOutQty(this List balances, + List expectOuts,List oldBalances, List locations) + { + + foreach (var balance in balances) + { + var location = locations.First(p => p.Code == balance.LocationCode); + var expectOutsOfBalance = expectOuts.Where(p => + p.PackingCode == balance.PackingCode + && p.ItemCode == balance.ItemCode + && p.Lot == balance.Lot + && p.LocationCode == balance.LocationCode + && p.Status == balance.Status); + + var expectOutsOfOldBalance = oldBalances.Where(p => + p.PackingCode == balance.PackingCode + && p.ItemCode == balance.ItemCode + && p.Lot == balance.Lot + && p.LocationCode == balance.LocationCode + && p.Status == balance.Status); + + var expectOutSumQty = !location.EnableSplitBox + ? balance.Qty + : expectOutsOfBalance.Sum(p => p.Qty); + var expectOutOldSumQty = !location.EnableSplitBox + ? balance.Qty + : expectOutsOfOldBalance.Sum(p => p.Qty); + balance.DecreaseQty(expectOutSumQty+ expectOutOldSumQty); + } + + return balances; + } /// /// 忽略不可拆托,同一托盘的库存 /// diff --git a/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/IBalanceManager.cs b/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/IBalanceManager.cs index 9f950b211..1d2e4880d 100644 --- a/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/IBalanceManager.cs +++ b/be/Modules/Inventory/src/Win_in.Sfs.Wms.Inventory.Domain/Balances/IBalanceManager.cs @@ -51,4 +51,5 @@ public interface IBalanceManager : IDomainService Task> GetUsableListAsync(string itemCode, List validLocations, List validStatuses, bool isRemovePackingCode); + Task> GetRecommendBalancesByLocationExpectOldBalancesAsync(Guid traceId, string itemCode, decimal requestQty, List validLocations, List validStatuses, bool ispackingcode, List oldBalances); } diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Jobs/IssueJobs/AssembleIssueJobs/AssembleIssueJobAppService.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Jobs/IssueJobs/AssembleIssueJobs/AssembleIssueJobAppService.cs index 5ce16111c..69201656c 100644 --- a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Jobs/IssueJobs/AssembleIssueJobs/AssembleIssueJobAppService.cs +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Jobs/IssueJobs/AssembleIssueJobs/AssembleIssueJobAppService.cs @@ -217,7 +217,7 @@ public class AssembleIssueJobAppService await _repository.UpdateAsync(assembleIssueJob).ConfigureAwait(false); } - [HttpPost("CompleteAsync/{id}")] + [HttpPost("Complete/{id}")] public async Task CompleteAsync(Guid id) { var assembleIssueJob = await _repository.FindAsync(id).ConfigureAwait(false); diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Requests/DeliverRequests/DeliverRequestAppService.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Requests/DeliverRequests/DeliverRequestAppService.cs index ff890095c..847bfb6fd 100644 --- a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Requests/DeliverRequests/DeliverRequestAppService.cs +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Application/Requests/DeliverRequests/DeliverRequestAppService.cs @@ -56,7 +56,7 @@ public class DeliverRequestAppService : public virtual async Task> HandleListAsync(List ids) { - var entitys = await _repository.GetListAsync(r=> ids.Contains(r.Id)).ConfigureAwait(false); + var entitys = await _repository.GetListAsync(r=> ids.Contains(r.Id),true).ConfigureAwait(false); if (entitys.Select(r => r.CustomerCode).Distinct().Count()>1) { throw new UserFriendlyException($"所选申请涉及多个客户不能创建为一个发货单,请重新选择!"); diff --git a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/Requests/DeliverRequestEventHandler.cs b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/Requests/DeliverRequestEventHandler.cs index 29c1e645d..eae76b3f9 100644 --- a/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/Requests/DeliverRequestEventHandler.cs +++ b/be/Modules/Store/src/Win_in.Sfs.Wms.Store.Event/Requests/DeliverRequestEventHandler.cs @@ -31,10 +31,11 @@ public class DeliverRequestEventHandler private readonly IDeliverRequestManager _deliverRequestManager; private readonly IBalanceAppService _balanceAppService; private readonly ILocationAppService _locationAppService; + private readonly IProductionLineItemAppService _productionLineItemAppService; public DeliverRequestEventHandler( IDeliverJobAppService deliverJobApp , IDeliverNoteAppService deliverNoteApp - , ICustomerAddressAppService customerAddressApp, IDeliverRequestManager deliverRequestManager, IBalanceAppService balanceAppService, ILocationAppService locationAppService) + , ICustomerAddressAppService customerAddressApp, IDeliverRequestManager deliverRequestManager, IBalanceAppService balanceAppService, ILocationAppService locationAppService, IProductionLineItemAppService productionLineItemAppService) { _deliverNoteApp = deliverNoteApp; _deliverJobApp = deliverJobApp; @@ -42,6 +43,7 @@ public class DeliverRequestEventHandler _deliverRequestManager = deliverRequestManager; _balanceAppService = balanceAppService; _locationAppService = locationAppService; + _productionLineItemAppService = productionLineItemAppService; } @@ -98,11 +100,11 @@ public class DeliverRequestEventHandler var noteCreateInput = await BuildDeliverNoteAsync(entity).ConfigureAwait(false); await _deliverNoteApp.CreateAsync(noteCreateInput).ConfigureAwait(false); } - else - { - var deliverJobCreateInputs = await BuildDeliverJobsAsync(entity).ConfigureAwait(false); - await _deliverJobApp.CreateManyAsync(deliverJobCreateInputs).ConfigureAwait(false); - } + //else + //{ + // var deliverJobCreateInputs = await BuildDeliverJobsAsync(entity).ConfigureAwait(false); + // await _deliverJobApp.CreateManyAsync(deliverJobCreateInputs).ConfigureAwait(false); + //} } /// /// 执行后 @@ -156,7 +158,7 @@ public class DeliverRequestEventHandler } createInput.Details = new List(); - + List oldBalances = new List(); foreach (var detail in requests.SelectMany(r=>r.Details)) { var locations = await _locationAppService.GetListByTypesAndErpCodeAsync(transactionType.OutLocationTypes, detail.AreaCode).ConfigureAwait(false); @@ -165,13 +167,14 @@ public class DeliverRequestEventHandler throw new UserFriendlyException($"储位 {detail.AreaCode} 未找到对应的成品库和半成品库。"); } - var balances = await _balanceAppService.GetRecommendBalancesByLocationsAsync( + var balances = await _balanceAppService.GetRecommendBalancesByLocationsExpectOldBalancesAsync( new RecommendBalanceRequestInput { ItemCode = detail.ItemCode, Qty = detail.Qty, Locations = locations.Select(r => r.Code).ToList(), - Statuses = transactionType.OutInventoryStatuses + Statuses = transactionType.OutInventoryStatuses, + OldBalances=oldBalances, }).ConfigureAwait(false); var sumQty = balances.Sum(t => t.Qty); @@ -180,7 +183,7 @@ public class DeliverRequestEventHandler { throw new UserFriendlyException($"物料号 {detail.ItemCode} 库存余额 {sumQty} 小于 {detail.Qty}。"); } - + oldBalances.AddRange(balances); foreach (var balance in balances) { var inputDetail = ObjectMapper.Map(balance); @@ -241,7 +244,7 @@ public class DeliverRequestEventHandler } createInput.Details = new List(); - + List oldBalances = new List(); foreach (var detail in request.Details) { var locations = await _locationAppService.GetListByTypesAndErpCodeAsync(transactionType.OutLocationTypes, detail.AreaCode).ConfigureAwait(false); @@ -250,13 +253,14 @@ public class DeliverRequestEventHandler throw new UserFriendlyException($"储位 {detail.AreaCode} 未找到对应的成品库和半成品库。"); } - var balances = await _balanceAppService.GetRecommendBalancesByLocationsAsync( + var balances = await _balanceAppService.GetRecommendBalancesByLocationsExpectOldBalancesAsync( new RecommendBalanceRequestInput { ItemCode = detail.ItemCode, Qty = detail.Qty, Locations = locations.Select(r=>r.Code).ToList(), - Statuses = transactionType.OutInventoryStatuses + Statuses = transactionType.OutInventoryStatuses, + OldBalances=oldBalances, }).ConfigureAwait(false); var sumQty = balances.Sum(t => t.Qty); @@ -265,7 +269,7 @@ public class DeliverRequestEventHandler { throw new UserFriendlyException($"物料号 {detail.ItemCode} 库存余额 {sumQty} 小于 {detail.Qty}。"); } - + oldBalances.AddRange(balances); foreach (var balance in balances) { var inputDetail = ObjectMapper.Map(balance); @@ -295,96 +299,96 @@ public class DeliverRequestEventHandler return createInput; } - private async Task> BuildDeliverJobsAsync(DeliverRequest request) - { - var transSubType = EnumTransSubType.None; - switch (request.DeliverRequestType) - { - case EnumDeliverRequestType.Normal: - transSubType = EnumTransSubType.Deliver_Standard; - break; - case EnumDeliverRequestType.FIS: - transSubType = EnumTransSubType.Deliver_FIS; - break; - case EnumDeliverRequestType.RAW: - transSubType = EnumTransSubType.Deliver_RAW; - break; - case EnumDeliverRequestType.None: - default: - throw new ArgumentOutOfRangeException(); - } - - var transactionType = await TransactionTypeAclService.GetByTransTypeAsync(EnumTransType.Deliver, transSubType) - .ConfigureAwait(false); - var createInput = ObjectMapper.Map(request); - var customerAddress = - (await _customerAddressApp.GetByCustomerCodeAsync(request.CustomerCode).ConfigureAwait(false)) - .FirstOrDefault(); - LocationDTO toLocation = null; - if (customerAddress != null && !string.IsNullOrEmpty(customerAddress.LocationCode)) - { - toLocation = await LocationAclService.GetByCodeAsync(customerAddress.LocationCode).ConfigureAwait(false); - Check.NotNull(toLocation, $"客户库位 {customerAddress.LocationCode} 不存在"); - } - - createInput.Details = new List(); - - foreach (var detail in request.Details) - { - var balances = await BalanceAclService.GetRecommendBalancesAsync( - new RecommendBalanceRequestInput - { - ItemCode = detail.ItemCode, - Qty = detail.Qty, - LocationTypes = transactionType.OutLocationTypes, - LocationAreas = new List { detail.AreaCode }, - Statuses = transactionType.OutInventoryStatuses - }).ConfigureAwait(false); - - var sumQty = balances.Sum(t => t.Qty); - - if (sumQty < detail.Qty) - { - throw new UserFriendlyException($"物料号 {detail.ItemCode} 库存余额 {sumQty} 小于 {detail.Qty}。"); - } - - foreach (var balance in balances) - { - var inputDetail = ObjectMapper.Map(balance); - if (toLocation != null) - { - inputDetail.ToLocationCode = toLocation.Code; - inputDetail.ToLocationErpCode = toLocation.ErpLocationCode; - inputDetail.ToWarehouseCode = toLocation.WarehouseCode; - } - - var item = await ItemBasicAclService.GetByCodeAsync(balance.ItemCode).ConfigureAwait(false); - - if (item != null) - { - inputDetail.StdPackQty = item.StdPackQty; - } - - createInput.Details.Add(inputDetail); - } - - var firstBalance = balances.FirstOrDefault(); - - var location = await LocationAclService.GetByCodeAsync(firstBalance.LocationCode).ConfigureAwait(false); - - if (location != null) - { - createInput.WarehouseCode = location.WarehouseCode; - createInput.WorkGroupCode = location.WorkGroupCode; - } - - } - - createInput.Priority = PriorityHelper.GetPriority(Clock); - createInput.PriorityIncrement = 1; - - return new List { createInput }; - } + //private async Task> BuildDeliverJobsAsync(DeliverRequest request) + //{ + // var transSubType = EnumTransSubType.None; + // switch (request.DeliverRequestType) + // { + // case EnumDeliverRequestType.Normal: + // transSubType = EnumTransSubType.Deliver_Standard; + // break; + // case EnumDeliverRequestType.FIS: + // transSubType = EnumTransSubType.Deliver_FIS; + // break; + // case EnumDeliverRequestType.RAW: + // transSubType = EnumTransSubType.Deliver_RAW; + // break; + // case EnumDeliverRequestType.None: + // default: + // throw new ArgumentOutOfRangeException(); + // } + + // var transactionType = await TransactionTypeAclService.GetByTransTypeAsync(EnumTransType.Deliver, transSubType) + // .ConfigureAwait(false); + // var createInput = ObjectMapper.Map(request); + // var customerAddress = + // (await _customerAddressApp.GetByCustomerCodeAsync(request.CustomerCode).ConfigureAwait(false)) + // .FirstOrDefault(); + // LocationDTO toLocation = null; + // if (customerAddress != null && !string.IsNullOrEmpty(customerAddress.LocationCode)) + // { + // toLocation = await LocationAclService.GetByCodeAsync(customerAddress.LocationCode).ConfigureAwait(false); + // Check.NotNull(toLocation, $"客户库位 {customerAddress.LocationCode} 不存在"); + // } + + // createInput.Details = new List(); + + // foreach (var detail in request.Details) + // { + // var balances = await BalanceAclService.GetRecommendBalancesAsync( + // new RecommendBalanceRequestInput + // { + // ItemCode = detail.ItemCode, + // Qty = detail.Qty, + // LocationTypes = transactionType.OutLocationTypes, + // LocationAreas = new List { detail.AreaCode }, + // Statuses = transactionType.OutInventoryStatuses + // }).ConfigureAwait(false); + + // var sumQty = balances.Sum(t => t.Qty); + + // if (sumQty < detail.Qty) + // { + // throw new UserFriendlyException($"物料号 {detail.ItemCode} 库存余额 {sumQty} 小于 {detail.Qty}。"); + // } + + // foreach (var balance in balances) + // { + // var inputDetail = ObjectMapper.Map(balance); + // if (toLocation != null) + // { + // inputDetail.ToLocationCode = toLocation.Code; + // inputDetail.ToLocationErpCode = toLocation.ErpLocationCode; + // inputDetail.ToWarehouseCode = toLocation.WarehouseCode; + // } + + // var item = await ItemBasicAclService.GetByCodeAsync(balance.ItemCode).ConfigureAwait(false); + + // if (item != null) + // { + // inputDetail.StdPackQty = item.StdPackQty; + // } + + // createInput.Details.Add(inputDetail); + // } + + // var firstBalance = balances.FirstOrDefault(); + + // var location = await LocationAclService.GetByCodeAsync(firstBalance.LocationCode).ConfigureAwait(false); + + // if (location != null) + // { + // createInput.WarehouseCode = location.WarehouseCode; + // createInput.WorkGroupCode = location.WorkGroupCode; + // } + + // } + + // createInput.Priority = PriorityHelper.GetPriority(Clock); + // createInput.PriorityIncrement = 1; + + // return new List { createInput }; + //} #endregion }