From 1a1bc81ac1d9ad656e15b409122e23f7f3763293 Mon Sep 17 00:00:00 2001
From: pan <antony1029@163.com>
Date: 星期四, 27 十一月 2025 08:27:41 +0800
Subject: [PATCH] 提交

---
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs | 1223 ++++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 967 insertions(+), 256 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/OutboundPickingService.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/OutboundPickingService.cs"
index eddd986..d9a755c 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/OutboundPickingService.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/OutboundPickingService.cs"
@@ -8,7 +8,9 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
+using System.Text.Json;
 using System.Threading.Tasks;
+using WIDESEA_Common.CommonEnum;
 using WIDESEA_Common.LocationEnum;
 using WIDESEA_Common.OrderEnum;
 using WIDESEA_Common.StockEnum;
@@ -16,10 +18,13 @@
 using WIDESEA_Core;
 using WIDESEA_Core.BaseRepository;
 using WIDESEA_Core.BaseServices;
+using WIDESEA_Core.Enums;
 using WIDESEA_Core.Helper;
+using WIDESEA_DTO.Allocate;
 using WIDESEA_DTO.Basic;
 using WIDESEA_DTO.Inbound;
 using WIDESEA_DTO.Outbound;
+using WIDESEA_IAllocateService;
 using WIDESEA_IBasicService;
 using WIDESEA_IOutboundService;
 using WIDESEA_IStockService;
@@ -47,6 +52,7 @@
         private readonly IESSApiService _eSSApiService;
         private readonly IInvokeMESService _invokeMESService;
         private readonly IDailySequenceService _dailySequenceService;
+        private readonly IAllocateService _allocateService;
 
         private readonly ILogger<OutboundPickingService> _logger;
 
@@ -67,7 +73,7 @@
         public OutboundPickingService(IRepository<Dt_PickingRecord> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockInfoService stockInfoService, IStockService stockService,
             IOutStockLockInfoService outStockLockInfoService, IStockInfoDetailService stockInfoDetailService, ILocationInfoService locationInfoService,
             IOutboundOrderDetailService outboundOrderDetailService, ISplitPackageService splitPackageService, IOutboundOrderService outboundOrderService,
-            IRepository<Dt_Task> taskRepository, IESSApiService eSSApiService, ILogger<OutboundPickingService> logger, IInvokeMESService invokeMESService, IDailySequenceService dailySequenceService) : base(BaseDal)
+            IRepository<Dt_Task> taskRepository, IESSApiService eSSApiService, ILogger<OutboundPickingService> logger, IInvokeMESService invokeMESService, IDailySequenceService dailySequenceService, IAllocateService allocateService) : base(BaseDal)
         {
             _unitOfWorkManage = unitOfWorkManage;
             _stockInfoService = stockInfoService;
@@ -83,8 +89,11 @@
             _logger = logger;
             _invokeMESService = invokeMESService;
             _dailySequenceService = dailySequenceService;
+            _allocateService = allocateService;
         }
 
+
+        #region 鏌ヨ鏂规硶
         // 鑾峰彇鏈嫞閫夊垪琛�
         public async Task<List<Dt_OutStockLockInfo>> GetUnpickedList(string orderNo, string palletCode)
         {
@@ -147,6 +156,8 @@
             return summary;
         }
 
+        #endregion
+
         #region 鏍稿績涓氬姟娴佺▼
         /// <summary>
         /// 鎷i��
@@ -160,7 +171,7 @@
             try
             {
                 _unitOfWorkManage.BeginTran();
-  
+
                 var validationResult = await ValidatePickingRequest(orderNo, palletCode, barcode);
                 if (!validationResult.IsValid)
                     return WebResponseContent.Instance.Error(validationResult.ErrorMessage);
@@ -180,10 +191,10 @@
                     return WebResponseContent.Instance.Error(overPickingValidation.ErrorMessage);
                 }
 
-                //  鎵ц鍒嗘嫞閫昏緫
+                // 鎵ц鍒嗘嫞閫昏緫锛堝彧澶勭悊搴撳瓨鍜岄攣瀹氾紝涓嶅鐞嗚鍗曪級
                 var pickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, orderNo, palletCode, barcode, actualQty);
 
-                // 鏇存柊鐩稿叧鏁版嵁
+                // 缁熶竴鏇存柊璁㈠崟鏁版嵁锛堟墍鏈夊垎鏀兘鍦ㄨ繖閲屾洿鏂帮級
                 await UpdateOrderRelatedData(orderDetail.Id, pickingResult.ActualPickedQty, orderNo);
 
                 // 璁板綍鎿嶄綔鍘嗗彶
@@ -200,6 +211,7 @@
                 return WebResponseContent.Instance.Error($"鎷i�夌‘璁ゅけ璐ワ細{ex.Message}");
             }
         }
+
         /// <summary>
         /// 鍙栨秷鎷i��
         /// </summary>
@@ -229,7 +241,7 @@
 
                 _unitOfWorkManage.CommitTran();
 
-                return WebResponseContent.Instance.OK($"鍙栨秷鍒嗘嫞鎴愬姛锛屾仮澶嶆暟閲忥細{pickingRecord.PickQuantity}");
+                return WebResponseContent.Instance.OK($"鍙栨秷鍒嗘嫞鎴愬姛");
             }
             catch (Exception ex)
             {
@@ -251,11 +263,11 @@
             {
                 _unitOfWorkManage.BeginTran();
 
-                // 1. 鍩虹楠岃瘉
+
                 if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode))
                     return WebResponseContent.Instance.Error("璁㈠崟鍙峰拰鎵樼洏鐮佷笉鑳戒负绌�");
 
-                // 2. 鑾峰彇搴撳瓨鍜屼换鍔′俊鎭�
+                //  鑾峰彇搴撳瓨鍜屼换鍔′俊鎭�
                 var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>().FirstAsync(x => x.PalletCode == palletCode);
 
                 if (stockInfo == null)
@@ -265,23 +277,35 @@
                 if (task == null)
                     return WebResponseContent.Instance.Error("鏈壘鍒板搴旂殑浠诲姟淇℃伅");
 
-                // 3. 鍒嗘瀽闇�瑕佸洖搴撶殑璐х墿
-                var returnAnalysis = await AnalyzeReturnItems(orderNo, palletCode, stockInfo.Id);
-                if (!returnAnalysis.HasItemsToReturn)
-                    return await HandleNoReturnItems(orderNo, palletCode,task);
+                //鍒嗘瀽闇�瑕佸洖搴撶殑璐х墿
+                //var returnAnalysis = await AnalyzeReturnItems(orderNo, palletCode, stockInfo.Id);
+                //if (!returnAnalysis.HasItemsToReturn)
+                //    return await HandleNoReturnItems(orderNo, palletCode, task);
 
-                // 4. 鎵ц鍥炲簱鎿嶄綔
-                await ExecuteReturnOperations(orderNo, palletCode, stockInfo, task, returnAnalysis);
+                var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id);
+                if (!statusAnalysis.HasItemsToReturn)
+                    return await HandleNoReturnItems(orderNo, palletCode, task, stockInfo.Id);
 
-                // 5. 鍒涘缓鍥炲簱浠诲姟
-                await CreateReturnTaskAndHandleESS(orderNo, palletCode, task, returnAnalysis);
+                // 4. 妫�鏌ユ槸鍚︽湁杩涜涓殑浠诲姟
+                if (statusAnalysis.HasActiveTasks)
+                {
+                    return WebResponseContent.Instance.Error($"鎵樼洏 {palletCode} 鏈夎繘琛屼腑鐨勪换鍔★紝涓嶈兘鎵ц鍥炲簱鎿嶄綔");
+                }
+
+                //鎵ц鍥炲簱鎿嶄綔
+                await ExecuteReturnOperations(orderNo, palletCode, stockInfo, task, statusAnalysis);
 
                 _unitOfWorkManage.CommitTran();
 
-                // 6. 鏇存柊璁㈠崟鐘舵�侊紙涓嶈Е鍙慚ES鍥炰紶锛�
+
+                // 鍒涘缓鍥炲簱浠诲姟
+                await CreateReturnTaskAndHandleESS(orderNo, palletCode, task, TaskTypeEnum.InPick, task.PalletType);
+
+                // 鏇存柊璁㈠崟鐘舵�侊紙涓嶈Е鍙慚ES鍥炰紶锛�
                 await UpdateOrderStatusForReturn(orderNo);
 
-                return WebResponseContent.Instance.OK($"鍥炲簱鎿嶄綔鎴愬姛锛屽叡鍥炲簱鏁伴噺锛歿returnAnalysis.TotalReturnQty}");
+                return WebResponseContent.Instance.OK($"鍥炲簱鎿嶄綔鎴愬姛");
+                //return WebResponseContent.Instance.OK($"鍥炲簱鎿嶄綔鎴愬姛锛屽叡鍥炲簱鏁伴噺锛歿statusAnalysis.TotalReturnQty}");
             }
             catch (Exception ex)
             {
@@ -291,6 +315,71 @@
             }
         }
 
