From a846d73009c695f51ef507f53f14b3b8c73e59d8 Mon Sep 17 00:00:00 2001
From: heshaofeng <heshaofeng@hnkhzn.com>
Date: 星期二, 31 三月 2026 10:26:50 +0800
Subject: [PATCH] Merge branch 'htq20251215' of http://115.159.85.185:8098/r/ZhongRui/ALDbanyunxiangmu into htq20251215

---
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundService.cs | 1910 +++++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 1,399 insertions(+), 511 deletions(-)

diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundService.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundService.cs"
index be08ce1..5503ec7 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundService.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundService.cs"
@@ -1,13 +1,16 @@
-锘縰sing System.Reflection.Emit;
-using AutoMapper;
+锘縰sing 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;
@@ -18,14 +21,18 @@
 using WIDESEA_Core.BaseRepository;
 using WIDESEA_Core.CodeConfigEnum;
 using WIDESEA_Core.Helper;
+using WIDESEA_DTO.Base;
 using WIDESEA_DTO.Basic;
 using WIDESEA_DTO.CalcOut;
+using WIDESEA_DTO.Outbound;
 using WIDESEA_DTO.ReturnMES;
 using WIDESEA_IBasicService;
 using WIDESEA_IOutboundService;
 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;
 
 namespace WIDESEA_OutboundService
@@ -59,6 +66,11 @@
         private readonly IESSApiService _eSSApiService;
         private readonly IRepository<Dt_AllocateOrder> _allocateOrderRepository;
         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;
+        public readonly IRepository<Dt_OutboundOrderDetail> _outboundOrderDetailRepository;
 
         private Dictionary<string, string> stations = new Dictionary<string, string>
         {
@@ -72,7 +84,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)
+        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, IRepository<Dt_OutboundOrderDetail> outboundOrderDetailRepository)
         {
             _mapper = mapper;
             _unitOfWorkManage = unitOfWorkManage;
@@ -95,6 +107,38 @@
             _eSSApiService = eSSApiService;
             _allocateOrderRepository = allocateOrderRepository;
             _allocateMaterialInfoRepository = allocateMaterialInfoRepository;
+            _inboundOrderDetailRepository = inboundOrderDetailRepository;
+            _inboundOrderRepository = inboundOrderRepository;
+            _locationTypeRepository = locationTypeRepository;
+            _warehouseAreaRepository = warehouseAreaRepository;
+            _outboundOrderDetailRepository = outboundOrderDetailRepository;
+        }
+
+        public WebResponseContent PrintFromData (string barcode)
+        {
+            var detail = _inboundOrderDetailRepository.QueryFirst(x => x.Barcode == barcode);
+            if(detail == null)
+            {
+                return WebResponseContent.Instance.Error();
+            }
+
+            var inbound = _inboundOrderRepository.QueryFirst(x=>x.Id ==  detail.OrderId);
+            if(inbound == null)
+            {
+                return WebResponseContent.Instance.Error();
+            }
+            var printFormData = new PrintFromDataDTO { 
+                materialCode = detail.MaterielCode,
+                materialName = detail.MaterielName,
+                materialSpec = detail.Unit,
+                batchNo = detail.BatchNo,
+                pruchaseOrderNo = inbound.UpperOrderNo,
+                factoryArea = inbound.FactoryArea,
+                suplierCode = detail.SupplyCode,
+                quantity = detail.BarcodeQty
+            };
+
+            return WebResponseContent.Instance.OK(data:printFormData);
         }
 
         #region 鍑哄簱鍒嗛厤
@@ -106,139 +150,288 @@
         public WebResponseContent ProcessPickingOutbound(PickingOutboundRequestDTO request)
         {
             WebResponseContent content = WebResponseContent.Instance;
-
             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
             {
                 _unitOfWorkManage.BeginTran();
                 // 1. 璁$畻鍑哄簱鏁伴噺閫昏緫
                 OutboundCalculationDTO calculationResult = CalcOutboundQuantity(request);
-
                 if (!calculationResult.CanOutbound)
                 {
                     content = WebResponseContent.Instance.Error("鏃犳硶澶勭悊鎷h揣鍑哄簱锛�" + calculationResult.ErrorMessage);
                     _unitOfWorkManage.RollbackTran();
                     return content;
                 }
+                // 璁板綍鎬婚渶姹傛暟閲�
+                totalNeedAllocate = calculationResult.MaterielCalculations.Sum(x => x.UnallocatedQuantity);
 
-                // 2. 璋冪敤鍑哄簱澶勭悊閫昏緫锛岄攣瀹氬簱瀛橈紝鐢熸垚鍑哄簱璁板綍绛�
+                
+                // 2. 澶勭悊鐗╂枡鍒嗛厤
                 List<PickedStockDetailDTO> pickedDetails = new List<PickedStockDetailDTO>();
-
-                // 鑾峰彇鍑哄簱鍗曚俊鎭�
                 Dt_OutboundOrder outboundOrder = calculationResult.OutboundOrder;
-
-                // 鍑哄簱璇︽儏娣诲姞鎴栦慨鏀归泦鍚�
                 List<Dt_OutStockLockInfo> outStockLockInfos = new List<Dt_OutStockLockInfo>();
-
-                List<Dt_OutboundOrderDetail> outboundOrderDetails = new();
-
+                List<Dt_OutboundOrderDetail> outboundOrderDetails = new List<Dt_OutboundOrderDetail>();
                 List<Dt_Task> tasks = new List<Dt_Task>();
+
                 foreach (var materielCalc in calculationResult.MaterielCalculations)
                 {
-                    (List<PickedStockDetailDTO> PickedDetails, List<Dt_Task> Tasks, List<Dt_OutStockLockInfo> OutStockLockInfo) materielPickedDetails = ProcessMaterielTaskGeneration(outboundOrder, materielCalc, request, calculationResult.FactoryArea);
+                    var materielPickedDetails = ProcessMaterielTaskGeneration(outboundOrder, materielCalc, request, calculationResult.FactoryArea);
+                    // 璁$畻褰撳墠鐗╂枡瀹為檯鍒嗛厤閲�
+                    decimal actualAllocatedQuantity = materielPickedDetails.PickedDetails.Sum(x => x.OutboundQuantity);
+                    actualAllocatedQuantity = Math.Min(actualAllocatedQuantity, materielCalc.UnallocatedQuantity);
+                    totalActualAllocate += actualAllocatedQuantity; // 绱姞鑷虫�诲疄闄呭垎閰嶉噺
+                    materielCalc.UnallocatedQuantity = materielCalc.UnallocatedQuantity - actualAllocatedQuantity;
 
+                    // 澶勭悊鍑哄簱閿佸畾璁板綍
                     foreach (var item in materielPickedDetails.OutStockLockInfo)
                     {
-                        Dt_OutStockLockInfo? outStockLockInfo = materielCalc.OutStockLockInfos.FirstOrDefault(x => x.Id == item.Id && x.Id > 0);
-                        if (outStockLockInfo != null)
+                        Dt_OutStockLockInfo? existLockInfo = materielCalc.OutStockLockInfos.FirstOrDefault(x => x.Id == item.Id && x.Id > 0);
+                        if (existLockInfo != null)
                         {
-                            outStockLockInfo = item;
+                            existLockInfo = item;
                             Dt_Task? task = tasks.FirstOrDefault(x => x.PalletCode == item.PalletCode);
-                            if (task != null)
-                            {
-                                outStockLockInfo.TaskNum = task.TaskNum;
-                            }
+                            if (task != null) existLockInfo.TaskNum = task.TaskNum;
                         }
                         else
                         {
                             Dt_Task? task = tasks.FirstOrDefault(x => x.PalletCode == item.PalletCode);
-                            if (task != null)
-                            {
-                                item.TaskNum = task.TaskNum;
-                            }
+                            if (task != null) item.TaskNum = task.TaskNum;
                             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()涓篎irstOrDefault()锛岄伩鍏嶇┖鍊煎紓甯�
+                                        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)
                     {
-                        Dt_Task? task = tasks.FirstOrDefault(x => x.PalletCode == item.PalletCode);
-                        if (task == null)
+                        if (outboundOrder.OrderType == 117
+                           && palletIsWholeCaseMap.ContainsKey(item.PalletCode)
+                           && palletIsWholeCaseMap[item.PalletCode]
+                           && palletLocationMap.ContainsKey(item.PalletCode))
                         {
-                            tasks.Add(item);
+                            item.TaskType = (int)TaskTypeEnum.Relocation;
+                            item.TargetAddress = palletLocationMap[item.PalletCode];
                         }
+                        if (tasks.FirstOrDefault(x => x.PalletCode == item.PalletCode) == null)
+                            tasks.Add(item);
                     }
 
+                    // 姹囨�诲垎鎷f槑缁�
                     pickedDetails.AddRange(materielPickedDetails.PickedDetails);
 
-                    decimal allallocatedQuantity = Math.Min(materielCalc.UnallocatedQuantity, materielPickedDetails.PickedDetails.Sum(x => x.OutboundQuantity));
-                    materielCalc.UnallocatedQuantity = allallocatedQuantity;
-                    // 鏇存柊鍑哄簱鍗曟槑缁嗭紙澧炲姞閿佸畾鏁伴噺锛屼笉澧炲姞宸插嚭鏁伴噺锛�
+                    // 鎸夊疄闄呭垎閰嶉噺鏇存柊鍗曟嵁閿佸畾鏁伴噺
+                    decimal remainingToLock = actualAllocatedQuantity;
                     foreach (var detail in materielCalc.Details)
                     {
-                        if (allallocatedQuantity <= 0) break;
-
-                        decimal lockQuantity = (detail.OrderQuantity - detail.OverOutQuantity);
-                        if (lockQuantity < materielCalc.UnallocatedQuantity)
+                        if (remainingToLock <= 0) break;
+                        decimal maxLockableQty = 0;
+                        if (detail.LockQuantity > detail.OverOutQuantity && detail.OverOutQuantity > 0)
                         {
-                            detail.LockQuantity += lockQuantity; // 澧炲姞閿佸畾鏁伴噺 涓嶆洿鏂� OverOutQuantity 鍜� OrderDetailStatus锛屽洜涓鸿繕娌℃湁瀹為檯鍑哄簱
-                            outboundOrderDetails.Add(detail);
-                            materielCalc.UnallocatedQuantity -= lockQuantity;
+                             maxLockableQty = detail.OrderQuantity - detail.LockQuantity;
+                        }
+                        else if(detail.OverOutQuantity > 0)
+                        {
+                            maxLockableQty = detail.OrderQuantity - detail.OverOutQuantity;
                         }
                         else
                         {
-                            detail.LockQuantity += materielCalc.UnallocatedQuantity;
-                            outboundOrderDetails.Add(detail);
-                            break;
+                            maxLockableQty = detail.OrderQuantity - detail.OverOutQuantity - detail.LockQuantity;
+                        }
+                        if (maxLockableQty <= 0) continue;
+                        decimal currentLockQty = Math.Min(remainingToLock, maxLockableQty);
+                        detail.LockQuantity += currentLockQty;
+                        outboundOrderDetails.Add(detail);
+                        remainingToLock -= currentLockQty;
+                    }
+                }
+
+                // 3. 鎵归噺鏇存柊鐘舵�侊紙鍘熸湁閫昏緫涓嶅彉锛�
+                UpdateOutboundOrderStatus(request.OrderNo, (int)OutOrderStatusEnum.鍑哄簱涓�);
+                _detailRepository.UpdateData(outboundOrderDetails);
+                if (pickedDetails.Any())
+                {
+                    UpdateStockStatus(pickedDetails.Select(x => x.PalletCode).ToList(), StockStatusEmun.鍑哄簱閿佸畾.ObjToInt());
+                    UpdateLocationStatus(pickedDetails.Select(x => x.LocationCode).ToList(), LocationStatusEnum.Lock.ObjToInt());
+                }
+                //閲嶆鍗曚笉鎷i�夛紝鍘绘帀閿佸畾璁板綍鍥炲簱锛屽啀娆$粍鐩樻椂鎵i櫎鍘熸潯鐮�
+                if (outboundOrder.OrderType != InOrderTypeEnum.ReCheck.ObjToInt())
+                {
+                    UpdateOutStockLockInfo(outStockLockInfos);
+                }
+                
+                if (tasks.Any()) _taskRepository.AddData(tasks);
+
+                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;
                         }
                     }
                 }
 
-                // 3. 鏇存柊鍑哄簱鍗曠姸鎬佷负鍑哄簱涓紙琛ㄧず宸叉湁浠诲姟鍒嗛厤锛�
-                UpdateOutboundOrderStatus(request.OrderNo, (int)OutOrderStatusEnum.鍑哄簱涓�);
-
-                // 4. 鏇存柊鍑哄簱鍗曟槑缁嗛攣瀹氭暟閲�
-                _detailRepository.UpdateData(outboundOrderDetails);
-
-                // 5. 鏇存柊搴撳瓨鐘舵��
-                UpdateStockStatus(pickedDetails.Select(x => x.PalletCode).ToList(), StockStatusEmun.鍑哄簱閿佸畾.ObjToInt());
-
-                // 6. 鏇存柊璐т綅鐘舵��
-                UpdateLocationStatus(pickedDetails.Select(x => x.LocationCode).ToList(), LocationStatusEnum.Lock.ObjToInt());
-
-                // 7. 鏇存柊搴撳瓨璇︽儏
-                UpdateOutStockLockInfo(outStockLockInfos);
-
-                // 8. 娣诲姞浠诲姟鏁版嵁
-                _taskRepository.AddData(tasks);
-
                 _unitOfWorkManage.CommitTran();
 
+                // 4. 鏋勯�犲搷搴旓細鍖哄垎銆屽叏閮ㄥ垎閰嶃�嶅拰銆岄儴鍒嗗垎閰嶃��
+                string responseMsg = totalActualAllocate == totalNeedAllocate
+                    ? "鍒嗘嫞浠诲姟鍒嗛厤鎴愬姛"
+                    : $"鍒嗘嫞浠诲姟鍒嗛厤瀹屾垚锛堝疄闄呭垎閰峽totalActualAllocate}锛岄渶姹倇totalNeedAllocate}锛屽簱瀛樹笉瓒抽儴鍒嗘湭鍒嗛厤锛�";
+                Dt_OutboundOrder outboundOrder1 = _outboundRepository.Db.Queryable<Dt_OutboundOrder>().Where(x => x.OrderNo == request.OrderNo).Includes(x=>x.Details).First();
+                if(totalActualAllocate == 0 && !outboundOrder1.Details.Any(x=>x.LockQuantity >0))
+                {
+                    UpdateOutboundOrderStatus(request.OrderNo, (int)OutOrderStatusEnum.鏈紑濮�);
+                    return WebResponseContent.Instance.Error("鍒嗛厤搴撳瓨鏁伴噺涓�0锛屾棤娉曞嚭搴�");
+                }
                 response.Success = true;
-                response.Message = "鍒嗘嫞浠诲姟鍒嗛厤鎴愬姛";
-                response.Tasks = tasks; // 杩斿洖绗竴涓换鍔″彿
-                response.PickedDetails = pickedDetails; // 杩斿洖绗竴涓垎鎷f槑缁�
-                content = WebResponseContent.Instance.OK("鍒嗘嫞浠诲姟鍒嗛厤鎴愬姛", response);
-                return content;
+                response.Message = responseMsg;
+                response.Tasks = tasks;
+                response.PickedDetails = pickedDetails;
+                content = WebResponseContent.Instance.OK(responseMsg, response);
             }
             catch (Exception ex)
             {
                 _unitOfWorkManage.RollbackTran();
-
                 content = WebResponseContent.Instance.Error("澶勭悊鎷h揣鍑哄簱澶辫触锛�" + ex.Message);
             }
             return content;
         }
 
