heshaofeng
2026-03-09 557f7f6079c30cd6fe8d6005cea3d89468bbcd31
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundService.cs
@@ -1,14 +1,16 @@
using System.Reflection.Emit;
using AutoMapper;
using AutoMapper;
using Dm.filter;
using MailKit.Search;
using Mapster;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
using Org.BouncyCastle.Asn1.Ocsp;
using Org.BouncyCastle.Crypto;
using SqlSugar;
using System;
using System.Reflection.Emit;
using WIDESEA_BasicService;
using WIDESEA_Common.CommonEnum;
using WIDESEA_Common.LocationEnum;
@@ -29,6 +31,7 @@
using WIDESEA_IRecordService;
using WIDESEA_IStockService;
using WIDESEA_Model.Models;
using WIDESEA_Model.Models.Basic;
using WIDESEA_Model.Models.Check;
using static HslCommunication.Profinet.Knx.KnxCode;
@@ -65,6 +68,8 @@
        private readonly IRepository<Dt_AllocateMaterialInfo> _allocateMaterialInfoRepository;
        public readonly IRepository<Dt_InboundOrderDetail> _inboundOrderDetailRepository;
        public readonly IRepository<Dt_InboundOrder> _inboundOrderRepository;
        public readonly IRepository<Dt_WarehouseArea> _warehouseAreaRepository;
        public readonly IRepository<Dt_LocationType> _locationTypeRepository;
        private Dictionary<string, string> stations = new Dictionary<string, string>
        {
@@ -78,7 +83,7 @@
            {"3-1","3-5" },
        };
        public OutboundService(IMapper mapper, IUnitOfWorkManage unitOfWorkManage, IRepository<Dt_OutboundOrderDetail> detailRepository, IRepository<Dt_OutboundOrder> outboundRepository, IRepository<Dt_OutStockLockInfo> outboundLockInfoRepository, IRepository<Dt_StockInfo> stockInfoRepository, IRepository<Dt_StockInfoDetail> stockDetailRepository, IRepository<Dt_StockQuantityChangeRecord> stockChangeRepository, IRepository<Dt_StockInfoDetail_Hty> stockDetailHistoryRepository, IBasicService basicService, IOutboundOrderDetailService outboundOrderDetailService, IOutboundOrderService outboundOrderService, IOutStockLockInfoService outboundStockLockInfoService, IFeedbackMesService feedbackMesService, IRepository<Dt_Task> taskRepository, ILocationInfoService locationInfoService, IESSApiService eSSApiService, IRepository<Dt_AllocateOrder> allocateOrderRepository, IRepository<Dt_AllocateMaterialInfo> allocateMaterialInfoRepository, IRepository<Dt_InboundOrderDetail> inboundOrderDetailRepository, IRepository<Dt_InboundOrder> inboundOrderRepository)
        public OutboundService(IMapper mapper, IUnitOfWorkManage unitOfWorkManage, IRepository<Dt_OutboundOrderDetail> detailRepository, IRepository<Dt_OutboundOrder> outboundRepository, IRepository<Dt_OutStockLockInfo> outboundLockInfoRepository, IRepository<Dt_StockInfo> stockInfoRepository, IRepository<Dt_StockInfoDetail> stockDetailRepository, IRepository<Dt_StockQuantityChangeRecord> stockChangeRepository, IRepository<Dt_StockInfoDetail_Hty> stockDetailHistoryRepository, IBasicService basicService, IOutboundOrderDetailService outboundOrderDetailService, IOutboundOrderService outboundOrderService, IOutStockLockInfoService outboundStockLockInfoService, IFeedbackMesService feedbackMesService, IRepository<Dt_Task> taskRepository, ILocationInfoService locationInfoService, IESSApiService eSSApiService, IRepository<Dt_AllocateOrder> allocateOrderRepository, IRepository<Dt_AllocateMaterialInfo> allocateMaterialInfoRepository, IRepository<Dt_InboundOrderDetail> inboundOrderDetailRepository, IRepository<Dt_InboundOrder> inboundOrderRepository, IRepository<Dt_LocationType> locationTypeRepository, IRepository<Dt_WarehouseArea> warehouseAreaRepository)
        {
            _mapper = mapper;
            _unitOfWorkManage = unitOfWorkManage;
@@ -103,6 +108,8 @@
            _allocateMaterialInfoRepository = allocateMaterialInfoRepository;
            _inboundOrderDetailRepository = inboundOrderDetailRepository;
            _inboundOrderRepository = inboundOrderRepository;
            _locationTypeRepository = locationTypeRepository;
            _warehouseAreaRepository = warehouseAreaRepository;
        }
        public WebResponseContent PrintFromData (string barcode)
