From 0f354b1feb21d6812e054a0531d0978ebbdca479 Mon Sep 17 00:00:00 2001
From: pan <antony1029@163.com>
Date: 星期一, 24 十一月 2025 11:57:32 +0800
Subject: [PATCH] 提交

---
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs | 2297 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 1,984 insertions(+), 313 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 5a87c34..14ac400 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"
@@ -1,14 +1,27 @@
-锘縰sing System;
+锘縰sing Dm.filter;
+using MailKit.Search;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+using SqlSugar;
+using System;
 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;
+using WIDESEA_Common.TaskEnum;
 using WIDESEA_Core;
 using WIDESEA_Core.BaseRepository;
 using WIDESEA_Core.BaseServices;
+using WIDESEA_Core.Enums;
+using WIDESEA_Core.Helper;
+using WIDESEA_DTO.Basic;
+using WIDESEA_DTO.Inbound;
 using WIDESEA_DTO.Outbound;
 using WIDESEA_IBasicService;
 using WIDESEA_IOutboundService;
@@ -31,10 +44,33 @@
         private readonly IStockInfoDetailService _stockInfoDetailService;
         private readonly ILocationInfoService _locationInfoService;
         private readonly IOutboundOrderDetailService _outboundOrderDetailService;
+        private readonly IOutboundOrderService _outboundOrderService;
         private readonly ISplitPackageService _splitPackageService;
- 
+        private readonly IRepository<Dt_Task> _taskRepository;
+        private readonly IESSApiService _eSSApiService;
+        private readonly IInvokeMESService _invokeMESService;
+        private readonly IDailySequenceService _dailySequenceService;
 
-        public OutboundPickingService(IRepository<Dt_PickingRecord> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockInfoService stockInfoService, IStockService stockService, IOutStockLockInfoService outStockLockInfoService, IStockInfoDetailService stockInfoDetailService, ILocationInfoService locationInfoService, IOutboundOrderDetailService outboundOrderDetailService, ISplitPackageService splitPackageService) : base(BaseDal)
+        private readonly ILogger<OutboundPickingService> _logger;
+
+        private Dictionary<string, string> stations = new Dictionary<string, string>
+        {
+            {"2-1","2-9" },
+            {"3-1","3-9" },
+
+        };
+
+        private Dictionary<string, string> movestations = new Dictionary<string, string>
+        {
+            {"2-1","2-5" },
+            {"3-1","3-5" },
+
+        };
+
+        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)
         {
             _unitOfWorkManage = unitOfWorkManage;
             _stockInfoService = stockInfoService;
@@ -44,384 +80,2019 @@
             _locationInfoService = locationInfoService;
             _outboundOrderDetailService = outboundOrderDetailService;
             _splitPackageService = splitPackageService;
+            _outboundOrderService = outboundOrderService;
+            _taskRepository = taskRepository;
+            _eSSApiService = eSSApiService;
+            _logger = logger;
+            _invokeMESService = invokeMESService;
+            _dailySequenceService = dailySequenceService;
         }
 
-        public async Task<WebResponseContent> ValidateBarcode(string barcode)
+
+        #region 鏌ヨ鏂规硶
+        // 鑾峰彇鏈嫞閫夊垪琛�
+        public async Task<List<Dt_OutStockLockInfo>> GetUnpickedList(string orderNo, string palletCode)
         {
-            try
-            {
-                if (string.IsNullOrEmpty(barcode))
-                {
-                    return WebResponseContent.Instance.Error("鏉$爜涓嶈兘涓虹┖");
-                }
-
-                // 鏍规嵁鏉$爜鏌ヨ搴撳瓨鏄庣粏
-                var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                    .Includes(x => x.StockInfo)
-                    .Where(x => x.Barcode == barcode)
-                    .FirstAsync();
-
-                if (stockDetail == null)
-                {
-                    return WebResponseContent.Instance.Error("鏉$爜涓嶅瓨鍦�");
-                }
-
-                
-
-                var result = new
-                {
-                    Barcode = barcode,
-                    MaterielCode = stockDetail.MaterielCode,
-                 
-                    BatchNo = stockDetail.BatchNo,
-                    AvailableQuantity = stockDetail.StockQuantity - stockDetail.OutboundQuantity,
-                    LocationCode = stockDetail.StockInfo?.LocationCode,
-                    PalletCode = stockDetail.StockInfo?.PalletCode
-                };
-
-                return WebResponseContent.Instance.OK(null, result);
-            }
-            catch (Exception ex)
-            {
-                return WebResponseContent.Instance.Error($"鏉$爜楠岃瘉澶辫触: {ex.Message}");
-            }
+            var list = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(x => x.OrderNo == orderNo &&
+                           x.PalletCode == palletCode &&
+                           x.Status == 1)
+                .ToListAsync();
+            return list.Where(x => x.RemainQuantity > 0).ToList();
         }
 
+        // 鑾峰彇宸叉嫞閫夊垪琛�
+        public async Task<List<Dt_OutStockLockInfo>> GetPickedList(string orderNo, string palletCode)
+        {
+            var list = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(x => x.OrderNo == orderNo &&
+                           x.PalletCode == palletCode &&
+                           x.Status == 6)
+                .ToListAsync();
+            return list;
+        }
+        // 鑾峰彇鎷i�夋眹鎬�
+        public async Task<object> GetPickingSummary(ConfirmPickingDto dto)
+        {
+            var picked = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+             .WhereIF(!string.IsNullOrEmpty(dto.OrderNo), x => x.OrderNo == dto.OrderNo)
+             .WhereIF(!string.IsNullOrEmpty(dto.PalletCode), x => x.PalletCode == dto.PalletCode)
+             .Where(x => x.Status == 6)
+             .GroupBy(x => new { x.PalletCode, x.MaterielCode })
+             .Select(x => new SummaryPickingDto
+             {
+                 PalletCode = x.PalletCode,
+                 MaterielCode = x.MaterielCode,
+                 pickedCount = SqlFunc.AggregateCount(x.Id)
+             }).FirstAsync();
+            if (picked == null)
+            {
+                picked = new SummaryPickingDto { pickedCount = 0 };
+            }
+
+            var summary = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .WhereIF(!string.IsNullOrEmpty(dto.OrderNo), x => x.OrderNo == dto.OrderNo)
+                .WhereIF(!string.IsNullOrEmpty(dto.PalletCode), x => x.PalletCode == dto.PalletCode)
+                .Where(x => x.Status == 1)
+                .GroupBy(x => new { x.PalletCode, x.MaterielCode })
+                .Select(x => new SummaryPickingDto
+                {
+                    PalletCode = x.PalletCode,
+                    MaterielCode = x.MaterielCode,
+                    UnpickedCount = SqlFunc.AggregateCount(x.Id),
+                    UnpickedQuantity = SqlFunc.AggregateSum(x.AssignQuantity) - SqlFunc.AggregateSum(x.PickedQty),
+
+                }).FirstAsync();
+            if (summary == null)
+            {
+                summary = new SummaryPickingDto { pickedCount = 0 };
+            }
+            summary.pickedCount = picked.pickedCount;
+
+            return summary;
+        }
+
+        #endregion
+
+        #region 鏍稿績涓氬姟娴佺▼
         /// <summary>
-        /// 鎵爜鎷i�夌‘璁� - 绠�鍖栫増鏈�
-        /// 鍙鐞嗗疄闄呮嫞閫夌殑搴撳瓨鎵e噺
+        /// 鎷i��
         /// </summary>