+
         /// <summary>
-        /// 璁$畻鍑哄簱鏁伴噺閫昏緫
+        /// 鏍规嵁鍗曟嵁鍙疯幏鍙栫洰鏍囦粨搴�
         /// </summary>
-        /// <param name="request"></param>
+        /// <param name="orderNo"></param>
         /// <returns></returns>
+        public String GetToWarehouseByOrderNo(string orderNo)
+        {
+            var order =_allocateOrderRepository.QueryFirst(x => x.OrderNo == orderNo);
+            return order.ToWarehouse;
+        }
+
+        /// <summary>
+        /// 璁$畻鍑哄簱鏁伴噺閫昏緫锛堝師鏈夐�昏緫涓嶅彉锛�
+        /// </summary>
         public OutboundCalculationDTO CalcOutboundQuantity(PickingOutboundRequestDTO request)
         {
-            OutboundCalculationDTO result = new();
-
+            OutboundCalculationDTO result = new OutboundCalculationDTO();
             try
             {
                 Dt_OutboundOrder outboundOrder = _outboundRepository.QueryFirst(x => x.OrderNo == request.OrderNo);
@@ -251,23 +444,14 @@
 
                 result.FactoryArea = outboundOrder.FactoryArea;
                 List<Dt_OutboundOrderDetail> selectedDetails = new List<Dt_OutboundOrderDetail>();
-
-                if(request.DetailIds == null || !request.DetailIds.Any())
+                if (request.DetailIds == null || !request.DetailIds.Any())
                 {
                     selectedDetails = _detailRepository.QueryData(x => x.OrderId == outboundOrder.Id);
                 }
                 else
                 {
-                    // 鑾峰彇閫夋嫨鐨勫嚭搴撴槑缁�
-                     selectedDetails = _detailRepository.QueryData(x => x.OrderId == outboundOrder.Id && request.DetailIds.Contains(x.Id));
+                    selectedDetails = _detailRepository.QueryData(x => x.OrderId == outboundOrder.Id && request.DetailIds.Contains(x.Id));
                 }
-                
-
-                //if (outboundOrder.IsBatch == 1 && request.DetailIds.Count == 1)
-                //{
-                //    selectedDetails = _detailRepository.QueryData(x => x.OrderId == selectedDetails.First().OrderId && x.WarehouseCode == selectedDetails.First().WarehouseCode && x.MaterielCode == selectedDetails.First().MaterielCode && x.BatchNo == selectedDetails.First().BatchNo && x.SupplyCode == selectedDetails.First().SupplyCode);
-                //}
-
 
                 if (!selectedDetails.Any())
                 {
@@ -278,23 +462,21 @@
                 if (selectedDetails.Any(x => x.LockQuantity > x.OrderQuantity - x.MoveQty || x.OverOutQuantity > x.OrderQuantity - x.MoveQty))
                 {
                     List<int> selectDetailIds = selectedDetails.Where(x => x.LockQuantity > x.OrderQuantity - x.MoveQty || x.OverOutQuantity > x.OrderQuantity - x.MoveQty).Select(x => x.Id).ToList();
-
                     result.CanOutbound = false;
                     result.ErrorMessage = $"鍑哄簱鏄庣粏淇℃伅{string.Join(",", selectDetailIds)}宸插垎閰嶅畬鎴�";
                     return result;
                 }
+
                 outboundOrder.Details = selectedDetails;
                 result.OutboundOrder = outboundOrder;
                 result.SelectedDetails = selectedDetails;
 
                 if (outboundOrder.IsBatch == 0 || request.DetailIds.Count != 1)
                 {
-                    // 澶氭槑缁嗗嚭搴擄細鎸夌墿鏂欏垎缁勫鐞�
                     result.MaterielCalculations = CalcMaterielOutboundQuantities(outboundOrder, selectedDetails.ToList());
                 }
                 else
                 {
-                    // 鍗曟槑缁嗗嚭搴擄細楠岃瘉杈撳叆鐨勫嚭搴撴暟閲�
                     if (!request.OutboundQuantity.HasValue || request.OutboundQuantity.Value <= 0)
                     {
                         result.CanOutbound = false;
@@ -306,10 +488,8 @@
                     decimal orderQuantity = selectedDetails.Sum(x => x.OrderQuantity);
                     decimal moveQuantity = selectedDetails.Sum(x => x.MoveQty);
                     decimal overQuantity = selectedDetails.Sum(x => x.OverOutQuantity);
-
                     Dt_OutboundOrderDetail? singleDetail = selectedDetails.First();
 
-                    //鍒ゆ柇鍙嚭搴撴暟閲�
                     if (orderQuantity - lockQuantity - moveQuantity < request.OutboundQuantity.Value || orderQuantity - overQuantity - moveQuantity < request.OutboundQuantity.Value)
                     {
                         result.CanOutbound = false;
@@ -323,10 +503,7 @@
                     {
                         inputQuantity -= (item.OrderQuantity - item.MoveQty - item.LockQuantity);
                         outboundOrderDetails.Add(item);
-                        if (inputQuantity <= 0)
-                        {
-                            break;
-                        }
+                        if (inputQuantity <= 0) break;
                     }
 
                     result.MaterielCalculations = new List<MaterielOutboundCalculationDTO>()
@@ -346,31 +523,24 @@
                             Details = outboundOrderDetails
                         }
                     };
-
                     outboundOrder.Details = outboundOrderDetails;
                 }
-
                 result.CanOutbound = true;
-                return result;
             }
             catch (Exception ex)
             {
                 result.CanOutbound = false;
                 result.ErrorMessage = ex.Message;
-                return result;
             }
-
+            return result;
         }
 
         /// <summary>
-        /// 澶氬嚭搴撳崟鏄庣粏鏃讹紝鎸夌墿鏂欏垎缁勮绠楀嚭搴撴暟閲�
+        /// 鎸夌墿鏂欏垎缁勮绠楀嚭搴撴暟閲忥紙鍘熸湁閫昏緫涓嶅彉锛�
         /// </summary>
-        /// <param name="selectedDetails"></param>
-        /// <returns></returns>
         private List<MaterielOutboundCalculationDTO> CalcMaterielOutboundQuantities(Dt_OutboundOrder outboundOrder, List<Dt_OutboundOrderDetail> selectedDetails)
         {
-            // 鎸夌墿鏂欏垎缁勶細鐗╂枡缂栧彿銆佹壒娆″彿銆佷緵搴斿晢缂栧彿銆佷粨搴撶紪鍙�
-            List<MaterielOutboundCalculationDTO> materielGroups = selectedDetails
+            return selectedDetails
                 .GroupBy(x => new
                 {
                     x.MaterielCode,
@@ -390,138 +560,395 @@
                     UnallocatedQuantity = g.Sum(x => x.OrderQuantity - x.LockQuantity - x.MoveQty),
                     MovedQuantity = g.Sum(x => x.MoveQty),
                     Details = g.ToList(),
-                    OutStockLockInfos = _outboundLockInfoRepository.QueryData(x => x.MaterielCode == g.Key.MaterielCode && x.BatchNo == g.Key.BatchNo && x.OrderType == (int)outboundOrder.OrderType && x.OrderNo == outboundOrder.OrderNo)
+                    OutStockLockInfos = _outboundLockInfoRepository.QueryData(x =>
+                        x.MaterielCode == g.Key.MaterielCode &&
+                        x.BatchNo == g.Key.BatchNo &&
+                        x.OrderType == (int)outboundOrder.OrderType &&
+                        x.OrderNo == outboundOrder.OrderNo)
                 })
                 .ToList();
-
-            return materielGroups;
         }
 
         /// <summary>
-        /// 澶勭悊鐗╂枡鐨勪换鍔$敓鎴�
+        /// 澶勭悊鐗╂枡浠诲姟鐢熸垚锛堟牳蹇冿細鏈夊灏戝垎澶氬皯+绉婚櫎搴撳瓨涓嶈冻寮傚父锛�
         /// </summary>
-        /// <param name="outboundOrder">鍑哄簱璁㈠崟</param>
-        /// <param name="materielCalc">鎸夌墿鏂欑殑鍑哄簱璁$畻缁撴灉</param>
-        /// <param name="request">鍒嗘嫞鍑哄簱璇锋眰</param>
-        /// <param name="factoryArea"></param>
-        /// <returns></returns>
-        /// <exception cref="Exception"></exception>
-        private (List<PickedStockDetailDTO> PickedDetails, List<Dt_Task> Tasks, List<Dt_OutStockLockInfo> OutStockLockInfo) ProcessMaterielTaskGeneration(Dt_OutboundOrder outboundOrder, MaterielOutboundCalculationDTO materielCalc, PickingOutboundRequestDTO request, string factoryArea)
+        private (List<PickedStockDetailDTO> PickedDetails, List<Dt_Task> Tasks, List<Dt_OutStockLockInfo> OutStockLockInfo) ProcessMaterielTaskGeneration(
+    Dt_OutboundOrder outboundOrder,
+    MaterielOutboundCalculationDTO materielCalc,
+    PickingOutboundRequestDTO request,
+    string factoryArea)
         {
             List<PickedStockDetailDTO> pickedDetails = new List<PickedStockDetailDTO>();
-            List<Dt_Task> generatedTasks = new List<Dt_Task>();
-
-            // 鏋勫缓搴撳瓨鏌ヨ鏉′欢锛堝寘鍚簱瀛樿〃銆佸簱瀛樻槑缁嗭級
-            List<Dt_StockInfo> stockQuery = BuildStockQueryWithInfo(materielCalc, factoryArea);
-
-            if (!stockQuery.Any())
-            {
-                throw new Exception($"鐗╂枡 {materielCalc.MaterielCode} 瀵瑰簲鐨勫簱瀛樹笉瀛樺湪");
-            }
-
-            // 鎵归噺璁$畻鎬诲彲鐢ㄥ簱瀛樻暟閲�
-            (Dictionary<int, decimal> AvailableStockMap, Dictionary<int, List<Dt_OutStockLockInfo>> LockStockMap) data = GetBatchAvailableStockQuantities(materielCalc, stockQuery);
-
-            // 鍙敤搴撳瓨鏁伴噺鏄犲皠
-            Dictionary<int, decimal> availableStockMap = data.AvailableStockMap;
-
-            // 鐗╂枡鎬诲彲鐢ㄥ簱瀛樻暟閲�
-            decimal totalAvailableStock = availableStockMap.Values.Sum();
-
-            // 宸查攣瀹氬簱瀛樻暟閲忔槧灏�
-            Dictionary<int, List<Dt_OutStockLockInfo>> lockStockMap = data.LockStockMap;
-
-            // 楠岃瘉鎬诲彲鐢ㄥ簱瀛樻槸鍚︽弧瓒冲嚭搴撻渶姹�
-            //if (totalAvailableStock < materielCalc.UnallocatedQuantity)
-            //{
-            //    throw new Exception($"鐗╂枡 {materielCalc.MaterielCode} 鍙敤搴撳瓨 {totalAvailableStock} 涓嶈冻鍑哄簱鏁伴噺 {materielCalc.UnallocatedQuantity}");
-            //}
-            // 闇�鍒嗛厤鏁伴噺
-            decimal remainingQuantity = Math.Min(totalAvailableStock, materielCalc.UnallocatedQuantity);
-
-            // 闇�鍒嗛厤鏁伴噺
-            //decimal remainingQuantity = materielCalc.UnallocatedQuantity;
-
-            // 宸插垎閰嶇殑鎵樼洏鍒楄〃
-            List<string> allocatedPallets = new List<string>();
-
-            // 鑾峰彇绗竴涓嚭搴撴槑缁�
-            Dt_OutboundOrderDetail firstDetail = materielCalc.Details.First();
-
-            // 棰勫姞杞藉簱瀛樻槑缁嗗拰閿佸畾璁板綍
-            List<int> stockIds = stockQuery.Select(x => x.Id).ToList();
-            Dictionary<int, List<Dt_StockInfoDetail>> stockDetailMap = stockQuery.ToDictionary(x => x.Id, x => x.Details);
-
-            // 璁板綍姣忎釜鎵樼洏鐨勫疄闄呭垎閰嶉噺
-            Dictionary<string, decimal> palletAllocations = new Dictionary<string, decimal>();
-
+            List<Dt_Task> generatedTasks = new List<Dt_Task>(); // 鍒濆绌轰换鍔″垪琛�
             List<Dt_OutStockLockInfo> lockInfoList = new List<Dt_OutStockLockInfo>();
-            foreach (var stock in stockQuery)
+            decimal remainingQuantity = materielCalc.UnallocatedQuantity;
+
+            // 1. 浼樺厛澶勭悊鎸囧畾搴撳瓨鏄庣粏
+            if (request.StockDetailIds?.Any() == true)
             {
-                if (remainingQuantity <= 0) break;
+                var specifiedResult = AllocateSpecifiedStockDetails(outboundOrder, materielCalc, request, factoryArea, remainingQuantity);
+                pickedDetails.AddRange(specifiedResult.PickedDetails);
+                lockInfoList.AddRange(specifiedResult.LockInfoList);
+                remainingQuantity -= specifiedResult.ActualAllocatedQuantity;
 
-                // 褰撳墠搴撳瓨鍙敤鏁伴噺
-                decimal availableQuantity = availableStockMap.GetValueOrDefault(stock.Id, 0);
-                if (availableQuantity <= 0) continue;
-
-                // 璁$畻璇ユ墭鐩樺彲鍒嗛厤鏁伴噺
-                decimal allocateQuantity = Math.Min(remainingQuantity, availableQuantity);
-                (decimal ActualAllocatedQuantity, List<Dt_OutStockLockInfo> LockInfoList) actualAllocated = AllocateStockQuantity(stock, allocateQuantity, availableQuantity, outboundOrder, firstDetail, request, lockStockMap.GetValueOrDefault(stock.Id, new List<Dt_OutStockLockInfo>()), stockDetailMap);
-
-                // 鏈鍒嗛厤鐨勬暟閲�
-                decimal actualAllocatedQuantity = actualAllocated.ActualAllocatedQuantity;
-
-                if (actualAllocatedQuantity > 0)
+                // ===== 鏍稿績淇锛氭寚瀹氬簱瀛樺垎閰嶅悗锛岀珛鍗崇敓鎴愪换鍔★紙鏃犺鍓╀綑閲忓灏戯級=====
+                if (specifiedResult.PickedDetails.Any()) // 鏈夋寚瀹氬簱瀛樺垎閰嶇粨鏋滃氨鐢熸垚浠诲姟
                 {
-                    allocatedPallets.Add(stock.PalletCode);
-                    palletAllocations[stock.PalletCode] = actualAllocatedQuantity; // 璁板綍瀹為檯鍒嗛厤閲�
-                    remainingQuantity -= actualAllocatedQuantity;
-                    lockInfoList.AddRange(actualAllocated.LockInfoList);
+                    var specifiedTasks = GenerateTasksForSpecifiedStock(specifiedResult.PickedDetails, request.OutboundTargetLocation);
+                    generatedTasks.AddRange(specifiedTasks); // 娣诲姞鎸囧畾搴撳瓨浠诲姟鍒版�讳换鍔″垪琛�
+                }
+
+                // 鍓╀綑閲�<=0鏃讹紝鐩存帴杩斿洖锛堝凡鐢熸垚鎸囧畾搴撳瓨浠诲姟锛�
+                if (remainingQuantity <= 0)
+                {
+                    return (pickedDetails, generatedTasks, lockInfoList);
                 }
             }
 
-            foreach (var palletCode in allocatedPallets)
+            // 2. 澶勭悊鍓╀綑鏁伴噺鐨勮嚜鍔ㄥ垎閰嶏紙鍘熸湁閫昏緫涓嶅彉锛岃嚜鍔ㄥ垎閰嶇殑浠诲姟浼氳拷鍔犲埌generatedTasks锛�
+            List<Dt_StockInfo> stockQuery = BuildStockQueryWithInfo(materielCalc, factoryArea);
+            var allocatedPalletCodes = pickedDetails.Select(x => x.PalletCode).Distinct().ToList();
+            stockQuery = stockQuery.Where(x => !allocatedPalletCodes.Contains(x.PalletCode)).ToList();
+
+            var stockData = GetBatchAvailableStockQuantities(materielCalc, stockQuery);
+            decimal totalAutoAvailable = stockData.AvailableStockMap.Values.Sum();
+            decimal autoAllocateQuantity = Math.Min(remainingQuantity, totalAutoAvailable);
+            remainingQuantity -= autoAllocateQuantity;
+
+            if (autoAllocateQuantity > 0 && stockQuery.Any())
             {
-                Dt_StockInfo stock = stockQuery.First(x => x.PalletCode == palletCode);
+                Dt_OutboundOrderDetail firstDetail = materielCalc.Details.First();
+                Dictionary<int, List<Dt_StockInfoDetail>> stockDetailMap = stockQuery.ToDictionary(x => x.Id, x => x.Details);
+                Dictionary<string, decimal> palletAllocations = new Dictionary<string, decimal>();
 
-                // 鑾峰彇瀹為檯鍒嗛厤鐨勬暟閲�
-                decimal actualAllocatedQuantity = palletAllocations.GetValueOrDefault(palletCode, 0);
-
-                // 璁$畻鍒嗛厤鍚庡墿浣欑殑搴撳瓨鏁伴噺
-                decimal originalAvailableQuantity = availableStockMap.GetValueOrDefault(stock.Id, 0);
-                decimal remainingStockQuantity = Math.Max(0, originalAvailableQuantity - actualAllocatedQuantity);
-
-                pickedDetails.Add(new PickedStockDetailDTO
+                foreach (var stock in stockQuery)
                 {
-                    PalletCode = palletCode,
-                    MaterielCode = materielCalc.MaterielCode,
-                    OutboundQuantity = actualAllocatedQuantity, // 鏈瀹為檯鍒嗛厤鐨勫嚭搴撻噺
-                    RemainingQuantity = remainingStockQuantity, // 鍒嗛厤鍚庡墿浣欑殑鍙敤搴撳瓨
-                    LocationCode = stock.LocationCode,
-                    OutStockLockInfos = lockInfoList
-                });
+                    if (autoAllocateQuantity <= 0) break;
+                    decimal availableQuantity = stockData.AvailableStockMap.GetValueOrDefault(stock.Id, 0);
+                    if (availableQuantity <= 0) continue;
 
-                Dt_OutStockLockInfo? outStockLockInfo = lockInfoList.FirstOrDefault(x => x.PalletCode == palletCode);
-                int taskNum = outStockLockInfo?.TaskNum ?? Db.Ado.GetScalar($"SELECT NEXT VALUE FOR SeqTaskNum").ObjToInt();
+                    // 鑷姩鍒嗛厤鏃舵煡璇㈡墭鐩樻�诲簱瀛橈紙鍘熸湁浼樺寲閫昏緫涓嶅彉锛�
+                    decimal palletMaterielTotalStock = _stockDetailRepository.QueryData(
+                        x => x.StockId == stock.Id && x.MaterielCode == materielCalc.MaterielCode
+                    ).Sum(x => x.StockQuantity);
 
-                Dt_Task task = GenerationOutTask(stock, TaskTypeEnum.Outbound, taskNum, request.OutboundTargetLocation);
-                if (generatedTasks.FirstOrDefault(x => x.PalletCode == stock.PalletCode) == null) generatedTasks.Add(task);
+                    decimal allocateQuantity = Math.Min(autoAllocateQuantity, availableQuantity);
+                    var actualAllocated = AllocateStockQuantity(
+                        stock, allocateQuantity, availableQuantity, outboundOrder, firstDetail,
+                        request, stockData.LockStockMap.GetValueOrDefault(stock.Id, new List<Dt_OutStockLockInfo>()),
+                        stockDetailMap, palletMaterielTotalStock);
+
+                    if (actualAllocated.ActualAllocatedQuantity > 0)
+                    {
+                        palletAllocations[stock.PalletCode] = actualAllocated.ActualAllocatedQuantity;
+                        autoAllocateQuantity -= actualAllocated.ActualAllocatedQuantity;
+                        lockInfoList.AddRange(actualAllocated.LockInfoList);
+                    }
+                }
+
+                // 鐢熸垚鑷姩鍒嗛厤鐨勪换鍔★紙杩藉姞鍒癵eneratedTasks锛屼笉浼氶噸澶嶏級
+                foreach (var palletCode in palletAllocations.Keys)
+                {
+                    Dt_StockInfo stock = stockQuery.First(x => x.PalletCode == palletCode);
+                    decimal actualQty = palletAllocations[palletCode];
+                    decimal originalAvailable = stockData.AvailableStockMap.GetValueOrDefault(stock.Id, 0);
+
+                    pickedDetails.Add(new PickedStockDetailDTO
+                    {
+                        PalletCode = palletCode,
+                        MaterielCode = materielCalc.MaterielCode,
+                        OutboundQuantity = actualQty,
+                        RemainingQuantity = Math.Max(0, originalAvailable - actualQty),
+                        LocationCode = stock.LocationCode,
+                        OutStockLockInfos = lockInfoList.Where(x => x.PalletCode == palletCode).ToList()
+                    });
+
+                    int taskNum = lockInfoList.FirstOrDefault(x => x.PalletCode == palletCode)?.TaskNum ??
+                                  Db.Ado.GetScalar($"SELECT NEXT VALUE FOR SeqTaskNum").ObjToInt();
+                    Dt_Task task = GenerationOutTask(stock, TaskTypeEnum.Outbound, taskNum, request.OutboundTargetLocation);
+                    // 杩囨护閲嶅浠诲姟锛堟寚瀹氬簱瀛樼殑鎵樼洏宸茬敓鎴愶紝涓嶄細閲嶅娣诲姞锛�
+                    if (generatedTasks.FirstOrDefault(x => x.PalletCode == palletCode) == null)
+                        generatedTasks.Add(task);
+                }
             }
 
+            // 杩斿洖銆屾寚瀹氬簱瀛樹换鍔�+鑷姩鍒嗛厤浠诲姟銆嶇殑鍚堝苟鍒楄〃
             return (pickedDetails, generatedTasks, lockInfoList);
         }
 
         /// <summary>