+        /// <summary>
+        /// 绌烘墭鐩樺彇璧版帴鍙o紙甯﹁鍗曞彿锛�
+        /// 楠岃瘉鎵樼洏鏄惁鐪熺殑涓虹┖锛屾竻鐞嗘暟鎹紝鏇存柊璁㈠崟鐘舵�侊紝鍒涘缓鍙栨墭鐩樹换鍔�
+        /// </summary>
+        public async Task<WebResponseContent> RemoveEmptyPallet(string orderNo, string palletCode)
+        {
+            try
+            {
+                _unitOfWorkManage.BeginTran();
+
+                if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode))
+                    return WebResponseContent.Instance.Error("璁㈠崟鍙峰拰鎵樼洏鐮佷笉鑳戒负绌�");
+
+                // 妫�鏌ヨ鍗曟槸鍚﹀瓨鍦�
+                var order = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
+                    .Where(x => x.OrderNo == orderNo)
+                    .FirstAsync();
+
+                if (order == null)
+                    return WebResponseContent.Instance.Error($"鏈壘鍒拌鍗� {orderNo}");
+
+                //妫�鏌ユ墭鐩樻槸鍚﹀瓨鍦ㄤ笖灞炰簬璇ヨ鍗�
+                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
+                    .Where(x => x.PalletCode == palletCode)
+                    .FirstAsync();
+
+                if (stockInfo == null)
+                    return WebResponseContent.Instance.Error($"鏈壘鍒版墭鐩� {palletCode} 瀵瑰簲鐨勫簱瀛樹俊鎭�");
+
+                var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id);
+
+                if (!statusAnalysis.CanRemove)
+                {
+                    if (!statusAnalysis.IsEmptyPallet)
+                    {
+                        return WebResponseContent.Instance.Error($"鎵樼洏 {palletCode} 涓婅繕鏈夎揣鐗╋紝涓嶈兘鍙栬蛋");
+                    }
+                    if (statusAnalysis.HasActiveTasks)
+                    {
+                        return WebResponseContent.Instance.Error($"鎵樼洏 {palletCode} 杩樻湁杩涜涓殑浠诲姟锛屼笉鑳藉彇璧�");
+                    }
+                }
+                // 娓呯悊闆跺簱瀛樻暟鎹�
+                await CleanupZeroStockData(stockInfo.Id);
+
+                // 鍒犻櫎鎴栧彇娑堢浉鍏充换鍔�
+                await HandleTaskCleanup(orderNo, palletCode);
+
+                // 鏇存柊璁㈠崟鐩稿叧鏁版嵁
+                await UpdateOrderData(orderNo, palletCode);
+
+
+                _unitOfWorkManage.CommitTran();
+
+                _logger.LogInformation($"绌烘墭鐩樺彇璧版搷浣滄垚鍔� - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}, 鎿嶄綔浜�: {App.User.UserName}");
+
+                return WebResponseContent.Instance.OK("绌烘墭鐩樺彇璧版搷浣滄垚鍔�");
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                _logger.LogError($"RemoveEmptyPallet澶辫触 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
+                return WebResponseContent.Instance.Error($"绌烘墭鐩樺彇璧板け璐�: {ex.Message}");
+            }
+        }
         #endregion
 
         #region 鍒嗘嫞纭绉佹湁鏂规硶
@@ -366,7 +455,7 @@
             {
                 // 鏌ユ壘鍚屼竴璁㈠崟涓嬬殑璁板綍
                 lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                    .Where(it => it.OrderNo == orderNo &&  it.CurrentBarcode == barcode && it.Status == (int)OutLockStockStatusEnum.鍑哄簱涓� && it.AssignQuantity > it.PickedQty).FirstAsync();
+                    .Where(it => it.OrderNo == orderNo && it.CurrentBarcode == barcode && it.Status == (int)OutLockStockStatusEnum.鍑哄簱涓� && it.AssignQuantity > it.PickedQty).FirstAsync();
 
                 if (lockInfo == null)
                 {
@@ -435,7 +524,7 @@
                 adjustedReason = adjustedReason != null
                     ? $"{adjustedReason}锛岄槻瓒呮嫞闄愬埗锛氭渶缁堣皟鏁翠负{actualQty}"
                     : $"闃茶秴鎷i檺鍒讹細浠巤plannedQty}璋冩暣涓簕actualQty}";
-            } 
+            }
 
             if (adjustedReason != null)
             {
@@ -466,9 +555,11 @@
 
             return ValidationResult<bool>.Success(true);
         }
+
+
         private async Task<PickingResult> ExecutePickingLogic(
-            Dt_OutStockLockInfo lockInfo, Dt_OutboundOrderDetail orderDetail, Dt_StockInfoDetail stockDetail,
-            string orderNo, string palletCode, string barcode, decimal actualQty)
+         Dt_OutStockLockInfo lockInfo, Dt_OutboundOrderDetail orderDetail, Dt_StockInfoDetail stockDetail,
+         string orderNo, string palletCode, string barcode, decimal actualQty)
         {
             decimal stockQuantity = stockDetail.StockQuantity;
             var result = new PickingResult
@@ -482,50 +573,58 @@
             if (actualQty < stockQuantity)
             {
                 await HandleSplitPacking(lockInfo, stockDetail, actualQty, stockQuantity, result);
+                // 鎷嗗寘鍦烘櫙杩斿洖瀹為檯鎷i�夋暟閲�
+                result.ActualPickedQty = actualQty;
             }
             else if (actualQty == stockQuantity)
             {
                 await HandleFullPicking(lockInfo, stockDetail, actualQty, result);
+                // 鏁村寘鎷i�夎繑鍥炲疄闄呮嫞閫夋暟閲�
+                result.ActualPickedQty = actualQty;
             }
             else
             {
                 await HandlePartialPicking(lockInfo, stockDetail, actualQty, stockQuantity, result);
+                // 閮ㄥ垎鎷i�夎繑鍥炶皟鏁村悗鐨勬暟閲�
+                result.ActualPickedQty = result.ActualPickedQty; // 宸茬粡鍦ㄦ柟娉曞唴璋冩暣
             }
 
             return result;
         }
-
         private async Task HandleSplitPacking(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
-            decimal actualQty, decimal stockQuantity, PickingResult result)
+       decimal actualQty, decimal stockQuantity, PickingResult result)
         {
             decimal remainingStockQty = stockQuantity - actualQty;
 
-            // 1. 鏇存柊鍘熸潯鐮佸簱瀛�
+            // 鏇存柊鍘熸潯鐮佸簱瀛�
             stockDetail.StockQuantity = remainingStockQty;
             stockDetail.OutboundQuantity = remainingStockQty;
             await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
 
-            // 2. 鐢熸垚鏂版潯鐮�
+            // 鐢熸垚鏂版潯鐮�
             string newBarcode = await GenerateNewBarcode();
 
-            // 3. 鍒涘缓鏂伴攣瀹氫俊鎭�
+            // 鍒涘缓鏂伴攣瀹氫俊鎭�
             var newLockInfo = await CreateSplitLockInfo(lockInfo, actualQty, newBarcode);
 
-            // 4. 璁板綍鎷嗗寘鍘嗗彶
+            // 璁板綍鎷嗗寘鍘嗗彶
             await RecordSplitHistory(lockInfo, stockDetail, actualQty, remainingStockQty, newBarcode);
 
-            // 5. 鏇存柊鍘熼攣瀹氫俊鎭�
+            // 鏇存柊鍘熼攣瀹氫俊鎭�
             lockInfo.AssignQuantity = remainingStockQty;
             lockInfo.PickedQty = 0;
             lockInfo.Operator = App.User.UserName;
             await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
 
-            // 6. 璁剧疆缁撴灉
+            // 璁剧疆缁撴灉
             result.FinalLockInfo = newLockInfo;
             result.FinalBarcode = newBarcode;
             result.SplitResults.AddRange(CreateSplitResults(lockInfo, actualQty, remainingStockQty, newBarcode, stockDetail.Barcode));
-        }
 
+
+
+            _logger.LogInformation($"鎷嗗寘鍒嗘嫞瀹屾垚 - OrderDetailId: {lockInfo.OrderDetailId}, 鍒嗘嫞鏁伴噺: {actualQty}");
+        }
         private async Task HandleFullPicking(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
             decimal actualQty, PickingResult result)
         {
@@ -577,10 +676,10 @@
 
             if (newOverOutQuantity > currentOrderDetail.NeedOutQuantity)
             {
-                
+
                 _logger.LogError($"闃茶秴鎷f鏌ュけ璐� - OrderDetailId: {orderDetailId}, 宸插嚭搴�: {newOverOutQuantity}, 闇�姹�: {currentOrderDetail.NeedOutQuantity}, 鏈鍒嗘嫞: {pickedQty}");
 
-                 
+
                 decimal adjustedQty = currentOrderDetail.NeedOutQuantity - currentOrderDetail.OverOutQuantity;
 
                 if (adjustedQty > 0)
@@ -643,7 +742,73 @@
         #endregion
 
         #region 鍙栨秷鍒嗘嫞绉佹湁鏂规硶
+        private async Task<ValidationResult<bool>> ValidateDataConsistencyBeforeCancel(CancelPickingContext context)
+        {
+            try
+            {
+                // 1. 楠岃瘉璁㈠崟鏄庣粏鏁版嵁
+                var currentOrderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                    .FirstAsync(x => x.Id == context.OrderDetail.Id);
 
+                if (currentOrderDetail.OverOutQuantity < context.PickingRecord.PickQuantity)
+                    return ValidationResult<bool>.Error($"璁㈠崟鏄庣粏宸插嚭搴撴暟閲�({currentOrderDetail.OverOutQuantity})灏忎簬鍙栨秷鏁伴噺({context.PickingRecord.PickQuantity})");
+
+                if (currentOrderDetail.PickedQty < context.PickingRecord.PickQuantity)
+                    return ValidationResult<bool>.Error($"璁㈠崟鏄庣粏宸叉嫞閫夋暟閲�({currentOrderDetail.PickedQty})灏忎簬鍙栨秷鏁伴噺({context.PickingRecord.PickQuantity})");
+
+                // 2. 楠岃瘉閿佸畾淇℃伅鏁版嵁
+                var currentLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                    .FirstAsync(x => x.Id == context.LockInfo.Id);
+
+                if (currentLockInfo.PickedQty < context.PickingRecord.PickQuantity)
+                    return ValidationResult<bool>.Error($"閿佸畾淇℃伅宸叉嫞閫夋暟閲�({currentLockInfo.PickedQty})灏忎簬鍙栨秷鏁伴噺({context.PickingRecord.PickQuantity})");
+
+                // 3. 楠岃瘉搴撳瓨鏁版嵁
+                var currentStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                    .FirstAsync(x => x.Barcode == context.PickingRecord.Barcode && x.StockId == context.PickingRecord.StockId);
+
+                if (currentStockDetail == null)
+                    return ValidationResult<bool>.Error($"鏈壘鍒板搴旂殑搴撳瓨鏄庣粏璁板綍");
+
+                if (currentStockDetail.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt() ||
+                    currentStockDetail.Status == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt())
+                    return ValidationResult<bool>.Error($"鏉$爜{context.PickingRecord.Barcode}宸茬粡鍥炲簱锛屾棤娉曞彇娑堝垎鎷�");
+
+                // 4. 楠岃瘉鐘舵�佹祦杞殑鍚堟硶鎬�
+                if (!await CanCancelPicking(currentLockInfo, currentStockDetail))
+                    return ValidationResult<bool>.Error($"褰撳墠鐘舵�佷笉鍏佽鍙栨秷鍒嗘嫞");
+
+                return ValidationResult<bool>.Success(true);
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError($"鍙栨秷鍒嗘嫞鏁版嵁涓�鑷存�ч獙璇佸け璐�: {ex.Message}");
+                return ValidationResult<bool>.Error($"鏁版嵁楠岃瘉澶辫触: {ex.Message}");
+            }
+        }
+
+        private async Task<bool> CanCancelPicking(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail)
+        {
+            // 閿佸畾淇℃伅鐘舵�佹鏌�
+            if (lockInfo.Status != (int)OutLockStockStatusEnum.鎷i�夊畬鎴�)
+                return false;
+
+            // 搴撳瓨鐘舵�佹鏌�
+            if (stockDetail.Status == StockStatusEmun.鍑哄簱瀹屾垚.ObjToInt())
+                return false;
+
+            // 濡傛灉鏄媶鍖呰褰曪紝杩橀渶瑕佹鏌ョ埗閿佸畾淇℃伅鐘舵��
+            if (lockInfo.IsSplitted == 1 && lockInfo.ParentLockId.HasValue)
+            {
+                var parentLock = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                    .FirstAsync(x => x.Id == lockInfo.ParentLockId.Value);
+
+                if (parentLock == null || parentLock.Status == (int)OutLockStockStatusEnum.鍥炲簱涓�)
+                    return false;
+            }
+
+            return true;
+        }
         private async Task<ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>> ValidateCancelRequest(string orderNo, string palletCode, string barcode)
         {
             // 鍩虹鍙傛暟楠岃瘉
@@ -672,7 +837,7 @@
 
             if (lockInfo == null)
                 return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("鏈壘鍒板搴旂殑鍑哄簱閿佸畾淇℃伅");
-          
+
             if (lockInfo.PickedQty < pickingRecord.PickQuantity)
             {
                 return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error(
@@ -714,8 +879,8 @@
                 {
                     return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error($"鏉$爜{barcode}宸茬粡鍥炲簱锛屼笉鑳藉彇娑堝垎鎷�");
                 }
-            }       
-            
+            }
+
             return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Success((pickingRecord, lockInfo, orderDetail));
         }
         /// <summary>
@@ -751,30 +916,25 @@
                    stockDetail.Status == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt();
         }
         private async Task ExecuteCancelLogic(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord,
-            Dt_OutboundOrderDetail orderDetail, string orderNo)
+        Dt_OutboundOrderDetail orderDetail, string orderNo)
         {
             decimal cancelQty = pickingRecord.PickQuantity;
 
-            var currentStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-        .Where(it => it.Barcode == pickingRecord.Barcode && it.StockId == pickingRecord.StockId)
-        .FirstAsync();
-
-            if (currentStockDetail != null &&
-                (currentStockDetail.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt() ||
-                 currentStockDetail.Status == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt()))
+            // 1. 鏁版嵁涓�鑷存�ч獙璇�
+            var context = new CancelPickingContext
             {
-                throw new Exception($"鏉$爜{pickingRecord.Barcode}宸茬粡鍥炲簱锛屾棤娉曞彇娑堝垎鎷�");
-            }
-            //   妫�鏌ュ彇娑堝悗鏁伴噺涓嶄細涓鸿礋鏁�
-            decimal newOverOutQuantity = orderDetail.OverOutQuantity - cancelQty;
-            decimal newPickedQty = orderDetail.PickedQty - cancelQty;
+                LockInfo = lockInfo,
+                PickingRecord = pickingRecord,
+                OrderDetail = orderDetail,
+                OrderNo = orderNo,
+                CancelQuantity = cancelQty
+            };
 
