From dcdb87f1cb6cfd66d3fc01bc2248e4876c37f223 Mon Sep 17 00:00:00 2001
From: pan <antony1029@163.com>
Date: 星期日, 30 十一月 2025 18:14:12 +0800
Subject: [PATCH] Merge branch 'master' of http://115.159.85.185:8098/r/ZhongRui/ALDbanyunxiangmu

---
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundBatchPickingService.cs | 1071 +++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 885 insertions(+), 186 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/OutboundBatchPickingService.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/OutboundBatchPickingService.cs"
index c7b468a..54eab6d 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/OutboundBatchPickingService.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/OutboundBatchPickingService.cs"
@@ -1,5 +1,6 @@
 锘縰sing Microsoft.Extensions.Logging;
 using SqlSugar;
+using SqlSugar.Extensions;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -267,7 +268,7 @@
                 await UpdateOrderStatusAfterPalletRemoval(orderNo);
 
                 // 璁板綍鎿嶄綔鍘嗗彶
-                await RecordEmptyPalletRemoval(orderNo, palletCode, completedLocks);
+               // await RecordEmptyPalletRemoval(orderNo, palletCode, completedLocks);
 
                 _unitOfWorkManage.CommitTran();
 
@@ -411,32 +412,68 @@
             {
                 _unitOfWorkManage.BeginTran();
 
-                // 1. 楠岃瘉鍒嗘嫞璇锋眰
+                // 楠岃瘉鍒嗘嫞璇锋眰
                 var validationResult = await ValidatePickingRequest(orderNo, palletCode, barcode);
                 if (!validationResult.IsValid)
                     return WebResponseContent.Instance.Error(validationResult.ErrorMessage);
 
                 var (lockInfo, orderDetail, stockDetail, batch) = validationResult.Data;
 
-                // 浣跨敤閿佸畾淇℃伅鐨勫垎閰嶆暟閲忎綔涓哄疄闄呭垎鎷f暟閲�
-                var actualPickedQty = lockInfo.AssignQuantity;
+                // 妫�鏌ユ槸鍚﹂渶瑕佽嚜鍔ㄦ媶鍖�
+                var autoSplitResult = await CheckAndAutoSplitIfNeeded(lockInfo, stockDetail, palletCode);
+                if (autoSplitResult != null)
+                {
+                    // 濡傛灉鎵ц浜嗚嚜鍔ㄦ媶鍖咃紝閲嶆柊鑾峰彇鏈�鏂扮殑閿佸畾淇℃伅鍜屽簱瀛樹俊鎭�
+                    var refreshedValidation = await ValidatePickingRequest(orderNo, palletCode, barcode);
+                    if (!refreshedValidation.IsValid)
+                    {
+                        _unitOfWorkManage.RollbackTran();
+                        return WebResponseContent.Instance.Error(refreshedValidation.ErrorMessage);
+                    }
 
-                // 2. 鎵ц鍒嗘嫞閫昏緫
-                var pickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, actualPickedQty);
+                    (lockInfo, orderDetail, stockDetail, batch) = refreshedValidation.Data;
 
-                // 3. 鏇存柊鎵规鍜岃鍗曟暟鎹�
-                await UpdateBatchAndOrderData(batch, orderDetail, actualPickedQty, orderNo);
+                    // 閲嶈淇锛氳嚜鍔ㄦ媶鍖呭悗锛岀珛鍗虫墽琛屽師鏉$爜鐨勫垎鎷�
+                    var actualPickedQty = lockInfo.AssignQuantity;
+                    var pickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, actualPickedQty);
 
-                // 4. 璁板綍鎷i�夊巻鍙�
-                await RecordPickingHistory(pickingResult, orderNo, palletCode);
+                    // 鏇存柊鎵规鍜岃鍗曟暟鎹�
+                    await UpdateBatchAndOrderData(batch, orderDetail, actualPickedQty, orderNo);
+
+                    // 璁板綍鎷i�夊巻鍙�
+                    await RecordPickingHistory(pickingResult, orderNo, palletCode);
+
+                    _unitOfWorkManage.CommitTran();
+
+                    return WebResponseContent.Instance.OK("鑷姩鎷嗗寘骞跺垎鎷f垚鍔�", new
+                    {
+                        AutoSplitted = true,
+                        NewBarcode = autoSplitResult.NewBarcode,
+                        OriginalBarcode = barcode,
+                        SplitQuantity = autoSplitResult.SplitQuantity,
+                        PickedQuantity = actualPickedQty,
+                        MaterialCode = lockInfo.MaterielCode
+                    });
+                }
+
+                // 姝e父鍒嗘嫞娴佺▼锛堜笉闇�瑕佽嚜鍔ㄦ媶鍖咃級
+                var normalPickedQty = lockInfo.AssignQuantity;
+                var normalPickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, normalPickedQty);
+
+                // 鏇存柊鎵规鍜岃鍗曟暟鎹�
+                await UpdateBatchAndOrderData(batch, orderDetail, normalPickedQty, orderNo);
+
+                // 璁板綍鎷i�夊巻鍙�
+                await RecordPickingHistory(normalPickingResult, orderNo, palletCode);
 
                 _unitOfWorkManage.CommitTran();
 
                 return WebResponseContent.Instance.OK("鍒嗘嫞鎴愬姛", new
                 {
-                    PickedQuantity = actualPickedQty,
+                    PickedQuantity = normalPickedQty,
                     Barcode = barcode,
-                    MaterialCode = lockInfo.MaterielCode
+                    MaterialCode = lockInfo.MaterielCode,
+                    AutoSplitted = false
                 });
             }
             catch (Exception ex)
@@ -494,6 +531,8 @@
 
         #region 鎵嬪姩鎷嗗寘
 
+        #region 鎵嬪姩鎷嗗寘鐩稿叧鏂规硶
+
         /// <summary>
         /// 鎵嬪姩鎷嗗寘
         /// </summary>
@@ -503,15 +542,15 @@
             {
                 _unitOfWorkManage.BeginTran();
 
-                //  楠岃瘉鎷嗗寘璇锋眰
+                // 楠岃瘉鎷嗗寘璇锋眰
                 var validationResult = await ValidateSplitRequest(orderNo, palletCode, originalBarcode, splitQuantity);
                 if (!validationResult.IsValid)
                     return WebResponseContent.Instance.Error(validationResult.ErrorMessage);
 
                 var (lockInfo, stockDetail) = validationResult.Data;
 
-                // . 鎵ц鎷嗗寘閫昏緫
-                var splitResult = await ExecuteSplitLogic(lockInfo, stockDetail, splitQuantity, palletCode);
+                // 鎵ц鎷嗗寘閫昏緫
+                var splitResult = await ExecuteManualSplitLogic(lockInfo, stockDetail, splitQuantity, palletCode);
 
                 _unitOfWorkManage.CommitTran();
 
@@ -530,9 +569,224 @@
             }
         }
 