-        public async Task<WebResponseContent> ConfirmPicking(PickingConfirmRequest request)
+        /// <param name="orderNo"></param>
+        /// <param name="palletCode"></param>
+        /// <param name="barcode"></param>
+        /// <returns></returns>
+        public async Task<WebResponseContent> ConfirmPicking(string orderNo, string palletCode, string barcode)
         {
             try
             {
                 _unitOfWorkManage.BeginTran();
 
-                // 1. 楠岃瘉鏉$爜鏈夋晥鎬�
-                var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                    .Where(x => x.Barcode == request.Barcode && x.MaterielCode == request.MaterielCode)
+                var validationResult = await ValidatePickingRequest(orderNo, palletCode, barcode);
+                if (!validationResult.IsValid)
+                    return WebResponseContent.Instance.Error(validationResult.ErrorMessage);
+
+                var (lockInfo, orderDetail, stockDetail) = validationResult.Data;
+
+                // 璁$畻瀹為檯鎷i�夋暟閲�
+                var quantityResult = await CalculateActualPickingQuantity(lockInfo, orderDetail, stockDetail);
+                if (!quantityResult.IsValid)
+                    return WebResponseContent.Instance.Error(quantityResult.ErrorMessage);
+
+                var (actualQty, adjustedReason) = quantityResult.Data;
+
+                var overPickingValidation = await ValidateOverPicking(orderDetail.Id, actualQty);
+                if (!overPickingValidation.IsValid)
+                {
+                    return WebResponseContent.Instance.Error(overPickingValidation.ErrorMessage);
+                }
+
+                //  鎵ц鍒嗘嫞閫昏緫
+                var pickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, orderNo, palletCode, barcode, actualQty);
+
+          
+                // 璁板綍鎿嶄綔鍘嗗彶
+                await RecordPickingHistory(pickingResult, orderNo, palletCode);
+
+                _unitOfWorkManage.CommitTran();
+
+                return CreatePickingResponse(pickingResult, adjustedReason);
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                _logger.LogError($"ConfirmPicking澶辫触 - OrderNo: {orderNo}, PalletCode: {palletCode}, Barcode: {barcode}, Error: {ex.Message}");
+                return WebResponseContent.Instance.Error($"鎷i�夌‘璁ゅけ璐ワ細{ex.Message}");
+            }
+        }
+        /// <summary>
+        /// 鍙栨秷鎷i��
+        /// </summary>
+        /// <param name="orderNo"></param>
+        /// <param name="palletCode"></param>
+        /// <param name="barcode"></param>
+        /// <returns></returns>
+        public async Task<WebResponseContent> CancelPicking(string orderNo, string palletCode, string barcode)
+        {
+            try
+            {
+                if (await IsPalletReturned(palletCode))
+                {
+                    return WebResponseContent.Instance.Error($"鎵樼洏{palletCode}宸茬粡鍥炲簱锛屼笉鑳藉彇娑堝垎鎷�");
+                }
+                _unitOfWorkManage.BeginTran();
+
+                // 1. 鍓嶇疆楠岃瘉
+                var validationResult = await ValidateCancelRequest(orderNo, palletCode, barcode);
+                if (!validationResult.IsValid)
+                    return WebResponseContent.Instance.Error(validationResult.ErrorMessage);
+
+                var (pickingRecord, lockInfo, orderDetail) = validationResult.Data;
+
+                // 2. 鎵ц鍙栨秷閫昏緫
+                await ExecuteCancelLogic(lockInfo, pickingRecord, orderDetail, orderNo);
+
+                _unitOfWorkManage.CommitTran();
+
+                return WebResponseContent.Instance.OK($"鍙栨秷鍒嗘嫞鎴愬姛锛屾仮澶嶆暟閲忥細{pickingRecord.PickQuantity}");
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                _logger.LogError($"CancelPicking澶辫触 - OrderNo: {orderNo}, PalletCode: {palletCode}, Barcode: {barcode}, Error: {ex.Message}");
+                return WebResponseContent.Instance.Error($"鍙栨秷鍒嗘嫞澶辫触锛歿ex.Message}");
+            }
+        }
+        /// <summary>
+        /// 鍥炲簱
+        /// </summary>
+        /// <param name="orderNo"></param>
+        /// <param name="palletCode"></param>
+        /// <param name="reason"></param>
+        /// <returns></returns>
+        public async Task<WebResponseContent> ReturnRemaining(string orderNo, string palletCode, string reason)
+        {
+            try
+            {
+                _unitOfWorkManage.BeginTran();
+
+
+                if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode))
+                    return WebResponseContent.Instance.Error("璁㈠崟鍙峰拰鎵樼洏鐮佷笉鑳戒负绌�");
+
+                //  鑾峰彇搴撳瓨鍜屼换鍔′俊鎭�
+                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>().FirstAsync(x => x.PalletCode == palletCode);
+
+                if (stockInfo == null)
+                    return WebResponseContent.Instance.Error($"鏈壘鍒版墭鐩� {palletCode} 瀵瑰簲鐨勫簱瀛樹俊鎭�");
+
+                var task = await GetCurrentTask(orderNo, palletCode);
+                if (task == null)
+                    return WebResponseContent.Instance.Error("鏈壘鍒板搴旂殑浠诲姟淇℃伅");
+
+                //鍒嗘瀽闇�瑕佸洖搴撶殑璐х墿
+                //var returnAnalysis = await AnalyzeReturnItems(orderNo, palletCode, stockInfo.Id);
+                //if (!returnAnalysis.HasItemsToReturn)
+                //    return await HandleNoReturnItems(orderNo, palletCode, task);
+
+                var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id);
+                if (!statusAnalysis.HasItemsToReturn)
+                    return await HandleNoReturnItems(orderNo, palletCode, task, stockInfo.Id);
+
+                // 4. 妫�鏌ユ槸鍚︽湁杩涜涓殑浠诲姟
+                if (statusAnalysis.HasActiveTasks)
+                {
+                    return WebResponseContent.Instance.Error($"鎵樼洏 {palletCode} 鏈夎繘琛屼腑鐨勪换鍔★紝涓嶈兘鎵ц鍥炲簱鎿嶄綔");
+                }
+
+                //鎵ц鍥炲簱鎿嶄綔
+                await ExecuteReturnOperations(orderNo, palletCode, stockInfo, task, statusAnalysis);
+
+                _unitOfWorkManage.CommitTran();
+
+              
+                // 鍒涘缓鍥炲簱浠诲姟
+                await CreateReturnTaskAndHandleESS(orderNo, palletCode, task, TaskTypeEnum.InPick);
+
+                // 鏇存柊璁㈠崟鐘舵�侊紙涓嶈Е鍙慚ES鍥炰紶锛�
+                await UpdateOrderStatusForReturn(orderNo);
+
+                return WebResponseContent.Instance.OK($"鍥炲簱鎿嶄綔鎴愬姛锛屽叡鍥炲簱鏁伴噺锛歿statusAnalysis.TotalReturnQty}");
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                _logger.LogError($"ReturnRemaining澶辫触 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
+                return WebResponseContent.Instance.Error($"鍥炲簱鎿嶄綔澶辫触: {ex.Message}");
+            }
+        }
+
+        /// <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 (stockDetail == null)
-                    return WebResponseContent.Instance.Error("鏃犳晥鐨勬潯鐮佹垨鐗╂枡缂栫爜");
+                if (order == null)
+                    return WebResponseContent.Instance.Error($"鏈壘鍒拌鍗� {orderNo}");
 
-                // 2. 妫�鏌ュ簱瀛樺彲鐢ㄦ暟閲�
-                decimal availableQuantity = stockDetail.StockQuantity - stockDetail.OutboundQuantity;
-                if (request.PickQuantity > availableQuantity)
-                    return WebResponseContent.Instance.Error($"鎷i�夋暟閲忚秴杩囧彲鐢ㄥ簱瀛橈紝鍙敤鏁伴噺锛歿availableQuantity}");
+                //妫�鏌ユ墭鐩樻槸鍚﹀瓨鍦ㄤ笖灞炰簬璇ヨ鍗�
+                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
+                    .Where(x => x.PalletCode == palletCode)
+                    .FirstAsync();
 