-            if (newOverOutQuantity < 0 || newPickedQty < 0)
-            {
-                throw new Exception($"鍙栨秷鍒嗘嫞灏嗗鑷存暟鎹紓甯革細宸插嚭搴搟newOverOutQuantity}锛屽凡鎷i�墈newPickedQty}");
-            }
+            var validationResult = await ValidateDataConsistencyBeforeCancel(context);
+            if (!validationResult.IsValid)
+                throw new Exception(validationResult.ErrorMessage);
 
-            //  澶勭悊涓嶅悓绫诲瀷鐨勫彇娑�
+            // 2. 澶勭悊涓嶅悓绫诲瀷鐨勫彇娑�
             if (lockInfo.IsSplitted == 1 && lockInfo.ParentLockId.HasValue)
             {
                 await HandleSplitBarcodeCancel(lockInfo, pickingRecord, cancelQty);
@@ -784,16 +944,23 @@
                 await HandleNormalBarcodeCancel(lockInfo, pickingRecord, cancelQty);
             }
 
-            // 鏇存柊璁㈠崟鏄庣粏
+            //  鏇存柊璁㈠崟鏄庣粏
             await UpdateOrderDetailOnCancel(pickingRecord.OrderDetailId, cancelQty);
 
             //  鍒犻櫎鎷i�夎褰�
-            await Db.Deleteable<Dt_PickingRecord>()
+            var deleteResult = await Db.Deleteable<Dt_PickingRecord>()
                 .Where(x => x.Id == pickingRecord.Id)
                 .ExecuteCommandAsync();
 
-            //  閲嶆柊妫�鏌ヨ鍗曠姸鎬�
+            if (deleteResult <= 0)
+                throw new Exception("鍒犻櫎鎷i�夎褰曞け璐�");
+
+            _logger.LogInformation($"鍒犻櫎鎷i�夎褰� - 璁板綍ID: {pickingRecord.Id}, 鏉$爜: {pickingRecord.Barcode}");
+
+            // 閲嶆柊妫�鏌ヨ鍗曠姸鎬�
             await UpdateOrderStatusForReturn(orderNo);
+
+
         }
 
         private async Task HandleSplitBarcodeCancel(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord, decimal cancelQty)
@@ -806,59 +973,85 @@
             if (parentLockInfo == null)
                 throw new Exception("鏈壘鍒扮埗閿佸畾淇℃伅锛屾棤娉曞彇娑堟媶鍖呭垎鎷�");
 
+            // 妫�鏌ョ埗鏉$爜鍜屾媶鍖呮潯鐮佺殑鐘舵��
             if (await IsLockInfoReturned(parentLockInfo))
-            {
                 throw new Exception($"鐖舵潯鐮亄parentLockInfo.CurrentBarcode}宸茬粡鍥炲簱锛屾棤娉曞彇娑堟媶鍖呭垎鎷�");
-            }
+
             if (await IsLockInfoReturned(lockInfo))
-            {
                 throw new Exception($"鎷嗗寘鏉$爜{lockInfo.CurrentBarcode}宸茬粡鍥炲簱锛屾棤娉曞彇娑堟媶鍖呭垎鎷�");
-            }
+
             // 鎭㈠鐖堕攣瀹氫俊鎭殑鍒嗛厤鏁伴噺
             parentLockInfo.AssignQuantity += cancelQty;
+            parentLockInfo.Status = (int)OutLockStockStatusEnum.鍑哄簱涓�; // 鎭㈠涓哄嚭搴撲腑鐘舵��
             await _outStockLockInfoService.Db.Updateable(parentLockInfo).ExecuteCommandAsync();
 
-            // 鎭㈠搴撳瓨
-            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+            // 鎭㈠鐖舵潯鐮佸簱瀛�
+            var parentStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                 .Where(x => x.Barcode == parentLockInfo.CurrentBarcode && x.StockId == parentLockInfo.StockId)
                 .FirstAsync();
 
-            if (stockDetail != null)
+            if (parentStockDetail != null)
             {
-                stockDetail.StockQuantity += cancelQty;
-                stockDetail.OutboundQuantity = stockDetail.StockQuantity;
-                stockDetail.Status = StockStatusEmun.鍑哄簱閿佸畾.ObjToInt();
-                await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+                parentStockDetail.StockQuantity += cancelQty;
+                parentStockDetail.OutboundQuantity = parentStockDetail.StockQuantity;
+                parentStockDetail.Status = StockStatusEmun.鍑哄簱閿佸畾.ObjToInt();
+                await _stockInfoDetailService.Db.Updateable(parentStockDetail).ExecuteCommandAsync();
+
+                _logger.LogInformation($"鎭㈠鐖舵潯鐮佸簱瀛� - 鏉$爜: {parentStockDetail.Barcode}, 鎭㈠鏁伴噺: {cancelQty}, 鏂板簱瀛�: {parentStockDetail.StockQuantity}");
+            }
+
+            // 澶勭悊鎷嗗寘浜х敓鐨勬柊鏉$爜搴撳瓨
+            var splitStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(x => x.Barcode == lockInfo.CurrentBarcode && x.StockId == lockInfo.StockId)
+                .FirstAsync();
+
+            if (splitStockDetail != null)
+            {
+                // 鍒犻櫎鎷嗗寘浜х敓鐨勬柊鏉$爜搴撳瓨璁板綍
+                await _stockInfoDetailService.Db.Deleteable(splitStockDetail).ExecuteCommandAsync();
+                _logger.LogInformation($"鍒犻櫎鎷嗗寘鏂版潯鐮佸簱瀛� - 鏉$爜: {splitStockDetail.Barcode}");
             }
 
             // 鏇存柊鎷嗗寘璁板綍鐘舵��
-            await _splitPackageService.Db.Updateable<Dt_SplitPackageRecord>()
+            var updateCount = await _splitPackageService.Db.Updateable<Dt_SplitPackageRecord>()
                 .SetColumns(x => new Dt_SplitPackageRecord
                 {
                     Status = (int)SplitPackageStatusEnum.宸叉挙閿�,
                     IsReverted = true,
+                    Operator = App.User.UserName,
+                    RevertTime = DateTime.Now
                 })
                 .Where(x => x.NewBarcode == lockInfo.CurrentBarcode && !x.IsReverted)
                 .ExecuteCommandAsync();
+
+            _logger.LogInformation($"鏇存柊鎷嗗寘璁板綍鐘舵�� - 鏇存柊璁板綍鏁�: {updateCount}");
 
             // 鍒犻櫎鎷嗗寘浜х敓鐨勯攣瀹氫俊鎭�
             await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
                 .Where(x => x.Id == lockInfo.Id)
                 .ExecuteCommandAsync();
-        }
 
