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

---
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs | 3126 +++++++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 2,181 insertions(+), 945 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 159cba4..f289724 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,13 +1,16 @@
 锘縰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;
@@ -15,9 +18,13 @@
 using WIDESEA_Core;
 using WIDESEA_Core.BaseRepository;
 using WIDESEA_Core.BaseServices;
+using WIDESEA_Core.Enums;
 using WIDESEA_Core.Helper;
+using WIDESEA_DTO.Allocate;
 using WIDESEA_DTO.Basic;
+using WIDESEA_DTO.Inbound;
 using WIDESEA_DTO.Outbound;
+using WIDESEA_IAllocateService;
 using WIDESEA_IBasicService;
 using WIDESEA_IOutboundService;
 using WIDESEA_IStockService;
@@ -43,7 +50,9 @@
         private readonly ISplitPackageService _splitPackageService;
         private readonly IRepository<Dt_Task> _taskRepository;
         private readonly IESSApiService _eSSApiService;
-
+        private readonly IInvokeMESService _invokeMESService;
+        private readonly IDailySequenceService _dailySequenceService;
+        private readonly IAllocateService _allocateService;
 
         private readonly ILogger<OutboundPickingService> _logger;
 
@@ -61,7 +70,10 @@
 
         };
 
-        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) : base(BaseDal)
+        public OutboundPickingService(IRepository<Dt_PickingRecord> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockInfoService stockInfoService, IStockService stockService,
+            IOutStockLockInfoService outStockLockInfoService, IStockInfoDetailService stockInfoDetailService, ILocationInfoService locationInfoService,
+            IOutboundOrderDetailService outboundOrderDetailService, ISplitPackageService splitPackageService, IOutboundOrderService outboundOrderService,
+            IRepository<Dt_Task> taskRepository, IESSApiService eSSApiService, ILogger<OutboundPickingService> logger, IInvokeMESService invokeMESService, IDailySequenceService dailySequenceService, IAllocateService allocateService) : base(BaseDal)
         {
             _unitOfWorkManage = unitOfWorkManage;
             _stockInfoService = stockInfoService;
@@ -75,748 +87,13 @@
             _taskRepository = taskRepository;
             _eSSApiService = eSSApiService;
             _logger = logger;
+            _invokeMESService = invokeMESService;
+            _dailySequenceService = dailySequenceService;
+            _allocateService = allocateService;
         }
 
 
