1
heshaofeng
2026-01-13 1866b69e8f67e382a0a75268d63e6418c8ae02e7
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs
@@ -34,6 +34,8 @@
using WIDESEA_BasicService.MESOperation;
using WIDESEA_Core.Util;
using WIDESEA_DTO.Allocate;
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
using WIDESEA_IRecordService;
namespace WIDESEA_OutboundService
{
@@ -70,6 +72,8 @@
        private readonly IFeedbackMesService _feedbackMesService;
        private readonly HttpClientHelper _httpClientHelper;
        private readonly IRepository<Dt_MesReturnRecord> _mesReturnRecord;
        private readonly IStockQuantityChangeRecordService _stockQuantityChangeRecordService;
        private readonly IInboundOrderService _inboundOrderService;
        private Dictionary<string, string> stations = new Dictionary<string, string>
        {
@@ -88,7 +92,7 @@
        public OutboundPickingService(IRepository<Dt_PickingRecord> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockInfoService stockInfoService, IStockService stockService,
            IOutStockLockInfoService outStockLockInfoService, IStockInfoDetailService stockInfoDetailService, ILocationInfoService locationInfoService,
            IOutboundOrderDetailService outboundOrderDetailService, ISplitPackageService splitPackageService, IOutboundOrderService outboundOrderService,
            IRepository<Dt_Task> taskRepository, IESSApiService eSSApiService, ILogger<OutboundPickingService> logger, IInvokeMESService invokeMESService, IDailySequenceService dailySequenceService, IAllocateService allocateService, IRepository<Dt_InboundOrder> inboundOrderRepository, IInboundOrderDetailService inboundOrderDetailService, IRepository<Dt_WarehouseArea> warehouseAreaRepository, IReCheckOrderService reCheckOrderService, ITask_HtyService task_HtyService, IRepository<Dt_InterfaceLog> interfaceLog, IInboundService inboundService, IFeedbackMesService feedbackMesService, HttpClientHelper httpClientHelper, IRepository<Dt_MesReturnRecord> mesReturnRecord) : base(BaseDal)
            IRepository<Dt_Task> taskRepository, IESSApiService eSSApiService, ILogger<OutboundPickingService> logger, IInvokeMESService invokeMESService, IDailySequenceService dailySequenceService, IAllocateService allocateService, IRepository<Dt_InboundOrder> inboundOrderRepository, IInboundOrderDetailService inboundOrderDetailService, IRepository<Dt_WarehouseArea> warehouseAreaRepository, IReCheckOrderService reCheckOrderService, ITask_HtyService task_HtyService, IRepository<Dt_InterfaceLog> interfaceLog, IInboundService inboundService, IFeedbackMesService feedbackMesService, HttpClientHelper httpClientHelper, IRepository<Dt_MesReturnRecord> mesReturnRecord,IStockQuantityChangeRecordService stockQuantityChangeRecordService,IInboundOrderService inboundOrderService) : base(BaseDal)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _stockInfoService = stockInfoService;
@@ -115,6 +119,8 @@
            _feedbackMesService = feedbackMesService;
            _httpClientHelper = httpClientHelper;
            _mesReturnRecord = mesReturnRecord;
            _stockQuantityChangeRecordService = stockQuantityChangeRecordService;
            _inboundOrderService = inboundOrderService;
        }
@@ -2365,7 +2371,7 @@
                        foreach (var detail in inboundOrder.Details)
                        {
                            if (detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt() &&
                                !string.IsNullOrEmpty(detail.Barcode))
                                !string.IsNullOrEmpty(detail.Barcode)&& detail.OutBoxbarcodes == noStockOut.barCode)
                            {
                                detailLists.Add(detail);
                            }