+        /// <summary>
+        /// 楠岃瘉鎷嗗寘璇锋眰 - 澧炲己鍒嗛厤鏁伴噺鎺у埗
+        /// </summary>
+        private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>> ValidateSplitRequest(
+            string orderNo, string palletCode, string originalBarcode, decimal splitQuantity)
+        {
+            _logger.LogInformation($"寮�濮嬮獙璇佹媶鍖呰姹� - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}, 鍘熸潯鐮�: {originalBarcode}, 鎷嗗寘鏁伴噺: {splitQuantity}");
+
+            // 鏌ユ壘閿佸畾淇℃伅
+            var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(x => x.OrderNo == orderNo &&
+                           x.PalletCode == palletCode &&
+                           x.CurrentBarcode == originalBarcode &&
+                           x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
+                .FirstAsync();
+
+            if (lockInfo == null)
+            {
+                _logger.LogWarning($"鏈壘鍒版湁鏁堢殑閿佸畾淇℃伅 - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}, 鏉$爜: {originalBarcode}");
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鏈壘鍒版湁鏁堢殑閿佸畾淇℃伅");
+            }
+
+            _logger.LogInformation($"鎵惧埌閿佸畾淇℃伅 - 鍒嗛厤鏁伴噺: {lockInfo.AssignQuantity}, 宸叉嫞閫�: {lockInfo.PickedQty}, 璁㈠崟鏁伴噺: {lockInfo.OrderQuantity}");
+
+            // 鑾峰彇璁㈠崟鏄庣粏
+            var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                .FirstAsync(x => x.Id == lockInfo.OrderDetailId);
+
+            if (orderDetail == null)
+            {
+                _logger.LogWarning($"鏈壘鍒拌鍗曟槑缁� - OrderDetailId: {lockInfo.OrderDetailId}");
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鏈壘鍒拌鍗曟槑缁�");
+            }
+
+            _logger.LogInformation($"鎵惧埌璁㈠崟鏄庣粏 - 宸插垎閰嶆暟閲�: {orderDetail.AllocatedQuantity}, 閿佸畾鏁伴噺: {orderDetail.LockQuantity}");
+
+            // 鑾峰彇搴撳瓨淇℃伅
+            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .FirstAsync(x => x.Barcode == originalBarcode && x.StockId == lockInfo.StockId);
+
+            if (stockDetail == null)
+            {
+                _logger.LogWarning($"鏈壘鍒板簱瀛樹俊鎭� - 鏉$爜: {originalBarcode}, StockId: {lockInfo.StockId}");
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鏈壘鍒板搴旂殑搴撳瓨淇℃伅");
+            }
+
+            _logger.LogInformation($"鎵惧埌搴撳瓨淇℃伅 - 搴撳瓨鏁伴噺: {stockDetail.StockQuantity}, 鍑哄簱鏁伴噺: {stockDetail.OutboundQuantity}");
+
+            // 閲嶈淇锛氶獙璇佹媶鍖呮暟閲忎笉鑳藉ぇ浜庡簱瀛樻暟閲�
+            if (stockDetail.StockQuantity < splitQuantity)
+            {
+                _logger.LogWarning($"鎷嗗寘鏁伴噺澶т簬搴撳瓨鏁伴噺 - 鎷嗗寘鏁伴噺: {splitQuantity}, 搴撳瓨鏁伴噺: {stockDetail.StockQuantity}");
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error($"鎷嗗寘鏁伴噺涓嶈兘澶т簬搴撳瓨鏁伴噺锛屽綋鍓嶅簱瀛橈細{stockDetail.StockQuantity}");
+            }
+
+            // 閲嶈淇锛氶獙璇佹媶鍖呮暟閲忎笉鑳藉ぇ浜庨攣瀹氫俊鎭殑鍒嗛厤鏁伴噺
+            if (lockInfo.AssignQuantity < splitQuantity)
+            {
+                _logger.LogWarning($"鎷嗗寘鏁伴噺澶т簬鍒嗛厤鏁伴噺 - 鎷嗗寘鏁伴噺: {splitQuantity}, 鍒嗛厤鏁伴噺: {lockInfo.AssignQuantity}");
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error($"鎷嗗寘鏁伴噺涓嶈兘澶т簬鍒嗛厤鏁伴噺锛屽綋鍓嶅垎閰嶆暟閲忥細{lockInfo.AssignQuantity}");
+            }
+
+            // 閲嶈淇锛氶獙璇佹媶鍖呮暟閲忎笉鑳藉ぇ浜庨攣瀹氫俊鎭殑鏈嫞閫夋暟閲�
+            decimal remainingToPick = lockInfo.AssignQuantity - lockInfo.PickedQty;
+            if (remainingToPick < splitQuantity)
+            {
+                _logger.LogWarning($"鎷嗗寘鏁伴噺澶т簬鏈嫞閫夋暟閲� - 鎷嗗寘鏁伴噺: {splitQuantity}, 鏈嫞閫夋暟閲�: {remainingToPick}");
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error($"鎷嗗寘鏁伴噺涓嶈兘澶т簬鏈嫞閫夋暟閲忥紝褰撳墠鏈嫞閫夛細{remainingToPick}");
+            }
+
+            // 閲嶈淇锛氶獙璇佹媶鍖呭悗鍘熼攣瀹氫俊鎭殑鍒嗛厤鏁伴噺涓嶄細涓鸿礋鏁�
+            if (lockInfo.AssignQuantity - splitQuantity < 0)
+            {
+                _logger.LogWarning($"鎷嗗寘鍚庡垎閰嶆暟閲忎负璐熸暟 - 褰撳墠鍒嗛厤鏁伴噺: {lockInfo.AssignQuantity}, 鎷嗗寘鏁伴噺: {splitQuantity}");
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error($"鎷嗗寘鍚庡垎閰嶆暟閲忎笉鑳戒负璐熸暟");
+            }
+
+            // 閲嶈淇锛氶獙璇佽鍗曟槑缁嗙殑鍒嗛厤鏁伴噺鏄惁瓒冲
+            // 娉ㄦ剰锛氭墜鍔ㄦ媶鍖呬笉浼氭敼鍙樿鍗曟槑缁嗙殑鍒嗛厤鏁伴噺锛屽洜涓烘�诲垎閰嶆暟閲忎笉鍙�
+            // 鍙槸浠庝竴涓攣瀹氫俊鎭浆绉诲埌鍙︿竴涓攣瀹氫俊鎭�
+            decimal totalLockAssignQuantity = await GetTotalLockAssignQuantity(orderDetail.Id);
+            if (orderDetail.AllocatedQuantity != totalLockAssignQuantity)
+            {
+                _logger.LogWarning($"璁㈠崟鏄庣粏鍒嗛厤鏁伴噺涓庨攣瀹氫俊鎭笉涓�鑷� - 璁㈠崟鏄庣粏鍒嗛厤鏁伴噺: {orderDetail.AllocatedQuantity}, 閿佸畾淇℃伅鎬诲垎閰嶆暟閲�: {totalLockAssignQuantity}");
+                // 杩欓噷涓嶇洿鎺ヨ繑鍥為敊璇紝鍥犱负鎷嗗寘鎿嶄綔鏈韩涓嶄細瀵艰嚧涓嶄竴鑷达紝鍙槸璁板綍璀﹀憡
+            }
+
+            _logger.LogInformation($"鎷嗗寘楠岃瘉閫氳繃 - 鍘熸潯鐮�: {originalBarcode}, 鎷嗗寘鏁伴噺: {splitQuantity}");
+
+            return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Success((lockInfo, stockDetail));
+        }
+
+        /// <summary>
+        /// 鑾峰彇璁㈠崟鏄庣粏鐨勬墍鏈夐攣瀹氫俊鎭殑鎬诲垎閰嶆暟閲�
+        /// </summary>
+        private async Task<decimal> GetTotalLockAssignQuantity(long orderDetailId)
+        {
+            var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .Where(x => x.OrderDetailId == orderDetailId)
+                .ToListAsync();
+
+            return lockInfos.Sum(x => x.AssignQuantity);
+        }
+
+        /// <summary>
+        /// 鎵ц鎵嬪姩鎷嗗寘閫昏緫 - 澧炲己鍒嗛厤鏁伴噺鎺у埗
+        /// </summary>
+        private async Task<SplitResultDto> ExecuteManualSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
+            decimal splitQuantity, string palletCode)
+        {
+            _logger.LogInformation($"寮�濮嬫墽琛屾墜鍔ㄦ媶鍖呴�昏緫 - 鍘熸潯鐮�: {stockDetail.Barcode}, 鎷嗗寘鏁伴噺: {splitQuantity}");
+
+            // 閲嶈淇锛氳幏鍙栬鍗曟槑缁嗗苟楠岃瘉鍒嗛厤鏁伴噺
+            var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
+                .FirstAsync(x => x.Id == lockInfo.OrderDetailId);
+
+            if (orderDetail == null)
+                throw new InvalidOperationException("鏈壘鍒拌鍗曟槑缁�");
+
+            // 楠岃瘉鎷嗗寘鏁伴噺涓嶄細瀵艰嚧鍒嗛厤鏁伴噺涓鸿礋鏁�
+            if (lockInfo.AssignQuantity < splitQuantity)
+            {
+                throw new InvalidOperationException($"鎷嗗寘鏁伴噺瓒呰繃閿佸畾淇℃伅鍒嗛厤鏁伴噺锛屾媶鍖呮暟閲�: {splitQuantity}, 鍒嗛厤鏁伴噺: {lockInfo.AssignQuantity}");
+            }
+
+            // 鐢熸垚鏂版潯鐮�
+            string newBarcode = await GenerateNewBarcode();
+
+            // 璁板綍鎷嗗寘鍓嶇殑鍒嗛厤鏁伴噺
+            decimal originalAssignQtyBefore = lockInfo.AssignQuantity;
+            decimal originalOrderQtyBefore = lockInfo.OrderQuantity;
+
+            // 1. 鍒涘缓鏂板簱瀛樻槑缁�
+            var newStockDetail = new Dt_StockInfoDetail
+            {
+                StockId = stockDetail.StockId,
+                MaterielCode = stockDetail.MaterielCode,
+                OrderNo = stockDetail.OrderNo,
+                BatchNo = stockDetail.BatchNo,
+                StockQuantity = splitQuantity,
+                OutboundQuantity = 0,
+                Barcode = newBarcode,
+                Status = (int)StockStatusEmun.鍑哄簱閿佸畾,
+                SupplyCode = stockDetail.SupplyCode,
+                Unit = stockDetail.Unit,
+                BarcodeQty = stockDetail.BarcodeQty,
+                BarcodeUnit = stockDetail.BarcodeUnit,
+                BusinessType = stockDetail.BusinessType,
+                InboundOrderRowNo = stockDetail.InboundOrderRowNo, 
+            };
+            await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync();
+            _logger.LogInformation($"鍒涘缓鏂板簱瀛樻槑缁� - 鏉$爜: {newBarcode}, 搴撳瓨鏁伴噺: {splitQuantity}");
+
+            // 2. 鏇存柊鍘熷簱瀛樻槑缁�
+            decimal originalStockQtyBefore = stockDetail.StockQuantity;
+            stockDetail.StockQuantity -= splitQuantity;
+            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+            _logger.LogInformation($"鏇存柊鍘熷簱瀛樻槑缁� - 搴撳瓨鏁伴噺浠� {originalStockQtyBefore} 鍑忓皯鍒� {stockDetail.StockQuantity}");
+
+            // 3. 鍒涘缓鏂伴攣瀹氫俊鎭�
+            var newLockInfo = new Dt_OutStockLockInfo
+            {
+                OrderNo = lockInfo.OrderNo,
+                OrderDetailId = lockInfo.OrderDetailId,
+                OutboundBatchNo = lockInfo.OutboundBatchNo,
+                MaterielCode = lockInfo.MaterielCode,
+                MaterielName = lockInfo.MaterielName,
+                StockId = lockInfo.StockId,
+                OrderQuantity = splitQuantity,
+                AssignQuantity = splitQuantity,
+                PickedQty = 0,
+                LocationCode = lockInfo.LocationCode,
+                PalletCode = lockInfo.PalletCode,
+                TaskNum = lockInfo.TaskNum,
+                Status = (int)OutLockStockStatusEnum.鍑哄簱涓�,
+                Unit = lockInfo.Unit,
+                SupplyCode = lockInfo.SupplyCode,
+                OrderType = lockInfo.OrderType,
+                CurrentBarcode = newBarcode,
+                IsSplitted = 1,
+                ParentLockId = lockInfo.Id,
+                Operator = App.User.UserName,
+                FactoryArea = lockInfo.FactoryArea,
+                lineNo = lockInfo.lineNo,
+                WarehouseCode = lockInfo.WarehouseCode,
+                BarcodeQty = lockInfo.BarcodeQty,
+                BarcodeUnit = lockInfo.BarcodeUnit, 
+            };
+
+            await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync();
+            _logger.LogInformation($"鍒涘缓鏂伴攣瀹氫俊鎭� - 鏉$爜: {newBarcode}, 鍒嗛厤鏁伴噺: {splitQuantity}");
+
+            // 4. 鏇存柊鍘熼攣瀹氫俊鎭�
+            lockInfo.AssignQuantity -= splitQuantity;
+            lockInfo.OrderQuantity -= splitQuantity;
+
+            _logger.LogInformation($"鏇存柊鍘熼攣瀹氫俊鎭� - 鍒嗛厤鏁伴噺浠� {originalAssignQtyBefore} 鍑忓皯鍒� {lockInfo.AssignQuantity}");
+            _logger.LogInformation($"鏇存柊鍘熼攣瀹氫俊鎭� - 璁㈠崟鏁伴噺浠� {originalOrderQtyBefore} 鍑忓皯鍒� {lockInfo.OrderQuantity}");
+
+            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
+
+            // 閲嶈淇锛氭墜鍔ㄦ媶鍖呬笉浼氭敼鍙樿鍗曟槑缁嗙殑鍒嗛厤鏁伴噺锛屽洜涓烘�诲垎閰嶆暟閲忎笉鍙�
+            // 鍙槸浠庝竴涓攣瀹氫俊鎭浆绉诲埌鍙︿竴涓攣瀹氫俊鎭�
+            _logger.LogInformation($"璁㈠崟鏄庣粏鍒嗛厤鏁伴噺淇濇寔涓嶅彉 - 宸插垎閰嶆暟閲�: {orderDetail.AllocatedQuantity}");
+
+            // 5. 璁板綍鎷嗗寘鍘嗗彶
+            await RecordSplitHistory(lockInfo, stockDetail, splitQuantity, newBarcode, false);
+
+            _logger.LogInformation($"鎵嬪姩鎷嗗寘閫昏緫鎵ц瀹屾垚");
+
+            return new SplitResultDto { NewBarcode = newBarcode };
+        }
+
         #endregion
 
