pan
2025-11-16 cf83e0828b286b61b69a15005e6247d8b03f4cd8
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_StockService/StockInfoService.cs
@@ -1,7 +1,10 @@
using AutoMapper;
using SqlSugar;
using WIDESEA_Common.LocationEnum;
using WIDESEA_Common.StockEnum;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.BaseServices;
using WIDESEA_Core.Helper;
using WIDESEA_IBasicService;
using WIDESEA_IRecordService;
using WIDESEA_IStockService;
@@ -84,84 +87,118 @@
        /// <param name="needQuantity"></param>
        /// <param name="residueQuantity"></param>
        /// <returns></returns>
        public List<Dt_StockInfo> GetOutboundStocks(List<Dt_StockInfo> stockInfos, string materielCode, decimal needQuantity, out decimal residueQuantity)
        public (List<Dt_StockInfo>, Dictionary<int, decimal>) GetOutboundStocks(List<Dt_StockInfo> stockInfos, string materielCode, decimal needQuantity, out decimal residueQuantity)
        {
            List<Dt_StockInfo> outStocks = new List<Dt_StockInfo>();
            var stockTotalQuantity = stockInfos.Select(x => x.Details.Sum(v => v.StockQuantity - v.OutboundQuantity)).Sum(x => x);
            //stockInfos = stockInfos.OrderBy(x => x.Id).ToList();
            if (stockTotalQuantity >= needQuantity)//库存够
            Dictionary<int, decimal> stockAllocations = new Dictionary<int, decimal>(); // è®°å½•每个库存明细的分配数量
            // æŒ‰å…ˆè¿›å…ˆå‡ºæŽ’序所有相关的库存明细
            var sortedStockDetails = stockInfos
                .SelectMany(x => x.Details)
                .Where(x => x.MaterielCode == materielCode &&
                           x.StockQuantity > x.OutboundQuantity) // æœ‰å¯ç”¨åº“å­˜
                .OrderBy(x => x.ProductionDate) // æŒ‰ç”Ÿäº§æ—¥æœŸæŽ’序,先进先出
                .ThenBy(x => x.StockId)         // ç›¸åŒç”Ÿäº§æ—¥æœŸæŒ‰åº“å­˜ID排序
                .ToList();
            if (!sortedStockDetails.Any())
            {
                int index = 0;
                while (needQuantity > 0)
                {
                    Dt_StockInfo stockInfo = stockInfos[index];
                    // è®¡ç®—可用库存时转换为decimal
                    decimal useableStockQuantity = stockInfo.Details
                        .Where(x => x.MaterielCode == materielCode)
                        .Sum(x => (decimal)x.StockQuantity - (decimal)x.OutboundQuantity);
                residueQuantity = needQuantity;
                return (outStocks, stockAllocations);
            }
                    // å°†needQuantity转换为decimal进行比较
                    if (useableStockQuantity < (decimal)needQuantity && useableStockQuantity > 0)
                    {
                        stockInfo.Details.ForEach(x =>
                            x.OutboundQuantity = x.StockQuantity);
            // è®¡ç®—总可用库存
            var stockTotalQuantity = sortedStockDetails.Sum(x => x.StockQuantity - x.OutboundQuantity);
                        // ä½¿ç”¨decimal进行计算后再转回float
                        needQuantity =   needQuantity - useableStockQuantity;
                    }
                    else
                    {
                        stockInfo.Details.ForEach(x =>
                        {
                            if (x.StockQuantity > x.OutboundQuantity && x.MaterielCode == materielCode)
                            {
                                // å°†ç›¸å…³å€¼è½¬æ¢ä¸ºdecimal进行精确计算
                                decimal currentStock = (decimal)x.StockQuantity;
                                decimal currentOutbound = (decimal)x.OutboundQuantity;
                                decimal currentNeed = (decimal)needQuantity;
                                decimal available = currentStock - currentOutbound;
                                if (available >= currentNeed)
                                {
                                    x.OutboundQuantity = currentOutbound + currentNeed;
                                    needQuantity = 0;
                                }
                                else
                                {
                                    needQuantity =currentNeed - available;
                                    x.OutboundQuantity = x.StockQuantity;
                                }
                            }
                        });
                    }
                    outStocks.Add(stockInfo);
                    index++;
                }
            if (stockTotalQuantity < needQuantity)
            {
                residueQuantity = needQuantity - stockTotalQuantity;
            }
            else
            {
                throw new Exception("库存不足");
                residueQuantity = 0;
            }
            residueQuantity = needQuantity;
            return outStocks;
            decimal remainingNeed = needQuantity;
            // æŒ‰å…ˆè¿›å…ˆå‡ºé¡ºåºåˆ†é…åº“å­˜
            foreach (var detail in sortedStockDetails)
            {
                if (remainingNeed <= 0) break;
                decimal availableQuantity = detail.StockQuantity - detail.OutboundQuantity;
                if (availableQuantity <= 0) continue;
                decimal allocateQuantity = Math.Min(availableQuantity, remainingNeed);
                // æ›´æ–°å‡ºåº“数量
                detail.OutboundQuantity += allocateQuantity;
                remainingNeed -= allocateQuantity;
                // è®°å½•分配数量
                stockAllocations[detail.Id] = allocateQuantity;
                // å¦‚果这个库存还没添加到出库列表中,就添加
                var stockInfo = stockInfos.First(x => x.Id == detail.StockId);
                if (!outStocks.Contains(stockInfo))
                {
                    outStocks.Add(stockInfo);
                }
            }
            residueQuantity = remainingNeed;
            return (outStocks, stockAllocations);
        }
        /// <summary>
        /// æ ¹æ®æ¡ç èŽ·å–åº“å­˜ä¿¡æ¯
        /// </summary>
        public async Task<Dt_StockInfoDetail> GetStockDetailByBarcode(string barcode, string materielCode)
        {
            return await Db.Queryable<Dt_StockInfoDetail>()
                .Includes(x => x.StockInfo)
                .Where(x => x.Barcode == barcode && x.MaterielCode == materielCode)
                .FirstAsync();
        }
        public List<Dt_StockInfo> GetStockInfos(string materielCode, string lotNo, List<string> locationCodes)
        /// <summary>
        /// èŽ·å–ç‰©æ–™çš„æ‰€æœ‰æ¡ç ä¿¡æ¯
        /// </summary>
        public async Task<List<Dt_StockInfoDetail>> GetMaterialBarcodes(string materielCode, string batchNo = null)
        {
            List<Dt_StockInfo> stockInfos = null;
            if (!string.IsNullOrEmpty(lotNo))
            var query = Db.Queryable<Dt_StockInfoDetail>()
                .Includes(x => x.StockInfo)
                .Where(x => x.MaterielCode == materielCode && x.StockQuantity > x.OutboundQuantity);
            if (!string.IsNullOrEmpty(batchNo))
            {
                var stockSort = Db.Queryable<Dt_StockInfo>().Where(x => locationCodes.Contains(x.LocationCode)).Includes(x => x.Details).Where(x => x.Details.Any(v => v.MaterielCode == materielCode && v.BatchNo == lotNo)).ToList();
                stockInfos = stockSort.OrderBy(x => x.Details.FirstOrDefault()?.EffectiveDate).ThenBy(x => x.Details.Sum(v => v.StockQuantity)).ToList();
            }
            else
            {
                var stockSort = Db.Queryable<Dt_StockInfo>().Where(x => locationCodes.Contains(x.LocationCode)).Includes(x => x.Details).Where(x => x.Details.Any(v => v.MaterielCode == materielCode)).ToList();
                stockInfos = stockSort.OrderBy(x => x.Details.FirstOrDefault()?.EffectiveDate).ThenBy(x => x.Details.Sum(v => v.StockQuantity)).ToList();
                query = query.Where(x => x.BatchNo == batchNo);
            }
            return stockInfos;
            return await query.OrderBy(x => x.ProductionDate).ToListAsync();
        }
        public List<Dt_StockInfo> GetStockInfos(string materielCode, string lotNo, List<string> locationCodes)
        {
            var query = Db.Queryable<Dt_StockInfo>()
             .Where(x => locationCodes.Contains(x.LocationCode)
             //  && x.StockStatus == (int)StockStatusEmun.正常)
             ).Includes(x => x.Details);
            if (!string.IsNullOrEmpty(materielCode))
            {
                query = query.Where(x => x.Details.Any(d => d.MaterielCode == materielCode));
            }
            if (!string.IsNullOrEmpty(lotNo))
            {
                query = query.Where(x => x.Details.Any(d => d.BatchNo == lotNo));
            }
            var stocks = query.ToList();
            return stocks.OrderBy(x => x.Details.Where(d => d.MaterielCode == materielCode &&
                           (string.IsNullOrEmpty(lotNo) || d.BatchNo == lotNo)).Min(d => d.ProductionDate)).ToList();
            //ISugarQueryable<Dt_LocationInfo> sugarQueryable = Db.Queryable<Dt_LocationInfo>().Where(x => locationCodes.Contains(x.LocationCode));
            //ISugarQueryable<Dt_StockInfo> sugarQueryable1 = Db.Queryable<Dt_StockInfo>().Includes(x => x.Details).Where(x => x.Details.Any(v => v.MaterielCode == materielCode));
            //return sugarQueryable.InnerJoin(sugarQueryable1, (a, b) => a.LocationCode == b.LocationCode).Select((a, b) => b).OrderBy(a => a.CreateDate).Includes(a => a.Details).ToList();
@@ -173,5 +210,11 @@
            return GetStockInfos(materielCode, batchNo, locationCodes);
        }
        public Dt_StockInfo GetPalletStockInfo(int locationType)
        {
            return Db.Queryable<Dt_StockInfo>().Where(x => x.StockStatus == StockStatusEmun.入库完成.ObjToInt() && SqlFunc.Subqueryable<Dt_LocationInfo>().Where(v => v.LocationCode == x.LocationCode && v.LocationType == locationType && v.LocationStatus == LocationStatusEnum.Pallet.ObjToInt() && (v.EnableStatus == EnableStatusEnum.OnlyOut.ObjToInt() || EnableStatusEnum.Normal.ObjToInt() == v.EnableStatus)).Any()).OrderBy(x => x.ModifyDate).First();
        }
    }
}