-        /// 鐢熸垚鍑哄簱浠诲姟
+        /// 鍒嗛厤鎸囧畾搴撳瓨鏄庣粏锛堟牳蹇冧紭鍖栵細鏌ヨ鎵樼洏鐗╂枡鎬诲簱瀛樺苟浼犻�掞級
         /// </summary>
-        /// <param name="stockInfo"></param>
-        /// <param name="taskType"></param>
-        /// <param name="outStation"></param>
-        /// <returns></returns>
+        private (decimal ActualAllocatedQuantity, List<PickedStockDetailDTO> PickedDetails, List<Dt_OutStockLockInfo> LockInfoList) AllocateSpecifiedStockDetails(
+            Dt_OutboundOrder outboundOrder,
+            MaterielOutboundCalculationDTO materielCalc,
+            PickingOutboundRequestDTO request,
+            string factoryArea,
+            decimal needAllocateQuantity)
+        {
+            List<PickedStockDetailDTO> pickedDetails = new List<PickedStockDetailDTO>();
+            List<Dt_OutStockLockInfo> lockInfoList = new List<Dt_OutStockLockInfo>();
+            decimal actualAllocated = 0;
+
+            List<Dt_StockInfoDetail> specifiedStockDetails = _stockDetailRepository.QueryData(
+                x => request.StockDetailIds.Contains(x.Id)
+                && x.MaterielCode == materielCalc.MaterielCode
+                && x.StockQuantity > 0
+                && (x.Status == (int)StockStatusEmun.鍏ュ簱瀹屾垚 || x.Status == (int)StockStatusEmun.鎵嬪姩鍐荤粨 || x.Status == (int)StockStatusEmun.鎵嬪姩瑙i攣 || x.Status == (int)StockStatusEmun.杩囨湡));
+
+            if (!specifiedStockDetails.Any())
+            {
+                throw new Exception($"鎸囧畾搴撳瓨鏄庣粏ID [{string.Join(",", request.StockDetailIds)}] 涓嶅瓨鍦ㄦ垨涓嶅彲鐢�");
+            }
+
+            List<int> stockIds = specifiedStockDetails.Select(x => x.StockId).Distinct().ToList();
+            List<Dt_StockInfo> specifiedStocks = _stockInfoRepository.QueryData(x => stockIds.Contains(x.Id));
+            Dictionary<int, Dt_StockInfo> stockMap = specifiedStocks.ToDictionary(x => x.Id);
+
+            foreach (var stockDetail in specifiedStockDetails)
+            {
+                if (needAllocateQuantity <= 0) break;
+                if (!stockMap.ContainsKey(stockDetail.StockId)) continue;
+
+                Dt_StockInfo stock = stockMap[stockDetail.StockId];
+                decimal availableQty = stockDetail.StockQuantity;
+                decimal allocateQty = Math.Min(needAllocateQuantity, availableQty);
+                if (allocateQty <= 0) continue;
+
+                // ===== 鏍稿績浼樺寲1锛氭煡璇㈣鎵樼洏涓嬪綋鍓嶇墿鏂欑殑鎬诲簱瀛� =====
+                decimal palletMaterielTotalStock = _stockDetailRepository.QueryData(
+                    x => x.StockId == stock.Id && x.MaterielCode == materielCalc.MaterielCode
+                ).Sum(x => x.StockQuantity); // 璇ユ墭鐩樿鐗╂枡鐨勬�诲簱瀛橈紙鑰岄潪鏈鍒嗛厤閲忥級
+
+                var lockInfos = materielCalc.OutStockLockInfos
+                    .Where(x => x.StockId == stock.Id && x.MaterielCode == materielCalc.MaterielCode)
+                    .ToList();
+
+                // ===== 浼犻�掓�诲簱瀛樺埌AllocateStockQuantity =====
+                var allocateResult = AllocateStockQuantity(
+                    stock, allocateQty, availableQty, outboundOrder, materielCalc.Details.First(),
+                    request, lockInfos,
+                    new Dictionary<int, List<Dt_StockInfoDetail>> { { stock.Id, new List<Dt_StockInfoDetail> { stockDetail } } },
+                    palletMaterielTotalStock // 鏂板锛氫紶鍏ユ墭鐩樼墿鏂欐�诲簱瀛�
+                );
+
+                if (allocateResult.ActualAllocatedQuantity > 0)
+                {
+                    pickedDetails.Add(new PickedStockDetailDTO
+                    {
+                        PalletCode = stock.PalletCode,
+                        MaterielCode = materielCalc.MaterielCode,
+                        OutboundQuantity = allocateResult.ActualAllocatedQuantity,
+                        RemainingQuantity = Math.Max(0, availableQty - allocateResult.ActualAllocatedQuantity),
+                        LocationCode = stock.LocationCode,
+                        OutStockLockInfos = allocateResult.LockInfoList
+                    });
+
+                    actualAllocated += allocateResult.ActualAllocatedQuantity;
+                    needAllocateQuantity -= allocateResult.ActualAllocatedQuantity;
+                    lockInfoList.AddRange(allocateResult.LockInfoList);
+                }
+            }
+
+            return (actualAllocated, pickedDetails, lockInfoList);
+        }
+
+        /// <summary>
+        /// 涓烘寚瀹氬簱瀛樼敓鎴愪换鍔★紙鍘熸湁閫昏緫涓嶅彉锛�
+        /// </summary>
+        private List<Dt_Task> GenerateTasksForSpecifiedStock(List<PickedStockDetailDTO> pickedDetails, string outboundTargetLocation)
+        {
+            List<Dt_Task> tasks = new List<Dt_Task>();
+            var palletCodes = pickedDetails.Select(x => x.PalletCode).Distinct().ToList();
+
+            foreach (var palletCode in palletCodes)
+            {
+                Dt_StockInfo stock = _stockInfoRepository.QueryFirst(x => x.PalletCode == palletCode);
+                if (stock == null) continue;
+
+                int taskNum = pickedDetails.First(x => x.PalletCode == palletCode)
+                    .OutStockLockInfos.FirstOrDefault()?.TaskNum ??
+                    Db.Ado.GetScalar($"SELECT NEXT VALUE FOR SeqTaskNum").ObjToInt();
+
+                Dt_Task task = GenerationOutTask(stock, TaskTypeEnum.Outbound, taskNum, outboundTargetLocation);
+                if (tasks.FirstOrDefault(x => x.PalletCode == palletCode) == null)
+                    tasks.Add(task);
+            }
+
+            return tasks;
+        }
+
+        /// <summary>
+        /// 鏋勫缓搴撳瓨鏌ヨ鏉′欢锛堝師鏈夐�昏緫涓嶅彉锛�
+        /// </summary>
+        private List<Dt_StockInfo> BuildStockQueryWithInfo(MaterielOutboundCalculationDTO materielCalc, string factoryArea)
+        {
+            ISugarQueryable<Dt_StockInfoDetail> stockDetails = _stockDetailRepository.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(x => x.MaterielCode == materielCalc.MaterielCode && x.StockQuantity > 0
+                && (x.Status == (int)StockStatusEmun.鍏ュ簱瀹屾垚 || x.Status == (int)StockStatusEmun.鎵嬪姩瑙i攣));
+
+            if (!string.IsNullOrEmpty(materielCalc.SupplyCode))
+                stockDetails = stockDetails.Where(x => x.SupplyCode == materielCalc.SupplyCode);
+            if (!string.IsNullOrEmpty(materielCalc.WarehouseCode))
+                stockDetails = stockDetails.Where(x => x.WarehouseCode == materielCalc.WarehouseCode);
+            if (!string.IsNullOrEmpty(factoryArea))
+                stockDetails = stockDetails.Where(x => x.FactoryArea == factoryArea);
+            if (!string.IsNullOrEmpty(materielCalc.BatchNo))
+                stockDetails = stockDetails.Where(x => x.BatchNo == materielCalc.BatchNo);
+
+            List<Dt_StockInfoDetail> stockDetailList = stockDetails.ToList();
+            List<string> locationCodes = _locationInfoRepository.QueryData(x =>
+                (x.LocationStatus == LocationStatusEnum.InStock.ObjToInt() || x.LocationStatus == LocationStatusEnum.Lock.ObjToInt())
+                && x.EnableStatus == EnableStatusEnum.Normal.ObjToInt()).Select(x => x.LocationCode).ToList();
+
+            List<int> stockIds = stockDetailList.GroupBy(x => x.StockId).Select(x => x.Key).ToList();
+            List<Dt_StockInfo> stockInfos = _stockInfoRepository.QueryData(x =>
+                stockIds.Contains(x.Id) && (x.StockStatus == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt())
+                && !string.IsNullOrEmpty(x.LocationCode) && locationCodes.Contains(x.LocationCode));
+
+            foreach (var stockInfo in stockInfos)
+            {
+                stockInfo.Details = stockDetailList.Where(x => x.StockId == stockInfo.Id).ToList();
+            }
+
+            return stockInfos;
+        }
+
+        /// <summary>
+        /// 鎵归噺鑾峰彇鎵樼洏鍙敤搴撳瓨淇℃伅锛堝師鏈夐�昏緫涓嶅彉锛�
+        /// </summary>
+        private (Dictionary<int, decimal> AvailableStockMap, Dictionary<int, List<Dt_OutStockLockInfo>> LockStockMap) GetBatchAvailableStockQuantities(
+            MaterielOutboundCalculationDTO materielCalc, List<Dt_StockInfo> stockInfos)
+        {
+            List<int> stockIds = stockInfos.Select(x => x.Id).ToList();
+            Dictionary<int, decimal> availableStockMap = new Dictionary<int, decimal>();
+            Dictionary<int, List<Dt_OutStockLockInfo>> lockStockMap = new Dictionary<int, List<Dt_OutStockLockInfo>>();
+
+            List<Dt_OutStockLockInfo> allocatedData = materielCalc.OutStockLockInfos
+                .Where(x => stockIds.Contains(x.StockId) && x.MaterielCode == materielCalc.MaterielCode).ToList();
+
+            foreach (var stockInfo in stockInfos)
+            {
+                decimal totalQuantity = stockInfo.Details.Sum(x => x.StockQuantity);
+                List<Dt_OutStockLockInfo> outStockLockInfos = allocatedData
+                    .Where(x => x.StockId == stockInfo.Id && x.MaterielCode == materielCalc.MaterielCode).ToList();
+                decimal allocatedQuantity = outStockLockInfos.Sum(x => x.AllocatedQuantity);
+
+                availableStockMap[stockInfo.Id] = Math.Max(0, totalQuantity - allocatedQuantity);
+                lockStockMap[stockInfo.Id] = outStockLockInfos;
+            }
+
+            return (availableStockMap, lockStockMap);
+        }
+
+        /// <summary>
+        /// 鍒嗛厤搴撳瓨锛堟牳蹇冧紭鍖栵細OriginalQuantity璧嬪�间负鎵樼洏鐗╂枡鎬诲簱瀛橈級
+        /// </summary>
+        private (decimal ActualAllocatedQuantity, List<Dt_OutStockLockInfo> LockInfoList) AllocateStockQuantity(
+            Dt_StockInfo stockInfo, decimal allocateQuantity, decimal availableQuantity,
+            Dt_OutboundOrder outboundOrder, Dt_OutboundOrderDetail detail,
+            PickingOutboundRequestDTO request, List<Dt_OutStockLockInfo> lockInfos,
+            Dictionary<int, List<Dt_StockInfoDetail>> stockDetailMap = null,
+            decimal palletMaterielTotalStock = 0 // 鏂板锛氭墭鐩樼墿鏂欐�诲簱瀛樺弬鏁�
+        )
+        {
+            decimal actualAllocatedQuantity = Math.Min(allocateQuantity, availableQuantity);
+            List<Dt_OutStockLockInfo> lockInfoList = new List<Dt_OutStockLockInfo>();
+
+            if (actualAllocatedQuantity > 0)
+            {
+                // 妫�鏌ョ洰鏍囦綅缃竴鑷存��
+                if (lockInfos.Any() && !string.IsNullOrEmpty(lockInfos.First().OutboundTargetLocation)
+                    && !string.Equals(lockInfos.First().OutboundTargetLocation, request.OutboundTargetLocation, StringComparison.OrdinalIgnoreCase))
+                {
+                    return (0, lockInfoList);
+                }
+
+                Dt_OutStockLockInfo? lockInfo = lockInfos.FirstOrDefault(x =>
+                    x.StockId == stockInfo.Id && x.Status == OutLockStockStatusEnum.宸插垎閰�.ObjToInt()
+                    && x.PalletCode == stockInfo.PalletCode && x.OrderNo == outboundOrder.OrderNo);
+
+                if (lockInfo != null)
+                {
+                    List<string> currentIds = lockInfo.OrderDetailIds?.Split(',').ToList() ?? new List<string>();
+                    if (!currentIds.Contains(detail.Id.ToString()))
+                    {
+                        currentIds.Add(detail.Id.ToString());
+                        lockInfo.OrderDetailIds = string.Join(",", currentIds);
+                    }
+
+                    decimal totalAllocatedQuantity = CalcTotalAllocatedQuantity(lockInfos, stockInfo.Id, detail.MaterielCode);
+                    lockInfo.AssignQuantity += actualAllocatedQuantity;
+                    lockInfo.AllocatedQuantity = totalAllocatedQuantity;
+                    if (palletMaterielTotalStock > 0)
+                        lockInfo.OriginalQuantity = palletMaterielTotalStock;
+                    lockInfoList.Add(lockInfo);
+                }
+                else
+                {
+                    decimal originalQuantity = palletMaterielTotalStock;
+
+                    List<string> allDetailIds = outboundOrder.Details.Where(x =>
+                        x.OrderId == outboundOrder.Id && x.MaterielCode == detail.MaterielCode
+                        && x.BatchNo == detail.BatchNo && x.SupplyCode == detail.SupplyCode
+                        && x.WarehouseCode == detail.WarehouseCode)
+                        .Select(x => x.Id.ToString()).ToList();
+
+                    decimal totalAllocatedQuantity = CalcTotalAllocatedQuantity(lockInfos, stockInfo.Id, detail.MaterielCode);
+
+                    lockInfo = new Dt_OutStockLockInfo
+                    {
+                        OrderNo = request.OrderNo,
+                        OrderDetailIds = string.Join(",", allDetailIds),
+                        OrderType = outboundOrder.OrderType,
+                        BatchNo = detail.BatchNo,
+                        MaterielCode = detail.MaterielCode,
+                        MaterielName = detail.MaterielName,
+                        StockId = stockInfo.Id,
+                        OrderQuantity = allDetailIds.Count > 1
+                            ? outboundOrder.Details.Where(x =>
+                                x.OrderId == outboundOrder.Id && x.MaterielCode == detail.MaterielCode
+                                && x.BatchNo == detail.BatchNo && x.SupplyCode == detail.SupplyCode
+                                && x.WarehouseCode == detail.WarehouseCode).Sum(x => x.OrderQuantity)
+                            : detail.OrderQuantity,
+                        OriginalQuantity = originalQuantity, // 鐜板湪璧嬪�间负鎵樼洏鐗╂枡鎬诲簱瀛�
+                        AssignQuantity = actualAllocatedQuantity,
+                        AllocatedQuantity = totalAllocatedQuantity,
+                        LocationCode = stockInfo.LocationCode,
+                        PalletCode = stockInfo.PalletCode,
+                        Unit = detail.Unit,
+                        OutboundTargetLocation = request.OutboundTargetLocation,
+                        Status = OutLockStockStatusEnum.宸插垎閰�.ObjToInt(),
+                        SupplyCode = detail.SupplyCode,
+                        WarehouseCode = detail.WarehouseCode,
+                        FactoryArea = outboundOrder.FactoryArea,
+                        TaskNum = Db.Ado.GetScalar($"SELECT NEXT VALUE FOR SeqTaskNum").ObjToInt(),
+                        OrderDetailId = 0
+                    };
+                    lockInfoList.Add(lockInfo);
+                }
+            }
+
+            return (actualAllocatedQuantity, lockInfoList);
+        }
+
+        /// <summary>
+        /// 璁$畻璇ユ墭鐩樼疮璁″凡鍒嗛厤鏁伴噺锛堝師鏈夐�昏緫涓嶅彉锛�
+        /// </summary>
+        private decimal CalcTotalAllocatedQuantity(List<Dt_OutStockLockInfo> lockInfos, int stockId, string materielCode)
+        {
+            List<Dt_OutStockLockInfo> lockRecords = _outboundLockInfoRepository.QueryData(x =>
+                x.StockId == stockId && x.MaterielCode == materielCode);
+
+            return lockRecords?.Sum(x => x.AssignQuantity) ?? 0;
+        }
+
+        /// <summary>
+        /// 鐢熸垚鍑哄簱浠诲姟锛堝師鏈夐�昏緫涓嶅彉锛�
+        /// </summary>
         public Dt_Task GenerationOutTask(Dt_StockInfo stockInfo, TaskTypeEnum taskType, int taskNum, string outStation)
         {
-
-            Dt_Task task = new()
+            return new Dt_Task
             {
                 CurrentAddress = stockInfo.LocationCode,
                 Grade = 0,
@@ -536,241 +963,18 @@
                 PalletType = stockInfo.PalletType,
                 WarehouseId = stockInfo.WarehouseId,
             };
-
-            return task;
         }
