From 7bafd627066668f8162690890f106d00e18d7bcd Mon Sep 17 00:00:00 2001
From: pan <antony1029@163.com>
Date: 星期六, 22 十一月 2025 15:32:27 +0800
Subject: [PATCH] 提交

---
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs |  148 ++++++++++++++++++++++++++++++++++++------------
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs       |   14 +++-
 2 files changed, 120 insertions(+), 42 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_BasicService/LocationInfoService.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_BasicService/LocationInfoService.cs"
index 82bbeeb..48640ac 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_BasicService/LocationInfoService.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_BasicService/LocationInfoService.cs"
@@ -140,7 +140,7 @@
 
                 List<string> lockLocationCodes = locationCaches.Select(x => x.LocationCode).ToList();
 
-                Dictionary<string, OrderByType> orderBy = new Dictionary<string, OrderByType>()
+                Dictionary<string, SqlSugar.OrderByType> orderBy = new Dictionary<string, OrderByType>()
                 {
                     { nameof(Dt_LocationInfo.RoadwayNo),OrderByType.Asc },
                     { nameof(Dt_LocationInfo.Layer),OrderByType.Asc },
@@ -153,7 +153,11 @@
                 if (first != null)
                 {
                     locationCaches.Add(new LocationCache { LocationCode = first?.LocationCode, DateTime = DateTime.Now });
-                }
+                    Db.Updateable<Dt_LocationInfo>().SetColumns(x => new Dt_LocationInfo
+                    {
+                        LocationStatus = (int)LocationStatusEnum.InStockLock,
+                    }).Where(x => x.Id == first.Id).ExecuteCommand();
+                }        
 
                 return first;
             }
@@ -182,8 +186,10 @@
                 };
 
                 var first = BaseDal.QueryFirst(x => x.LocationStatus == LocationStatusEnum.Free.ObjToInt() && x.EnableStatus != EnableStatusEnum.Disable.ObjToInt() && !lockLocationCodes.Contains(x.LocationCode), orderBy);//鏌ヨ绌鸿揣浣嶄俊鎭苟鎺掗櫎5鍒嗛挓鍐呭垎閰嶇殑璐т綅,鏍规嵁灞傘�佸垪銆佹繁搴︺�佽鎺掑簭
-
-                locationCaches.Add(new LocationCache { LocationCode = first.LocationCode, DateTime = DateTime.Now });
+                if (first != null)
+                {
+                    locationCaches.Add(new LocationCache { LocationCode = first.LocationCode, DateTime = DateTime.Now });
+                }
 
                 return first;
             }
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 19418a6..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"
@@ -160,28 +160,33 @@
             try
             {
                 _unitOfWorkManage.BeginTran();
-
-                // 1. 鍓嶇疆楠岃瘉鍜屼笟鍔℃鏌�
+  
                 var validationResult = await ValidatePickingRequest(orderNo, palletCode, barcode);
                 if (!validationResult.IsValid)
                     return WebResponseContent.Instance.Error(validationResult.ErrorMessage);
 
                 var (lockInfo, orderDetail, stockDetail) = validationResult.Data;
 
-                // 2. 璁$畻瀹為檯鎷i�夋暟閲�
+                // 璁$畻瀹為檯鎷i�夋暟閲�
                 var quantityResult = await CalculateActualPickingQuantity(lockInfo, orderDetail, stockDetail);
                 if (!quantityResult.IsValid)
                     return WebResponseContent.Instance.Error(quantityResult.ErrorMessage);
 
                 var (actualQty, adjustedReason) = quantityResult.Data;
 
-                // 3. 鎵ц鍒嗘嫞閫昏緫
+                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);
 
-                // 4. 鏇存柊鐩稿叧鏁版嵁
+                // 鏇存柊鐩稿叧鏁版嵁
                 await UpdateOrderRelatedData(orderDetail.Id, pickingResult.ActualPickedQty, orderNo);
 
