pan
2025-11-30 c100108c13c74ebd99253c4c144b262720b55ecd
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs
@@ -66,6 +66,11 @@
            var outboundOrder = _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
                .First(x => x.Id == orderId);
            if (!CanReassignOrder(outboundOrder))
            {
                throw new Exception($"订单{outboundOrder.OrderNo}状态不允许重新分配库存");
            }
            List<Dt_StockInfo> outStocks = new List<Dt_StockInfo>();
            List<Dt_OutStockLockInfo> outStockLockInfos = new List<Dt_OutStockLockInfo>();
            List<Dt_LocationInfo> locationInfos = new List<Dt_LocationInfo>();
@@ -79,7 +84,7 @@
                    BatchNo = x.Key.BatchNo,
                    SupplyCode = x.Key.SupplyCode,
                    Details = x.ToList(),
                    TotalNeedQuantity = x.Sum(v => v.OrderQuantity - v.OverOutQuantity - v.LockQuantity - v.MoveQty)
                    TotalNeedQuantity = CalculateReassignNeedQuantity(x.ToList())
                })
                .Where(x => x.TotalNeedQuantity > 0)
                .ToList();
@@ -93,7 +98,7 @@
                if (!stockInfos.Any())
                {
                    throw new Exception($"物料[{item.MaterielCode}]批次[{item.BatchNo}]未找到可分配库存");
                    throw new Exception($"物料[{item.MaterielCode}]批次[{item.BatchNo}]供应商[{item.SupplyCode}]未找到可分配库存");
                }
                // åˆ†é…åº“存(按先进先出)
@@ -127,6 +132,39 @@
            }
            return (outStocks, outboundOrderDetails, outStockLockInfos, locationInfos);
        }
        /// <summary>
        /// æ£€æŸ¥è®¢å•是否允许重新分配
        /// </summary>
        private bool CanReassignOrder(Dt_OutboundOrder outboundOrder)
        {
            // å…è®¸é‡æ–°åˆ†é…çš„状态
            var allowedStatus = new[] {OutOrderStatusEnum.未开始, OutOrderStatusEnum.出库中,OutOrderStatusEnum.部分完成};
            return allowedStatus.Contains((OutOrderStatusEnum)outboundOrder.OrderStatus);
        }
        /// <summary>
        /// é‡æ–°è®¡ç®—需求数量(考虑重新分配的场景)
        /// </summary>
        private decimal CalculateReassignNeedQuantity(List<Dt_OutboundOrderDetail> details)
        {
            decimal totalNeed = 0;
            foreach (var detail in details)
            {
                // å…³é”®ä¿®æ”¹ï¼šé‡æ–°åˆ†é…æ—¶ï¼Œåªè€ƒè™‘未出库的部分,忽略锁定数量
                // å› ä¸ºé”å®šæ•°é‡åœ¨å›žåº“时已经被重置
                decimal remainingNeed = detail.OrderQuantity - detail.OverOutQuantity - detail.MoveQty;
                if (remainingNeed > 0)
                {
                    totalNeed += remainingNeed;
                }
            }
            return totalNeed;
        }
        private (bool success, string message) DistributeLockQuantityByFIFO(
           List<Dt_OutboundOrderDetail> details,
@@ -231,7 +269,7 @@
        /// <summary>
        /// ä¸ºåˆ†æ‰¹åˆ†é…åº“å­˜
        /// </summary>
        public  async Task<(List<Dt_StockInfo>, List<Dt_OutboundOrderDetail>, List<Dt_OutStockLockInfo>, List<Dt_LocationInfo>)>
        public async Task<(List<Dt_StockInfo>, List<Dt_OutboundOrderDetail>, List<Dt_OutStockLockInfo>, List<Dt_LocationInfo>)>
            AssignStockForBatch(Dt_OutboundOrderDetail orderDetail, decimal batchQuantity, string batchNo)
        {
            if (orderDetail == null)
@@ -263,7 +301,7 @@
            foreach (var item in groupDetails)
            {
                var needQuantity = item.TotalNeedQuantity;
                // èŽ·å–å¯ç”¨åº“å­˜ï¼ˆæŒ‰å…ˆè¿›å…ˆå‡ºæŽ’åºï¼‰
                List<Dt_StockInfo> stockInfos = _stockService.StockInfoService.GetUseableStocks(item.MaterielCode, item.BatchNo, item.SupplyCode);
                if (!stockInfos.Any())
@@ -272,7 +310,7 @@
                }
                // åˆ†é…åº“存(按先进先出)
                var (autoAssignStocks, stockAllocations) = _stockService.StockInfoService.GetOutboundStocks  (stockInfos, item.MaterielCode, needQuantity, out decimal residueQuantity);
                var (autoAssignStocks, stockAllocations) = _stockService.StockInfoService.GetOutboundStocks(stockInfos, item.MaterielCode, needQuantity, out decimal residueQuantity);
                // æ£€æŸ¥åˆ†é…ç»“æžœ
                decimal allocatedQuantity = needQuantity - residueQuantity;
@@ -300,7 +338,7 @@
                locationInfos.AddRange(_locationInfoService.GetLocationInfos(
                  outStocks.Select(x => x.LocationCode).Distinct().ToList()));
            }
            return (outStocks, groupDetails.SelectMany(x => x.Details).ToList(), outStockLockInfos, locationInfos);
@@ -370,15 +408,16 @@
                    {
                        return (false, $"库存明细ID[{stockDetail.Id}]的条码为空");
                    }
                    // åˆ›å»ºå‡ºåº“锁定信息
                    var lockInfo = _outStockLockInfoService.GetOutStockLockInfo(
                        outboundOrder, detail, stockInfo, assignQuantity, stockDetail.Barcode,batchNo);
                        outboundOrder, detail, stockInfo, assignQuantity, stockDetail.Barcode, batchNo);
                    outStockLockInfos.Add(lockInfo);
                    // æ›´æ–°æ˜Žç»†çš„已分配数量
                    detail.AllocatedQuantity += assignQuantity;
                    detail.LockQuantity = detail.AllocatedQuantity;
                    remainingAllocate -= assignQuantity;
                    allocatedQuantity += assignQuantity;
                }