pan
2025-12-02 61d8f975a9f02a4e1d3bd0eb234851e6da39fff4
提交
已修改4个文件
828 ■■■■ 文件已修改
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_BasicService/InvokeMESService.cs 314 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutStockLockInfoService.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs 500 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_BasicService/InvokeMESService.cs
@@ -275,8 +275,7 @@
                                               MaterialCode = group.Key.MaterielCode,
                                               LineNo = group.Key.InboundOrderRowNo,
                                               WarehouseCode = group.Key.WarehouseCode,
                                               Qty = group.Sum(x => x.BarcodeQty),
                                               // warehouseCode= "1072",
                                               Qty = group.Sum(x => x.BarcodeQty),
                                               Unit = group.Key.BarcodeUnit,
                                               Barcodes = group.Select(row => new BarcodeInfo
                                               {
@@ -354,62 +353,88 @@
                    var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>().FirstAsync(x => x.OrderNo == orderNo);
                    if (outboundOrder != null && outboundOrder.IsBatch == 0)
                    {
                        await HandleOutboundOrderToMESCompletion(outboundOrder, orderNo);
                        var result = await HandleOutboundOrderToMESCompletion(outboundOrder, orderNo);
                        return result;
                    }
                    else if (outboundOrder != null && outboundOrder.IsBatch == 1)
                    {
                        await HandleOutboundOrderBatchToMESCompletion(outboundOrder, orderNo);
                        var result = await HandleOutboundOrderBatchToMESCompletion(outboundOrder, orderNo);
                        return result;
                    }
                }
            }
            return WebResponseContent.Instance.OK();
        }
        private async Task HandleOutboundOrderBatchToMESCompletion(Dt_OutboundOrder outboundOrder, string orderNo)
        private async Task<WebResponseContent> HandleOutboundOrderBatchToMESCompletion(Dt_OutboundOrder outboundOrder, string orderNo)
        {
            // å®šä¹‰é»˜è®¤è¿”回(成功态)
            WebResponseContent response = WebResponseContent.Instance.OK("回传MES处理完成");
            try
            {
                // æ ¡éªŒï¼šå·²å›žä¼ ç›´æŽ¥è¿”回错误
                if (outboundOrder.ReturnToMESStatus == 1)
                {
                    return;
                    return WebResponseContent.Instance.Error("该单已经回传!");
                }
                // æŸ¥è¯¢è®¢å•明细(仅查询未回传成功的)
                var orderDetails = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                    .LeftJoin<Dt_OutboundOrder>((o, item) => o.OrderId == item.Id)
                    .Where((o, item) => item.OrderNo == orderNo && item.ReturnToMESStatus != 1)
                    .Select((o, item) => o)
                    .ToListAsync();
                var detailids = new List<int>();
                if (!orderDetails.Any())
                {
                    return WebResponseContent.Instance.Error("暂无需要处理的订单明细");
                }
                //  ç­›é€‰å·²å®Œæˆå‡ºåº“的明细ID
                var detailIds = new List<int>();
                var allCompleted = true;
                foreach (var detail in orderDetails.Where(x => x.ReturnToMESStatus == 0).ToList())
                // ç­›é€‰å¾…回传的明细(ReturnToMESStatus=0)
                var pendingDetails = orderDetails.Where(x => x.ReturnToMESStatus == 0).ToList();
                foreach (var detail in pendingDetails)
                {
                    if (detail.OverOutQuantity >= detail.NeedOutQuantity)
                    {
                        detailids.Add(detail.Id);
                        detailIds.Add(detail.Id);
                    }
                    else
                    {
                        allCompleted = false;
                    }
                }
                // å­˜åœ¨å›žä¼ å¤±è´¥çš„æ˜Žç»†ï¼ˆReturnToMESStatus=2),标记未完成
                if (orderDetails.Any(x => x.ReturnToMESStatus == 2))
                {
                    allCompleted = false;
                }
                //  æ›´æ–°è®¢å•状态
                int newStatus = allCompleted ? (int)OutOrderStatusEnum.出库完成 : (int)OutOrderStatusEnum.出库中;
                if (outboundOrder.OrderStatus != newStatus)
                {
                    await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
                    // ä¿®æ­£åŽŸæœ‰è¯­æ³•é”™è¯¯ï¼šSetColumns æ˜¯èµ‹å€¼ï¼ˆ=)而非判断(==)
                    int updateCount = await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
                        .SetColumns(x => x.OrderStatus == newStatus)
                        .Where(x => x.OrderNo == orderNo)
                        .ExecuteCommandAsync();
                    if (updateCount <= 0)
                    {
                        _logger.LogWarning($"更新出库单状态失败 - OrderNo: {orderNo}, ç›®æ ‡çŠ¶æ€: {newStatus}");
                        // çŠ¶æ€æ›´æ–°å¤±è´¥ä¸ä¸­æ–­æµç¨‹ï¼Œä½†è®°å½•è­¦å‘Š
                    }
                }
                var documentno = UniqueValueGenerator.Generate();
                var feedmodel = new FeedbackOutboundRequestModel
                // æž„建回传MES的模型
                var documentNo = UniqueValueGenerator.Generate();
                var feedModel = new FeedbackOutboundRequestModel
                {
                    reqCode = Guid.NewGuid().ToString(),
                    reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
@@ -418,137 +443,185 @@
                    operationType = 1,
                    Operator = outboundOrder.Operator,
                    orderNo = outboundOrder.UpperOrderNo,
                    documentsNO = documentno,
                    documentsNO = documentNo,
                    status = outboundOrder.OrderStatus,
                    details = new List<FeedbackOutboundDetailsModel>()
                };
                foreach (var detail in orderDetails.Where(x => detailids.Contains(x.Id)).ToList())
                // å¡«å……明细和条码信息
                foreach (var detail in orderDetails.Where(x => detailIds.Contains(x.Id)).ToList())
                {
                    // èŽ·å–è¯¥æ˜Žç»†å¯¹åº”çš„æ¡ç ä¿¡æ¯ï¼ˆä»Žé”å®šè®°å½•ï¼‰
                    // æŸ¥è¯¢è¯¥æ˜Žç»†å¯¹åº”的锁定条码记录
                    var detailLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                        .Where(x => x.OrderNo == orderNo && detail.Id == x.OrderDetailId &&
                                   x.Status == (int)OutLockStockStatusEnum.拣选完成)
                        .Where(x => x.OrderNo == orderNo
                                   && detail.Id == x.OrderDetailId
                                   && (x.Status == (int)OutLockStockStatusEnum.拣选完成
                                       || x.Status == (int)OutLockStockStatusEnum.已回库))
                        .ToListAsync();
                    var detailModel = new FeedbackOutboundDetailsModel
                    {
                        materialCode = detail.MaterielCode,
                        lineNo = detail.lineNo, // æ³¨æ„ï¼šè¿™é‡Œå¯èƒ½éœ€è¦è°ƒæ•´å­—段名
                        lineNo = detail.lineNo,
                        warehouseCode = detail.WarehouseCode,
                        qty = detail.BarcodeQty, // ä½¿ç”¨è®¢å•明细的已出库数量
                        qty = detail.BarcodeQty,
                        currentDeliveryQty = detail.BarcodeQty,
                        unit = detail.BarcodeUnit,
                        barcodes = new List<WIDESEA_DTO.Outbound.BarcodesModel>()
                    };
                    // å¡«å……条码信息(含单位转换)
                    foreach (var item in detailLocks)
                    {
                        var barmodel = new WIDESEA_DTO.Outbound.BarcodesModel
                        var barModel = new WIDESEA_DTO.Outbound.BarcodesModel
                        {
                            barcode = item.CurrentBarcode,
                            supplyCode = item.SupplyCode,
                            batchNo = item.BatchNo,
                            unit = item.BarcodeUnit,
                            qty = item.BarcodeQty // æ¡ç çº§åˆ«çš„æ•°é‡ä»ç”¨é”å®šè®°å½•
                            qty = item.BarcodeQty
                        };
                        // å•位不一致时转换
                        if (item.BarcodeUnit != item.Unit)
                        {
                            var issueoStockResult = await _materialUnitService.ConvertAsync(item.MaterielCode, item.BarcodeQty, item.Unit, item.BarcodeUnit);
                            barmodel.unit = issueoStockResult.Unit;
                            barmodel.qty = issueoStockResult.Quantity;
                            var convertResult = await _materialUnitService.ConvertAsync(
                                item.MaterielCode, item.BarcodeQty, item.Unit, item.BarcodeUnit);
                            barModel.unit = convertResult.Unit;
                            barModel.qty = convertResult.Quantity;
                        }
                        detailModel.qty += barmodel.qty;
                        detailModel.currentDeliveryQty += barmodel.qty;
                        detailModel.barcodes.Add(barmodel);
                        detailModel.qty += barModel.qty;
                        detailModel.currentDeliveryQty += barModel.qty;
                        detailModel.barcodes.Add(barModel);
                    }
                    feedmodel.details.Add(detailModel);
                    feedModel.details.Add(detailModel);
                }
                var result = await FeedbackOutbound(feedmodel);
                if (result != null && result.code == 200)
                // è°ƒç”¨MES回传接口
                var mesResult = await FeedbackOutbound(feedModel);
                if (mesResult == null || mesResult.code != 200)
                {
                    // æ›´æ–°æ˜Žç»†ä¸ºå›žä¼ å¤±è´¥ï¼ˆReturnToMESStatus=2)
                    await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
                           .SetColumns(it => new Dt_OutboundOrderDetail
                           {
                               ReturnToMESStatus = 1,
                               documentsNO = documentno,
                           })
                        .Where(x => detailids.Contains(x.Id))
                        .SetColumns(it => new Dt_OutboundOrderDetail
                        {
                            ReturnToMESStatus = 2,
                            documentsNO = documentNo,
                        })
                        .Where(x => detailIds.Contains(x.Id))
                        .ExecuteCommandAsync();
                    if (allCompleted && newStatus == (int)OutOrderStatusEnum.出库完成)
                    return WebResponseContent.Instance.Error($"回传MES失败");
                }
                //MES回传成功:更新明细为回传成功状态
                await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
                    .SetColumns(it => new Dt_OutboundOrderDetail
                    {
                        await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
                          .SetColumns(x => x.ReturnToMESStatus == 1)
                          .Where(x => x.OrderNo == orderNo)
                          .ExecuteCommandAsync();
                    }
                    else
                    {
                        var dborderDetails = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                              .LeftJoin<Dt_OutboundOrder>((o, item) => o.OrderId == item.Id)
                              .Where((o, item) => item.OrderNo == orderNo && item.ReturnToMESStatus != 1)
                              .Select((o, item) => o)
                              .ToListAsync();
                        var secallCompleted = true;
                        foreach (var detail in orderDetails.Where(x => x.ReturnToMESStatus == 0).ToList())
                        ReturnToMESStatus = 1,
                        documentsNO = documentNo,
                    })
                    .Where(x => detailIds.Contains(x.Id))
                    .ExecuteCommandAsync();
                // æ ¡éªŒæ˜¯å¦æ‰€æœ‰æ˜Žç»†éƒ½å®Œæˆï¼Œæ›´æ–°è®¢å•最终状态
                if (allCompleted && newStatus == (int)OutOrderStatusEnum.出库完成)
                {
                    await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
                        .SetColumns(x => new Dt_OutboundOrder
                        {
                            if (detail.OverOutQuantity < detail.NeedOutQuantity)
                            {
                                secallCompleted = false;
                            }
                        }
                        if (secallCompleted)
                        {
                            await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
                                 .SetColumns(it => new Dt_OutboundOrder
                                 {
                                     ReturnToMESStatus = 1,
                                     OrderStatus = OutOrderStatusEnum.出库完成.ObjToInt(),
                                 })
                                 .Where(x => x.OrderNo == orderNo)
                                 .ExecuteCommandAsync();
                        }
                    }
                            ReturnToMESStatus = 1,
                            OrderStatus = newStatus
                        })
                        .Where(x => x.OrderNo == orderNo)
                        .ExecuteCommandAsync();
                }
                else
                {
                    await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
                         .SetColumns(it => new Dt_OutboundOrderDetail
                         {
                             ReturnToMESStatus = 2,
                             documentsNO = documentno,
                         })
                      .Where(x => detailids.Contains(x.Id))
                      .ExecuteCommandAsync();
                    // äºŒæ¬¡æ ¡éªŒæ˜¯å¦æ‰€æœ‰æœªå›žä¼ æ˜Žç»†éƒ½å·²å®Œæˆ
                    var dbOrderDetails = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                        .LeftJoin<Dt_OutboundOrder>((o, item) => o.OrderId == item.Id)
                        .Where((o, item) => item.OrderNo == orderNo && item.ReturnToMESStatus != 1)
                        .Select((o, item) => o)
                        .ToListAsync();
                    var secAllCompleted = true;
                    foreach (var detail in dbOrderDetails.Where(x => x.ReturnToMESStatus == 0).ToList())
                    {
                        if (detail.OverOutQuantity < detail.NeedOutQuantity)
                        {
                            secAllCompleted = false;
                            break;
                        }
                    }
                    if (secAllCompleted)
                    {
                        await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
                            .SetColumns(it => new Dt_OutboundOrder
                            {
                                ReturnToMESStatus = 1,
                                OrderStatus = OutOrderStatusEnum.出库完成.ObjToInt(),
                            })
                            .Where(x => x.OrderNo == orderNo)
                            .ExecuteCommandAsync();
                    }
                }
                // å›žä¼ æˆåŠŸçš„æœ€ç»ˆè¿”å›ž
                response = WebResponseContent.Instance.OK($"回传MES成功,单据号:{documentNo}");
            }
            catch (Exception ex)
            {
                _logger.LogError($"CheckAndUpdateOrderStatus失败 - OrderNo: {orderNo}, Error: {ex.Message}");
                // å…¨å±€å¼‚常捕获:记录详细日志 + è¿”回错误
                string errorMsg = $"处理出库单回传MES时发生异常 - OrderNo: {orderNo}, Error: {ex.Message}, StackTrace: {ex.StackTrace}";
                _logger.LogError(ex, errorMsg); // è®°å½•带异常堆栈的日志
                // å¼‚常返回(给前端的友好提示,隐藏堆栈信息)
                response = WebResponseContent.Instance.Error("处理回传MES时发生异常,请联系管理员");
            }
            return response;
        }
        private async Task HandleOutboundOrderToMESCompletion(Dt_OutboundOrder outboundOrder, string orderNo)
        private async Task<WebResponseContent> HandleOutboundOrderToMESCompletion(Dt_OutboundOrder outboundOrder, string orderNo)
        {
            // å‰ç½®å‚数校验:空值直接返回错误
            if (outboundOrder == null)
            {
                return WebResponseContent.Instance.Error("出库单实体为空,无法处理回传MES");
            }
            if (string.IsNullOrWhiteSpace(orderNo))
            {
                return WebResponseContent.Instance.Error("订单号为空,无法处理回传MES");
            }
            try
            {
                if (outboundOrder.ReturnToMESStatus == 1)
                {
                    return;
                    return WebResponseContent.Instance.Error($"OrderNo: {orderNo}, è¯¥å•已经回传!");
                }
                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())
                {
                    return WebResponseContent.Instance.Error($"OrderNo: {orderNo} æœªæŸ¥è¯¢åˆ°è®¢å•明细");
                }
                // åˆ¤æ–­æ˜¯å¦æ‰€æœ‰æ˜Žç»†å®Œæˆå‡ºåº“
                bool allCompleted = true;
                foreach (var detail in orderDetails)
                {
@@ -559,17 +632,17 @@
                    }
                }
                //  æ›´æ–°è®¢å•状态(修正语法错误:== â†’ =)
                int newStatus = allCompleted ? (int)OutOrderStatusEnum.出库完成 : (int)OutOrderStatusEnum.出库中;
                if (outboundOrder.OrderStatus != newStatus)
                {
                    await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
                        .SetColumns(x => x.OrderStatus == newStatus)
                        .SetColumns(x => x.OrderStatus == newStatus) // å…³é”®ä¿®æ­£ï¼šèµ‹å€¼è€Œéžåˆ¤æ–­
                        .Where(x => x.OrderNo == orderNo)
                        .ExecuteCommandAsync();
                }
                //只有正常分拣完成时才向MES反馈
                // ä»…分拣完成时向MES反馈
                if (allCompleted && newStatus == (int)OutOrderStatusEnum.出库完成)
                {
                    var feedmodel = new FeedbackOutboundRequestModel
@@ -586,42 +659,47 @@
                        details = new List<FeedbackOutboundDetailsModel>()
                    };
                    // æž„建明细数据
                    foreach (var detail in orderDetails)
                    {
                        // èŽ·å–è¯¥æ˜Žç»†å¯¹åº”çš„æ¡ç ä¿¡æ¯ï¼ˆä»Žé”å®šè®°å½•ï¼‰
                        var detailLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                            .Where(x => x.OrderNo == orderNo &&
                                       x.OrderDetailId == detail.Id &&
                                       x.Status == (int)OutLockStockStatusEnum.拣选完成)
                                       (x.Status == (int)OutLockStockStatusEnum.拣选完成 || x.Status == (int)OutLockStockStatusEnum.已回库))
                            .ToListAsync();
                        var groupdata = detailLocks.GroupBy(item => new { item.MaterielCode, item.lineNo, item.BarcodeUnit, item.WarehouseCode })
                            .Select(group => new FeedbackOutboundDetailsModel
                            {
                                materialCode = group.Key.MaterielCode,
                                lineNo = group.Key.lineNo,
                                warehouseCode = group.Key.WarehouseCode,
                                qty = group.Sum(x => x.BarcodeQty),
                                currentDeliveryQty = group.Sum(x => x.BarcodeQty),
                                unit = group.Key.BarcodeUnit,
                                barcodes = group.Select(lockInfo => new WIDESEA_DTO.Outbound.BarcodesModel
                                {
                                    barcode = lockInfo.CurrentBarcode,
                                    supplyCode = lockInfo.SupplyCode,
                                    batchNo = lockInfo.BatchNo,
                                    unit = lockInfo.BarcodeUnit,
                                    qty = lockInfo.BarcodeQty
                                }).ToList()
                            }).ToList();
                        var groupdata = detailLocks.GroupBy(item => new { item.MaterielCode,item.lineNo, item.BarcodeUnit, item.WarehouseCode })
                                 .Select(group =>new FeedbackOutboundDetailsModel
                                  {
                                      materialCode = group.Key.MaterielCode,
                                      lineNo = group.Key.lineNo, // æ³¨æ„ï¼šè¿™é‡Œå¯èƒ½éœ€è¦è°ƒæ•´å­—段名
                                      warehouseCode = group.Key.WarehouseCode,
                                      qty = group.Sum(x => x.BarcodeQty),
                                      currentDeliveryQty = group.Sum(x => x.BarcodeQty),
                                      unit = group.Key.BarcodeUnit,
                                      barcodes = group.Select(lockInfo => new WIDESEA_DTO.Outbound.BarcodesModel
                                      {
                                          barcode = lockInfo.CurrentBarcode,
                                          supplyCode = lockInfo.SupplyCode,
                                          batchNo = lockInfo.BatchNo,
                                          unit = lockInfo.BarcodeUnit,
                                          qty = lockInfo.BarcodeQty // æ¡ç çº§åˆ«çš„æ•°é‡ä»ç”¨é”å®šè®°å½•
                                      }).ToList()
                                  }).ToList();
                        feedmodel.details.AddRange(groupdata);
                    }
                    //  è°ƒç”¨MES接口
                    var result = await FeedbackOutbound(feedmodel);
                    if (result != null && result.code == 200)
                    if (result == null)
                    {
                        return WebResponseContent.Instance.Error($"OrderNo: {orderNo} MES回传接口返回空");
                    }
                    if (result.code == 200)
                    {
                        //  å›žä¼ æˆåŠŸï¼šæ›´æ–°å›žä¼ çŠ¶æ€
                        await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
                            .SetColumns(x => x.ReturnToMESStatus == 1)
                            .Where(x => x.OrderId == outboundOrder.Id)
@@ -631,16 +709,26 @@
                            .SetColumns(x => x.ReturnToMESStatus == 1)
                            .Where(x => x.OrderNo == orderNo)
                            .ExecuteCommandAsync();
                        return WebResponseContent.Instance.OK("回传MES成功");
                    }
                    else
                    {
                        var errorMsg = $"OrderNo: {orderNo} å›žä¼ MES失败,错误码:{result.code},错误信息:{result.message ?? "无"}";
                        _logger.LogError(errorMsg);
                        return WebResponseContent.Instance.Error(errorMsg);
                    }
                }
                return WebResponseContent.Instance.OK("订单状态已更新,未完全完成分拣无需回传MES");
            }
            catch (Exception ex)
            {
                _logger.LogError($"CheckAndUpdateOrderStatus失败 - OrderNo: {orderNo}, Error: {ex.Message}");
                // å…¨å±€å¼‚常捕获:返回错误+记录详细日志
                var errorMsg = $"OrderNo: {orderNo} å¤„理回传MES时发生异常:{ex.Message}";
                _logger.LogError(ex, errorMsg); // è®°å½•堆栈信息便于排查
                return WebResponseContent.Instance.Error("处理回传MES时发生异常,请联系管理员");
            }
        }
    }
    public static class UniqueValueGenerator
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutStockLockInfoService.cs
@@ -74,7 +74,7 @@
                // ä½¿ç”¨ç¬¬ä¸€ä¸ªå¯ç”¨æ¡ç 
                  firstAvailableDetail = stockDetails
                    .Where(x => x.StockQuantity > x.OutboundQuantity)
                    .OrderBy(x => x.CreateDate)
                    .OrderByDescending(x => x.CreateDate)
                    .FirstOrDefault();
                if (firstAvailableDetail == null)
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs
@@ -1805,11 +1805,7 @@
                    _logger.LogInformation($"订单状态更新 - OrderNo: {orderNo}, æ—§çŠ¶æ€: {outboundOrder.OrderStatus}, æ–°çŠ¶æ€: {newStatus}");
                    // åªæœ‰æ­£å¸¸åˆ†æ‹£å®Œæˆæ—¶æ‰å‘MES反馈
                    if (allCompleted && newStatus == (int)OutOrderStatusEnum.出库完成)
                    {
                        await HandleOrderCompletion(outboundOrder, orderNo);
                    }
                }
            }
            catch (Exception ex)