@@ -2386,11 +2392,18 @@
                {
                    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);
                    var matchedCode = outboundOrder.Details.FirstOrDefault(detail => detail.MaterielCode == item.MaterielCode && detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt()&& detail.OrderQuantity - detail.LockQuantity - detail.MoveQty - detail.NoStockOutQty > 0);
                    if (matchedCode == null)
                    if (matchedCode != null)
                    {
                        return WebResponseContent.Instance.Error($"在出库单的物料编码中未找到与采购单中的{item.MaterielCode} å¯¹åº”的物料。");
                        if(matchedCode.OrderQuantity - matchedCode.LockQuantity - matchedCode.MoveQty - matchedCode.NoStockOutQty < 0)
                        {
                            return WebResponseContent.Instance.Error($"物料{item.MaterielCode}可出数量溢出{(matchedCode.LockQuantity + matchedCode.MoveQty + matchedCode.NoStockOutQty) - matchedCode.OrderQuantity}");
                        }
                    }
                    else
                    {
                        return WebResponseContent.Instance.Error($"在出库单的物料编码中未找到与采购单中的{item.MaterielCode} å¯¹åº”的物料");
                    }
                    if (!matchedCode.BatchNo.IsNullOrEmpty() && matchedCode.BatchNo != "")
                    {
@@ -2415,13 +2428,20 @@
                            return WebResponseContent.Instance.Error($"该条码{item.Barcode}对应的单据厂区与出库单据不一致!不允许出库。");
                        }
                    }
                    if (!matchedCode.WarehouseCode.IsNullOrEmpty() && matchedCode.WarehouseCode != "")
                    if(inboundOrder.BusinessType != "11")
                    {
                        var matcheBatch = outboundOrder.Details.FirstOrDefault(detail => detail.WarehouseCode == item.WarehouseCode);
                        if (matcheBatch == null)
                        if (!matchedCode.WarehouseCode.IsNullOrEmpty() && matchedCode.WarehouseCode != "")
                        {
                            return WebResponseContent.Instance.Error($"仓库不一致!在出库单的物料编码中未找到与采购单仓库中的{item.WarehouseCode} å¯¹åº”的物料。");
                            var matcheBatch = outboundOrder.Details.FirstOrDefault(detail => detail.WarehouseCode == item.WarehouseCode);
                            if (matcheBatch == null)
                            {
                                return WebResponseContent.Instance.Error($"仓库不一致!在出库单的物料编码中未找到与采购单仓库中的{item.WarehouseCode} å¯¹åº”的物料。");
                            }
                        }
                    }
                    else
                    {
                        item.WarehouseCode = matchedCode.WarehouseCode;
                    }
                    //剩余入库数量即虚拟出入库剩余可出数量
@@ -2443,7 +2463,7 @@
                    Barcodes barcodes = new Barcodes
                    {
                        Barcode = item.Barcode,
                        Qty = item.BarcodeQty,
                        Qty = item.OrderQuantity,
                        SupplyCode = item?.SupplyCode ?? "",
                        BatchNo = item?.BatchNo ?? "",
                        Unit = item?.Unit ?? ""
@@ -2464,7 +2484,6 @@
                    {
                        return WebResponseContent.Instance.Error($"出库单明细数量溢出{matchedCode.OrderQuantity - matchedCode.LockQuantity-matchedCode.NoStockOutQty-matchedCode.MoveQty}");
                    }
                    item.OrderDetailStatus = OrderDetailStatusEnum.Inbounding.ObjToInt();
                    outDetails.Add(matchedCode);
                }