+            _logger.LogInformation($"鍒犻櫎鎷嗗寘閿佸畾淇℃伅 - 閿佸畾ID: {lockInfo.Id}, 鏉$爜: {lockInfo.CurrentBarcode}");
+        }
         private async Task HandleNormalBarcodeCancel(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord, decimal cancelQty)
         {
             if (await IsLockInfoReturned(lockInfo))
-            {
                 throw new Exception($"鏉$爜{lockInfo.CurrentBarcode}宸茬粡鍥炲簱锛屾棤娉曞彇娑堝垎鎷�");
-            }
+
             // 鎭㈠閿佸畾淇℃伅
             lockInfo.PickedQty -= cancelQty;
             if (lockInfo.PickedQty < 0) lockInfo.PickedQty = 0;
 
-            lockInfo.Status = (int)OutLockStockStatusEnum.鍑哄簱涓�;
+            // 鍙湁褰撴嫞閫夋暟閲忓畬鍏ㄥ彇娑堟椂鎵嶆仮澶嶇姸鎬�
+            if (lockInfo.PickedQty == 0)
+            {
+                lockInfo.Status = (int)OutLockStockStatusEnum.鍑哄簱涓�;
+            }
+
+            lockInfo.Operator = App.User.UserName;
             await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
+
+            _logger.LogInformation($"鎭㈠閿佸畾淇℃伅 - 閿佸畾ID: {lockInfo.Id}, 鎵e噺鎷i�夋暟閲�: {cancelQty}, 鏂板凡鎷i�夋暟閲�: {lockInfo.PickedQty}");
 
             // 鎭㈠搴撳瓨
             var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
@@ -869,36 +1062,57 @@
             {
                 stockDetail.StockQuantity += cancelQty;
                 stockDetail.OutboundQuantity = stockDetail.StockQuantity;
-                stockDetail.Status = StockStatusEmun.鍑哄簱閿佸畾.ObjToInt();
+
+                // 鎭㈠搴撳瓨鐘舵��
+                if (stockDetail.Status == StockStatusEmun.鍑哄簱瀹屾垚.ObjToInt())
+                {
+                    stockDetail.Status = StockStatusEmun.鍑哄簱閿佸畾.ObjToInt();
+                }
+
                 await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+
+                _logger.LogInformation($"鎭㈠搴撳瓨 - 鏉$爜: {stockDetail.Barcode}, 鎭㈠鏁伴噺: {cancelQty}, " +
+                                      $"鏂板簱瀛�: {stockDetail.StockQuantity}, 鏂扮姸鎬�: {stockDetail.Status}");
+            }
+            else
+            {
+                _logger.LogWarning($"鏈壘鍒板簱瀛樿褰� - 鏉$爜: {pickingRecord.Barcode}, 搴撳瓨ID: {pickingRecord.StockId}");
             }
         }
-
         private async Task UpdateOrderDetailOnCancel(int orderDetailId, decimal cancelQty)
         {
-            // 鑾峰彇鏈�鏂扮殑璁㈠崟鏄庣粏鏁版嵁
+            // 鑾峰彇鏈�鏂扮殑璁㈠崟鏄庣粏鏁版嵁锛堝甫閿侊級
             var currentOrderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                .With(SqlWith.RowLock)
                 .FirstAsync(x => x.Id == orderDetailId);
 
             decimal newOverOutQuantity = currentOrderDetail.OverOutQuantity - cancelQty;
             decimal newPickedQty = currentOrderDetail.PickedQty - cancelQty;
 
-            // 妫�鏌ュ彇娑堝悗鏁伴噺涓嶄細涓鸿礋鏁�
-            if (newOverOutQuantity < 0 || newPickedQty < 0)
-            {
-                throw new Exception($"鍙栨秷鍒嗘嫞灏嗗鑷村凡鍑哄簱鏁伴噺({newOverOutQuantity})鎴栧凡鎷i�夋暟閲�({newPickedQty})涓鸿礋鏁�");
-            }
+            // 涓ユ牸妫�鏌ュ彇娑堝悗鏁伴噺涓嶄細涓鸿礋鏁�
+            if (newOverOutQuantity < 0)
+                throw new Exception($"鍙栨秷鍒嗘嫞灏嗗鑷村凡鍑哄簱鏁伴噺({newOverOutQuantity})涓鸿礋鏁�");
 
-            await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
+            if (newPickedQty < 0)
+                throw new Exception($"鍙栨秷鍒嗘嫞灏嗗鑷村凡鎷i�夋暟閲�({newPickedQty})涓鸿礋鏁�");
+
+            // 鏇存柊璁㈠崟鏄庣粏
+            var updateResult = await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
                 .SetColumns(it => new Dt_OutboundOrderDetail
                 {
                     PickedQty = newPickedQty,
-                    OverOutQuantity = newOverOutQuantity,
+                    OverOutQuantity = newOverOutQuantity
                 })
                 .Where(it => it.Id == orderDetailId)
                 .ExecuteCommandAsync();
-        }
 
+            if (updateResult <= 0)
+                throw new Exception("鏇存柊璁㈠崟鏄庣粏澶辫触");
+
+            _logger.LogInformation($"鏇存柊璁㈠崟鏄庣粏 - OrderDetailId: {orderDetailId}, " +
+                                  $"鎵e噺宸插嚭搴�: {cancelQty}, 鏂板凡鍑哄簱: {newOverOutQuantity}, " +
+                                  $"鎵e噺宸叉嫞閫�: {cancelQty}, 鏂板凡鎷i��: {newPickedQty}");
+        }
         #endregion
 
         #region 鍥炲簱鎿嶄綔绉佹湁鏂规硶
@@ -942,58 +1156,6 @@
             return task;
         }
 