@@ -2018,7 +2014,7 @@
                    // åªèŽ·å–å·²æ‹£é€‰å®Œæˆçš„é”å®šè®°å½•
                    var lists = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                        .Where(x => x.OrderNo == orderNo && x.Status == (int)OutLockStockStatusEnum.拣选完成)
                        .Where(x => x.OrderNo == orderNo && (x.Status == (int)OutLockStockStatusEnum.拣选完成 || x.Status == (int)OutLockStockStatusEnum.已回库))
                        .ToListAsync();
                    var groupedData = lists.GroupBy(item => new { item.MaterielCode, item.lineNo, item.BarcodeUnit, item.WarehouseCode })
@@ -2205,7 +2201,7 @@
                _logger.LogInformation($"订单 {orderNo} å·²æ ‡è®°ä¸ºå‡ºåº“完成");
                // å‘MES反馈订单完成(如果需要)
                await HandleOrderCompletion(outboundOrder, orderNo);
                //await HandleOrderCompletion(outboundOrder, orderNo);
            }
        }
@@ -2825,7 +2821,7 @@
                        var detailLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                            .Where(x => x.OrderNo == outboundOrder.OrderNo &&
                                       x.OrderDetailId == detail.Id &&
                                       x.Status == (int)OutLockStockStatusEnum.拣选完成)
                                         (x.Status == (int)OutLockStockStatusEnum.拣选完成 || x.Status == (int)OutLockStockStatusEnum.已回库))
                            .ToListAsync();
                        var groupdata = detailLocks.GroupBy(item => new { item.MaterielCode, item.lineNo, item.BarcodeUnit, item.WarehouseCode })
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -27,6 +27,7 @@
using System.Reflection.Emit;
using System.Threading.Tasks;
using System.Xml.Linq;
using WIDESEA_BasicService;
using WIDESEA_Common.AllocateEnum;
using WIDESEA_Common.CommonEnum;
using WIDESEA_Common.LocationEnum;
@@ -76,6 +77,7 @@
        private readonly IOutboundOrderDetailService _outboundOrderDetailService;
        private readonly IOutStockLockInfoService _outStockLockInfoService;
        private readonly ILocationStatusChangeRecordService _locationStatusChangeRecordService;
        private readonly IMaterialUnitService _materialUnitService;
        private readonly IESSApiService _eSSApiService;
        private readonly IStockService _stockService;
        private readonly IRecordService _recordService;