-                // 3. 鏌ユ壘鐩稿叧鐨勫嚭搴撻攣瀹氫俊鎭紙鏀寔鎷嗗寘鍚庣殑鏂版潯鐮侊級
-                var lockInfo = await FindLockInfoByBarcode(request.OrderDetailId, request.Barcode, request.MaterielCode);
+                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 鍒嗘嫞纭绉佹湁鏂规硶
+
+        private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>> ValidatePickingRequest(string orderNo, string palletCode, string barcode)
+        {
+            // 1. 鍩虹鍙傛暟楠岃瘉
+            if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode) || string.IsNullOrEmpty(barcode))
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error("璁㈠崟鍙枫�佹墭鐩樼爜鍜屾潯鐮佷笉鑳戒负绌�");
+
+            // 2. 鏌ユ壘鏈夋晥鐨勯攣瀹氫俊鎭�
+            var lockInfo = await FindValidLockInfo(orderNo, palletCode, barcode);
+            if (lockInfo == null)
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"鏈壘鍒版湁鏁堢殑閿佸畾淇℃伅");
+
+            // 3. 妫�鏌ヨ鍗曠姸鎬�
+            var order = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
+                .Where(x => x.OrderNo == orderNo)
+                .FirstAsync();
+
+            if (order?.OrderStatus == (int)OutOrderStatusEnum.鍑哄簱瀹屾垚)
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"璁㈠崟{orderNo}宸插畬鎴愶紝涓嶈兘缁х画鍒嗘嫞");
+
+            // 4. 鑾峰彇璁㈠崟鏄庣粏
+            var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                .FirstAsync(x => x.Id == lockInfo.OrderDetailId);
+
+            if (orderDetail == null)
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"鏈壘鍒拌鍗曟槑缁�");
+
+            // 5. 妫�鏌ヨ鍗曟槑缁嗘暟閲�
+            if (orderDetail.OverOutQuantity >= orderDetail.NeedOutQuantity)
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"璁㈠崟鏄庣粏闇�姹傛暟閲忓凡婊¤冻");
+
+            // 6. 鑾峰彇搴撳瓨鏄庣粏
+            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(x => x.Barcode == barcode && x.StockId == lockInfo.StockId &&
+                   x.Status != StockStatusEmun.鍏ュ簱纭.ObjToInt())
+                .FirstAsync();
+
+            if (stockDetail == null)
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"鏃犳晥鐨勬潯鐮佹垨鐗╂枡缂栫爜");
+
+            // 7. 妫�鏌ュ簱瀛樼姸鎬佸拰鏁伴噺
+            if (stockDetail.StockQuantity <= 0)
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"鏉$爜{barcode}搴撳瓨涓嶈冻");
+
+            if (stockDetail.Status != StockStatusEmun.鍑哄簱閿佸畾.ObjToInt())
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"鏉$爜{barcode}鐘舵�佷笉姝g‘锛屾棤娉曞垎鎷�");
+
+            // 8. 妫�鏌ユ槸鍚﹂噸澶嶅垎鎷�
+            var existingPicking = await Db.Queryable<Dt_PickingRecord>()
+                .Where(x => x.Barcode == barcode && x.OrderNo == orderNo && x.PalletCode == palletCode && x.OutStockLockId == lockInfo.Id)
+                .FirstAsync();
+
+            if (existingPicking != null)
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"鏉$爜{barcode}宸茬粡鍒嗘嫞杩�");
+
+            return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Success((lockInfo, orderDetail, stockDetail));
+        }
+
+        private async Task<Dt_OutStockLockInfo> FindValidLockInfo(string orderNo, string palletCode, string barcode)
+        {
+            // 浼樺厛鏌ユ壘绮剧‘鍖归厤鐨勮褰�
+            var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(it => it.OrderNo == orderNo &&
+                           it.Status == (int)OutLockStockStatusEnum.鍑哄簱涓� &&
+                           it.PalletCode == palletCode &&
+                           it.CurrentBarcode == barcode &&
+                           it.AssignQuantity > it.PickedQty).FirstAsync();
+
+            if (lockInfo == null)
+            {
+                // 鏌ユ壘鍚屼竴璁㈠崟涓嬬殑璁板綍
+                lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                    .Where(it => it.OrderNo == orderNo && it.CurrentBarcode == barcode && it.Status == (int)OutLockStockStatusEnum.鍑哄簱涓� && it.AssignQuantity > it.PickedQty).FirstAsync();
 
                 if (lockInfo == null)
-                    return WebResponseContent.Instance.Error("鏈壘鍒扮浉鍏崇殑鍑哄簱閿佸畾淇℃伅");
-
-                // 4. 妫�鏌ラ攣瀹氭暟閲�
-                decimal remainingLockQuantity = lockInfo.AssignQuantity - lockInfo.PickedQty;
-                if (request.PickQuantity > remainingLockQuantity)
-                    return WebResponseContent.Instance.Error($"鎷i�夋暟閲忚秴杩囬攣瀹氭暟閲忥紝鍓╀綑鍙嫞閫夛細{remainingLockQuantity}");
-
-                // 5. 鏇存柊閿佸畾淇℃伅鐨勫凡鎷i�夋暟閲�
-                lockInfo.PickedQty += request.PickQuantity;
-                await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
-
-                // 6. 鏇存柊搴撳瓨鍑哄簱鏁伴噺 - 瀹為檯鍑忓皯搴撳瓨
-                stockDetail.OutboundQuantity += request.PickQuantity;
-                await _stockInfoService.Db.Updateable(stockDetail).ExecuteCommandAsync();
-
-                // 7. 鏇存柊鍑哄簱鍗曟槑缁�
-                var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
-                    .Where(x => x.Id == request.OrderDetailId)
-                    .FirstAsync();
-
-                orderDetail.OverOutQuantity += request.PickQuantity;
-                orderDetail.LockQuantity -= request.PickQuantity;
-
-                // 妫�鏌ユ槸鍚﹀畬鎴愬嚭搴�
-                if (Math.Abs(orderDetail.OverOutQuantity - orderDetail.OrderQuantity) < 0.001m)
                 {
-                    orderDetail.OrderDetailStatus = (int)OrderDetailStatusEnum.Over;
-                    orderDetail.LockQuantity = 0;
+                    // 妫�鏌ユ槸鍚﹀凡缁忓畬鎴愬垎鎷�
+                    var completedLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                        .Where(it => it.CurrentBarcode == barcode &&
+                                   (it.Status == (int)OutLockStockStatusEnum.鎷i�夊畬鎴� ||
+                                    it.PickedQty >= it.AssignQuantity)).FirstAsync();
 
-                    // 鏇存柊鐩稿叧鐨勯攣瀹氫俊鎭姸鎬佷负宸插嚭搴�
-                    var relatedLockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                        .Where(x => x.OrderDetailId == request.OrderDetailId &&
-                                   x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
-                        .ToListAsync();
-
-                    foreach (var relatedLock in relatedLockInfos)
-                    {
-                        relatedLock.Status = (int)OutLockStockStatusEnum.宸插嚭搴�;
-                    }
-                    await _outStockLockInfoService.Db.Updateable(relatedLockInfos).ExecuteCommandAsync();
+                    if (completedLockInfo != null)
+                        throw new Exception($"鏉$爜{barcode}宸茬粡瀹屾垚鍒嗘嫞锛屼笉鑳介噸澶嶅垎鎷�");
+                    else
+                        return null;
                 }
-
-                await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync();
-
-                // 8. 璁板綍鎷i�夊巻鍙�
-                var pickHistory = new Dt_PickingRecord
-                {
-                    OrderDetailId = request.OrderDetailId,
-                    Barcode = request.Barcode,
-                    PickQuantity = request.PickQuantity,
-                    PickTime = DateTime.Now,
-
-                    LocationCode = request.LocationCode,
-                    StockId = stockDetail.StockId
-                };
-                await Db.Insertable(pickHistory).ExecuteCommandAsync();
-
-                _unitOfWorkManage.CommitTran();
-
-                return WebResponseContent.Instance.OK("鎷i�夌‘璁ゆ垚鍔�");
             }
-            catch (Exception ex)
+
+            return lockInfo;
+        }
+
+        private async Task<ValidationResult<(decimal, string)>> CalculateActualPickingQuantity(
+            Dt_OutStockLockInfo lockInfo, Dt_OutboundOrderDetail orderDetail, Dt_StockInfoDetail stockDetail)
+        {
+            decimal plannedQty = lockInfo.AssignQuantity - lockInfo.PickedQty;
+            decimal remainingOrderQty = orderDetail.NeedOutQuantity - orderDetail.OverOutQuantity;
+            decimal stockQuantity = stockDetail.StockQuantity;
+
+            if (plannedQty <= 0)
             {
-                _unitOfWorkManage.RollbackTran();
-                return WebResponseContent.Instance.Error($"鎷i�夌‘璁ゅけ璐�: {ex.Message}");
+                return ValidationResult<(decimal, string)>.Error($"璁″垝鎷i�夋暟閲忓繀椤诲ぇ浜�0锛屽綋鍓�: {plannedQty}");
             }
+
+            if (remainingOrderQty <= 0)
+            {
+                return ValidationResult<(decimal, string)>.Error($"璁㈠崟鍓╀綑闇�姹傛暟閲忓繀椤诲ぇ浜�0锛屽綋鍓�: {remainingOrderQty}");
+            }
+
+            if (stockQuantity <= 0)
+            {
+                return ValidationResult<(decimal, string)>.Error($"搴撳瓨鏁伴噺蹇呴』澶т簬0锛屽綋鍓�: {stockQuantity}");
+            }
+            // 涓夐噸妫�鏌ワ細鍙栨渶灏忓��
+            decimal actualQty = plannedQty;
+            string adjustedReason = null;
+
+            if (plannedQty > remainingOrderQty)
+            {
+                actualQty = remainingOrderQty;
+                adjustedReason = $"璁㈠崟鏁伴噺闄愬埗锛氫粠{plannedQty}璋冩暣涓簕actualQty}";
+            }
+            if (actualQty > stockQuantity)
+            {
+                actualQty = stockQuantity;
+                adjustedReason = adjustedReason != null
+                    ? $"{adjustedReason}锛屽簱瀛樻暟閲忛檺鍒讹細杩涗竴姝ヨ皟鏁翠负{actualQty}"
+                    : $"搴撳瓨鏁伴噺闄愬埗锛氫粠{plannedQty}璋冩暣涓簕actualQty}";
+            }
+            if (actualQty <= 0)
+            {
+                return ValidationResult<(decimal, string)>.Error($"鏃犳硶鍒嗘嫞锛氳绠楀悗鐨勫疄闄呮暟閲忎负{actualQty}");
+            }
+            decimal projectedOverOut = orderDetail.OverOutQuantity + actualQty;
+            if (projectedOverOut > orderDetail.NeedOutQuantity)
+            {
+                // 濡傛灉浼氳秴鎷o紝璋冩暣涓哄垰濂芥弧瓒抽渶姹傜殑鏁伴噺
+                actualQty = orderDetail.NeedOutQuantity - orderDetail.OverOutQuantity;
+                adjustedReason = adjustedReason != null
+                    ? $"{adjustedReason}锛岄槻瓒呮嫞闄愬埗锛氭渶缁堣皟鏁翠负{actualQty}"
+                    : $"闃茶秴鎷i檺鍒讹細浠巤plannedQty}璋冩暣涓簕actualQty}";
+            }
+
+            if (adjustedReason != null)
+            {
+                _logger.LogWarning($"鍒嗘嫞鏁伴噺璋冩暣锛歿adjustedReason}锛岃鍗晎orderDetail.NeedOutQuantity}锛屽凡鍑哄簱{orderDetail.OverOutQuantity}锛屽簱瀛榹stockQuantity}");
+            }
+
+            return ValidationResult<(decimal, string)>.Success((actualQty, adjustedReason));
         }
 
         /// <summary>
-        /// 鏍规嵁鏉$爜鏌ユ壘閿佸畾淇℃伅
+        /// 涓撻棬楠岃瘉鏄惁浼氬彂鐢熻秴鎷�
         /// </summary>
-        private async Task<Dt_OutStockLockInfo> FindLockInfoByBarcode(int orderDetailId, string barcode, string materielCode)
+        private async Task<ValidationResult<bool>> ValidateOverPicking(int orderDetailId, decimal pickingQty)
         {
-            return await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                .Where(x => x.OrderDetailId == orderDetailId &&
-                           x.MaterielCode == materielCode &&
-                           x.CurrentBarcode == barcode &&
-                           x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓� &&
-                           x.AssignQuantity > x.PickedQty)
+            var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                .FirstAsync(x => x.Id == orderDetailId);
+
+            if (orderDetail == null)
+                return ValidationResult<bool>.Error("鏈壘鍒拌鍗曟槑缁�");
+
+            decimal projectedOverOut = orderDetail.OverOutQuantity + pickingQty;
+
+            if (projectedOverOut > orderDetail.NeedOutQuantity)
+            {
+                return ValidationResult<bool>.Error(
+                    $"鍒嗘嫞鍚庡皢瀵艰嚧瓒呮嫞锛氬綋鍓嶅凡鍑哄簱{orderDetail.OverOutQuantity}锛屾湰娆″垎鎷pickingQty}锛屽悎璁projectedOverOut}锛岃秴杩囬渶姹倇orderDetail.NeedOutQuantity}");
+            }
+
+            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)
+        {
+            decimal stockQuantity = stockDetail.StockQuantity;
+            var result = new PickingResult
+            {
+                FinalLockInfo = lockInfo,
+                FinalBarcode = barcode,
+                FinalStockId = stockDetail.Id,
+                ActualPickedQty = actualQty
+            };
+
+            decimal finalPickedQty = actualQty;
+
+            if (actualQty < stockQuantity)
+            {
+                // 鎷嗗寘鍦烘櫙
+                await HandleSplitPacking(lockInfo, stockDetail, actualQty, stockQuantity, result);
+                finalPickedQty = actualQty;
+            }
+            else if (actualQty == stockQuantity)
+            {
+                // 鏁村寘鎷i��
+                await HandleFullPicking(lockInfo, stockDetail, actualQty, result);
+                finalPickedQty = actualQty;
+            }
+            else
+            {
+                // 閮ㄥ垎鎷i�夛紙搴撳瓨涓嶈冻锛�
+                await HandlePartialPicking(lockInfo, stockDetail, actualQty, stockQuantity, result);
+                finalPickedQty = result.ActualPickedQty; // 鍙兘琚皟鏁�
+            }
+
+            // 缁熶竴鏇存柊璁㈠崟鏁版嵁锛堟墍鏈夊垎鏀兘浠庤繖閲屾洿鏂帮級
+            await UpdateOrderRelatedData(lockInfo.OrderDetailId, finalPickedQty, orderNo);
+
+            return result;
+        }
+
+        private async Task HandleSplitPacking(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
+            decimal actualQty, decimal stockQuantity, PickingResult result)
+        {
+            decimal remainingStockQty = stockQuantity - actualQty;
+
+            // 鏇存柊鍘熸潯鐮佸簱瀛�
+            stockDetail.StockQuantity = remainingStockQty;
+            stockDetail.OutboundQuantity = remainingStockQty;
+            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+
+            //鐢熸垚鏂版潯鐮�
+            string newBarcode = await GenerateNewBarcode();
+
+            //鍒涘缓鏂伴攣瀹氫俊鎭�
+            var newLockInfo = await CreateSplitLockInfo(lockInfo, actualQty, newBarcode);
+
+            // 璁板綍鎷嗗寘鍘嗗彶
+            await RecordSplitHistory(lockInfo, stockDetail, actualQty, remainingStockQty, newBarcode);
+
+            // 鏇存柊鍘熼攣瀹氫俊鎭�
+            lockInfo.AssignQuantity = remainingStockQty;
+            lockInfo.PickedQty = 0;
+            lockInfo.Operator = App.User.UserName;
+            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
+
+            // 璁剧疆缁撴灉
+            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)
+        {
+            // 1. 鏇存柊搴撳瓨
+            stockDetail.StockQuantity = 0;
+            stockDetail.OutboundQuantity = 0;
+            stockDetail.Status = StockStatusEmun.鍑哄簱瀹屾垚.ObjToInt();
+            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+
+            // 2. 鏇存柊閿佸畾淇℃伅
+            lockInfo.PickedQty += actualQty;
+            lockInfo.Status = (int)OutLockStockStatusEnum.鎷i�夊畬鎴�;
+            lockInfo.Operator = App.User.UserName;
+            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
+        }
+
+        private async Task HandlePartialPicking(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
+            decimal actualQty, decimal stockQuantity, PickingResult result)
+        {
+            decimal stockOutQty = stockQuantity;
+            decimal remainingAssignQty = actualQty - stockQuantity;
+
+            // 1. 鏇存柊搴撳瓨
+            stockDetail.StockQuantity = 0;
+            stockDetail.OutboundQuantity = 0;
+            stockDetail.Status = StockStatusEmun.鍑哄簱瀹屾垚.ObjToInt();
+            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+
+            // 2. 鏇存柊閿佸畾淇℃伅
+            lockInfo.PickedQty += stockOutQty;
+            lockInfo.AssignQuantity = remainingAssignQty;
+            lockInfo.Operator = App.User.UserName;
+            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
+
+            // 3. 鏇存柊鎷嗗寘璁板綍鐘舵��
+            await UpdateSplitRecordsStatus(stockDetail.Barcode);
+
+            result.ActualPickedQty = stockOutQty;
+        }
+
+        private async Task UpdateOrderRelatedData(int orderDetailId, decimal pickedQty, string orderNo)
+        {
+            // 鑾峰彇鏈�鏂扮殑璁㈠崟鏄庣粏鏁版嵁
+            var currentOrderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                .FirstAsync(x => x.Id == orderDetailId);
+
+            decimal newOverOutQuantity = currentOrderDetail.OverOutQuantity + pickedQty;
+            decimal newPickedQty = currentOrderDetail.PickedQty + pickedQty;
+
+            if (newOverOutQuantity > currentOrderDetail.NeedOutQuantity)
+            {
+
+                _logger.LogError($"闃茶秴鎷f鏌ュけ璐� - OrderDetailId: {orderDetailId}, 宸插嚭搴�: {newOverOutQuantity}, 闇�姹�: {currentOrderDetail.NeedOutQuantity}, 鏈鍒嗘嫞: {pickedQty}");
+
+
+                decimal adjustedQty = currentOrderDetail.NeedOutQuantity - currentOrderDetail.OverOutQuantity;
+
+                if (adjustedQty > 0)
+                {
+                    _logger.LogWarning($"鑷姩璋冩暣鍒嗘嫞鏁伴噺闃叉瓒呮嫞锛氫粠{pickedQty}璋冩暣涓簕adjustedQty}");
+                    newOverOutQuantity = currentOrderDetail.NeedOutQuantity;
+                    newPickedQty = currentOrderDetail.PickedQty + adjustedQty;
+                }
+                else
+                {
+                    throw new Exception($"鍒嗘嫞鍚庡皢瀵艰嚧宸插嚭搴撴暟閲�({newOverOutQuantity})瓒呰繃璁㈠崟闇�姹傛暟閲�({currentOrderDetail.NeedOutQuantity})锛屼笖鏃犳硶鑷姩璋冩暣");
+                }
+            }
+
+            // 鏇存柊璁㈠崟鏄庣粏
+            await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
+                .SetColumns(it => new Dt_OutboundOrderDetail
+                {
+                    PickedQty = newPickedQty,
+                    OverOutQuantity = newOverOutQuantity,
+                })
+                .Where(it => it.Id == orderDetailId)
+                .ExecuteCommandAsync();
+
+            // 妫�鏌ュ苟鏇存柊璁㈠崟鐘舵��
+            await CheckAndUpdateOrderStatus(orderNo);
+        }
+
+        private async Task RecordPickingHistory(PickingResult result, string orderNo, string palletCode)
+        {
+            var task = await _taskRepository.Db.Queryable<Dt_Task>()
+                .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode)
                 .FirstAsync();
-        }
 