@@ -144,6 +151,14 @@
            PickingOutboundResponseDTO response = new PickingOutboundResponseDTO();
            decimal totalNeedAllocate = 0; // æ€»éœ€æ±‚分配量
            decimal totalActualAllocate = 0; // å®žé™…总分配量
            string targetWarehouse = string.Empty;// ç›®æ ‡ä»“库
            string targetLocationCode = string.Empty; // ç›®æ ‡è´§ä½
            bool isWholeCaseOutbound = false; // æ˜¯å¦æ•´ç®±å‡ºåº“
            List<string> wholeCasePallets = new List<string>();
            Dictionary<string, string> palletLocationMap = new Dictionary<string, string>();
            Dictionary<string, bool> palletIsWholeCaseMap = new Dictionary<string, bool>();
            int? targetLocationType = null;
            try
            {
@@ -159,6 +174,7 @@
                // è®°å½•总需求数量
                totalNeedAllocate = calculationResult.MaterielCalculations.Sum(x => x.UnallocatedQuantity);
                // 2. å¤„理物料分配
                List<PickedStockDetailDTO> pickedDetails = new List<PickedStockDetailDTO>();
                Dt_OutboundOrder outboundOrder = calculationResult.OutboundOrder;
@@ -192,11 +208,116 @@
                            materielCalc.OutStockLockInfos.Add(item);
                        }
                        outStockLockInfos.Add(item);
                    }
                        if (outboundOrder.OrderType == 117)
                        {
                            // åŒ¹é…å½“前单据的锁定记录
                            if (outboundOrder.OrderNo == item.OrderNo)
                            {
                                // æŸ¥è¯¢åº“存信息
                                var stockInfo = _stockInfoRepository.QueryFirst(x => x.PalletCode == item.PalletCode);
                                if (stockInfo == null)
                                {
                                    content = WebResponseContent.Instance.Error($"托盘{item.PalletCode}未查询到库存信息,无法处理整箱出库");
                                    _unitOfWorkManage.RollbackTran();
                                    return content;
                                }
                                // è®¡ç®—库存总量,判断是否整箱(增加0值保护)
                                decimal stockQuantity = _stockDetailRepository.QueryData(x => x.StockId == stockInfo.Id).Sum(x => x.StockQuantity);
                                if (stockQuantity > 0 && stockQuantity == item.AssignQuantity)
                                {
                                    // æ ‡è®°å½“前托盘为整箱(核心修复:按托盘维度记录状态)
                                    if (!palletIsWholeCaseMap.ContainsKey(item.PalletCode))
                                    {
                                        palletIsWholeCaseMap.Add(item.PalletCode, true);
                                    }
                                    else
                                    {
                                        palletIsWholeCaseMap[item.PalletCode] = true;
                                    }
                                    // ç›®æ ‡ä»“库/货位类型只查询一次(性能优化+空值保护)
                                    if (string.IsNullOrEmpty(targetWarehouse))
                                    {
                                        targetWarehouse = GetToWarehouseByOrderNo(request.OrderNo);
                                        if (string.IsNullOrEmpty(targetWarehouse))
                                        {
                                            content = WebResponseContent.Instance.Error("智仓调智仓整箱出库单据未配置目标仓库");
                                            _unitOfWorkManage.RollbackTran();
                                            return content;
                                        }
                                        // æ›¿æ¢First()为FirstOrDefault(),避免空值异常
                                        string warehouseAreaName = _warehouseAreaRepository.Db.Queryable<Dt_WarehouseArea>()
                                            .Where(x => x.Code == targetWarehouse)
                                            .Select(x => x.Name)
                                            .First();
                                        if (string.IsNullOrEmpty(warehouseAreaName))
                                        {
                                            content = WebResponseContent.Instance.Error($"目标仓库{targetWarehouse}未查询到对应的库区名称");
                                            _unitOfWorkManage.RollbackTran();
                                            return content;
                                        }
                                        int? locationType = _locationTypeRepository.Db.Queryable<Dt_LocationType>()
                                            .Where(x => string.Equals(x.LocationTypeDesc, warehouseAreaName, StringComparison.OrdinalIgnoreCase))
                                            .Select(x => x.LocationType)
                                            .First();
                                        if (!locationType.HasValue)
                                        {
                                            content = WebResponseContent.Instance.Error($"库区{warehouseAreaName}未匹配到对应的货位类型");
                                            _unitOfWorkManage.RollbackTran();
                                            return content;
                                        }
                                        targetLocationType = locationType.Value;
                                    }
                                    // åˆ†é…ç›®æ ‡è´§ä½ï¼ˆæ¯ä¸ªæ‰˜ç›˜ç‹¬ç«‹è´§ä½ï¼‰
                                    if (!palletLocationMap.ContainsKey(item.PalletCode) && targetLocationType.HasValue)
                                    {
                                        Dt_LocationInfo locationInfo = _locationInfoService.AssignLocation(targetLocationType.Value);
                                        if (locationInfo == null || string.IsNullOrEmpty(locationInfo.LocationCode))
                                        {
                                            content = WebResponseContent.Instance.Error($"货位类型{targetLocationType.Value}未分配到可用货位(托盘:{item.PalletCode})");
                                            _unitOfWorkManage.RollbackTran();
                                            return content;
                                        }
                                        palletLocationMap.Add(item.PalletCode, locationInfo.LocationCode);
                                    }
                                    // åŠ å…¥æ•´ç®±æ‰˜ç›˜åˆ—è¡¨
                                    if (!wholeCasePallets.Contains(item.PalletCode))
                                    {
                                        wholeCasePallets.Add(item.PalletCode);
                                    }
                                }
                                else
                                {
                                    if (!palletIsWholeCaseMap.ContainsKey(item.PalletCode))
                                    {
                                        palletIsWholeCaseMap.Add(item.PalletCode, false);
                                    }
                                    else
                                    {
                                        palletIsWholeCaseMap[item.PalletCode] = false;
                                    }
                                }
                            }
                          }
                        }
                    // å¤„理任务
                    foreach (var item in materielPickedDetails.Tasks)
                    {
                        if (outboundOrder.OrderType == 117
                           && palletIsWholeCaseMap.ContainsKey(item.PalletCode)
                           && palletIsWholeCaseMap[item.PalletCode]
                           && palletLocationMap.ContainsKey(item.PalletCode))
                        {
                            item.TaskType = (int)TaskTypeEnum.Relocation;
                            item.TargetAddress = palletLocationMap[item.PalletCode];
                        }
                        if (tasks.FirstOrDefault(x => x.PalletCode == item.PalletCode) == null)
                            tasks.Add(item);
                    }