@@ -2516,7 +2535,7 @@
                Barcodes barcodes = new Barcodes
                {
                    Barcode = matchedDetail.Barcode,
                    Qty = matchedDetail.BarcodeQty,
                    Qty = matchedDetail.OrderQuantity,
                    SupplyCode = matchedDetail?.SupplyCode ?? "",
                    BatchNo = matchedDetail?.BatchNo ?? "",
                    Unit = matchedDetail?.Unit ?? ""
@@ -2582,13 +2601,14 @@
                Dictionary<int, Dt_InboundOrder> updateInboundOrders = new Dictionary<int, Dt_InboundOrder>();
                List<Dt_StockQuantityChangeRecord> changeRecords = new List<Dt_StockQuantityChangeRecord>();
                _unitOfWorkManage.BeginTran();
                List<Dt_InboundOrderDetail> allInboundDetails = _inboundOrderDetailService.Db
                    .Queryable<Dt_InboundOrderDetail>()
                    .Where(detail => noStockOutSubmit.BarCodeSubmit.Contains(detail.Barcode)
                        && detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt())
                    .ToList();
                .Queryable<Dt_InboundOrderDetail>()
                .Where(detail => noStockOutSubmit.BarCodeSubmit.Contains(detail.Barcode)
                    && detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt())
                .ToList();
                var detailGroupByOrderId = allInboundDetails.GroupBy(d => d.OrderId).ToList();
                foreach (var group in detailGroupByOrderId)
@@ -2597,8 +2617,24 @@
                    List<Dt_InboundOrderDetail> groupDetails = group.ToList();
                    List<string> groupBarCodes = groupDetails.Select(d => d.Barcode).ToList();
                    orderIdBarCodeDict[orderId] = groupBarCodes;
                    Dt_InboundOrder currentInboundOrder = null;
                    if (!updateInboundOrders.TryGetValue(orderId, out currentInboundOrder))
                    {
                        currentInboundOrder = _inboundOrderRepository.Db
                            .Queryable<Dt_InboundOrder>()
                            .Where(x => x.Id == orderId)
                            .Includes(x => x.Details)
                            .First();
                        if (currentInboundOrder == null)
                        {
                            _unitOfWorkManage.RollbackTran();
                            return WebResponseContent.Instance.Error($"未找到入库单ID为 {orderId} çš„单据");
                        }
                        updateInboundOrders[orderId] = currentInboundOrder;
                    }
                    foreach (var detail in groupDetails)
                    {
@@ -2610,53 +2646,49 @@
                            detail.OrderDetailStatus = OrderDetailStatusEnum.Over.ObjToInt();
                        }
                        updateInboundDetails.Add(detail);
                    }
                    if (!updateInboundOrders.ContainsKey(orderId))
                    {
                        Dt_InboundOrder inboundOrder = _inboundOrderRepository.Db
                            .Queryable<Dt_InboundOrder>()
                            .Where(x => x.Id == orderId)
                            .Includes(x => x.Details)
                            .First();
                        if (inboundOrder == null)
                        //添加库存变动记录
                        Dt_StockQuantityChangeRecord changeRecord = new Dt_StockQuantityChangeRecord
                        {
                            _unitOfWorkManage.RollbackTran();
                            return WebResponseContent.Instance.Error($"未找到入库单ID为 {orderId} çš„单据");
                        }
                        // åˆ¤æ–­æ•´å•是否全部完成
                        int totalDetailCount = inboundOrder.Details.Count();
                        int beforeDetailCount = inboundOrder.Details.Where(x => x.OrderId == orderId && x.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt())
                            .Count();
                        int finishedDetailCount = updateInboundDetails
                            .Where(x => x.OrderId == orderId && x.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt())
                            .Count();
                        inboundOrder.OrderStatus = totalDetailCount == finishedDetailCount+beforeDetailCount
                            ? InOrderStatusEnum.入库完成.ObjToInt()
                            : InOrderStatusEnum.入库中.ObjToInt();
                        updateInboundOrders[orderId] = inboundOrder;
                            StockDetailId = detail.Id,
                            PalleCode = DateTime.Now.ToString(),
                            MaterielCode = detail.MaterielCode,
                            MaterielName = detail.MaterielName ?? "",
                            BatchNo = detail.BatchNo ?? "",
                            OriginalSerilNumber = detail.Barcode,
                            NewSerilNumber = "",
                            OrderNo = currentInboundOrder.InboundOrderNo,
                            TaskNum = 0,
                            ChangeType = (int)StockChangeTypeEnum.Inbound,
                            ChangeQuantity = detail.NoStockOutQty,
                            BeforeQuantity = detail.OverInQuantity - detail.NoStockOutQty,
                            AfterQuantity = detail.OverInQuantity,
                            SupplyCode = detail.SupplyCode ?? "",
                            WarehouseCode = detail.WarehouseCode ?? "",
                            Remark = $"虚拟入库"
                        };
                        changeRecords.Add(changeRecord);
                    }
                    var inboundOrder = updateInboundOrders[orderId];
                    int totalDetailCount = inboundOrder.Details.Count;
                    int finishedDetailCount = inboundOrder.Details.Count(x => x.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt())
                                             + groupDetails.Count(x => x.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt());
                    inboundOrder.OrderStatus = totalDetailCount == finishedDetailCount
                        ? InOrderStatusEnum.入库完成.ObjToInt()
                        : InOrderStatusEnum.入库中.ObjToInt();
                }
                // 6. æ‰¹é‡æ›´æ–°æ˜Žç»†å’Œä¸»å•(批量操作提升性能)
                if (updateInboundDetails.Any())
                {
                    foreach (var detail in updateInboundDetails)
                    {
                        _inboundOrderDetailService.UpdateData(detail);
                    }
                    _inboundOrderDetailService.Db.Updateable(updateInboundDetails).ExecuteCommand();
                }
                if (updateInboundOrders.Any())
                {
                    foreach (var order in updateInboundOrders.Values)
                    {
                        _inboundOrderRepository.UpdateData(order);
                    }
                    // æ‰¹é‡æ›´æ–°å…¥åº“主单
                    _inboundOrderService.Db.Updateable(updateInboundOrders.Values.ToList()).ExecuteCommand();
                }
                // 7. å¾ªçŽ¯åˆ†ç»„ç»“æžœï¼Œè°ƒç”¨MES回传方法(按入库单分组回传)