- 
+        #endregion
+
+
 
         #region 鍙栨秷鎷嗗寘 
 
@@ -588,15 +842,24 @@
             Dt_OutStockLockInfo originalLockInfo, Dt_OutStockLockInfo newLockInfo,
             Dt_StockInfoDetail newStockDetail)
         {
-            // 1. 鎭㈠鍘熼攣瀹氫俊鎭�
-            // 娉ㄦ剰锛氳繖閲岄渶瑕佺疮鍔狅紝鑰屼笉鏄畝鍗曠殑璧嬪�硷紝鍥犱负鍙兘鏈夊娆℃媶鍖�
+            _logger.LogInformation($"寮�濮嬫墽琛屽彇娑堟媶鍖呴�昏緫 - 鍘熸潯鐮�: {splitRecord.OriginalBarcode}, 鏂版潯鐮�: {splitRecord.NewBarcode}, 鎷嗗寘鏁伴噺: {splitRecord.SplitQty}");
+
+            // 鎭㈠鍘熼攣瀹氫俊鎭�
+            decimal originalAssignQtyBefore = originalLockInfo.AssignQuantity;
+            decimal originalOrderQtyBefore = originalLockInfo.OrderQuantity;
+
+            // 閲嶈淇锛氭仮澶嶅垎閰嶆暟閲忓拰璁㈠崟鏁伴噺
             originalLockInfo.AssignQuantity += splitRecord.SplitQty;
             originalLockInfo.OrderQuantity += splitRecord.SplitQty;
+
+            _logger.LogInformation($"鎭㈠鍘熼攣瀹氫俊鎭� - 鍒嗛厤鏁伴噺浠� {originalAssignQtyBefore} 澧炲姞鍒� {originalLockInfo.AssignQuantity}");
+            _logger.LogInformation($"鎭㈠鍘熼攣瀹氫俊鎭� - 璁㈠崟鏁伴噺浠� {originalOrderQtyBefore} 澧炲姞鍒� {originalLockInfo.OrderQuantity}");
 
             // 濡傛灉鍘熼攣瀹氫俊鎭殑鐘舵�佹槸鎷i�夊畬鎴愶紝闇�瑕侀噸鏂拌缃负鍑哄簱涓�
             if (originalLockInfo.Status == (int)OutLockStockStatusEnum.鎷i�夊畬鎴�)
             {
                 originalLockInfo.Status = (int)OutLockStockStatusEnum.鍑哄簱涓�;
+                _logger.LogInformation($"鍘熼攣瀹氫俊鎭姸鎬佷粠鎷i�夊畬鎴愭仮澶嶄负鍑哄簱涓�");
             }
 
             await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync();
@@ -605,35 +868,47 @@
             var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                 .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == splitRecord.StockId);
 
-            originalStock.StockQuantity += splitRecord.SplitQty;
-
-            // 濡傛灉鍘熷簱瀛樼姸鎬佹槸鍑哄簱瀹屾垚锛岄渶瑕侀噸鏂拌缃负鍑哄簱閿佸畾
-            if (originalStock.Status == (int)StockStatusEmun.鍑哄簱瀹屾垚)
+            if (originalStock != null)
             {
-                originalStock.Status = (int)StockStatusEmun.鍑哄簱閿佸畾;
+                decimal originalStockQtyBefore = originalStock.StockQuantity;
+                originalStock.StockQuantity += splitRecord.SplitQty;
+
+                _logger.LogInformation($"鎭㈠鍘熷簱瀛樻槑缁� - 搴撳瓨鏁伴噺浠� {originalStockQtyBefore} 澧炲姞鍒� {originalStock.StockQuantity}");
+
+                // 濡傛灉鍘熷簱瀛樼姸鎬佹槸鍑哄簱瀹屾垚锛岄渶瑕侀噸鏂拌缃负鍑哄簱閿佸畾
+                if (originalStock.Status == (int)StockStatusEmun.鍑哄簱瀹屾垚)
+                {
+                    originalStock.Status = (int)StockStatusEmun.鍑哄簱閿佸畾;
+                    _logger.LogInformation($"鍘熷簱瀛樼姸鎬佷粠鍑哄簱瀹屾垚鎭㈠涓哄嚭搴撻攣瀹�");
+                }
+
+                await _stockInfoDetailService.Db.Updateable(originalStock).ExecuteCommandAsync();
             }
 
-            await _stockInfoDetailService.Db.Updateable(originalStock).ExecuteCommandAsync();
-
             // 鍒犻櫎鏂伴攣瀹氫俊鎭�
+            _logger.LogInformation($"鍒犻櫎鏂伴攣瀹氫俊鎭� - 鏉$爜: {newLockInfo.CurrentBarcode}, 鍒嗛厤鏁伴噺: {newLockInfo.AssignQuantity}");
             await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
                 .Where(x => x.Id == newLockInfo.Id)
                 .ExecuteCommandAsync();
 
-            // 鍒犻櫎鏂板簱瀛樻槑缁�
+            //  鍒犻櫎鏂板簱瀛樻槑缁�
+            _logger.LogInformation($"鍒犻櫎鏂板簱瀛樻槑缁� - 鏉$爜: {newStockDetail.Barcode}, 搴撳瓨鏁伴噺: {newStockDetail.StockQuantity}");
             await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>()
                 .Where(x => x.Barcode == newLockInfo.CurrentBarcode)
                 .ExecuteCommandAsync();
 
-            //鏍囪鎷嗗寘璁板綍涓哄凡鎾ら攢
+            // 鏍囪鎷嗗寘璁板綍涓哄凡鎾ら攢
             splitRecord.IsReverted = true;
             splitRecord.RevertTime = DateTime.Now;
             splitRecord.RevertOperator = App.User.UserName;
             await _splitPackageService.Db.Updateable(splitRecord).ExecuteCommandAsync();
+            _logger.LogInformation($"鏍囪鎷嗗寘璁板綍涓哄凡鎾ら攢");
 
             // 妫�鏌ュ苟鏇存柊鎵规鍜岃鍗曠姸鎬�
             await CheckAndUpdateBatchStatus(originalLockInfo.BatchNo);
             await CheckAndUpdateOrderStatus(originalLockInfo.OrderNo);
+
+            _logger.LogInformation($"鍙栨秷鎷嗗寘閫昏緫鎵ц瀹屾垚");
         }
 
         /// <summary>
@@ -642,6 +917,8 @@
         private async Task<ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>> ValidateCancelSplitRequest(
             string orderNo, string palletCode, string newBarcode)
         {
+            _logger.LogInformation($"寮�濮嬮獙璇佸彇娑堟媶鍖呰姹� - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}, 鏉$爜: {newBarcode}");
+
             // 鏌ユ壘鎷嗗寘璁板綍
             var splitRecord = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
                 .Where(x => x.NewBarcode == newBarcode &&
@@ -651,6 +928,8 @@
 
             if (splitRecord == null)
                 return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鏈壘鍒版媶鍖呰褰�");
+
+            _logger.LogInformation($"鎵惧埌鎷嗗寘璁板綍 - 鍘熸潯鐮�: {splitRecord.OriginalBarcode}, 鏂版潯鐮�: {splitRecord.NewBarcode}, 鎷嗗寘鏁伴噺: {splitRecord.SplitQty}");
 
             // 鏌ユ壘鏂伴攣瀹氫俊鎭�
             var newLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
@@ -662,13 +941,35 @@
             if (newLockInfo == null)
                 return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鏈壘鍒版柊閿佸畾淇℃伅");
 
-            // 妫�鏌ユ柊鏉$爜鏄惁宸茶鍒嗘嫞
-            var pickingRecord = await Db.Queryable<Dt_PickingRecord>()
-                .Where(x => x.Barcode == newBarcode && !x.IsCancelled)
-                .FirstAsync();
+            _logger.LogInformation($"鎵惧埌鏂伴攣瀹氫俊鎭� - 鐘舵��: {newLockInfo.Status}, 宸叉嫞閫�: {newLockInfo.PickedQty}, 鍒嗛厤鏁伴噺: {newLockInfo.AssignQuantity}");
 
-            if (pickingRecord != null)
-                return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("璇ユ潯鐮佸凡琚垎鎷o紝鏃犳硶鍙栨秷鎷嗗寘");
+            // 閲嶈淇锛氭鏌ユ柊鏉$爜鏄惁宸茶鍒嗘嫞
+            var newBarcodePickingRecords = await Db.Queryable<Dt_PickingRecord>()
+                .Where(x => x.Barcode == newBarcode && x.OrderNo == orderNo && !x.IsCancelled)
+                .ToListAsync();
+
+            if (newBarcodePickingRecords.Any())
+            {
+                var totalPickedQty = newBarcodePickingRecords.Sum(x => x.PickQuantity);
+                _logger.LogWarning($"鏂版潯鐮� {newBarcode} 宸茶鍒嗘嫞锛屾�绘嫞閫夋暟閲�: {totalPickedQty}");
+                return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error(
+                    $"鏂版潯鐮佸凡琚垎鎷o紙宸叉嫞閫夋暟閲忥細{totalPickedQty}锛夛紝璇峰厛鍙栨秷鍒嗘嫞锛岀劧鍚庡啀鍙栨秷鎷嗗寘");
+            }
+
+            // 閲嶈淇锛氭鏌ュ師鏉$爜鏄惁宸茶鍒嗘嫞
+            var originalBarcodePickingRecords = await Db.Queryable<Dt_PickingRecord>()
+                .Where(x => x.Barcode == splitRecord.OriginalBarcode && x.OrderNo == orderNo && !x.IsCancelled)
+                .ToListAsync();
+
+            if (originalBarcodePickingRecords.Any())
+            {
+                var totalPickedQty = originalBarcodePickingRecords.Sum(x => x.PickQuantity);
+                _logger.LogWarning($"鍘熸潯鐮� {splitRecord.OriginalBarcode} 宸茶鍒嗘嫞锛屾�绘嫞閫夋暟閲�: {totalPickedQty}");
+                return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error(
+                    $"鍘熸潯鐮佸凡琚垎鎷o紙宸叉嫞閫夋暟閲忥細{totalPickedQty}锛夛紝璇峰厛鍙栨秷鍒嗘嫞锛岀劧鍚庡啀鍙栨秷鎷嗗寘");
+            }
+
+            _logger.LogInformation($"鏂版棫鏉$爜鍧囨湭琚垎鎷o紝鍙互鍙栨秷鎷嗗寘");
 
             // 妫�鏌ユ柊鏉$爜鏄惁琚啀娆℃媶鍖�
             var childSplitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
@@ -678,12 +979,18 @@
             if (childSplitRecords.Any())
             {
                 var childBarcodes = string.Join(", ", childSplitRecords.Select(x => x.NewBarcode));
+                _logger.LogWarning($"鏉$爜 {newBarcode} 宸茶鍐嶆鎷嗗寘锛岀敓鎴愮殑鏂版潯鐮�: {childBarcodes}");
                 return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error(
                     $"璇ユ潯鐮佸凡琚啀娆℃媶鍖咃紝鐢熸垚鐨勬柊鏉$爜锛歿childBarcodes}锛岃鍏堝彇娑堝悗缁媶鍖�");
             }
 
             var newStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                 .FirstAsync(x => x.Barcode == newBarcode);
+
+            if (newStockDetail == null)
+                return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鏈壘鍒版柊搴撳瓨鏄庣粏");
+
+            _logger.LogInformation($"鍙栨秷鎷嗗寘楠岃瘉閫氳繃 - 鏉$爜: {newBarcode}");
 
             return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Success((splitRecord, newLockInfo, newStockDetail));
         }
@@ -707,11 +1014,28 @@
                 if (!splitChain.Any())
                     return WebResponseContent.Instance.Error("鏈壘鍒版媶鍖呰褰�");
 
-                // 2. 鎸夋媶鍖呴『搴忓�掑簭鍙栨秷锛堜粠鏈�鏂扮殑寮�濮嬪彇娑堬級
+                _logger.LogInformation($"鎵惧埌鎷嗗寘閾撅紝鍏� {splitChain.Count} 鏉¤褰�");
+
+                // 2. 鏀堕泦鎷嗗寘閾句腑娑夊強鐨勬墍鏈夋潯鐮侊紙鍖呮嫭鍘熸潯鐮佸拰鏂版潯鐮侊級
+                var allBarcodesInChain = new List<string> { startBarcode };
+                allBarcodesInChain.AddRange(splitChain.Select(x => x.NewBarcode));
+
+                // 3. 妫�鏌ユ媶鍖呴摼涓槸鍚︽湁宸茶鍒嗘嫞鐨勬潯鐮�
+                var pickedBarcodesInfo = await GetPickedBarcodesInfo(orderNo, allBarcodesInChain);
+
+                if (pickedBarcodesInfo.Any())
+                {
+                    var pickedBarcodes = string.Join(", ", pickedBarcodesInfo.Select(x => $"{x.Barcode}(宸叉嫞閫墈x.PickedQty})"));
+                    return WebResponseContent.Instance.Error(
+                        $"浠ヤ笅鏉$爜宸茶鍒嗘嫞锛岃鍏堝彇娑堝垎鎷o細{pickedBarcodes}");
+                }
+
+                // 4. 鎸夋媶鍖呴『搴忓�掑簭鍙栨秷锛堜粠鏈�鏂扮殑寮�濮嬪彇娑堬級
                 var reversedChain = splitChain.OrderByDescending(x => x.SplitTime).ToList();
 
                 foreach (var splitRecord in reversedChain)
                 {
+                    _logger.LogInformation($"鍙栨秷鎷嗗寘璁板綍 - 鍘熸潯鐮�: {splitRecord.OriginalBarcode}, 鏂版潯鐮�: {splitRecord.NewBarcode}");
                     await CancelSingleSplitPackage(splitRecord, palletCode);
                 }
 
@@ -727,6 +1051,133 @@
             }
         }
 