-        /// <summary>
-        /// 鑾峰彇鎷i�夊巻鍙�
-        /// </summary>
-        public async Task<List<Dt_PickingRecord>> GetPickingHistory(int orderId)
-        {
-            // 閫氳繃鍑哄簱鍗旾D鏌ヨ鐩稿叧鐨勬嫞閫夊巻鍙�
-            // 娉ㄦ剰锛欴t_PickingRecord 涓病鏈夌洿鎺ュ瓨鍌∣rderId锛岄渶瑕侀�氳繃鍑哄簱鍗曟槑缁嗗叧鑱�
-            var detailIds = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
-                .Where(d => d.OrderId == orderId)
-                .Select(d => d.Id)
-                .ToListAsync();
-
-            return await Db.Queryable<Dt_PickingRecord>()
-                .Where(p => detailIds.Contains(p.OrderDetailId))
-                .OrderByDescending(p => p.PickTime)
-                .ToListAsync();
-        }
-
-        /// <summary>
-        /// 鎾ら攢鎷i��
-        /// </summary>
-        public async Task<WebResponseContent> CancelPicking(CancelPickingRequest request)
-        {
-            // 瀹炵幇鎾ら攢鎷i�夌殑閫昏緫锛岄渶瑕侊細
-            // 1. 鎭㈠搴撳瓨鍑哄簱鏁伴噺
-            // 2. 鎭㈠閿佸畾淇℃伅鐨勫凡鎷i�夋暟閲�
-            // 3. 鎭㈠鍑哄簱鍗曟槑缁嗙殑宸插嚭鏁伴噺鍜岄攣瀹氭暟閲�
-            // 4. 鍒犻櫎鎴栨爣璁版嫞閫夊巻鍙茶褰�
-            // 娉ㄦ剰锛氳繖閲岄渶瑕佷簨鍔″鐞�
-            try
+            if (result.FinalLockInfo.Id <= 0)
             {
-                _unitOfWorkManage.BeginTran();
-
-                var pickHistory = await Db.Queryable<Dt_PickingRecord>()
-                    .Where(x => x.Id == request.PickingHistoryId)
-                    .FirstAsync();
-
-                if (pickHistory == null)
-                    return WebResponseContent.Instance.Error("鏈壘鍒版嫞閫夎褰�");
-
-                // 鎭㈠搴撳瓨
-                var stockDetail = await _stockInfoService.Db.Queryable<Dt_StockInfoDetail>()
-                    .Where(x => x.Barcode == pickHistory.Barcode && x.StockId == pickHistory.StockId)
-                    .FirstAsync();
-                if (stockDetail != null)
-                {
-                    stockDetail.OutboundQuantity -= pickHistory.PickQuantity;
-                    await _stockInfoService.Db.Updateable(stockDetail).ExecuteCommandAsync();
-                }
-                // 鎭㈠閿佸畾淇℃伅
-                var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                    .Where(x => x.OrderDetailId == pickHistory.OrderDetailId && x.StockId == pickHistory.StockId)
-                    .FirstAsync();
-                lockInfo.PickedQty -= pickHistory.PickQuantity;
-                await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
-
-                // 鎭㈠鍑哄簱鍗曟槑缁�
-                var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
-                    .Where(x => x.Id == pickHistory.OrderDetailId)
-                    .FirstAsync();
-                orderDetail.OverOutQuantity -= pickHistory.PickQuantity;
-                orderDetail.LockQuantity += pickHistory.PickQuantity;
-                if (orderDetail.OverOutQuantity < orderDetail.OrderQuantity)
-                {
-                    orderDetail.OrderDetailStatus = orderDetail.LockQuantity > 0 ?
-                        (int)OrderDetailStatusEnum.Outbound : (int)OrderDetailStatusEnum.AssignOverPartial;
-                }
-                await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync();
-
-                // 鍒犻櫎鎷i�夊巻鍙茶褰�
-                await Db.Deleteable<Dt_PickingRecord>().Where(x => x.Id == request.PickingHistoryId).ExecuteCommandAsync();
-
-                _unitOfWorkManage.CommitTran();
-                return WebResponseContent.Instance.OK("鎾ら攢鎴愬姛");
+                throw new Exception($"閿佸畾淇℃伅ID鏃犳晥: {result.FinalLockInfo.Id}锛屾棤娉曡褰曟嫞閫夊巻鍙�");
             }
-            catch (Exception ex)
+
+            var pickingHistory = new Dt_PickingRecord
             {
-                _unitOfWorkManage.RollbackTran();
-                return WebResponseContent.Instance.Error($"鎾ら攢澶辫触: {ex.Message}");
+                FactoryArea = result.FinalLockInfo.FactoryArea,
+                TaskNo = task?.TaskNum ?? 0,
+                LocationCode = task?.SourceAddress ?? "",
+                StockId = result.FinalStockId,
+                OrderNo = orderNo,
+                OrderDetailId = result.FinalLockInfo.OrderDetailId,
+                PalletCode = palletCode,
+                Barcode = result.FinalBarcode,
+                MaterielCode = result.FinalLockInfo.MaterielCode,
+                PickQuantity = result.ActualPickedQty,
+                PickTime = DateTime.Now,
+                Operator = App.User.UserName,
+                OutStockLockId = result.FinalLockInfo.Id
+            };
+
+            await Db.Insertable(pickingHistory).ExecuteCommandAsync();
+        }
+
+        #endregion
+
+        #region 鍙栨秷鍒嗘嫞绉佹湁鏂规硶
+
+        private async Task<ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>> ValidateCancelRequest(string orderNo, string palletCode, string barcode)
+        {
+            // 鍩虹鍙傛暟楠岃瘉
+            if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode) || string.IsNullOrEmpty(barcode))
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("璁㈠崟鍙枫�佹墭鐩樼爜鍜屾潯鐮佷笉鑳戒负绌�");
+
+            // 鏌ユ壘鎷i�夎褰�
+            var pickingRecord = await Db.Queryable<Dt_PickingRecord>()
+                .Where(it => it.OrderNo == orderNo &&
+                           it.PalletCode == palletCode &&
+                           it.Barcode == barcode)
+                .OrderByDescending(it => it.PickTime)
+                .FirstAsync();
+
+            if (pickingRecord == null)
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("鏈壘鍒板搴旂殑鎷i�夎褰�");
+
+            if (pickingRecord.PickQuantity <= 0)
+            {
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error($"鎷i�夎褰曟暟閲忔棤鏁�: {pickingRecord.PickQuantity}");
+            }
+            // 鏌ユ壘閿佸畾淇℃伅
+            var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(it => it.Id == pickingRecord.OutStockLockId)
+                .FirstAsync();
+
+            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(
+                    $"鍙栨秷鏁伴噺({pickingRecord.PickQuantity})瓒呰繃閿佸畾淇℃伅鐨勫凡鎷i�夋暟閲�({lockInfo.PickedQty})");
+            }
+            // 妫�鏌ョ姸鎬佹槸鍚﹀厑璁稿彇娑�
+            if (lockInfo.Status != (int)OutLockStockStatusEnum.鎷i�夊畬鎴�)
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("褰撳墠鐘舵�佷笉鍏佽鍙栨秷鍒嗘嫞");
+
+            var order = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>().FirstAsync(x => x.OrderNo == orderNo);
+
+            if (order?.OrderStatus == (int)OutOrderStatusEnum.鍑哄簱瀹屾垚)
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("璁㈠崟宸插嚭搴撳畬鎴愶紝涓嶅厑璁稿彇娑堝垎鎷�");
+
+            var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>().FirstAsync(x => x.Id == pickingRecord.OrderDetailId);
+
+            if (orderDetail == null)
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error($"鏈壘鍒拌鍗曟槑缁嗭紝ID: {pickingRecord.OrderDetailId}");
+
+            // 妫�鏌ヨ鍗曟槑缁嗙殑宸叉嫞閫夋暟閲忔槸鍚﹁冻澶熷彇娑�
+            if (orderDetail.PickedQty < pickingRecord.PickQuantity)
+            {
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error($"鍙栨秷鏁伴噺({pickingRecord.PickQuantity})瓒呰繃璁㈠崟鏄庣粏鐨勫凡鎷i�夋暟閲�({orderDetail.PickedQty})");
+            }
+
+            // 妫�鏌ヨ鍗曟槑缁嗙殑宸插嚭搴撴暟閲忔槸鍚﹁冻澶熷彇娑�
+            if (orderDetail.OverOutQuantity < pickingRecord.PickQuantity)
+            {
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error($"鍙栨秷鏁伴噺({pickingRecord.PickQuantity})瓒呰繃璁㈠崟鏄庣粏鐨勫凡鍑哄簱鏁伴噺({orderDetail.OverOutQuantity})");
+            }
+
+            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>().FirstAsync(it => it.Barcode == barcode && it.StockId == pickingRecord.StockId);
+
+            if (stockDetail != null)
+            {
+                // 妫�鏌ュ簱瀛樼姸鎬� - 濡傛灉鐘舵�佹槸鍏ュ簱纭鎴栧叆搴撳畬鎴愶紝璇存槑宸茬粡鍥炲簱
+                if (stockDetail.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt() ||
+                    stockDetail.Status == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt())
+                {
+                    return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error($"鏉$爜{barcode}宸茬粡鍥炲簱锛屼笉鑳藉彇娑堝垎鎷�");
+                }
+            }
+
+            return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Success((pickingRecord, lockInfo, orderDetail));
+        }
+        /// <summary>
+        /// 妫�鏌ユ潯鐮佹槸鍚﹀凡缁忓洖搴�
+        /// </summary>
+        private async Task<bool> IsBarcodeReturned(string barcode, int stockId)
+        {
+            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(it => it.Barcode == barcode && it.StockId == stockId)
+                .FirstAsync();
+
+            if (stockDetail == null)
+                return false;
+
+            // 濡傛灉鐘舵�佹槸鍏ュ簱纭鎴栧叆搴撳畬鎴愶紝璇存槑宸茬粡鍥炲簱
+            return stockDetail.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt() ||
+                   stockDetail.Status == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt();
+        }
+
+        /// <summary>
+        /// 妫�鏌ラ攣瀹氫俊鎭搴旂殑鏉$爜鏄惁宸茬粡鍥炲簱
+        /// </summary>
+        private async Task<bool> IsLockInfoReturned(Dt_OutStockLockInfo lockInfo)
+        {
+            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(it => it.Barcode == lockInfo.CurrentBarcode && it.StockId == lockInfo.StockId)
+                .FirstAsync();
+
+            if (stockDetail == null)
+                return false;
+
+            return stockDetail.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt() ||
+                   stockDetail.Status == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt();
+        }
+        private async Task ExecuteCancelLogic(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord,
+            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()))
+            {
+                throw new Exception($"鏉$爜{pickingRecord.Barcode}宸茬粡鍥炲簱锛屾棤娉曞彇娑堝垎鎷�");
+            }
+            //   妫�鏌ュ彇娑堝悗鏁伴噺涓嶄細涓鸿礋鏁�
+            decimal newOverOutQuantity = orderDetail.OverOutQuantity - cancelQty;
+            decimal newPickedQty = orderDetail.PickedQty - cancelQty;
+
+            if (newOverOutQuantity < 0 || newPickedQty < 0)
+            {
+                throw new Exception($"鍙栨秷鍒嗘嫞灏嗗鑷存暟鎹紓甯革細宸插嚭搴搟newOverOutQuantity}锛屽凡鎷i�墈newPickedQty}");
+            }
+
+            //  澶勭悊涓嶅悓绫诲瀷鐨勫彇娑�
+            if (lockInfo.IsSplitted == 1 && lockInfo.ParentLockId.HasValue)
+            {
+                await HandleSplitBarcodeCancel(lockInfo, pickingRecord, cancelQty);
+            }
+            else
+            {
+                await HandleNormalBarcodeCancel(lockInfo, pickingRecord, cancelQty);
+            }
+
+            // 鏇存柊璁㈠崟鏄庣粏
+            await UpdateOrderDetailOnCancel(pickingRecord.OrderDetailId, cancelQty);
+
+            //  鍒犻櫎鎷i�夎褰�
+            await Db.Deleteable<Dt_PickingRecord>()
+                .Where(x => x.Id == pickingRecord.Id)
+                .ExecuteCommandAsync();
+
+            //  閲嶆柊妫�鏌ヨ鍗曠姸鎬�
+            await UpdateOrderStatusForReturn(orderNo);
+        }
+
+        private async Task HandleSplitBarcodeCancel(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord, decimal cancelQty)
+        {
+            // 鏌ユ壘鐖堕攣瀹氫俊鎭�
+            var parentLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(x => x.Id == lockInfo.ParentLockId.Value)
+                .FirstAsync();
+
+            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;
+            await _outStockLockInfoService.Db.Updateable(parentLockInfo).ExecuteCommandAsync();
+
+            // 鎭㈠搴撳瓨
+            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(x => x.Barcode == parentLockInfo.CurrentBarcode && x.StockId == parentLockInfo.StockId)
+                .FirstAsync();
+
+            if (stockDetail != null)
+            {
+                stockDetail.StockQuantity += cancelQty;
+                stockDetail.OutboundQuantity = stockDetail.StockQuantity;
+                stockDetail.Status = StockStatusEmun.鍑哄簱閿佸畾.ObjToInt();
+                await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+            }
+
+            // 鏇存柊鎷嗗寘璁板綍鐘舵��
+            await _splitPackageService.Db.Updateable<Dt_SplitPackageRecord>()
+                .SetColumns(x => new Dt_SplitPackageRecord
+                {
+                    Status = (int)SplitPackageStatusEnum.宸叉挙閿�,
+                    IsReverted = true,
+                })
+                .Where(x => x.NewBarcode == lockInfo.CurrentBarcode && !x.IsReverted)
+                .ExecuteCommandAsync();
+
+            // 鍒犻櫎鎷嗗寘浜х敓鐨勯攣瀹氫俊鎭�
+            await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
+                .Where(x => x.Id == lockInfo.Id)
+                .ExecuteCommandAsync();
+
+            await UpdateOrderDetailOnCancel(pickingRecord.OrderDetailId, cancelQty);
+        }
+
+        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.鍑哄簱涓�;
+            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
+
+            // 鎭㈠搴撳瓨
+            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(x => x.Barcode == pickingRecord.Barcode && x.StockId == pickingRecord.StockId)
+                .FirstAsync();
+
+            if (stockDetail != null)
+            {
+                stockDetail.StockQuantity += cancelQty;
+                stockDetail.OutboundQuantity = stockDetail.StockQuantity;
+                stockDetail.Status = StockStatusEmun.鍑哄簱閿佸畾.ObjToInt();
+                await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
             }
         }
 