@@ -100,7 +102,7 @@
        public List<int> TaskOutboundTypes => typeof(TaskTypeEnum).GetEnumIndexList();
        public TaskService(IRepository<Dt_Task> BaseDal, IMapper mapper, IUnitOfWorkManage unitOfWorkManage, IRepository<Dt_StockInfo> stockRepository, ILocationInfoService locationInfoService, IInboundOrderService inboundOrderService, ILocationStatusChangeRecordService locationStatusChangeRecordService, IESSApiService eSSApiService, ILogger<TaskService> logger, IStockService stockService, IRecordService recordService, IInboundOrderDetailService inboundOrderDetailService, IOutboundOrderService outboundOrderService, IOutboundOrderDetailService outboundOrderDetailService, IInvokeMESService invokeMESService, IOutStockLockInfoService outStockLockInfoService, IAllocateService allocateService, IRepository<Dt_OutboundBatch> outboundBatchRepository, IRepository<Dt_ReCheckOrder> reCheckOrderRepository, IRepository<Dt_AllocateOrderDetail> allocateOrderDetailRepository, IRepository<Dt_AllocateOrder> allocateOrderRepository) : base(BaseDal)
        public TaskService(IRepository<Dt_Task> BaseDal, IMapper mapper, IUnitOfWorkManage unitOfWorkManage, IRepository<Dt_StockInfo> stockRepository, ILocationInfoService locationInfoService, IInboundOrderService inboundOrderService, ILocationStatusChangeRecordService locationStatusChangeRecordService, IESSApiService eSSApiService, ILogger<TaskService> logger, IStockService stockService, IRecordService recordService, IInboundOrderDetailService inboundOrderDetailService, IOutboundOrderService outboundOrderService, IOutboundOrderDetailService outboundOrderDetailService, IInvokeMESService invokeMESService, IOutStockLockInfoService outStockLockInfoService, IAllocateService allocateService, IRepository<Dt_OutboundBatch> outboundBatchRepository, IRepository<Dt_ReCheckOrder> reCheckOrderRepository, IRepository<Dt_AllocateOrderDetail> allocateOrderDetailRepository, IRepository<Dt_AllocateOrder> allocateOrderRepository, IMaterialUnitService materialUnitService) : base(BaseDal)
        {
            _mapper = mapper;
            _unitOfWorkManage = unitOfWorkManage;
@@ -122,6 +124,7 @@
            _reCheckOrderRepository = reCheckOrderRepository;
            _allocateOrderDetailRepository = allocateOrderDetailRepository;
            _allocateOrderRepository = allocateOrderRepository;
            _materialUnitService = materialUnitService;
        }