+        /// <summary>
+        /// 鑾峰彇鏉$爜鐨勬媶鍖呭拰鎷i�夌姸鎬�
+        /// </summary>
+        public async Task<WebResponseContent> GetBarcodeSplitAndPickStatus(string orderNo, string barcode)
+        {
+            try
+            {
+                // 1. 鑾峰彇鎷嗗寘淇℃伅
+                var splitChain = await GetSplitPackageChain(orderNo, barcode);
+                var isOriginalBarcode = !splitChain.Any(x => x.NewBarcode == barcode);
+
+                // 2. 鑾峰彇鎷i�変俊鎭�
+                var pickingRecords = await Db.Queryable<Dt_PickingRecord>()
+                    .Where(x => x.Barcode == barcode && x.OrderNo == orderNo && !x.IsCancelled)
+                    .ToListAsync();
+
+                var totalPickedQty = pickingRecords.Sum(x => x.PickQuantity);
+
+                // 3. 鑾峰彇閿佸畾淇℃伅
+                var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                    .Where(x => x.CurrentBarcode == barcode && x.OrderNo == orderNo)
+                    .FirstAsync();
+
+                // 4. 鑾峰彇搴撳瓨淇℃伅
+                var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                    .Where(x => x.Barcode == barcode)
+                    .FirstAsync();
+
+                var statusInfo = new BarcodeStatusInfoDto
+                {
+                    Barcode = barcode,
+                    OrderNo = orderNo,
+                    IsOriginalBarcode = isOriginalBarcode,
+                    SplitChainCount = splitChain.Count,
+                    HasBeenPicked = pickingRecords.Any(),
+                    TotalPickedQuantity = totalPickedQty,
+                    PickRecordCount = pickingRecords.Count,
+                    LockInfoStatus = lockInfo?.Status ?? 0,
+                    LockInfoPickedQty = lockInfo?.PickedQty ?? 0,
+                    LockInfoAssignQty = lockInfo?.AssignQuantity ?? 0,
+                    StockQuantity = stockDetail?.StockQuantity ?? 0,
+                    StockStatus = stockDetail?.Status ?? 0,
+                    CanCancelSplit = !pickingRecords.Any(), // 鏈鍒嗘嫞鎵嶈兘鍙栨秷鎷嗗寘
+                    NeedCancelPickFirst = pickingRecords.Any() // 闇�瑕佸厛鍙栨秷鍒嗘嫞
+                };
+
+                // 5. 鑾峰彇鎿嶄綔寤鸿
+                statusInfo.OperationSuggestions = GetOperationSuggestions(statusInfo);
+
+                return WebResponseContent.Instance.OK("鑾峰彇鐘舵�佹垚鍔�", statusInfo);
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError($"鑾峰彇鏉$爜鐘舵�佸け璐� - OrderNo: {orderNo}, Barcode: {barcode}, Error: {ex.Message}");
+                return WebResponseContent.Instance.Error("鑾峰彇鏉$爜鐘舵�佸け璐�");
+            }
+        }
+         /// <summary>
+        /// 鑾峰彇鎿嶄綔寤鸿
+        /// </summary>
+        private List<string> GetOperationSuggestions(BarcodeStatusInfoDto statusInfo)
+        {
+            var suggestions = new List<string>();
+
+            if (statusInfo.HasBeenPicked)
+            {
+                suggestions.Add($"璇ユ潯鐮佸凡琚垎鎷o紙鏁伴噺锛歿statusInfo.TotalPickedQuantity}锛夛紝濡傞渶鍙栨秷鎷嗗寘锛岃鍏堝彇娑堝垎鎷�");
+
+                if (statusInfo.IsOriginalBarcode)
+                {
+                    suggestions.Add("杩欐槸鍘熸潯鐮侊紝鍙栨秷鍒嗘嫞鍚庡皢鎭㈠涓哄彲鍒嗘嫞鐘舵��");
+                }
+                else
+                {
+                    suggestions.Add("杩欐槸鎷嗗寘鐢熸垚鐨勬柊鏉$爜锛屽彇娑堝垎鎷e悗鎵嶈兘鍙栨秷鎷嗗寘");
+                }
+            }
+            else
+            {
+                if (statusInfo.IsOriginalBarcode && statusInfo.SplitChainCount > 0)
+                {
+                    suggestions.Add("杩欐槸鍘熸潯鐮侊紝鍙互鍙栨秷鎷嗗寘閾�");
+                }
+                else if (!statusInfo.IsOriginalBarcode)
+                {
+                    suggestions.Add("杩欐槸鎷嗗寘鐢熸垚鐨勬柊鏉$爜锛屽彲浠ュ崟鐙彇娑堟媶鍖�");
+                }
+            }
+
+            if (statusInfo.LockInfoStatus == (int)OutLockStockStatusEnum.鎷i�夊畬鎴�)
+            {
+                suggestions.Add("閿佸畾鐘舵�侊細鎷i�夊畬鎴�");
+            }
+            else if (statusInfo.LockInfoStatus == (int)OutLockStockStatusEnum.鍑哄簱涓�)
+            {
+                suggestions.Add("閿佸畾鐘舵�侊細鍑哄簱涓�");
+            }
+
+            return suggestions;
+        }
+        /// <summary>
+        /// 鑾峰彇宸茶鍒嗘嫞鐨勬潯鐮佷俊鎭�
+        /// </summary>
+        private async Task<List<PickedBarcodeInfo>> GetPickedBarcodesInfo(string orderNo, List<string> barcodes)
+        {
+            var pickedBarcodes = new List<PickedBarcodeInfo>();
+
+            foreach (var barcode in barcodes)
+            {
+                var pickingRecords = await Db.Queryable<Dt_PickingRecord>()
+                    .Where(x => x.Barcode == barcode && x.OrderNo == orderNo && !x.IsCancelled)
+                    .ToListAsync();
+
+                if (pickingRecords.Any())
+                {
+                    var totalPickedQty = pickingRecords.Sum(x => x.PickQuantity);
+                    pickedBarcodes.Add(new PickedBarcodeInfo
+                    {
+                        Barcode = barcode,
+                        PickedQty = totalPickedQty,
+                        PickRecordCount = pickingRecords.Count
+                    });
+                }
+            }
+
+            return pickedBarcodes;
+        }
         /// <summary>
         /// 鑾峰彇鎷嗗寘閾� - 鏌ユ壘鏌愪釜鏉$爜鐨勬墍鏈夋媶鍖呰褰曪紙鍖呮嫭鍚庣画鎷嗗寘锛�
         /// </summary>
