From 68628c6cc163cddfcc745c225a9f3f34767261ef Mon Sep 17 00:00:00 2001
From: 647556386 <647556386@qq.com>
Date: 星期六, 22 十一月 2025 20:44:40 +0800
Subject: [PATCH] Merge branch 'master' of http://115.159.85.185:8098/r/ZhongRui/ALDbanyunxiangmu

---
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs | 2670 +++++++++++++++++++++++++++++++++--------------------------
 1 files changed, 1,493 insertions(+), 1,177 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 6d672b9..eddd986 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,6 +1,7 @@
 锘縰sing Dm.filter;
 using MailKit.Search;
 using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
 using Microsoft.Extensions.Logging;
 using SqlSugar;
 using System;
@@ -84,1030 +85,6 @@
             _dailySequenceService = dailySequenceService;
         }
 
-
-        #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}");
-            }
-        }
-
-        // 妫�鏌ュ苟鏇存柊璁㈠崟鐘舵��
-        private async Task CheckAndUpdateOrderStatus(string orderNo)
-        {
-
-            var orderDetails = _stockInfoDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
-                      .LeftJoin<Dt_OutboundOrder>((o, item) => o.OrderId == item.Id) // 鍏宠仈鏉′欢锛氱埗琛� Id = 瀛愯〃 OrderId
-                      .Where((o, item) => item.OrderNo == orderNo) // 杩囨护鐖惰〃 OrderNo
-                      .Select((o, item) => o) // 鍙繑鍥炲瓙琛ㄦ暟鎹�
-                      .ToList();
-
-            //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)
-            {
-                try
-                {
-                    await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
-                        .SetColumns(x => x.OrderStatus == 2) // 宸插畬鎴�
-                        .Where(x => x.OrderNo == orderNo)
-                        .ExecuteCommandAsync();
-
-                    var outboundOrder = _stockInfoService.Db.Queryable<Dt_OutboundOrder>().First(x => x.OrderNo == orderNo);
-
-
-                    if (outboundOrder != null && outboundOrder.OrderStatus == OutOrderStatusEnum.鍑哄簱瀹屾垚.ObjToInt())
-                    {
-
-                        if (outboundOrder.OrderType == OutOrderTypeEnum.Allocate.ObjToInt().ObjToInt())//璋冩嫧鍑哄簱
-                        {
-
-                        }
-                        else if (outboundOrder.OrderType == OutOrderTypeEnum.ReCheck.ObjToInt()) //閲嶆鍑哄簱
-                        {
-
-                        }
-                        else
-                        {
-                            var feedmodel = new FeedbackOutboundRequestModel
-                            {
-                                reqCode = Guid.NewGuid().ToString(),
-                                reqTime = DateTime.Now.ToString(),
-                                business_type = outboundOrder.BusinessType,
-                                factoryArea = outboundOrder.FactoryArea,
-                                operationType = 1,
-                                Operator = outboundOrder.Operator,
-                                orderNo = outboundOrder.UpperOrderNo,
-                                status = outboundOrder.OrderStatus,
-                                details = new List<FeedbackOutboundDetailsModel>()
-
-                            };
-                            var lists = _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>().Where(x => x.OrderNo == orderNo).ToList();
-
-                            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,
-                                   currentDeliveryQty = group.Sum(x => x.OrderQuantity),
-                                   // warehouseCode= "1072",
-                                   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.AssignQuantity
-                                   }).ToList()
-                               }).ToList();
-                            feedmodel.details = groupedData;
-
-                            _invokeMESService.FeedbackOutbound(feedmodel);
-                        }
-                    }
-                }
-                catch (Exception ex)
-                {
-                    _logger.LogError(" OutboundPickingService  FeedbackOutbound : " + ex.Message);
-                }
-
-            }
-        }
-
-        public async Task<WebResponseContent> ConfirmPicking(string orderNo, string palletCode, string barcode)
-        {
-            try
-            {
-                _unitOfWorkManage.BeginTran();
-
-                // 1. 鏌ユ壘鍑哄簱閿佸畾淇℃伅
-                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)
-                {
-                    lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-    .Where(it => it.CurrentBarcode == barcode &&
-               it.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
-    .FirstAsync();
-
-                    if (lockInfo == null)
-                        throw new Exception($"鏉$爜{barcode}涓嶅睘浜庢墭鐩榹palletCode}鎴栦笉瀛樺湪寰呭垎鎷h褰�");
-                }
-
-                if (lockInfo.PalletCode != palletCode)
-                    throw new Exception($"鏉$爜{barcode}涓嶅睘浜庢墭鐩榹palletCode}");
-
-                var outorderdetail = _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>().First(x => x.Id == lockInfo.OrderDetailId);
-                if (outorderdetail != null && lockInfo.AssignQuantity > outorderdetail.OrderQuantity)
-                {
-                    throw new Exception($"鏉$爜{barcode}鐨勫嚭搴撴暟閲忓ぇ浜庤鍗曠殑鏁伴噺");
-                }
-
-                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;
-                decimal stockQuantity = stockDetail.StockQuantity;
-
-                List<SplitResult> splitResults = new List<SplitResult>();
-
-                if (actualQty < stockQuantity)
-                {
-                    // 鎯呭喌1: 鍒嗛厤鏁伴噺灏忎簬搴撳瓨鏁伴噺锛岄渶瑕佽嚜鍔ㄦ媶鍖�
-                    // 璁$畻鍓╀綑搴撳瓨鏁伴噺
-                    decimal remainingStockQty = stockQuantity - actualQty;
-
-                    // 鏇存柊鍘熸潯鐮佸簱瀛樹负鍓╀綑鏁伴噺
-                    stockDetail.StockQuantity = remainingStockQty;
-                    stockDetail.OutboundQuantity = remainingStockQty;
-                    await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
-
-                    // 鐢熸垚鏂版潯鐮佺敤浜庤褰曟嫞閫夋暟閲忥紙浣嗕笉鍒涘缓搴撳瓨璁板綍锛�
-                    var seq = await _dailySequenceService.GetNextSequenceAsync();
-                    string newBarcode = "WSLOT" + DateTime.Now.ToString("yyyyMMdd") + seq.ToString()?.PadLeft(5, '0');
-
-                    // 涓烘柊鏉$爜鍒涘缓鍑哄簱閿佸畾淇℃伅锛堢敤浜庤褰曟嫞閫夛級
-                    var newLockInfo = new Dt_OutStockLockInfo
-                    {
-                        OrderNo = lockInfo.OrderNo,
-                        OrderDetailId = lockInfo.OrderDetailId,
-                        BatchNo = lockInfo.BatchNo,
-                        MaterielCode = lockInfo.MaterielCode,
-                        MaterielName = lockInfo.MaterielName,
-                        StockId = lockInfo.StockId,
-                        OrderQuantity = actualQty,
-                        OriginalQuantity = actualQty,
-                        AssignQuantity = actualQty,
-                        PickedQty = actualQty,
-                        LocationCode = lockInfo.LocationCode,
-                        PalletCode = lockInfo.PalletCode,
-                        TaskNum = lockInfo.TaskNum,
-                        Status = (int)OutLockStockStatusEnum.鎷i�夊畬鎴�,
-                        Unit = lockInfo.Unit,
-                        SupplyCode = lockInfo.SupplyCode,
-                        OrderType = lockInfo.OrderType,
-                        CurrentBarcode = newBarcode,
-                        OriginalLockQuantity = actualQty,
-                        IsSplitted = 1,
-                        ParentLockId = lockInfo.Id
-                    };
-                    await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync();
-
-                    // 璁板綍鎷嗗寘鍘嗗彶锛堢敤浜庤拷韪級
-                    var splitHistory = new Dt_SplitPackageRecord
-                    {
-                        FactoryArea = lockInfo.FactoryArea,
-                        TaskNum = lockInfo.TaskNum,
-                        OutStockLockInfoId = lockInfo.Id,
-                        StockId = stockDetail.StockId,
-                        Operator = App.User.UserName,
-                        IsReverted = false,
-                        OriginalBarcode = barcode,
-                        NewBarcode = newBarcode,
-                        SplitQty = actualQty,
-                        RemainQuantity = remainingStockQty,
-                        MaterielCode = lockInfo.MaterielCode,
-                        SplitTime = DateTime.Now,
-                        OrderNo = lockInfo.OrderNo,
-                        PalletCode = lockInfo.PalletCode,
-                        Status = (int)SplitPackageStatusEnum.宸叉嫞閫�
-                    };
-                    await _splitPackageService.Db.Insertable(splitHistory).ExecuteCommandAsync();
-
-                    // 鏇存柊鍘熼攣瀹氫俊鎭负鍓╀綑搴撳瓨鏁伴噺
-                    lockInfo.AssignQuantity = remainingStockQty;
-                    lockInfo.PickedQty = 0;  
-                                       
-                    await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
-
-                    splitResults.Add(new SplitResult
-                    {
-                        OriginalBarcode = barcode,
-                        NewBarcode = newBarcode,
-                        SplitQuantity = actualQty,
-                        RemainQuantity = remainingStockQty
-                    });
-
-                    // 鏇存柊鎷i�夎褰曚腑鐨勬潯鐮佷负鏂版潯鐮�
-                    barcode = newBarcode;
-                    lockInfo = newLockInfo;
-                }
-                else if (actualQty == stockQuantity)
-                {
-                    // 鎯呭喌2: 鍒嗛厤鏁伴噺绛変簬搴撳瓨鏁伴噺锛屾暣鍖呭嚭搴�
-                    stockDetail.StockQuantity = 0;
-                    stockDetail.OutboundQuantity = 0;
-                    await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
-
-                    lockInfo.PickedQty += actualQty;
-                    lockInfo.Status = (int)OutLockStockStatusEnum.鎷i�夊畬鎴�;
-                    await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
-                }
-                else
-                {
-                    // 鎯呭喌3: 鍒嗛厤鏁伴噺澶т簬搴撳瓨鏁伴噺锛屽簱瀛樻暣鍖呭嚭搴�
-                    // 鏁村寘鍑哄簱褰撳墠搴撳瓨
-                    decimal stockOutQty = stockQuantity;
-                    stockDetail.StockQuantity = 0;
-                    stockDetail.OutboundQuantity = 0;
-                    await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
-
-                    // 璁$畻鍓╀綑鍒嗛厤鏁伴噺
-                    decimal remainingAssignQty = actualQty - stockQuantity;
-
-                    // 鏇存柊閿佸畾淇℃伅锛堝彧瀹屾垚搴撳瓨閮ㄥ垎锛�
-                    lockInfo.PickedQty += stockOutQty;
-                    lockInfo.AssignQuantity = remainingAssignQty;
-
-                    await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
-
-                    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();
-                    }
-                }
-
-   
-
-                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();
-
-                // 璁板綍鎷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 = actualQty,
-                    PickTime = DateTime.Now,
-                    Operator = App.User.UserName,
-                    OutStockLockId = lockInfo.Id
-                };
-                await Db.Insertable(pickingHistory).ExecuteCommandAsync();
-
-                _unitOfWorkManage.CommitTran();
-
-                // 濡傛灉鏈夋媶鍖呯粨鏋滐紝杩斿洖鎷嗗寘淇℃伅
-                if (splitResults.Any())
-                {
-                    return WebResponseContent.Instance.OK("鎷i�夌‘璁ゆ垚鍔燂紝宸茶嚜鍔ㄦ媶鍖�", new { SplitResults = splitResults });
-                }
-
-                return WebResponseContent.Instance.OK("鎷i�夌‘璁ゆ垚鍔�");
-
-            }
-            catch (Exception ex)
-            {
-                _unitOfWorkManage.RollbackTran();
-                return WebResponseContent.Instance.Error($"鎷i�夌‘璁ゅけ璐ワ細{ex.Message}");
-            }
-        }
-        
-        /// <summary>
-        /// 鍥炲簱鎿嶄綔  
-        /// </summary>
-
-        public async Task<WebResponseContent> ReturnRemaining(string orderNo, string palletCode, string reason)
-        {
-            try
-            {
-                _unitOfWorkManage.BeginTran();
-
-                // 鑾峰彇鎵�鏈夋湭鍒嗘嫞鐨勫嚭搴撻攣瀹氳褰曪紝鍖呮嫭鎷嗗寘浜х敓鐨勮褰�
-                var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                    .Where(it => it.OrderNo == orderNo && it.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
-                    .ToListAsync();
-
-                var stockinfo = _stockInfoService.Db.Queryable<Dt_StockInfo>().First(x => x.PalletCode == palletCode);
-
-                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 palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                    .Where(it => it.StockId == stockinfo.Id &&
-                                (it.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt() ||
-                                 it.Status == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt() ||
-                                 it.Status == StockStatusEmun.鍑哄簱閿佸畾.ObjToInt()))
-                    .Where(it => it.OutboundQuantity == 0 || it.OutboundQuantity < it.StockQuantity) // 鏈畬鍏ㄥ嚭搴撶殑
-                    .ToListAsync();
-
-                // 妫�鏌ユ媶鍖呰褰曪紝鎵惧嚭闇�瑕佸洖搴撶殑鏉$爜
-                var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
-                    .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode && !it.IsReverted)
-                    .ToListAsync();
-
-                // 璁$畻闇�瑕佸洖搴撶殑鎷嗗寘鏉$爜
-                var splitBarcodesToReturn = new List<string>();
-                foreach (var splitRecord in splitRecords)
-                {
-                    // 妫�鏌ュ師鏉$爜鏄惁杩樻湁搴撳瓨闇�瑕佸洖搴�
-                    var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                        .Where(it => it.Barcode == splitRecord.OriginalBarcode && it.StockId == stockinfo.Id)
-                        .FirstAsync();
-
-                    if (originalStock != null && originalStock.StockQuantity > 0)
-                    {
-                        splitBarcodesToReturn.Add(splitRecord.OriginalBarcode);
-                    }
-
-                    // 妫�鏌ユ柊鏉$爜鏄惁杩樻湁搴撳瓨闇�瑕佸洖搴�
-                    var newStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                        .Where(it => it.Barcode == splitRecord.NewBarcode && it.StockId == stockinfo.Id)
-                        .FirstAsync();
-
-                    if (newStock != null && newStock.StockQuantity > 0)
-                    {
-                        splitBarcodesToReturn.Add(splitRecord.NewBarcode);
-                    }
-                }
-
-                // 濡傛灉娌℃湁闇�瑕佸洖搴撶殑璐х墿锛堟棦鏃犳湭鍒嗘嫞鍑哄簱璐х墿锛屼篃鏃犲叾浠栧簱瀛樿揣鐗╋紝涔熸棤鎷嗗寘鍓╀綑璐х墿锛�
-                if (!remainingLocks.Any() && !palletStockGoods.Any() && !splitBarcodesToReturn.Any())
-                {
-                    // 妫�鏌ユ槸鍚︽墍鏈夎揣鐗╅兘宸叉嫞閫夊畬鎴�
-                    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)
-                    {
-                        return WebResponseContent.Instance.OK("鎵�鏈夎揣鐗╁凡鎷i�夊畬鎴愶紝鎵樼洏涓虹┖");
-                    }
-                    else
-                    {
-                        return WebResponseContent.Instance.Error("娌℃湁闇�瑕佸洖搴撶殑鍓╀綑璐х墿");
-                    }
-                }
-
-                var firstlocation = _locationInfoService.Db.Queryable<Dt_LocationInfo>().First(x => x.LocationCode == task.SourceAddress);
-                decimal totalReturnQty = 0;
-
-                // 鎯呭喌1锛氬鐞嗘湭鍒嗘嫞鐨勫嚭搴撻攣瀹氳褰�
-                if (remainingLocks.Any(x => x.PalletCode == palletCode))
-                {
-                    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 = (int)OutLockStockStatusEnum.鍥炲簱涓� })
-                            .Where(it => lockIds.Contains(it.Id))
-                            .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)
-                            {
-                                // 搴撳瓨璁板綍瀛樺湪锛屾仮澶嶉攣瀹氭暟閲�
-                                existingStock.OutboundQuantity = 0;
-
-                                await _stockInfoDetailService.Db.Updateable(existingStock).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();
-                            }
-                        }
-
-                        // 鍒涘缓鍥炲簱浠诲姟
-                        CreateReturnTask(tasks, task, palletCode, newLocation);
-                    }
-                }
-
-                // 鎯呭喌2锛氬鐞嗘媶鍖呭墿浣欑殑搴撳瓨璐х墿
-                if (splitBarcodesToReturn.Any())
-                {
-                    decimal splitReturnQty = 0;
-
-                    foreach (var barcode in splitBarcodesToReturn)
-                    {
-                        var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                            .Where(it => it.Barcode == barcode && it.StockId == stockinfo.Id)
-                            .FirstAsync();
-
-                        if (stockDetail != null && stockDetail.StockQuantity > 0)
-                        {
-                            splitReturnQty += stockDetail.StockQuantity;
-
-                            // 鎭㈠搴撳瓨鐘舵�佷负鍏ュ簱瀹屾垚
-                            stockDetail.OutboundQuantity = 0;
-
-                            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
-                        }
-                    }
-
-                    totalReturnQty += splitReturnQty;
-
-                    // 濡傛灉娌℃湁鍒涘缓浠诲姟锛屽垱寤哄洖搴撲换鍔�
-                    if (!tasks.Any())
-                    {
-                        var newLocation = _locationInfoService.AssignLocation(firstlocation.LocationType);
-                        CreateReturnTask(tasks, task, palletCode, newLocation);
-                    }
-                }
-
-                // 鎯呭喌3锛氬嚭搴撹揣鐗╁凡鍒嗘嫞瀹岋紝浣嗘墭鐩樹笂杩樻湁鍏朵粬搴撳瓨璐х墿闇�瑕佸洖搴�
-                if (palletStockGoods.Any() && !remainingLocks.Any(x => x.PalletCode == palletCode))
-                {
-                    decimal otherReturnQty = palletStockGoods.Sum(x => x.StockQuantity - x.OutboundQuantity);
-                    totalReturnQty += otherReturnQty;
-                    // 鏇存柊杩欎簺搴撳瓨璐х墿鐨勭姸鎬�
-                    foreach (var stockGood in palletStockGoods)
-                    {
-                        stockGood.OutboundQuantity = 0;
-
-                        await _stockInfoDetailService.Db.Updateable(stockGood).ExecuteCommandAsync();
-                    }
-                    // 濡傛灉娌℃湁鍒涘缓浠诲姟锛屽垱寤哄洖搴撲换鍔�
-                    if (!tasks.Any())
-                    {
-                        var newLocation = _locationInfoService.AssignLocation(firstlocation.LocationType);
-                        CreateReturnTask(tasks, task, palletCode, newLocation);
-                    }
-
-                 
-                }
-            
-                var allSplitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
-                    .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode && !it.IsReverted)
-                    .ToListAsync();
-
-                foreach (var record in allSplitRecords)
-                {
-                    record.Status = (int)SplitPackageStatusEnum.宸插洖搴�;
-                    await _splitPackageService.Db.Updateable(record).ExecuteCommandAsync();
-                }
-                // 淇濆瓨浠诲姟 缁橢SS涓嬪彂浠诲姟
-                if (tasks.Any())
-                {
-                    try
-                    {
-                        await _taskRepository.Db.Insertable(tasks).ExecuteCommandAsync();
-                        var targetAddress = task.TargetAddress;
-                        _taskRepository.DeleteData(task);
-
-                        // 缁� ESS 娴佸姩淇″彿鍜屽垱寤轰换鍔�
-                        try
-                        {
-                            var result = await _eSSApiService.MoveContainerAsync(new WIDESEA_DTO.Basic.MoveContainerRequest
-                            {
-                                slotCode = movestations[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(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);
-                        }
-
-                        _unitOfWorkManage.CommitTran();
-                        return WebResponseContent.Instance.OK($"鍥炲簱鎿嶄綔鎴愬姛锛屽叡鍥炲簱鏁伴噺锛歿totalReturnQty}");
-                    }
-                    catch (Exception ex)
-                    {
-                        _unitOfWorkManage.RollbackTran();
-                        return WebResponseContent.Instance.Error($"鍒涘缓鍥炲簱浠诲姟澶辫触: {ex.Message}");
-                    }
-                }
-
-                _unitOfWorkManage.RollbackTran();
-                return WebResponseContent.Instance.Error("鏈垱寤轰换浣曞洖搴撲换鍔�");
-            }
-            catch (Exception ex)
-            {
-                _unitOfWorkManage.RollbackTran();
-                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 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 WebResponseContent.Instance.Error("鏈壘鍒板搴旂殑鎷i�夎褰�");
-
-                // 鏌ユ壘鍑哄簱閿佸畾淇℃伅
-                var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                    .Where(it => it.Id == pickingRecord.OutStockLockId)
-                    .FirstAsync();
-
-                if (lockInfo == null)
-                    return WebResponseContent.Instance.Error("鏈壘鍒板搴旂殑鍑哄簱閿佸畾淇℃伅");
-
-                //妫�鏌ユ槸鍚﹀彲浠ュ彇娑堬紙鐘舵�佸繀椤绘槸鎷i�夊畬鎴愶級
-                if (lockInfo.Status != (int)OutLockStockStatusEnum.鎷i�夊畬鎴�)
-                    return WebResponseContent.Instance.Error("褰撳墠鐘舵�佷笉鍏佽鍙栨秷鍒嗘嫞");
-
-                decimal cancelQty = pickingRecord.PickQuantity;
-
-                // 妫�鏌ユ媶鍖呴摼鍏崇郴
-                var splitChain = await GetSplitChain(barcode);
-
-                if (splitChain.Any())
-                {
-                    // 鎯呭喌A锛氬鐞嗘媶鍖呴摼鐨勫彇娑堬紙澶氭鎵嬪姩鎷嗗寘锛�
-                    await HandleSplitChainCancel(orderNo, palletCode, barcode, cancelQty, lockInfo, pickingRecord, splitChain);
-                }
-                else
-                {
-                    // 鎯呭喌B锛氬鐞嗘櫘閫氭潯鐮佺殑鍙栨秷
-                    await HandleNormalBarcodeCancel(orderNo, palletCode, barcode, cancelQty, lockInfo, pickingRecord);
-                }
-
-                _unitOfWorkManage.CommitTran();
-                return WebResponseContent.Instance.OK($"鍙栨秷鍒嗘嫞鎴愬姛锛屾仮澶嶆暟閲忥細{cancelQty}");
-            }
-            catch (Exception ex)
-            {
-                _unitOfWorkManage.RollbackTran();
-                return WebResponseContent.Instance.Error($"鍙栨秷鍒嗘嫞澶辫触锛歿ex.Message}");
-            }
-        }
-
-        /// <summary>
-        /// 鑾峰彇鎷嗗寘閾撅紙浠庡綋鍓嶆潯鐮佽拷婧埌鍘熷鏉$爜锛�
-        /// </summary>
-        // 鍦� GetSplitChain 鏂规硶涓坊鍔犳洿涓ユ牸鐨勯獙璇�
-        private async Task<List<SplitChainItem>> GetSplitChain(string currentBarcode)
-        {
-            var chain = new List<SplitChainItem>();
-            var visited = new HashSet<string>();
-
-            string current = currentBarcode;
-            int maxDepth = 10; // 闃叉鏃犻檺寰幆
-
-            while (!string.IsNullOrEmpty(current) && maxDepth > 0)
-            {
-                maxDepth--;
-
-                if (visited.Contains(current))
-                {
-                    _logger.LogWarning($"妫�娴嬪埌寰幆寮曠敤鍦ㄦ媶鍖呴摼涓�: {current}");
-                    break;
-                }
-
-                visited.Add(current);
-
-                var splitRecord = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
-                    .Where(it => it.NewBarcode == current && !it.IsReverted)
-                    .FirstAsync();
-
-                if (splitRecord == null)
-                    break;
-
-                // 楠岃瘉鎷嗗寘璁板綍鐨勫畬鏁存��
-                if (string.IsNullOrEmpty(splitRecord.OriginalBarcode))
-                {
-                    _logger.LogError($"鎷嗗寘璁板綍 {splitRecord.Id} 缂哄皯鍘熷鏉$爜");
-                    break;
-                }
-
-                var item = new SplitChainItem
-                {
-                    SplitRecord = splitRecord,
-                    OriginalBarcode = splitRecord.OriginalBarcode,
-                    NewBarcode = splitRecord.NewBarcode,
-                    SplitQuantity = splitRecord.SplitQty
-                };
-
-                chain.Add(item);
-
-                current = splitRecord.OriginalBarcode;
-            }
-
-            if (maxDepth <= 0)
-            {
-                _logger.LogWarning($"鎷嗗寘閾捐拷婧揪鍒版渶澶ф繁搴�: {currentBarcode}");
-            }
-
-            chain.Reverse();
-            return chain;
-        }
-        /// <summary>
-        /// 澶勭悊鎷嗗寘閾剧殑鍙栨秷鍒嗘嫞
-        /// </summary>
-        private async Task HandleSplitChainCancel(string orderNo, string palletCode, string barcode,
-            decimal cancelQty, Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord, List<SplitChainItem> splitChain)
-        {
-            if (!splitChain.Any())
-                return;
-
-            //  鎵惧埌鍘熷鏉$爜锛堥摼鐨勭涓�涓級
-            var originalSplitItem = splitChain.First();
-            var originalBarcode = originalSplitItem.OriginalBarcode;
-
-            // 鏌ユ壘鍘熷鏉$爜鐨勯攣瀹氫俊鎭拰搴撳瓨
-            var originalLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                .Where(it => it.CurrentBarcode == originalBarcode && it.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
-                .FirstAsync();
-
-            var originalStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                .Where(it => it.Barcode == originalBarcode && it.StockId == originalLockInfo.StockId)
-                .FirstAsync();
-
-            if (originalLockInfo == null || originalStockDetail == null)
-                throw new Exception("鏈壘鍒板師濮嬫潯鐮佺殑閿佸畾淇℃伅鎴栧簱瀛樹俊鎭�");
-
-            // 鎭㈠鍘熷鏉$爜搴撳瓨锛堝皢鍙栨秷鐨勬暟閲忓姞鍥炲幓锛�
-            originalStockDetail.StockQuantity += cancelQty;
-            originalStockDetail.OutboundQuantity += cancelQty;
-            await _stockInfoDetailService.Db.Updateable(originalStockDetail).ExecuteCommandAsync();
-
-            // 鎭㈠鍘熷鏉$爜閿佸畾淇℃伅
-            originalLockInfo.AssignQuantity += cancelQty;
-            await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync();
-
-            //  鍒犻櫎鎷嗗寘閾句腑鎵�鏈夋柊鏉$爜鐨勯攣瀹氫俊鎭拰搴撳瓨璁板綍
-            var allNewBarcodes = splitChain.Select(x => x.NewBarcode).ToList();
-
-            // 鍒犻櫎閿佸畾淇℃伅
-            await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
-                .Where(it => allNewBarcodes.Contains(it.CurrentBarcode))
-                .ExecuteCommandAsync();
-
-            // 鍒犻櫎搴撳瓨璁板綍锛堝彧鍒犻櫎鎷嗗寘浜х敓鐨勬柊鏉$爜搴撳瓨锛屼繚鐣欏師濮嬫潯鐮侊級
-            await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>()
-                .Where(it => allNewBarcodes.Contains(it.Barcode) && it.Barcode != originalBarcode)
-                .ExecuteCommandAsync();
-
-            // 鏇存柊鎷嗗寘閾句腑鎵�鏈夋媶鍖呰褰曠姸鎬佷负宸叉媶鍖�
-            foreach (var chainItem in splitChain)
-            {
-                chainItem.SplitRecord.Status = (int)SplitPackageStatusEnum.宸叉媶鍖�;
-                await _splitPackageService.Db.Updateable(chainItem.SplitRecord).ExecuteCommandAsync();
-            }
-
-            //  鎭㈠璁㈠崟鏄庣粏鎷i�夋暟閲忥紙浣跨敤鍘熷閿佸畾淇℃伅鐨勮鍗曟槑缁咺D锛�
-            await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
-                .SetColumns(it => it.PickedQty == it.PickedQty - cancelQty)
-                .Where(it => it.Id == originalLockInfo.OrderDetailId)
-                .ExecuteCommandAsync();
-
-            //   鎭㈠璁㈠崟鐘舵��
-            await CheckAndRevertOrderStatus(orderNo);
-
-            //  鍒犻櫎鎷i�夎褰�
-            await Db.Deleteable<Dt_PickingRecord>()
-                .Where(it => it.Id == pickingRecord.Id)
-                .ExecuteCommandAsync();
-
-            ////  璁板綍鍙栨秷鎿嶄綔鍘嗗彶
-            //await RecordCancelHistory(orderNo, palletCode, barcode, cancelQty, pickingRecord.Id,
-            //    lockInfo.MaterielCode, "鍙栨秷鎷嗗寘閾惧垎鎷�");
-        }
-
-        /// <summary>
-        /// 澶勭悊鏅�氭潯鐮佺殑鍙栨秷鍒嗘嫞
-        /// </summary>
-        private async Task HandleNormalBarcodeCancel(string orderNo, string palletCode, string barcode,
-            decimal cancelQty, Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord)
-        {
-            // 1. 鏌ユ壘搴撳瓨淇℃伅
-            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                .Where(it => it.Barcode == barcode && it.StockId == lockInfo.StockId)
-                .FirstAsync();
-
-            if (stockDetail == null)
-                throw new Exception("鏈壘鍒板搴旂殑搴撳瓨淇℃伅");
-
-            // 2. 鎭㈠搴撳瓨鏁伴噺
-            if (stockDetail.StockQuantity == 0)
-            {
-                // 鏁村寘鍑哄簱鐨勬儏鍐�
-                stockDetail.StockQuantity = cancelQty;
-                stockDetail.OutboundQuantity = cancelQty;
-            }
-            else
-            {
-                // 閮ㄥ垎鍑哄簱鐨勬儏鍐�
-                stockDetail.StockQuantity += cancelQty;
-                stockDetail.OutboundQuantity += cancelQty;
-            }
-            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
-
-            // 3. 鎭㈠閿佸畾淇℃伅鐘舵��
-            lockInfo.AssignQuantity += cancelQty;
-            lockInfo.PickedQty -= cancelQty;
-
-            if (lockInfo.PickedQty == 0)
-            {
-                lockInfo.Status = (int)OutLockStockStatusEnum.鍑哄簱涓�;
-            }
-            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
-
-            // 4. 澶勭悊鐩稿叧鐨勬媶鍖呰褰曠姸鎬佹仮澶�
-            var relatedSplitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
-                .Where(it => it.OriginalBarcode == barcode &&
-                           it.Status == (int)SplitPackageStatusEnum.宸叉嫞閫�)
-                .ToListAsync();
-
-            foreach (var record in relatedSplitRecords)
-            {
-                record.Status = (int)SplitPackageStatusEnum.宸叉媶鍖�;
-                await _splitPackageService.Db.Updateable(record).ExecuteCommandAsync();
-            }
-
-            // 5. 鎭㈠璁㈠崟鏄庣粏鐨勬嫞閫夋暟閲�
-            await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
-                .SetColumns(it => it.PickedQty == it.PickedQty - cancelQty)
-                .Where(it => it.Id == lockInfo.OrderDetailId)
-                .ExecuteCommandAsync();
-
-            // 6. 鎭㈠璁㈠崟鐘舵��
-            await CheckAndRevertOrderStatus(orderNo);
-
-            // 7. 鍒犻櫎鎷i�夎褰�
-            await Db.Deleteable<Dt_PickingRecord>().Where(it => it.Id == pickingRecord.Id).ExecuteCommandAsync();
-
-            //// 8. 璁板綍鍙栨秷鎿嶄綔鍘嗗彶
-            //await RecordCancelHistory(orderNo, palletCode, barcode, cancelQty, pickingRecord.Id,
-            //    lockInfo.MaterielCode, "鍙栨秷鍒嗘嫞");
-        }
-
-        /// <summary>
-        /// 妫�鏌ュ苟鎭㈠璁㈠崟鐘舵��
-        /// </summary>
-        private async Task CheckAndRevertOrderStatus(string orderNo)
-        {
-            var order = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
-                .Where(x => x.OrderNo == orderNo)
-                .FirstAsync();
-
-            if (order != null && order.OrderStatus == OutOrderStatusEnum.鍑哄簱瀹屾垚.ObjToInt())
-            {
-                await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
-                    .SetColumns(x => x.OrderStatus == OutOrderStatusEnum.鍑哄簱涓�.ObjToInt())
-                    .Where(x => x.OrderNo == orderNo)
-                    .ExecuteCommandAsync();
-            }
-        }
-
-        /// <summary>
-        /// 璁板綍鍙栨秷鎿嶄綔鍘嗗彶
-        /// </summary>
-        private async Task RecordCancelHistory(string orderNo, string palletCode, string barcode,
-            decimal cancelQty, int pickingRecordId, string materielCode, string reason)
-        {
-           
-            //var cancelHistory = new Dt_PickingCancelRecord
-            //{
-            //    OrderNo = orderNo,
-            //    PalletCode = palletCode,
-            //    Barcode = barcode,
-            //    CancelQuantity = cancelQty,
-            //    CancelTime = DateTime.Now,
-            //    Operator = App.User.UserName,
-            //    OriginalPickingRecordId = pickingRecordId,
-            //    MaterielCode = materielCode,
-            //    Reason = reason
-            //};
-            //await Db.Insertable(cancelHistory).ExecuteCommandAsync();
-        }
-
-        /// <summary>
-        /// 鎷嗗寘閾鹃」
-        /// </summary>
-        public class SplitChainItem
-        {
-            public Dt_SplitPackageRecord SplitRecord { get; set; }
-            public string OriginalBarcode { get; set; }
-            public string NewBarcode { get; set; }
-            public decimal SplitQuantity { get; set; }
-        }
         // 鑾峰彇鏈嫞閫夊垪琛�
         public async Task<List<Dt_OutStockLockInfo>> GetUnpickedList(string orderNo, string palletCode)
         {
@@ -1169,186 +146,1525 @@
 
             return summary;
         }
+
+        #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();
-        }
-
-
-        /// <summary>
-        /// 鑾峰彇鎵樼洏鐨勫嚭搴撶姸鎬佷俊鎭�
-        /// </summary>
-        public async Task<WebResponseContent> GetPalletOutboundStatus(string palletCode)
-        {
-            // 鑾峰彇鎵樼洏鐨勯攣瀹氫俊鎭�
-            var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                .Where(x => x.PalletCode == palletCode)
-                .ToListAsync();
-
-            // 鑾峰彇鎵樼洏搴撳瓨淇℃伅
-            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("鏈壘鍒版墭鐩樹俊鎭�");
-
-            // 璁$畻鍚勭鏁伴噺
-            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);
-
-            var result = new
+            try
             {
-                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()
-            };
+                _unitOfWorkManage.BeginTran();
+  
+                var validationResult = await ValidatePickingRequest(orderNo, palletCode, barcode);
+                if (!validationResult.IsValid)
+                    return WebResponseContent.Instance.Error(validationResult.ErrorMessage);
 
-            return WebResponseContent.Instance.OK(null, result);
+                var (lockInfo, orderDetail, stockDetail) = validationResult.Data;
+
+                // 璁$畻瀹為檯鎷i�夋暟閲�
+                var quantityResult = await CalculateActualPickingQuantity(lockInfo, orderDetail, stockDetail);
+                if (!quantityResult.IsValid)
+                    return WebResponseContent.Instance.Error(quantityResult.ErrorMessage);
+
+                var (actualQty, adjustedReason) = quantityResult.Data;
+
+                var overPickingValidation = await ValidateOverPicking(orderDetail.Id, actualQty);
+                if (!overPickingValidation.IsValid)
+                {
+                    return WebResponseContent.Instance.Error(overPickingValidation.ErrorMessage);
+                }
+
+                //  鎵ц鍒嗘嫞閫昏緫
+                var pickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, orderNo, palletCode, barcode, actualQty);
+
+                // 鏇存柊鐩稿叧鏁版嵁
+                await UpdateOrderRelatedData(orderDetail.Id, pickingResult.ActualPickedQty, orderNo);
+
+                // 璁板綍鎿嶄綔鍘嗗彶
+                await RecordPickingHistory(pickingResult, orderNo, palletCode);
+
+                _unitOfWorkManage.CommitTran();
+
+                return CreatePickingResponse(pickingResult, adjustedReason);
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                _logger.LogError($"ConfirmPicking澶辫触 - OrderNo: {orderNo}, PalletCode: {palletCode}, Barcode: {barcode}, Error: {ex.Message}");
+                return WebResponseContent.Instance.Error($"鎷i�夌‘璁ゅけ璐ワ細{ex.Message}");
+            }
         }
