| | |
| | | using CMS.Plugin.HIAWms.Application.Contracts.Dtos.CommonDto; |
| | | using CMS.Plugin.HIAWms.Application.Contracts.Dtos.WmsMaterialStocks; |
| | | using CMS.Plugin.HIAWms.Application.Contracts.Dtos.WmsPlace; |
| | | using CMS.Plugin.HIAWms.Application.Contracts.Services; |
| | | using CMS.Plugin.HIAWms.Domain.WmsMaterials; |
| | | using CMS.Plugin.HIAWms.Domain.WmsMaterialStocks; |
| | | using CMS.Plugin.HIAWms.Domain.WmsPlaces; |
| | | using CmsQueryExtensions.Extension; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Linq.Expressions; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | using Volo.Abp; |
| | |
| | | /// <summary> |
| | | /// 公共操作服务 |
| | | /// </summary> |
| | | public class WmsCommonAppService : CMSPluginAppService |
| | | public class WmsCommonAppService : CMSPluginAppService,IWmsCommonAppService |
| | | { |
| | | private readonly IWmsMaterialRepository _wmsMaterialRepository; |
| | | private readonly IWmsPlaceRepository _wmsPlaceRepository; |
| | |
| | | _wmsMaterialStockRepository = wmsMaterialStockRepository; |
| | | } |
| | | |
| | | public async Task<List<MaterialModelOutput>> GetMaterialModeListAsync() |
| | | { |
| | | var materialList = await _wmsMaterialRepository.GetMaterialListAsync(new WmsMaterial()); |
| | | if (materialList == null || materialList.Count <= 0) return new List<MaterialModelOutput>(); ; |
| | | |
| | | return materialList.Select(material => new MaterialModelOutput |
| | | { |
| | | MaterialModel = material.MaterialModel, |
| | | MaterialModelDesc = material.MaterialModel |
| | | }).ToList(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 查找空库位 |
| | |
| | | /// <param name="requiredNum"></param> |
| | | /// <returns></returns> |
| | | /// <exception cref="UserFriendlyException"></exception> |
| | | public async Task<Dictionary<WmsPlace, int>> FindAvailablePlacesAsync(string materialModel, string materialNo, int requiredNum) |
| | | public async Task<Dictionary<WmsPlaceDto, int>> FindAvailablePlacesAsync(string materialModel,int requiredNum, string materialNo="" ) |
| | | { |
| | | |
| | | var whereConditions = DynamicGetQueryParams(new GetWmsMaterialStockInput { StorageTypeNo = Domain.Shared.Enums.PlaceTypeEnum.YUANLIAOKUWEI }); |
| | | // 1. 获取所有库存和库位信息 |
| | | var stockList = await _wmsMaterialStockRepository.GetListAsync(new WmsMaterialStock()); |
| | | var allPlaceList = await _wmsPlaceRepository.GetListAsync(new WmsPlace()); |
| | | var stockList = await _wmsMaterialStockRepository.GetListAsync(whereConditions); |
| | | |
| | | var placeList = await _wmsPlaceRepository.GetListAsync(new WmsPlace { StorageTypeNo = Domain.Shared.Enums.PlaceTypeEnum.YUANLIAOKUWEI}); |
| | | var allPlaceList = ObjectMapper.Map<List<WmsPlace>, List<WmsPlaceDto>>(placeList.Where(x => !x.IsDisabled).ToList()); |
| | | |
| | | // 2. 查找相同物料型号和编号的库存(按库存量降序) |
| | | var sameModelStocks = stockList |
| | |
| | | .OrderByDescending(x => x.StockNumber) |
| | | .ToList(); |
| | | |
| | | var availablePlaces = new Dictionary<WmsPlace, int>(); |
| | | var availablePlaces = new Dictionary<WmsPlaceDto, int>(); |
| | | int remainingNum = requiredNum; |
| | | |
| | | // 3. 优先检查已有库存的库位是否能存放(相同 MaterialNo) |
| | |
| | | |
| | | return availablePlaces; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 查找库存 |
| | | /// </summary> |
| | | /// <param name="materialModel"></param> |
| | | /// <param name="requiredNum"></param> |
| | | /// <param name="materialNo"></param> |
| | | /// <returns></returns> |
| | | public async Task<Dictionary<WmsMaterialStockDto, int>> FindStockAsync(string materialModel, int requiredNum, string materialNo = "") |
| | | { |
| | | // 1. 获取所有库存(排除锁定库存) |
| | | var whereConditions = DynamicGetQueryParams(new GetWmsMaterialStockInput()); |
| | | var stockList = (await _wmsMaterialStockRepository.GetListAsync(whereConditions)) |
| | | .Where(x => x.IsLock == Domain.Shared.Enums.YesNoEnum.N) |
| | | .Where(x=>x.StorageTypeNo == Domain.Shared.Enums.PlaceTypeEnum.YUANLIAOKUWEI) |
| | | .ToList(); |
| | | |
| | | // 2. 筛选匹配物料 |
| | | var availableStocklist = stockList |
| | | .Where(x => x.MaterialModel == materialModel) |
| | | .WhereIf(!string.IsNullOrEmpty(materialNo), x => x.MaterialNo == materialNo) |
| | | .OrderBy(x => x.StockNumber) // 优先从库存少的库位出 |
| | | .ToList(); |
| | | |
| | | var availableStocks = ObjectMapper.Map<List<WmsMaterialStock>, List<WmsMaterialStockDto>>(availableStocklist); |
| | | |
| | | // 3. 检查总库存是否足够 |
| | | int totalAvailable = availableStocks.Sum(x => x.StockNumber); |
| | | if (totalAvailable < requiredNum) |
| | | { |
| | | throw new UserFriendlyException( |
| | | $"库存不足!需求: {requiredNum}, 可用: {totalAvailable}, 缺: {requiredNum - totalAvailable}"); |
| | | } |
| | | |
| | | // 4. 计算各库位出库数量 |
| | | var allocation = new Dictionary<WmsMaterialStockDto, int>(); // <库位号, 出库数> |
| | | int remaining = requiredNum; |
| | | |
| | | foreach (var stock in availableStocks) |
| | | { |
| | | if (remaining <= 0) break; |
| | | |
| | | int deductAmount = Math.Min(stock.StockNumber, remaining); |
| | | allocation.Add(stock, deductAmount); |
| | | remaining -= deductAmount; |
| | | } |
| | | |
| | | return allocation; |
| | | } |
| | | |
| | | private FunReturnResultModel<Expression<Func<WmsMaterialStock, bool>>> DynamicGetQueryParams(GetWmsMaterialStockInput input) |
| | | { |
| | | //动态构造查询条件 |
| | | var whereConditions = WhereConditionsExtensions.GetWhereConditions<WmsMaterialStock, GetWmsMaterialStockInput>(input); |
| | | if (!whereConditions.IsSuccess) |
| | | { |
| | | throw new Exception("动态构造查询条件失败:" + whereConditions.ErrMsg); |
| | | } |
| | | |
| | | //也可再次自定义构建查询条件 |
| | | Expression<Func<WmsMaterialStock, bool>> extendExpression = a => a.IsDeleted == false; |
| | | // 使用 System.Linq.PredicateBuilder 的 And |
| | | var pres = (System.Linq.Expressions.Expression<Func<WmsMaterialStock, bool>>)(whereConditions.data); |
| | | whereConditions.data = System.Linq.PredicateBuilder.And(pres, extendExpression); |
| | | |
| | | return whereConditions; |
| | | } |
| | | } |
| | | } |