-                // 5. 璁板綍鎿嶄綔鍘嗗彶
+                // 璁板綍鎿嶄綔鍘嗗彶
                 await RecordPickingHistory(pickingResult, orderNo, palletCode);
 
                 _unitOfWorkManage.CommitTran();
@@ -388,18 +393,29 @@
             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;
 
-            // 妫�鏌�1锛氳鍗曟暟閲忛檺鍒�
-            if (plannedQty > remainingOrderQty && remainingOrderQty > 0)
+            if (plannedQty > remainingOrderQty)
             {
                 actualQty = remainingOrderQty;
                 adjustedReason = $"璁㈠崟鏁伴噺闄愬埗锛氫粠{plannedQty}璋冩暣涓簕actualQty}";
             }
-
-            // 妫�鏌�2锛氬簱瀛樻暟閲忛檺鍒�
             if (actualQty > stockQuantity)
             {
                 actualQty = stockQuantity;
@@ -407,12 +423,19 @@
                     ? $"{adjustedReason}锛屽簱瀛樻暟閲忛檺鍒讹細杩涗竴姝ヨ皟鏁翠负{actualQty}"
                     : $"搴撳瓨鏁伴噺闄愬埗锛氫粠{plannedQty}璋冩暣涓簕actualQty}";
             }
-
-            // 妫�鏌�3锛氬疄闄呭彲鎷i�夋暟閲忓繀椤诲ぇ浜�0
             if (actualQty <= 0)
             {
-                return ValidationResult<(decimal, string)>.Error($"鏃犳硶鍒嗘嫞锛氳鍒掓暟閲弡plannedQty}锛屽墿浣欒鍗晎remainingOrderQty}锛屽簱瀛榹stockQuantity}");
+                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)
             {
@@ -422,6 +445,27 @@
             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)
@@ -531,10 +575,24 @@
             decimal newOverOutQuantity = currentOrderDetail.OverOutQuantity + pickedQty;
             decimal newPickedQty = currentOrderDetail.PickedQty + pickedQty;
 
-            // 鏈�缁堟鏌ワ細纭繚涓嶄細瓒呰繃璁㈠崟闇�姹傛暟閲�
             if (newOverOutQuantity > currentOrderDetail.NeedOutQuantity)
             {
-                throw new Exception($"鍒嗘嫞鍚庡皢瀵艰嚧宸插嚭搴撴暟閲�({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})锛屼笖鏃犳硶鑷姩璋冩暣");
+                }
             }
 
             // 鏇存柊璁㈠崟鏄庣粏
@@ -603,6 +661,10 @@
             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)
@@ -610,14 +672,39 @@
 
             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 stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
-       .Where(it => it.Barcode == barcode && it.StockId == pickingRecord.StockId)
-       .FirstAsync();
+            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)
             {
@@ -627,23 +714,8 @@
                 {
                     return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error($"鏉$爜{barcode}宸茬粡鍥炲簱锛屼笉鑳藉彇娑堝垎鎷�");
                 }
-            }
-
-            // 妫�鏌ヨ鍗曠姸鎬�
-            var order = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
-                .Where(x => x.OrderNo == orderNo)
-                .FirstAsync();
-
-            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}");
-
+            }       
+            
             return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Success((pickingRecord, lockInfo, orderDetail));
         }
         /// <summary>
@@ -996,13 +1068,13 @@
                 await UpdateOrderDetailsOnReturn(analysis.RemainingLocks);
             }
 
-            // 鎯呭喌2锛氬鐞嗘墭鐩樹笂鍏朵粬搴撳瓨璐х墿
+            // 澶勭悊鎵樼洏涓婂叾浠栧簱瀛樿揣鐗�
             if (analysis.HasPalletStockGoods)
             {
                 await HandlePalletStockGoodsReturn(analysis.PalletStockGoods);
             }
 
-            // 鎯呭喌3锛氬鐞嗘媶鍖呰褰�
+            // 澶勭悊鎷嗗寘璁板綍
             if (analysis.HasSplitRecords)
             {
                 await HandleSplitRecordsReturn(analysis.SplitRecords, orderNo, palletCode);

--
Gitblit v1.9.3