-
-        /// <summary>
-        /// 鏋勫缓搴撳瓨鏌ヨ鏉′欢锛堝寘鍚簱瀛樹俊鎭拰搴撳瓨鏄庣粏锛�
-        /// </summary>
-        /// <param name="materielCalc"></param>
-        /// <param name="factoryArea"></param>
-        /// <returns></returns>
-        private List<Dt_StockInfo> BuildStockQueryWithInfo(MaterielOutboundCalculationDTO materielCalc, string factoryArea)
-        {
-            // 鍩虹鏌ヨ鏉′欢锛氱墿鏂欑紪鍙枫�佹壒娆″彿锛堝鏋滄彁渚涳級銆佸簱瀛樻暟閲�>0
-            ISugarQueryable<Dt_StockInfoDetail> stockDetails = _stockDetailRepository.Db.Queryable<Dt_StockInfoDetail>().Where(x => x.MaterielCode == materielCalc.MaterielCode && x.StockQuantity > 0);
-
-            // 鏍规嵁鏉′欢娣诲姞渚涘簲鍟嗙紪鍙峰尮閰嶏紙涓嶄负绌烘椂鎵嶉渶瑕佸尮閰嶏級
-            if (!string.IsNullOrEmpty(materielCalc.SupplyCode))
-            {
-                stockDetails = stockDetails.Where(x => x.SupplyCode == materielCalc.SupplyCode);
-            }
-
-            // 鏍规嵁鏉′欢娣诲姞浠撳簱缂栧彿鍖归厤锛堜笉涓虹┖鏃舵墠闇�瑕佸尮閰嶏級
-            if (!string.IsNullOrEmpty(materielCalc.WarehouseCode))
-            {
-                stockDetails = stockDetails.Where(x => x.WarehouseCode == materielCalc.WarehouseCode);
-            }
-
-            // 鏍规嵁鏉′欢娣诲姞鍘傚尯鍖归厤锛堜笉涓虹┖鏃舵墠闇�瑕佸尮閰嶏級
-            if (!string.IsNullOrEmpty(factoryArea))
-            {
-                stockDetails = stockDetails.Where(x => x.FactoryArea == factoryArea);
-            }
-
-            // 鏍规嵁鎵规鍙疯繘琛岃繃婊わ紙濡傛灉鎻愪緵锛�
-            if (!string.IsNullOrEmpty(materielCalc.BatchNo))
-            {
-                stockDetails = stockDetails.Where(x => x.BatchNo == materielCalc.BatchNo);
-            }
-
-            List<Dt_StockInfoDetail> stockDetailList = stockDetails.ToList();
-
-            // 鑾峰彇鍙敤璐т綅缂栧彿
-            List<string> locationCodes = _locationInfoRepository.QueryData(x => (x.LocationStatus == LocationStatusEnum.InStock.ObjToInt() /*|| x.LocationStatus == LocationStatusEnum.Lock.ObjToInt()*/) && x.EnableStatus == EnableStatusEnum.Normal.ObjToInt()).Select(x => x.LocationCode).ToList();
-
-            // 鑾峰彇鎵�鏈夌浉鍏崇殑搴撳瓨淇℃伅
-            List<int> stockIds = stockDetailList.GroupBy(x => x.StockId).Select(x => x.Key).ToList();
-            List<Dt_StockInfo> stockInfos = _stockInfoRepository.QueryData(x => stockIds.Contains(x.Id) && (x.StockStatus == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt() /*|| x.StockStatus == StockStatusEmun.鍑哄簱閿佸畾.ObjToInt()*/) && !string.IsNullOrEmpty(x.LocationCode) && locationCodes.Contains(x.LocationCode));
-
-            // 鍦ㄥ唴瀛樹腑鍏宠仈鏁版嵁
-            foreach (var stockInfo in stockInfos)
-            {
-                stockInfo.Details = new List<Dt_StockInfoDetail>();
-                stockInfo.Details = stockDetailList.Where(x => x.StockId == stockInfo.Id).ToList();
-            }
-
-            return stockInfos;
-        }
-
-        /// <summary>
-        /// 鎵归噺鑾峰彇鎵樼洏鍙敤搴撳瓨淇℃伅
-        /// </summary>
-        /// <param name="stockInfos">搴撳瓨淇℃伅鍒楄〃</param>
-        /// <param name="materielCode">鐗╂枡缂栧彿</param>
-        /// <returns>杩斿洖鍊间负(搴撳瓨涓婚敭锛屽彲鐢ㄦ暟閲�)瀛楀吀</returns>
-        private (Dictionary<int, decimal> AvailableStockMap, Dictionary<int, List<Dt_OutStockLockInfo>> LockStockMap) GetBatchAvailableStockQuantities(MaterielOutboundCalculationDTO materielCalc, List<Dt_StockInfo> stockInfos)
-        {
-            List<int> stockIds = stockInfos.Select(x => x.Id).ToList();
-
-            Dictionary<int, decimal> availableStockMap = new Dictionary<int, decimal>(); // 鍙敤搴撳瓨鏁伴噺
-            Dictionary<int, List<Dt_OutStockLockInfo>> lockStockMap = new Dictionary<int, List<Dt_OutStockLockInfo>>(); // 宸查攣瀹氬簱瀛樻暟閲�
-
-            // 鎵归噺鏌ヨ宸插垎閰嶆暟閲�
-            List<Dt_OutStockLockInfo> allocatedData = materielCalc.OutStockLockInfos.Where(x => stockIds.Contains(x.StockId) && x.MaterielCode == materielCalc.MaterielCode).ToList();
-
-            foreach (var stockInfo in stockInfos)
-            {
-                // 璁$畻鎬诲簱瀛樻暟閲�
-                decimal totalQuantity = stockInfo.Details.Sum(x => x.StockQuantity);
-
-                List<Dt_OutStockLockInfo> outStockLockInfos = allocatedData.Where(x => x.StockId == stockInfo.Id && x.MaterielCode == materielCalc.MaterielCode).ToList();
-
-                // 璁$畻宸插垎閰嶆暟閲�
-                decimal allocatedQuantity = outStockLockInfos.Sum(x => x.AllocatedQuantity);
-                availableStockMap[stockInfo.Id] = Math.Max(0, totalQuantity - allocatedQuantity);
-
-                lockStockMap[stockInfo.Id] = outStockLockInfos;
-            }
-
-            return (availableStockMap, lockStockMap);
-        }
-
-        /// <summary>
-        /// 鍒嗛厤搴撳瓨
-        /// </summary>
-        /// <param name="stockInfo">搴撳瓨淇℃伅</param>
-        /// <param name="allocateQuantity">瑕佸垎閰嶇殑鏁伴噺</param>
-        /// <param name="availableQuantity">鍙垎閰嶇殑鏁伴噺</param>
-        /// <param name="outboundOrder">鍑哄簱鍗�</param>
-        /// <param name="detail">鍑哄簱鍗曟槑缁�</param>
-        /// <param name="request"></param>
-        /// <param name="lockInfos"></param>
-        /// <param name="stockDetailMap"></param>
-        /// <returns></returns>
-        private (decimal ActualAllocatedQuantity, List<Dt_OutStockLockInfo> LockInfoList) AllocateStockQuantity(Dt_StockInfo stockInfo, decimal allocateQuantity, decimal availableQuantity, Dt_OutboundOrder outboundOrder, Dt_OutboundOrderDetail detail, PickingOutboundRequestDTO request, List<Dt_OutStockLockInfo> lockInfos, Dictionary<int, List<Dt_StockInfoDetail>> stockDetailMap = null)
-        {
-            decimal actualAllocatedQuantity = Math.Min(allocateQuantity, availableQuantity); // 瀹為檯鍒嗛厤鏁伴噺
-            List<Dt_OutStockLockInfo> lockInfoList = new List<Dt_OutStockLockInfo>();
-            if (actualAllocatedQuantity > 0)
-            {
-                //妫�鏌ョ洰鏍囦綅缃竴鑷存�э細濡傛灉鎵樼洏宸叉湁閿佸畾璁板綍涓旂洰鏍囦綅缃笉鍚岋紝鍒欎笉鍏佽鍒嗛厤
-                if (lockInfos.Any() && !string.IsNullOrEmpty(lockInfos.First().OutboundTargetLocation))
-                {
-                    if (!string.Equals(lockInfos.First().OutboundTargetLocation, request.OutboundTargetLocation, StringComparison.OrdinalIgnoreCase))
-                    {
-                        // 鎵樼洏鐨勭洰鏍囦綅缃笌鏂拌姹傜殑鐩爣浣嶇疆涓嶅悓锛屼笉鍏佽浣跨敤璇ユ墭鐩�
-                        return (0, lockInfoList);
-                    }
-                }
-
-                Dt_OutStockLockInfo? lockInfo = lockInfos.FirstOrDefault(x => x.StockId == stockInfo.Id && x.Status == OutLockStockStatusEnum.宸插垎閰�.ObjToInt() && x.PalletCode == stockInfo.PalletCode && x.OrderNo == outboundOrder.OrderNo);
-
-                if (lockInfo != null)
-                {
-                    // 杩藉姞褰撳墠鏄庣粏ID鍒癘rderDetailIds瀛楁锛堥伩鍏嶉噸澶嶏級
-                    List<string> currentIds = lockInfo.OrderDetailIds?.Split(',').ToList() ?? new List<string>();
-                    if (!currentIds.Contains(detail.Id.ToString()))
-                    {
-                        currentIds.Add(detail.Id.ToString());
-                        lockInfo.OrderDetailIds = string.Join(",", currentIds);
-                    }
-
-                    // 璁$畻璇ユ墭鐩樿鐗╂枡鐨勬�荤疮璁″凡鍑哄簱鏁伴噺锛堣法鎵�鏈夊崟鎹級
-                    decimal totalAllocatedQuantity = CalcTotalAllocatedQuantity(lockInfos, stockInfo.Id, detail.MaterielCode);
-
-                    // 鏇存柊鍒嗛厤鍑哄簱閲�
-                    decimal beforeAssignQuantity = totalAllocatedQuantity; // 鏈鍒嗛厤鍓嶇殑鎬荤疮璁¢噺
-                    lockInfo.AssignQuantity += actualAllocatedQuantity; // 鏈鍒嗛厤鏁伴噺
-                    lockInfo.AllocatedQuantity = beforeAssignQuantity; // 璁板綍鏈鍒嗛厤鍓嶇殑鎬荤疮璁¢噺
-
-                    lockInfoList.Add(lockInfo);
-                }
-                else
-                {
-                    // 鍒涘缓鏂扮殑閿佸畾璁板綍锛堜娇鐢ㄩ鍔犺浇鐨勫簱瀛樻槑缁嗭級
-                    decimal originalQuantity = 0;
-                    if (stockDetailMap?.ContainsKey(stockInfo.Id) == true)
-                    {
-                        originalQuantity = stockDetailMap[stockInfo.Id].Sum(x => x.StockQuantity);
-                    }
-
-                    // 鑾峰彇璇ョ墿鏂欏湪璇ヨ鍗曚腑鐨勬墍鏈夋槑缁咺D
-                    List<string> allDetailIds = (outboundOrder.Details.Where(x =>
-                        x.OrderId == outboundOrder.Id &&
-                        x.MaterielCode == detail.MaterielCode &&
-                        x.BatchNo == detail.BatchNo &&
-                        x.SupplyCode == detail.SupplyCode &&
-                        x.WarehouseCode == detail.WarehouseCode))
-                        .Select(x => x.Id.ToString())
-                        .ToList();
-
-                    // 璁$畻璇ユ墭鐩樿鐗╂枡鐨勬�荤疮璁″凡鍑哄簱鏁伴噺锛堣法鎵�鏈夊崟鎹級
-                    decimal totalAllocatedQuantity = CalcTotalAllocatedQuantity(lockInfos, stockInfo.Id, detail.MaterielCode);
-
-                    lockInfo = new Dt_OutStockLockInfo
-                    {
-                        OrderNo = request.OrderNo,
-                        OrderDetailIds = string.Join(",", allDetailIds), // 璁板綍璇ョ墿鏂欑殑鎵�鏈夋槑缁咺D
-                        OrderType = outboundOrder.OrderType,
-                        BatchNo = detail.BatchNo,
-                        MaterielCode = detail.MaterielCode,
-                        MaterielName = detail.MaterielName,
-                        StockId = stockInfo.Id,
-                        OrderQuantity = allDetailIds.SelectMany(id => allDetailIds).Count() > 1
-                            ? (outboundOrder.Details.Where(x =>
-                                x.OrderId == outboundOrder.Id &&
-                                x.MaterielCode == detail.MaterielCode &&
-                                x.BatchNo == detail.BatchNo &&
-                                x.SupplyCode == detail.SupplyCode &&
-                                x.WarehouseCode == detail.WarehouseCode))
-                                .Sum(x => x.OrderQuantity)
-                            : detail.OrderQuantity, // 濡傛灉鍙湁涓�涓槑缁嗭紝浣跨敤鏄庣粏鏁伴噺
-                        OriginalQuantity = originalQuantity,
-                        AssignQuantity = actualAllocatedQuantity, // 鏈鍒嗛厤鏁伴噺
-                        AllocatedQuantity = totalAllocatedQuantity, // 鏈鍒嗛厤鍓嶇殑鎬荤疮璁″凡鍑哄簱鏁伴噺锛堣法鎵�鏈夊崟鎹級
-                        LocationCode = stockInfo.LocationCode,
-                        PalletCode = stockInfo.PalletCode,
-                        Unit = detail.Unit,
-                        OutboundTargetLocation = request.OutboundTargetLocation,
-                        Status = OutLockStockStatusEnum.宸插垎閰�.ObjToInt(),
-                        SupplyCode = detail.SupplyCode,
-                        WarehouseCode = detail.WarehouseCode,
-                        FactoryArea = outboundOrder.FactoryArea,
-                        TaskNum = Db.Ado.GetScalar($"SELECT NEXT VALUE FOR SeqTaskNum").ObjToInt(),
-                        OrderDetailId = 0 // 鏈叧鑱斿叿浣撴槑缁咺D
-                    };
-                    lockInfoList.Add(lockInfo);
-                }
-            }
-            return (actualAllocatedQuantity, lockInfoList);
-        }
-
-        /// <summary>
-        /// 璁$畻璇ユ墭鐩樼疮璁″凡鍒嗛厤鏁伴噺
-        /// </summary>
-        /// <param name="lockInfos"></param>
-        /// <param name="stockId"></param>
-        /// <param name="materielCode"></param>
-        /// <returns></returns>
-        private decimal CalcTotalAllocatedQuantity(List<Dt_OutStockLockInfo> lockInfos, int stockId, string materielCode)
-        {
-            // 鏌ヨ璇ユ墭鐩樿鐗╂枡鍦ㄦ墍鏈夐攣瀹氳褰曚腑鐨勬渶澶у凡鍒嗛厤鏁伴噺
-            List<Dt_OutStockLockInfo> lockRecords = _outboundLockInfoRepository.QueryData(x =>
-                x.StockId == stockId &&
-                x.MaterielCode == materielCode);
-
-            if (lockRecords == null || !lockRecords.Any())
-            {
-                return 0;
-            }
-
-            // 杩斿洖绱宸插垎閰嶆暟閲�
-            return lockRecords.Sum(x => x.AssignQuantity);
-        }
-
-        /// <summary>
-        /// 鏇存柊鍑哄簱鍗曠姸鎬�
-        /// </summary>
         public bool UpdateOutboundOrderStatus(string orderNo, int status)
         {
             try
             {
                 Dt_OutboundOrder outboundOrder = _outboundRepository.QueryFirst(x => x.OrderNo == orderNo);
                 if (outboundOrder == null) return false;
-
                 outboundOrder.OrderStatus = status;
+                if(outboundOrder.CreateType == OrderCreateTypeEnum.CreateInSystem.ObjToInt())
+                {
+                    outboundOrder.ReturnToMESStatus = 5;
+                }
                 _outboundRepository.UpdateData(outboundOrder);
                 return true;
             }
@@ -780,22 +984,12 @@
             }
         }
 