@@ -771,6 +1222,27 @@
         /// </summary>
         private async Task CancelSingleSplitPackage(Dt_SplitPackageRecord splitRecord, string palletCode)
         {
+            _logger.LogInformation($"寮�濮嬪彇娑堝崟涓媶鍖呰褰� - 鍘熸潯鐮�: {splitRecord.OriginalBarcode}, 鏂版潯鐮�: {splitRecord.NewBarcode}");
+
+            // 鍐嶆楠岃瘉鍒嗘嫞鐘舵�侊紙闃叉骞跺彂鎿嶄綔锛�
+            var newBarcodePickingRecords = await Db.Queryable<Dt_PickingRecord>()
+                .Where(x => x.Barcode == splitRecord.NewBarcode && !x.IsCancelled)
+                .ToListAsync();
+
+            if (newBarcodePickingRecords.Any())
+            {
+                throw new InvalidOperationException($"鏂版潯鐮� {splitRecord.NewBarcode} 鍦ㄩ獙璇佸悗琚垎鎷o紝鏃犳硶鍙栨秷鎷嗗寘");
+            }
+
+            var originalBarcodePickingRecords = await Db.Queryable<Dt_PickingRecord>()
+                .Where(x => x.Barcode == splitRecord.OriginalBarcode && !x.IsCancelled)
+                .ToListAsync();
+
+            if (originalBarcodePickingRecords.Any())
+            {
+                throw new InvalidOperationException($"鍘熸潯鐮� {splitRecord.OriginalBarcode} 鍦ㄩ獙璇佸悗琚垎鎷o紝鏃犳硶鍙栨秷鎷嗗寘");
+            }
+
             // 鏌ユ壘鐩稿叧鏁版嵁
             var newLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                 .Where(x => x.CurrentBarcode == splitRecord.NewBarcode &&
@@ -785,6 +1257,8 @@
 
             // 鎵ц鍙栨秷閫昏緫
             await ExecuteCancelSplitLogic(splitRecord, originalLockInfo, newLockInfo, newStockDetail);
+
+            _logger.LogInformation($"鍙栨秷鍗曚釜鎷嗗寘璁板綍瀹屾垚 - 鍘熸潯鐮�: {splitRecord.OriginalBarcode}, 鏂版潯鐮�: {splitRecord.NewBarcode}");
         }
         #endregion
 
@@ -810,7 +1284,8 @@
                         NewBarcode = x.NewBarcode,
                         SplitQuantity = x.SplitQty,
                         Operator = x.Operator,
-                        IsReverted = x.IsReverted
+                        IsReverted = x.IsReverted ,
+                        IsAutoSplit = x.IsAutoSplit
                     }).ToList()
                 };
 
@@ -899,9 +1374,7 @@
 
         #endregion
 
-
-
-
+       
         #region 鍒嗘壒鍥炲簱
 
         /// <summary>
@@ -961,6 +1434,8 @@
         private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>> ValidatePickingRequest(
        string orderNo, string palletCode, string barcode)
         {
+            _logger.LogInformation($"寮�濮嬮獙璇佸垎鎷h姹� - 璁㈠崟: {orderNo}, 鎵樼洏: {palletCode}, 鏉$爜: {barcode}");
+
             // 鏌ユ壘閿佸畾淇℃伅
             var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                 .Where(x => x.OrderNo == orderNo &&
@@ -972,6 +1447,8 @@
             if (lockInfo == null)
                 return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error("鏈壘鍒版湁鏁堢殑閿佸畾淇℃伅");
 
+            _logger.LogInformation($"鎵惧埌閿佸畾淇℃伅 - 鍒嗛厤鏁伴噺: {lockInfo.AssignQuantity}, 宸叉嫞閫�: {lockInfo.PickedQty}");
+
             // 妫�鏌ユ槸鍚﹀凡缁忓垎鎷e畬鎴�
             if (lockInfo.PickedQty >= lockInfo.AssignQuantity)
                 return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error("璇ユ潯鐮佸凡鍒嗘嫞瀹屾垚");
@@ -980,132 +1457,106 @@
             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, Dt_OutboundBatch)>.Error("鏈壘鍒拌鍗曟槑缁�");
+
+            _logger.LogInformation($"鎵惧埌璁㈠崟鏄庣粏 - 宸插垎閰嶆暟閲�: {orderDetail.AllocatedQuantity}, 閿佸畾鏁伴噺: {orderDetail.LockQuantity}");
+
+            // 閲嶈淇锛氭鏌ヨ鍗曟槑缁嗙殑宸插垎閰嶆暟閲忔槸鍚﹁冻澶�
+            decimal remainingToPick = lockInfo.AssignQuantity - lockInfo.PickedQty;
+            if (orderDetail.AllocatedQuantity < remainingToPick)
+            {
+                _logger.LogWarning($"璁㈠崟鏄庣粏宸插垎閰嶆暟閲忎笉瓒� - 闇�瑕佹嫞閫�: {remainingToPick}, 鍙敤鍒嗛厤鏁伴噺: {orderDetail.AllocatedQuantity}");
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error(
+                    $"璁㈠崟鏄庣粏鍒嗛厤鏁伴噺涓嶈冻锛岄渶瑕佹嫞閫夛細{remainingToPick}锛屽彲鐢ㄥ垎閰嶆暟閲忥細{orderDetail.AllocatedQuantity}");
+            }
+
+            // 閲嶈淇锛氭鏌ラ攣瀹氭暟閲忔槸鍚﹁冻澶�
+            if (orderDetail.LockQuantity < remainingToPick)
+            {
+                _logger.LogWarning($"璁㈠崟鏄庣粏閿佸畾鏁伴噺涓嶈冻 - 闇�瑕佹嫞閫�: {remainingToPick}, 鍙敤閿佸畾鏁伴噺: {orderDetail.LockQuantity}");
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error(
+                    $"璁㈠崟鏄庣粏閿佸畾鏁伴噺涓嶈冻锛岄渶瑕佹嫞閫夛細{remainingToPick}锛屽彲鐢ㄩ攣瀹氭暟閲忥細{orderDetail.LockQuantity}");
+            }
+
             var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                 .FirstAsync(x => x.Barcode == barcode && x.StockId == lockInfo.StockId);
 
+            if (stockDetail == null)
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error("鏈壘鍒板搴旂殑搴撳瓨淇℃伅");
+
             // 楠岃瘉搴撳瓨鏁伴噺
-            if (stockDetail.StockQuantity < lockInfo.AssignQuantity)
+            if (stockDetail.StockQuantity < remainingToPick)
                 return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error(
-                    $"搴撳瓨鏁伴噺涓嶈冻锛岄渶瑕侊細{lockInfo.AssignQuantity}锛屽疄闄咃細{stockDetail.StockQuantity}");
+                    $"搴撳瓨鏁伴噺涓嶈冻锛岄渶瑕佹嫞閫夛細{remainingToPick}锛屽疄闄呭簱瀛橈細{stockDetail.StockQuantity}");
+
+            // 楠岃瘉搴撳瓨鐘舵��
+            if (stockDetail.Status != (int)StockStatusEmun.鍑哄簱閿佸畾)
+            {
+                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error(
+                    $"搴撳瓨鐘舵�佸紓甯革紝褰撳墠鐘舵�侊細{stockDetail.Status}锛屾湡鏈涚姸鎬侊細鍑哄簱閿佸畾");
+            }
 
             // 浣跨敤 OutboundBatchNo 鏌ユ壘鎵规
             var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>()
-                .FirstAsync(x => x.BatchNo == lockInfo.OutboundBatchNo); // 淇涓� OutboundBatchNo
+                .FirstAsync(x => x.BatchNo == lockInfo.OutboundBatchNo);
+
+            _logger.LogInformation($"鍒嗘嫞楠岃瘉閫氳繃 - 鏉$爜: {barcode}, 鍓╀綑闇�鎷i��: {remainingToPick}, 鍙敤搴撳瓨: {stockDetail.StockQuantity}");
 
             return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Success((lockInfo, orderDetail, stockDetail, batch));
         }
-        private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>> ValidateSplitRequest(
-            string orderNo, string palletCode, string originalBarcode, decimal splitQuantity)
+
+
+        /// <summary>
+        /// 妫�鏌ュ苟鎵ц鑷姩鎷嗗寘锛堝鏋滈渶瑕侊級
+        /// </summary>
+        private async Task<AutoSplitResult> CheckAndAutoSplitIfNeeded(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, string palletCode)
         {
-            var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                .Where(x => x.OrderNo == orderNo &&
-                           x.PalletCode == palletCode &&
-                           x.CurrentBarcode == originalBarcode &&
-                           x.Status == (int)OutLockStockStatusEnum.鍑哄簱涓�)
-                .FirstAsync();
+            // 妫�鏌ユ槸鍚﹂渶瑕佽嚜鍔ㄦ媶鍖呯殑鏉′欢锛�
+            // 1. 搴撳瓨鏁伴噺澶т簬鍒嗛厤鏁伴噺
+            // 2. 閿佸畾淇℃伅鐘舵�佷负鍑哄簱涓�
+            // 3. 鏈嫞閫夋暟閲忕瓑浜庡垎閰嶆暟閲忥紙琛ㄧず杩樻湭寮�濮嬫嫞閫夛級
+            bool needAutoSplit = stockDetail.StockQuantity > lockInfo.AssignQuantity &&
+                                lockInfo.Status == (int)OutLockStockStatusEnum.鍑哄簱涓� &&
+                                lockInfo.PickedQty == 0;
 
-            if (lockInfo == null)
-                return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鏈壘鍒版湁鏁堢殑閿佸畾淇℃伅");
+            if (!needAutoSplit)
+                return null;
 
-            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                .FirstAsync(x => x.Barcode == originalBarcode && x.StockId == lockInfo.StockId);
+            // 璁$畻鎷嗗寘鏁伴噺 = 搴撳瓨鏁伴噺 - 鍒嗛厤鏁伴噺
+            decimal splitQuantity = stockDetail.StockQuantity - lockInfo.AssignQuantity;
 
-            if (stockDetail.StockQuantity < splitQuantity)
-                return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鎷嗗寘鏁伴噺涓嶈兘澶т簬搴撳瓨鏁伴噺");
+            // 鎵ц鑷姩鎷嗗寘
+            var splitResult = await ExecuteAutoSplitLogic(lockInfo, stockDetail, splitQuantity, palletCode);
 
-            if (lockInfo.AssignQuantity - lockInfo.PickedQty < splitQuantity)
-                return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("鎷嗗寘鏁伴噺涓嶈兘澶т簬鏈嫞閫夋暟閲�");
-
-            return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Success((lockInfo, stockDetail));
-        }
- 
-        #endregion
-
-        #region 鏍稿績閫昏緫鏂规硶
-
-        private async Task<PickingResult> ExecutePickingLogic(
-            Dt_OutStockLockInfo lockInfo, Dt_OutboundOrderDetail orderDetail,
-            Dt_StockInfoDetail stockDetail, decimal actualPickedQty)
-        {
-            // 鏇存柊閿佸畾淇℃伅
-            lockInfo.PickedQty += actualPickedQty;
-            if (lockInfo.PickedQty >= lockInfo.AssignQuantity)
+            return new AutoSplitResult
             {
-                lockInfo.Status = (int)OutLockStockStatusEnum.鎷i�夊畬鎴�;
-            }
-            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
-
-            // 鏇存柊搴撳瓨
-            stockDetail.StockQuantity -= actualPickedQty;
-            stockDetail.OutboundQuantity += actualPickedQty;
-
-            if (stockDetail.StockQuantity <= 0)
-            {
-                stockDetail.Status = (int)StockStatusEmun.鍑哄簱瀹屾垚;
-            }
-            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
-
-            return new PickingResult
-            {
-                FinalLockInfo = lockInfo,
-                ActualPickedQty = actualPickedQty
+                NewBarcode = splitResult.NewBarcode,
+                SplitQuantity = splitQuantity
             };
         }