-        /// <summary>
-        /// 鑾峰彇鎵樼洏鐨勫嚭搴撶姸鎬佷俊鎭�
-        /// </summary>
-        public async Task<WebResponseContent> GetPalletOutboundStatus(string palletCode)
+        private async Task UpdateOrderDetailOnCancel(int orderDetailId, decimal cancelQty)
         {
-            // 鑾峰彇鎵樼洏鐨勯攣瀹氫俊鎭�
-            var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                .Where(x => x.PalletCode == palletCode)
-                .ToListAsync();
+            // 鑾峰彇鏈�鏂扮殑璁㈠崟鏄庣粏鏁版嵁
+            var currentOrderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                .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})涓鸿礋鏁�");
+            }
+
+            await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
+                .SetColumns(it => new Dt_OutboundOrderDetail
+                {
+                    PickedQty = newPickedQty,
+                    OverOutQuantity = newOverOutQuantity,
+                })
+                .Where(it => it.Id == orderDetailId)
+                .ExecuteCommandAsync();
+        }
+
+        #endregion
+
+        #region 鍥炲簱鎿嶄綔绉佹湁鏂规硶
+
+        private async Task<Dt_StockInfo> GetStockInfo(string palletCode)
+        {
+            return await _stockInfoService.Db.Queryable<Dt_StockInfo>()
+                .FirstAsync(x => x.PalletCode == palletCode);
+        }
+        /// <summary>
+        /// 妫�鏌ユ暣涓墭鐩樻槸鍚﹀凡缁忓洖搴�
+        /// </summary>
+        private async Task<bool> IsPalletReturned(string palletCode)
+        {
             var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
-                .Includes(x => x.Details)
                 .Where(x => x.PalletCode == palletCode)
                 .FirstAsync();
 
             if (stockInfo == null)
-                return WebResponseContent.Instance.Error("鏈壘鍒版墭鐩樹俊鎭�");
+                return false;
 
-            // 璁$畻鍚勭鏁伴噺
-            var totalStockQuantity = stockInfo.Details.Sum(x => x.StockQuantity);
-            var totalOutboundQuantity = stockInfo.Details.Sum(x => x.OutboundQuantity);
-            var totalLockedQuantity = lockInfos.Where(x => x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
-                .Sum(x => x.AssignQuantity - x.PickedQty);
-            var totalPickedQuantity = lockInfos.Sum(x => x.PickedQty);
+            // 濡傛灉鎵樼洏鐘舵�佹槸鍏ュ簱纭鎴栧叆搴撳畬鎴愶紝璇存槑宸茬粡鍥炲簱
+            return stockInfo.StockStatus == StockStatusEmun.鍏ュ簱纭.ObjToInt() ||
+                   stockInfo.StockStatus == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt();
+        }
+        private async Task<Dt_Task> GetCurrentTask(string orderNo, string palletCode)
+        {
+            // 鍏堝皾璇曢�氳繃璁㈠崟鍙峰拰鎵樼洏鍙锋煡鎵句换鍔�
+            var task = await _taskRepository.Db.Queryable<Dt_Task>()
+                .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode)
+                .FirstAsync();
 
-            var result = new
+            if (task == null)
             {
-                PalletCode = palletCode,
-                LocationCode = stockInfo.LocationCode,
-                StockStatus = stockInfo.StockStatus,
-                TotalStockQuantity = totalStockQuantity,
-                TotalOutboundQuantity = totalOutboundQuantity,
-                TotalLockedQuantity = totalLockedQuantity,
-                TotalPickedQuantity = totalPickedQuantity,
-                AvailableQuantity = totalStockQuantity - totalOutboundQuantity,
-                LockInfos = lockInfos.Select(x => new
-                {
-                    x.Id,
-                    x.MaterielCode,
-                    x.OrderDetailId,
-                    x.AssignQuantity,
-                    x.PickedQty,
-                    x.Status,
-                    x.CurrentBarcode,
-                    x.IsSplitted
-                }).ToList(),
-                StockDetails = stockInfo.Details.Select(x => new
-                {
-                    x.Barcode,
-                    x.MaterielCode,
-                    StockQuantity = x.StockQuantity,
-                    OutboundQuantity = x.OutboundQuantity,
-                    AvailableQuantity = x.StockQuantity - x.OutboundQuantity
-                }).ToList()
-            };
+                // 濡傛灉鎵句笉鍒帮紝鍐嶉�氳繃鎵樼洏鍙锋煡鎵�
+                task = await _taskRepository.Db.Queryable<Dt_Task>()
+                    .Where(x => x.PalletCode == palletCode)
+                    .FirstAsync();
+            }
 