-        /// <summary>
-        /// 
-        /// </summary>
-        /// <param name="palletCodes"></param>
-        /// <param name="status"></param>
-        /// <returns></returns>
         public bool UpdateStockStatus(List<string> palletCodes, int status)
         {
             try
             {
                 List<Dt_StockInfo> stockInfos = _stockInfoRepository.QueryData(x => palletCodes.Contains(x.PalletCode));
-                stockInfos.ForEach(stockInfo =>
-                {
-                    stockInfo.StockStatus = status;
-                });
-
+                stockInfos.ForEach(stockInfo => stockInfo.StockStatus = status);
                 _stockInfoRepository.UpdateData(stockInfos);
                 return true;
             }
@@ -805,22 +999,12 @@
             }
         }
 
-        /// <summary>
-        /// 
-        /// </summary>
-        /// <param name="locationCodes"></param>
-        /// <param name="status"></param>
-        /// <returns></returns>
         public bool UpdateLocationStatus(List<string> locationCodes, int status)
         {
             try
             {
                 List<Dt_LocationInfo> locationInfos = _locationInfoRepository.QueryData(x => locationCodes.Contains(x.LocationCode));
-                locationInfos.ForEach(x =>
-                {
-                    x.LocationStatus = status;
-                });
-
+                locationInfos.ForEach(x => x.LocationStatus = status);
                 _locationInfoRepository.UpdateData(locationInfos);
                 return true;
             }
@@ -830,21 +1014,14 @@
             }
         }
 
-        /// <summary>
-        /// 
-        /// </summary>
-        /// <param name="outStockLockInfos"></param>
-        /// <returns></returns>
         public bool UpdateOutStockLockInfo(List<Dt_OutStockLockInfo> outStockLockInfos)
         {
             try
             {
                 List<Dt_OutStockLockInfo> updateData = outStockLockInfos.Where(x => x.Id > 0).ToList();
                 _outboundLockInfoRepository.UpdateData(updateData);
-
                 List<Dt_OutStockLockInfo> addData = outStockLockInfos.Where(x => x.Id <= 0).ToList();
                 _outboundLockInfoRepository.AddData(addData);
-
                 return true;
             }
             catch
@@ -878,22 +1055,6 @@
                     return WebResponseContent.Instance.Error(response.Message);
                 }
 
-                bool isMatMixed = stockInfo.Details.GroupBy(x => new
-                {
-                    x.MaterielCode,
-                    x.MaterielName,
-                    x.BatchNo,
-                    x.SupplyCode,
-                    x.WarehouseCode
-                }).Count() > 1;
-
-                if (isMatMixed)
-                {
-                    response.Success = false;
-                    response.Message = $"娣锋枡鎵樼洏 {request.PalletCode} 涓嶈兘鏁寸鍑哄簱";
-                    return WebResponseContent.Instance.Error(response.Message);
-                }
-
                 // 2. 鏌ユ壘鍑哄簱鍗曚俊鎭�
                 Dt_OutboundOrder outboundOrder = _outboundRepository.QueryFirst(o => o.OrderNo == request.OrderNo);
                 if (outboundOrder == null)
@@ -916,6 +1077,67 @@
                 {
                     response.Success = false;
                     response.Message = $"璇ュ簱瀛樻病鏈夊垎閰嶅嚭搴撻噺锛屾墭鐩樺彿锛歿request.PalletCode}";
+                    return WebResponseContent.Instance.Error(response.Message);
+                }
+
+                //bool isMatMixed = stockInfo.Details.GroupBy(x => new
+                //{
+                //    x.MaterielCode,
+                //    x.MaterielName,
+                //    x.BatchNo,
+                //    x.SupplyCode,
+                //    x.WarehouseCode
+                //}).Count() > 1;
+                bool isMatMixed = false;
+
+                bool includeBatchNo = !string.IsNullOrEmpty(lockInfo.BatchNo);
+                bool includeSupplyCode = !string.IsNullOrEmpty(lockInfo.SupplyCode);
+
+                if (includeBatchNo && includeSupplyCode)
+                {
+                    isMatMixed = stockInfo.Details.GroupBy(x => new
+                    {
+                        x.MaterielCode,
+                        x.MaterielName,
+                        x.BatchNo,
+                        x.SupplyCode,
+                        x.WarehouseCode
+                    }).Count() > 1;
+                }
+                else if (includeBatchNo && !includeSupplyCode)
+                {
+                    isMatMixed = stockInfo.Details.GroupBy(x => new
+                    {
+                        x.MaterielCode,
+                        x.MaterielName,
+                        x.BatchNo,
+                        x.WarehouseCode
+                    }).Count() > 1;
+                }
+                else if (!includeBatchNo && includeSupplyCode)
+                {
+                    isMatMixed = stockInfo.Details.GroupBy(x => new
+                    {
+                        x.MaterielCode,
+                        x.MaterielName,
+                        x.SupplyCode,
+                        x.WarehouseCode
+                    }).Count() > 1;
+                }
+                else
+                {
+                    isMatMixed = stockInfo.Details.GroupBy(x => new
+                    {
+                        x.MaterielCode,
+                        x.MaterielName,
+                        x.WarehouseCode
+                    }).Count() > 1;
+                }
+
+                if (isMatMixed)
+                {
+                    response.Success = false;
+                    response.Message = $"娣锋枡鎵樼洏 {request.PalletCode} 涓嶈兘鏁寸鍑哄簱";
                     return WebResponseContent.Instance.Error(response.Message);
                 }
 
@@ -968,7 +1190,7 @@
                     // 鏁寸鍑哄簱鏃犻渶鎷嗗寘
                     PerformFullOutboundOperation(stockInfo, request, lockInfo.TaskNum.GetValueOrDefault());
 
-                    if (outboundOrder.OrderType != 0)
+                    if (outboundOrder.OrderType == InOrderTypeEnum.InternalAllocat.ObjToInt())
                     {
                         Dt_AllocateOrder allocateOrder = _allocateOrderRepository.QueryFirst(x => x.OrderNo == outboundOrder.OrderNo);
                         if (allocateOrder != null)
@@ -995,6 +1217,29 @@
                             _allocateMaterialInfoRepository.AddData(allocateMaterialInfos);
                         }
                     }