-
-        private async Task<RevertPickingResult> RevertPickingData(Dt_PickingRecord pickingRecord)
+        /// <summary>
+        /// 鎵ц鑷姩鎷嗗寘閫昏緫
+        /// </summary>
+        private async Task<SplitResultDto> ExecuteAutoSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
+            decimal splitQuantity, string palletCode)
         {
-            // 鎭㈠閿佸畾淇℃伅
-            var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                .FirstAsync(x => x.Id == pickingRecord.OutStockLockId);
+            _logger.LogInformation($"寮�濮嬫墽琛岃嚜鍔ㄦ媶鍖呴�昏緫 - 鍘熸潯鐮�: {stockDetail.Barcode}, 鎷嗗寘鏁伴噺: {splitQuantity}");
 
-            lockInfo.PickedQty -= pickingRecord.PickQuantity;
-
-            // 鏍规嵁鎷i�夋暟閲忓垽鏂姸鎬�
-            if (lockInfo.PickedQty <= 0)
-            {
-                lockInfo.Status = (int)OutLockStockStatusEnum.鍑哄簱涓�;
-            }
-            else if (lockInfo.PickedQty < lockInfo.AssignQuantity)
-            {
-                lockInfo.Status = (int)OutLockStockStatusEnum.鍑哄簱涓�;
-            }
-
-            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
-
-            // 鎭㈠搴撳瓨
-            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                .FirstAsync(x => x.Barcode == pickingRecord.Barcode);
-
-            stockDetail.StockQuantity += pickingRecord.PickQuantity;
-            stockDetail.OutboundQuantity -= pickingRecord.PickQuantity;
-
-            // 鎭㈠搴撳瓨鐘舵��
-            if (stockDetail.StockQuantity > 0)
-            {
-                stockDetail.Status = (int)StockStatusEmun.鍑哄簱閿佸畾;
-            }
-
-            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
-
-            return new RevertPickingResult
-            {
-                LockInfo = lockInfo,
-                StockDetail = stockDetail
-            };
-        }
-        private async Task<SplitResultDto> ExecuteSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
-     decimal splitQuantity, string palletCode)
-        {
             // 鐢熸垚鏂版潯鐮�
             string newBarcode = await GenerateNewBarcode();
 
-            // 鍒涘缓鏂板簱瀛樻槑缁�
+            // 閲嶈淇锛氳褰曟媶鍖呭墠鐨勫垎閰嶆暟閲�
+            decimal originalAssignQtyBefore = lockInfo.AssignQuantity;
+            decimal originalOrderQtyBefore = lockInfo.OrderQuantity;
+
+            // 1. 鍒涘缓鏂板簱瀛樻槑缁嗭紙鍓╀綑閮ㄥ垎锛�
             var newStockDetail = new Dt_StockInfoDetail
             {
                 StockId = stockDetail.StockId,
                 MaterielCode = stockDetail.MaterielCode,
                 OrderNo = stockDetail.OrderNo,
-                BatchNo = stockDetail.BatchNo, // 鐗╂枡鎵规
+                BatchNo = stockDetail.BatchNo,
                 StockQuantity = splitQuantity,
                 OutboundQuantity = 0,
                 Barcode = newBarcode,
@@ -1115,20 +1566,25 @@
                 BarcodeQty = stockDetail.BarcodeQty,
                 BarcodeUnit = stockDetail.BarcodeUnit,
                 BusinessType = stockDetail.BusinessType,
-                InboundOrderRowNo = stockDetail.InboundOrderRowNo,
+                InboundOrderRowNo = stockDetail.InboundOrderRowNo, 
             };
             await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync();
+            _logger.LogInformation($"鍒涘缓鏂板簱瀛樻槑缁� - 鏉$爜: {newBarcode}, 搴撳瓨鏁伴噺: {splitQuantity}");
 
-            // 鏇存柊鍘熷簱瀛樻槑缁�
-            stockDetail.StockQuantity -= splitQuantity;
-            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+            // 2. 鏇存柊鍘熷簱瀛樻槑缁�
+            // 閲嶈淇锛氬師搴撳瓨鏁伴噺璁剧疆涓哄垎閰嶆暟閲忥紙淇濇寔涓嶅彉锛�
+            decimal originalStockQtyBefore = stockDetail.StockQuantity;
+            // 娉ㄦ剰锛氳嚜鍔ㄦ媶鍖呮椂锛屽師搴撳瓨鏁伴噺淇濇寔涓嶅彉锛屽洜涓烘垜浠鍒嗘嫞鐨勫氨鏄垎閰嶆暟閲�
+            // stockDetail.StockQuantity 淇濇寔涓嶅彉
 
-            // 鍒涘缓鏂伴攣瀹氫俊鎭� - 浣跨敤姝g‘鐨� OutboundBatchNo
+            _logger.LogInformation($"鍘熷簱瀛樻槑缁嗕繚鎸佷笉鍙� - 搴撳瓨鏁伴噺: {stockDetail.StockQuantity}");
+
+            // 3. 鍒涘缓鏂伴攣瀹氫俊鎭紙鍓╀綑閮ㄥ垎锛�
             var newLockInfo = new Dt_OutStockLockInfo
             {
                 OrderNo = lockInfo.OrderNo,
                 OrderDetailId = lockInfo.OrderDetailId,
-                OutboundBatchNo = lockInfo.OutboundBatchNo, // 浣跨敤 OutboundBatchNo
+                OutboundBatchNo = lockInfo.OutboundBatchNo,
                 MaterielCode = lockInfo.MaterielCode,
                 MaterielName = lockInfo.MaterielName,
                 StockId = lockInfo.StockId,
@@ -1150,111 +1606,310 @@
                 lineNo = lockInfo.lineNo,
                 WarehouseCode = lockInfo.WarehouseCode,
                 BarcodeQty = lockInfo.BarcodeQty,
-                BarcodeUnit = lockInfo.BarcodeUnit,
+                BarcodeUnit = lockInfo.BarcodeUnit, 
             };
 
             await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync();
+            _logger.LogInformation($"鍒涘缓鏂伴攣瀹氫俊鎭� - 鏉$爜: {newBarcode}, 鍒嗛厤鏁伴噺: {splitQuantity}");
 
-            // 鏇存柊鍘熼攣瀹氫俊鎭�
-            lockInfo.AssignQuantity -= splitQuantity;
-            lockInfo.OrderQuantity -= splitQuantity;
-            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
+            // 4. 閲嶈淇锛氳嚜鍔ㄦ媶鍖呮椂锛屽師閿佸畾淇℃伅鐨勫垎閰嶆暟閲忎繚鎸佷笉鍙�
+            // 鍥犱负鑷姩鎷嗗寘鍚庯紝鍘熸潯鐮佷粛鐒堕渶瑕佽鍒嗘嫞锛屽垎閰嶆暟閲忎笉搴旇鏀瑰彉
+            _logger.LogInformation($"鍘熼攣瀹氫俊鎭繚鎸佷笉鍙� - 鍒嗛厤鏁伴噺: {lockInfo.AssignQuantity}, 璁㈠崟鏁伴噺: {lockInfo.OrderQuantity}");
 
-            // 璁板綍鎷嗗寘鍘嗗彶
-            await RecordSplitHistory(lockInfo, stockDetail, splitQuantity, newBarcode);
+            // 5. 璁板綍鎷嗗寘鍘嗗彶
+            await RecordSplitHistory(lockInfo, stockDetail, splitQuantity, newBarcode, true, originalStockQtyBefore);
+
+            _logger.LogInformation($"鑷姩鎷嗗寘閫昏緫鎵ц瀹屾垚");
 
             return new SplitResultDto { NewBarcode = newBarcode };
         }
-        private async Task ExecuteCancelSplitLogic(Dt_SplitPackageRecord splitRecord, Dt_OutStockLockInfo newLockInfo, Dt_StockInfoDetail newStockDetail)
+
+   
+        #endregion
+
+        #region 鏍稿績閫昏緫鏂规硶
+
+        private async Task<PickingResult> ExecutePickingLogic(
+            Dt_OutStockLockInfo lockInfo, Dt_OutboundOrderDetail orderDetail,
+            Dt_StockInfoDetail stockDetail, decimal actualPickedQty)
         {
-            // 鎭㈠鍘熷簱瀛�
-            var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-                .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == splitRecord.StockId);
+            _logger.LogInformation($"寮�濮嬫墽琛屽垎鎷i�昏緫 - 鏉$爜: {stockDetail.Barcode}, 鍒嗛厤鏁伴噺: {lockInfo.AssignQuantity}, 瀹為檯鎷i��: {actualPickedQty}");
 
-            originalStock.StockQuantity += splitRecord.SplitQty;
-            await _stockInfoDetailService.Db.Updateable(originalStock).ExecuteCommandAsync();
+            // 閲嶈淇锛氬啀娆¢獙璇佽鍗曟槑缁嗙殑鍒嗛厤鏁伴噺锛堥槻姝㈠苟鍙戞搷浣滐級
+            if (orderDetail.AllocatedQuantity < actualPickedQty)
+            {
+                throw new InvalidOperationException($"璁㈠崟鏄庣粏鍒嗛厤鏁伴噺涓嶈冻锛岄渶瑕佹嫞閫� {actualPickedQty}锛屽彲鐢ㄥ垎閰嶆暟閲� {orderDetail.AllocatedQuantity}");
+            }
 
-            // 鎭㈠鍘熼攣瀹氫俊鎭�
-            var originalLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
-                .FirstAsync(x => x.Id == splitRecord.OutStockLockInfoId);
+            if (orderDetail.LockQuantity < actualPickedQty)
+            {
+                throw new InvalidOperationException($"璁㈠崟鏄庣粏閿佸畾鏁伴噺涓嶈冻锛岄渶瑕佹嫞閫� {actualPickedQty}锛屽彲鐢ㄩ攣瀹氭暟閲� {orderDetail.LockQuantity}");
+            }
 