@@ -554,60 +557,92 @@
            }
        }
        public async Task<WebResponseContent> InPickTaskCompleted(Dt_Task task)
        {
            _logger.LogInformation($"TaskService  InPickTaskCompleted: {task.TaskNum}");
            _logger.LogInformation($"TaskService InPickTaskCompleted: {task.TaskNum}");
            try
            {
                //查库存
                Dt_StockInfo stockInfo = await _stockRepository.Db.Queryable<Dt_StockInfo>().Includes(x => x.Details).Where(x => x.PalletCode == task.PalletCode).FirstAsync();
                _unitOfWorkManage.BeginTran(); // æ·»åŠ äº‹åŠ¡ç®¡ç†
                // æŸ¥åº“å­˜
                Dt_StockInfo stockInfo = await _stockRepository.Db.Queryable<Dt_StockInfo>()
                    .Includes(x => x.Details)
                    .Where(x => x.PalletCode == task.PalletCode)
                    .FirstAsync();
                if (stockInfo == null)
                {
                    _logger.LogInformation($"TaskService  InPickTaskCompleted: æœªæ‰¾åˆ°æ‰˜ç›˜å¯¹åº”的组盘信息.{task.TaskNum}");
                    _logger.LogInformation($"TaskService InPickTaskCompleted: æœªæ‰¾åˆ°æ‰˜ç›˜å¯¹åº”的组盘信息.{task.TaskNum}");
                    return WebResponseContent.Instance.Error($"未找到托盘对应的组盘信息");
                }
                if (stockInfo.Details.Count == 0 && stockInfo.PalletType != PalletTypeEnum.Empty.ObjToInt())
                {
                    _logger.LogInformation($"TaskService  InPickTaskCompleted: æœªæ‰¾åˆ°è¯¥æ‰˜ç›˜åº“存明细信息.{task.TaskNum}");
                    _logger.LogInformation($"TaskService InPickTaskCompleted: æœªæ‰¾åˆ°è¯¥æ‰˜ç›˜åº“存明细信息.{task.TaskNum}");
                    return WebResponseContent.Instance.Error($"未找到该托盘库存明细信息");
                }
                //查货位
                // æŸ¥è´§ä½
                Dt_LocationInfo locationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.TargetAddress);
                if (locationInfo == null)
                {
                    _logger.LogInformation($"TaskService  InPickTaskCompleted:  æœªæ‰¾åˆ°å¯¹åº”的终点货位信息 {task.TaskNum}.");
                    _logger.LogInformation($"TaskService InPickTaskCompleted: æœªæ‰¾åˆ°å¯¹åº”的终点货位信息 {task.TaskNum}.");
                    return WebResponseContent.Instance.Error($"未找到对应的终点货位信息");
                }
                var beforelocationStatus = locationInfo.LocationStatus;
                // èŽ·å–æ‰€æœ‰å›žåº“ä¸­çš„å‡ºåº“é”å®šè®°å½•
                var returnLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                    .Where(it => it.OrderNo == task.OrderNo && it.PalletCode == task.PalletCode && it.Status == (int)OutLockStockStatusEnum.回库中)
                    .Where(it => it.OrderNo == task.OrderNo &&
                               it.PalletCode == task.PalletCode &&
                               it.Status == (int)OutLockStockStatusEnum.回库中)
                    .ToListAsync();
                // æ›´æ–°å‡ºåº“锁定记录状态为回库完成
                foreach (var lockInfo in returnLocks)
                {
                    lockInfo.Status = (int)OutLockStockStatusEnum.已回库;
                    lockInfo.Operator = App.User.UserName;
                }
                _outStockLockInfoService.Db.Updateable(returnLocks).ExecuteCommand();
                if (returnLocks.Any())
                {
                    await _outStockLockInfoService.Db.Updateable(returnLocks).ExecuteCommandAsync();
                    _logger.LogInformation($"更新{returnLocks.Count}条锁定记录为已回库状态");
                }
                // æ›´æ–°åº“存信息
                stockInfo.LocationCode = task.TargetAddress;
                stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt();
                stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt();
                // æ›´æ–°åº“存明细状态
                if (stockInfo.Details != null && stockInfo.Details.Any())
                {
                    stockInfo.Details.ForEach(x =>
                    foreach (var detail in stockInfo.Details)
                    {
                        x.Status = StockStatusEmun.入库完成.ObjToInt();
                    });
                    _stockService.StockInfoDetailService.Repository.UpdateData(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);
                  _stockService.StockInfoService.Repository.UpdateData(stockInfo);
                // å¤„理回库相关的库存明细
                await ProcessStockDetailsForReturn(task, stockInfo.Id);
                // åˆ é™¤é›¶åº“存数据
                await DeleteZeroQuantityStockDetails(stockInfo.Id);
                // æ›´æ–°è´§ä½çŠ¶æ€
                if (stockInfo.PalletType == PalletTypeEnum.Empty.ObjToInt())
                {
                    locationInfo.LocationStatus = LocationStatusEnum.Pallet.ObjToInt();
@@ -616,30 +651,321 @@
                {
                    locationInfo.LocationStatus = LocationStatusEnum.InStock.ObjToInt();
                }
                _locationInfoService.Repository.UpdateData(locationInfo);
                var outboundOrder = _outboundOrderService.Db.Queryable<Dt_OutboundOrder>().First(x => x.OrderNo == task.OrderNo);
                task.TaskStatus = TaskStatusEnum.Finish.ObjToInt();
                 _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();
                // åˆ é™¤ä»»åŠ¡è®°å½•
                BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成);
                BaseDal.DeleteData(task);
                _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforelocationStatus, StockChangeType.Inbound.ObjToInt(), "", task.TaskNum);
                // è®°å½•货位状态变更
                _locationStatusChangeRecordService.AddLocationStatusChangeRecord(
                    locationInfo,
                    beforelocationStatus,
                    StockChangeType.Inbound.ObjToInt(),
                    "",
                    task.TaskNum
                );
                if (outboundOrder != null)
                {
                    // æ£€æŸ¥è®¢å•状态是否需要更新
                    await CheckAndUpdateOrderStatusAfterReturn(task.OrderNo);
                    // å¤„理MES反馈
                    await HandleOutboundOrderToMESCompletion(outboundOrder, outboundOrder.OrderNo);
                }
                else
                {
                    _logger.LogInformation($"TaskService  InPickTaskCompleted: {task.TaskNum} ,未找到出库单。  ");
                    _logger.LogInformation($"TaskService InPickTaskCompleted: {task.TaskNum} ,未找到出库单。");
                }
                _unitOfWorkManage.CommitTran(); // æäº¤äº‹åŠ¡
                _logger.LogInformation($"回库任务完成处理成功 - ä»»åŠ¡å·: {task.TaskNum}, æ‰˜ç›˜: {task.PalletCode}");
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran(); // å›žæ»šäº‹åŠ¡
                _logger.LogError($"TaskService InPickTaskCompleted失败 - TaskNum: {task.TaskNum}, Error: {ex.Message}");
                return WebResponseContent.Instance.Error($"回库任务完成处理失败: {ex.Message}");
            }
            return WebResponseContent.Instance.OK();
        }
        /// <summary>
        /// å›žåº“后更新订单数据
        /// </summary>
        private async Task UpdateOrderDataAfterReturn(string orderNo, List<Dt_OutStockLockInfo> returnLocks)
        {
            try
            {
                // èŽ·å–æ‰€æœ‰å—å½±å“çš„è®¢å•æ˜Žç»†ID
                var affectedDetailIds = returnLocks
                    .Select(x => x.OrderDetailId)
                    .Distinct()
                    .ToList();
                foreach (var detailId in affectedDetailIds)
                {
                    // è®¡ç®—该订单明细的回库总数量
                    var detailReturnLocks = returnLocks
                        .Where(x => x.OrderDetailId == detailId)
                        .ToList();
                    decimal totalReturnQty = detailReturnLocks.Sum(x => x.AssignQuantity - x.PickedQty);
                    if (totalReturnQty > 0)
                    {
                        // èŽ·å–è®¢å•æ˜Žç»†
                        var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                            .FirstAsync(x => x.Id == detailId);
                        if (orderDetail != null)
                        {
                            // æ›´æ–°é”å®šæ•°é‡ï¼ˆå›žåº“后锁定数量应减少)
                            var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                                .Where(x => x.OrderDetailId == detailId &&
                                           x.Status == (int)OutLockStockStatusEnum.出库中)
                                .ToListAsync();
                            decimal remainingLockQty = remainingLocks.Sum(x => x.AssignQuantity - x.PickedQty);
                            // æ›´æ–°è®¢å•明细
                            await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
                                .SetColumns(it => new Dt_OutboundOrderDetail
                                {
                                    LockQuantity = remainingLockQty,
                                })
                                .Where(it => it.Id == detailId)
                                .ExecuteCommandAsync();
                            // æ›´æ–°è®¢å•明细状态
                            await UpdateOrderDetailStatus(detailId);
                            _logger.LogInformation($"回库更新订单明细 - OrderDetailId: {detailId}, " +
                                                  $"扣减锁定数量: {totalReturnQty}, æ–°é”å®šæ•°é‡: {remainingLockQty}");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogInformation($"TaskService  InPickTaskCompleted: {task.TaskNum} , {ex.Message}");
                _logger.LogError($"UpdateOrderDataAfterReturn失败 - OrderNo: {orderNo}, Error: {ex.Message}");
                throw;
            }
            return await Task.FromResult(WebResponseContent.Instance.OK());
        }
        /// <summary>
        /// æ›´æ–°è®¢å•明细状态
        /// </summary>
        private async Task UpdateOrderDetailStatus(int orderDetailId)
        {
            try
            {
                var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                    .FirstAsync(x => x.Id == orderDetailId);
                if (orderDetail == null)
                {
                    _logger.LogWarning($"UpdateOrderDetailStatus失败:未找到订单明细,ID: {orderDetailId}");
                    return;
                }
                int newStatus = orderDetail.OrderDetailStatus;
                // 1. æ£€æŸ¥æ˜¯å¦å·²å®Œæˆ
                if (orderDetail.OverOutQuantity >= orderDetail.NeedOutQuantity)
                {
                    newStatus = (int)OrderDetailStatusEnum.Over;
                }
                // 2. æ£€æŸ¥æ˜¯å¦æ­£åœ¨è¿›è¡Œä¸­ï¼ˆæœ‰é”å®šæ•°é‡æˆ–部分拣选)
                else if (orderDetail.LockQuantity > 0 ||
                         (orderDetail.OverOutQuantity > 0 && orderDetail.OverOutQuantity < orderDetail.NeedOutQuantity))
                {
                    newStatus = (int)OrderDetailStatusEnum.Outbound;
                }
                // 3. æ£€æŸ¥æ˜¯å¦æœ‰é”å®šä½†æœªæ‹£é€‰
                else if (orderDetail.LockQuantity > 0 && orderDetail.OverOutQuantity == 0)
                {
                    newStatus = (int)OrderDetailStatusEnum.AssignOverPartial;
                }
                // 4. å¦åˆ™ä¸ºæ–°è®¢å•
                else
                {
                    newStatus = (int)OrderDetailStatusEnum.New;
                }
                // åªæœ‰çŠ¶æ€å˜åŒ–æ—¶æ‰æ›´æ–°
                if (orderDetail.OrderDetailStatus != newStatus)
                {
                    await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
                        .SetColumns(it => new Dt_OutboundOrderDetail
                        {
                            OrderDetailStatus = newStatus,
                        })
                        .Where(it => it.Id == orderDetailId)
                        .ExecuteCommandAsync();
                    _logger.LogInformation($"更新订单明细状态 - OrderDetailId: {orderDetailId}, " +
                                          $"旧状态: {orderDetail.OrderDetailStatus}, æ–°çŠ¶æ€: {newStatus}, " +
                                          $"已出库: {orderDetail.OverOutQuantity}/{orderDetail.NeedOutQuantity}, " +
                                          $"锁定数量: {orderDetail.LockQuantity}");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"UpdateOrderDetailStatus失败 - OrderDetailId: {orderDetailId}, Error: {ex.Message}");
                throw;
            }
        }
        /// <summary>
        /// å›žåº“后检查并更新订单状态
        /// </summary>
        private async Task CheckAndUpdateOrderStatusAfterReturn(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();
                bool allCompleted = true;
                bool hasInProgress = false;
                foreach (var detail in orderDetails)
                {
                    // æ£€æŸ¥æ˜¯å¦å®Œæˆ
                    if (detail.OverOutQuantity < detail.NeedOutQuantity)
                    {
                        allCompleted = false;
                    }
                    // æ£€æŸ¥æ˜¯å¦æœ‰è¿›è¡Œä¸­çš„任务(锁定或部分拣选)
                    if (detail.LockQuantity > 0 ||
                        detail.OrderDetailStatus == OrderDetailStatusEnum.Outbound.ObjToInt())
                    {
                        hasInProgress = true;
                    }
                }
                var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
                    .FirstAsync(x => x.OrderNo == orderNo);
                if (outboundOrder == null) return;
                int newStatus;
                if (allCompleted)
                {
                    newStatus = (int)OutOrderStatusEnum.出库完成;
                }
                else if (hasInProgress)
                {
                    newStatus = (int)OutOrderStatusEnum.出库中;
                }
                else
                {
                    newStatus = (int)OutOrderStatusEnum.未开始;
                }
                if (outboundOrder.OrderStatus != newStatus)
                {
                    await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
                        .SetColumns(x => new Dt_OutboundOrder
                        {
                            OrderStatus = newStatus,
                            Operator = App.User.UserName,
                        })
                        .Where(x => x.OrderNo == orderNo)
                        .ExecuteCommandAsync();
                    _logger.LogInformation($"回库后更新订单状态 - OrderNo: {orderNo}, æ–°çŠ¶æ€: {newStatus}");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"CheckAndUpdateOrderStatusAfterReturn失败 - 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>
        /// åˆ é™¤é›¶åº“存数据(增强版)
        /// </summary>
        private async Task DeleteZeroQuantityStockDetails(int stockId)
        {
            try
            {
                // æŸ¥æ‰¾åº“存数量为0的记录
                var zeroStockDetails = await _stockService.StockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                    .Where(x => x.StockId == stockId && x.StockQuantity <= 0)
                    .ToListAsync();
                if (zeroStockDetails.Any())
                {
                    await _stockService.StockInfoDetailService.Db.Deleteable(zeroStockDetails).ExecuteCommandAsync();
                    _logger.LogInformation($"删除{zeroStockDetails.Count}条零库存记录 - StockId: {stockId}");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"DeleteZeroQuantityStockDetails失败 - StockId: {stockId}, Error: {ex.Message}");
                throw;
            }
        }
        private async Task HandleOutboundOrderToMESCompletion(Dt_OutboundOrder outboundOrder, string orderNo)
        {
@@ -701,7 +1027,7 @@
                            var detailLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                                .Where(x => x.OrderNo == orderNo &&
                                           x.OrderDetailId == detail.Id &&
                                           x.Status == (int)OutLockStockStatusEnum.拣选完成)
                                           (x.Status == (int)OutLockStockStatusEnum.拣选完成 || x.Status == (int)OutLockStockStatusEnum.已回库))
                                .ToListAsync();
                            var detailModel = new AllocateDtoDetail
@@ -709,17 +1035,32 @@
                                MaterialCode = detail.MaterielCode,
                                LineNo = detail.lineNo,  
                                WarehouseCode = detail.WarehouseCode,
                                Qty = detailLocks.Sum(x=>x.BarcodeQty),
                                Unit = detail.Unit,
                                Barcodes = detailLocks.Select(lockInfo => new BarcodeInfo
                                {
                                    Barcode = lockInfo.CurrentBarcode,
                                    SupplyCode = lockInfo.SupplyCode,
                                    BatchNo = lockInfo.BatchNo,
                                    Unit = lockInfo.BarcodeUnit,
                                    Qty = lockInfo.BarcodeQty // æ¡ç çº§åˆ«çš„æ•°é‡ä»ç”¨é”å®šè®°å½•
                                }).ToList()
                                Qty = detailLocks.Sum(x=>x.PickedQty),
                                Unit = detail.BarcodeUnit,
                                Barcodes = new List<BarcodeInfo> ()
                            };
                            foreach (var item in detailLocks)
                            {
                                var barModel = new  BarcodeInfo
                                {
                                    Barcode = item.CurrentBarcode,
                                    SupplyCode = item.SupplyCode,
                                    BatchNo = item.BatchNo,
                                    Unit = item.BarcodeUnit,
                                    Qty = item.PickedQty
                                };
                                // å•位不一致时转换
                                if (item.BarcodeUnit != item.Unit)
                                {
                                    var convertResult = await _materialUnitService.ConvertAsync(item.MaterielCode, item.PickedQty, item.Unit, item.BarcodeUnit);
                                    barModel.Unit = convertResult.Unit;
                                    barModel.Qty = convertResult.Quantity;
                                }
                                detailModel.Qty += barModel.Qty;
                                detailModel.Barcodes.Add(barModel);
                            }
                            allocatefeedmodel.Details.Add(detailModel);
                        }
@@ -766,7 +1107,7 @@
                            var detailLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                                .Where(x => x.OrderNo == orderNo &&
                                           x.OrderDetailId == detail.Id &&
                                           x.Status == (int)OutLockStockStatusEnum.拣选完成)
                                           (x.Status == (int)OutLockStockStatusEnum.拣选完成 || x.Status == (int)OutLockStockStatusEnum.已回库))
                                .ToListAsync();
                            var detailModel = new FeedbackOutboundDetailsModel
@@ -774,19 +1115,33 @@
                                materialCode = detail.MaterielCode,
                                lineNo = detail.lineNo, // æ³¨æ„ï¼šè¿™é‡Œå¯èƒ½éœ€è¦è°ƒæ•´å­—段名
                                warehouseCode = detail.WarehouseCode,
                                qty = detail.BarcodeQty,
                                currentDeliveryQty = detail.BarcodeQty,
                                qty = detail.PickedQty,
                                currentDeliveryQty = detail.PickedQty,
                                unit = detail.Unit,
                                barcodes = detailLocks.Select(lockInfo => new WIDESEA_DTO.Outbound.BarcodesModel
                                {
                                    barcode = lockInfo.CurrentBarcode,
                                    supplyCode = lockInfo.SupplyCode,
                                    batchNo = lockInfo.BatchNo,
                                    unit = lockInfo.BarcodeUnit,
                                    qty = lockInfo.BarcodeQty // æ¡ç çº§åˆ«çš„æ•°é‡ä»ç”¨é”å®šè®°å½•
                                }).ToList()
                                barcodes = new List<WIDESEA_DTO.Outbound.BarcodesModel>()
                            };
                            foreach (var item in detailLocks)
                            {
                                var barModel = new WIDESEA_DTO.Outbound.BarcodesModel
                                {
                                    barcode = item.CurrentBarcode,
                                    supplyCode = item.SupplyCode,
                                    batchNo = item.BatchNo,
                                    unit = item.BarcodeUnit,
                                    qty = item.PickedQty
                                };
                                // å•位不一致时转换
                                if (item.BarcodeUnit != item.Unit)
                                {
                                    var convertResult = await _materialUnitService.ConvertAsync(item.MaterielCode, item.PickedQty, item.Unit, item.BarcodeUnit);
                                    barModel.unit = convertResult.Unit;
                                    barModel.qty = convertResult.Quantity;
                                }
                                detailModel.qty += barModel.qty;
                                detailModel.currentDeliveryQty += barModel.qty;
                                detailModel.barcodes.Add(barModel);
                            }
                            feedmodel.details.Add(detailModel);
                        }
                        var result = await _invokeMESService.FeedbackOutbound(feedmodel);