-        #region 鏌ヨ鍑哄簱璇︽儏鍒楄〃
-        public async Task<List<OutStockLockListResp>> GetOutStockLockListAsync(string orderNo)
-        {
-            var locks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                .Where(t => t.OrderNo == orderNo)
-                .ToListAsync();
-
-            return locks.Select(t => new OutStockLockListResp
-            {
-                Id = t.Id,
-                // TaskNum = t.TaskNum,
-                PalletCode = t.PalletCode,
-                CurrentBarcode = t.CurrentBarcode,
-                AssignQuantity = t.AssignQuantity,
-                PickedQty = t.PickedQty,
-                Status = t.Status,
-                //  IsSplitted = t.IsSplitted
-            }).ToList();
-        }
-        #endregion
-        public async Task<WebResponseContent> ValidateBarcode(string barcode)
-        {
-            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}");
-            }
-        }
-
-        /// <summary>
-        /// 鎵爜鎷i�夌‘璁� 
-        /// </summary>
-        public async Task<WebResponseContent> ConfirmPicking(PickingConfirmRequest request)
-        {
-            try
-            {
-                _unitOfWorkManage.BeginTran();
-
-                // 1. 楠岃瘉鏉$爜鏈夋晥鎬�
-                var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                    .Where(x => x.Barcode == request.Barcode && x.MaterielCode == request.MaterielCode)
-                    .FirstAsync();
-
-                if (stockDetail == null)
-                    return WebResponseContent.Instance.Error("鏃犳晥鐨勬潯鐮佹垨鐗╂枡缂栫爜");
-
-                // 2. 妫�鏌ュ簱瀛樺彲鐢ㄦ暟閲�
-                decimal availableQuantity = stockDetail.StockQuantity - stockDetail.OutboundQuantity;
-                if (request.PickQuantity > availableQuantity)
-                    return WebResponseContent.Instance.Error($"鎷i�夋暟閲忚秴杩囧彲鐢ㄥ簱瀛橈紝鍙敤鏁伴噺锛歿availableQuantity}");
-
-                // 3. 鏌ユ壘鐩稿叧鐨勫嚭搴撻攣瀹氫俊鎭紙鏀寔鎷嗗寘鍚庣殑鏂版潯鐮侊級
-                var lockInfo = await FindLockInfoByBarcode(request.OrderDetailId, request.Barcode, request.MaterielCode);
-
-                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 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();
-                }
-
-                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)
-            {
-                _unitOfWorkManage.RollbackTran();
-                return WebResponseContent.Instance.Error($"鎷i�夌‘璁ゅけ璐�: {ex.Message}");
-            }
-        }
-
-        public async Task<WebResponseContent> ConfirmPicking(string orderNo, string palletCode, string barcode)
-        {
-            try
-            {
-                _unitOfWorkManage.BeginTran();
-                var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                  .Where(it => it.OrderNo == orderNo &&
-                             it.Status == (int)OutLockStockStatusEnum.鍑哄簱涓� &&
-                             it.PalletCode == palletCode &&
-                             it.CurrentBarcode == barcode)
-                  .FirstAsync();
-
-                if (lockInfo == null)
-                {
-                    var splitBarcode = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
-                   .Where(it => it.NewBarcode == barcode && it.Status == 1)
-                   .FirstAsync();
-
-                    if (splitBarcode != null)
-                    {
-                        // 閫氳繃鎷嗗寘鏉$爜璁板綍鎵惧埌瀵瑰簲鐨勫嚭搴撻攣瀹氳褰�
-                        lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                            .Where(it => it.ParentLockId == splitBarcode.OutStockLockInfoId)
-                            .FirstAsync();
-
-                        if (lockInfo == null)
-                            throw new Exception($"鏈壘鍒版媶鍖呮潯鐮亄barcode}瀵瑰簲鐨勫嚭搴撻攣瀹氳褰�");
-                    }
-                    else
-                    {
-                        throw new Exception($"鏉$爜{barcode}涓嶅睘浜庢墭鐩榹palletCode}鎴栦笉瀛樺湪寰呭垎鎷h褰�");
-                    }
-
-                }
-                if (lockInfo.PalletCode != palletCode)
-                    throw new Exception($"鏉$爜{barcode}涓嶅睘浜庢墭鐩榹palletCode}");
-
-                var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                        .Where(x => x.Barcode == barcode && x.StockId == lockInfo.StockId)
-                        .FirstAsync();
-
-                if (stockDetail == null)
-                    return WebResponseContent.Instance.Error("鏃犳晥鐨勬潯鐮佹垨鐗╂枡缂栫爜");
-
-
-                decimal actualQty = lockInfo.AssignQuantity - lockInfo.PickedQty;
-
-                // 4. 鏇存柊搴撳瓨
-                stockDetail.StockQuantity -= actualQty;
-                stockDetail.OutboundQuantity -= actualQty;
-                await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
-
-                lockInfo.PickedQty += actualQty;
-                lockInfo.Status = (int)OutLockStockStatusEnum.鎷i�夊畬鎴�;
-                await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
-
-                var splitBarcodeRecord = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
-               .Where(it => it.NewBarcode == barcode)
-               .FirstAsync();
-
-                if (splitBarcodeRecord != null)
-                {
-                    splitBarcodeRecord.Status = 2;
-                    await _splitPackageService.Db.Updateable(splitBarcodeRecord).ExecuteCommandAsync();
-                }
-
-                await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
-               .SetColumns(it => it.PickedQty == it.PickedQty + actualQty)
-               .Where(it => it.Id == lockInfo.OrderDetailId)
-               .ExecuteCommandAsync();
-
-
-                await CheckAndUpdateOrderStatus(orderNo);
-
-                //鏌ヨ浠诲姟琛� 
-                var task = _taskRepository.QueryData(x => x.OrderNo == orderNo && x.PalletCode == palletCode).FirstOrDefault();
-                // 9. 璁板綍鎷i�夊巻鍙�
-                var pickingHistory = new Dt_PickingRecord
-                {
-                    FactoryArea = lockInfo.FactoryArea,
-                    TaskNo = task?.TaskNum ?? 0,
-                    LocationCode = task?.SourceAddress ?? "",
-                    StockId = stockDetail.Id,
-                    OrderNo = orderNo,
-                    OrderDetailId = lockInfo.OrderDetailId,
-                    PalletCode = palletCode,
-                    Barcode = barcode,
-                    MaterielCode = lockInfo.MaterielCode,
-                    PickQuantity = lockInfo.AssignQuantity,
-                    PickTime = DateTime.Now,
-                    Operator = App.User.UserName,
-                    OutStockLockId = lockInfo.Id
-                };
-                await Db.Insertable(pickingHistory).ExecuteCommandAsync();
-
-                _unitOfWorkManage.CommitTran();
-                return WebResponseContent.Instance.OK("鎷i�夌‘璁ゆ垚鍔�");
-
-            }
-            catch (Exception ex)
-            {
-                return WebResponseContent.Instance.Error($"鎷i�夌‘璁ゅけ璐ワ細{ex.Message}");
-            }
-        }
-        // 妫�鏌ュ苟鏇存柊璁㈠崟鐘舵��
-        private async Task CheckAndUpdateOrderStatus(string orderNo)
-        {
-
-
-            var orderDetails = await _stockInfoDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
-                .Where(x => x.OrderId == orderNo.ObjToInt())
-                .ToListAsync();
-
-            bool allCompleted = true;
-            foreach (var detail in orderDetails)
-            {
-                if (detail.OverOutQuantity < detail.NeedOutQuantity)
-                {
-                    allCompleted = false;
-                    break;
-                }
-            }
-
-            if (allCompleted)
-            {
-                await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
-                    .SetColumns(x => x.OrderStatus == 2) // 宸插畬鎴�
-                    .Where(x => x.OrderNo == orderNo)
-                    .ExecuteCommandAsync();
-            }
-        }
-
-
-        /// <summary>
-        /// 鍥炲簱鎿嶄綔  
-        /// </summary>
-        //public async Task<WebResponseContent> ReturnRemaining(string orderNo, string palletCode, string reason)
-        //{
-        //    try
-        //    {
-        //        // 1. 鑾峰彇鎵�鏈夋湭鍒嗘嫞鐨勫嚭搴撻攣瀹氳褰曪紝鍖呮嫭鎷嗗寘浜х敓鐨勮褰�
-        //        var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-        //            .Where(it => it.OrderNo == orderNo && it.Status == 1)
-        //            .ToListAsync();
-
-        //        if (!remainingLocks.Any())
-        //        {
-        //            return WebResponseContent.Instance.Error("娌℃湁闇�瑕佸洖搴撶殑鍓╀綑璐х墿");
-        //        }
-        //        var tasks = new List<Dt_Task>();
-        //        // 鎸夋墭鐩樺垎缁�
-        //        var palletGroups = remainingLocks.GroupBy(x => x.PalletCode);
-        //        //鏌ヨ浠诲姟琛� 
-        //        var task = _taskRepository.QueryData(x => x.TaskNum == remainingLocks.First().TaskNum).FirstOrDefault();
-        //        foreach (var group in palletGroups)
-        //        {
-        //            if (group.Key == palletCode)
-        //            {
-        //                var totalReturnQty = group.Sum(x => x.AssignQuantity - x.PickedQty);
-
-        //                if (totalReturnQty <= 0) continue;
-
-        //                // 鍒嗛厤鏂拌揣浣�
-        //                var newLocation = _locationInfoService.AssignLocation();
-
-        //                // 鏇存柊鍑哄簱閿佸畾璁板綍鐘舵��
-        //                var lockIds = group.Where(x => x.PalletCode == palletCode).Select(x => x.Id).ToList();
-        //                await _outStockLockInfoService.Db.Updateable<Dt_OutStockLockInfo>()
-        //                    .SetColumns(it => new Dt_OutStockLockInfo { Status = OutLockStockStatusEnum.鍥炲簱涓�.ObjToInt() })
-        //                    .Where(it => lockIds.Contains(it.Id))
-        //                    .ExecuteCommandAsync();
-
-        //                // 鏇存柊鎷嗗寘鏉$爜璁板綍鐘舵��
-        //                var splitBarcodes = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
-        //                    .Where(it => lockIds.Contains(it.OutStockLockInfoId))
-        //                    .ToListAsync();
-
-        //                foreach (var splitBarcode in splitBarcodes)
-        //                {
-        //                    splitBarcode.Status = 3;
-        //                    await _splitPackageService.Db.Updateable(splitBarcode).ExecuteCommandAsync();
-        //                }
-
-        //                foreach (var lockInfo in group)
-        //                {
-        //                    if (lockInfo.PalletCode == palletCode)
-        //                    {
-        //                        decimal returnQty = lockInfo.AssignQuantity - lockInfo.PickedQty;
-
-        //                        // 妫�鏌ュ簱瀛樿褰曟槸鍚﹀瓨鍦�
-        //                        var existingStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-        //                            .Where(it => it.Barcode == lockInfo.CurrentBarcode && it.StockId == lockInfo.StockId)
-        //                            .FirstAsync();
-
-        //                        if (existingStock != null)
-        //                        {
-        //                            // 搴撳瓨璁板綍瀛樺湪锛屾仮澶嶉攣瀹氭暟閲�
-        //                            await _stockInfoDetailService.Db.Updateable<Dt_StockInfoDetail>()
-        //                                .SetColumns(it => new Dt_StockInfoDetail
-        //                                {
-        //                                    OutboundQuantity = it.OutboundQuantity - returnQty
-        //                                })
-        //                                .Where(it => it.Barcode == lockInfo.CurrentBarcode && it.StockId == lockInfo.StockId)
-        //                                .ExecuteCommandAsync();
-        //                        }
-        //                        else
-        //                        {
-        //                            // 搴撳瓨璁板綍涓嶅瓨鍦紙鍙兘鏄媶鍖呬骇鐢熺殑鏂版潯鐮侊級锛屽垱寤烘柊鐨勫簱瀛樿褰�
-        //                            var newStockDetail = new Dt_StockInfoDetail
-        //                            {
-        //                                StockId = lockInfo.StockId,
-        //                                MaterielCode = lockInfo.MaterielCode,
-        //                                OrderNo = lockInfo.OrderNo,
-        //                                BatchNo = lockInfo.BatchNo,
-        //                                StockQuantity = returnQty, // 瀹為檯搴撳瓨鏁伴噺
-        //                                OutboundQuantity = 0, // 鍥炲簱鍚庝笉鍐嶉攣瀹�
-        //                                Barcode = lockInfo.CurrentBarcode,
-        //                                InboundOrderRowNo = "0",
-        //                                Status = StockStatusEmun.鍏ュ簱纭.ObjToInt(),
-
-        //                            };
-        //                            await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync();
-        //                        }
-        //                    }
-        //                }
-
-
-        //                Dt_Task newtask = new()
-        //                {
-        //                    CurrentAddress = stations[task.TargetAddress],
-        //                    Grade = 0,
-        //                    PalletCode = palletCode,
-        //                    NextAddress = "",
-        //                    OrderNo= task.OrderNo,
-        //                    Roadway = newLocation.RoadwayNo,
-        //                    SourceAddress = stations[task.TargetAddress],
-        //                    TargetAddress = newLocation.LocationCode,
-        //                    TaskStatus = TaskStatusEnum.New.ObjToInt(),
-        //                    TaskType = TaskTypeEnum.InPick.ObjToInt(),
-        //                    // TaskNum = BaseDal.GetTaskNum(nameof(SequenceEnum.SeqTaskNum)),
-        //                    PalletType = task.PalletType,
-        //                    WarehouseId = task.WarehouseId,
-        //                };
-        //                tasks.Add(newtask);
-
-        //            }
-        //        }
-        //        try
-        //        {
-        //            await _taskRepository.Db.Insertable(tasks).ExecuteCommandAsync();
-        //            //鍒犻櫎 鍑哄簱鐨�  task
-
-
-        //            //缁� ess  娴佸姩淇″彿  鍜屽垱寤轰换鍔�
-
-
-        //        }
-        //        catch (Exception ex)
-        //        {
-
-        //        }
-
-
-
-
-        //        return WebResponseContent.Instance.OK();
-        //    }
-        //    catch (Exception ex)
-        //    {
-        //        return WebResponseContent.Instance.Error($"鍥炲簱鎿嶄綔澶辫触: {ex.Message}");
-        //    }
-        //}
-
-        public async Task<WebResponseContent> ReturnRemaining(string orderNo, string palletCode, string reason)
-        {
-            try
-            {
-                // 1. 鑾峰彇鎵�鏈夋湭鍒嗘嫞鐨勫嚭搴撻攣瀹氳褰曪紝鍖呮嫭鎷嗗寘浜х敓鐨勮褰�
-                var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                    .Where(it => it.OrderNo == orderNo && it.Status == 1)
-                    .ToListAsync();
-
-                var stockinfo = _stockInfoService.Db.Queryable<Dt_StockInfo>().First(x => x.PalletCode == palletCode);
-
-                // 2. 妫�鏌ユ墭鐩樹笂鏄惁鏈夊叾浠栭潪鍑哄簱璐х墿锛堝簱瀛樿揣鐗╋級
-                var palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                    .Where(it => it.StockId == stockinfo.Id && it.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt())
-                    .Where(it => it.OutboundQuantity == 0 || it.OutboundQuantity < it.StockQuantity) // 鏈畬鍏ㄥ嚭搴撶殑
-                    .ToListAsync();
-
-                // 3. 濡傛灉娌℃湁闇�瑕佸洖搴撶殑璐х墿锛堟棦鏃犳湭鍒嗘嫞鍑哄簱璐х墿锛屼篃鏃犲叾浠栧簱瀛樿揣鐗╋級
-                if (!remainingLocks.Any() && !palletStockGoods.Any())
-                {
-                    return WebResponseContent.Instance.Error("娌℃湁闇�瑕佸洖搴撶殑鍓╀綑璐х墿");
-                }
-
-                var tasks = new List<Dt_Task>();
-
-                // 鏌ヨ浠诲姟琛�
-                var task = remainingLocks.Any()
-                    ? _taskRepository.QueryData(x => x.TaskNum == remainingLocks.First().TaskNum).FirstOrDefault()
-                    : _taskRepository.QueryData(x => x.PalletCode == palletCode).FirstOrDefault();
-
-                if (task == null)
-                {
-                    return WebResponseContent.Instance.Error("鏈壘鍒板搴旂殑浠诲姟淇℃伅");
-                }
-                var firstlocation = _locationInfoService.Db.Queryable<Dt_LocationInfo>().First(x => x.LocationCode == task.SourceAddress);
-                decimal totalReturnQty = 0;
-                var hasRemainingLocks = remainingLocks.Any(x => x.PalletCode == palletCode);
-
-                // 鎯呭喌1锛氬鐞嗘湭鍒嗘嫞鐨勫嚭搴撻攣瀹氳褰�
-                if (hasRemainingLocks)
-                {
-                    var palletLocks = remainingLocks.Where(x => x.PalletCode == palletCode).ToList();
-                    totalReturnQty = palletLocks.Sum(x => x.AssignQuantity - x.PickedQty);
-
-                    if (totalReturnQty > 0)
-                    {
-                        // 鍒嗛厤鏂拌揣浣�
-                        var newLocation = _locationInfoService.AssignLocation(firstlocation.LocationType);
-
-                        // 鏇存柊鍑哄簱閿佸畾璁板綍鐘舵��
-                        var lockIds = palletLocks.Select(x => x.Id).ToList();
-                        await _outStockLockInfoService.Db.Updateable<Dt_OutStockLockInfo>()
-                            .SetColumns(it => new Dt_OutStockLockInfo { Status = OutLockStockStatusEnum.鍥炲簱涓�.ObjToInt() })
-                            .Where(it => lockIds.Contains(it.Id))
-                            .ExecuteCommandAsync();
-
-                        // 鏇存柊鎷嗗寘鏉$爜璁板綍鐘舵��
-                        var splitBarcodes = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
-                            .Where(it => lockIds.Contains(it.OutStockLockInfoId))
-                            .ToListAsync();
-
-                        foreach (var splitBarcode in splitBarcodes)
-                        {
-                            splitBarcode.Status = 3;
-                            await _splitPackageService.Db.Updateable(splitBarcode).ExecuteCommandAsync();
-                        }
-
-                        // 澶勭悊搴撳瓨璁板綍
-                        foreach (var lockInfo in palletLocks)
-                        {
-                            decimal returnQty = lockInfo.AssignQuantity - lockInfo.PickedQty;
-
-                            // 妫�鏌ュ簱瀛樿褰曟槸鍚﹀瓨鍦�
-                            var existingStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                                .Where(it => it.Barcode == lockInfo.CurrentBarcode && it.StockId == lockInfo.StockId)
-                                .FirstAsync();
-
-                            if (existingStock != null)
-                            {
-                                // 搴撳瓨璁板綍瀛樺湪锛屾仮澶嶉攣瀹氭暟閲�
-                                await _stockInfoDetailService.Db.Updateable<Dt_StockInfoDetail>()
-                                    .SetColumns(it => new Dt_StockInfoDetail
-                                    {
-                                        OutboundQuantity = it.OutboundQuantity - returnQty
-                                    })
-                                    .Where(it => it.Barcode == lockInfo.CurrentBarcode && it.StockId == lockInfo.StockId)
-                                    .ExecuteCommandAsync();
-                            }
-                            else
-                            {
-                                // 搴撳瓨璁板綍涓嶅瓨鍦紙鍙兘鏄媶鍖呬骇鐢熺殑鏂版潯鐮侊級锛屽垱寤烘柊鐨勫簱瀛樿褰�
-                                var newStockDetail = new Dt_StockInfoDetail
-                                {
-                                    StockId = lockInfo.StockId,
-                                    MaterielCode = lockInfo.MaterielCode,
-                                    OrderNo = lockInfo.OrderNo,
-                                    BatchNo = lockInfo.BatchNo,
-                                    StockQuantity = returnQty,
-                                    OutboundQuantity = 0,
-                                    Barcode = lockInfo.CurrentBarcode,
-                                    InboundOrderRowNo = "0",
-                                    Status = StockStatusEmun.鍏ュ簱纭.ObjToInt(),
-
-                                };
-                                await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync();
-                            }
-                        }
-
-                        // 鍒涘缓鍥炲簱浠诲姟
-                        CreateReturnTask(tasks, task, palletCode, newLocation);
-                    }
-                }
-
-                // 鎯呭喌2锛氬嚭搴撹揣鐗╁凡鍒嗘嫞瀹岋紝浣嗘墭鐩樹笂杩樻湁鍏朵粬搴撳瓨璐х墿闇�瑕佸洖搴�
-                if (!hasRemainingLocks && palletStockGoods.Any())
-                {
-                    // 鍒嗛厤鏂拌揣浣�
-                    var newLocation = _locationInfoService.AssignLocation(firstlocation.LocationType);
-
-                    // 鍒涘缓鍥炲簱浠诲姟
-                    CreateReturnTask(tasks, task, palletCode, newLocation);
-
-                    totalReturnQty = palletStockGoods.Sum(x => x.StockQuantity - x.OutboundQuantity);
-                }
-
-                // 淇濆瓨浠诲姟
-                if (tasks.Any())
-                {
-                    try
-                    {
-                        await _taskRepository.Db.Insertable(tasks).ExecuteCommandAsync();
-
-                        // 缁� ESS 娴佸姩淇″彿鍜屽垱寤轰换鍔�
-                        try
-                        {
-                            var result = await _eSSApiService.MoveContainerAsync(new WIDESEA_DTO.Basic.MoveContainerRequest
-                            {
-                                slotCode = movestations[task.TargetAddress],
-                                containerCode = palletCode
-                            });
-                            if (result)
-                            {
-                                TaskModel esstask = new TaskModel()
-                                {
-                                    taskType = "putaway",
-                                    taskGroupCode = "",
-                                    groupPriority = 0,
-                                    tasks = new List<TasksType>
-                                    {
-                                        new()
-                                        {
-                                            taskCode = tasks.First().TaskNum.ToString(),
-                                            taskPriority = 0,
-                                            taskDescribe = new TaskDescribeType {
-                                                containerCode = palletCode,
-                                                containerType = "CT_KUBOT_STANDARD",
-                                                fromLocationCode = stations.GetValueOrDefault(task.TargetAddress) ?? "",
-                                                toStationCode = "",
-                                                toLocationCode = tasks.First().TargetAddress,
-                                                deadline = 0, storageTag = ""
-                                            }
-                                        }
-                                    }
-                                };
-                              
-
-                                var resulttask = await _eSSApiService.CreateTaskAsync(esstask);
-
-                                _logger.LogInformation("ReturnRemaining 鍒涘缓浠诲姟杩斿洖:  " + resulttask);
-                            }
-                        }
-                        catch (Exception ex)
-                        {
-                            _logger.LogInformation("ReturnRemaining 鍒涘缓浠诲姟杩斿洖 catch err:  " + ex.Message);
-
-                        }
-                
-
-                        return WebResponseContent.Instance.OK($"鍥炲簱鎿嶄綔鎴愬姛锛屽叡鍥炲簱鏁伴噺锛歿totalReturnQty}");
-                    }
-                    catch (Exception ex)
-                    {
-                        return WebResponseContent.Instance.Error($"鍒涘缓鍥炲簱浠诲姟澶辫触: {ex.Message}");
-                    }
-                }
-
-                return WebResponseContent.Instance.Error("鏈垱寤轰换浣曞洖搴撲换鍔�");
-            }
-            catch (Exception ex)
-            {
-                return WebResponseContent.Instance.Error($"鍥炲簱鎿嶄綔澶辫触: {ex.Message}");
-            }
-        }
-
-        /// <summary>
-        /// 鍒涘缓鍥炲簱浠诲姟
-        /// </summary>
-        private void CreateReturnTask(List<Dt_Task> tasks, Dt_Task originalTask, string palletCode, Dt_LocationInfo newLocation)
-        {
-            Dt_Task newTask = 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.InPick.ObjToInt(),
-                PalletType = originalTask.PalletType,
-                WarehouseId = originalTask.WarehouseId,
-
-            };
-            tasks.Add(newTask);
-        }
-
-        /// <summary>
-        /// 妫�鏌ユ墭鐩樻槸鍚﹂渶瑕佸洖搴撶殑杈呭姪鏂规硶
-        /// </summary>
-        public async Task<bool> CheckPalletNeedReturn(string orderNo, string palletCode)
-        {
-            // 1. 妫�鏌ユ槸鍚︽湁鏈垎鎷g殑鍑哄簱璁板綍
-            var hasUnpickedLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode && it.Status == 1)
-                .AnyAsync();
-
-            if (hasUnpickedLocks)
-                return true;
-
-            // 2. 妫�鏌ュ嚭搴撴槸鍚﹀凡瀹屾垚浣嗘墭鐩樿繕鏈夊簱瀛樿揣鐗�
-            var outboundFinished = !await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                .Where(it => it.PalletCode == palletCode && it.Status == 1)
-                .AnyAsync();
-
-            var stockinfo = _stockInfoService.Db.Queryable<Dt_StockInfo>().First(x => x.PalletCode == palletCode);
-
-
-            var hasRemainingGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                .Where(it => it.StockId == stockinfo.Id && it.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt())
-                .Where(it => it.OutboundQuantity == 0 || it.OutboundQuantity < it.StockQuantity)
-                .AnyAsync();
-
-            return outboundFinished && hasRemainingGoods;
-        }
-
-        // 鍙栨秷鎷i�夊姛鑳�
-        public async Task<WebResponseContent> CancelPicking(string orderNo, string palletCode, string barcode)
-        {
-            try
-            {
-                _unitOfWorkManage.BeginTran();
-                // 鏌ユ壘鎷i�夎褰�
-                var outStockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                        .Where(x => x.OrderNo == orderNo &&
-                                   x.PalletCode == palletCode &&
-                                   x.CurrentBarcode == barcode &&
-                                   x.Status == 2)
-                        .FirstAsync();
-
-                if (outStockInfo == null)
-                    return WebResponseContent.Instance.Error("鏈壘鍒板凡鎷i�夎褰�");
-
-                // 杩樺師鍑哄簱璇︽儏鐘舵��
-                outStockInfo.PickedQty = 0;
-                outStockInfo.Status = 1;
-                await _outStockLockInfoService.Db.Updateable(outStockInfo).ExecuteCommandAsync();
-
-                //// 杩樺師搴撳瓨鍑哄簱鏁伴噺
-                //await _stockInfoDetailService.Db.Updateable<Dt_StockInfoDetail>()
-                //        .SetColumns(x => x.OutboundQuantity == x.OutboundQuantity - outStockInfo.AssignQuantity)
-                //        .Where(x => x.Barcode == barcode)
-                //        .ExecuteCommandAsync();
-
-                // 杩樺師鍑哄簱鍗曟槑缁�
-                var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
-                    .Where(x => x.Id == outStockInfo.OrderDetailId)
-                    .FirstAsync();
-
-                orderDetail.OverOutQuantity -= outStockInfo.AssignQuantity;
-                await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync();
-
-                // 鍒犻櫎鎷i�夊巻鍙�
-                await Db.Deleteable<Dt_PickingRecord>()
-                    .Where(x => x.OutStockLockId == outStockInfo.Id)
-                    .ExecuteCommandAsync();
-
-                _unitOfWorkManage.CommitTran();
-                return WebResponseContent.Instance.OK("鍙栨秷鎷i�夋垚鍔�");
-
-            }
-            catch (Exception ex)
-            {
-                return WebResponseContent.Instance.Error($"鍙栨秷鎷i�夊け璐ワ細{ex.Message}");
-            }
-        }
-        /// <summary>
-        /// 鏍规嵁鏉$爜鏌ユ壘閿佸畾淇℃伅
-        /// </summary>
-        private async Task<Dt_OutStockLockInfo> FindLockInfoByBarcode(int orderDetailId, string barcode, string materielCode)
-        {
-            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)
-                .FirstAsync();
-        }
-
+        #region 鏌ヨ鏂规硶
         // 鑾峰彇鏈嫞閫夊垪琛�
         public async Task<List<Dt_OutStockLockInfo>> GetUnpickedList(string orderNo, string palletCode)
         {
@@ -878,268 +155,2227 @@
 
             return summary;
         }