+                    else if(outboundOrder.OrderType == InOrderTypeEnum.ReCheck.ObjToInt())
+                    {
+                        List<Dt_AllocateMaterialInfo> allocateMaterialInfos = new List<Dt_AllocateMaterialInfo>();
+                        foreach (var item in stockInfo.Details)
+                        {
+                            Dt_AllocateMaterialInfo allocateMaterialInfo = new Dt_AllocateMaterialInfo()
+                            {
+                                Barcode = item.Barcode??"",
+                                BatchNo = item.BatchNo,
+                                FactoryArea = item.FactoryArea,
+                                MaterialCode = item.MaterielCode,
+                                MaterialName = item.MaterielName,
+                                OrderId = outboundOrder.Id,
+                                OrderNo = outboundOrder.OrderNo,
+                                Quantity = item.StockQuantity,
+                                SupplyCode = item.SupplyCode??"",
+                                Unit = item.Unit,
+                                WarehouseCode = item.WarehouseCode??""
+                            };
+                            allocateMaterialInfos.Add(allocateMaterialInfo);
+                        }
+                        _allocateMaterialInfoRepository.AddData(allocateMaterialInfos);
+                    }
 
                     decimal allocatedQuantity = actualOutboundQuantity;
                     List<Dt_OutboundOrderDetail> updateDetails = new();
@@ -1015,34 +1260,47 @@
                         //}
                         List<Barcodes> barcodesList = new List<Barcodes>();
                         List<Dt_StockInfoDetail> stockInfoDetails = stockInfo.Details.Where((x => x.StockQuantity > x.OutboundQuantity)).ToList();
+
+                        decimal itemQuantity = item.LockQuantity - item.OverOutQuantity;
+                        decimal unitbarcodeQuantity;
                         foreach (var stockDetail in stockInfoDetails)
                         {
-                            if (item.LockQuantity - item.OverOutQuantity >= stockDetail.StockQuantity - stockInfoDetail.OutboundQuantity)
+                            
+
+                            if (itemQuantity >= stockDetail.StockQuantity - stockDetail.OutboundQuantity)
                             {
+                                unitbarcodeQuantity = stockDetail.StockQuantity - stockDetail.OutboundQuantity;
+                                UnitConvertResultDTO currentResult = _basicService.UnitQuantityConvert(item.MaterielCode, item.Unit, item.BarcodeUnit, unitbarcodeQuantity);
+
                                 Barcodes barcodes = new Barcodes
                                 {
                                     Barcode = stockDetail.Barcode,
-                                    Qty = stockDetail.StockQuantity - stockInfoDetail.OutboundQuantity,
+                                    Qty = currentResult.ToQuantity,
                                     SupplyCode = stockDetail?.SupplyCode ?? "",
                                     BatchNo = stockDetail?.BatchNo ?? "",
-                                    Unit = stockDetail?.Unit ?? ""
+                                    Unit = currentResult.ToUnit ?? ""
                                 };
 
-                                stockDetail.StockQuantity = stockInfoDetail.OutboundQuantity;
+                                itemQuantity -= (stockDetail.StockQuantity - stockDetail.OutboundQuantity);
+                                stockDetail.OutboundQuantity = stockDetail.StockQuantity;
                                 barcodesList.Add(barcodes);
+
+                                if (itemQuantity <= 0) break;
                             }
                             else
                             {
+                                UnitConvertResultDTO currentResult = _basicService.UnitQuantityConvert(item.MaterielCode, item.Unit, item.BarcodeUnit, itemQuantity);
                                 Barcodes barcodes = new Barcodes
                                 {
                                     Barcode = stockDetail.Barcode,
-                                    Qty = item.LockQuantity - item.OverOutQuantity,
+                                    Qty = currentResult.ToQuantity,
                                     SupplyCode = stockDetail?.SupplyCode ?? "",
                                     BatchNo = stockDetail?.BatchNo ?? "",
-                                    Unit = stockDetail?.Unit ?? ""
+                                    Unit = currentResult.ToUnit ?? ""
                                 };
-                                stockInfoDetail.OutboundQuantity += item.LockQuantity - item.OverOutQuantity;
+                                stockDetail.OutboundQuantity += itemQuantity;
                                 barcodesList.Add(barcodes);
+                                break;
                             }
                         }
 
@@ -1058,8 +1316,15 @@
                         {
                             barcodeQuantity = item.LockQuantity - item.OverOutQuantity;
                             allocatedQuantity -= (item.LockQuantity - item.OverOutQuantity);
+                            if(item.ReturnToMESStatus == 0)
+                            {
+                                item.CurrentDeliveryQty = item.LockQuantity;
+                            }
+                            else
+                            {
+                                item.CurrentDeliveryQty += item.LockQuantity - item.OverOutQuantity;
+                            }
                             item.OverOutQuantity = item.LockQuantity;
-                            item.CurrentDeliveryQty = item.LockQuantity;
                         }
 
                         updateDetails.Add(item);
@@ -1075,6 +1340,11 @@
                             ContractResolver = new CamelCasePropertyNamesContractResolver()
                         };
                         item.ReturnJsonData = JsonConvert.SerializeObject(barcodesList, settings);
+                        //閲嶆嫞鍑哄簱涓嶉渶瑕佸洖浼�
+                        if (outboundOrder.OrderType == InOrderTypeEnum.ReCheck.ObjToInt())
+                        {
+                            item.ReturnJsonData = "";
+                        }
                     }
 
                     lockInfo.SortedQuantity = lockInfo.SortedQuantity + actualOutboundQuantity;
@@ -1102,12 +1372,38 @@
                     response.Message = "鍑哄簱瀹屾垚";
                     response.UpdatedDetails = updateDetails;
 
+                    if (CheckOutboundOrderDetailCompletedByMatCode(request.OrderNo, lockInfo.MaterielCode, outboundOrderDetails))
+                    {
+                        Func<Dt_OutStockLockInfo, bool> supWhere = x => string.IsNullOrEmpty(outboundOrderDetails.First().SupplyCode) ? true : x.SupplyCode == outboundOrderDetails.First().SupplyCode;
+
+                        Func<Dt_OutStockLockInfo, bool> wareWhere = x => string.IsNullOrEmpty(outboundOrderDetails.First().WarehouseCode) ? true : x.WarehouseCode == outboundOrderDetails.First().WarehouseCode;
+
+                        var stockLockInfos = _outboundLockInfoRepository.QueryData(x =>
+                            x.OrderDetailIds == lockInfo.OrderDetailIds &&
+                            x.OrderNo == request.OrderNo &&
+                            x.MaterielCode == stockInfoDetail.MaterielCode)
+                            .Where(supWhere)
+                            .Where(wareWhere)
+                            .ToList();
+                        if (stockLockInfos != null && stockLockInfos.Any())
+                        {
+                            _outboundLockInfoRepository.DeleteAndMoveIntoHty(stockLockInfos, WIDESEA_Core.Enums.OperateTypeEnum.鑷姩鍒犻櫎);
+                        }
+
+                        outboundOrderDetails.FirstOrDefault().OrderDetailStatus = (int)OrderDetailStatusEnum.Over;
+                        _detailRepository.UpdateData(outboundOrderDetails);
+                    }
+
                     // 妫�鏌ュ嚭搴撳崟鏄惁瀹屾垚
                     if (CheckOutboundOrderCompleted(request.OrderNo))
                     {
                         UpdateOutboundOrderStatus(request.OrderNo, OutOrderStatusEnum.鍑哄簱瀹屾垚.ObjToInt());
 
-                        _feedbackMesService.OutboundFeedback(outboundOrder.OrderNo);
+                        if (outboundOrder.OrderType != OutOrderTypeEnum.InternalAllocat.ObjToInt()&& outboundOrder.OrderType!= InOrderTypeEnum.ReCheck.ObjToInt())
+                        {
+                            _feedbackMesService.OutboundFeedback(outboundOrder.OrderNo);
+                        }
+
                     }
                 }
                 catch (Exception ex)
@@ -1203,9 +1499,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 鎷i��
@@ -1332,7 +1634,7 @@
 
                         MaterialCodeReturnDTO returnDTO = returnDTOs.First(x => x.Barcode == newBarcode);
 