-
         /// <summary>
-        /// 鐩存帴鍑哄簱 - 鏁翠釜鎵樼洏鍑哄簱锛屾竻绌哄簱瀛�
+        /// 鍙栨秷鎷i��
         /// </summary>
-        public async Task<WebResponseContent> DirectOutbound(DirectOutboundRequest request)
+        /// <param name="orderNo"></param>
+        /// <param name="palletCode"></param>
+        /// <param name="barcode"></param>
+        /// <returns></returns>
+        public async Task<WebResponseContent> CancelPicking(string orderNo, string palletCode, string barcode)
+        {
+            try
+            {
+                if (await IsPalletReturned(palletCode))
+                {
+                    return WebResponseContent.Instance.Error($"鎵樼洏{palletCode}宸茬粡鍥炲簱锛屼笉鑳藉彇娑堝垎鎷�");
+                }
+                _unitOfWorkManage.BeginTran();
+
+                // 1. 鍓嶇疆楠岃瘉
+                var validationResult = await ValidateCancelRequest(orderNo, palletCode, barcode);
+                if (!validationResult.IsValid)
+                    return WebResponseContent.Instance.Error(validationResult.ErrorMessage);
+
+                var (pickingRecord, lockInfo, orderDetail) = validationResult.Data;
+
+                // 2. 鎵ц鍙栨秷閫昏緫
+                await ExecuteCancelLogic(lockInfo, pickingRecord, orderDetail, orderNo);
+
+                _unitOfWorkManage.CommitTran();
+
+                return WebResponseContent.Instance.OK($"鍙栨秷鍒嗘嫞鎴愬姛锛屾仮澶嶆暟閲忥細{pickingRecord.PickQuantity}");
+            }
+            catch (Exception ex)
+            {
+                _unitOfWorkManage.RollbackTran();
+                _logger.LogError($"CancelPicking澶辫触 - OrderNo: {orderNo}, PalletCode: {palletCode}, Barcode: {barcode}, Error: {ex.Message}");
+                return WebResponseContent.Instance.Error($"鍙栨秷鍒嗘嫞澶辫触锛歿ex.Message}");
+            }
+        }
+        /// <summary>
+        /// 鍥炲簱
+        /// </summary>
+        /// <param name="orderNo"></param>
+        /// <param name="palletCode"></param>
+        /// <param name="reason"></param>
+        /// <returns></returns>
+        public async Task<WebResponseContent> ReturnRemaining(string orderNo, string palletCode, string reason)
         {
             try
             {
                 _unitOfWorkManage.BeginTran();
 
-                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
-                    .Includes(x => x.Details)
-                    .Where(x => x.PalletCode == request.PalletCode).FirstAsync();
+                // 1. 鍩虹楠岃瘉
+                if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode))
+                    return WebResponseContent.Instance.Error("璁㈠崟鍙峰拰鎵樼洏鐮佷笉鑳戒负绌�");
+
+                // 2. 鑾峰彇搴撳瓨鍜屼换鍔′俊鎭�
+                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>().FirstAsync(x => x.PalletCode == palletCode);
 
                 if (stockInfo == null)