+
+        #endregion
+
+        #region 鏍稿績涓氬姟娴佺▼
         /// <summary>
-        /// 鑾峰彇鎷i�夊巻鍙�
+        /// 鎷i��
         /// </summary>
-        public async Task<List<Dt_PickingRecord>> GetPickingHistory(int orderId)
+        /// <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)
         {
-            // 閫氳繃鍑哄簱鍗旾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();
-        }
-
-        public async Task GetPalletPickingSummary(string orderNo, string palletCode)
-        {
-            var summary = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode)
-                .GroupBy(x => new { x.PalletCode, x.Status })
-                .Select(x => new
-                {
-                    PalletCode = x.PalletCode,
-                    Status = x.Status,
-                    TotalAssignQty = SqlFunc.AggregateSum(x.AssignQuantity),
-                    TotalPickedQty = SqlFunc.AggregateSum(x.PickedQty)
-                })
-                .ToListAsync();
-
-            //   return summary;
-        }
-
-
-
-        /// <summary>
-        /// 鎾ら攢鎷i��
-        /// </summary>
-        public async Task<WebResponseContent> CancelPicking(CancelPickingRequest request)
-        {
-            // 瀹炵幇鎾ら攢鎷i�夌殑閫昏緫锛岄渶瑕侊細
-            // 1. 鎭㈠搴撳瓨鍑哄簱鏁伴噺
-            // 2. 鎭㈠閿佸畾淇℃伅鐨勫凡鎷i�夋暟閲�
-            // 3. 鎭㈠鍑哄簱鍗曟槑缁嗙殑宸插嚭鏁伴噺鍜岄攣瀹氭暟閲�
-            // 4. 鍒犻櫎鎴栨爣璁版嫞閫夊巻鍙茶褰�
-            // 娉ㄦ剰锛氳繖閲岄渶瑕佷簨鍔″鐞�
             try
             {
                 _unitOfWorkManage.BeginTran();
 
-                var pickHistory = await Db.Queryable<Dt_PickingRecord>()
-                    .Where(x => x.Id == request.PickingHistoryId)
-                    .FirstAsync();
+                var validationResult = await ValidatePickingRequest(orderNo, palletCode, barcode);
+                if (!validationResult.IsValid)
+                    return WebResponseContent.Instance.Error(validationResult.ErrorMessage);
 
-                if (pickHistory == null)
-                    return WebResponseContent.Instance.Error("鏈壘鍒版嫞閫夎褰�");
+                var (lockInfo, orderDetail, stockDetail) = validationResult.Data;
 
-                // 鎭㈠搴撳瓨
-                var stockDetail = await _stockInfoService.Db.Queryable<Dt_StockInfoDetail>()
-                    .Where(x => x.Barcode == pickHistory.Barcode && x.StockId == pickHistory.StockId)
-                    .FirstAsync();
-                if (stockDetail != null)
+                // 璁$畻瀹為檯鎷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)
                 {
-                    stockDetail.OutboundQuantity -= pickHistory.PickQuantity;
-                    await _stockInfoService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+                    return WebResponseContent.Instance.Error(overPickingValidation.ErrorMessage);
                 }
-                // 鎭㈠閿佸畾淇℃伅
-                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();
+                // 鎵ц鍒嗘嫞閫昏緫锛堝彧澶勭悊搴撳瓨鍜岄攣瀹氾紝涓嶅鐞嗚鍗曪級
+                var pickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, orderNo, palletCode, barcode, actualQty);
 
-                // 鍒犻櫎鎷i�夊巻鍙茶褰�
-                await Db.Deleteable<Dt_PickingRecord>().Where(x => x.Id == request.PickingHistoryId).ExecuteCommandAsync();
+                // 缁熶竴鏇存柊璁㈠崟鏁版嵁锛堟墍鏈夊垎鏀兘鍦ㄨ繖閲屾洿鏂帮級
+                await UpdateOrderRelatedData(orderDetail.Id, pickingResult.ActualPickedQty, orderNo);
+
+                // 璁板綍鎿嶄綔鍘嗗彶
+                await RecordPickingHistory(pickingResult, orderNo, palletCode);
 
                 _unitOfWorkManage.CommitTran();
-                return WebResponseContent.Instance.OK("鎾ら攢鎴愬姛");
+
+                return CreatePickingResponse(pickingResult, adjustedReason);
             }
             catch (Exception ex)
             {
                 _unitOfWorkManage.RollbackTran();
-                return WebResponseContent.Instance.Error($"鎾ら攢澶辫触: {ex.Message}");
+                _logger.LogError($"ConfirmPicking澶辫触 - OrderNo: {orderNo}, PalletCode: {palletCode}, Barcode: {barcode}, Error: {ex.Message}");
+                return WebResponseContent.Instance.Error($"鎷i�夌‘璁ゅけ璐ワ細{ex.Message}");
             }
         }
 
         /// <summary>