-                        if (outboundOrder.OrderType != 0)
+                        if (outboundOrder.OrderType == InOrderTypeEnum.ReCheck.ObjToInt()||outboundOrder.OrderType == InOrderTypeEnum.InternalAllocat.ObjToInt())
                         {
                             allocateMaterialInfo = new Dt_AllocateMaterialInfo()
                             {
@@ -1354,7 +1656,7 @@
                     {
                         PerformFullOutboundOperation(stockDetail, stockInfo, actualOutboundQuantity, request, beforeQuantity, lockInfo.TaskNum.GetValueOrDefault());
 
-                        if (outboundOrder.OrderType != 0)
+                        if (outboundOrder.OrderType == InOrderTypeEnum.ReCheck.ObjToInt() || outboundOrder.OrderType == InOrderTypeEnum.InternalAllocat.ObjToInt())
                         {
                             allocateMaterialInfo = new Dt_AllocateMaterialInfo()
                             {
@@ -1373,8 +1675,8 @@
 
                     }
 
-                    // 鍒ゆ柇鏄惁鏄皟鎷ㄥ崟
-                    if (outboundOrder.OrderType != 0)
+                    // 鍒ゆ柇鏄惁鏄櫤浠撹皟鏅轰粨鍗�
+                    if ( outboundOrder.OrderType == InOrderTypeEnum.InternalAllocat.ObjToInt())
                     {
                         Dt_AllocateOrder allocateOrder = _allocateOrderRepository.QueryFirst(x => x.OrderNo == outboundOrder.OrderNo);
                         if (allocateOrder != null)
@@ -1390,7 +1692,6 @@
                     foreach (var item in outboundOrderDetails)
                     {
                         if (allocatedQuantity <= 0) break;
-
 
                         //if (item.OrderQuantity - item.MoveQty - item.OverOutQuantity >= allocatedQuantity)
                         //{
@@ -1415,20 +1716,33 @@
                         {
                             barcodeQuantity = item.LockQuantity - item.OverOutQuantity;
                             allocatedQuantity -= (item.LockQuantity - item.OverOutQuantity);
+                            if (item.ReturnToMESStatus == 0)
+                            {
+                                item.CurrentDeliveryQty = item.LockQuantity;
+                            }
+                            else
+                            {
+                                item.CurrentDeliveryQty += item.LockQuantity - item.OverOutQuantity;
+                            }
                             item.OverOutQuantity = item.LockQuantity;
-                            item.CurrentDeliveryQty = item.LockQuantity;
                         }
 
+                        if (item.OverOutQuantity == item.OrderQuantity)
+                        {
+                            item.OrderDetailStatus = (int)OrderDetailStatusEnum.Over;
+                        }
                         updateDetails.Add(item);
 
                         List<Barcodes> barcodesList = new List<Barcodes>();
+                        UnitConvertResultDTO currentResult = _basicService.UnitQuantityConvert(item.MaterielCode, item.Unit, item.BarcodeUnit, barcodeQuantity);
+
                         Barcodes barcodes = new Barcodes
                         {
-                            Barcode = request.Barcode,
-                            Qty = barcodeQuantity,
+                            Barcode = isUnpacked ? newBarcode : stockDetail?.Barcode,
+                            Qty = currentResult.ToQuantity,
                             SupplyCode = stockDetail?.SupplyCode ?? "",
                             BatchNo = stockDetail?.BatchNo ?? "",
-                            Unit = stockDetail?.Unit ?? ""
+                            Unit = currentResult.ToUnit ?? ""
                         };
                         if (!string.IsNullOrEmpty(item.ReturnJsonData))
                         {
@@ -1444,7 +1758,7 @@
 
                     lockInfo.SortedQuantity = lockInfo.SortedQuantity + actualOutboundQuantity;
 
-                    if (lockInfo.SortedQuantity == lockInfo.AssignQuantity)
+                    if (lockInfo.SortedQuantity >= lockInfo.AssignQuantity)
                     {
                         _outboundLockInfoRepository.DeleteAndMoveIntoHty(lockInfo, WIDESEA_Core.Enums.OperateTypeEnum.鑷姩瀹屾垚);
                     }
@@ -1490,12 +1804,38 @@
                         _feedbackMesService.BarcodeFeedback(newBarcode);
                     }
 
+                    if (CheckOutboundOrderDetailCompletedByMatCode(request.OrderNo, lockInfo.MaterielCode, outboundOrderDetails))
+                    {
+                        Func<Dt_OutStockLockInfo, bool> supWhere = x => string.IsNullOrEmpty(outboundOrderDetails.First().SupplyCode) ? true : x.SupplyCode == outboundOrderDetails.First().SupplyCode;
+
+                        Func<Dt_OutStockLockInfo, bool> wareWhere = x => string.IsNullOrEmpty(outboundOrderDetails.First().WarehouseCode) ? true : x.WarehouseCode == outboundOrderDetails.First().WarehouseCode;
+
+                        var stockLockInfos = _outboundLockInfoRepository.QueryData(x =>
+                            x.OrderDetailIds == lockInfo.OrderDetailIds &&
+                            x.OrderNo == request.OrderNo &&
+                            x.MaterielCode == stockDetail.MaterielCode)
+                            .Where(supWhere)
+                            .Where(wareWhere)
+                            .ToList();
+                        if (stockLockInfos != null && stockLockInfos.Any())
+                        {
+                            _outboundLockInfoRepository.DeleteAndMoveIntoHty(stockLockInfos, WIDESEA_Core.Enums.OperateTypeEnum.鑷姩鍒犻櫎);
+                        }
+                    }
+                    
+
                     // 妫�鏌ュ嚭搴撳崟鏄惁瀹屾垚
                     if (CheckOutboundOrderCompleted(request.OrderNo))
                     {
-                        UpdateOutboundOrderStatus(request.OrderNo, OutOrderStatusEnum.鍑哄簱瀹屾垚.ObjToInt());
+                        if(outboundOrder.OrderType != OutOrderTypeEnum.InternalAllocat.ObjToInt())
+                        {
+                            UpdateOutboundOrderStatus(request.OrderNo, OutOrderStatusEnum.鍑哄簱瀹屾垚.ObjToInt());
 
-                        _feedbackMesService.OutboundFeedback(outboundOrder.OrderNo);
+                            if (outboundOrder.CreateType != OrderCreateTypeEnum.CreateInSystem.ObjToInt())
+                            {
+                                _feedbackMesService.OutboundFeedback(outboundOrder.OrderNo);
+                            }
+                        }
                     }
                 }
                 catch (Exception ex)
@@ -1544,6 +1884,8 @@
         /// </summary>
         private decimal CalculateActualOutboundQuantity(Dt_StockInfoDetail stockDetail, List<Dt_OutboundOrderDetail> outboundDetails, Dt_OutStockLockInfo lockInfo)
         {
+            // decimal availableOutboundQuantity = lockInfo.AssignQuantity - lockInfo.SortedQuantity;
+
             decimal availableOutboundQuantity = lockInfo.AssignQuantity;
             decimal detailRemainingQuantity = outboundDetails.Sum(x => x.OrderQuantity - x.OverOutQuantity - x.MoveQty);//outboundDetail.OrderQuantity - outboundDetail.OverOutQuantity;
 
@@ -1562,7 +1904,7 @@
         /// <param name="beforeQuantity"></param>
         /// <param name="taskNum"></param>
         /// <returns></returns>
-        private (string NewBarcode, List<MaterialCodeReturnDTO> MaterialCodeReturnDTOs) PerformUnpackOperation(Dt_StockInfoDetail stockDetail, Dt_StockInfo stockInfo,
+        public (string NewBarcode, List<MaterialCodeReturnDTO> MaterialCodeReturnDTOs) PerformUnpackOperation(Dt_StockInfoDetail stockDetail, Dt_StockInfo stockInfo,
             decimal actualOutboundQuantity, OutboundCompleteRequestDTO request, decimal beforeQuantity, int taskNum, int orderId, string orderNo)
         {
             string newBarcode = GenerateNewBarcode();
@@ -1640,7 +1982,7 @@
         /// <summary>
         /// 鎵ц瀹屾暣鍑哄簱鎿嶄綔锛堜笉鎷嗗寘锛�
         /// </summary>
-        private void PerformFullOutboundOperation(Dt_StockInfoDetail stockDetail, Dt_StockInfo stockInfo,
+        public void PerformFullOutboundOperation(Dt_StockInfoDetail stockDetail, Dt_StockInfo stockInfo,
             decimal actualOutboundQuantity, OutboundCompleteRequestDTO request, decimal beforeQuantity, int taskNum)
         {
             // 淇濆瓨搴撳瓨鏄庣粏鍒板巻鍙茶褰�
@@ -1650,6 +1992,7 @@
                 OperateType = "鍑哄簱瀹屾垚",
                 InsertTime = DateTime.Now,
                 StockId = stockDetail.StockId,
+                Barcode = stockDetail.Barcode,
                 MaterielCode = stockDetail.MaterielCode,
                 MaterielName = stockDetail.MaterielName,
                 OrderNo = stockDetail.OrderNo,
@@ -1667,6 +2010,7 @@
                 Creater = stockDetail.Creater,
                 CreateDate = stockDetail.CreateDate,
                 WarehouseCode = stockDetail.WarehouseCode,
+                ValidDate = stockDetail.ValidDate,
                 Remark = $"鍑哄簱瀹屾垚鍒犻櫎锛屾潯鐮侊細{request.Barcode}锛屽師鏁伴噺锛歿stockDetail.StockQuantity}锛屽嚭搴撴暟閲忥細{actualOutboundQuantity}锛屾搷浣滆�咃細{request.Operator}"
             };
             _stockDetailHistoryRepository.AddData(historyRecord);
@@ -1820,6 +2164,36 @@
             return details.All(x => x.OverOutQuantity >= x.OrderQuantity - x.MoveQty);
         }
 
+        /// <summary>
+        /// 妫�鏌ュ嚭搴撳崟鏄庣粏鏄惁瀹屾垚
+        /// </summary>
+        public bool CheckOutboundOrderDetailCompletedByMatCode(string orderNo, string materialCode, List<Dt_OutboundOrderDetail> outboundOrderDetails)
+        {
+            if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(materialCode) || outboundOrderDetails == null || !outboundOrderDetails.Any())
+                return false;
+
+            // 鏌ヨ涓昏鍗曪紝涓嶅瓨鍦ㄧ洿鎺ヨ繑鍥瀎alse
+            Dt_OutboundOrder outboundOrder = _outboundRepository.QueryFirst(x => x.OrderNo == orderNo);
+            if (outboundOrder == null) return false;
+
+            var firstDetail = outboundOrderDetails.FirstOrDefault();
+            string supplyCode = firstDetail.SupplyCode;
+            string warehouseCode = firstDetail.WarehouseCode;
+            List<int> ids = outboundOrderDetails.Select(x => x.Id).ToList();
+
+            List<Dt_OutboundOrderDetail> details = _detailRepository.QueryData(x =>
+                x.OrderId == outboundOrder.Id
+                && x.MaterielCode == materialCode
+                && ids.Contains(x.Id)
+                && (string.IsNullOrEmpty(supplyCode) || x.SupplyCode == supplyCode)
+                && (string.IsNullOrEmpty(warehouseCode) || x.WarehouseCode == warehouseCode)
+            );
+
+            if (!details.Any()) return false;
+
+            return details.All(x => x.OverOutQuantity >= x.OrderQuantity - x.MoveQty);
+        }
+
         #endregion
 
         #region 鍙栫┖绠�
@@ -1829,6 +2203,12 @@
             try
             {
                 var stock = await _stockInfoRepository.Db.Queryable<Dt_StockInfo>().Includes(x => x.Details).Where(x => x.PalletCode == palletCode).FirstAsync();
+
+                Dt_Task task = _taskRepository.QueryFirst(x => x.PalletCode == palletCode);
+                if (task != null)
+                {
+                    return WebResponseContent.Instance.Error("浠诲姟淇℃伅鍒楄〃瀛樺湪璇ユ墭鐩樼殑浠诲姟淇℃伅锛屼笉鍙彇璧扮┖绠憋紝璇锋鏌ヤ换鍔℃槸鍚﹀畬鎴�");
+                }
 
                 if (stock == null)
                 {
@@ -1874,21 +2254,105 @@
                 if (stock.Details.Count <= 0)
                 {
                     stock.PalletType = (int)PalletTypeEnum.Empty;
-                    stock.StockStatus = (int)StockStatusEmun.缁勭洏鏆傚瓨;
+                    stock.StockStatus = (int)StockStatusEmun.鍏ュ簱纭;
                     stock.LocationCode = "";
                 }
                 else if (stock.Details.Count > 0)
                 {
                     Dt_OutStockLockInfo lockInfo = _outboundLockInfoRepository.QueryFirst(x =>
-                       x.OrderNo == OrderNo &&
                        x.StockId == stock.Id &&
                        x.PalletCode == palletCode);
 
                     if (lockInfo != null && lockInfo.SortedQuantity != lockInfo.AssignQuantity)
                     {
-                        return content.Error($"鎵樼洏{palletCode}搴撳瓨鏈嫞閫夊畬涓嶅厑璁稿洖搴�");
+                        // 1. 璁$畻闇�瑕佸洖婊氱殑鎬绘暟閲�
+                        decimal? rollbackTotalQuantity = lockInfo.AssignQuantity - lockInfo.SortedQuantity;
+                        // 纭繚鍥炴粴鏁伴噺涓烘鏁�
+                        if (rollbackTotalQuantity <= 0)
+                        {
+                            // 娌℃湁闇�瑕佸洖婊氱殑鏁伴噺
+                            stock.StockStatus = (int)StockStatusEmun.鍏ュ簱纭;
+                            stock.LocationCode = "";
+                        }
+
+                        try
+                        {
+                            //澶勭悊OrderDetailIds锛屽垎鍓插苟杞崲涓篒D鍒楄〃
+                            List<long> orderDetailIds = new List<long>();
+                            if (!string.IsNullOrEmpty(lockInfo.OrderDetailIds))
+                            {
+                                orderDetailIds = lockInfo.OrderDetailIds.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
+                                    .Select(id =>
+                                    {
+                                        if (long.TryParse(id.Trim(), out long result))
+                                        {
+                                            return result;
+                                        }
+                                        return 0; // 鏃犳晥ID鏍囪涓�0
+                                    })
+                                    .Where(id => id > 0)
+                                    .OrderByDescending(id => id)
+                                    .ToList();
+                            }
+
+                            if (orderDetailIds.Count == 0)
+                            {
+                                return WebResponseContent.Instance.Error("鍗曟嵁閿佸畾鍑哄簱鍗曟槑缁咺d鏃犳晥锛屾鏌ラ攣瀹氬嚭搴撴暟鎹槸鍚︽纭�");
+                            }
+
+                            //鏌ヨ瀵瑰簲鐨勮鍗曟槑缁�
+                            List<Dt_OutboundOrderDetail> orderDetails = _outboundRepository.Db.Queryable<Dt_OutboundOrderDetail>()
+                                .Where(x => orderDetailIds.Contains(x.Id))
+                                .ToList();
+
+                            if (orderDetails.Count == 0)
+                            {
+                                return WebResponseContent.Instance.Error("鏈壘鍒板彲鍥炴粴鏄庣粏锛岃妫�鏌ュ嚭搴撳崟鏄庣粏");
+                            }
+
+                            decimal remainingRollbackQty = (decimal)rollbackTotalQuantity;
+                            foreach (var detail in orderDetails)
+                            {
+                                if (remainingRollbackQty <= 0)
+                                {
+                                    break;
+                                }
+
+                                // 璁$畻璇ユ槑缁嗙殑鍙洖婊氭暟閲�
+                                decimal availableRollbackQty = detail.LockQuantity - detail.OverOutQuantity - detail.MoveQty;
+
+                                availableRollbackQty = Math.Max(0, availableRollbackQty);
+
+                                if (availableRollbackQty <= 0)
+                                {
+                                    continue; // 璇ユ槑缁嗘棤鍙洖婊氭暟閲忥紝璺宠繃
+                                }
+
+                                // 璁$畻鏈瀹為檯鍥炴粴鏁伴噺锛堝彇鍙洖婊氭暟閲忓拰鍓╀綑闇�瑕佸洖婊氭暟閲忕殑杈冨皬鍊硷級
+                                decimal actualRollbackQty = Math.Min(availableRollbackQty, remainingRollbackQty);
+
+                                detail.LockQuantity -= actualRollbackQty;
+                                detail.LockQuantity = Math.Max(0, detail.LockQuantity);
+
+                                _detailRepository.UpdateData(detail);
+
+                                //鏇存柊鍓╀綑闇�瑕佸洖婊氱殑鏁伴噺
+                                remainingRollbackQty -= actualRollbackQty;
+                            }
+                            
+                            if (remainingRollbackQty > 0)
+                            {
+                                return WebResponseContent.Instance.Error($"鍓╀綑鍥炴粴鏁伴噺{remainingRollbackQty}");
+                            }
+                            _outboundLockInfoRepository.DeleteAndMoveIntoHty(lockInfo, WIDESEA_Core.Enums.OperateTypeEnum.浜哄伐鍒犻櫎);
+                        }
+                        catch (Exception ex)
+                        {
+                            return WebResponseContent.Instance.Error(ex.Message);
+                        }
                     }
-                    stock.StockStatus = (int)StockStatusEmun.缁勭洏鏆傚瓨;
+
+                    stock.StockStatus = (int)StockStatusEmun.鍏ュ簱纭;
                     stock.LocationCode = "";
                 }
 
@@ -1904,15 +2368,20 @@
                 // 鍒嗛厤鏂拌揣浣�
                 var newLocation = _locationInfoService.AssignLocation(stock.LocationType);
 
+                if(newLocation == null)
+                {
+                    return WebResponseContent.Instance.Error("娌℃湁绌洪棽搴撲綅鍙洖搴�");
+                }
+
                 var newTask = new Dt_Task()
                 {
-                    CurrentAddress = stations[station],
+                    CurrentAddress = stations.GetValueOrDefault(station) ?? "",
                     Grade = 0,
                     PalletCode = palletCode,
                     NextAddress = "",
                     OrderNo = OrderNo,
                     Roadway = newLocation.RoadwayNo,
-                    SourceAddress = stations[station],
+                    SourceAddress = stations.GetValueOrDefault(station) ?? "",
                     TargetAddress = newLocation.LocationCode,
                     TaskStatus = (int)TaskStatusEnum.New,
                     TaskType = stock.Details.Count > 0 ? (int)TaskTypeEnum.InPick : (int)TaskTypeEnum.InEmpty,
@@ -1922,11 +2391,11 @@
                 _stockInfoRepository.UpdateData(stock);
                 _taskRepository.AddData(newTask);
 
-                //var moveResult = await _eSSApiService.MoveContainerAsync(new MoveContainerRequest
-                //{
-                //    slotCode = movestations[station],
-                //    containerCode = palletCode
-                //});
+                var moveResult = await _eSSApiService.MoveContainerAsync(new MoveContainerRequest
+                {
+                    slotCode = movestations[station],
+                    containerCode = palletCode
+                });
                 return content.OK();
 
             }
@@ -1936,6 +2405,425 @@
             }
         }
 
+        public WebResponseContent RecheckPicking(RecheckPickingDTO pickingDTO)
+        {
+            try
+            {
+                Dt_ReCheckOrder reCheckOrder = _outboundRepository.Db.Queryable<Dt_ReCheckOrder>().Where(x => x.OrderNo == pickingDTO.orderNo && x.Result == 0).First();
+                if(reCheckOrder == null)
+                {
+                    return WebResponseContent.Instance.Error($"鏈壘鍒拌寰呴噸鎷g殑鍗曟嵁{pickingDTO.orderNo}");
+                }
+                Dt_StockInfoDetail stockInfoDetail = _stockDetailRepository.QueryFirst(x=>x.Barcode == pickingDTO.barCode && x.Status == StockStatusEmun.鎵嬪姩鍐荤粨.ObjToInt() );
+                if(stockInfoDetail == null)
+                {
+                    return WebResponseContent.Instance.Error($"鏈湪搴撳瓨涓壘鍒拌鍐荤粨/闅旂鏉$爜 {pickingDTO.barCode}");
+                }
+                if (stockInfoDetail.MaterielCode != reCheckOrder.MaterielCode || stockInfoDetail.BatchNo != reCheckOrder.BatchNo)
+                {
+                    return WebResponseContent.Instance.Error("璇ユ潯鐮佺殑鐗╂枡缂栫爜鍜屾壒娆″拰璇ラ噸妫�鍗曚笉绗�");
+                }
+                stockInfoDetail.OrderNo = pickingDTO.orderNo;
+                stockInfoDetail.Status = StockStatusEmun.閲嶆涓�.ObjToInt();
+                var currentRemark = _outboundRepository.Db.Queryable<Dt_OutboundOrder>()
+                .Where(x => x.OrderNo == pickingDTO.orderNo)
+                .Select(x => x.Remark)
+                .First();
+
+                string newRemark;
+                if (string.IsNullOrWhiteSpace(currentRemark))
+                {
+                    newRemark = pickingDTO.barCode;
+                }
+                else
+                {
+                    var existingCodes = currentRemark.Split(',', StringSplitOptions.RemoveEmptyEntries)
+                        .Select(s => s.Trim())
+                        .ToList();
+
+                    if (!existingCodes.Contains(pickingDTO.barCode))
+                    {
+                        existingCodes.Add(pickingDTO.barCode);
+                        newRemark = string.Join(",", existingCodes);
+                    }
+                    else
+                    {
+                        newRemark = currentRemark;
+                    }
+                }
+                _outboundRepository.Db.Updateable<Dt_OutboundOrder>()
+                    .SetColumns(x => x.Remark == newRemark)
+                    .SetColumns(x=>x.OrderStatus == (int)OutOrderStatusEnum.鍑哄簱瀹屾垚)
+                    .Where(x => x.OrderNo == pickingDTO.orderNo)
+                    .ExecuteCommand();
+                _stockDetailRepository.UpdateData(stockInfoDetail);
+
+                return WebResponseContent.Instance.OK();
+            }
+            catch(Exception ex)
+            {
+                return WebResponseContent.Instance.Error(ex.Message);
+            }
+        }
+
         #endregion
+
+        #region 鎾ら攢鎷i��
+        /// <summary>
+        /// 鎾ら攢鎷i�夋潯鐮侊紙鍙嶅悜鍥炴粴鍑哄簱鎷i�夋搷浣滐級
+        /// </summary>
+        /// <param name="request">鎾ら攢鎷i�夎姹傦紙鑷冲皯鍖呭惈鏉$爜銆佽鍗曞彿銆佹墭鐩樺彿锛�</param>
+        /// <returns>鎾ら攢鍝嶅簲</returns>
+        public WebResponseContent ReversePicking(ReversePickingRequestDTO request)
+        {
+            WebResponseContent content = WebResponseContent.Instance;
+            ReversePickingResponseDTO response = new ReversePickingResponseDTO();
+
+            try
+            {
+                if (string.IsNullOrWhiteSpace(request.Barcode) || string.IsNullOrWhiteSpace(request.OrderNo) || string.IsNullOrWhiteSpace(request.PalletCode))
+                {
+                    response.Success = false;
+                    response.Message = "鏉$爜銆佽鍗曞彿銆佹墭鐩樺彿涓嶈兘涓虹┖";
+                    return WebResponseContent.Instance.Error(response.Message);
+                }
+
+                Dt_StockInfo stockInfo = _stockInfoRepository.QueryFirst(x => x.PalletCode == request.PalletCode);
+                if (stockInfo == null)
+                {
+                    response.Success = false;
+                    response.Message = $"鎵樼洏鍙� {request.PalletCode} 瀵瑰簲鐨勫簱瀛樹笉瀛樺湪";
+                    return WebResponseContent.Instance.Error(response.Message);
+                }
+
+                Dt_OutboundOrder outboundOrder = _outboundRepository.QueryFirst(o => o.OrderNo == request.OrderNo);
+                if (outboundOrder == null)
+                {
+                    response.Success = false;
+                    response.Message = $"鍑哄簱鍗� {request.OrderNo} 涓嶅瓨鍦�";
+                    return WebResponseContent.Instance.Error(response.Message);
+                }
+
+                Dt_StockInfoDetail_Hty historyDetail = _stockDetailHistoryRepository.QueryFirst(x =>
+                    x.Barcode == request.Barcode &&
+                    (x.OperateType == "鍑哄簱瀹屾垚" || x.OperateType == "鎷嗗寘-鍘熷璁板綍"));
+
+                if (historyDetail != null)
+                {
+                    double minutesDiff = (DateTime.Now - historyDetail.InsertTime).TotalMinutes;
+                    if (minutesDiff >= 30)
+                    {
+                        return WebResponseContent.Instance.Error($"鏉$爜{request.Barcode}宸叉棤娉曟挙閿�");
+                    }
+                }
+                else
+                {
+                    return WebResponseContent.Instance.Error($"鏉$爜{request.Barcode}宸叉棤娉曟挙閿�");
+                }
+
+                Dt_OutStockLockInfo lockInfo = _outboundLockInfoRepository.QueryFirst(x =>
+                    x.OrderNo == request.OrderNo &&
+                    x.StockId == stockInfo.Id &&
+                    x.MaterielCode == historyDetail.MaterielCode &&
+                    x.PalletCode == stockInfo.PalletCode);
+
+                if (lockInfo == null)
+                {
+                    return WebResponseContent.Instance.Error("璇ユ墭鐩樺凡鍏ㄩ儴鎷i�夊畬,涓嶅厑璁告挙閿�");
+                }
+
+               var details = _outboundOrderDetailRepository.QueryData(x => x.OrderId == outboundOrder.Id);
+
+                var outboundDetails = details
+                    .Where(x =>
+                        x.MaterielCode == historyDetail.MaterielCode
+                        &&
+                        !string.IsNullOrEmpty(lockInfo.OrderDetailIds)
+                        &&
+                        lockInfo.OrderDetailIds.Split(",")
+                            .Any(idStr => idStr.Trim() == x.Id.ToString())
+                    ).ToList();
+
+                var detail = outboundDetails.FirstOrDefault();
+                if (detail != null && !string.IsNullOrEmpty(detail.ReturnJsonData))
+                {
+                    try
+                    {
+                        string deleteBarcode = request.Barcode;
+
+                        var list = JsonConvert.DeserializeObject<List<BarcodeItem>>(detail.ReturnJsonData);
+                        if (list != null)
+                        {
+                            var filteredList = list.Where(x => x.barcode != deleteBarcode).ToList();
+                            
+                            detail.ReturnJsonData = JsonConvert.SerializeObject(filteredList);
+                            _outboundOrderDetailRepository.UpdateData(detail);
+                        }
+                    }
+                    catch
+                    {
+                        
+                    }
+                }
+
+                _unitOfWorkManage.BeginTran();
+                try
+                {
+                    bool isUnpack = historyDetail.OperateType == "鎷嗗寘-鍘熷璁板綍";
+                    if (isUnpack)
+                    {
+                        return WebResponseContent.Instance.Error("璇ユ潯鐮佸凡鎷嗗寘锛屼笉鍏佽鎾ら攢");
+                    }
+                    else
+                    {
+                        ReverseFullOutboundOperation(historyDetail, stockInfo, request);
+                    }
+
+                    RollbackOutboundOrderDetails(historyDetail.MaterielCode, request.OrderNo, historyDetail.StockQuantity, stockInfo.Id);
+
+                    lockInfo.SortedQuantity = Math.Max(0, (decimal)(lockInfo.SortedQuantity - historyDetail.StockQuantity));
+                    _outboundLockInfoRepository.UpdateData(lockInfo);
+
+                    _stockDetailHistoryRepository.DeleteData(historyDetail);
+
+                    DeleteStockChangeRecord(request.Barcode, request.OrderNo);
+
+                    if (!CheckOutboundOrderCompleted(request.OrderNo))
+                    {
+                        UpdateOutboundOrderStatus(request.OrderNo, OutOrderStatusEnum.鍑哄簱涓�.ObjToInt());
+                    }
+
+                    _unitOfWorkManage.CommitTran();
+
+                    response.Success = true;
+                    response.Message = $"鏉$爜 {request.Barcode} 鎾ら攢鎷i�夋垚鍔�";
+                    response.Barcode = request.Barcode;
+                    response.RestoredQuantity = historyDetail.StockQuantity;
+
+                    content = WebResponseContent.Instance.OK(data: response);
+                }
+                catch (Exception ex)
+                {
+                    _unitOfWorkManage.RollbackTran();
+                    response.Success = false;
+                    response.Message = $"鎾ら攢鎷i�夊け璐ワ細{ex.Message}";
+                    content = WebResponseContent.Instance.Error(response.Message);
+                }
+            }
+            catch (Exception ex)
+            {
+                response.Success = false;
+                response.Message = $"澶勭悊鎾ら攢鎷i�夊け璐ワ細{ex.Message}";
+                content = WebResponseContent.Instance.Error(response.Message);
+            }
+
+            return content;
+        }
+
+        /// <summary>
+        /// 鎾ら攢鎷嗗寘鍑哄簱鎿嶄綔锛堝弽鍚戞仮澶嶆媶鍖呭墠鐘舵�侊級
+        /// </summary>
+        private void ReverseUnpackOperation(Dt_StockInfoDetail_Hty historyDetail, Dt_StockInfo stockInfo, ReversePickingRequestDTO request, Dt_OutboundOrder outboundOrder)
+        {
+            Dt_StockInfoDetail currentDetail = _stockDetailRepository.QueryFirst(x =>
+                x.Barcode == request.Barcode &&
+                x.StockId == stockInfo.Id &&
+                x.MaterielCode == historyDetail.MaterielCode);
+
+            if (currentDetail != null)
+            {
+                currentDetail.StockQuantity = historyDetail.StockQuantity;
+                currentDetail.Remark = $"鎾ら攢鎷嗗寘鎷i�夛紝鎭㈠鍘熷鏁伴噺锛歿historyDetail.StockQuantity}锛屾搷浣滆�咃細{request.Operator}";
+                _stockDetailRepository.UpdateData(currentDetail);
+            }
+            else
+            {
+                Dt_StockInfoDetail restoreDetail = new Dt_StockInfoDetail
+                {
+                    StockId = historyDetail.StockId,
+                    MaterielCode = historyDetail.MaterielCode,
+                    MaterielName = historyDetail.MaterielName,
+                    Barcode =historyDetail.Barcode,
+                    OrderNo = historyDetail.OrderNo,
+                    BatchNo = historyDetail.BatchNo,
+                    ProductionDate = historyDetail.ProductionDate,
+                    EffectiveDate = historyDetail.EffectiveDate,
+                    SerialNumber = historyDetail.SerialNumber,
+                    StockQuantity = historyDetail.StockQuantity,
+                    OutboundQuantity = historyDetail.OutboundQuantity,
+                    Status = historyDetail.Status,
+                    Unit = historyDetail.Unit,
+                    InboundOrderRowNo = historyDetail.InboundOrderRowNo,
+                    SupplyCode = historyDetail.SupplyCode,
+                    Creater = request.Operator,
+                    CreateDate = DateTime.Now,
+                    FactoryArea = historyDetail.FactoryArea,
+                    WarehouseCode = historyDetail.WarehouseCode,
+                    Remark = $"鎾ら攢鎷嗗寘鎷i�夛紝閲嶆柊鍒涘缓搴撳瓨鏄庣粏锛屾潯鐮侊細{request.Barcode}锛屾搷浣滆�咃細{request.Operator}"
+                };
+                _stockDetailRepository.AddData(restoreDetail);
+            }
+
+            List<Dt_MaterialCodeInfo> materialCodeInfos = _basicService.MaterielCodeInfoService.Repository.QueryData(x =>
+                x.OldBarcode == request.Barcode &&
+                x.OrderNo == request.OrderNo);
+            if (materialCodeInfos.Any())
+            {
+                _basicService.MaterielCodeInfoService.Repository.DeleteData(materialCodeInfos);
+            }
+
+            if (outboundOrder.OrderType == InOrderTypeEnum.InternalAllocat.ObjToInt())
+            {
+                Dt_AllocateMaterialInfo allocateMaterialInfo = _allocateMaterialInfoRepository.QueryFirst(x =>
+                    x.Barcode == request.Barcode &&
+                    x.OrderNo == request.OrderNo);
+                if (allocateMaterialInfo != null)
+                {
+                    _allocateMaterialInfoRepository.DeleteData(allocateMaterialInfo);
+                }
+            }
+        }
+
+        /// <summary>
+        /// 鎾ら攢瀹屾暣鍑哄簱鎿嶄綔锛堟仮澶嶈鍒犻櫎鐨勫簱瀛樻槑缁嗭級
+        /// </summary>
+        private void ReverseFullOutboundOperation(Dt_StockInfoDetail_Hty historyDetail, Dt_StockInfo stockInfo, ReversePickingRequestDTO request)
+        {
+            Dt_StockInfoDetail restoreDetail = new Dt_StockInfoDetail
+            {
+             
+                StockId = historyDetail.StockId,
+                MaterielCode = historyDetail.MaterielCode,
+                MaterielName = historyDetail.MaterielName,
+                Barcode = historyDetail.Barcode,
+                OrderNo = historyDetail.OrderNo,
+                BatchNo = historyDetail.BatchNo,
+                ProductionDate = historyDetail.ProductionDate,
+                EffectiveDate = historyDetail.EffectiveDate,
+                SerialNumber = historyDetail.SerialNumber,
+                StockQuantity = historyDetail.StockQuantity,
+                OutboundQuantity = historyDetail.OutboundQuantity - historyDetail.StockQuantity,
+                Status = historyDetail.Status,
+                Unit = historyDetail.Unit,
+                InboundOrderRowNo = historyDetail.InboundOrderRowNo,
+                SupplyCode = historyDetail.SupplyCode,
+                Creater = request.Operator,
+                CreateDate = DateTime.Now,
+                FactoryArea = historyDetail.FactoryArea,
+                WarehouseCode = historyDetail.WarehouseCode,
+                Remark = $"鎾ら攢瀹屾暣鍑哄簱鎷i�夛紝鎭㈠搴撳瓨鏄庣粏锛屾潯鐮侊細{request.Barcode}锛屾搷浣滆�咃細{request.Operator}"
+            };
+
+            _stockDetailRepository.AddData(restoreDetail);
+
+            if (request.OrderType == InOrderTypeEnum.InternalAllocat.ObjToInt())
+            {
+                Dt_AllocateMaterialInfo allocateMaterialInfo = _allocateMaterialInfoRepository.QueryFirst(x =>
+                    x.Barcode == request.Barcode &&
+                    x.OrderNo == request.OrderNo);
+                if (allocateMaterialInfo != null)
+                {
+                    _allocateMaterialInfoRepository.DeleteData(allocateMaterialInfo);
+                }
+            }
+        }
+
+        /// <summary>
+        /// 鍥炴粴鍑哄簱鍗曟槑缁嗭紙鎵e噺宸插嚭搴撴暟閲忥級
+        /// </summary>
+        private void RollbackOutboundOrderDetails(string materielCode, string orderNo, decimal rollbackQuantity, int stockId)
+        {
+            Dt_OutboundOrder outboundOrder = _outboundRepository.QueryFirst(x => x.OrderNo == orderNo);
+            List<Dt_OutboundOrderDetail> details = _detailRepository.QueryData(x =>
+                x.OrderId == outboundOrder.Id &&
+                x.MaterielCode == materielCode &&
+                x.OverOutQuantity > 0);
+
+            if (!details.Any()) return;
+
+            decimal remainingRollbackQty = rollbackQuantity;
+            foreach (var detail in details)
+            {
+                if (remainingRollbackQty <= 0) break;
+
+                decimal rollbackQty = Math.Min(remainingRollbackQty, detail.OverOutQuantity);
+
+                detail.OverOutQuantity -= rollbackQty;
+                detail.CurrentDeliveryQty -= rollbackQty;
+
+                if (detail.OrderDetailStatus == (int)OrderDetailStatusEnum.Over && detail.OverOutQuantity < detail.OrderQuantity - detail.MoveQty)
+                {
+                    detail.OrderDetailStatus = (int)OrderDetailStatusEnum.New;
+                }
+
+                if (!string.IsNullOrEmpty(detail.ReturnJsonData))
+                {
+                    List<Barcodes> barcodesList = JsonConvert.DeserializeObject<List<Barcodes>>(detail.ReturnJsonData) ?? new List<Barcodes>();
+                    var targetBarcode = barcodesList.FirstOrDefault(x => x.Barcode == materielCode);
+                    if (targetBarcode != null)
+                    {
+                        barcodesList.Remove(targetBarcode);
+                        detail.ReturnJsonData = JsonConvert.SerializeObject(barcodesList, new JsonSerializerSettings
+                        {
+                            ContractResolver = new CamelCasePropertyNamesContractResolver()
+                        });
+                    }
+                }
+
+                _detailRepository.UpdateData(detail);
+                remainingRollbackQty -= rollbackQty;
+            }
+        }
+
+        /// <summary>
+        /// 鍒犻櫎搴撳瓨鍙樺姩璁板綍锛堟嫞閫夋椂鐢熸垚鐨勶級
+        /// </summary>
+        private void DeleteStockChangeRecord(string barcode, string orderNo)
+        {
+            Dt_StockQuantityChangeRecord changeRecord = _stockChangeRepository.QueryFirst(x =>
+                x.OriginalSerilNumber == barcode &&
+                x.OrderNo == orderNo &&
+                x.ChangeType == (int)StockChangeTypeEnum.Outbound);
+            if (changeRecord != null)
+            {
+                _stockChangeRepository.DeleteData(changeRecord);
+            }
+        }
+
+       
+        #endregion
+
+       
+    }
+
+    /// <summary>
+    /// 鏉$爜鏄庣粏瀹炰綋
+    /// </summary>
+    public class BarcodeItem
+    {
+        /// <summary>
+        /// 鏉$爜
+        /// </summary>
+        public string barcode { get; set; }
+
+        /// <summary>
+        /// 鏁伴噺
+        /// </summary>
+        public decimal qty { get; set; }
+
+        /// <summary>
+        /// 渚涘簲鍟嗙紪鐮�
+        /// </summary>
+        public string supplyCode { get; set; }
+
+        /// <summary>
+        /// 鎵规鍙�
+        /// </summary>
+        public string batchNo { get; set; }
+
+        /// <summary>
+        /// 鍗曚綅
+        /// </summary>
+        public string unit { get; set; }
     }
 }

--
Gitblit v1.9.3