1
heshaofeng
2026-03-25 37454e625df68d40897112b2e8c2e3cf4d7163e3
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs
@@ -2322,6 +2322,10 @@
            {
                return WebResponseContent.Instance.Error("未找到满足出库条件的出库单");
            }
            if(outboundOrder.IsBatch == 0)
            {
                return WebResponseContent.Instance.Error("该单据不属于分批回传单据,不允许虚拟出入库");
            }
            //先清空单据虚拟出入库数量进行计算
            foreach (var item in outboundOrder.Details)
            {
@@ -2332,258 +2336,374 @@
            return WebResponseContent.Instance.OK("成功");
        }
        public WebResponseContent BarcodeValidate(NoStockOutModel noStockOut)
    public WebResponseContent BarcodeValidate(NoStockOutModel noStockOut)
    {
        try
        {
            try
            Dt_InboundOrder inboundOrder = Db.Queryable<Dt_InboundOrder>()
                .Where(x => x.UpperOrderNo == noStockOut.inOder && x.OrderStatus != InOrderStatusEnum.入库完成.ObjToInt())
                .Includes(x => x.Details)
                .First();
            if (inboundOrder == null)
            {
                Dt_InboundOrder inboundOrder = Db.Queryable<Dt_InboundOrder>().Where(x => x.UpperOrderNo == noStockOut.inOder && x.OrderStatus != InOrderStatusEnum.入库完成.ObjToInt()).Includes(x => x.Details).First();
                if (inboundOrder == null)
                {
                    return WebResponseContent.Instance.Error($"未找到采购单:{noStockOut.inOder}");
                }
                Dt_OutboundOrder outboundOrder = Db.Queryable<Dt_OutboundOrder>().Where(x => x.UpperOrderNo == noStockOut.outOder && x.OrderStatus != OutOrderStatusEnum.出库完成.ObjToInt()).Includes(x => x.Details).First();
                if (outboundOrder == null)
                {
                    return WebResponseContent.Instance.Error($"未找到出库单:{noStockOut.inOder}");
                }
                return WebResponseContent.Instance.Error($"未找到采购单:{noStockOut.inOder}");
            }
                //存储入库单据明细信息
                var detailLists = new List<Dt_InboundOrderDetail>();
            Dt_OutboundOrder outboundOrder = Db.Queryable<Dt_OutboundOrder>()
                .Where(x => x.UpperOrderNo == noStockOut.outOder && x.OrderStatus != OutOrderStatusEnum.出库完成.ObjToInt())
                .Includes(x => x.Details)
                .First();
            if (outboundOrder == null)
            {
                return WebResponseContent.Instance.Error($"未找到出库单:{noStockOut.outOder}");
            }
                var matchedDetail = inboundOrder.Details.FirstOrDefault(detail =>
                    detail.Barcode == noStockOut.barCode &&
                    detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt());
            var detailLists = new List<Dt_InboundOrderDetail>();
            var matchedDetail = inboundOrder.Details.FirstOrDefault(detail =>
                detail.Barcode == noStockOut.barCode &&
                detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt()&& detail.ReceiptQuantity == 0);
            if (matchedDetail == null)
            {
                matchedDetail = inboundOrder.Details.FirstOrDefault(detail =>
                    detail.OutBoxbarcodes == noStockOut.barCode &&
                    detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt() && detail.ReceiptQuantity == 0);
                if (matchedDetail == null)
                {
                    matchedDetail = inboundOrder.Details.FirstOrDefault(detail =>
                        detail.OutBoxbarcodes == noStockOut.barCode &&
                        detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt());
                    if (matchedDetail == null)
                    {
                        return WebResponseContent.Instance.Error($"在采购单 {noStockOut.inOder} ä¸­æœªæ‰¾åˆ°æ¡ç ä¸º {noStockOut.barCode} çš„æ˜Žç»†ã€‚");
                    }
                    else
                    {
                        // æ·»åŠ æ‰€æœ‰éžå®ŒæˆçŠ¶æ€çš„æ˜Žç»†æ¡ç 
                        foreach (var detail in inboundOrder.Details)
                        {
                            if (detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt() &&
                                !string.IsNullOrEmpty(detail.Barcode)&& detail.OutBoxbarcodes == noStockOut.barCode)
                            {
                                detailLists.Add(detail);
                            }
                        }
                    }
                    return WebResponseContent.Instance.Error($"在采购单 {noStockOut.inOder} ä¸­æœªæ‰¾åˆ°æ¡ç ä¸º {noStockOut.barCode} çš„可出库明细。");
                }
                else
                {
                    if (!string.IsNullOrEmpty(noStockOut.barCode))
                    // æ·»åŠ æ‰€æœ‰åŒ¹é…å¤–ç®±ç ä¸”éžå®ŒæˆçŠ¶æ€çš„æ˜Žç»†
                    foreach (var detail in inboundOrder.Details)
                    {
                        detailLists.Add(matchedDetail);
                        if (detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt() &&
                            !string.IsNullOrEmpty(detail.Barcode) &&
                            detail.OutBoxbarcodes == noStockOut.barCode && detail.OrderQuantity > detail.NoStockOutQty)
                        {
                            detailLists.Add(detail);
                        }
                    }
                }
            }
            else
            {
                if (!string.IsNullOrEmpty(noStockOut.barCode))
                {
                    detailLists.Add(matchedDetail);
                }
            }
                if (!detailLists.Any())
                {
                    return WebResponseContent.Instance.Error("该条码已经没有可出库数量");
                }
                var outDetails = new List<Dt_OutboundOrderDetail>();
                // éåŽ†æ¯ä¸ªå…¥åº“æ˜Žç»†
                foreach (var item in detailLists)
                {
                    // é‡ç½®å½“前入库明细的无库存出库数量
                    item.NoStockOutQty = 0;
                    var matchedCode = outboundOrder.Details.FirstOrDefault(detail => detail.MaterielCode == item.MaterielCode && detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt()&& detail.OrderQuantity - detail.LockQuantity - detail.MoveQty - detail.NoStockOutQty > 0);
                    // å½“前条码需要出库的总数量(入库单剩余可出数量)
                    decimal remainingBarcodeQty = item.OrderQuantity - item.ReceiptQuantity;
                    if (remainingBarcodeQty <= 0)
                    {
                        return WebResponseContent.Instance.Error($"该采购单中的条码{item.Barcode}对应的可出数量为0");
                    }
                    if (matchedCode != null)
                    // ç­›é€‰å‡ºåº“单中符合条件的明细(同物料、非完成、有剩余可出数量)
                    var eligibleOutDetails = outboundOrder.Details.Where(detail =>
                        detail.MaterielCode == item.MaterielCode &&
                        detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt() &&
                        (detail.OrderQuantity - detail.LockQuantity - detail.MoveQty - detail.NoStockOutQty) > 0).ToList();
                    if (!eligibleOutDetails.Any())
                    {
                        if(matchedCode.OrderQuantity - matchedCode.LockQuantity - matchedCode.MoveQty - matchedCode.NoStockOutQty < 0)
                        {
                            return WebResponseContent.Instance.Error($"物料{item.MaterielCode}可出数量溢出{(matchedCode.LockQuantity + matchedCode.MoveQty + matchedCode.NoStockOutQty) - matchedCode.OrderQuantity}");
                        }
                        return WebResponseContent.Instance.Error($"在出库单中未找到物料{item.MaterielCode}的可出库明细");
                    }
                    else
                    // éåŽ†ç¬¦åˆæ¡ä»¶çš„å‡ºåº“æ˜Žç»†ï¼Œé€è¡Œåˆ†é…æ•°é‡
                    foreach (var outDetail in eligibleOutDetails)
                    {
                        return WebResponseContent.Instance.Error($"在出库单的物料编码中未找到与采购单中的{item.MaterielCode} å¯¹åº”的物料");
                    }
                    if (!matchedCode.BatchNo.IsNullOrEmpty() && matchedCode.BatchNo != "")
                    {
                        var matcheBatch = outboundOrder.Details.FirstOrDefault(detail => detail.BatchNo == item.BatchNo);
                        if (matcheBatch == null)
                        // è®¡ç®—当前出库行的剩余可出数量
                        decimal rowRemainingQty = outDetail.OrderQuantity - outDetail.LockQuantity - outDetail.MoveQty - outDetail.NoStockOutQty;
                        if (rowRemainingQty <= 0) continue;
                        if (!outDetail.BatchNo.IsNullOrEmpty())
                        {
                            return WebResponseContent.Instance.Error($"在出库单的物料编码中未找到与采购单批次中的{item.BatchNo} å¯¹åº”的物料。");
                        }
                    }
                    if (!matchedCode.SupplyCode.IsNullOrEmpty() && matchedCode.SupplyCode != "")
                    {
                        var matcheBatch = outboundOrder.Details.FirstOrDefault(detail => detail.SupplyCode == item.SupplyCode);
                        if (matcheBatch == null)
                        {
                            return WebResponseContent.Instance.Error($"在出库单的物料编码中未找到与采购单供应商中的{item.SupplyCode} å¯¹åº”的物料。");
                        }
                    }
                    if (!outboundOrder.FactoryArea.IsNullOrEmpty() && outboundOrder.FactoryArea != "" && !inboundOrder.FactoryArea.IsNullOrEmpty() && inboundOrder.FactoryArea != "")
                    {
                        if (inboundOrder.FactoryArea != outboundOrder.FactoryArea)
                        {
                            return WebResponseContent.Instance.Error($"该条码{item.Barcode}对应的单据厂区与出库单据不一致!不允许出库。");
                        }
                    }
                    if(inboundOrder.BusinessType != "11")
                    {
                        if (!matchedCode.WarehouseCode.IsNullOrEmpty() && matchedCode.WarehouseCode != "")
                        {
                            var matcheBatch = outboundOrder.Details.FirstOrDefault(detail => detail.WarehouseCode == item.WarehouseCode);
                            if (matcheBatch == null)
                            if (outDetail.BatchNo != item.BatchNo)
                            {
                                return WebResponseContent.Instance.Error($"仓库不一致!在出库单的物料编码中未找到与采购单仓库中的{item.WarehouseCode} å¯¹åº”的物料。");
                                return WebResponseContent.Instance.Error($"出库单行批次{outDetail.BatchNo}与采购单批次{item.BatchNo}不匹配");
                            }
                        }
                    }
                    else
                    {
                        item.WarehouseCode = matchedCode.WarehouseCode;
                        if (!outDetail.SupplyCode.IsNullOrEmpty())
                        {
                            if (outDetail.SupplyCode != item.SupplyCode)
                            {
                                return WebResponseContent.Instance.Error($"出库单行供应商{outDetail.SupplyCode}与采购单供应商{item.SupplyCode}不匹配");
                            }
                        }
                        if (!string.IsNullOrEmpty(outboundOrder.FactoryArea) && !string.IsNullOrEmpty(inboundOrder.FactoryArea))
                        {
                            if (inboundOrder.FactoryArea != outboundOrder.FactoryArea)
                            {
                                return WebResponseContent.Instance.Error($"该条码{item.Barcode}对应的单据厂区与出库单据不一致!不允许出库。");
                            }
                        }
                        if (inboundOrder.BusinessType != "11" && !outDetail.WarehouseCode.IsNullOrEmpty())
                        {
                            if (outDetail.WarehouseCode != item.WarehouseCode)
                            {
                                return WebResponseContent.Instance.Error($"仓库不一致!出库单行仓库{outDetail.WarehouseCode}与采购单仓库{item.WarehouseCode}不匹配");
                            }
                        }
                        else
                        {
                            item.WarehouseCode = outDetail.WarehouseCode;
                        }
                        // è®¡ç®—本次分配的数量(取剩余条码数量和当前行剩余数量的较小值)
                        decimal assignQty = Math.Min(remainingBarcodeQty, rowRemainingQty);
                        // æ›´æ–°å…¥åº“明细和出库明细的无库存出库数量
                        item.NoStockOutQty += assignQty;
                        outDetail.NoStockOutQty += assignQty;
                        // æ›´æ–°å‰©ä½™éœ€è¦åˆ†é…çš„æ¡ç æ•°é‡
                        remainingBarcodeQty -= assignQty;
                        // è®°å½•已更新的出库明细(去重)
                        if (!outDetails.Contains(outDetail))
                        {
                            outDetails.Add(outDetail);
                        }
                        // éªŒè¯å½“前行是否溢出
                        if ((outDetail.LockQuantity + outDetail.NoStockOutQty + outDetail.MoveQty) > outDetail.OrderQuantity)
                        {
                            return WebResponseContent.Instance.Error($"出库单明细{outDetail.Id}数量溢出,超出数量:{(outDetail.LockQuantity + outDetail.NoStockOutQty + outDetail.MoveQty) - outDetail.OrderQuantity}");
                        }
                        // å¤„理MES参数回传:记录当前条码分配到该行的实际数量
                        List<Barcodes> barcodesList = new List<Barcodes>();
                        Barcodes barcodes = new Barcodes
                        {
                            Barcode = item.Barcode,
                            Qty = assignQty,
                            SupplyCode = item?.SupplyCode ?? "",
                            BatchNo = item?.BatchNo ?? "",
                            Unit = item?.Unit ?? ""
                        };
                        // ååºåˆ—化该行已有的条码记录
                        if (!string.IsNullOrEmpty(outDetail.documentsNO))
                        {
                            try
                            {
                                barcodesList = JsonConvert.DeserializeObject<List<Barcodes>>(outDetail.documentsNO) ?? new List<Barcodes>();
                            }
                            catch (JsonException ex)
                            {
                                return WebResponseContent.Instance.Error($"出库单明细{outDetail.Id}的documentsNO字段格式错误:{ex.Message}");
                            }
                        }
                        // æ·»åŠ æœ¬æ¬¡åˆ†é…çš„è®°å½•
                        barcodesList.Add(barcodes);
                        // åºåˆ—化回存
                        JsonSerializerSettings settings = new JsonSerializerSettings
                        {
                            ContractResolver = new CamelCasePropertyNamesContractResolver()
                        };
                        outDetail.documentsNO = JsonConvert.SerializeObject(barcodesList, settings);
                        // æ¡ç æ•°é‡åˆ†é…å®Œæ¯•,退出当前行循环
                        if (remainingBarcodeQty <= 0)
                        {
                            break;
                        }
                    }
                    //剩余入库数量即虚拟出入库剩余可出数量
                    decimal outQuantity = item.OrderQuantity - item.ReceiptQuantity;
                    if (outQuantity == 0)
                    // æ‰€æœ‰ç¬¦åˆæ¡ä»¶çš„出库行遍历完后,条码数量仍有剩余
                    if (remainingBarcodeQty > 0)
                    {
                        return WebResponseContent.Instance.Error($"该采购单中的条码对应的可出数量为0");
                        return WebResponseContent.Instance.Error($"条码{item.Barcode}需出库数量{item.OrderQuantity - item.ReceiptQuantity},但出库单中物料{item.MaterielCode}剩余可出总量不足,仍剩余{remainingBarcodeQty}数量未分配");
                    }
                    if (matchedCode.OrderQuantity - matchedCode.LockQuantity - matchedCode.MoveQty - matchedCode.NoStockOutQty < outQuantity)
                    {
                        return WebResponseContent.Instance.Error($"该采购单中的条码对应的可出数量超出出库单出库数量{item.OrderQuantity - (matchedCode.OrderQuantity - matchedCode.LockQuantity - matchedCode.MoveQty)},不满足整包出库");
                    }
                    //单据出库锁定数量
                    item.NoStockOutQty += outQuantity;
                    matchedCode.NoStockOutQty += outQuantity;
                    //回传MES参数
                    List<Barcodes> barcodesList = new List<Barcodes>();
                    Barcodes barcodes = new Barcodes
                    {
                        Barcode = item.Barcode,
                        Qty = item.BarcodeQty,
                        SupplyCode = item?.SupplyCode ?? "",
                        BatchNo = item?.BatchNo ?? "",
                        Unit = item?.Unit ?? ""
                    };
                    if (!string.IsNullOrEmpty(matchedCode.documentsNO))
                    {
                        barcodesList = JsonConvert.DeserializeObject<List<Barcodes>>(matchedCode.documentsNO) ?? new List<Barcodes>();
                    }
                    barcodesList.Add(barcodes);
                    JsonSerializerSettings settings = new JsonSerializerSettings
                    {
                        ContractResolver = new CamelCasePropertyNamesContractResolver()
                    };
                    matchedCode.documentsNO = JsonConvert.SerializeObject(barcodesList, settings);
                    if ((matchedCode.LockQuantity + matchedCode.NoStockOutQty+matchedCode.MoveQty) > matchedCode.OrderQuantity)
                    {
                        return WebResponseContent.Instance.Error($"出库单明细数量溢出{matchedCode.OrderQuantity - matchedCode.LockQuantity-matchedCode.NoStockOutQty-matchedCode.MoveQty}");
                    }
                    outDetails.Add(matchedCode);
                }
                _unitOfWorkManage.BeginTran();
                _inboundOrderDetailService.UpdateData(detailLists);
                _outboundOrderDetailService.UpdateData(outDetails);
                _unitOfWorkManage.CommitTran();
                return WebResponseContent.Instance.OK("成功",data:detailLists);
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                return WebResponseContent.Instance.Error(ex.Message);
            }
            _inboundOrderDetailService.UpdateData(detailLists);
            _outboundOrderDetailService.UpdateData(outDetails);
            _unitOfWorkManage.CommitTran();
            return WebResponseContent.Instance.OK("成功", data: detailLists);
        }
        public WebResponseContent DeleteBarcode(NoStockOutModel noStockOut)
        catch (Exception ex)
        {
            try
            _unitOfWorkManage.RollbackTran();
            return WebResponseContent.Instance.Error(ex.Message);
        }
    }
    public WebResponseContent DeleteBarcode(NoStockOutModel noStockOut)
    {
        try
        {
            Dt_InboundOrder inboundOrder = Db.Queryable<Dt_InboundOrder>()
                .Where(x => x.UpperOrderNo == noStockOut.inOder && x.OrderStatus != InOrderStatusEnum.入库完成.ObjToInt())
                .Includes(x => x.Details)
                .First();
            if (inboundOrder == null)
            {
                Dt_InboundOrder inboundOrder = Db.Queryable<Dt_InboundOrder>().Where(x => x.UpperOrderNo == noStockOut.inOder && x.OrderStatus != InOrderStatusEnum.入库完成.ObjToInt()).Includes(x => x.Details).First();
                if (inboundOrder == null)
                {
                    return WebResponseContent.Instance.Error($"未找到采购单:{noStockOut.inOder}");
                }
                var matchedDetail = inboundOrder.Details.FirstOrDefault(detail => detail.Barcode == noStockOut.barCode && detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt());
                return WebResponseContent.Instance.Error($"未找到采购单:{noStockOut.inOder}");
            }
                if (matchedDetail == null)
                {
                    return WebResponseContent.Instance.Error($"在采购单 {noStockOut.inOder} ä¸­æœªæ‰¾åˆ°æ¡ç ä¸º {noStockOut.barCode} çš„æ˜Žç»†ã€‚");
                }
                matchedDetail.NoStockOutQty = 0;
            var matchedDetail = inboundOrder.Details.FirstOrDefault(detail =>
                detail.Barcode == noStockOut.barCode &&
                detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt());
                if (matchedDetail.ReceiptQuantity == 0 && matchedDetail.OverInQuantity == 0)
                {
                    matchedDetail.OrderDetailStatus = OrderDetailStatusEnum.New.ObjToInt();
                }
            if (matchedDetail == null)
            {
                return WebResponseContent.Instance.Error($"在采购单 {noStockOut.inOder} ä¸­æœªæ‰¾åˆ°æ¡ç ä¸º {noStockOut.barCode} çš„æ˜Žç»†ã€‚");
            }
                Dt_OutboundOrder outboundOrder = Db.Queryable<Dt_OutboundOrder>().Where(x => x.UpperOrderNo == noStockOut.outOder && x.OrderStatus != OutOrderStatusEnum.出库完成.ObjToInt()).Includes(x => x.Details).First();
                if (outboundOrder == null)
                {
                    return WebResponseContent.Instance.Error($"未找到出库单:{noStockOut.inOder}");
                }
            // é‡ç½®å…¥åº“明细的无库存出库数量
            decimal revokedTotalQty = matchedDetail.NoStockOutQty; // è®°å½•需要撤销的总数量(入库单中已分配的数量)
            matchedDetail.NoStockOutQty = 0;
            if(inboundOrder.BusinessType == "11")
            {
                matchedDetail.WarehouseCode ="";
            }
                // æ’¤é”€å›žä¼ MES参数
            // é‡ç½®å…¥åº“明细状态
            if (matchedDetail.ReceiptQuantity == 0 && matchedDetail.OverInQuantity == 0)
            {
                matchedDetail.OrderDetailStatus = OrderDetailStatusEnum.New.ObjToInt();
            }
            Dt_OutboundOrder outboundOrder = Db.Queryable<Dt_OutboundOrder>()
                .Where(x => x.UpperOrderNo == noStockOut.outOder && x.OrderStatus != OutOrderStatusEnum.出库完成.ObjToInt())
                .Includes(x => x.Details)
                .First();
            if (outboundOrder == null)
            {
                return WebResponseContent.Instance.Error($"未找到出库单:{noStockOut.outOder}");
            }
            // æ‰¾åˆ°æ‰€æœ‰å…³è”该条码的出库明细行
            // åŒç‰©æ–™ã€éžå®ŒæˆçŠ¶æ€ã€documentsNO包含该条码
            var matchedCodeList = outboundOrder.Details.Where(detail =>
                detail.MaterielCode == matchedDetail.MaterielCode && // ç¡®ä¿ç‰©æ–™åŒ¹é…
                detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt() &&
                !string.IsNullOrEmpty(detail.documentsNO) &&
                detail.documentsNO.Contains(noStockOut.barCode) // åŒ…含当前条码
            ).ToList();
            if (!matchedCodeList.Any())
            {
                return WebResponseContent.Instance.Error($"在出库单中未找到关联条码{noStockOut.barCode}的物料{matchedDetail.MaterielCode}明细。");
            }
            //逐行处理出库明细的撤销逻辑
            decimal remainingRevokeQty = revokedTotalQty; // å‰©ä½™éœ€è¦æ’¤é”€çš„æ•°é‡
            foreach (var matchedCode in matchedCodeList)
            {
                if (remainingRevokeQty <= 0) break; // æ‰€æœ‰æ•°é‡å·²æ’¤é”€ï¼Œé€€å‡ºå¾ªçޝ
                // å¤„理MES参数撤销
                List<Barcodes> barcodesList = new List<Barcodes>();
                Barcodes barcodes = new Barcodes
                {
                    Barcode = matchedDetail.Barcode,
                    Qty = matchedDetail.BarcodeQty,
                    SupplyCode = matchedDetail?.SupplyCode ?? "",
                    BatchNo = matchedDetail?.BatchNo ?? "",
                    Unit = matchedDetail?.Unit ?? ""
                };
                var matchedCode = outboundOrder.Details.FirstOrDefault(detail =>
                    detail.documentsNO.Contains(barcodes.Barcode) &&
                    detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt()
                );
                if (matchedCode == null)
                {
                    return WebResponseContent.Instance.Error($"在出库单的物料编码中未找到与采购单中的{matchedDetail.MaterielCode} å¯¹åº”的物料。");
                }
                if (!string.IsNullOrEmpty(matchedCode.documentsNO))
                {
                    barcodesList = JsonConvert.DeserializeObject<List<Barcodes>>(matchedCode.documentsNO) ?? new List<Barcodes>();
                    try
                    {
                        barcodesList = JsonConvert.DeserializeObject<List<Barcodes>>(matchedCode.documentsNO) ?? new List<Barcodes>();
                    }
                    catch (JsonException ex)
                    {
                        return WebResponseContent.Instance.Error($"出库单明细{matchedCode.Id}的documentsNO字段格式错误:{ex.Message}");
                    }
                }
                barcodesList.RemoveAll(b =>
                    string.Equals(b.Barcode, barcodes.Barcode, StringComparison.OrdinalIgnoreCase)
                );
                // ç­›é€‰å‡ºå½“前条码的所有记录
                var barcodeRecords = barcodesList.Where(b =>
                    string.Equals(b.Barcode, noStockOut.barCode, StringComparison.OrdinalIgnoreCase)).ToList();
                if (!barcodeRecords.Any()) continue;
                // è®¡ç®—该行需要撤销的数量(累加该条码在该行的所有分配数量)
                decimal rowRevokeQty = barcodeRecords.Sum(b => b.Qty);
                // å®žé™…撤销数量:取该行可撤销数量和剩余需要撤销数量的较小值
                decimal actualRevokeQty = Math.Min(rowRevokeQty, remainingRevokeQty);
                // ç§»é™¤è¯¥è¡Œä¸­è¯¥æ¡ç çš„记录(或部分记录,若剩余撤销数量不足)
                if (actualRevokeQty < rowRevokeQty)
                {
                    // å‰©ä½™æ’¤é”€æ•°é‡ä¸è¶³ï¼Œåªç§»é™¤éƒ¨åˆ†è®°å½•(按数量扣减)
                    decimal tempQty = actualRevokeQty;
                    var removeList = new List<Barcodes>();
                    foreach (var record in barcodeRecords)
                    {
                        if (tempQty <= 0) break;
                        if (record.Qty <= tempQty)
                        {
                            removeList.Add(record);
                            tempQty -= record.Qty;
                        }
                        else
                        {
                            // è®°å½•数量拆分,扣减部分数量
                            record.Qty -= tempQty;
                            tempQty = 0;
                        }
                    }
                    barcodesList.RemoveAll(b => removeList.Contains(b));
                }
                else
                {
                    // ç§»é™¤è¯¥è¡Œä¸­è¯¥æ¡ç çš„æ‰€æœ‰è®°å½•
                    barcodesList.RemoveAll(b =>
                        string.Equals(b.Barcode, noStockOut.barCode, StringComparison.OrdinalIgnoreCase));
                }
                //重新序列化MES参数
                JsonSerializerSettings settings = new JsonSerializerSettings
                {
                    ContractResolver = new CamelCasePropertyNamesContractResolver()
                };
                matchedCode.documentsNO = JsonConvert.SerializeObject(barcodesList, settings);
                matchedCode.NoStockOutQty -= matchedDetail.OrderQuantity;
                //扣减出库明细的无库存出库数量
                matchedCode.NoStockOutQty = Math.Max(0, matchedCode.NoStockOutQty - actualRevokeQty);
                remainingRevokeQty -= actualRevokeQty;
                //重置出库明细状态
                if (matchedCode.LockQuantity == 0 && matchedCode.OverOutQuantity == 0)
                {
                    matchedCode.OrderDetailStatus = OrderDetailStatusEnum.New.ObjToInt();
                }
                _unitOfWorkManage.BeginTran();
                _inboundOrderDetailService.UpdateData(matchedDetail);
                _outboundOrderDetailService.UpdateData(matchedCode);
                _unitOfWorkManage.CommitTran();
                return WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            //若仍有未撤销的数量,说明数据不一致
            if (remainingRevokeQty > 0)
            {
                _unitOfWorkManage.RollbackTran();
                return WebResponseContent.Instance.Error(ex.Message);
                return WebResponseContent.Instance.Error($"撤销条码{noStockOut.barCode}时,出库单中可撤销数量不足,仍有{remainingRevokeQty}数量未撤销");
            }
        }
        public async Task<WebResponseContent> NoStockOutSubmit(NoStockOutSubmit noStockOutSubmit)
            _unitOfWorkManage.BeginTran();
            _inboundOrderDetailService.UpdateData(matchedDetail);
            _outboundOrderDetailService.UpdateData(matchedCodeList);
            _unitOfWorkManage.CommitTran();
            return WebResponseContent.Instance.OK("条码撤销成功", data: new { RevokedQty = revokedTotalQty });
        }
        catch (Exception ex)
        {
            _unitOfWorkManage.RollbackTran();
            return WebResponseContent.Instance.Error(ex.Message);
        }
    }
    public async Task<WebResponseContent> NoStockOutSubmit(NoStockOutSubmit noStockOutSubmit)
        {
            try
            {
@@ -2711,13 +2831,13 @@
                {
                    item.LockQuantity += item.NoStockOutQty;
                    item.OverOutQuantity += item.NoStockOutQty;
                    item.CurrentDeliveryQty = item.NoStockOutQty;
                    item.CurrentDeliveryQty += item.NoStockOutQty;
                    //添加回传MES参数
                    List<Barcodes> barcodesList = new List<Barcodes>();
                    List<Barcodes> documentsNOList = new List<Barcodes>();
                    if (!string.IsNullOrEmpty(item.ReturnJsonData))
                    {
                        barcodesList = JsonConvert.DeserializeObject<List<Barcodes>>(item.documentsNO) ?? new List<Barcodes>();
                        barcodesList = JsonConvert.DeserializeObject<List<Barcodes>>(item.ReturnJsonData) ?? new List<Barcodes>();
                    }
                    if (!string.IsNullOrEmpty(item.documentsNO) && item.documentsNO!="")
                    {
@@ -2766,8 +2886,13 @@
                if (CheckOutboundOrderCompleted(outboundOrder.OrderNo))
                {
                    outboundOrder.OrderStatus = OutOrderStatusEnum.出库完成.ObjToInt();
                    _outboundOrderService.UpdateData(outboundOrder);
                }
                else
                {
                    outboundOrder.OrderStatus = OutOrderStatusEnum.出库中.ObjToInt();
                }
                _outboundOrderService.UpdateData(outboundOrder);
                _unitOfWorkManage.CommitTran();
                //出库回传MES
                _feedbackMesService.OutboundFeedback(outboundOrder.OrderNo);
@@ -2844,12 +2969,16 @@
                    if (response != null && response.IsSuccess)
                    {
                        _inboundOrderRepository.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 1 })
                            .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
                            .Where(it => it.OrderId == inboundOrder.Id && barCodeList.Contains(it.Barcode)).ExecuteCommand();
                        _inboundOrderRepository.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 1 })
                            .Where(it => it.Id == inboundOrder.Id).ExecuteCommand();
                    }
                    else
                    {
                        _inboundOrderRepository.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 2 })
                            .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
                            .Where(it => it.OrderId == inboundOrder.Id && barCodeList.Contains(it.Barcode)).ExecuteCommand();
                        _inboundOrderRepository.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus =2})
                            .Where(it => it.Id == inboundOrder.Id).ExecuteCommand();
                        return content.Error("回传MES失败");
                    }
                }
@@ -2877,13 +3006,13 @@
                    if (response != null && response.IsSuccess)
                    {
                        _inboundOrderRepository.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 1 })
                            .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
                            .Where(it => it.OrderId == inboundOrder.Id && barCodeList.Contains(it.Barcode)).ExecuteCommand();
                        _inboundOrderRepository.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 1 })
                            .Where(it => it.Id == inboundOrder.Id).ExecuteCommand();
                    }
                    else
                    {
                        _inboundOrderRepository.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 2 }).Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
                        _inboundOrderRepository.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 2 }).Where(it => it.OrderId == inboundOrder.Id && barCodeList.Contains(it.Barcode)).ExecuteCommand();
                        _inboundOrderRepository.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 2 })
                            .Where(it => it.Id == inboundOrder.Id).ExecuteCommand();
                        return content.Error("回传MES失败");