-        /// 鑾峰彇鎵樼洏鐨勫嚭搴撶姸鎬佷俊鎭�
+        /// 鍙栨秷鎷i��
         /// </summary>
-        public async Task<WebResponseContent> GetPalletOutboundStatus(string palletCode)
+        /// <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)
         {
-            // 鑾峰彇鎵樼洏鐨勯攣瀹氫俊鎭�
-            var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                .Where(x => x.PalletCode == palletCode)
-                .ToListAsync();
+            try
+            {
+                if (await IsPalletReturned(palletCode))
+                {
+                    return WebResponseContent.Instance.Error($"鎵樼洏{palletCode}宸茬粡鍥炲簱锛屼笉鑳藉彇娑堝垎鎷�");
+                }
+                _unitOfWorkManage.BeginTran();
 
-            // 鑾峰彇鎵樼洏搴撳瓨淇℃伅
+                // 鍓嶇疆楠岃瘉
+                var validationResult = await ValidateCancelRequest(orderNo, palletCode, barcode);
+                if (!validationResult.IsValid)
+                    return WebResponseContent.Instance.Error(validationResult.ErrorMessage);
+
+                var (pickingRecord, lockInfo, orderDetail) = validationResult.Data;
+
+                //鎵ц鍙栨秷閫昏緫
+                await ExecuteCancelLogic(lockInfo, pickingRecord, orderDetail, orderNo);
+
+                _unitOfWorkManage.CommitTran();
+
+                return WebResponseContent.Instance.OK($"鍙栨秷鍒嗘嫞鎴愬姛");
+            }
+            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, task.PalletType);
+
+                // 鏇存柊璁㈠崟鐘舵�侊紙涓嶈Е鍙慚ES鍥炰紶锛�
+                await UpdateOrderStatusForReturn(orderNo);
+
+                return WebResponseContent.Instance.OK($"鍥炲簱鎿嶄綔鎴愬姛");
+                //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 (order == null)
+                    return WebResponseContent.Instance.Error($"鏈壘鍒拌鍗� {orderNo}");
+
+                //妫�鏌ユ墭鐩樻槸鍚﹀瓨鍦ㄤ笖灞炰簬璇ヨ鍗�
+                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
+                    .Where(x => x.PalletCode == palletCode)
+                    .FirstAsync();
+
+                if (stockInfo == null)
+                    return WebResponseContent.Instance.Error($"鏈壘鍒版墭鐩� {palletCode} 瀵瑰簲鐨勫簱瀛樹俊鎭�");
+
+                var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id);
+
+                if (!statusAnalysis.CanRemove)
+                {
+                    if (!statusAnalysis.IsEmptyPallet)
+                    {
+                        return WebResponseContent.Instance.Error($"鎵樼洏 {palletCode} 涓婅繕鏈夎揣鐗╋紝涓嶈兘鍙栬蛋");
+                    }
+                    if (statusAnalysis.HasActiveTasks)
+                    {
+                        return WebResponseContent.Instance.Error($"鎵樼洏 {palletCode} 杩樻湁杩涜涓殑浠诲姟锛屼笉鑳藉彇璧�");
+                    }
+                }
+                // 娓呯悊闆跺簱瀛樻暟鎹�
+                await CleanupZeroStockData(stockInfo.Id);
+
+                // 鍒犻櫎鎴栧彇娑堢浉鍏充换鍔�
+                await HandleTaskCleanup(orderNo, palletCode);
+
+                // 鏇存柊璁㈠崟鐩稿叧鏁版嵁
+                await UpdateOrderData(orderNo, palletCode);
+
+
+                _unitOfWorkManage.CommitTran();
+
+                _logger.LogInformation($"绌烘墭鐩樺彇璧版搷浣滄垚鍔� - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}, 鎿嶄綔浜�: {App.User.UserName}");
+
+                return WebResponseContent.Instance.OK("绌烘墭鐩樺彇璧版搷浣滄垚鍔�");
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                _logger.LogError($"RemoveEmptyPallet澶辫触 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
+                return WebResponseContent.Instance.Error($"绌烘墭鐩樺彇璧板け璐�: {ex.Message}");
+            }
+        }
+        #endregion
+
+        #region 鍒嗘嫞纭绉佹湁鏂规硶
+
+        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)
+                {
+                    // 妫�鏌ユ槸鍚﹀凡缁忓畬鎴愬垎鎷�
+                    var completedLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                        .Where(it => it.CurrentBarcode == barcode &&
+                                   (it.Status == (int)OutLockStockStatusEnum.鎷i�夊畬鎴� ||
+                                    it.PickedQty >= it.AssignQuantity)).FirstAsync();
+
+                    if (completedLockInfo != null)
+                        throw new Exception($"鏉$爜{barcode}宸茬粡瀹屾垚鍒嗘嫞锛屼笉鑳介噸澶嶅垎鎷�");
+                    else
+                        return null;
+                }
+            }
+
+            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)
+            {
+                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<ValidationResult<bool>> ValidateOverPicking(int orderDetailId, decimal pickingQty)
+        {
+            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
+            };
+
+            if (actualQty < stockQuantity)
+            {
+                await HandleSplitPacking(lockInfo, stockDetail, actualQty, stockQuantity, result);
+                // 鎷嗗寘鍦烘櫙杩斿洖瀹為檯鎷i�夋暟閲�
+                result.ActualPickedQty = actualQty;
+            }
+            else if (actualQty == stockQuantity)
+            {
+                await HandleFullPicking(lockInfo, stockDetail, actualQty, result);
+                // 鏁村寘鎷i�夎繑鍥炲疄闄呮嫞閫夋暟閲�
+                result.ActualPickedQty = actualQty;
+            }
+            else
+            {
+                await HandlePartialPicking(lockInfo, stockDetail, actualQty, stockQuantity, result);
+                // 閮ㄥ垎鎷i�夎繑鍥炶皟鏁村悗鐨勬暟閲�
+                result.ActualPickedQty = result.ActualPickedQty; // 宸茬粡鍦ㄦ柟娉曞唴璋冩暣
+            }
+
+            return result;
+        }
+        private async Task HandleSplitPacking(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
+       decimal actualQty, decimal stockQuantity, PickingResult result)
+        {
+            decimal 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();
+
+            if (result.FinalLockInfo.Id <= 0)
+            {
+                throw new Exception($"閿佸畾淇℃伅ID鏃犳晥: {result.FinalLockInfo.Id}锛屾棤娉曡褰曟嫞閫夊巻鍙�");
+            }
+
+            var pickingHistory = new Dt_PickingRecord
+            {
+                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<bool>> ValidateDataConsistencyBeforeCancel(CancelPickingContext context)
+        {
+            try
+            {
+                //  楠岃瘉璁㈠崟鏄庣粏鏁版嵁
+                var currentOrderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                    .FirstAsync(x => x.Id == context.OrderDetail.Id);
+
+                if (currentOrderDetail.OverOutQuantity < context.PickingRecord.PickQuantity)
+                    return ValidationResult<bool>.Error($"璁㈠崟鏄庣粏宸插嚭搴撴暟閲�({currentOrderDetail.OverOutQuantity})灏忎簬鍙栨秷鏁伴噺({context.PickingRecord.PickQuantity})");
+
+                if (currentOrderDetail.PickedQty < context.PickingRecord.PickQuantity)
+                    return ValidationResult<bool>.Error($"璁㈠崟鏄庣粏宸叉嫞閫夋暟閲�({currentOrderDetail.PickedQty})灏忎簬鍙栨秷鏁伴噺({context.PickingRecord.PickQuantity})");
+
+                //  楠岃瘉閿佸畾淇℃伅鏁版嵁
+                var currentLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                    .FirstAsync(x => x.Id == context.LockInfo.Id);
+
+                if (currentLockInfo.PickedQty < context.PickingRecord.PickQuantity)
+                    return ValidationResult<bool>.Error($"閿佸畾淇℃伅宸叉嫞閫夋暟閲�({currentLockInfo.PickedQty})灏忎簬鍙栨秷鏁伴噺({context.PickingRecord.PickQuantity})");
+
+                // 楠岃瘉搴撳瓨鏁版嵁
+                var currentStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                    .FirstAsync(x => x.Barcode == context.PickingRecord.Barcode && x.StockId == context.PickingRecord.StockId);
+
+                if (currentStockDetail == null)
+                    return ValidationResult<bool>.Error($"鏈壘鍒板搴旂殑搴撳瓨鏄庣粏璁板綍");
+
+                if (currentStockDetail.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt() ||
+                    currentStockDetail.Status == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt())
+                    return ValidationResult<bool>.Error($"鏉$爜{context.PickingRecord.Barcode}宸茬粡鍥炲簱锛屾棤娉曞彇娑堝垎鎷�");
+
+                // 楠岃瘉鐘舵�佹祦杞殑鍚堟硶鎬�
+                if (!await CanCancelPicking(currentLockInfo, currentStockDetail))
+                    return ValidationResult<bool>.Error($"褰撳墠鐘舵�佷笉鍏佽鍙栨秷鍒嗘嫞");
+
+                return ValidationResult<bool>.Success(true);
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError($"鍙栨秷鍒嗘嫞鏁版嵁涓�鑷存�ч獙璇佸け璐�: {ex.Message}");
+                return ValidationResult<bool>.Error($"鏁版嵁楠岃瘉澶辫触: {ex.Message}");
+            }
+        }
+
+        private async Task<bool> CanCancelPicking(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail)
+        {
+            // 閿佸畾淇℃伅鐘舵�佹鏌�
+            if (lockInfo.Status != (int)OutLockStockStatusEnum.鎷i�夊畬鎴�)
+                return false;
+
+            // 搴撳瓨鐘舵�佹鏌�
+            if (stockDetail.Status == StockStatusEmun.鍑哄簱瀹屾垚.ObjToInt())
+                return false;
+
+            // 濡傛灉鏄媶鍖呰褰曪紝杩橀渶瑕佹鏌ョ埗閿佸畾淇℃伅鐘舵��
+            if (lockInfo.IsSplitted == 1 && lockInfo.ParentLockId.HasValue)
+            {
+                var parentLock = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                    .FirstAsync(x => x.Id == lockInfo.ParentLockId.Value);
+
+                if (parentLock == null || parentLock.Status == (int)OutLockStockStatusEnum.鍥炲簱涓�)
+                    return false;
+            }
+
+            return true;
+        }
+        private async Task<ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>> ValidateCancelRequest(string orderNo, string palletCode, string barcode)
+        {
+            // 鍩虹鍙傛暟楠岃瘉
+            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 context = new CancelPickingContext
+            {
+                LockInfo = lockInfo,
+                PickingRecord = pickingRecord,
+                OrderDetail = orderDetail,
+                OrderNo = orderNo,
+                CancelQuantity = cancelQty
+            };
+
+            var validationResult = await ValidateDataConsistencyBeforeCancel(context);
+            if (!validationResult.IsValid)
+                throw new Exception(validationResult.ErrorMessage);
+
+            // 澶勭悊涓嶅悓绫诲瀷鐨勫彇娑�
+            if (lockInfo.IsSplitted == 1 && lockInfo.ParentLockId.HasValue)
+            {
+                await HandleSplitBarcodeCancel(lockInfo, pickingRecord, cancelQty);
+            }
+            else
+            {
+                await HandleNormalBarcodeCancel(lockInfo, pickingRecord, cancelQty);
+            }
+
+            //  鏇存柊璁㈠崟鏄庣粏
+            await UpdateOrderDetailOnCancel(pickingRecord.OrderDetailId, cancelQty);
+
+            //  鍒犻櫎鎷i�夎褰�
+            var deleteResult = await Db.Deleteable<Dt_PickingRecord>()
+                .Where(x => x.Id == pickingRecord.Id)
+                .ExecuteCommandAsync();
+
+            if (deleteResult <= 0)
+                throw new Exception("鍒犻櫎鎷i�夎褰曞け璐�");
+
+            _logger.LogInformation($"鍒犻櫎鎷i�夎褰� - 璁板綍ID: {pickingRecord.Id}, 鏉$爜: {pickingRecord.Barcode}");
+
+            // 閲嶆柊妫�鏌ヨ鍗曠姸鎬�
+            await UpdateOrderStatusForReturn(orderNo);
+
+
+        }
+
+        private async Task HandleSplitBarcodeCancel(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord, decimal cancelQty)
+        {
+            // 鏌ユ壘鐖堕攣瀹氫俊鎭�
+            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;
+            parentLockInfo.Status = (int)OutLockStockStatusEnum.鍑哄簱涓�; // 鎭㈠涓哄嚭搴撲腑鐘舵��
+            await _outStockLockInfoService.Db.Updateable(parentLockInfo).ExecuteCommandAsync();
+
+            // 鎭㈠鐖舵潯鐮佸簱瀛�
+            var parentStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(x => x.Barcode == parentLockInfo.CurrentBarcode && x.StockId == parentLockInfo.StockId)
+                .FirstAsync();
+
+            if (parentStockDetail != null)
+            {
+                parentStockDetail.StockQuantity += cancelQty;
+                parentStockDetail.OutboundQuantity = parentStockDetail.StockQuantity;
+                parentStockDetail.Status = StockStatusEmun.鍑哄簱閿佸畾.ObjToInt();
+                await _stockInfoDetailService.Db.Updateable(parentStockDetail).ExecuteCommandAsync();
+
+                _logger.LogInformation($"鎭㈠鐖舵潯鐮佸簱瀛� - 鏉$爜: {parentStockDetail.Barcode}, 鎭㈠鏁伴噺: {cancelQty}, 鏂板簱瀛�: {parentStockDetail.StockQuantity}");
+            }
+
+            // 澶勭悊鎷嗗寘浜х敓鐨勬柊鏉$爜搴撳瓨
+            var splitStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(x => x.Barcode == lockInfo.CurrentBarcode && x.StockId == lockInfo.StockId)
+                .FirstAsync();
+
+            if (splitStockDetail != null)
+            {
+                // 鍒犻櫎鎷嗗寘浜х敓鐨勬柊鏉$爜搴撳瓨璁板綍
+                await _stockInfoDetailService.Db.Deleteable(splitStockDetail).ExecuteCommandAsync();
+                _logger.LogInformation($"鍒犻櫎鎷嗗寘鏂版潯鐮佸簱瀛� - 鏉$爜: {splitStockDetail.Barcode}");
+            }
+
+            // 鏇存柊鎷嗗寘璁板綍鐘舵��
+            var updateCount = await _splitPackageService.Db.Updateable<Dt_SplitPackageRecord>()
+                .SetColumns(x => new Dt_SplitPackageRecord
+                {
+                    Status = (int)SplitPackageStatusEnum.宸叉挙閿�,
+                    IsReverted = true,
+                    Operator = App.User.UserName,
+                    RevertTime = DateTime.Now
+                })
+                .Where(x => x.NewBarcode == lockInfo.CurrentBarcode && !x.IsReverted)
+                .ExecuteCommandAsync();
+
+            _logger.LogInformation($"鏇存柊鎷嗗寘璁板綍鐘舵�� - 鏇存柊璁板綍鏁�: {updateCount}");
+
+            // 鍒犻櫎鎷嗗寘浜х敓鐨勯攣瀹氫俊鎭�
+            await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
+                .Where(x => x.Id == lockInfo.Id)
+                .ExecuteCommandAsync();
+
+            _logger.LogInformation($"鍒犻櫎鎷嗗寘閿佸畾淇℃伅 - 閿佸畾ID: {lockInfo.Id}, 鏉$爜: {lockInfo.CurrentBarcode}");
+        }
+        private async Task HandleNormalBarcodeCancel(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord, decimal cancelQty)
+        {
+            if (await IsLockInfoReturned(lockInfo))
+                throw new Exception($"鏉$爜{lockInfo.CurrentBarcode}宸茬粡鍥炲簱锛屾棤娉曞彇娑堝垎鎷�");
+
+            // 鎭㈠閿佸畾淇℃伅
+            lockInfo.PickedQty -= cancelQty;
+            if (lockInfo.PickedQty < 0) lockInfo.PickedQty = 0;
+
+            // 鍙湁褰撴嫞閫夋暟閲忓畬鍏ㄥ彇娑堟椂鎵嶆仮澶嶇姸鎬�
+            if (lockInfo.PickedQty == 0)
+            {
+                lockInfo.Status = (int)OutLockStockStatusEnum.鍑哄簱涓�;
+            }
+
+            lockInfo.Operator = App.User.UserName;
+            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
+
+            _logger.LogInformation($"鎭㈠閿佸畾淇℃伅 - 閿佸畾ID: {lockInfo.Id}, 鎵e噺鎷i�夋暟閲�: {cancelQty}, 鏂板凡鎷i�夋暟閲�: {lockInfo.PickedQty}");
+
+            // 鎭㈠搴撳瓨
+            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(x => x.Barcode == pickingRecord.Barcode && x.StockId == pickingRecord.StockId)
+                .FirstAsync();
+
+            if (stockDetail != null)
+            {
+                stockDetail.StockQuantity += cancelQty;
+                stockDetail.OutboundQuantity = stockDetail.StockQuantity;
+
+                // 鎭㈠搴撳瓨鐘舵��
+                if (stockDetail.Status == StockStatusEmun.鍑哄簱瀹屾垚.ObjToInt())
+                {
+                    stockDetail.Status = StockStatusEmun.鍑哄簱閿佸畾.ObjToInt();
+                }
+
+                await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+
+                _logger.LogInformation($"鎭㈠搴撳瓨 - 鏉$爜: {stockDetail.Barcode}, 鎭㈠鏁伴噺: {cancelQty}, " +
+                                      $"鏂板簱瀛�: {stockDetail.StockQuantity}, 鏂扮姸鎬�: {stockDetail.Status}");
+            }
+            else
+            {
+                _logger.LogWarning($"鏈壘鍒板簱瀛樿褰� - 鏉$爜: {pickingRecord.Barcode}, 搴撳瓨ID: {pickingRecord.StockId}");
+            }
+        }
+        private async Task UpdateOrderDetailOnCancel(int orderDetailId, decimal cancelQty)
+        {
+            // 鑾峰彇鏈�鏂扮殑璁㈠崟鏄庣粏鏁版嵁锛堝甫閿侊級
+            var currentOrderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                .With(SqlWith.RowLock)
+                .FirstAsync(x => x.Id == orderDetailId);
+
+            decimal newOverOutQuantity = currentOrderDetail.OverOutQuantity - cancelQty;
+            decimal newPickedQty = currentOrderDetail.PickedQty - cancelQty;
+
+            // 涓ユ牸妫�鏌ュ彇娑堝悗鏁伴噺涓嶄細涓鸿礋鏁�
+            if (newOverOutQuantity < 0)
+                throw new Exception($"鍙栨秷鍒嗘嫞灏嗗鑷村凡鍑哄簱鏁伴噺({newOverOutQuantity})涓鸿礋鏁�");
+
+            if (newPickedQty < 0)
+                throw new Exception($"鍙栨秷鍒嗘嫞灏嗗鑷村凡鎷i�夋暟閲�({newPickedQty})涓鸿礋鏁�");
+
+            // 鏇存柊璁㈠崟鏄庣粏
+            var updateResult = await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
+                .SetColumns(it => new Dt_OutboundOrderDetail
+                {
+                    PickedQty = newPickedQty,
+                    OverOutQuantity = newOverOutQuantity
+                })
+                .Where(it => it.Id == orderDetailId)
+                .ExecuteCommandAsync();
+
+            if (updateResult <= 0)
+                throw new Exception("鏇存柊璁㈠崟鏄庣粏澶辫触");
+
+            _logger.LogInformation($"鏇存柊璁㈠崟鏄庣粏 - OrderDetailId: {orderDetailId}, " +
+                                  $"鎵e噺宸插嚭搴�: {cancelQty}, 鏂板凡鍑哄簱: {newOverOutQuantity}, " +
+                                  $"鎵e噺宸叉嫞閫�: {cancelQty}, 鏂板凡鎷i��: {newPickedQty}");
+        }
+        #endregion
+
+        #region 鍥炲簱鎿嶄綔绉佹湁鏂规硶
+
+        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;
         }
 
-        /// <summary>
-        /// 鐩存帴鍑哄簱 - 鏁翠釜鎵樼洏鍑哄簱锛屾竻绌哄簱瀛�
-        /// </summary>
-        public async Task<WebResponseContent> DirectOutbound(DirectOutboundRequest request)
+        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 (splitRecord.Status != (int)SplitPackageStatusEnum.宸叉挙閿�)
+                    continue;
+                // 妫�鏌ュ師鏉$爜
+                if (!processedBarcodes.Contains(splitRecord.OriginalBarcode))
+                {
+                    var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                        .Where(it => it.Barcode == splitRecord.OriginalBarcode && it.StockId == stockId &&
+                           it.Status != StockStatusEmun.鍑哄簱瀹屾垚.ObjToInt())
+                        .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 && it.Status != StockStatusEmun.鍑哄簱瀹屾垚.ObjToInt())
+                        .FirstAsync();
+
+                    if (newStock != null && newStock.StockQuantity > 0)
+                    {
+                        totalQty += newStock.StockQuantity;
+                        processedBarcodes.Add(splitRecord.NewBarcode);
+                    }
+                }
+            }
+
+            return totalQty;
+        }
+
+        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();
-
+                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("鏈壘鍒版墭鐩樺簱瀛樹俊鎭�");
-
-
-                var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                    .Where(x => x.OrderNo == request.OrderNo && x.PalletCode == request.PalletCode)
-                    .ToListAsync();
-
-
-                foreach (var lockInfo in lockInfos)
                 {
-                    if (lockInfo.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
-                    {
-                        lockInfo.PickedQty = lockInfo.AssignQuantity;
-                    }
-                    lockInfo.Status = (int)OutLockStockStatusEnum.宸插嚭搴�;
-                    await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
-
-                    var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
-                    .Where(x => x.Id == lockInfo.OrderDetailId)
-                    .FirstAsync();
-                    if (orderDetail != null)
-                    {
-                        orderDetail.OverOutQuantity += lockInfo.PickedQty;
-                        orderDetail.LockQuantity -= lockInfo.PickedQty;
-                        orderDetail.OrderDetailStatus = (int)OrderDetailStatusEnum.Over;
-                        orderDetail.LockQuantity = 0;
-                        await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync();
-                    }
+                    var firstLocation = await _locationInfoService.Db.Queryable<Dt_LocationInfo>().FirstAsync(x => x.LocationCode == originalTask.SourceAddress);
+                    locationtype = firstLocation?.LocationType ?? 1;
                 }
-                var groupDetails = lockInfos.GroupBy(x => x.OrderDetailId).Select(x => new
+                else
                 {
-                    OrderDetailId = x.Key,
-                    TotalQuantity = x.Sum(o => o.PickedQty)
-                }).ToList();
-                foreach (var item in groupDetails)
-                {
-                    var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>().Where(x => x.Id == item.OrderDetailId).FirstAsync();
-                    if (orderDetail != null)
-                    {
-                        orderDetail.OverOutQuantity = item.TotalQuantity;
-                        orderDetail.LockQuantity = 0;
-                        orderDetail.OrderDetailStatus = (int)OrderDetailStatusEnum.Over;
-                        await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync();
-                    }
+                    locationtype = stockInfo.LocationType;
+                    _stockInfoService.DeleteData(stockInfo);
                 }
 
-                await CheckAndUpdateOrderStatus(request.OrderNo);
+                var targetAddress = originalTask.TargetAddress;
 
-                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();
-
-                foreach (var record in splitRecords)
-                {
-                    record.Status = (int)SplitPackageStatusEnum.宸叉嫞閫�;
-                    await _splitPackageService.Db.Updateable(record).ExecuteCommandAsync();
-                }
+                await CleanupZeroStockData(stockInfoId);
 
 
-                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();
-                }
+                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();
 