-        private async Task<ReturnAnalysisResult> AnalyzeReturnItems(string orderNo, string palletCode, int stockId)
-        {
-            var result = new ReturnAnalysisResult();
-
-            // 鎯呭喌1锛氳幏鍙栨湭鍒嗘嫞鐨勫嚭搴撻攣瀹氳褰�
-            var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                .Where(it => it.OrderNo == orderNo &&
-                           it.PalletCode == palletCode &&
-                           it.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
-                .ToListAsync();
-
-            if (remainingLocks.Any())
-            {
-                result.HasRemainingLocks = true;
-                result.RemainingLocks = remainingLocks;
-                result.RemainingLocksReturnQty = remainingLocks.Sum(x => x.AssignQuantity - x.PickedQty);
-            }
-
-            // 鎯呭喌2锛氭鏌ユ墭鐩樹笂鏄惁鏈夊叾浠栧簱瀛樿揣鐗�
-            var palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                .Where(it => it.StockId == stockId &&
-                            (it.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt() ||
-                             it.Status == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt() ||
-                             it.Status == StockStatusEmun.鍑哄簱閿佸畾.ObjToInt()))
-                .Where(it => it.StockQuantity > 0)
-                .ToListAsync();
-
-            if (palletStockGoods.Any())
-            {
-                result.HasPalletStockGoods = true;
-                result.PalletStockGoods = palletStockGoods;
-                result.PalletStockReturnQty = palletStockGoods.Sum(x => x.StockQuantity);
-            }
-
-            // 鎯呭喌3锛氭鏌ユ媶鍖呰褰�
-            var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
-                .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode && !it.IsReverted && it.Status != (int)SplitPackageStatusEnum.宸插洖搴�)
-                .ToListAsync();
-
-            if (splitRecords.Any())
-            {
-                result.HasSplitRecords = true;
-                result.SplitRecords = splitRecords;
-                result.SplitReturnQty = await CalculateSplitReturnQuantity(splitRecords, stockId);
-            }
-
-            result.TotalReturnQty = result.RemainingLocksReturnQty + result.PalletStockReturnQty + result.SplitReturnQty;
-            result.HasItemsToReturn = result.TotalReturnQty > 0;
-
-            return result;
-        }
-
         private async Task<decimal> CalculateSplitReturnQuantity(List<Dt_SplitPackageRecord> splitRecords, int stockId)
         {
             decimal totalQty = 0;
@@ -1001,11 +1163,14 @@
 
             foreach (var splitRecord in splitRecords)
             {
+                if (splitRecord.Status != (int)SplitPackageStatusEnum.宸叉挙閿�)
+                    continue;
                 // 妫�鏌ュ師鏉$爜
                 if (!processedBarcodes.Contains(splitRecord.OriginalBarcode))
                 {
                     var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                        .Where(it => it.Barcode == splitRecord.OriginalBarcode && it.StockId == stockId)
+                        .Where(it => it.Barcode == splitRecord.OriginalBarcode && it.StockId == stockId &&
+                           it.Status != StockStatusEmun.鍑哄簱瀹屾垚.ObjToInt())
                         .FirstAsync();
 
                     if (originalStock != null && originalStock.StockQuantity > 0)
@@ -1019,7 +1184,7 @@
                 if (!processedBarcodes.Contains(splitRecord.NewBarcode))
                 {
                     var newStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                        .Where(it => it.Barcode == splitRecord.NewBarcode && it.StockId == stockId)
+                        .Where(it => it.Barcode == splitRecord.NewBarcode && it.StockId == stockId && it.Status != StockStatusEmun.鍑哄簱瀹屾垚.ObjToInt())
                         .FirstAsync();
 
                     if (newStock != null && newStock.StockQuantity > 0)
@@ -1033,51 +1198,109 @@
             return totalQty;
         }
 
-        private async Task<WebResponseContent> HandleNoReturnItems(string orderNo, string palletCode,Dt_Task originalTask)
+        private async Task<WebResponseContent> HandleNoReturnItems(string orderNo, string palletCode, Dt_Task originalTask, int stockInfoId)
         {
             // 妫�鏌ユ槸鍚︽墍鏈夎揣鐗╅兘宸叉嫞閫夊畬鎴�
-            var allPicked = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode)
-                .AnyAsync(it => it.Status == (int)OutLockStockStatusEnum.鎷i�夊畬鎴�);
+            //var allPicked = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+            //    .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode)
+            //    .AnyAsync(it => it.Status == (int)OutLockStockStatusEnum.鎷i�夊畬鎴�);
 
-            if (allPicked)
+            //if (allPicked)
+            //{
+            //    // 鍒犻櫎鍘熷鍑哄簱浠诲姟 缁勭┖鐩�   绌虹洏鍥炲簱 
+            //    //await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync();
+            //    return WebResponseContent.Instance.OK("鎵�鏈夎揣鐗╁凡鎷i�夊畬鎴愶紝鎵樼洏涓虹┖");
+            //}
+            //else
+            //{
+            //    // 鍒犻櫎鍘熷鍑哄簱浠诲姟
+            //    //await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync();
+            //    return WebResponseContent.Instance.Error("娌℃湁闇�瑕佸洖搴撶殑鍓╀綑璐х墿");
+            //}
+            try
             {
-                // 鍒犻櫎鍘熷鍑哄簱浠诲姟
-                await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync();
-                return WebResponseContent.Instance.OK("鎵�鏈夎揣鐗╁凡鎷i�夊畬鎴愶紝鎵樼洏涓虹┖");
+                var locationtype = 0;
+                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
+                        .Where(x => x.PalletCode == palletCode)
+                        .FirstAsync();
+
+                if (stockInfo == null)
+                {
+                    var firstLocation = await _locationInfoService.Db.Queryable<Dt_LocationInfo>().FirstAsync(x => x.LocationCode == originalTask.SourceAddress);
+                    locationtype = firstLocation?.LocationType ?? 1;
+                }
+                else
+                {
+                    locationtype = stockInfo.LocationType;
+                    _stockInfoService.DeleteData(stockInfo);
+                }
+
+                var targetAddress = originalTask.TargetAddress;
+
+                await CleanupZeroStockData(stockInfoId);
+
+
+                var emptystockInfo = new Dt_StockInfo() { PalletType = PalletTypeEnum.Empty.ObjToInt(), StockStatus = StockStatusEmun.缁勭洏鏆傚瓨.ObjToInt(), PalletCode = palletCode, LocationType = locationtype };
+                emptystockInfo.Details = new List<Dt_StockInfoDetail>();
+                _stockInfoService.AddMaterielGroup(emptystockInfo);
+                //绌烘墭鐩樺浣曞鐞�  杩樻湁涓�涓嚭搴撲换鍔¤澶勭悊銆�
+                originalTask.PalletType = PalletTypeEnum.Empty.ObjToInt();
+
+                await CreateReturnTaskAndHandleESS(orderNo, palletCode, originalTask, TaskTypeEnum.InEmpty, PalletTypeEnum.Empty.ObjToInt());
+
             }
-            else
+            catch (Exception ex)
             {
-                // 鍒犻櫎鍘熷鍑哄簱浠诲姟
-                await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync();
-                return WebResponseContent.Instance.Error("娌℃湁闇�瑕佸洖搴撶殑鍓╀綑璐х墿");
+                _logger.LogError($" HandleNoReturnItems  澶辫触: {ex.Message}");
+                return WebResponseContent.Instance.Error($" 鍥炲簱绌烘墭鐩樺け璐ワ紒");
             }
-            //绌烘墭鐩樺浣曞鐞�  杩樻湁涓�涓嚭搴撲换鍔¤澶勭悊銆�
-         
+            return WebResponseContent.Instance.OK("绌烘墭鐩樺洖搴撲换鍔″垱寤烘垚鍔�");
+
         }
 
         private async Task ExecuteReturnOperations(string orderNo, string palletCode, Dt_StockInfo stockInfo,
-            Dt_Task task, ReturnAnalysisResult analysis)
+            Dt_Task task, PalletStatusAnalysis analysis)
         {
             // 鎯呭喌1锛氬鐞嗘湭鍒嗘嫞鐨勫嚭搴撻攣瀹氳褰�
             if (analysis.HasRemainingLocks)
             {
                 await HandleRemainingLocksReturn(analysis.RemainingLocks, stockInfo.Id);
 
-                // 鍏抽敭锛氭洿鏂拌鍗曟槑缁嗙殑宸叉嫞閫夋暟閲�
-                await UpdateOrderDetailsOnReturn(analysis.RemainingLocks);
+                // await UpdateOrderDetailsOnReturn(analysis.RemainingLocks);
             }
 
             // 澶勭悊鎵樼洏涓婂叾浠栧簱瀛樿揣鐗�
             if (analysis.HasPalletStockGoods)
             {
-                await HandlePalletStockGoodsReturn(analysis.PalletStockGoods);
+                var validStockGoods = analysis.PalletStockGoods
+            .Where(x => x.Status != StockStatusEmun.鍑哄簱瀹屾垚.ObjToInt())
+            .ToList();
+
+                if (validStockGoods.Any())
+                {
+                    await HandlePalletStockGoodsReturn(analysis.PalletStockGoods);
+                }
+                else
+                {
+                    _logger.LogInformation("娌℃湁鏈夋晥鐨勫簱瀛樿揣鐗╅渶瑕佸洖搴�");
+                }
             }
 
             // 澶勭悊鎷嗗寘璁板綍
             if (analysis.HasSplitRecords)
             {
-                await HandleSplitRecordsReturn(analysis.SplitRecords, orderNo, palletCode);
+                var validSplitRecords = analysis.SplitRecords
+            .Where(x => x.Status != (int)SplitPackageStatusEnum.宸叉嫞閫�)
+            .ToList();
+
+                if (validSplitRecords.Any())
+                {
+                    await HandleSplitRecordsReturn(analysis.SplitRecords, orderNo, palletCode);
+                }
+                else
+                {
+                    _logger.LogInformation("娌℃湁鏈夋晥鐨勬媶鍖呰褰曢渶瑕佸鐞�");
+                }
             }
 
             // 鏇存柊搴撳瓨涓昏〃鐘舵��
@@ -1101,7 +1324,13 @@
             foreach (var lockInfo in remainingLocks)
             {
                 decimal returnQty = lockInfo.AssignQuantity - lockInfo.PickedQty;
+                if (returnQty <= 0)
+                {
+                    _logger.LogWarning($"閿佸畾璁板綍{lockInfo.Id}鏃犻渶鍥炲簱锛屽垎閰嶆暟閲�: {lockInfo.AssignQuantity}, 宸叉嫞閫�: {lockInfo.PickedQty}");
+                    continue;
+                }
 
+                _logger.LogInformation($"澶勭悊閿佸畾璁板綍鍥炲簱 - 閿佸畾ID: {lockInfo.Id}, 鏉$爜: {lockInfo.CurrentBarcode}, 鍥炲簱鏁伴噺: {returnQty}");
                 // 鏌ユ壘瀵瑰簲鐨勫簱瀛樻槑缁�
                 var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                     .Where(it => it.Barcode == lockInfo.CurrentBarcode && it.StockId == lockInfo.StockId)
@@ -1117,23 +1346,23 @@
                 else
                 {
                     // 鍒涘缓鏂扮殑搴撳瓨璁板綍
-                    var newStockDetail = new Dt_StockInfoDetail
-                    {
-                        StockId = lockInfo.StockId,
-                        MaterielCode = lockInfo.MaterielCode,
-                        MaterielName = lockInfo.MaterielName,
-                        OrderNo = lockInfo.OrderNo,
-                        BatchNo = lockInfo.BatchNo,
-                        StockQuantity = returnQty,
-                        OutboundQuantity = 0,
-                        Barcode = lockInfo.CurrentBarcode,
-                        InboundOrderRowNo = "",
-                        Status = StockStatusEmun.鍏ュ簱纭.ObjToInt(),
-                        SupplyCode = lockInfo.SupplyCode,
-                        WarehouseCode = lockInfo.WarehouseCode,
-                        Unit = lockInfo.Unit,
-                    };
-                    await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync();
+                    //var newStockDetail = new Dt_StockInfoDetail
+                    //{
+                    //    StockId = lockInfo.StockId,
+                    //    MaterielCode = lockInfo.MaterielCode,
+                    //    MaterielName = lockInfo.MaterielName,
+                    //    OrderNo = lockInfo.OrderNo,
+                    //    BatchNo = lockInfo.BatchNo,
+                    //    StockQuantity = returnQty,
+                    //    OutboundQuantity = 0,
+                    //    Barcode = lockInfo.CurrentBarcode,
+                    //    InboundOrderRowNo = "",
+                    //    Status = StockStatusEmun.鍏ュ簱纭.ObjToInt(),
+                    //    SupplyCode = lockInfo.SupplyCode,
+                    //    WarehouseCode = lockInfo.WarehouseCode,
+                    //    Unit = lockInfo.Unit,
+                    //};
+                    //await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync();
                 }
             }
         }
@@ -1176,24 +1405,42 @@
             foreach (var stockGood in palletStockGoods)
             {
                 _logger.LogInformation($"寰呭洖搴撹揣鐗� - 鏉$爜: {stockGood.Barcode}, 鏁伴噺: {stockGood.StockQuantity}, 褰撳墠鐘舵��: {stockGood.Status}");
-            
-            // 鎭㈠搴撳瓨鐘舵��
-            stockGood.OutboundQuantity = 0;
-                stockGood.Status = StockStatusEmun.鍏ュ簱纭.ObjToInt();
 
-                await _stockInfoDetailService.Db.Updateable(stockGood).ExecuteCommandAsync();
+                if (stockGood.Status != StockStatusEmun.鍑哄簱瀹屾垚.ObjToInt())
+                {
+                    stockGood.OutboundQuantity = 0;
+                    stockGood.Status = StockStatusEmun.鍏ュ簱纭.ObjToInt();
+                    await _stockInfoDetailService.Db.Updateable(stockGood).ExecuteCommandAsync();
+
+                    _logger.LogInformation($"搴撳瓨璐х墿鍥炲簱瀹屾垚 - 鏉$爜: {stockGood.Barcode}, 鏂扮姸鎬�: {stockGood.Status}");
+                }
+                else
+                {
+                    _logger.LogWarning($"璺宠繃宸插嚭搴撳畬鎴愮殑璐х墿 - 鏉$爜: {stockGood.Barcode}");
+                }
             }
         }
 
         private async Task HandleSplitRecordsReturn(List<Dt_SplitPackageRecord> splitRecords, string orderNo, string palletCode)
         {
+            var validRecords = splitRecords.Where(x => x.Status != (int)SplitPackageStatusEnum.宸叉嫞閫�).ToList();
+
+            if (!validRecords.Any())
+            {
+                _logger.LogInformation("娌℃湁闇�瑕佸洖搴撶殑鎷嗗寘璁板綍");
+                return;
+            }
+
+            _logger.LogInformation($"鏇存柊{validRecords.Count}鏉℃媶鍖呰褰曠姸鎬佷负宸插洖搴�");
+
             // 鏇存柊鎷嗗寘璁板綍鐘舵��
             await _splitPackageService.Db.Updateable<Dt_SplitPackageRecord>()
                 .SetColumns(x => new Dt_SplitPackageRecord
                 {
                     Status = (int)SplitPackageStatusEnum.宸插洖搴�,
+                    Operator = App.User.UserName
                 })
-                .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode && !x.IsReverted)
+                .Where(x => validRecords.Select(r => r.Id).Contains(x.Id))
                 .ExecuteCommandAsync();
         }
 
@@ -1212,7 +1459,7 @@
         /// <param name="originalTask"></param>
         /// <param name="analysis"></param>
         /// <returns></returns>