@@ -2666,20 +2698,20 @@
                    List<string> barCodeList = kvp.Value;
                    //入库回传MES
                    NoStockOutBatchInOrderFeedbackToMes(orderId, barCodeList);
                }
                //只对出库条码的出库单明细进行计算回传
                List<Dt_OutboundOrderDetail> outboundOrderDetail = outboundOrder.Details
    .Where(x => !string.IsNullOrWhiteSpace(x.documentsNO)
        && noStockOutSubmit.BarCodeSubmit.Any(barcode =>
            x.documentsNO.IndexOf(barcode, StringComparison.OrdinalIgnoreCase) >= 0))
    .ToList();
                .Where(x => !string.IsNullOrWhiteSpace(x.documentsNO)
                    && noStockOutSubmit.BarCodeSubmit.Any(barcode =>
                        x.documentsNO.IndexOf(barcode, StringComparison.OrdinalIgnoreCase) >= 0))
                .ToList();
                foreach (var item in outboundOrderDetail)
                {
                    item.LockQuantity = item.NoStockOutQty;
                    item.OverOutQuantity = item.NoStockOutQty;
                    item.LockQuantity += item.NoStockOutQty;
                    item.OverOutQuantity += item.NoStockOutQty;
                    item.CurrentDeliveryQty = item.NoStockOutQty;
                    //添加回传MES参数
                    List<Barcodes> barcodesList = new List<Barcodes>();
                    List<Barcodes> documentsNOList = new List<Barcodes>();
@@ -2700,18 +2732,47 @@
                        ContractResolver = new CamelCasePropertyNamesContractResolver()
                    };
                    item.ReturnJsonData = JsonConvert.SerializeObject(barcodesList, settings);
                    //添加库存变动记录
                    Dt_StockQuantityChangeRecord changeRecord = new Dt_StockQuantityChangeRecord
                    {
                        StockDetailId = item.Id,
                        PalleCode = DateTime.Now.ToString(),
                        MaterielCode = item.MaterielCode,
                        MaterielName = item.MaterielName ?? "",
                        BatchNo = item.BatchNo ?? "",
                        OriginalSerilNumber = item.ReturnJsonData,
                        NewSerilNumber = "",
                        OrderNo = outboundOrder.OrderNo,
                        TaskNum = 0,
                        ChangeType = (int)StockChangeTypeEnum.Inbound,
                        ChangeQuantity = -item.NoStockOutQty,
                        BeforeQuantity = item.OrderQuantity,
                        AfterQuantity = item.OrderQuantity - item.OverOutQuantity,
                        SupplyCode = item.SupplyCode ?? "",
                        WarehouseCode = item.WarehouseCode ?? "",
                        Remark = $"虚拟出库"
                    };
                    changeRecords.Add(changeRecord);
                    outboundOrderDetails.Add(item);
                }
                _outboundOrderDetailService.UpdateData(outboundOrderDetails);
                //批量添加库存变动记录
                if (changeRecords.Any())
                {
                    _stockQuantityChangeRecordService.Db.Insertable(changeRecords).ExecuteCommand();
                }
                // æ£€æŸ¥å‡ºåº“单是否完成
                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);
@@ -2771,7 +2832,7 @@
                        BusinessType = "3",
                        FactoryArea = inboundOrder.FactoryArea,
                        OperationType = 1,
                        Operator = inboundOrder.Operator,
                        Operator = App.User.UserName,
                        OrderNo = inboundOrder.UpperOrderNo,
                        fromWarehouse = allocate?.FromWarehouse ?? "",
                        toWarehouse = allocate?.ToWarehouse ?? "",
@@ -2787,11 +2848,17 @@
                    if (response != null && response.IsSuccess)
                    {
                        _inboundOrderRepository.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 1 });
                        _inboundOrderRepository.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 1 })
                            .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 });
                        _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失败");
                    }
                }
@@ -2804,7 +2871,7 @@
                        business_type = inboundOrder.BusinessType,
                        factoryArea = inboundOrder.FactoryArea,
                        operationType = 1,
                        Operator = inboundOrder.Operator,
                        Operator = App.User.UserName,
                        orderNo = inboundOrder.UpperOrderNo,
                        status = inboundOrder.OrderStatus,
                        details = NoStockOutFeedbackInboundDetailsModelDto(detail)
@@ -2818,11 +2885,16 @@
                    if (response != null && response.IsSuccess)
                    {
                        _inboundOrderRepository.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 1 });
                        _inboundOrderRepository.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 1 })
                            .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 });
                        _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失败");
                    }
                }
@@ -2856,7 +2928,7 @@
               }).ToList();
            return groupedData;
        }
        public List<FeedbackInboundDetailsModel> NoStockOutFeedbackInboundDetailsModelDto(List<Dt_InboundOrderDetail> inboundOrderDetails)
        public List<FeedbackInboundDetailsModel> NoStockOutFeedbackInboundDetailsModelDto(List<Dt_InboundOrderDetail> inboundOrderDetails )
        {
            var groupedData = inboundOrderDetails.GroupBy(item => new { item.MaterielCode, item.lineNo, item.BarcodeUnit, item.WarehouseCode })
               .Select(group => new FeedbackInboundDetailsModel