-                foreach (var detail in stockInfo.Details)
-                {
-                    await _stockInfoDetailService.Db.Deleteable(detail).ExecuteCommandAsync();
-                }
-                await _stockInfoService.Db.Deleteable(stockInfo).ExecuteCommandAsync();
+                await CreateReturnTaskAndHandleESS(orderNo, palletCode, originalTask, TaskTypeEnum.InEmpty, PalletTypeEnum.Empty.ObjToInt());
 
-
-
-                _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)
+            {
+                var validStockGoods = analysis.PalletStockGoods
+            .Where(x => x.Status != StockStatusEmun.鍑哄簱瀹屾垚.ObjToInt())
+            .ToList();
+
+                if (validStockGoods.Any())
+                {
+                    await HandlePalletStockGoodsReturn(analysis.PalletStockGoods);
+                }
+                else
+                {
+                    _logger.LogInformation("娌℃湁鏈夋晥鐨勫簱瀛樿揣鐗╅渶瑕佸洖搴�");
+                }
+            }
+
+            // 澶勭悊鎷嗗寘璁板綍
+            if (analysis.HasSplitRecords)
+            {
+                var validSplitRecords = analysis.SplitRecords
+            .Where(x => x.Status != (int)SplitPackageStatusEnum.宸叉嫞閫�)
+            .ToList();
+
+                if (validSplitRecords.Any())
+                {
+                    await HandleSplitRecordsReturn(analysis.SplitRecords, orderNo, palletCode);
+                }
+                else
+                {
+                    _logger.LogInformation("娌℃湁鏈夋晥鐨勬媶鍖呰褰曢渶瑕佸鐞�");
+                }
+            }
+
+            // 鏇存柊搴撳瓨涓昏〃鐘舵��
+            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;
+                if (returnQty <= 0)
+                {
+                    _logger.LogWarning($"閿佸畾璁板綍{lockInfo.Id}鏃犻渶鍥炲簱锛屽垎閰嶆暟閲�: {lockInfo.AssignQuantity}, 宸叉嫞閫�: {lockInfo.PickedQty}");
+                    continue;
+                }
+
+                _logger.LogInformation($"澶勭悊閿佸畾璁板綍鍥炲簱 - 閿佸畾ID: {lockInfo.Id}, 鏉$爜: {lockInfo.CurrentBarcode}, 鍥炲簱鏁伴噺: {returnQty}");
+                // 鏌ユ壘瀵瑰簲鐨勫簱瀛樻槑缁�
+                var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                    .Where(it => it.Barcode == lockInfo.CurrentBarcode && it.StockId == lockInfo.StockId)
+                    .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}");
+
+                if (stockGood.Status != StockStatusEmun.鍑哄簱瀹屾垚.ObjToInt())
+                {
+                    stockGood.OutboundQuantity = 0;
+                    stockGood.Status = StockStatusEmun.鍏ュ簱纭.ObjToInt();
+                    await _stockInfoDetailService.Db.Updateable(stockGood).ExecuteCommandAsync();
+
+                    _logger.LogInformation($"搴撳瓨璐х墿鍥炲簱瀹屾垚 - 鏉$爜: {stockGood.Barcode}, 鏂扮姸鎬�: {stockGood.Status}");
+                }
+                else
+                {
+                    _logger.LogWarning($"璺宠繃宸插嚭搴撳畬鎴愮殑璐х墿 - 鏉$爜: {stockGood.Barcode}");
+                }
+            }
+        }
+
+        private async Task HandleSplitRecordsReturn(List<Dt_SplitPackageRecord> splitRecords, string orderNo, string palletCode)
+        {
+            var validRecords = splitRecords.Where(x => x.Status != (int)SplitPackageStatusEnum.宸叉嫞閫�).ToList();
+
+            if (!validRecords.Any())
+            {
+                _logger.LogInformation("娌℃湁闇�瑕佸洖搴撶殑鎷嗗寘璁板綍");
+                return;
+            }
+
+            _logger.LogInformation($"鏇存柊{validRecords.Count}鏉℃媶鍖呰褰曠姸鎬佷负宸插洖搴�");
+
+            // 鏇存柊鎷嗗寘璁板綍鐘舵��
+            await _splitPackageService.Db.Updateable<Dt_SplitPackageRecord>()
+                .SetColumns(x => new Dt_SplitPackageRecord
+                {
+                    Status = (int)SplitPackageStatusEnum.宸插洖搴�,
+                    Operator = App.User.UserName
+                })
+                .Where(x => validRecords.Select(r => r.Id).Contains(x.Id))
+                .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, int palletType)
+        {
+            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,
+                OrderNo = orderNo,
+                Roadway = newLocation.RoadwayNo,
+                SourceAddress = stations[originalTask.TargetAddress],
+                TargetAddress = newLocation.LocationCode,
+                TaskStatus = TaskStatusEnum.New.ObjToInt(),
+                TaskType = taskTypeEnum.ObjToInt(),
+                PalletType = 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 => new Dt_OutboundOrder
+                        {
+                            OrderStatus = newStatus,
+                            Operator = App.User.UserName,
+                        })
+                        .Where(x => x.OrderNo == orderNo)
+                        .ExecuteCommandAsync();
+
+                    // 鍙湁姝e父鍒嗘嫞瀹屾垚鏃舵墠鍚慚ES鍙嶉
+                    //if (allCompleted && newStatus == (int)OutOrderStatusEnum.鍑哄簱瀹屾垚)
+                    //{
+                    //    await HandleOrderCompletion(outboundOrder, orderNo);
+                    //}
+                }
+            }
+            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 => new Dt_OutboundOrder
+                          {
+                              OrderStatus = newStatus,
+                              Operator = App.User.UserName,
+                          })
+                        .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())
+            {
+                var allocate = _allocateService.Repository.QueryData(x => x.UpperOrderNo == outboundOrder.UpperOrderNo).First();
+                var feedmodel = new AllocateDto
+                {
+                    ReqCode = Guid.NewGuid().ToString(),
+                    ReqTime = DateTime.Now.ToString(),
+                    BusinessType = "3",
+                  
+                    FactoryArea = outboundOrder.FactoryArea,
+                    OperationType = 1,
+                    Operator = App.User.UserName,
+                    OrderNo = outboundOrder.UpperOrderNo,
+                   // documentsNO = outboundOrder.OrderNo,
+                   // status = outboundOrder.OrderStatus,
+                    fromWarehouse = allocate?.FromWarehouse ?? "",
+                    toWarehouse = allocate?.ToWarehouse ?? "",
+                    Details = new List<AllocateDtoDetail>()
+
+                };
+                // 鍙幏鍙栧凡鎷i�夊畬鎴愮殑閿佸畾璁板綍
+                var lists = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                    .Where(x => x.OrderNo == orderNo && x.Status == (int)OutLockStockStatusEnum.鎷i�夊畬鎴�)
+                    .ToListAsync();
+
+                var groupedData = lists.GroupBy(item => new { item.MaterielCode, item.lineNo, item.Unit, item.WarehouseCode })
+                   .Select(group => new AllocateDtoDetail
+                   {
+                       MaterialCode = group.Key.MaterielCode,
+                       LineNo = group.Key.lineNo,
+                       WarehouseCode = group.Key.WarehouseCode,
+                       Qty = group.Sum(x => x.PickedQty),
+                      
+                       Unit = group.Key.Unit,
+                       Barcodes = group.Select(row => new BarcodeInfo
+                       {
+                           Barcode = row.CurrentBarcode,
+                           SupplyCode = row.SupplyCode,
+                           BatchNo = row.BatchNo,
+                           Unit = row.Unit,
+                           Qty = row.PickedQty
+                       }).ToList()
+
+                  
+                   }).ToList();
+                feedmodel.Details = groupedData;
+
+                var result = await _invokeMESService.FeedbackAllocate(feedmodel);
+                if (result != null && result.code == 200)
+                {                    
+                    await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
+                           .SetColumns(x => x.ReturnToMESStatus == 1)
+                           .Where(x => x.OrderId == outboundOrder.Id).ExecuteCommandAsync();
+
+                    await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
+                          .SetColumns(x => new Dt_OutboundOrder
+                          {
+                              ReturnToMESStatus = 1,
+                              Operator = App.User.UserName,
+                          }).Where(x => x.OrderNo == orderNo).ExecuteCommandAsync();
+                }
+            }
+            else if (outboundOrder.OrderType == OutOrderTypeEnum.ReCheck.ObjToInt())
+            {
+
+            }
+            else
+            {
+                try
+                {
+                    var feedmodel = new FeedbackOutboundRequestModel
+                    {
+                        reqCode = Guid.NewGuid().ToString(),
+                        reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
+                        business_type = outboundOrder.BusinessType,
+                        factoryArea = outboundOrder.FactoryArea,
+                        operationType = 1,
+                        Operator = App.User.UserName,
+                        orderNo = outboundOrder.UpperOrderNo,
+                        documentsNO = outboundOrder.OrderNo,
+                        status = outboundOrder.OrderStatus,
+                        details = new List<FeedbackOutboundDetailsModel>()
+                    };
+
+                    // 鍙幏鍙栧凡鎷i�夊畬鎴愮殑閿佸畾璁板綍
+                    var lists = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                        .Where(x => x.OrderNo == orderNo && x.Status == (int)OutLockStockStatusEnum.鎷i�夊畬鎴�)
+                        .ToListAsync();
+
+                    var groupedData = lists.GroupBy(item => new { item.MaterielCode, item.lineNo, item.Unit, item.WarehouseCode })
+                       .Select(group => new FeedbackOutboundDetailsModel
+                       {
+                           materialCode = group.Key.MaterielCode,
+                           lineNo = group.Key.lineNo,
+                           warehouseCode = group.Key.WarehouseCode,
+                           qty = group.Sum(x => x.PickedQty),
+                           currentDeliveryQty = group.Sum(x => x.PickedQty),
+                           unit = group.Key.Unit,
+                           barcodes = group.Select(row => new WIDESEA_DTO.Outbound.BarcodesModel
+                           {
+                               barcode = row.CurrentBarcode,
+                               supplyCode = row.SupplyCode,
+                               batchNo = row.BatchNo,
+                               unit = row.Unit,
+                               qty = row.PickedQty
+                           }).ToList()
+                       }).ToList();
+
+                    feedmodel.details = groupedData;
+
+                    var result = await _invokeMESService.FeedbackOutbound(feedmodel);
+                    if (result != null && result.code == 200)
+                    {
+                        await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
+                            .SetColumns(x => x.ReturnToMESStatus == 1)
+                            .Where(x => x.OrderId == outboundOrder.Id)
+                            .ExecuteCommandAsync();
+
+                        await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
+                              .SetColumns(x => new Dt_OutboundOrder
+                              {
+                                  ReturnToMESStatus = 1,
+                                  Operator = App.User.UserName,
+                              })
+
+                            .Where(x => x.OrderNo == orderNo)
+                            .ExecuteCommandAsync();
+                    }
+
+                    _logger.LogError($"FeedbackOutbound鎴愬姛 - OrderNo: {orderNo}, {JsonSerializer.Serialize(result)}");
+                }
+                catch (Exception ex)
+                {
+                    _logger.LogError($"FeedbackOutbound澶辫触 - OrderNo: {orderNo}, Error: {ex.Message}");
+                }
+            }
+        }
+
+        #endregion
+
+        #region 绌烘墭鐩�
+
+        /// <summary>
+        /// 娓呯悊闆跺簱瀛樻暟鎹�
+        /// </summary>
+        private async Task CleanupZeroStockData(int stockId)
+        {
+            try
+            {
+                // 1. 鍒犻櫎搴撳瓨鏁伴噺涓�0鐨勬槑缁嗚褰�
+                var deleteDetailCount = await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>()
+                    .Where(x => x.StockId == stockId && x.StockQuantity == 0 && (x.Status == StockStatusEmun.鍑哄簱瀹屾垚.ObjToInt() || x.Status ==
+                                          StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt()))
+                    .ExecuteCommandAsync();
+
+                await _stockInfoService.Db.Deleteable<Dt_StockInfo>()
+                   .Where(x => x.Id == stockId).ExecuteCommandAsync();
+
+                _logger.LogInformation($"娓呯悊闆跺簱瀛樻槑缁嗚褰� - StockId: {stockId}, 鍒犻櫎璁板綍鏁�: {deleteDetailCount}");
+
+
+
+            }
+            catch (Exception ex)
+            {
+                _logger.LogWarning($"娓呯悊闆跺簱瀛樻暟鎹け璐� - StockId: {stockId}, Error: {ex.Message}");
+                // 娉ㄦ剰锛氭竻鐞嗗け璐ヤ笉搴旇褰卞搷涓绘祦绋�
+            }
+        }
+        /// <summary>
+        /// 澶勭悊浠诲姟娓呯悊锛堟寜璁㈠崟鍜屾墭鐩橈級
+        /// </summary>
+        private async Task HandleTaskCleanup(string orderNo, string palletCode)
+        {
+            try
+            {
+                // 1. 鏌ユ壘鎵�鏈変笌璇ヨ鍗曞拰鎵樼洏鐩稿叧鐨勪换鍔�
+                var tasks = await _taskRepository.Db.Queryable<Dt_Task>().Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode).ToListAsync();
+
+                if (tasks.Any())
+                {
+                    foreach (var task in tasks)
+                    {
+                        task.TaskStatus = (int)TaskStatusEnum.Finish;
+                    }
+                    // await _taskRepository.Db.Updateable(tasks).ExecuteCommandAsync();
+
+                    _taskRepository.DeleteAndMoveIntoHty(tasks, OperateTypeEnum.鑷姩瀹屾垚);
+                    _logger.LogInformation($"瀹屾垚{tasks.Count}涓墭鐩樹换鍔� - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}");
+                }
+
+            }
+            catch (Exception ex)
+            {
+                _logger.LogWarning($"澶勭悊浠诲姟娓呯悊澶辫触 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
+                throw new Exception($"浠诲姟娓呯悊澶辫触: {ex.Message}");
+            }
+        }
+        /// <summary>
+        /// 鏇存柊璁㈠崟鐩稿叧鏁版嵁
+        /// </summary>
+        private async Task UpdateOrderData(string orderNo, string palletCode)
+        {
+            try
+            {
+                // 妫�鏌ヨ鍗曟槸鍚﹁繕鏈夊叾浠栨墭鐩樺湪澶勭悊涓�
+                var otherActivePallets = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                    .Where(x => x.OrderNo == orderNo &&
+                               x.PalletCode != palletCode &&
+                             (x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓� || x.Status == (int)OutLockStockStatusEnum.鍥炲簱涓�))
+                    .AnyAsync();
+
+                var otherActiveTasks = await _taskRepository.Db.Queryable<Dt_Task>()
+                    .Where(x => x.OrderNo == orderNo &&
+                               x.PalletCode != palletCode
+                    // && x.TaskStatus.In((int)TaskStatusEnum.寰呮墽琛�, (int)TaskStatusEnum.鎵ц涓�)
+                     )
+                    .AnyAsync();
+
+                // 濡傛灉娌℃湁鍏朵粬鎵樼洏鍦ㄥ鐞嗭紝妫�鏌ヨ鍗曟槸鍚﹀簲璇ュ畬鎴�
+                if (!otherActivePallets && !otherActiveTasks)
+                {
+                    await CheckAndUpdateOrderCompletion(orderNo);
+                }
+                else
+                {
+                    _logger.LogInformation($"璁㈠崟 {orderNo} 杩樻湁鍏朵粬鎵樼洏鍦ㄥ鐞嗭紝涓嶆洿鏂拌鍗曠姸鎬�");
+                }
+
+                // 3. 鏇存柊鎷i�夎褰曠姸鎬侊紙鍙�夛級
+                await UpdatePickingRecordsStatus(orderNo, palletCode);
+
+            }
+            catch (Exception ex)
+            {
+                _logger.LogWarning($"鏇存柊璁㈠崟鏁版嵁澶辫触 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
+                throw new Exception($"鏇存柊璁㈠崟鏁版嵁澶辫触: {ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 妫�鏌ュ苟鏇存柊璁㈠崟瀹屾垚鐘舵��
+        /// </summary>
+        private async Task CheckAndUpdateOrderCompletion(string orderNo)
+        {
+            var orderDetails = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                .LeftJoin<Dt_OutboundOrder>((o, item) => o.OrderId == item.Id)
+                .Where((o, item) => item.OrderNo == orderNo)
+                .Select((o, item) => o)
+                .ToListAsync();
+
+            bool allCompleted = true;
+            foreach (var detail in orderDetails)
+            {
+                if (detail.OverOutQuantity < detail.NeedOutQuantity)
+                {
+                    allCompleted = false;
+                    break;
+                }
+            }
+
+            var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
+                .FirstAsync(x => x.OrderNo == orderNo);
+
+            if (outboundOrder != null && allCompleted && outboundOrder.OrderStatus != (int)OutOrderStatusEnum.鍑哄簱瀹屾垚)
+            {
+                outboundOrder.OrderStatus = (int)OutOrderStatusEnum.鍑哄簱瀹屾垚;
+                outboundOrder.Operator = App.User.UserName;
+                await _outboundOrderService.Db.Updateable(outboundOrder).ExecuteCommandAsync();
+
+                _logger.LogInformation($"璁㈠崟 {orderNo} 宸叉爣璁颁负鍑哄簱瀹屾垚");
+
+                // 鍚慚ES鍙嶉璁㈠崟瀹屾垚锛堝鏋滈渶瑕侊級
+                await HandleOrderCompletion(outboundOrder, orderNo);
+            }
+        }
+
+        /// <summary>
+        /// 鏇存柊鎷i�夎褰曠姸鎬�
+        /// </summary>
+        private async Task UpdatePickingRecordsStatus(string orderNo, string palletCode)
+        {
+            try
+            {
+                // 鍙互灏嗙浉鍏崇殑鎷i�夎褰曟爣璁颁负宸插畬鎴�
+                var pickingRecords = await Db.Queryable<Dt_PickingRecord>()
+                    .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode)
+                    .ToListAsync();
+
+                // 杩欓噷鍙互鏍规嵁闇�瑕佹洿鏂版嫞閫夎褰曠殑鐘舵�佸瓧娈�
+                // 渚嬪锛歱ickingRecord.Status = (int)PickingStatusEnum.宸插畬鎴�;
+
+                _logger.LogInformation($"鎵惧埌{pickingRecords.Count}鏉℃嫞閫夎褰� - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}");
+
+            }
+            catch (Exception ex)
+            {
+                _logger.LogWarning($"鏇存柊鎷i�夎褰曠姸鎬佸け璐�: {ex.Message}");
+            }
+        }
+        #endregion
+
+
+
+        #region 杈呭姪鏂规硶
+        /// <summary>
+        /// 缁熶竴鍒嗘瀽鎵樼洏鐘舵�� - 杩斿洖鎵樼洏鐨勫畬鏁寸姸鎬佷俊鎭�
+        /// </summary>
+        private async Task<PalletStatusAnalysis> AnalyzePalletStatus(string orderNo, string palletCode, int stockId)
+        {
+            var result = new PalletStatusAnalysis
+            {
+                OrderNo = orderNo,
+                PalletCode = palletCode,
+                StockId = stockId
+            };
+
+            // 鍒嗘瀽鏈垎鎷g殑鍑哄簱閿佸畾璁板綍
+            var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(it => it.OrderNo == orderNo &&
+                           it.PalletCode == palletCode &&
+                           it.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
+                .ToListAsync();
+
+            if (remainingLocks.Any())
+            {
+                result.HasRemainingLocks = true;
+                result.RemainingLocks = remainingLocks;
+                result.RemainingLocksReturnQty = remainingLocks.Sum(x => x.AssignQuantity - x.PickedQty);
+                _logger.LogInformation($"鍙戠幇{remainingLocks.Count}鏉℃湭鍒嗘嫞閿佸畾璁板綍锛屾�绘暟閲�: {result.RemainingLocksReturnQty}");
+            }
+
+            // 鍒嗘瀽鎵樼洏涓婄殑搴撳瓨璐х墿
+            var palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(it => it.StockId == stockId &&
+                     (it.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt() ||
+                      it.Status == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt() ||
+                      it.Status == StockStatusEmun.鍑哄簱閿佸畾.ObjToInt()))
+                .Where(it => it.StockQuantity > 0)
+                .ToListAsync();
+
+            if (palletStockGoods.Any())
+            {
+                result.HasPalletStockGoods = true;
+                result.PalletStockGoods = palletStockGoods;
+                result.PalletStockReturnQty = palletStockGoods.Sum(x => x.StockQuantity);
+                _logger.LogInformation($"鍙戠幇{palletStockGoods.Count}涓簱瀛樿揣鐗╋紝鎬绘暟閲�: {result.PalletStockReturnQty}");
+
+                // 璁板綍璇︾粏鐘舵�佸垎甯�
+                var statusGroups = palletStockGoods.GroupBy(x => x.Status);
+                foreach (var group in statusGroups)
+                {
+                    _logger.LogInformation($"搴撳瓨鐘舵�亄group.Key}: {group.Count()}涓揣鐗╋紝鏁伴噺: {group.Sum(x => x.StockQuantity)}");
+                }
+            }
+
+            //鍒嗘瀽鎷嗗寘璁板綍
+            var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
+                .Where(it => it.OrderNo == orderNo &&
+                           it.PalletCode == palletCode &&
+                           !it.IsReverted && it.Status != (int)SplitPackageStatusEnum.宸叉嫞閫� &&
+                           it.Status != (int)SplitPackageStatusEnum.宸插洖搴�)
+                .ToListAsync();
+
+            if (splitRecords.Any())
+            {
+                result.HasSplitRecords = true;
+                result.SplitRecords = splitRecords;
+                result.SplitReturnQty = await CalculateSplitReturnQuantity(splitRecords, stockId);
+
+                _logger.LogInformation($"鍙戠幇{splitRecords.Count}鏉℃湭鎷i�夋媶鍖呰褰曪紝鎬绘暟閲�: {result.SplitReturnQty}");
+            }
+
+            // 4. 璁$畻鎬诲洖搴撴暟閲忓拰绌烘墭鐩樼姸鎬�
+            result.TotalReturnQty = result.RemainingLocksReturnQty + result.PalletStockReturnQty + result.SplitReturnQty;
+            result.HasItemsToReturn = result.TotalReturnQty > 0;
+            result.IsEmptyPallet = !result.HasItemsToReturn;
+
+            // 5. 妫�鏌ユ槸鍚︽湁杩涜涓殑浠诲姟
+            result.HasActiveTasks = await _taskRepository.Db.Queryable<Dt_Task>()
+                .Where(x => x.OrderNo == orderNo && x.TaskType == TaskTypeEnum.InPick.ObjToInt() &&
+                           x.PalletCode == palletCode &&
+                           x.TaskStatus == (int)TaskStatusEnum.New)
+                .AnyAsync();
+
+            _logger.LogInformation($"鎵樼洏鐘舵�佸垎鏋愬畬鎴� - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}, " +
+                                  $"鎬诲洖搴撴暟閲�: {result.TotalReturnQty}, 鏄惁绌烘墭鐩�: {result.IsEmptyPallet}, " +
+                                  $"鏈夎繘琛屼腑浠诲姟: {result.HasActiveTasks}");
+
+            return result;
+        }
+
+        /// <summary>
+        /// 妫�鏌ユ墭鐩樻槸鍚︿负绌� 
+        /// </summary>
+        private async Task<bool> IsPalletEmpty(string orderNo, string palletCode)
+        {
+            try
+            {
+                // 鑾峰彇搴撳瓨淇℃伅
+                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
+                    .Where(x => x.PalletCode == palletCode)
+                    .FirstAsync();
+
+                if (stockInfo == null)
+                    return false;
+
+                // 浣跨敤缁熶竴鐨勭姸鎬佸垎鏋�
+                var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id);
+                return statusAnalysis.IsEmptyPallet;
+            }
+            catch (Exception ex)
+            {
+                _logger.LogWarning($"妫�鏌ユ墭鐩樻槸鍚︿负绌哄け璐� - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
+                return false;
+            }
+        }
+        /// <summary>
+        /// 妫�鏌ュ苟澶勭悊绌烘墭鐩� 
+        /// </summary>
+        private async Task<bool> CheckAndHandleEmptyPallet(string orderNo, string palletCode)
+        {
+            try
+            {
+                // 1. 鑾峰彇搴撳瓨淇℃伅
+                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
+                    .Where(x => x.PalletCode == palletCode)
+                    .FirstAsync();
+
+                if (stockInfo == null)
+                {
+                    _logger.LogWarning($"鏈壘鍒版墭鐩� {palletCode} 鐨勫簱瀛樹俊鎭�");
+                    return false;
+                }
+
+                // 2. 浣跨敤缁熶竴鐨勭姸鎬佸垎鏋�
+                var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id);
+
+                // 3. 妫�鏌ユ槸鍚︿负绌烘墭鐩樹笖娌℃湁杩涜涓殑浠诲姟
+                if (!statusAnalysis.IsEmptyPallet || statusAnalysis.HasActiveTasks)
+                {
+                    return false;
+                }
+
+                _logger.LogInformation($"妫�娴嬪埌绌烘墭鐩橈紝寮�濮嬭嚜鍔ㄥ鐞� - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}");
+
+                //// 娓呯悊闆跺簱瀛樻暟鎹�
+                //await CleanupZeroStockData(stockInfo.Id);
+
+                //// 鏇存柊搴撳瓨涓昏〃鐘舵�佷负绌烘墭鐩�
+                //await UpdateStockInfoAsEmpty(stockInfo);
+
+                //// 澶勭悊鍑哄簱閿佸畾璁板綍
+                //await HandleOutStockLockRecords(orderNo, palletCode);
+
+                //// 澶勭悊浠诲姟鐘舵��
+                //await HandleTaskStatusForEmptyPallet(orderNo, palletCode);
+
+                //// 鏇存柊璁㈠崟鏁版嵁
+                //await UpdateOrderDataForEmptyPallet(orderNo, palletCode);
+
+                ////璁板綍鎿嶄綔鍘嗗彶
+                //await RecordAutoEmptyPalletOperation(orderNo, palletCode);
+
+                _logger.LogInformation($"绌烘墭鐩樿嚜鍔ㄥ鐞嗗畬鎴� - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}");
+
+                return true;
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError($"鑷姩澶勭悊绌烘墭鐩樺け璐� - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
+                return false;
+            }
+        }
+
+        private async Task<string> GenerateNewBarcode()
+        {
+            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;
+    }
+    public class PickingContext
+    {
+        public string OrderNo { get; set; }
+        public string PalletCode { get; set; }
+        public string Barcode { get; set; }
+        public string Operator { get; set; }
+        public Dt_OutStockLockInfo LockInfo { get; set; }
+        public Dt_OutboundOrderDetail OrderDetail { get; set; }
+        public Dt_StockInfoDetail StockDetail { get; set; }
+        public decimal ActualQuantity { get; set; }
+        public string AdjustedReason { get; set; }
+    }
+    public class CancelPickingContext
+    {
+        public string OrderNo { get; set; }
+        public string PalletCode { get; set; }
+        public string Barcode { get; set; }
+        public string Operator { get; set; }
+
+        public decimal CancelQuantity { get; set; }
+        public Dt_PickingRecord PickingRecord { get; set; }
+        public Dt_OutStockLockInfo LockInfo { get; set; }
+        public Dt_OutboundOrderDetail OrderDetail { get; set; }
+    }
+    #endregion
 }

--
Gitblit v1.9.3