-                    return WebResponseContent.Instance.Error("鏈壘鍒版墭鐩樺簱瀛樹俊鎭�");
+                    return WebResponseContent.Instance.Error($"鏈壘鍒版墭鐩� {palletCode} 瀵瑰簲鐨勫簱瀛樹俊鎭�");
 
+                var task = await GetCurrentTask(orderNo, palletCode);
+                if (task == null)
+                    return WebResponseContent.Instance.Error("鏈壘鍒板搴旂殑浠诲姟淇℃伅");
 
-                var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                    .Where(x => x.OrderNo == request.OrderNo && x.PalletCode == request.PalletCode)
-                    .ToListAsync();
+                // 3. 鍒嗘瀽闇�瑕佸洖搴撶殑璐х墿
+                var returnAnalysis = await AnalyzeReturnItems(orderNo, palletCode, stockInfo.Id);
+                if (!returnAnalysis.HasItemsToReturn)
+                    return await HandleNoReturnItems(orderNo, palletCode,task);
 
+                // 4. 鎵ц鍥炲簱鎿嶄綔
+                await ExecuteReturnOperations(orderNo, palletCode, stockInfo, task, returnAnalysis);
 
-                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 groupDetails = lockInfos.GroupBy(x => x.OrderDetailId).Select(x => new
-                {
-                    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();
-                    }
-                }
-
-                await CheckAndUpdateOrderStatus(request.OrderNo);
-
-                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();
-                }
-
-
-                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();
-                }
-
-                foreach (var detail in stockInfo.Details)
-                {
-                    await _stockInfoDetailService.Db.Deleteable(detail).ExecuteCommandAsync();
-                }
-                await _stockInfoService.Db.Deleteable(stockInfo).ExecuteCommandAsync();
-
-
+                // 5. 鍒涘缓鍥炲簱浠诲姟
+                await CreateReturnTaskAndHandleESS(orderNo, palletCode, task, returnAnalysis);
 
                 _unitOfWorkManage.CommitTran();