-            originalLockInfo.AssignQuantity += splitRecord.SplitQty;
-            originalLockInfo.OrderQuantity += splitRecord.SplitQty;
-            await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync();
+            // 1. 鏇存柊閿佸畾淇℃伅
+            lockInfo.PickedQty += actualPickedQty;
+            _logger.LogInformation($"鏇存柊閿佸畾淇℃伅 - 宸叉嫞閫夋暟閲忎粠 {lockInfo.PickedQty - actualPickedQty} 澧炲姞鍒� {lockInfo.PickedQty}");
 
-            // 鍒犻櫎鏂板簱瀛樻槑缁�
-            await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>()
-                .Where(x => x.Barcode == newLockInfo.CurrentBarcode)
-                .ExecuteCommandAsync();
+            // 鍑嗙‘鍒ゆ柇鎷i�夊畬鎴愮姸鎬�
+            if (Math.Abs(lockInfo.PickedQty - lockInfo.AssignQuantity) < 0.001m)
+            {
+                lockInfo.Status = (int)OutLockStockStatusEnum.鎷i�夊畬鎴�;
+                _logger.LogInformation($"閿佸畾淇℃伅鐘舵�佹洿鏂颁负鎷i�夊畬鎴�");
+            }
+            else if (lockInfo.PickedQty > 0)
+            {
+                lockInfo.Status = (int)OutLockStockStatusEnum.鍑哄簱涓�;
+                _logger.LogInformation($"閿佸畾淇℃伅鐘舵�佷繚鎸佷负鍑哄簱涓紙閮ㄥ垎鎷i�夛級");
+            }
 
-            // 鍒犻櫎鏂伴攣瀹氫俊鎭�
-            await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
-                .Where(x => x.Id == newLockInfo.Id)
-                .ExecuteCommandAsync();
+            lockInfo.Operator = App.User.UserName;
+            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
 
-            // 鏍囪鎷嗗寘璁板綍涓哄凡鎾ら攢
-            splitRecord.IsReverted = true;
-            splitRecord.RevertTime = DateTime.Now;
-            splitRecord.RevertOperator = App.User.UserName;
-            await _splitPackageService.Db.Updateable(splitRecord).ExecuteCommandAsync();
+            // 2. 鏇存柊搴撳瓨淇℃伅
+            decimal originalStockQty = stockDetail.StockQuantity;
+            decimal originalOutboundQty = stockDetail.OutboundQuantity;
+
+            stockDetail.StockQuantity -= actualPickedQty;
+            stockDetail.OutboundQuantity += actualPickedQty;
+
+            _logger.LogInformation($"鏇存柊搴撳瓨淇℃伅 - 搴撳瓨鏁伴噺浠� {originalStockQty} 鍑忓皯鍒� {stockDetail.StockQuantity}");
+            _logger.LogInformation($"鏇存柊搴撳瓨淇℃伅 - 鍑哄簱鏁伴噺浠� {originalOutboundQty} 澧炲姞鍒� {stockDetail.OutboundQuantity}");
+
+            // 鍑嗙‘鍒ゆ柇搴撳瓨鐘舵��
+            if (stockDetail.StockQuantity <= 0)
+            {
+                stockDetail.Status = (int)StockStatusEmun.鍑哄簱瀹屾垚;
+                _logger.LogInformation($"搴撳瓨鐘舵�佹洿鏂颁负鍑哄簱瀹屾垚");
+            }
+            else
+            {
+                stockDetail.Status = (int)StockStatusEmun.鍑哄簱閿佸畾;
+                _logger.LogInformation($"搴撳瓨鐘舵�佷繚鎸佷负鍑哄簱閿佸畾");
+            }
+
+            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+
+            _logger.LogInformation($"鍒嗘嫞閫昏緫鎵ц瀹屾垚 - 鏉$爜: {stockDetail.Barcode}");
+
+            return new PickingResult
+            {
+                FinalLockInfo = lockInfo,
+                ActualPickedQty = actualPickedQty
+            };
         }
 
