schangxiang@126.com
2025-05-13 25246d39da4b74b54a844b36d8a50752917b81cc
HIAWms/server/src/CMS.Plugin.HIAWms.Application/Implements/WmsCommonAppService.cs
@@ -1,10 +1,15 @@
using CMS.Plugin.HIAWms.Application.Contracts.Dtos.CommonDto;
using CMS.Plugin.HIAWms.Application.Contracts.Dtos.WmsMaterialStocks;
using CMS.Plugin.HIAWms.Application.Contracts.Dtos.WmsPlaces;
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;
@@ -14,7 +19,7 @@
    /// <summary>
    /// 公共操作服务
    /// </summary>
    public class WmsCommonAppService : CMSPluginAppService
    public class WmsCommonAppService : CMSPluginAppService,IWmsCommonAppService
    {
        private readonly IWmsMaterialRepository _wmsMaterialRepository;
        private readonly IWmsPlaceRepository _wmsPlaceRepository;
@@ -30,17 +35,6 @@
            _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>
        /// 查找空库位
@@ -50,11 +44,15 @@
        /// <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);
            // 2. 查找相同物料型号和编号的库存(按库存量降序)
            var sameModelStocks = stockList
@@ -63,7 +61,7 @@
                .OrderByDescending(x => x.StockNumber)
                .ToList();
            var availablePlaces = new Dictionary<WmsPlace, int>();
            var availablePlaces = new Dictionary<WmsPlaceDto, int>();
            int remainingNum = requiredNum;
            // 3. 优先检查已有库存的库位是否能存放(相同 MaterialNo)
@@ -108,5 +106,72 @@
            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;
        }
    }
}