-        private async Task CreateReturnTaskAndHandleESS(string orderNo, string palletCode, Dt_Task originalTask, ReturnAnalysisResult analysis)
+        private async Task CreateReturnTaskAndHandleESS(string orderNo, string palletCode, Dt_Task originalTask, TaskTypeEnum taskTypeEnum, int palletType)
         {
             var firstLocation = await _locationInfoService.Db.Queryable<Dt_LocationInfo>()
                 .FirstAsync(x => x.LocationCode == originalTask.SourceAddress);
@@ -1226,22 +1473,26 @@
                 Grade = 0,
                 PalletCode = palletCode,
                 NextAddress = "",
-                OrderNo = originalTask.OrderNo,
+                // OrderNo = originalTask.OrderNo,
+                OrderNo = orderNo,
                 Roadway = newLocation.RoadwayNo,
                 SourceAddress = stations[originalTask.TargetAddress],
                 TargetAddress = newLocation.LocationCode,
                 TaskStatus = TaskStatusEnum.New.ObjToInt(),
-                TaskType = TaskTypeEnum.InPick.ObjToInt(),
-                PalletType = originalTask.PalletType,
+                TaskType = taskTypeEnum.ObjToInt(),
+                PalletType = palletType,
                 WarehouseId = originalTask.WarehouseId
 
             };
             // 淇濆瓨鍥炲簱浠诲姟
             await _taskRepository.Db.Insertable(returnTask).ExecuteCommandAsync();
-            var targetAddress = originalTask.TargetAddress;        
-         
+            var targetAddress = originalTask.TargetAddress;
+
             // 鍒犻櫎鍘熷鍑哄簱浠诲姟
-            await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync();
+            _taskRepository.DeleteAndMoveIntoHty(originalTask, OperateTypeEnum.鑷姩瀹屾垚);
+            // await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync();
+
+
 
             // 缁� ESS 鍙戦�佹祦鍔ㄤ俊鍙峰拰鍒涘缓浠诲姟
             await SendESSCommands(palletCode, targetAddress, returnTask);
@@ -1265,18 +1516,15 @@
                     containerCode = palletCode
                 });
 
-                if (moveResult)
+                //if (moveResult)
+                //{
+                // 2. 鍒涘缓鍥炲簱浠诲姟
+                var essTask = new TaskModel()
                 {
-                    // 2. 鍒涘缓鍥炲簱浠诲姟
-                    var essTask = new TaskModel()
-                    {
-                        taskType = "putaway",
-                        taskGroupCode = "",
-                        groupPriority = 0,
-                        tasks = new List<TasksType>
-                    {
-                        new()
-                        {
+                    taskType = "putaway",
+                    taskGroupCode = "",
+                    groupPriority = 0,
+                    tasks = new List<TasksType>{  new() {
                             taskCode = returnTask.TaskNum.ToString(),
                             taskPriority = 0,
                             taskDescribe = new TaskDescribeType
@@ -1289,13 +1537,12 @@
                                 deadline = 0,
                                 storageTag = ""
                             }
-                        }
-                    }
-                    };
+                        } }
+                };
 
-                    var resultTask = await _eSSApiService.CreateTaskAsync(essTask);
-                    _logger.LogInformation($"ReturnRemaining 鍒涘缓浠诲姟鎴愬姛: {resultTask}");
-                }
+                var resultTask = await _eSSApiService.CreateTaskAsync(essTask);
+                _logger.LogInformation($"ReturnRemaining 鍒涘缓浠诲姟鎴愬姛: {resultTask}");
+                //}
             }
             catch (Exception ex)
             {
@@ -1338,15 +1585,19 @@
                 if (outboundOrder.OrderStatus != newStatus)
                 {
                     await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
-                        .SetColumns(x => x.OrderStatus == newStatus)
+                        .SetColumns(x => new Dt_OutboundOrder
+                        {
+                            OrderStatus = newStatus,
+                            Operator = App.User.UserName,
+                        })
                         .Where(x => x.OrderNo == orderNo)
                         .ExecuteCommandAsync();
 
                     // 鍙湁姝e父鍒嗘嫞瀹屾垚鏃舵墠鍚慚ES鍙嶉
-                    if (allCompleted && newStatus == (int)OutOrderStatusEnum.鍑哄簱瀹屾垚)
-                    {
-                        await HandleOrderCompletion(outboundOrder, orderNo);
-                    }
+                    //if (allCompleted && newStatus == (int)OutOrderStatusEnum.鍑哄簱瀹屾垚)
+                    //{
+                    //    await HandleOrderCompletion(outboundOrder, orderNo);
+                    //}
                 }
             }
             catch (Exception ex)
@@ -1354,6 +1605,8 @@
                 _logger.LogError($"CheckAndUpdateOrderStatus澶辫触 - OrderNo: {orderNo}, Error: {ex.Message}");
             }
         }
