pan
2025-12-02 1527b89f90c48e5791c740a877aec305a2065064
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -624,24 +624,16 @@
                    foreach (var detail in stockInfo.Details)
                    {
                        detail.Status = StockStatusEmun.入库完成.ObjToInt(); 
                        // ç¡®ä¿åº“存数量与出库数量一致
                        if (detail.Status == StockStatusEmun.入库完成.ObjToInt())
                        {
                            detail.OutboundQuantity = 0; // å…¥åº“完成时出库数量清零
                        }
                    }
                      _stockService.StockInfoDetailService.Repository.UpdateData(stockInfo.Details);
                }
                  _stockService.StockInfoService.Repository.UpdateData(stockInfo);
                // å¤„理回库相关的库存明细
                await ProcessStockDetailsForReturn(task, stockInfo.Id);
                // åˆ é™¤é›¶åº“存数据
                await DeleteZeroQuantityStockDetails(stockInfo.Id);
                await UpdateAffectedOrderDetails(task.OrderNo, returnLocks);
                // æ›´æ–°è´§ä½çŠ¶æ€
                if (stockInfo.PalletType == PalletTypeEnum.Empty.ObjToInt())
                {
@@ -653,13 +645,6 @@
                }
             
                 _locationInfoService.Repository.UpdateData(locationInfo);
                // æ›´æ–°è®¢å•相关数据
                await UpdateOrderDataAfterReturn(task.OrderNo, returnLocks);
                // èŽ·å–å¹¶æ›´æ–°å‡ºåº“è®¢å•
                var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
                    .FirstAsync(x => x.OrderNo == task.OrderNo);
                task.TaskStatus = TaskStatusEnum.Finish.ObjToInt(); 