-            return WebResponseContent.Instance.OK(null, result);
+            return task;
+        }
+ 
+        private async Task<decimal> CalculateSplitReturnQuantity(List<Dt_SplitPackageRecord> splitRecords, int stockId)
+        {
+            decimal totalQty = 0;
+            var processedBarcodes = new HashSet<string>();
+
+            foreach (var splitRecord in splitRecords)
+            {
+                // 妫�鏌ュ師鏉$爜
+                if (!processedBarcodes.Contains(splitRecord.OriginalBarcode))
+                {
+                    var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                        .Where(it => it.Barcode == splitRecord.OriginalBarcode && it.StockId == stockId)
+                        .FirstAsync();
+
+                    if (originalStock != null && originalStock.StockQuantity > 0)
+                    {
+                        totalQty += originalStock.StockQuantity;
+                        processedBarcodes.Add(splitRecord.OriginalBarcode);
+                    }
+                }
+
+                // 妫�鏌ユ柊鏉$爜
+                if (!processedBarcodes.Contains(splitRecord.NewBarcode))
+                {
+                    var newStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                        .Where(it => it.Barcode == splitRecord.NewBarcode && it.StockId == stockId)
+                        .FirstAsync();
+
+                    if (newStock != null && newStock.StockQuantity > 0)
+                    {
+                        totalQty += newStock.StockQuantity;
+                        processedBarcodes.Add(splitRecord.NewBarcode);
+                    }
+                }
+            }
+
+            return totalQty;
         }
 