+        private async Task<RevertPickingResult> RevertPickingData(Dt_PickingRecord pickingRecord)
+        {
+            _logger.LogInformation($"寮�濮嬫仮澶嶆嫞閫夋暟鎹� - 鎷i�夎褰旾D: {pickingRecord.Id}, 鏉$爜: {pickingRecord.Barcode}, 鎷i�夋暟閲�: {pickingRecord.PickQuantity}");
+
+            // 1. 鎭㈠閿佸畾淇℃伅
+            var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
+                .FirstAsync(x => x.Id == pickingRecord.OutStockLockId);
+
+            if (lockInfo == null)
+            {
+                throw new InvalidOperationException($"鏈壘鍒板搴旂殑閿佸畾淇℃伅锛孖D: {pickingRecord.OutStockLockId}");
+            }
+
+            decimal originalPickedQty = lockInfo.PickedQty;
+            decimal originalAssignQty = lockInfo.AssignQuantity; // 璁板綍鍘熷鍒嗛厤鏁伴噺
+
+            // 閲嶈淇锛氬彧鎭㈠宸叉嫞閫夋暟閲忥紝涓嶄慨鏀瑰垎閰嶆暟閲�
+            lockInfo.PickedQty -= pickingRecord.PickQuantity;
+
+            // 纭繚宸叉嫞閫夋暟閲忎笉浼氫负璐熸暟
+            if (lockInfo.PickedQty < 0)
+            {
+                _logger.LogWarning($"宸叉嫞閫夋暟閲忓嚭鐜拌礋鏁帮紝閲嶇疆涓�0銆傚師鍊�: {lockInfo.PickedQty + pickingRecord.PickQuantity}, 鎭㈠鏁伴噺: {pickingRecord.PickQuantity}");
+                lockInfo.PickedQty = 0;
+            }
+
+            _logger.LogInformation($"鎭㈠閿佸畾淇℃伅 - 宸叉嫞閫夋暟閲忎粠 {originalPickedQty} 鍑忓皯鍒� {lockInfo.PickedQty}");
+            _logger.LogInformation($"閿佸畾淇℃伅鍒嗛厤鏁伴噺淇濇寔涓嶅彉: {originalAssignQty}");
+
+            // 鎭㈠閿佸畾鐘舵��
+            if (lockInfo.PickedQty <= 0)
+            {
+                lockInfo.Status = (int)OutLockStockStatusEnum.鍑哄簱涓�;
+                _logger.LogInformation($"閿佸畾淇℃伅鐘舵�佹仮澶嶄负鍑哄簱涓�");
+            }
+            else if (lockInfo.PickedQty < lockInfo.AssignQuantity)
+            {
+                lockInfo.Status = (int)OutLockStockStatusEnum.鍑哄簱涓�; // 閮ㄥ垎鎷i�夌姸鎬�
+                _logger.LogInformation($"閿佸畾淇℃伅鐘舵�佹仮澶嶄负鍑哄簱涓紙閮ㄥ垎鎷i�夛級");
+            }
+
+            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
+
+            // 2. 鎭㈠搴撳瓨淇℃伅
+            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
+                .FirstAsync(x => x.Barcode == pickingRecord.Barcode);
+
+            if (stockDetail == null)
+            {
+                throw new InvalidOperationException($"鏈壘鍒板搴旂殑搴撳瓨淇℃伅锛屾潯鐮�: {pickingRecord.Barcode}");
+            }
+
+            decimal originalStockQty = stockDetail.StockQuantity;
+            decimal originalOutboundQty = stockDetail.OutboundQuantity;
+
+            stockDetail.StockQuantity += pickingRecord.PickQuantity;
+            stockDetail.OutboundQuantity -= pickingRecord.PickQuantity;
+
+            // 纭繚鍑哄簱鏁伴噺涓嶄細涓鸿礋鏁�
+            if (stockDetail.OutboundQuantity < 0)
+            {
+                _logger.LogWarning($"鍑哄簱鏁伴噺鍑虹幇璐熸暟锛岄噸缃负0銆傚師鍊�: {stockDetail.OutboundQuantity + pickingRecord.PickQuantity}, 鎭㈠鏁伴噺: {pickingRecord.PickQuantity}");
+                stockDetail.OutboundQuantity = 0;
+            }
+
+            _logger.LogInformation($"鎭㈠搴撳瓨淇℃伅 - 搴撳瓨鏁伴噺浠� {originalStockQty} 澧炲姞鍒� {stockDetail.StockQuantity}");
+            _logger.LogInformation($"鎭㈠搴撳瓨淇℃伅 - 鍑哄簱鏁伴噺浠� {originalOutboundQty} 鍑忓皯鍒� {stockDetail.OutboundQuantity}");
+
+            // 鎭㈠搴撳瓨鐘舵��
+            if (stockDetail.StockQuantity > 0)
+            {
+                stockDetail.Status = (int)StockStatusEmun.鍑哄簱閿佸畾;
+                _logger.LogInformation($"搴撳瓨鐘舵�佹仮澶嶄负鍑哄簱閿佸畾");
+            }
+
+            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
+
+            _logger.LogInformation($"鎭㈠鎷i�夋暟鎹畬鎴� - 鏉$爜: {pickingRecord.Barcode}");
+
+            return new RevertPickingResult
+            {
+                LockInfo = lockInfo,
+                StockDetail = stockDetail
+            };
+        }
+ 
         #endregion
 
         #region 鏁版嵁鏇存柊鏂规硶
 
         private async Task UpdateBatchAndOrderData(Dt_OutboundBatch batch, Dt_OutboundOrderDetail orderDetail, decimal pickedQty, string orderNo)
         {
-            // 鏇存柊鎵规瀹屾垚鏁伴噺
+            _logger.LogInformation($"寮�濮嬫洿鏂版壒娆″拰璁㈠崟鏁版嵁 - 鎷i�夋暟閲�: {pickedQty}");
+
+            // 閲嶈淇锛氶獙璇佸垎閰嶆暟閲忎笉浼氬彉鎴愯礋鏁�
+            if (orderDetail.AllocatedQuantity < pickedQty)
+            {
+                throw new InvalidOperationException($"鏇存柊璁㈠崟鏁版嵁鏃跺垎閰嶆暟閲忎笉瓒筹紝闇�瑕佸噺灏� {pickedQty}锛屽綋鍓嶅垎閰嶆暟閲� {orderDetail.AllocatedQuantity}");
+            }
+
+            if (orderDetail.LockQuantity < pickedQty)
+            {
+                throw new InvalidOperationException($"鏇存柊璁㈠崟鏁版嵁鏃堕攣瀹氭暟閲忎笉瓒筹紝闇�瑕佸噺灏� {pickedQty}锛屽綋鍓嶉攣瀹氭暟閲� {orderDetail.LockQuantity}");
+            }
+
+            // 1. 鏇存柊鎵规瀹屾垚鏁伴噺
+            decimal originalBatchCompletedQty = batch.CompletedQuantity;
             batch.CompletedQuantity += pickedQty;
+
+            _logger.LogInformation($"鏇存柊鎵规瀹屾垚鏁伴噺 - 浠� {originalBatchCompletedQty} 澧炲姞鍒� {batch.CompletedQuantity}");
+
             if (batch.CompletedQuantity >= batch.BatchQuantity)
             {
                 batch.BatchStatus = (int)BatchStatusEnum.宸插畬鎴�;
+                _logger.LogInformation($"鎵规鐘舵�佹洿鏂颁负宸插畬鎴�");
             }
             await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync();
 
-            // 鏇存柊璁㈠崟鏄庣粏
+            // 2. 鏇存柊璁㈠崟鏄庣粏
+            decimal originalOverOutQty = orderDetail.OverOutQuantity;
+            decimal originalAllocatedQty = orderDetail.AllocatedQuantity;
+            decimal originalLockQty = orderDetail.LockQuantity;
+
             orderDetail.OverOutQuantity += pickedQty;
             orderDetail.AllocatedQuantity -= pickedQty;
+            // LockQuantity 鍚屾鍑忓皯
+            orderDetail.LockQuantity = orderDetail.AllocatedQuantity;
+
+            _logger.LogInformation($"鏇存柊璁㈠崟鏄庣粏 - 宸插嚭搴撴暟閲忎粠 {originalOverOutQty} 澧炲姞鍒� {orderDetail.OverOutQuantity}");
+            _logger.LogInformation($"鏇存柊璁㈠崟鏄庣粏 - 宸插垎閰嶆暟閲忎粠 {originalAllocatedQty} 鍑忓皯鍒� {orderDetail.AllocatedQuantity}");
+            _logger.LogInformation($"鏇存柊璁㈠崟鏄庣粏 - 閿佸畾鏁伴噺浠� {originalLockQty} 鍑忓皯鍒� {orderDetail.LockQuantity}");
+
             await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync();
 
-            // 妫�鏌ヨ鍗曠姸鎬�
+            // 3. 妫�鏌ヨ鍗曠姸鎬�
             await CheckAndUpdateOrderStatus(orderNo);
+
+            _logger.LogInformation($"鎵规鍜岃鍗曟暟鎹洿鏂板畬鎴�");
         }
 
         private async Task RevertBatchAndOrderData(Dt_PickingRecord pickingRecord, RevertPickingResult revertResult)
         {
-            // 鎭㈠鎵规瀹屾垚鏁伴噺
+            _logger.LogInformation($"寮�濮嬫仮澶嶆壒娆″拰璁㈠崟鏁版嵁");
+
+            // 1. 鎭㈠鎵规瀹屾垚鏁伴噺
             var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>()
-                .FirstAsync(x => x.BatchNo == revertResult.LockInfo.OutboundBatchNo); // 浣跨敤 OutboundBatchNo
+                .FirstAsync(x => x.BatchNo == revertResult.LockInfo.OutboundBatchNo);
 
             if (batch != null)
             {
+                decimal originalCompletedQty = batch.CompletedQuantity;
                 batch.CompletedQuantity -= pickingRecord.PickQuantity;
+
+                _logger.LogInformation($"鎭㈠鎵规瀹屾垚鏁伴噺 - 浠� {originalCompletedQty} 鍑忓皯鍒� {batch.CompletedQuantity}");
 
                 // 閲嶆柊璁$畻鎵规鐘舵��
                 if (batch.CompletedQuantity <= 0)
                 {
                     batch.BatchStatus = (int)BatchStatusEnum.鍒嗛厤涓�;
+                    _logger.LogInformation($"鎵规鐘舵�佹仮澶嶄负鍒嗛厤涓�");
                 }
                 else if (batch.CompletedQuantity < batch.BatchQuantity)
                 {
                     batch.BatchStatus = (int)BatchStatusEnum.鎵ц涓�;
+                    _logger.LogInformation($"鎵规鐘舵�佹仮澶嶄负鎵ц涓�");
                 }
 
                 await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync();
             }
 
-            // 鎭㈠璁㈠崟鏄庣粏
+            // 2. 鎭㈠璁㈠崟鏄庣粏
             var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                 .FirstAsync(x => x.Id == pickingRecord.OrderDetailId);
 
-            orderDetail.OverOutQuantity -= pickingRecord.PickQuantity;
-            orderDetail.AllocatedQuantity += pickingRecord.PickQuantity;
-            await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync();
+            if (orderDetail != null)
+            {
+                decimal originalOverOutQty = orderDetail.OverOutQuantity;
+                decimal originalAllocatedQty = orderDetail.AllocatedQuantity;
+                decimal originalLockQty = orderDetail.LockQuantity;
 
-            // 閲嶆柊妫�鏌ヨ鍗曠姸鎬�
+                // 閲嶈淇锛氬彧鎭㈠鐩稿叧鏁伴噺锛屽垎閰嶆暟閲忎繚鎸佷笉鍙�
+                orderDetail.OverOutQuantity -= pickingRecord.PickQuantity;
+                // 娉ㄦ剰锛欰llocatedQuantity 鍜� LockQuantity 鍦ㄥ彇娑堝垎鎷f椂涓嶅簲璇ユ敼鍙�
+
+                _logger.LogInformation($"鎭㈠璁㈠崟鏄庣粏 - 宸插嚭搴撴暟閲忎粠 {originalOverOutQty} 鍑忓皯鍒� {orderDetail.OverOutQuantity}");
+                _logger.LogInformation($"璁㈠崟鏄庣粏鍒嗛厤鏁伴噺淇濇寔涓嶅彉: {originalAllocatedQty}");
+                _logger.LogInformation($"璁㈠崟鏄庣粏閿佸畾鏁伴噺淇濇寔涓嶅彉: {originalLockQty}");
+
+                await UpdateBatchAllocateStatus(orderDetail);
+                await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync();
+            }
+
+            // 3. 閲嶆柊妫�鏌ヨ鍗曠姸鎬�
             await CheckAndUpdateOrderStatus(pickingRecord.OrderNo);
+
+            _logger.LogInformation($"鎭㈠鎵规鍜岃鍗曟暟鎹畬鎴�");
+        }
+
+        private async Task UpdateBatchAllocateStatus(Dt_OutboundOrderDetail orderDetail)
+        {
+            if (orderDetail.AllocatedQuantity >= orderDetail.NeedOutQuantity)
+            {
+                orderDetail.BatchAllocateStatus = OrderDetailStatusEnum.AssignOver.ObjToInt();
+            }
+            else if (orderDetail.AllocatedQuantity > 0)
+            {
+                orderDetail.BatchAllocateStatus = OrderDetailStatusEnum.AssignOverPartial.ObjToInt();
+            }
+            else
+            {
+                orderDetail.BatchAllocateStatus = OrderDetailStatusEnum.New.ObjToInt();
+            }
         }
         private async Task ReleaseLockAndStock(Dt_OutStockLockInfo lockInfo)
         {
@@ -1326,6 +1981,11 @@
                 if (orderDetail != null)
                 {
                     orderDetail.AllocatedQuantity -= returnedQty;
+                    // LockQuantity 鍚屾鍑忓皯锛屼繚鎸佷笌宸插垎閰嶆暟閲忎竴鑷�
+                    orderDetail.LockQuantity = orderDetail.AllocatedQuantity;
+
+                    await UpdateBatchAllocateStatus(orderDetail);
+
                     await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync();
                 }
             }
@@ -1340,7 +2000,7 @@
             return "WSLOT" + DateTime.Now.ToString("yyyyMMdd") + seq.ToString().PadLeft(5, '0');
         }
 
-        private async Task RecordSplitHistory(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, decimal splitQty, string newBarcode)
+        private async Task RecordSplitHistory(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, decimal splitQty, string newBarcode, bool isAutoSplit, decimal? originalStockQuantity = null)
         {
             var splitHistory = new Dt_SplitPackageRecord
             {
@@ -1352,7 +2012,11 @@
                 NewBarcode = newBarcode,
                 SplitQty = splitQty,
                 SplitTime = DateTime.Now,
-                Status = (int)SplitPackageStatusEnum.宸叉媶鍖�
+                Status = (int)SplitPackageStatusEnum.宸叉媶鍖�,
+                IsAutoSplit = isAutoSplit  ,
+                // SplitType = isAutoSplit ? "鑷姩鎷嗗寘" : "鎵嬪姩鎷嗗寘"
+                OriginalStockQuantity = originalStockQuantity ?? stockDetail.StockQuantity,
+                //RemainingStockQuantity = stockDetail.StockQuantity - splitQty
             };
 
             await _splitPackageService.Db.Insertable(splitHistory).ExecuteCommandAsync();
@@ -1414,9 +2078,44 @@
             };
         }
         #endregion
- 
+
 
         #region DTO绫�
+        /// <summary>
+        /// 鏉$爜鐘舵�佷俊鎭疍TO
+        /// </summary>
+        public class BarcodeStatusInfoDto
+        {
+            public string Barcode { get; set; }
+            public string OrderNo { get; set; }
+            public bool IsOriginalBarcode { get; set; }
+            public int SplitChainCount { get; set; }
+            public bool HasBeenPicked { get; set; }
+            public decimal TotalPickedQuantity { get; set; }
+            public int PickRecordCount { get; set; }
+            public int LockInfoStatus { get; set; }
+            public decimal LockInfoPickedQty { get; set; }
+            public decimal LockInfoAssignQty { get; set; }
+            public decimal StockQuantity { get; set; }
+            public int StockStatus { get; set; }
+            public bool CanCancelSplit { get; set; }
+            public bool NeedCancelPickFirst { get; set; }
+            public List<string> OperationSuggestions { get; set; } = new List<string>();
+        }
+        public class PickedBarcodeInfo
+        {
+            public string Barcode { get; set; }
+            public decimal PickedQty { get; set; }
+            public int PickRecordCount { get; set; }
+        }
+        /// <summary>
+        /// 鑷姩鎷嗗寘缁撴灉
+        /// </summary>
+        public class AutoSplitResult
+        {
+            public string NewBarcode { get; set; }
+            public decimal SplitQuantity { get; set; }
+        }
 
         public class PickingResult
         {

--
Gitblit v1.9.3