@@ -812,60 +1167,7 @@
        }
        /// <summary>
        /// åˆ é™¤åº“存数为0的库存明细记录
        /// </summary>
        private async Task DeleteZeroQuantityStockDetails(int stockId)
        {
            try
            {
                // åˆ é™¤åº“存数量为0的记录
                var deleteCount = await _stockService.StockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>()
                    .Where(x => x.StockId == stockId &&
                               x.StockQuantity == 0 &&
                               (x.Status == StockStatusEmun.出库完成.ObjToInt() || x.Status ==
                                          StockStatusEmun.入库完成.ObjToInt())) // åªåˆ é™¤å·²å®ŒæˆçŠ¶æ€çš„é›¶åº“å­˜
                    .ExecuteCommandAsync();
                if (deleteCount > 0)
                {
                    _logger.LogInformation($"删除{deleteCount}条零库存明细记录 - StockId: {stockId}");
                }
            }
            catch (Exception ex)
            {
                _logger.LogWarning($"删除零库存记录失败 - StockId: {stockId}, Error: {ex.Message}");
                // æ³¨æ„ï¼šåˆ é™¤å¤±è´¥ä¸åº”该影响主流程,记录日志后继续
            }
        }
        /// <summary>
        /// å¤„理回库相关的所有库存明细状态变更
        /// </summary>
        private async Task ProcessStockDetailsForReturn(Dt_Task returnTask, int stockId)
        {
            // èŽ·å–è¯¥æ‰˜ç›˜ä¸‹æ‰€æœ‰éœ€è¦å›žåº“çš„åº“å­˜æ˜Žç»†
            var stockDetails = await _stockService.StockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                .Where(x => x.StockId == stockId &&
                           x.StockQuantity > 0 &&
                          (x.Status == StockStatusEmun.出库锁定.ObjToInt() || x.Status ==
                                      StockStatusEmun.入库确认.ObjToInt()))  // åŒ…括出库锁定和入库确认的
                .ToListAsync();
            foreach (var detail in stockDetails)
            {
                detail.Status = StockStatusEmun.入库完成.ObjToInt();
                detail.OutboundQuantity = 0;  // æ¸…空出库数量
                _logger.LogInformation($"更新库存明细状态 - æ¡ç : {detail.Barcode}, æ•°é‡: {detail.StockQuantity}");
            }
            if (stockDetails.Any())
            {
                await _stockService.StockInfoDetailService.Db.Updateable(stockDetails).ExecuteCommandAsync();
                _logger.LogInformation($"共更新{stockDetails.Count}个库存明细状态为入库完成");
            }
        }
        public async Task<WebResponseContent> OutEmptyTaskCompleted(Dt_Task task)
        {
            WebResponseContent content = new WebResponseContent();