-        /// <summary>
-        /// 鐩存帴鍑哄簱 - 鏁翠釜鎵樼洏鍑哄簱锛屾竻绌哄簱瀛�
-        /// </summary>
-        public async Task<WebResponseContent> DirectOutbound(DirectOutboundRequest request)
+        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�夊畬鎴�);
+
+            //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
             {
-                _unitOfWorkManage.BeginTran();
-
-                // 1. 鑾峰彇鎵樼洏搴撳瓨淇℃伅
+                var locationtype = 0;
                 var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
-                    .Includes(x => x.Details)
-                    .Where(x => x.PalletCode == request.PalletCode)
-                    .FirstAsync();
+                        .Where(x => x.PalletCode == palletCode)
+                        .FirstAsync();
 
                 if (stockInfo == null)
-                    return WebResponseContent.Instance.Error("鏈壘鍒版墭鐩樺簱瀛樹俊鎭�");
-
-                // 2. 鑾峰彇鐩稿叧鐨勫嚭搴撻攣瀹氫俊鎭�
-                var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                    .Where(x => x.PalletCode == request.PalletCode &&
-                               x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
-                    .ToListAsync();
-
-                // 3. 鏁翠釜鎵樼洏鍑哄簱 - 璁剧疆鍑哄簱鏁伴噺绛変簬搴撳瓨鏁伴噺
-                foreach (var detail in stockInfo.Details)
                 {
-                    decimal outboundQuantity = detail.StockQuantity - detail.OutboundQuantity;
-                    detail.OutboundQuantity = detail.StockQuantity; // 鍏ㄩ儴鍑哄簱
-                    await _stockInfoDetailService.Db.Updateable(detail).ExecuteCommandAsync();
+                    var firstLocation = await _locationInfoService.Db.Queryable<Dt_LocationInfo>().FirstAsync(x => x.LocationCode == originalTask.SourceAddress);
+                    locationtype = firstLocation?.LocationType ?? 1;
+                }
+                else
+                {
+                    locationtype = stockInfo.LocationType;
                 }
 
-                // 4. 鏇存柊鍑哄簱閿佸畾淇℃伅
-                foreach (var lockInfo in lockInfos)
-                {
-                    decimal unpicked = lockInfo.AssignQuantity - lockInfo.PickedQty;
-                    lockInfo.PickedQty += unpicked; // 鏍囪涓哄叏閮ㄦ嫞閫�
-                    lockInfo.Status = (int)OutLockStockStatusEnum.宸插嚭搴�;
-                    await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
+                var targetAddress = originalTask.TargetAddress;
 
-                    // 鏇存柊鍑哄簱鍗曟槑缁�
-                    var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
-                        .Where(x => x.Id == lockInfo.OrderDetailId)
-                        .FirstAsync();
-                    orderDetail.OverOutQuantity += unpicked;
-                    orderDetail.LockQuantity -= unpicked;
-                    orderDetail.OrderDetailStatus = (int)OrderDetailStatusEnum.Over;
-                    orderDetail.LockQuantity = 0;
+                await CleanupZeroStockData(stockInfoId);
 
-                    await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync();
-                }
+                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();
 
-                // 5. 鏇存柊鎷嗗寘璁板綍鐘舵��
-                var lockInfoIds = lockInfos.Select(x => x.Id).ToList();
-                var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
-                    .Where(x => lockInfoIds.Contains(x.OutStockLockInfoId) &&
-                               x.Status == (int)SplitPackageStatusEnum.宸叉媶鍖�)
-                    .ToListAsync();
+                await CreateReturnTaskAndHandleESS(orderNo, palletCode, originalTask, TaskTypeEnum.InEmpty);
 
-                foreach (var record in splitRecords)
-                {
-                    record.Status = (int)SplitPackageStatusEnum.宸叉嫞閫�;
-                    await _splitPackageService.Db.Updateable(record).ExecuteCommandAsync();
-                }
-
-                // 6. 娓呯┖璐т綅
-                var location = await _locationInfoService.Db.Queryable<Dt_LocationInfo>()
-                    .Where(x => x.LocationCode == stockInfo.LocationCode)
-                    .FirstAsync();
-                if (location != null)
-                {
-                    location.LocationStatus = (int)LocationStatusEnum.Free;
-                    await _locationInfoService.Db.Updateable(location).ExecuteCommandAsync();
-                }
-
-                _unitOfWorkManage.CommitTran();
-                return WebResponseContent.Instance.OK("鐩存帴鍑哄簱鎴愬姛");
             }
             catch (Exception ex)
             {
-                _unitOfWorkManage.RollbackTran();
-                return WebResponseContent.Instance.Error($"鐩存帴鍑哄簱澶辫触: {ex.Message}");
+                _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, PalletStatusAnalysis analysis)
+        {
+            // 鎯呭喌1锛氬鐞嗘湭鍒嗘嫞鐨勫嚭搴撻攣瀹氳褰�
+            if (analysis.HasRemainingLocks)
+            {
+                await HandleRemainingLocksReturn(analysis.RemainingLocks, stockInfo.Id);
+
+               // await UpdateOrderDetailsOnReturn(analysis.RemainingLocks);
+            }                
+
+            // 澶勭悊鎵樼洏涓婂叾浠栧簱瀛樿揣鐗�
+            if (analysis.HasPalletStockGoods)
+            {
+                await HandlePalletStockGoodsReturn(analysis.PalletStockGoods);
+            }
+
+            // 澶勭悊鎷嗗寘璁板綍
+            if (analysis.HasSplitRecords)
+            {
+                await HandleSplitRecordsReturn(analysis.SplitRecords, orderNo, palletCode);
+            }
+
+            // 鏇存柊搴撳瓨涓昏〃鐘舵��
+            await UpdateStockInfoStatus(stockInfo);
+        }
+
+        private async Task HandleRemainingLocksReturn(List<Dt_OutStockLockInfo> remainingLocks, int stockId)
+        {
+            var lockIds = remainingLocks.Select(x => x.Id).ToList();
+
+            // 鏇存柊鍑哄簱閿佸畾璁板綍鐘舵�佷负鍥炲簱涓�
+            await _outStockLockInfoService.Db.Updateable<Dt_OutStockLockInfo>()
+                .SetColumns(it => new Dt_OutStockLockInfo
+                {
+                    Status = (int)OutLockStockStatusEnum.鍥炲簱涓�,
+                })
+                .Where(it => lockIds.Contains(it.Id))
+                .ExecuteCommandAsync();
+
+            // 澶勭悊搴撳瓨璁板綍
+            foreach (var lockInfo in remainingLocks)
+            {
+                decimal returnQty = lockInfo.AssignQuantity - lockInfo.PickedQty;
+
+                // 鏌ユ壘瀵瑰簲鐨勫簱瀛樻槑缁�
+                var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                    .Where(it => it.Barcode == lockInfo.CurrentBarcode && it.StockId == lockInfo.StockId)
+                    .FirstAsync();
+
+                if (stockDetail != null)
+                {
+                    // 鎭㈠搴撳瓨鐘舵��
+                    stockDetail.OutboundQuantity = Math.Max(0, stockDetail.OutboundQuantity - returnQty);
+                    stockDetail.Status = StockStatusEmun.鍏ュ簱纭.ObjToInt();
+                    await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+                }
+                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();
+                }
+            }
+        }
+
+        private async Task UpdateOrderDetailsOnReturn(List<Dt_OutStockLockInfo> remainingLocks)
+        {
+            // 鎸夎鍗曟槑缁嗗垎缁�
+            var orderDetailGroups = remainingLocks.GroupBy(x => x.OrderDetailId);
+
+            foreach (var group in orderDetailGroups)
+            {
+                var orderDetailId = group.Key;
+                var totalReturnQty = group.Sum(x => x.AssignQuantity - x.PickedQty);
+
+                // 鑾峰彇褰撳墠璁㈠崟鏄庣粏
+                var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                    .FirstAsync(x => x.Id == orderDetailId);
+
+                if (orderDetail != null)
+                {
+                    // 璋冩暣宸叉嫞閫夋暟閲忓拰宸插嚭搴撴暟閲�
+                    decimal newPickedQty = Math.Max(0, orderDetail.PickedQty - totalReturnQty);
+                    decimal newOverOutQuantity = Math.Max(0, orderDetail.OverOutQuantity - totalReturnQty);
+
+                    await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
+                        .SetColumns(it => new Dt_OutboundOrderDetail
+                        {
+                            PickedQty = newPickedQty,
+                            OverOutQuantity = newOverOutQuantity,
+                        })
+                        .Where(it => it.Id == orderDetailId)
+                        .ExecuteCommandAsync();
+                }
+            }
+        }
+
+        private async Task HandlePalletStockGoodsReturn(List<Dt_StockInfoDetail> palletStockGoods)
+        {
+            _logger.LogInformation($"鍥炲簱鎿嶄綔锛氬彂鐜皗palletStockGoods.Count}涓簱瀛樻槑缁嗛渶瑕佸洖搴擄紝绛夊緟AGV鎼繍");
+            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();
+            }
+        }
+
+        private async Task HandleSplitRecordsReturn(List<Dt_SplitPackageRecord> splitRecords, string orderNo, string palletCode)
+        {
+            // 鏇存柊鎷嗗寘璁板綍鐘舵��
+            await _splitPackageService.Db.Updateable<Dt_SplitPackageRecord>()
+                .SetColumns(x => new Dt_SplitPackageRecord
+                {
+                    Status = (int)SplitPackageStatusEnum.宸插洖搴�,
+                })
+                .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode && !x.IsReverted)
+                .ExecuteCommandAsync();
+        }
+
+        private async Task UpdateStockInfoStatus(Dt_StockInfo stockInfo)
+        {
+            _logger.LogInformation($"鍥炲簱鎿嶄綔锛氭墭鐩榹stockInfo.PalletCode}绛夊緟AGV鍥炲簱鎼繍");
+            // 鏇存柊搴撳瓨涓昏〃鐘舵��
+            stockInfo.StockStatus = StockStatusEmun.鍏ュ簱纭.ObjToInt();
+            await _stockInfoService.Db.Updateable(stockInfo).ExecuteCommandAsync();
+        }
+        /// <summary>
+        /// 鍒涘缓鍥炲簱浠诲姟
+        /// </summary>
+        /// <param name="orderNo"></param>
+        /// <param name="palletCode"></param>
+        /// <param name="originalTask"></param>
+        /// <param name="analysis"></param>
+        /// <returns></returns>
+        private async Task CreateReturnTaskAndHandleESS(string orderNo, string palletCode, Dt_Task originalTask, TaskTypeEnum taskTypeEnum)
+        {
+            var firstLocation = await _locationInfoService.Db.Queryable<Dt_LocationInfo>()
+                .FirstAsync(x => x.LocationCode == originalTask.SourceAddress);
+
+            // 鍒嗛厤鏂拌揣浣�
+            var newLocation = _locationInfoService.AssignLocation(firstLocation.LocationType);
+
+            Dt_Task returnTask = new()
+            {
+                CurrentAddress = stations[originalTask.TargetAddress],
+                Grade = 0,
+                PalletCode = palletCode,
+                NextAddress = "",
+                OrderNo = originalTask.OrderNo,
+                Roadway = newLocation.RoadwayNo,
+                SourceAddress = stations[originalTask.TargetAddress],
+                TargetAddress = newLocation.LocationCode,
+                TaskStatus = TaskStatusEnum.New.ObjToInt(),
+                TaskType = taskTypeEnum.ObjToInt(),
+                PalletType = originalTask.PalletType,
+                WarehouseId = originalTask.WarehouseId
+
+            };
+            // 淇濆瓨鍥炲簱浠诲姟
+            await _taskRepository.Db.Insertable(returnTask).ExecuteCommandAsync();
+            var targetAddress = originalTask.TargetAddress;
+
+            // 鍒犻櫎鍘熷鍑哄簱浠诲姟
+            _taskRepository.DeleteAndMoveIntoHty(originalTask, OperateTypeEnum.鑷姩瀹屾垚);
+            // await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync();
+
+
+
+            // 缁� ESS 鍙戦�佹祦鍔ㄤ俊鍙峰拰鍒涘缓浠诲姟
+            await SendESSCommands(palletCode, targetAddress, returnTask);
+        }
+        /// <summary>
+        /// 缁橢SS涓嬩换鍔�
+        /// </summary>
+        /// <param name="palletCode"></param>
+        /// <param name="targetAddress"></param>
+        /// <param name="returnTask"></param>
+        /// <returns></returns>
+        /// <exception cref="Exception"></exception>
+        private async Task SendESSCommands(string palletCode, string targetAddress, Dt_Task returnTask)
+        {
+            try
+            {
+                // 1. 鍙戦�佹祦鍔ㄤ俊鍙�
+                var moveResult = await _eSSApiService.MoveContainerAsync(new WIDESEA_DTO.Basic.MoveContainerRequest
+                {
+                    slotCode = movestations[targetAddress],
+                    containerCode = palletCode
+                });
+
+                if (moveResult)
+                {
+                    // 2. 鍒涘缓鍥炲簱浠诲姟
+                    var essTask = new TaskModel()
+                    {
+                        taskType = "putaway",
+                        taskGroupCode = "",
+                        groupPriority = 0,
+                        tasks = new List<TasksType>{  new() {
+                            taskCode = returnTask.TaskNum.ToString(),
+                            taskPriority = 0,
+                            taskDescribe = new TaskDescribeType
+                            {
+                                containerCode = palletCode,
+                                containerType = "CT_KUBOT_STANDARD",
+                                fromLocationCode = stations.GetValueOrDefault(targetAddress) ?? "",
+                                toStationCode = "",
+                                toLocationCode = returnTask.TargetAddress,
+                                deadline = 0,
+                                storageTag = ""
+                            }
+                        } }
+                    };
+
+                    var resultTask = await _eSSApiService.CreateTaskAsync(essTask);
+                    _logger.LogInformation($"ReturnRemaining 鍒涘缓浠诲姟鎴愬姛: {resultTask}");
+                }
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError($"ReturnRemaining ESS鍛戒护鍙戦�佸け璐�: {ex.Message}");
+                throw new Exception($"ESS绯荤粺閫氫俊澶辫触: {ex.Message}");
+            }
+        }
+
+        #endregion
+
+        #region 璁㈠崟鐘舵�佺鐞�
+
+        private async Task CheckAndUpdateOrderStatus(string orderNo)
+        {
+            try
+            {
+                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) return;
+
+                int newStatus = allCompleted ? (int)OutOrderStatusEnum.鍑哄簱瀹屾垚 : (int)OutOrderStatusEnum.鍑哄簱涓�;
+
+                if (outboundOrder.OrderStatus != newStatus)
+                {
+                    await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
+                        .SetColumns(x => x.OrderStatus == newStatus)
+                        .Where(x => x.OrderNo == orderNo)
+                        .ExecuteCommandAsync();
+
+                    // 鍙湁姝e父鍒嗘嫞瀹屾垚鏃舵墠鍚慚ES鍙嶉
+                    if (allCompleted && newStatus == (int)OutOrderStatusEnum.鍑哄簱瀹屾垚)
+                    {
+                        await HandleOrderCompletion(outboundOrder, orderNo);
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError($"CheckAndUpdateOrderStatus澶辫触 - OrderNo: {orderNo}, Error: {ex.Message}");
+            }
+        }
+
+        
+
+        private async Task UpdateOrderStatusForReturn(string orderNo)
+        {
+            try
+            {
+                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) return;
+
+                int newStatus = allCompleted ? (int)OutOrderStatusEnum.鍑哄簱瀹屾垚 : (int)OutOrderStatusEnum.鍑哄簱涓�;
+
+                if (outboundOrder.OrderStatus != newStatus)
+                {
+                    await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
+                        .SetColumns(x => x.OrderStatus == newStatus)
+                        .Where(x => x.OrderNo == orderNo)
+                        .ExecuteCommandAsync();
+
+                    _logger.LogInformation($"鍥炲簱鎿嶄綔鏇存柊璁㈠崟鐘舵�� - OrderNo: {orderNo}, 鏂扮姸鎬�: {newStatus}");
+                }
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError($"UpdateOrderStatusForReturn澶辫触 - OrderNo: {orderNo}, Error: {ex.Message}");
+            }
+        }
+
+        private async Task HandleOrderCompletion(Dt_OutboundOrder outboundOrder, string orderNo)
+        {
+            // 璋冩嫧鍑哄簱鍜岄噸妫�鍑哄簱涓嶉渶瑕佸弽棣圡ES
+            if (outboundOrder.OrderType == OutOrderTypeEnum.Allocate.ObjToInt() ||
+                outboundOrder.OrderType == OutOrderTypeEnum.ReCheck.ObjToInt())
+            {
+                return;
+            }
+
+            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 => x.ReturnToMESStatus == 1)
+                        .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.鍑哄簱瀹屾垚;
+                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
+            };
+
+            // 1. 鍒嗘瀽鏈垎鎷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);
+            }
+
+            // 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);
+            }
+
+            // 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();
+
+            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()
+        {
+            var seq = await _dailySequenceService.GetNextSequenceAsync();
+            return "WSLOT" + DateTime.Now.ToString("yyyyMMdd") + seq.ToString()?.PadLeft(5, '0');
+        }
+
+        private async Task<Dt_OutStockLockInfo> CreateSplitLockInfo(Dt_OutStockLockInfo originalLock, decimal quantity, string newBarcode)
+        {
+            var newLockInfo = new Dt_OutStockLockInfo
+            {
+                OrderNo = originalLock.OrderNo,
+                OrderDetailId = originalLock.OrderDetailId,
+                BatchNo = originalLock.BatchNo,
+                MaterielCode = originalLock.MaterielCode,
+                MaterielName = originalLock.MaterielName,
+                StockId = originalLock.StockId,
+                OrderQuantity = quantity,
+                OriginalQuantity = quantity,
+                AssignQuantity = quantity,
+                PickedQty = quantity,
+                LocationCode = originalLock.LocationCode,
+                PalletCode = originalLock.PalletCode,
+                TaskNum = originalLock.TaskNum,
+                Status = (int)OutLockStockStatusEnum.鎷i�夊畬鎴�,
+                Unit = originalLock.Unit,
+                SupplyCode = originalLock.SupplyCode,
+                OrderType = originalLock.OrderType,
+                CurrentBarcode = newBarcode,
+                OriginalLockQuantity = quantity,
+                IsSplitted = 1,
+                ParentLockId = originalLock.Id,
+                Operator = App.User.UserName,
+                FactoryArea = originalLock.FactoryArea,
+                lineNo = originalLock.lineNo,
+                WarehouseCode = originalLock.WarehouseCode,
+
+            };
+
+            var newLockId = await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteReturnIdentityAsync();
+            newLockInfo.Id = newLockId;
+            return newLockInfo;
+        }
+
+        private async Task RecordSplitHistory(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
+            decimal splitQty, decimal remainQty, string newBarcode)
+        {
+            var splitHistory = new Dt_SplitPackageRecord
+            {
+                FactoryArea = lockInfo.FactoryArea,
+                TaskNum = lockInfo.TaskNum,
+                OutStockLockInfoId = lockInfo.Id,
+                StockId = stockDetail.StockId,
+                Operator = App.User.UserName,
+                IsReverted = false,
+                OriginalBarcode = stockDetail.Barcode,
+                NewBarcode = newBarcode,
+                SplitQty = splitQty,
+                RemainQuantity = remainQty,
+                MaterielCode = lockInfo.MaterielCode,
+                SplitTime = DateTime.Now,
+                OrderNo = lockInfo.OrderNo,
+                PalletCode = lockInfo.PalletCode,
+                Status = (int)SplitPackageStatusEnum.宸叉嫞閫�
+            };
+
+            await _splitPackageService.Db.Insertable(splitHistory).ExecuteCommandAsync();
+        }
+
+        private List<SplitResult> CreateSplitResults(Dt_OutStockLockInfo lockInfo, decimal splitQty, decimal remainQty, string newBarcode, string originalBarcode)
+        {
+            return new List<SplitResult>
+        {
+            new SplitResult
+            {
+                materialCode = lockInfo.MaterielCode,
+                supplierCode = lockInfo.SupplyCode,
+                quantityTotal = splitQty.ToString("F2"),
+                batchNumber = newBarcode,
+                batch = lockInfo.BatchNo,
+                factory = lockInfo.FactoryArea,
+                date = DateTime.Now.ToString("yyyy-MM-dd"),
+            },
+            new SplitResult
+            {
+                materialCode = lockInfo.MaterielCode,
+                supplierCode = lockInfo.SupplyCode,
+                quantityTotal = remainQty.ToString("F2"),
+                batchNumber = originalBarcode,
+                batch = lockInfo.BatchNo,
+                factory = lockInfo.FactoryArea,
+                date = DateTime.Now.ToString("yyyy-MM-dd"),
+            }
+        };
+        }
+
+        private async Task UpdateSplitRecordsStatus(string barcode)
+        {
+            var relatedSplitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
+                .Where(it => it.OriginalBarcode == barcode || it.NewBarcode == barcode)
+                .Where(it => !it.IsReverted)
+                .ToListAsync();
+
+            foreach (var record in relatedSplitRecords)
+            {
+                record.Status = (int)SplitPackageStatusEnum.宸叉嫞閫�;
+                await _splitPackageService.Db.Updateable(record).ExecuteCommandAsync();
+            }
+        }
+
+        private async Task<int> GenerateTaskNumber()
+        {
+            return await _dailySequenceService.GetNextSequenceAsync();
+        }
+
+        private WebResponseContent CreatePickingResponse(PickingResult result, string adjustedReason)
+        {
+            //if (result.SplitResults.Any())
+            //{
+            //    var responseData = new { SplitResults = result.SplitResults, AdjustedReason = "" };
+            //    if (!string.IsNullOrEmpty(adjustedReason))
+            //    {
+            //        responseData = new { SplitResults = result.SplitResults, AdjustedReason = adjustedReason };
+            //    }
+            //    return WebResponseContent.Instance.OK("鎷i�夌‘璁ゆ垚鍔燂紝宸茶嚜鍔ㄦ媶鍖�", responseData);
+            //}
+
+            //if (!string.IsNullOrEmpty(adjustedReason))
+            //{
+            //    return WebResponseContent.Instance.OK($"鎷i�夌‘璁ゆ垚鍔燂紙{adjustedReason}锛�");
+            //}
+
+            //return WebResponseContent.Instance.OK("鎷i�夌‘璁ゆ垚鍔�");
+
+            if (result.SplitResults.Any())
+            {
+                return WebResponseContent.Instance.OK("鎷i�夌‘璁ゆ垚鍔燂紝宸茶嚜鍔ㄦ媶鍖�", new { SplitResults = result.SplitResults });
+            }
+            return WebResponseContent.Instance.OK("鎷i�夌‘璁ゆ垚鍔�", new { SplitResults = new List<SplitResult>() });
+        }
+
+        #endregion
+    }
+
+    #region 鏀寔绫诲畾涔�
+
+    public class ValidationResult<T>
+    {
+        public bool IsValid { get; set; }
+        public T Data { get; set; }
+        public string ErrorMessage { get; set; }
+
+        public static ValidationResult<T> Success(T data)
+        {
+            return new ValidationResult<T>
+            {
+                IsValid = true,
+                Data = data
+            };
+        }
+
+        public static ValidationResult<T> Error(string message)
+        {
+            return new ValidationResult<T>
+            {
+                IsValid = false,
+                ErrorMessage = message
+            };
         }
     }
 
+    public class PickingResult
+    {
+        public Dt_OutStockLockInfo FinalLockInfo { get; set; }
+        public string FinalBarcode { get; set; }
+        public int FinalStockId { get; set; }
+        public decimal ActualPickedQty { get; set; }
+        public List<SplitResult> SplitResults { get; set; } = new List<SplitResult>();
+    }
+
+    public class ReturnAnalysisResult
+    {
+        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 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;
+    }
+    #endregion
 }

--
Gitblit v1.9.3