-                return WebResponseContent.Instance.OK("鐩存帴鍑哄簱鎴愬姛");
+
+                // 6. 鏇存柊璁㈠崟鐘舵�侊紙涓嶈Е鍙慚ES鍥炰紶锛�
+                await UpdateOrderStatusForReturn(orderNo);
+
+                return WebResponseContent.Instance.OK($"鍥炲簱鎿嶄綔鎴愬姛锛屽叡鍥炲簱鏁伴噺锛歿returnAnalysis.TotalReturnQty}");
             }
             catch (Exception ex)
             {
                 _unitOfWorkManage.RollbackTran();
-                return WebResponseContent.Instance.Error($"鐩存帴鍑哄簱澶辫触: {ex.Message}");
+                _logger.LogError($"ReturnRemaining澶辫触 - 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);
+            }
+            else if (actualQty == stockQuantity)
+            {
+                await HandleFullPicking(lockInfo, stockDetail, actualQty, result);
+            }
+            else
+            {
+                await HandlePartialPicking(lockInfo, stockDetail, actualQty, stockQuantity, result);
+            }
+
+            return result;
+        }
+
+        private async Task HandleSplitPacking(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
+            decimal actualQty, decimal stockQuantity, PickingResult result)
+        {
+            decimal remainingStockQty = stockQuantity - actualQty;
+
+            // 1. 鏇存柊鍘熸潯鐮佸簱瀛�
+            stockDetail.StockQuantity = remainingStockQty;
+            stockDetail.OutboundQuantity = remainingStockQty;
+            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+
+            // 2. 鐢熸垚鏂版潯鐮�
+            string newBarcode = await GenerateNewBarcode();
+
+            // 3. 鍒涘缓鏂伴攣瀹氫俊鎭�
+            var newLockInfo = await CreateSplitLockInfo(lockInfo, actualQty, newBarcode);
+
+            // 4. 璁板綍鎷嗗寘鍘嗗彶
+            await RecordSplitHistory(lockInfo, stockDetail, actualQty, remainingStockQty, newBarcode);
+
+            // 5. 鏇存柊鍘熼攣瀹氫俊鎭�
+            lockInfo.AssignQuantity = remainingStockQty;
+            lockInfo.PickedQty = 0;
+            lockInfo.Operator = App.User.UserName;
+            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
+
+            // 6. 璁剧疆缁撴灉
+            result.FinalLockInfo = newLockInfo;
+            result.FinalBarcode = newBarcode;
+            result.SplitResults.AddRange(CreateSplitResults(lockInfo, actualQty, remainingStockQty, newBarcode, stockDetail.Barcode));
+        }
+
+        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<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>> ValidateCancelRequest(string orderNo, string palletCode, string barcode)
+        {
+            // 鍩虹鍙傛暟楠岃瘉
+            if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode) || string.IsNullOrEmpty(barcode))
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("璁㈠崟鍙枫�佹墭鐩樼爜鍜屾潯鐮佷笉鑳戒负绌�");
+
+            // 鏌ユ壘鎷i�夎褰�
+            var pickingRecord = await Db.Queryable<Dt_PickingRecord>()
+                .Where(it => it.OrderNo == orderNo &&
+                           it.PalletCode == palletCode &&
+                           it.Barcode == barcode)
+                .OrderByDescending(it => it.PickTime)
+                .FirstAsync();
+
+            if (pickingRecord == null)
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("鏈壘鍒板搴旂殑鎷i�夎褰�");
+
+            if (pickingRecord.PickQuantity <= 0)
+            {
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error($"鎷i�夎褰曟暟閲忔棤鏁�: {pickingRecord.PickQuantity}");
+            }
+            // 鏌ユ壘閿佸畾淇℃伅
+            var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(it => it.Id == pickingRecord.OutStockLockId)
+                .FirstAsync();
+
+            if (lockInfo == null)
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("鏈壘鍒板搴旂殑鍑哄簱閿佸畾淇℃伅");
+          
+            if (lockInfo.PickedQty < pickingRecord.PickQuantity)
+            {
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error(
+                    $"鍙栨秷鏁伴噺({pickingRecord.PickQuantity})瓒呰繃閿佸畾淇℃伅鐨勫凡鎷i�夋暟閲�({lockInfo.PickedQty})");
+            }
+            // 妫�鏌ョ姸鎬佹槸鍚﹀厑璁稿彇娑�
+            if (lockInfo.Status != (int)OutLockStockStatusEnum.鎷i�夊畬鎴�)
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("褰撳墠鐘舵�佷笉鍏佽鍙栨秷鍒嗘嫞");
+
+            var order = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>().FirstAsync(x => x.OrderNo == orderNo);
+
+            if (order?.OrderStatus == (int)OutOrderStatusEnum.鍑哄簱瀹屾垚)
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("璁㈠崟宸插嚭搴撳畬鎴愶紝涓嶅厑璁稿彇娑堝垎鎷�");
+
+            var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>().FirstAsync(x => x.Id == pickingRecord.OrderDetailId);
+
+            if (orderDetail == null)
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error($"鏈壘鍒拌鍗曟槑缁嗭紝ID: {pickingRecord.OrderDetailId}");
+
+            // 妫�鏌ヨ鍗曟槑缁嗙殑宸叉嫞閫夋暟閲忔槸鍚﹁冻澶熷彇娑�
+            if (orderDetail.PickedQty < pickingRecord.PickQuantity)
+            {
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error($"鍙栨秷鏁伴噺({pickingRecord.PickQuantity})瓒呰繃璁㈠崟鏄庣粏鐨勫凡鎷i�夋暟閲�({orderDetail.PickedQty})");
+            }
+
+            // 妫�鏌ヨ鍗曟槑缁嗙殑宸插嚭搴撴暟閲忔槸鍚﹁冻澶熷彇娑�
+            if (orderDetail.OverOutQuantity < pickingRecord.PickQuantity)
+            {
+                return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error($"鍙栨秷鏁伴噺({pickingRecord.PickQuantity})瓒呰繃璁㈠崟鏄庣粏鐨勫凡鍑哄簱鏁伴噺({orderDetail.OverOutQuantity})");
+            }
+
+            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>().FirstAsync(it => it.Barcode == barcode && it.StockId == pickingRecord.StockId);
+
+            if (stockDetail != null)
+            {
+                // 妫�鏌ュ簱瀛樼姸鎬� - 濡傛灉鐘舵�佹槸鍏ュ簱纭鎴栧叆搴撳畬鎴愶紝璇存槑宸茬粡鍥炲簱
+                if (stockDetail.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt() ||
+                    stockDetail.Status == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt())
+                {
+                    return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error($"鏉$爜{barcode}宸茬粡鍥炲簱锛屼笉鑳藉彇娑堝垎鎷�");
+                }
+            }       
+            
+            return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Success((pickingRecord, lockInfo, orderDetail));
+        }
+        /// <summary>
+        /// 妫�鏌ユ潯鐮佹槸鍚﹀凡缁忓洖搴�
+        /// </summary>
+        private async Task<bool> IsBarcodeReturned(string barcode, int stockId)
+        {
+            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(it => it.Barcode == barcode && it.StockId == stockId)
+                .FirstAsync();
+
+            if (stockDetail == null)
+                return false;
+
+            // 濡傛灉鐘舵�佹槸鍏ュ簱纭鎴栧叆搴撳畬鎴愶紝璇存槑宸茬粡鍥炲簱
+            return stockDetail.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt() ||
+                   stockDetail.Status == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt();
+        }
+
+        /// <summary>
+        /// 妫�鏌ラ攣瀹氫俊鎭搴旂殑鏉$爜鏄惁宸茬粡鍥炲簱
+        /// </summary>
+        private async Task<bool> IsLockInfoReturned(Dt_OutStockLockInfo lockInfo)
+        {
+            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(it => it.Barcode == lockInfo.CurrentBarcode && it.StockId == lockInfo.StockId)
+                .FirstAsync();
+
+            if (stockDetail == null)
+                return false;
+
+            return stockDetail.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt() ||
+                   stockDetail.Status == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt();
+        }
+        private async Task ExecuteCancelLogic(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord,
+            Dt_OutboundOrderDetail orderDetail, string orderNo)
+        {
+            decimal cancelQty = pickingRecord.PickQuantity;
+
+            var currentStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+        .Where(it => it.Barcode == pickingRecord.Barcode && it.StockId == pickingRecord.StockId)
+        .FirstAsync();
+
+            if (currentStockDetail != null &&
+                (currentStockDetail.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt() ||
+                 currentStockDetail.Status == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt()))
+            {
+                throw new Exception($"鏉$爜{pickingRecord.Barcode}宸茬粡鍥炲簱锛屾棤娉曞彇娑堝垎鎷�");
+            }
+            //   妫�鏌ュ彇娑堝悗鏁伴噺涓嶄細涓鸿礋鏁�
+            decimal newOverOutQuantity = orderDetail.OverOutQuantity - cancelQty;
+            decimal newPickedQty = orderDetail.PickedQty - cancelQty;
+
+            if (newOverOutQuantity < 0 || newPickedQty < 0)
+            {
+                throw new Exception($"鍙栨秷鍒嗘嫞灏嗗鑷存暟鎹紓甯革細宸插嚭搴搟newOverOutQuantity}锛屽凡鎷i�墈newPickedQty}");
+            }
+
+            //  澶勭悊涓嶅悓绫诲瀷鐨勫彇娑�
+            if (lockInfo.IsSplitted == 1 && lockInfo.ParentLockId.HasValue)
+            {
+                await HandleSplitBarcodeCancel(lockInfo, pickingRecord, cancelQty);
+            }
+            else
+            {
+                await HandleNormalBarcodeCancel(lockInfo, pickingRecord, cancelQty);
+            }
+
+            // 鏇存柊璁㈠崟鏄庣粏
+            await UpdateOrderDetailOnCancel(pickingRecord.OrderDetailId, cancelQty);
+
+            //  鍒犻櫎鎷i�夎褰�
+            await Db.Deleteable<Dt_PickingRecord>()
+                .Where(x => x.Id == pickingRecord.Id)
+                .ExecuteCommandAsync();
+
+            //  閲嶆柊妫�鏌ヨ鍗曠姸鎬�
+            await UpdateOrderStatusForReturn(orderNo);
+        }
+
+        private async Task HandleSplitBarcodeCancel(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord, decimal cancelQty)
+        {
+            // 鏌ユ壘鐖堕攣瀹氫俊鎭�
+            var parentLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(x => x.Id == lockInfo.ParentLockId.Value)
+                .FirstAsync();
+
+            if (parentLockInfo == null)
+                throw new Exception("鏈壘鍒扮埗閿佸畾淇℃伅锛屾棤娉曞彇娑堟媶鍖呭垎鎷�");
+
+            if (await IsLockInfoReturned(parentLockInfo))
+            {
+                throw new Exception($"鐖舵潯鐮亄parentLockInfo.CurrentBarcode}宸茬粡鍥炲簱锛屾棤娉曞彇娑堟媶鍖呭垎鎷�");
+            }
+            if (await IsLockInfoReturned(lockInfo))
+            {
+                throw new Exception($"鎷嗗寘鏉$爜{lockInfo.CurrentBarcode}宸茬粡鍥炲簱锛屾棤娉曞彇娑堟媶鍖呭垎鎷�");
+            }
+            // 鎭㈠鐖堕攣瀹氫俊鎭殑鍒嗛厤鏁伴噺
+            parentLockInfo.AssignQuantity += cancelQty;
+            await _outStockLockInfoService.Db.Updateable(parentLockInfo).ExecuteCommandAsync();
+
+            // 鎭㈠搴撳瓨
+            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(x => x.Barcode == parentLockInfo.CurrentBarcode && x.StockId == parentLockInfo.StockId)
+                .FirstAsync();
+
+            if (stockDetail != null)
+            {
+                stockDetail.StockQuantity += cancelQty;
+                stockDetail.OutboundQuantity = stockDetail.StockQuantity;
+                stockDetail.Status = StockStatusEmun.鍑哄簱閿佸畾.ObjToInt();
+                await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+            }
+
+            // 鏇存柊鎷嗗寘璁板綍鐘舵��
+            await _splitPackageService.Db.Updateable<Dt_SplitPackageRecord>()
+                .SetColumns(x => new Dt_SplitPackageRecord
+                {
+                    Status = (int)SplitPackageStatusEnum.宸叉挙閿�,
+                    IsReverted = true,
+                })
+                .Where(x => x.NewBarcode == lockInfo.CurrentBarcode && !x.IsReverted)
+                .ExecuteCommandAsync();
+
+            // 鍒犻櫎鎷嗗寘浜х敓鐨勯攣瀹氫俊鎭�
+            await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
+                .Where(x => x.Id == lockInfo.Id)
+                .ExecuteCommandAsync();
+        }
+
+        private async Task HandleNormalBarcodeCancel(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord, decimal cancelQty)
+        {
+            if (await IsLockInfoReturned(lockInfo))
+            {
+                throw new Exception($"鏉$爜{lockInfo.CurrentBarcode}宸茬粡鍥炲簱锛屾棤娉曞彇娑堝垎鎷�");
+            }
+            // 鎭㈠閿佸畾淇℃伅
+            lockInfo.PickedQty -= cancelQty;
+            if (lockInfo.PickedQty < 0) lockInfo.PickedQty = 0;
+
+            lockInfo.Status = (int)OutLockStockStatusEnum.鍑哄簱涓�;
+            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
+
+            // 鎭㈠搴撳瓨
+            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(x => x.Barcode == pickingRecord.Barcode && x.StockId == pickingRecord.StockId)
+                .FirstAsync();
+
+            if (stockDetail != null)
+            {
+                stockDetail.StockQuantity += cancelQty;
+                stockDetail.OutboundQuantity = stockDetail.StockQuantity;
+                stockDetail.Status = StockStatusEmun.鍑哄簱閿佸畾.ObjToInt();
+                await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+            }
+        }
+
+        private async Task UpdateOrderDetailOnCancel(int orderDetailId, decimal cancelQty)
+        {
+            // 鑾峰彇鏈�鏂扮殑璁㈠崟鏄庣粏鏁版嵁
+            var currentOrderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                .FirstAsync(x => x.Id == orderDetailId);
+
+            decimal newOverOutQuantity = currentOrderDetail.OverOutQuantity - cancelQty;
+            decimal newPickedQty = currentOrderDetail.PickedQty - cancelQty;
+
+            // 妫�鏌ュ彇娑堝悗鏁伴噺涓嶄細涓鸿礋鏁�
+            if (newOverOutQuantity < 0 || newPickedQty < 0)
+            {
+                throw new Exception($"鍙栨秷鍒嗘嫞灏嗗鑷村凡鍑哄簱鏁伴噺({newOverOutQuantity})鎴栧凡鎷i�夋暟閲�({newPickedQty})涓鸿礋鏁�");
+            }
+
+            await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
+                .SetColumns(it => new Dt_OutboundOrderDetail
+                {
+                    PickedQty = newPickedQty,
+                    OverOutQuantity = newOverOutQuantity,
+                })
+                .Where(it => it.Id == orderDetailId)
+                .ExecuteCommandAsync();
+        }
+
+        #endregion
+
+        #region 鍥炲簱鎿嶄綔绉佹湁鏂规硶
+
+        private async Task<Dt_StockInfo> GetStockInfo(string palletCode)
+        {
+            return await _stockInfoService.Db.Queryable<Dt_StockInfo>()
+                .FirstAsync(x => x.PalletCode == palletCode);
+        }
+        /// <summary>
+        /// 妫�鏌ユ暣涓墭鐩樻槸鍚﹀凡缁忓洖搴�
+        /// </summary>
+        private async Task<bool> IsPalletReturned(string palletCode)
+        {
+            var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
+                .Where(x => x.PalletCode == palletCode)
+                .FirstAsync();
+
+            if (stockInfo == null)
+                return false;
+
+            // 濡傛灉鎵樼洏鐘舵�佹槸鍏ュ簱纭鎴栧叆搴撳畬鎴愶紝璇存槑宸茬粡鍥炲簱
+            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();
+
+            if (task == null)
+            {
+                // 濡傛灉鎵句笉鍒帮紝鍐嶉�氳繃鎵樼洏鍙锋煡鎵�
+                task = await _taskRepository.Db.Queryable<Dt_Task>()
+                    .Where(x => x.PalletCode == palletCode)
+                    .FirstAsync();
+            }
+
+            return task;
+        }
+
+        private async Task<ReturnAnalysisResult> AnalyzeReturnItems(string orderNo, string palletCode, int stockId)
+        {
+            var result = new ReturnAnalysisResult();
+
+            // 鎯呭喌1锛氳幏鍙栨湭鍒嗘嫞鐨勫嚭搴撻攣瀹氳褰�
+            var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(it => it.OrderNo == orderNo &&
+                           it.PalletCode == palletCode &&
+                           it.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
+                .ToListAsync();
+
+            if (remainingLocks.Any())
+            {
+                result.HasRemainingLocks = true;
+                result.RemainingLocks = remainingLocks;
+                result.RemainingLocksReturnQty = remainingLocks.Sum(x => x.AssignQuantity - x.PickedQty);
+            }
+
+            // 鎯呭喌2锛氭鏌ユ墭鐩樹笂鏄惁鏈夊叾浠栧簱瀛樿揣鐗�
+            var palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .Where(it => it.StockId == stockId &&
+                            (it.Status == StockStatusEmun.鍏ュ簱纭.ObjToInt() ||
+                             it.Status == StockStatusEmun.鍏ュ簱瀹屾垚.ObjToInt() ||
+                             it.Status == StockStatusEmun.鍑哄簱閿佸畾.ObjToInt()))
+                .Where(it => it.StockQuantity > 0)
+                .ToListAsync();
+
+            if (palletStockGoods.Any())
+            {
+                result.HasPalletStockGoods = true;
+                result.PalletStockGoods = palletStockGoods;
+                result.PalletStockReturnQty = palletStockGoods.Sum(x => x.StockQuantity);
+            }
+
+            // 鎯呭喌3锛氭鏌ユ媶鍖呰褰�
+            var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
+                .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode && !it.IsReverted && it.Status != (int)SplitPackageStatusEnum.宸插洖搴�)
+                .ToListAsync();
+
+            if (splitRecords.Any())
+            {
+                result.HasSplitRecords = true;
+                result.SplitRecords = splitRecords;
+                result.SplitReturnQty = await CalculateSplitReturnQuantity(splitRecords, stockId);
+            }
+
+            result.TotalReturnQty = result.RemainingLocksReturnQty + result.PalletStockReturnQty + result.SplitReturnQty;
+            result.HasItemsToReturn = result.TotalReturnQty > 0;
+
+            return result;
+        }
+
+        private async Task<decimal> CalculateSplitReturnQuantity(List<Dt_SplitPackageRecord> splitRecords, int stockId)
+        {
+            decimal totalQty = 0;
+            var processedBarcodes = new HashSet<string>();
+
+            foreach (var splitRecord in splitRecords)
+            {
+                // 妫�鏌ュ師鏉$爜
+                if (!processedBarcodes.Contains(splitRecord.OriginalBarcode))
+                {
+                    var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                        .Where(it => it.Barcode == splitRecord.OriginalBarcode && it.StockId == stockId)
+                        .FirstAsync();
+
+                    if (originalStock != null && originalStock.StockQuantity > 0)
+                    {
+                        totalQty += originalStock.StockQuantity;
+                        processedBarcodes.Add(splitRecord.OriginalBarcode);
+                    }
+                }
+
+                // 妫�鏌ユ柊鏉$爜
+                if (!processedBarcodes.Contains(splitRecord.NewBarcode))
+                {
+                    var newStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                        .Where(it => it.Barcode == splitRecord.NewBarcode && it.StockId == stockId)
+                        .FirstAsync();
+
+                    if (newStock != null && newStock.StockQuantity > 0)
+                    {
+                        totalQty += newStock.StockQuantity;
+                        processedBarcodes.Add(splitRecord.NewBarcode);
+                    }
+                }
+            }
+
+            return totalQty;
+        }
+
+        private async Task<WebResponseContent> HandleNoReturnItems(string orderNo, string palletCode,Dt_Task originalTask)
+        {
+            // 妫�鏌ユ槸鍚︽墍鏈夎揣鐗╅兘宸叉嫞閫夊畬鎴�
+            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("娌℃湁闇�瑕佸洖搴撶殑鍓╀綑璐х墿");
+            }
+            //绌烘墭鐩樺浣曞鐞�  杩樻湁涓�涓嚭搴撲换鍔¤澶勭悊銆�
+         
+        }
+
+        private async Task ExecuteReturnOperations(string orderNo, string palletCode, Dt_StockInfo stockInfo,
+            Dt_Task task, ReturnAnalysisResult analysis)
+        {
+            // 鎯呭喌1锛氬鐞嗘湭鍒嗘嫞鐨勫嚭搴撻攣瀹氳褰�
+            if (analysis.HasRemainingLocks)
+            {
+                await HandleRemainingLocksReturn(analysis.RemainingLocks, stockInfo.Id);
+
+                // 鍏抽敭锛氭洿鏂拌鍗曟槑缁嗙殑宸叉嫞閫夋暟閲�
+                await UpdateOrderDetailsOnReturn(analysis.RemainingLocks);
+            }
+
+            // 澶勭悊鎵樼洏涓婂叾浠栧簱瀛樿揣鐗�
+            if (analysis.HasPalletStockGoods)
+            {
+                await HandlePalletStockGoodsReturn(analysis.PalletStockGoods);
+            }
+
+            // 澶勭悊鎷嗗寘璁板綍
+            if (analysis.HasSplitRecords)
+            {
+                await HandleSplitRecordsReturn(analysis.SplitRecords, orderNo, palletCode);
+            }
+
+            // 鏇存柊搴撳瓨涓昏〃鐘舵��
+            await UpdateStockInfoStatus(stockInfo);
+        }
+
+        private async Task HandleRemainingLocksReturn(List<Dt_OutStockLockInfo> remainingLocks, int stockId)
+        {
+            var lockIds = remainingLocks.Select(x => x.Id).ToList();
+
+            // 鏇存柊鍑哄簱閿佸畾璁板綍鐘舵�佷负鍥炲簱涓�
+            await _outStockLockInfoService.Db.Updateable<Dt_OutStockLockInfo>()
+                .SetColumns(it => new Dt_OutStockLockInfo
+                {
+                    Status = (int)OutLockStockStatusEnum.鍥炲簱涓�,
+                })
+                .Where(it => lockIds.Contains(it.Id))
+                .ExecuteCommandAsync();
+
+            // 澶勭悊搴撳瓨璁板綍
+            foreach (var lockInfo in remainingLocks)
+            {
+                decimal returnQty = lockInfo.AssignQuantity - lockInfo.PickedQty;
+
+                // 鏌ユ壘瀵瑰簲鐨勫簱瀛樻槑缁�
+                var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                    .Where(it => it.Barcode == lockInfo.CurrentBarcode && it.StockId == lockInfo.StockId)
+                    .FirstAsync();
+
+                if (stockDetail != null)
+                {
+                    // 鎭㈠搴撳瓨鐘舵��
+                    stockDetail.OutboundQuantity = Math.Max(0, stockDetail.OutboundQuantity - returnQty);
+                    stockDetail.Status = StockStatusEmun.鍏ュ簱纭.ObjToInt();
+                    await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+                }
+                else
+                {
+                    // 鍒涘缓鏂扮殑搴撳瓨璁板綍
+                    var newStockDetail = new Dt_StockInfoDetail
+                    {
+                        StockId = lockInfo.StockId,
+                        MaterielCode = lockInfo.MaterielCode,
+                        MaterielName = lockInfo.MaterielName,
+                        OrderNo = lockInfo.OrderNo,
+                        BatchNo = lockInfo.BatchNo,
+                        StockQuantity = returnQty,
+                        OutboundQuantity = 0,
+                        Barcode = lockInfo.CurrentBarcode,
+                        InboundOrderRowNo = "",
+                        Status = StockStatusEmun.鍏ュ簱纭.ObjToInt(),
+                        SupplyCode = lockInfo.SupplyCode,
+                        WarehouseCode = lockInfo.WarehouseCode,
+                        Unit = lockInfo.Unit,
+                    };
+                    await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync();
+                }
+            }
+        }
+
+        private async Task UpdateOrderDetailsOnReturn(List<Dt_OutStockLockInfo> remainingLocks)
+        {
+            // 鎸夎鍗曟槑缁嗗垎缁�
+            var orderDetailGroups = remainingLocks.GroupBy(x => x.OrderDetailId);
+
+            foreach (var group in orderDetailGroups)
+            {
+                var orderDetailId = group.Key;
+                var totalReturnQty = group.Sum(x => x.AssignQuantity - x.PickedQty);
+
+                // 鑾峰彇褰撳墠璁㈠崟鏄庣粏
+                var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                    .FirstAsync(x => x.Id == orderDetailId);
+
+                if (orderDetail != null)
+                {
+                    // 璋冩暣宸叉嫞閫夋暟閲忓拰宸插嚭搴撴暟閲�
+                    decimal newPickedQty = Math.Max(0, orderDetail.PickedQty - totalReturnQty);
+                    decimal newOverOutQuantity = Math.Max(0, orderDetail.OverOutQuantity - totalReturnQty);
+
+                    await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
+                        .SetColumns(it => new Dt_OutboundOrderDetail
+                        {
+                            PickedQty = newPickedQty,
+                            OverOutQuantity = newOverOutQuantity,
+                        })
+                        .Where(it => it.Id == orderDetailId)
+                        .ExecuteCommandAsync();
+                }
+            }
+        }
+
+        private async Task HandlePalletStockGoodsReturn(List<Dt_StockInfoDetail> palletStockGoods)
+        {
+            _logger.LogInformation($"鍥炲簱鎿嶄綔锛氬彂鐜皗palletStockGoods.Count}涓簱瀛樻槑缁嗛渶瑕佸洖搴擄紝绛夊緟AGV鎼繍");
+            foreach (var stockGood in palletStockGoods)
+            {
+                _logger.LogInformation($"寰呭洖搴撹揣鐗� - 鏉$爜: {stockGood.Barcode}, 鏁伴噺: {stockGood.StockQuantity}, 褰撳墠鐘舵��: {stockGood.Status}");
+            
+            // 鎭㈠搴撳瓨鐘舵��
+            stockGood.OutboundQuantity = 0;
+                stockGood.Status = StockStatusEmun.鍏ュ簱纭.ObjToInt();
+
+                await _stockInfoDetailService.Db.Updateable(stockGood).ExecuteCommandAsync();
+            }
+        }
+
+        private async Task HandleSplitRecordsReturn(List<Dt_SplitPackageRecord> splitRecords, string orderNo, string palletCode)
+        {
+            // 鏇存柊鎷嗗寘璁板綍鐘舵��
+            await _splitPackageService.Db.Updateable<Dt_SplitPackageRecord>()
+                .SetColumns(x => new Dt_SplitPackageRecord
+                {
+                    Status = (int)SplitPackageStatusEnum.宸插洖搴�,
+                })
+                .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode && !x.IsReverted)
+                .ExecuteCommandAsync();
+        }
+
+        private async Task UpdateStockInfoStatus(Dt_StockInfo stockInfo)
+        {
+            _logger.LogInformation($"鍥炲簱鎿嶄綔锛氭墭鐩榹stockInfo.PalletCode}绛夊緟AGV鍥炲簱鎼繍");
+            // 鏇存柊搴撳瓨涓昏〃鐘舵��
+            stockInfo.StockStatus = StockStatusEmun.鍏ュ簱纭.ObjToInt();
+            await _stockInfoService.Db.Updateable(stockInfo).ExecuteCommandAsync();
+        }
+        /// <summary>
+        /// 鍒涘缓鍥炲簱浠诲姟
+        /// </summary>
+        /// <param name="orderNo"></param>
+        /// <param name="palletCode"></param>
+        /// <param name="originalTask"></param>
+        /// <param name="analysis"></param>
+        /// <returns></returns>
+        private async Task CreateReturnTaskAndHandleESS(string orderNo, string palletCode, Dt_Task originalTask, ReturnAnalysisResult analysis)
+        {
+            var firstLocation = await _locationInfoService.Db.Queryable<Dt_LocationInfo>()
+                .FirstAsync(x => x.LocationCode == originalTask.SourceAddress);
+
+            // 鍒嗛厤鏂拌揣浣�
+            var newLocation = _locationInfoService.AssignLocation(firstLocation.LocationType);
+
+            Dt_Task returnTask = new()
+            {
+                CurrentAddress = stations[originalTask.TargetAddress],
+                Grade = 0,
+                PalletCode = palletCode,
+                NextAddress = "",
+                OrderNo = originalTask.OrderNo,
+                Roadway = newLocation.RoadwayNo,
+                SourceAddress = stations[originalTask.TargetAddress],
+                TargetAddress = newLocation.LocationCode,
+                TaskStatus = TaskStatusEnum.New.ObjToInt(),
+                TaskType = TaskTypeEnum.InPick.ObjToInt(),
+                PalletType = originalTask.PalletType,
+                WarehouseId = originalTask.WarehouseId
+
+            };
+            // 淇濆瓨鍥炲簱浠诲姟
+            await _taskRepository.Db.Insertable(returnTask).ExecuteCommandAsync();
+            var targetAddress = originalTask.TargetAddress;        
+         
+            // 鍒犻櫎鍘熷鍑哄簱浠诲姟
+            await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync();
+
+            // 缁� ESS 鍙戦�佹祦鍔ㄤ俊鍙峰拰鍒涘缓浠诲姟
+            await SendESSCommands(palletCode, targetAddress, returnTask);
+        }
+        /// <summary>
+        /// 缁橢SS涓嬩换鍔�
+        /// </summary>
+        /// <param name="palletCode"></param>
+        /// <param name="targetAddress"></param>
+        /// <param name="returnTask"></param>
+        /// <returns></returns>
+        /// <exception cref="Exception"></exception>
+        private async Task SendESSCommands(string palletCode, string targetAddress, Dt_Task returnTask)
+        {
+            try
+            {
+                // 1. 鍙戦�佹祦鍔ㄤ俊鍙�
+                var moveResult = await _eSSApiService.MoveContainerAsync(new WIDESEA_DTO.Basic.MoveContainerRequest
+                {
+                    slotCode = movestations[targetAddress],
+                    containerCode = palletCode
+                });
+
+                if (moveResult)
+                {
+                    // 2. 鍒涘缓鍥炲簱浠诲姟
+                    var essTask = new TaskModel()
+                    {
+                        taskType = "putaway",
+                        taskGroupCode = "",
+                        groupPriority = 0,
+                        tasks = new List<TasksType>
+                    {
+                        new()
+                        {
+                            taskCode = returnTask.TaskNum.ToString(),
+                            taskPriority = 0,
+                            taskDescribe = new TaskDescribeType
+                            {
+                                containerCode = palletCode,
+                                containerType = "CT_KUBOT_STANDARD",
+                                fromLocationCode = stations.GetValueOrDefault(targetAddress) ?? "",
+                                toStationCode = "",
+                                toLocationCode = returnTask.TargetAddress,
+                                deadline = 0,
+                                storageTag = ""
+                            }
+                        }
+                    }
+                    };
+
+                    var resultTask = await _eSSApiService.CreateTaskAsync(essTask);
+                    _logger.LogInformation($"ReturnRemaining 鍒涘缓浠诲姟鎴愬姛: {resultTask}");
+                }
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError($"ReturnRemaining ESS鍛戒护鍙戦�佸け璐�: {ex.Message}");
+                throw new Exception($"ESS绯荤粺閫氫俊澶辫触: {ex.Message}");
+            }
+        }
+
+        #endregion
+
+        #region 璁㈠崟鐘舵�佺鐞�
+
+        private async Task CheckAndUpdateOrderStatus(string orderNo)
+        {
+            try
+            {
+                var orderDetails = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                    .LeftJoin<Dt_OutboundOrder>((o, item) => o.OrderId == item.Id)
+                    .Where((o, item) => item.OrderNo == orderNo)
+                    .Select((o, item) => o)
+                    .ToListAsync();
+
+                bool allCompleted = true;
+                foreach (var detail in orderDetails)
+                {
+                    if (detail.OverOutQuantity < detail.NeedOutQuantity)
+                    {
+                        allCompleted = false;
+                        break;
+                    }
+                }
+
+                var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
+                    .FirstAsync(x => x.OrderNo == orderNo);
+
+                if (outboundOrder == null) return;
+
+                int newStatus = allCompleted ? (int)OutOrderStatusEnum.鍑哄簱瀹屾垚 : (int)OutOrderStatusEnum.鍑哄簱涓�;
+
+                if (outboundOrder.OrderStatus != newStatus)
+                {
+                    await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
+                        .SetColumns(x => x.OrderStatus == newStatus)
+                        .Where(x => x.OrderNo == orderNo)
+                        .ExecuteCommandAsync();
+
+                    // 鍙湁姝e父鍒嗘嫞瀹屾垚鏃舵墠鍚慚ES鍙嶉
+                    if (allCompleted && newStatus == (int)OutOrderStatusEnum.鍑哄簱瀹屾垚)
+                    {
+                        await HandleOrderCompletion(outboundOrder, orderNo);
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError($"CheckAndUpdateOrderStatus澶辫触 - OrderNo: {orderNo}, Error: {ex.Message}");
+            }
+        }
+
+        private async Task UpdateOrderStatusForReturn(string orderNo)
+        {
+            try
+            {
+                var orderDetails = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                    .LeftJoin<Dt_OutboundOrder>((o, item) => o.OrderId == item.Id)
+                    .Where((o, item) => item.OrderNo == orderNo)
+                    .Select((o, item) => o)
+                    .ToListAsync();
+
+                bool allCompleted = true;
+                foreach (var detail in orderDetails)
+                {
+                    if (detail.OverOutQuantity < detail.NeedOutQuantity)
+                    {
+                        allCompleted = false;
+                        break;
+                    }
+                }
+
+                var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
+                    .FirstAsync(x => x.OrderNo == orderNo);
+
+                if (outboundOrder == null) return;
+
+                int newStatus = allCompleted ? (int)OutOrderStatusEnum.鍑哄簱瀹屾垚 : (int)OutOrderStatusEnum.鍑哄簱涓�;
+
+                if (outboundOrder.OrderStatus != newStatus)
+                {
+                    await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
+                        .SetColumns(x => x.OrderStatus == newStatus)
+                        .Where(x => x.OrderNo == orderNo)
+                        .ExecuteCommandAsync();
+
+                    _logger.LogInformation($"鍥炲簱鎿嶄綔鏇存柊璁㈠崟鐘舵�� - OrderNo: {orderNo}, 鏂扮姸鎬�: {newStatus}");
+                }
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError($"UpdateOrderStatusForReturn澶辫触 - OrderNo: {orderNo}, Error: {ex.Message}");
+            }
+        }
+
+        private async Task HandleOrderCompletion(Dt_OutboundOrder outboundOrder, string orderNo)
+        {
+            // 璋冩嫧鍑哄簱鍜岄噸妫�鍑哄簱涓嶉渶瑕佸弽棣圡ES
+            if (outboundOrder.OrderType == OutOrderTypeEnum.Allocate.ObjToInt() ||
+                outboundOrder.OrderType == OutOrderTypeEnum.ReCheck.ObjToInt())
+            {
+                return;
+            }
+
+            try
+            {
+                var feedmodel = new FeedbackOutboundRequestModel
+                {
+                    reqCode = Guid.NewGuid().ToString(),
+                    reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
+                    business_type = outboundOrder.BusinessType,
+                    factoryArea = outboundOrder.FactoryArea,
+                    operationType = 1,
+                    Operator = App.User.UserName,
+                    orderNo = outboundOrder.UpperOrderNo,
+                    status = outboundOrder.OrderStatus,
+                    details = new List<FeedbackOutboundDetailsModel>()
+                };
+
+                // 鍙幏鍙栧凡鎷i�夊畬鎴愮殑閿佸畾璁板綍
+                var lists = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                    .Where(x => x.OrderNo == orderNo && x.Status == (int)OutLockStockStatusEnum.鎷i�夊畬鎴�)
+                    .ToListAsync();
+
+                var groupedData = lists.GroupBy(item => new { item.MaterielCode, item.lineNo, item.Unit, item.WarehouseCode })
+                   .Select(group => new FeedbackOutboundDetailsModel
+                   {
+                       materialCode = group.Key.MaterielCode,
+                       lineNo = group.Key.lineNo,
+                       warehouseCode = group.Key.WarehouseCode,
+                       qty = group.Sum(x => x.PickedQty),
+                       currentDeliveryQty = group.Sum(x => x.PickedQty),
+                       unit = group.Key.Unit,
+                       barcodes = group.Select(row => new WIDESEA_DTO.Outbound.BarcodesModel
+                       {
+                           barcode = row.CurrentBarcode,
+                           supplyCode = row.SupplyCode,
+                           batchNo = row.BatchNo,
+                           unit = row.Unit,
+                           qty = row.PickedQty
+                       }).ToList()
+                   }).ToList();
+
+                feedmodel.details = groupedData;
+
+                var result = await _invokeMESService.FeedbackOutbound(feedmodel);
+                if (result != null && result.code == 200)
+                {
+                    await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
+                        .SetColumns(x => x.ReturnToMESStatus == 1)
+                        .Where(x => x.OrderId == outboundOrder.Id)
+                        .ExecuteCommandAsync();
+
+                    await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
+                        .SetColumns(x => x.ReturnToMESStatus == 1)
+                        .Where(x => x.OrderNo == orderNo)
+                        .ExecuteCommandAsync();
+                }
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError($"FeedbackOutbound澶辫触 - OrderNo: {orderNo}, Error: {ex.Message}");
+            }
+        }
+
+        #endregion
+
+        #region 杈呭姪鏂规硶
+
+        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>();
+    }
+
+    #endregion
 }

--
Gitblit v1.9.3