+
+
 
         private async Task UpdateOrderStatusForReturn(string orderNo)
         {
@@ -1385,7 +1638,11 @@
                 if (outboundOrder.OrderStatus != newStatus)
                 {
                     await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
-                        .SetColumns(x => x.OrderStatus == newStatus)
+                          .SetColumns(x => new Dt_OutboundOrder
+                          {
+                              OrderStatus = newStatus,
+                              Operator = App.User.UserName,
+                          })
                         .Where(x => x.OrderNo == orderNo)
                         .ExecuteCommandAsync();
 
@@ -1401,76 +1658,480 @@
         private async Task HandleOrderCompletion(Dt_OutboundOrder outboundOrder, string orderNo)
         {
             // 璋冩嫧鍑哄簱鍜岄噸妫�鍑哄簱涓嶉渶瑕佸弽棣圡ES
-            if (outboundOrder.OrderType == OutOrderTypeEnum.Allocate.ObjToInt() ||
-                outboundOrder.OrderType == OutOrderTypeEnum.ReCheck.ObjToInt())
+            if (outboundOrder.OrderType == OutOrderTypeEnum.Allocate.ObjToInt())
             {
-                return;
-            }
-
-            try
-            {
-                var feedmodel = new FeedbackOutboundRequestModel
+                var allocate = _allocateService.Repository.QueryData(x => x.UpperOrderNo == outboundOrder.UpperOrderNo).First();
+                var feedmodel = new AllocateDto
                 {
-                    reqCode = Guid.NewGuid().ToString(),
-                    reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
-                    business_type = outboundOrder.BusinessType,
-                    factoryArea = outboundOrder.FactoryArea,
-                    operationType = 1,
+                    ReqCode = Guid.NewGuid().ToString(),
+                    ReqTime = DateTime.Now.ToString(),
+                    BusinessType = "3",
+                  
+                    FactoryArea = outboundOrder.FactoryArea,
+                    OperationType = 1,
                     Operator = App.User.UserName,
-                    orderNo = outboundOrder.UpperOrderNo,
-                    status = outboundOrder.OrderStatus,
-                    details = new List<FeedbackOutboundDetailsModel>()
-                };
+                    OrderNo = outboundOrder.UpperOrderNo,
+                   // documentsNO = outboundOrder.OrderNo,
+                   // status = outboundOrder.OrderStatus,
+                    fromWarehouse = allocate?.FromWarehouse ?? "",
+                    toWarehouse = allocate?.ToWarehouse ?? "",
+                    Details = new List<AllocateDtoDetail>()
 
+                };
                 // 鍙幏鍙栧凡鎷i�夊畬鎴愮殑閿佸畾璁板綍
                 var lists = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                     .Where(x => x.OrderNo == orderNo && x.Status == (int)OutLockStockStatusEnum.鎷i�夊畬鎴�)
                     .ToListAsync();
 
                 var groupedData = lists.GroupBy(item => new { item.MaterielCode, item.lineNo, item.Unit, item.WarehouseCode })
-                   .Select(group => new FeedbackOutboundDetailsModel
+                   .Select(group => new AllocateDtoDetail
                    {
-                       materialCode = group.Key.MaterielCode,
-                       lineNo = group.Key.lineNo,
-                       warehouseCode = group.Key.WarehouseCode,
-                       qty = group.Sum(x => x.PickedQty),
-                       currentDeliveryQty = group.Sum(x => x.PickedQty),
-                       unit = group.Key.Unit,
-                       barcodes = group.Select(row => new WIDESEA_DTO.Outbound.BarcodesModel
+                       MaterialCode = group.Key.MaterielCode,
+                       LineNo = group.Key.lineNo,
+                       WarehouseCode = group.Key.WarehouseCode,
+                       Qty = group.Sum(x => x.PickedQty),
+                      
+                       Unit = group.Key.Unit,
+                       Barcodes = group.Select(row => new BarcodeInfo
                        {
-                           barcode = row.CurrentBarcode,
-                           supplyCode = row.SupplyCode,
-                           batchNo = row.BatchNo,
-                           unit = row.Unit,
-                           qty = row.PickedQty
+                           Barcode = row.CurrentBarcode,
+                           SupplyCode = row.SupplyCode,
+                           BatchNo = row.BatchNo,
+                           Unit = row.Unit,
+                           Qty = row.PickedQty
                        }).ToList()
+
+                  
                    }).ToList();
+                feedmodel.Details = groupedData;
 
-                feedmodel.details = groupedData;
-
-                var result = await _invokeMESService.FeedbackOutbound(feedmodel);
+                var result = await _invokeMESService.FeedbackAllocate(feedmodel);
                 if (result != null && result.code == 200)
-                {
+                {                    
                     await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
-                        .SetColumns(x => x.ReturnToMESStatus == 1)
-                        .Where(x => x.OrderId == outboundOrder.Id)
-                        .ExecuteCommandAsync();
+                           .SetColumns(x => x.ReturnToMESStatus == 1)
+                           .Where(x => x.OrderId == outboundOrder.Id).ExecuteCommandAsync();
 
                     await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
-                        .SetColumns(x => x.ReturnToMESStatus == 1)
-                        .Where(x => x.OrderNo == orderNo)
-                        .ExecuteCommandAsync();
+                          .SetColumns(x => new Dt_OutboundOrder
+                          {
+                              ReturnToMESStatus = 1,
+                              Operator = App.User.UserName,
+                          }).Where(x => x.OrderNo == orderNo).ExecuteCommandAsync();
                 }
             }
-            catch (Exception ex)
+            else if (outboundOrder.OrderType == OutOrderTypeEnum.ReCheck.ObjToInt())
             {
-                _logger.LogError($"FeedbackOutbound澶辫触 - OrderNo: {orderNo}, Error: {ex.Message}");
+
+            }
+            else
+            {
+                try
+                {
+                    var feedmodel = new FeedbackOutboundRequestModel
+                    {
+                        reqCode = Guid.NewGuid().ToString(),
+                        reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
+                        business_type = outboundOrder.BusinessType,
+                        factoryArea = outboundOrder.FactoryArea,
+                        operationType = 1,
+                        Operator = App.User.UserName,
+                        orderNo = outboundOrder.UpperOrderNo,
+                        documentsNO = outboundOrder.OrderNo,
+                        status = outboundOrder.OrderStatus,
+                        details = new List<FeedbackOutboundDetailsModel>()
+                    };
+
+                    // 鍙幏鍙栧凡鎷i�夊畬鎴愮殑閿佸畾璁板綍
+                    var lists = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                        .Where(x => x.OrderNo == orderNo && x.Status == (int)OutLockStockStatusEnum.鎷i�夊畬鎴�)
+                        .ToListAsync();
+
+                    var groupedData = lists.GroupBy(item => new { item.MaterielCode, item.lineNo, item.Unit, item.WarehouseCode })
+                       .Select(group => new FeedbackOutboundDetailsModel
+                       {
+                           materialCode = group.Key.MaterielCode,
+                           lineNo = group.Key.lineNo,
+                           warehouseCode = group.Key.WarehouseCode,
+                           qty = group.Sum(x => x.PickedQty),
+                           currentDeliveryQty = group.Sum(x => x.PickedQty),
+                           unit = group.Key.Unit,
+                           barcodes = group.Select(row => new WIDESEA_DTO.Outbound.BarcodesModel
+                           {
+                               barcode = row.CurrentBarcode,
+                               supplyCode = row.SupplyCode,
+                               batchNo = row.BatchNo,
+                               unit = row.Unit,
+                               qty = row.PickedQty
+                           }).ToList()
+                       }).ToList();
+
+                    feedmodel.details = groupedData;
+
+                    var result = await _invokeMESService.FeedbackOutbound(feedmodel);
+                    if (result != null && result.code == 200)
+                    {
+                        await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
+                            .SetColumns(x => x.ReturnToMESStatus == 1)
+                            .Where(x => x.OrderId == outboundOrder.Id)
+                            .ExecuteCommandAsync();
+
+                        await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
+                              .SetColumns(x => new Dt_OutboundOrder
+                              {
+                                  ReturnToMESStatus = 1,
+                                  Operator = App.User.UserName,
+                              })
+
+                            .Where(x => x.OrderNo == orderNo)
+                            .ExecuteCommandAsync();
+                    }
+
+                    _logger.LogError($"FeedbackOutbound鎴愬姛 - OrderNo: {orderNo}, {JsonSerializer.Serialize(result)}");
+                }
+                catch (Exception ex)
+                {
+                    _logger.LogError($"FeedbackOutbound澶辫触 - OrderNo: {orderNo}, Error: {ex.Message}");
+                }
             }
         }
 
         #endregion
 
+        #region 绌烘墭鐩�
+
+        /// <summary>
+        /// 娓呯悊闆跺簱瀛樻暟鎹�
+        /// </summary>
+        private async Task CleanupZeroStockData(int stockId)
+        {
+            try
+            {
+                // 1. 鍒犻櫎搴撳瓨鏁伴噺涓�0鐨勬槑缁嗚褰�
+                var deleteDetailCount = await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>()
+                    .Where(x => x.StockId == stockId && x.StockQuantity == 0 && (x.Status == StockStatusEmun.鍑哄簱瀹屾垚.ObjToInt() || x.Status ==
+                                          StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt()))
+                    .ExecuteCommandAsync();
+
+                await _stockInfoService.Db.Deleteable<Dt_StockInfo>()
+                   .Where(x => x.Id == stockId).ExecuteCommandAsync();
+
+                _logger.LogInformation($"娓呯悊闆跺簱瀛樻槑缁嗚褰� - StockId: {stockId}, 鍒犻櫎璁板綍鏁�: {deleteDetailCount}");
+
+
+
+            }
+            catch (Exception ex)
+            {
+                _logger.LogWarning($"娓呯悊闆跺簱瀛樻暟鎹け璐� - StockId: {stockId}, Error: {ex.Message}");
+                // 娉ㄦ剰锛氭竻鐞嗗け璐ヤ笉搴旇褰卞搷涓绘祦绋�
+            }
+        }
+        /// <summary>
+        /// 澶勭悊浠诲姟娓呯悊锛堟寜璁㈠崟鍜屾墭鐩橈級
+        /// </summary>
+        private async Task HandleTaskCleanup(string orderNo, string palletCode)
+        {
+            try
+            {
+                // 1. 鏌ユ壘鎵�鏈変笌璇ヨ鍗曞拰鎵樼洏鐩稿叧鐨勪换鍔�
+                var tasks = await _taskRepository.Db.Queryable<Dt_Task>().Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode).ToListAsync();
+
+                if (tasks.Any())
+                {
+                    foreach (var task in tasks)
+                    {
+                        task.TaskStatus = (int)TaskStatusEnum.Finish;
+                    }
+                    // await _taskRepository.Db.Updateable(tasks).ExecuteCommandAsync();
+
+                    _taskRepository.DeleteAndMoveIntoHty(tasks, OperateTypeEnum.鑷姩瀹屾垚);
+                    _logger.LogInformation($"瀹屾垚{tasks.Count}涓墭鐩樹换鍔� - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}");
+                }
+
+            }
+            catch (Exception ex)
+            {
+                _logger.LogWarning($"澶勭悊浠诲姟娓呯悊澶辫触 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
+                throw new Exception($"浠诲姟娓呯悊澶辫触: {ex.Message}");
+            }
+        }
+        /// <summary>
+        /// 鏇存柊璁㈠崟鐩稿叧鏁版嵁
+        /// </summary>
+        private async Task UpdateOrderData(string orderNo, string palletCode)
+        {
+            try
+            {
+                // 妫�鏌ヨ鍗曟槸鍚﹁繕鏈夊叾浠栨墭鐩樺湪澶勭悊涓�
+                var otherActivePallets = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                    .Where(x => x.OrderNo == orderNo &&
+                               x.PalletCode != palletCode &&
+                             (x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓� || x.Status == (int)OutLockStockStatusEnum.鍥炲簱涓�))
+                    .AnyAsync();
+
+                var otherActiveTasks = await _taskRepository.Db.Queryable<Dt_Task>()
+                    .Where(x => x.OrderNo == orderNo &&
+                               x.PalletCode != palletCode
+                    // && x.TaskStatus.In((int)TaskStatusEnum.寰呮墽琛�, (int)TaskStatusEnum.鎵ц涓�)
+                     )
+                    .AnyAsync();
+
+                // 濡傛灉娌℃湁鍏朵粬鎵樼洏鍦ㄥ鐞嗭紝妫�鏌ヨ鍗曟槸鍚﹀簲璇ュ畬鎴�
+                if (!otherActivePallets && !otherActiveTasks)
+                {
+                    await CheckAndUpdateOrderCompletion(orderNo);
+                }
+                else
+                {
+                    _logger.LogInformation($"璁㈠崟 {orderNo} 杩樻湁鍏朵粬鎵樼洏鍦ㄥ鐞嗭紝涓嶆洿鏂拌鍗曠姸鎬�");
+                }
+
+                // 3. 鏇存柊鎷i�夎褰曠姸鎬侊紙鍙�夛級
+                await UpdatePickingRecordsStatus(orderNo, palletCode);
+
+            }
+            catch (Exception ex)
+            {
+                _logger.LogWarning($"鏇存柊璁㈠崟鏁版嵁澶辫触 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
+                throw new Exception($"鏇存柊璁㈠崟鏁版嵁澶辫触: {ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 妫�鏌ュ苟鏇存柊璁㈠崟瀹屾垚鐘舵��
+        /// </summary>
+        private async Task CheckAndUpdateOrderCompletion(string orderNo)
+        {
+            var orderDetails = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                .LeftJoin<Dt_OutboundOrder>((o, item) => o.OrderId == item.Id)
+                .Where((o, item) => item.OrderNo == orderNo)
+                .Select((o, item) => o)
+                .ToListAsync();
+
+            bool allCompleted = true;
+            foreach (var detail in orderDetails)
+            {
+                if (detail.OverOutQuantity < detail.NeedOutQuantity)
+                {
+                    allCompleted = false;
+                    break;
+                }
+            }
+
+            var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
+                .FirstAsync(x => x.OrderNo == orderNo);
+
+            if (outboundOrder != null && allCompleted && outboundOrder.OrderStatus != (int)OutOrderStatusEnum.鍑哄簱瀹屾垚)
+            {
+                outboundOrder.OrderStatus = (int)OutOrderStatusEnum.鍑哄簱瀹屾垚;
+                outboundOrder.Operator = App.User.UserName;
+                await _outboundOrderService.Db.Updateable(outboundOrder).ExecuteCommandAsync();
+
+                _logger.LogInformation($"璁㈠崟 {orderNo} 宸叉爣璁颁负鍑哄簱瀹屾垚");
+
+                // 鍚慚ES鍙嶉璁㈠崟瀹屾垚锛堝鏋滈渶瑕侊級
+                await HandleOrderCompletion(outboundOrder, orderNo);
+            }
+        }
+
+        /// <summary>
+        /// 鏇存柊鎷i�夎褰曠姸鎬�
+        /// </summary>
+        private async Task UpdatePickingRecordsStatus(string orderNo, string palletCode)
+        {
+            try
+            {
+                // 鍙互灏嗙浉鍏崇殑鎷i�夎褰曟爣璁颁负宸插畬鎴�
+                var pickingRecords = await Db.Queryable<Dt_PickingRecord>()
+                    .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode)
+                    .ToListAsync();
+
+                // 杩欓噷鍙互鏍规嵁闇�瑕佹洿鏂版嫞閫夎褰曠殑鐘舵�佸瓧娈�
+                // 渚嬪锛歱ickingRecord.Status = (int)PickingStatusEnum.宸插畬鎴�;
+
+                _logger.LogInformation($"鎵惧埌{pickingRecords.Count}鏉℃嫞閫夎褰� - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}");
+
+            }
+            catch (Exception ex)
+            {
+                _logger.LogWarning($"鏇存柊鎷i�夎褰曠姸鎬佸け璐�: {ex.Message}");
+            }
+        }
+        #endregion
+
+
+
         #region 杈呭姪鏂规硶
+        /// <summary>
+        /// 缁熶竴鍒嗘瀽鎵樼洏鐘舵�� - 杩斿洖鎵樼洏鐨勫畬鏁寸姸鎬佷俊鎭�
+        /// </summary>
+        private async Task<PalletStatusAnalysis> AnalyzePalletStatus(string orderNo, string palletCode, int stockId)
+        {
+            var result = new PalletStatusAnalysis
+            {
+                OrderNo = orderNo,
+                PalletCode = palletCode,
+                StockId = stockId
+            };
+
+            // 鍒嗘瀽鏈垎鎷g殑鍑哄簱閿佸畾璁板綍
+            var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(it => it.OrderNo == orderNo &&
+                           it.PalletCode == palletCode &&
+                           it.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
+                .ToListAsync();
+
+            if (remainingLocks.Any())
+            {
+                result.HasRemainingLocks = true;
+                result.RemainingLocks = remainingLocks;
+                result.RemainingLocksReturnQty = remainingLocks.Sum(x => x.AssignQuantity - x.PickedQty);
+                _logger.LogInformation($"鍙戠幇{remainingLocks.Count}鏉℃湭鍒嗘嫞閿佸畾璁板綍锛屾�绘暟閲�: {result.RemainingLocksReturnQty}");
+            }
+
+            // 鍒嗘瀽鎵樼洏涓婄殑搴撳瓨璐х墿
+            var palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(it => it.StockId == stockId &&
+                     (it.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt() ||
+                      it.Status == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt() ||
+                      it.Status == StockStatusEmun.鍑哄簱閿佸畾.ObjToInt()))
+                .Where(it => it.StockQuantity > 0)
+                .ToListAsync();
+
+            if (palletStockGoods.Any())
+            {
+                result.HasPalletStockGoods = true;
+                result.PalletStockGoods = palletStockGoods;
+                result.PalletStockReturnQty = palletStockGoods.Sum(x => x.StockQuantity);
+                _logger.LogInformation($"鍙戠幇{palletStockGoods.Count}涓簱瀛樿揣鐗╋紝鎬绘暟閲�: {result.PalletStockReturnQty}");
+
+                // 璁板綍璇︾粏鐘舵�佸垎甯�
+                var statusGroups = palletStockGoods.GroupBy(x => x.Status);
+                foreach (var group in statusGroups)
+                {
+                    _logger.LogInformation($"搴撳瓨鐘舵�亄group.Key}: {group.Count()}涓揣鐗╋紝鏁伴噺: {group.Sum(x => x.StockQuantity)}");
+                }
+            }
+
+            //鍒嗘瀽鎷嗗寘璁板綍
+            var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
+                .Where(it => it.OrderNo == orderNo &&
+                           it.PalletCode == palletCode &&
+                           !it.IsReverted && it.Status != (int)SplitPackageStatusEnum.宸叉嫞閫� &&
+                           it.Status != (int)SplitPackageStatusEnum.宸插洖搴�)
+                .ToListAsync();
+
+            if (splitRecords.Any())
+            {
+                result.HasSplitRecords = true;
+                result.SplitRecords = splitRecords;
+                result.SplitReturnQty = await CalculateSplitReturnQuantity(splitRecords, stockId);
+
+                _logger.LogInformation($"鍙戠幇{splitRecords.Count}鏉℃湭鎷i�夋媶鍖呰褰曪紝鎬绘暟閲�: {result.SplitReturnQty}");
+            }
+
+            // 4. 璁$畻鎬诲洖搴撴暟閲忓拰绌烘墭鐩樼姸鎬�
+            result.TotalReturnQty = result.RemainingLocksReturnQty + result.PalletStockReturnQty + result.SplitReturnQty;
+            result.HasItemsToReturn = result.TotalReturnQty > 0;
+            result.IsEmptyPallet = !result.HasItemsToReturn;
+
+            // 5. 妫�鏌ユ槸鍚︽湁杩涜涓殑浠诲姟
+            result.HasActiveTasks = await _taskRepository.Db.Queryable<Dt_Task>()
+                .Where(x => x.OrderNo == orderNo && x.TaskType == TaskTypeEnum.InPick.ObjToInt() &&
+                           x.PalletCode == palletCode &&
+                           x.TaskStatus == (int)TaskStatusEnum.New)
+                .AnyAsync();
+
+            _logger.LogInformation($"鎵樼洏鐘舵�佸垎鏋愬畬鎴� - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}, " +
+                                  $"鎬诲洖搴撴暟閲�: {result.TotalReturnQty}, 鏄惁绌烘墭鐩�: {result.IsEmptyPallet}, " +
+                                  $"鏈夎繘琛屼腑浠诲姟: {result.HasActiveTasks}");
+
+            return result;
+        }
+
+        /// <summary>
+        /// 妫�鏌ユ墭鐩樻槸鍚︿负绌� 
+        /// </summary>
+        private async Task<bool> IsPalletEmpty(string orderNo, string palletCode)
+        {
+            try
+            {
+                // 鑾峰彇搴撳瓨淇℃伅
+                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
+                    .Where(x => x.PalletCode == palletCode)
+                    .FirstAsync();
+
+                if (stockInfo == null)
+                    return false;
+
+                // 浣跨敤缁熶竴鐨勭姸鎬佸垎鏋�
+                var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id);
+                return statusAnalysis.IsEmptyPallet;
+            }
+            catch (Exception ex)
+            {
+                _logger.LogWarning($"妫�鏌ユ墭鐩樻槸鍚︿负绌哄け璐� - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
+                return false;
+            }
+        }
+        /// <summary>
+        /// 妫�鏌ュ苟澶勭悊绌烘墭鐩� 
+        /// </summary>
+        private async Task<bool> CheckAndHandleEmptyPallet(string orderNo, string palletCode)
+        {
+            try
+            {
+                // 1. 鑾峰彇搴撳瓨淇℃伅
+                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
+                    .Where(x => x.PalletCode == palletCode)
+                    .FirstAsync();
+
+                if (stockInfo == null)
+                {
+                    _logger.LogWarning($"鏈壘鍒版墭鐩� {palletCode} 鐨勫簱瀛樹俊鎭�");
+                    return false;
+                }
+
+                // 2. 浣跨敤缁熶竴鐨勭姸鎬佸垎鏋�
+                var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id);
+
+                // 3. 妫�鏌ユ槸鍚︿负绌烘墭鐩樹笖娌℃湁杩涜涓殑浠诲姟
+                if (!statusAnalysis.IsEmptyPallet || statusAnalysis.HasActiveTasks)
+                {
+                    return false;
+                }
+
+                _logger.LogInformation($"妫�娴嬪埌绌烘墭鐩橈紝寮�濮嬭嚜鍔ㄥ鐞� - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}");
+
+                //// 娓呯悊闆跺簱瀛樻暟鎹�
+                //await CleanupZeroStockData(stockInfo.Id);
+
+                //// 鏇存柊搴撳瓨涓昏〃鐘舵�佷负绌烘墭鐩�
+                //await UpdateStockInfoAsEmpty(stockInfo);
+
+                //// 澶勭悊鍑哄簱閿佸畾璁板綍
+                //await HandleOutStockLockRecords(orderNo, palletCode);
+
+                //// 澶勭悊浠诲姟鐘舵��
+                //await HandleTaskStatusForEmptyPallet(orderNo, palletCode);
+
+                //// 鏇存柊璁㈠崟鏁版嵁
+                //await UpdateOrderDataForEmptyPallet(orderNo, palletCode);
+
+                ////璁板綍鎿嶄綔鍘嗗彶
+                //await RecordAutoEmptyPalletOperation(orderNo, palletCode);
+
+                _logger.LogInformation($"绌烘墭鐩樿嚜鍔ㄥ鐞嗗畬鎴� - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}");
+
+                return true;
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError($"鑷姩澶勭悊绌烘墭鐩樺け璐� - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
+                return false;
+            }
+        }
 
         private async Task<string> GenerateNewBarcode()
         {
@@ -1503,10 +2164,10 @@
                 OriginalLockQuantity = quantity,
                 IsSplitted = 1,
                 ParentLockId = originalLock.Id,
-                Operator=  App.User.UserName,
-                FactoryArea=originalLock.FactoryArea,
-                lineNo=originalLock.lineNo,
-                WarehouseCode=originalLock.WarehouseCode,
+                Operator = App.User.UserName,
+                FactoryArea = originalLock.FactoryArea,
+                lineNo = originalLock.lineNo,
+                WarehouseCode = originalLock.WarehouseCode,
 
             };
 
@@ -1611,7 +2272,7 @@
             }
             return WebResponseContent.Instance.OK("鎷i�夌‘璁ゆ垚鍔�", new { SplitResults = new List<SplitResult>() });
         }
- 
+
         #endregion
     }
 
@@ -1665,6 +2326,56 @@
         public List<Dt_StockInfoDetail> PalletStockGoods { get; set; } = new List<Dt_StockInfoDetail>();
         public List<Dt_SplitPackageRecord> SplitRecords { get; set; } = new List<Dt_SplitPackageRecord>();
     }
+    public class PalletStatusAnalysis
+    {
+        public string OrderNo { get; set; }
+        public string PalletCode { get; set; }
+        public int StockId { get; set; }
 
+        // 鍥炲簱鐩稿叧灞炴��
+        public bool HasItemsToReturn { get; set; }
+        public bool HasRemainingLocks { get; set; }
+        public bool HasPalletStockGoods { get; set; }
+        public bool HasSplitRecords { get; set; }
+        public decimal RemainingLocksReturnQty { get; set; }
+        public decimal PalletStockReturnQty { get; set; }
+        public decimal SplitReturnQty { get; set; }
+        public decimal TotalReturnQty { get; set; }
+        public List<Dt_OutStockLockInfo> RemainingLocks { get; set; } = new List<Dt_OutStockLockInfo>();
+        public List<Dt_StockInfoDetail> PalletStockGoods { get; set; } = new List<Dt_StockInfoDetail>();
+        public List<Dt_SplitPackageRecord> SplitRecords { get; set; } = new List<Dt_SplitPackageRecord>();
+
+        // 绌烘墭鐩樼浉鍏冲睘鎬�
+        public bool IsEmptyPallet { get; set; }
+        public bool HasActiveTasks { get; set; }
+
+        // 渚垮埄鏂规硶
+        public bool CanReturn => HasItemsToReturn && !HasActiveTasks;
+        public bool CanRemove => IsEmptyPallet && !HasActiveTasks;
+    }
+    public class PickingContext
+    {
+        public string OrderNo { get; set; }
+        public string PalletCode { get; set; }
+        public string Barcode { get; set; }
+        public string Operator { get; set; }
+        public Dt_OutStockLockInfo LockInfo { get; set; }
+        public Dt_OutboundOrderDetail OrderDetail { get; set; }
+        public Dt_StockInfoDetail StockDetail { get; set; }
+        public decimal ActualQuantity { get; set; }
+        public string AdjustedReason { get; set; }
+    }
+    public class CancelPickingContext
+    {
+        public string OrderNo { get; set; }
+        public string PalletCode { get; set; }
+        public string Barcode { get; set; }
+        public string Operator { get; set; }
+
+        public decimal CancelQuantity { get; set; }
+        public Dt_PickingRecord PickingRecord { get; set; }
+        public Dt_OutStockLockInfo LockInfo { get; set; }
+        public Dt_OutboundOrderDetail OrderDetail { get; set; }
+    }
     #endregion
 }

--
Gitblit v1.9.3