@@ -675,23 +660,35 @@
                    "",
                    task.TaskNum
                );
                await RecalculateOrderStatus(task.OrderNo);
                _unitOfWorkManage.CommitTran(); // æäº¤äº‹åŠ¡
                _logger.LogInformation($"托盘回库完成处理成功 - ä»»åŠ¡å·: {task.TaskNum}, æ‰˜ç›˜: {task.PalletCode}, è®¢å•: {task.OrderNo}");
                _ = Task.Run(async () =>
                {
                    try
                    {
                        var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
                            .FirstAsync(x => x.OrderNo == task.OrderNo);
                if (outboundOrder != null)
                {
                    // æ£€æŸ¥è®¢å•状态是否需要更新
                    await CheckAndUpdateOrderStatusAfterReturn(task.OrderNo);
                    // å¤„理MES反馈
                            // æ£€æŸ¥è®¢å•是否已完成,只有完成时才向MES反馈
                            if (outboundOrder.OrderStatus == (int)OutOrderStatusEnum.出库完成)
                            {
                    await HandleOutboundOrderToMESCompletion(outboundOrder, outboundOrder.OrderNo);
                }
                else
                {
                    _logger.LogInformation($"TaskService InPickTaskCompleted: {task.TaskNum} ,未找到出库单。");
                                _logger.LogInformation($"订单{task.OrderNo}状态为{outboundOrder.OrderStatus},暂不向MES反馈");
                }
                _unitOfWorkManage.CommitTran(); // æäº¤äº‹åŠ¡
                _logger.LogInformation($"回库任务完成处理成功 - ä»»åŠ¡å·: {task.TaskNum}, æ‰˜ç›˜: {task.PalletCode}");
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError($"异步MES反馈处理失败 - OrderNo: {task.OrderNo}, Error: {ex.Message}");
                    }
                });
            }
            catch (Exception ex)
            {
@@ -702,107 +699,151 @@
            return WebResponseContent.Instance.OK();
        }
        /// <summary>
        /// å›žåº“后更新订单数据
        // <summary>
        /// æ›´æ–°å—影响的订单明细锁定数量
        /// </summary>
        private async Task UpdateOrderDataAfterReturn(string orderNo, List<Dt_OutStockLockInfo> returnLocks)
        private async Task UpdateAffectedOrderDetails(string orderNo, List<Dt_OutStockLockInfo> returnLocks)
        {
            try
            {
                // èŽ·å–æ‰€æœ‰å—å½±å“çš„è®¢å•æ˜Žç»†ID
                // èŽ·å–å—å½±å“çš„è®¢å•æ˜Žç»†ID(去重)
                var affectedDetailIds = returnLocks
                    .Select(x => x.OrderDetailId)
                    .Distinct()
                    .ToList();
                if (!affectedDetailIds.Any())
                {
                    _logger.LogInformation($"没有受影响的订单明细 - OrderNo: {orderNo}");
                    return;
                }
                _logger.LogInformation($"更新{affectedDetailIds.Count}个受影响的订单明细 - OrderNo: {orderNo}");
                foreach (var detailId in affectedDetailIds)
                {
                    // è®¡ç®—该订单明细的回库总数量
                    var detailReturnLocks = returnLocks
                        .Where(x => x.OrderDetailId == detailId)
                        .ToList();
                    // é‡æ–°è®¡ç®—该订单明细的锁定数量
                    decimal currentLockQty = await CalculateOrderDetailLockQuantity(detailId);
                    decimal totalReturnQty = detailReturnLocks.Sum(x => x.AssignQuantity - x.PickedQty);
                    if (totalReturnQty > 0)
                    // æ£€æŸ¥æ•°æ®ä¸€è‡´æ€§
                    if (currentLockQty < 0)
                    {
                        _logger.LogWarning($"锁定数量计算为负值 - OrderDetailId: {detailId}, å½“前值: {currentLockQty},重置为0");
                        currentLockQty = 0;
                    }
                        // èŽ·å–è®¢å•æ˜Žç»†
                        var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                            .FirstAsync(x => x.Id == detailId);
                        if (orderDetail != null)
                    if (orderDetail == null)
                        {
                            // æ›´æ–°é”å®šæ•°é‡ï¼ˆå›žåº“后锁定数量应减少)
                            var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                                .Where(x => x.OrderDetailId == detailId &&
                                           x.Status == (int)OutLockStockStatusEnum.出库中)
                                .ToListAsync();
                        _logger.LogWarning($"未找到订单明细 - OrderDetailId: {detailId}");
                        continue;
                    }
                            decimal remainingLockQty = remainingLocks.Sum(x => x.AssignQuantity - x.PickedQty);
                            // æ›´æ–°è®¢å•明细
                    // æ›´æ–°é”å®šæ•°é‡
                    if (orderDetail.LockQuantity != currentLockQty)
                    {
                            await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
                                .SetColumns(it => new Dt_OutboundOrderDetail
                                {
                                    LockQuantity = remainingLockQty,
                                LockQuantity = currentLockQty,
                                })
                                .Where(it => it.Id == detailId)
                                .ExecuteCommandAsync();
                            // æ›´æ–°è®¢å•明细状态
                            await UpdateOrderDetailStatus(detailId);
                        _logger.LogInformation($"更新订单明细锁定数量 - OrderDetailId: {detailId}, " +
                                              $"旧值: {orderDetail.LockQuantity}, æ–°å€¼: {currentLockQty}");
                    }
                            _logger.LogInformation($"回库更新订单明细 - OrderDetailId: {detailId}, " +
                                                  $"扣减锁定数量: {totalReturnQty}, æ–°é”å®šæ•°é‡: {remainingLockQty}");
                        }
                    }
                    // æ›´æ–°è®¢å•明细状态
                    await UpdateOrderDetailStatus(orderDetail);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"UpdateOrderDataAfterReturn失败 - OrderNo: {orderNo}, Error: {ex.Message}");
                _logger.LogError($"UpdateAffectedOrderDetails失败 - OrderNo: {orderNo}, Error: {ex.Message}");
                throw;
            }
        }
        /// <summary>
        /// æ›´æ–°è®¢å•明细状态
        /// é‡æ–°è®¡ç®—订单明细锁定数量
        /// </summary>
        private async Task UpdateOrderDetailStatus(int orderDetailId)
        private async Task<decimal> CalculateOrderDetailLockQuantity(int orderDetailId)
        {
            try
            {
                var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                    .FirstAsync(x => x.Id == orderDetailId);
                // æŸ¥æ‰¾è¯¥è®¢å•明细下所有状态为"出库中"的锁定记录
                var activeLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                    .Where(x => x.OrderDetailId == orderDetailId &&
                               x.Status == (int)OutLockStockStatusEnum.出库中)
                    .ToListAsync();
                if (orderDetail == null)
                // è¿‡æ»¤æ‹†åŒ…记录
                var filteredLocks = new List<Dt_OutStockLockInfo>();
                foreach (var lockInfo in activeLocks)
                {
                    _logger.LogWarning($"UpdateOrderDetailStatus失败:未找到订单明细,ID: {orderDetailId}");
                    return;
                    // å¦‚果是拆包记录,需要特殊处理
                    if (lockInfo.IsSplitted == 1 && lockInfo.ParentLockId.HasValue)
                    {
                        // æŸ¥æ‰¾çˆ¶é”å®šè®°å½•
                        var parentLock = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                            .Where(x => x.Id == lockInfo.ParentLockId.Value)
                            .FirstAsync();
                        // å¦‚果父记录存在且状态也是出库中,则只计算父记录
                        if (parentLock != null && parentLock.Status == (int)OutLockStockStatusEnum.出库中)
                        {
                            // çˆ¶è®°å½•已经在列表中,跳过当前拆包记录
                            continue;
                        }
                }
                    filteredLocks.Add(lockInfo);
                }
                decimal totalLockQty = filteredLocks.Sum(x => x.AssignQuantity - x.PickedQty);
                _logger.LogDebug($"计算锁定数量 - OrderDetailId: {orderDetailId}, " +
                               $"找到{filteredLocks.Count}个有效锁定记录, " +
                               $"总锁定数量: {totalLockQty}");
                return totalLockQty;
            }
            catch (Exception ex)
            {
                _logger.LogError($"CalculateOrderDetailLockQuantity失败 - OrderDetailId: {orderDetailId}, Error: {ex.Message}");
                return 0;
            }
        }
        /// <summary>
        /// æ›´æ–°è®¢å•明细状态
        /// </summary>
        private async Task UpdateOrderDetailStatus(Dt_OutboundOrderDetail orderDetail)
        {
            try
            {
                int newStatus = orderDetail.OrderDetailStatus;
                // 1. æ£€æŸ¥æ˜¯å¦å·²å®Œæˆ
                // æ ¹æ®å®žé™…枚举值调整
                // 1. æ£€æŸ¥æ˜¯å¦å·²å®Œæˆï¼ˆå·²å‡ºåº“数量 >= éœ€æ±‚数量)
                if (orderDetail.OverOutQuantity >= orderDetail.NeedOutQuantity)
                {
                    newStatus = (int)OrderDetailStatusEnum.Over;
                    newStatus = (int)OrderDetailStatusEnum.Over; // å·²å®Œæˆ
                }
                // 2. æ£€æŸ¥æ˜¯å¦æ­£åœ¨è¿›è¡Œä¸­ï¼ˆæœ‰é”å®šæ•°é‡æˆ–部分拣选)
                else if (orderDetail.LockQuantity > 0 ||
                         (orderDetail.OverOutQuantity > 0 && orderDetail.OverOutQuantity < orderDetail.NeedOutQuantity))
                // 2. æ£€æŸ¥æ˜¯å¦æœ‰éƒ¨åˆ†å‡ºåº“或有锁定数量
                else if (orderDetail.OverOutQuantity > 0 || orderDetail.LockQuantity > 0)
                {
                    newStatus = (int)OrderDetailStatusEnum.Outbound;
                    newStatus = (int)OrderDetailStatusEnum.Outbound; // éƒ¨åˆ†å®Œæˆ/进行中
                }
                // 3. æ£€æŸ¥æ˜¯å¦æœ‰é”å®šä½†æœªæ‹£é€‰
                else if (orderDetail.LockQuantity > 0 && orderDetail.OverOutQuantity == 0)
                {
                    newStatus = (int)OrderDetailStatusEnum.AssignOverPartial;
                }
                // 4. å¦åˆ™ä¸ºæ–°è®¢å•
                // 3. å¦åˆ™ä¸ºæ–°è®¢å•
                else
                {
                    newStatus = (int)OrderDetailStatusEnum.New;
                    newStatus = (int)OrderDetailStatusEnum.New; // æ–°å»º
                }
                // åªæœ‰çŠ¶æ€å˜åŒ–æ—¶æ‰æ›´æ–°
@@ -813,10 +854,10 @@
                        {
                            OrderDetailStatus = newStatus, 
                        })
                        .Where(it => it.Id == orderDetailId)
                        .Where(it => it.Id == orderDetail.Id)
                        .ExecuteCommandAsync();
                    _logger.LogInformation($"更新订单明细状态 - OrderDetailId: {orderDetailId}, " +
                    _logger.LogInformation($"更新订单明细状态 - OrderDetailId: {orderDetail.Id}, " +
                                          $"旧状态: {orderDetail.OrderDetailStatus}, æ–°çŠ¶æ€: {newStatus}, " +
                                          $"已出库: {orderDetail.OverOutQuantity}/{orderDetail.NeedOutQuantity}, " +
                                          $"锁定数量: {orderDetail.LockQuantity}");
@@ -824,23 +865,32 @@
            }
            catch (Exception ex)
            {
                _logger.LogError($"UpdateOrderDetailStatus失败 - OrderDetailId: {orderDetailId}, Error: {ex.Message}");
                _logger.LogError($"UpdateOrderDetailStatus失败 - OrderDetailId: {orderDetail.Id}, Error: {ex.Message}");
                throw;
            }
        }
        /// <summary>
        /// å›žåº“后检查并更新订单状态
        /// é‡æ–°è®¡ç®—并更新订单状态
        /// </summary>
        private async Task CheckAndUpdateOrderStatusAfterReturn(string orderNo)
        private async Task RecalculateOrderStatus(string orderNo)
        {
            try
            {
                // èŽ·å–è®¢å•çš„æ‰€æœ‰æ˜Žç»†
                var orderDetails = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                    .LeftJoin<Dt_OutboundOrder>((o, item) => o.OrderId == item.Id)
                    .Where((o, item) => item.OrderNo == orderNo)
                    .Select((o, item) => o)
                    .ToListAsync();
                if (!orderDetails.Any())
                {
                    _logger.LogWarning($"未找到订单明细 - OrderNo: {orderNo}");
                    return;
                }
                // æ£€æŸ¥çŠ¶æ€
                bool allCompleted = true;
                bool hasInProgress = false;
@@ -854,7 +904,7 @@
                    // æ£€æŸ¥æ˜¯å¦æœ‰è¿›è¡Œä¸­çš„任务(锁定或部分拣选)
                    if (detail.LockQuantity > 0 ||
                        detail.OrderDetailStatus == OrderDetailStatusEnum.Outbound.ObjToInt())
                        detail.OrderDetailStatus == (int)OrderDetailStatusEnum.Outbound)
                    {
                        hasInProgress = true;
                    }
@@ -863,7 +913,11 @@
                var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
                    .FirstAsync(x => x.OrderNo == orderNo);
                if (outboundOrder == null) return;
                if (outboundOrder == null)
                {
                    _logger.LogWarning($"未找到出库订单 - OrderNo: {orderNo}");
                    return;
                }
                int newStatus;
                if (allCompleted)
@@ -890,57 +944,16 @@
                        .Where(x => x.OrderNo == orderNo)
                        .ExecuteCommandAsync();
                    _logger.LogInformation($"回库后更新订单状态 - OrderNo: {orderNo}, æ–°çŠ¶æ€: {newStatus}");
                    _logger.LogInformation($"更新订单状态 - OrderNo: {orderNo}, æ—§çŠ¶æ€: {outboundOrder.OrderStatus}, æ–°çŠ¶æ€: {newStatus}");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"CheckAndUpdateOrderStatusAfterReturn失败 - OrderNo: {orderNo}, Error: {ex.Message}");
                _logger.LogError($"RecalculateOrderStatus失败 - OrderNo: {orderNo}, Error: {ex.Message}");
                throw;
            }
        }
        /// <summary>
        /// å¤„理回库的库存明细(增强版)
        /// </summary>
        private async Task ProcessStockDetailsForReturn(Dt_Task task, int stockId)
        {
            try
            {
                // èŽ·å–æ‰€æœ‰éœ€è¦å¤„ç†çš„åº“å­˜æ˜Žç»†
                var stockDetails = await _stockService.StockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                    .Where(x => x.StockId == stockId)
                    .ToListAsync();
                foreach (var detail in stockDetails)
                {
                    // ç¡®ä¿åº“存状态正确
                    if (detail.Status == StockStatusEmun.入库确认.ObjToInt())
                    {
                        // å¦‚果已经是入库确认状态,更新为入库完成
                        detail.Status = StockStatusEmun.入库完成.ObjToInt();
                        detail.OutboundQuantity = 0;
                        await _stockService.StockInfoDetailService.Db.Updateable(detail).ExecuteCommandAsync();
                        _logger.LogInformation($"更新库存明细状态 - æ¡ç : {detail.Barcode}, " +
                                              $"新状态: {detail.Status}, å‡ºåº“数量: {detail.OutboundQuantity}");
                    }
                    else if (detail.Status == StockStatusEmun.出库锁定.ObjToInt() ||
                             detail.Status == StockStatusEmun.出库完成.ObjToInt())
                    {
                        // è¿™äº›çŠ¶æ€ä¸åº”è¯¥å­˜åœ¨ï¼Œè®°å½•è­¦å‘Š
                        _logger.LogWarning($"异常库存状态 - æ¡ç : {detail.Barcode}, çŠ¶æ€: {detail.Status}, " +
                                         $"任务号: {task.TaskNum}");
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"ProcessStockDetailsForReturn失败 - StockId: {stockId}, Error: {ex.Message}");
                throw;
            }
        }
        /// <summary>
        /// åˆ é™¤é›¶åº“存数据(增强版)
@@ -1035,7 +1048,7 @@
                                MaterialCode = detail.MaterielCode,
                                LineNo = detail.lineNo,  
                                WarehouseCode = detail.WarehouseCode,
                                Qty = detailLocks.Sum(x=>x.PickedQty),
                                Qty =0,
                                Unit = detail.BarcodeUnit,
                                Barcodes = new List<BarcodeInfo> ()
                            };
@@ -1047,7 +1060,7 @@
                                    SupplyCode = item.SupplyCode,
                                    BatchNo = item.BatchNo,
                                    Unit = item.BarcodeUnit,
                                    Qty = item.PickedQty
                                    Qty = 0
                                };
                                // å•位不一致时转换
                                if (item.BarcodeUnit != item.Unit)
@@ -1115,8 +1128,8 @@
                                materialCode = detail.MaterielCode,
                                lineNo = detail.lineNo, // æ³¨æ„ï¼šè¿™é‡Œå¯èƒ½éœ€è¦è°ƒæ•´å­—段名
                                warehouseCode = detail.WarehouseCode,
                                qty = detail.PickedQty,
                                currentDeliveryQty = detail.PickedQty,
                                qty = 0,
                                currentDeliveryQty =0,
                                unit = detail.Unit,
                                barcodes = new List<WIDESEA_DTO.Outbound.BarcodesModel>()
                            };