@@ -234,8 +355,26 @@
                
                if (tasks.Any()) _taskRepository.AddData(tasks);
                    _unitOfWorkManage.CommitTran();
                if (outboundOrder.OrderType == 117 && wholeCasePallets.Any())
                {
                    foreach (var palletCode in wholeCasePallets)
                    {
                        var completeReq = new OutboundCompletePalletRequestDTO
                        {
                            OrderNo = request.OrderNo,
                            PalletCode = palletCode
                        };
                        var res = CompleteOutboundWithPallet(completeReq);
                        if (!res.Status)
                        {
                            _unitOfWorkManage.RollbackTran();
                            return res;
                        }
                    }
                }
                _unitOfWorkManage.CommitTran();
                // 4. æž„造响应:区分「全部分配」和「部分分配」
                string responseMsg = totalActualAllocate == totalNeedAllocate
@@ -259,6 +398,18 @@
                content = WebResponseContent.Instance.Error("处理拣货出库失败:" + ex.Message);
            }
            return content;
        }
        /// <summary>
        /// æ ¹æ®å•据号获取目标仓库
        /// </summary>
        /// <param name="orderNo"></param>
        /// <returns></returns>
        public String GetToWarehouseByOrderNo(string orderNo)
        {
            var order =_allocateOrderRepository.QueryFirst(x => x.OrderNo == orderNo);
            return order.ToWarehouse;
        }
        /// <summary>
@@ -1327,9 +1478,15 @@
            _stockDetailHistoryRepository.AddData(historyRecords);
            // åˆ é™¤åº“存明细记录
            _stockDetailRepository.DeleteData(stockInfo.Details);
            var orderNo =_outboundRepository.QueryFirst(x => x.OrderNo == request.OrderNo);
            if(orderNo.OrderType != 117)
            {
                _stockDetailRepository.DeleteData(stockInfo.Details);
            }
            _stockChangeRepository.AddData(changeRecords);
        }
        #endregion
        #region æ‹£é€‰
@@ -1549,6 +1706,10 @@
                            item.OverOutQuantity = item.LockQuantity;
                        }
                        if (item.OverOutQuantity == item.OrderQuantity)
                        {
                            item.OrderDetailStatus = (int)OrderDetailStatusEnum.Over;
                        }
                        updateDetails.Add(item);
                        List<Barcodes> barcodesList = new List<Barcodes>();
@@ -1643,7 +1804,7 @@
                    {
                        UpdateOutboundOrderStatus(request.OrderNo, OutOrderStatusEnum.出库完成.ObjToInt());
                        if (outboundOrder.OrderType != OutOrderTypeEnum.InternalAllocat.ObjToInt() && outboundOrder.CreateType!=OrderCreateTypeEnum.CreateInSystem.ObjToInt())
                        if (outboundOrder.CreateType!=OrderCreateTypeEnum.CreateInSystem.ObjToInt())
                        {
                            _feedbackMesService.OutboundFeedback(outboundOrder.OrderNo);
                        }
@@ -2191,5 +2352,7 @@
        }
        #endregion
    }
}