From d42ad8b01195def2a9309930e14f90ff13ad47b1 Mon Sep 17 00:00:00 2001
From: 杨前锦 <1010338399@qq.com>
Date: 星期四, 19 六月 2025 17:24:28 +0800
Subject: [PATCH] 印尼佳通出入库策略优化

---
 HH.WCS.Mobox3/HH.WCS.Mobox3.YNJT_PT/wms/WMSHelper.cs |  577 ++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 460 insertions(+), 117 deletions(-)

diff --git a/HH.WCS.Mobox3/HH.WCS.Mobox3.YNJT_PT/wms/WMSHelper.cs b/HH.WCS.Mobox3/HH.WCS.Mobox3.YNJT_PT/wms/WMSHelper.cs
index e2d0f97..a1736e8 100644
--- a/HH.WCS.Mobox3/HH.WCS.Mobox3.YNJT_PT/wms/WMSHelper.cs
+++ b/HH.WCS.Mobox3/HH.WCS.Mobox3.YNJT_PT/wms/WMSHelper.cs
@@ -1,5 +1,6 @@
 锘縰sing HH.WCS.Mobox3.YNJT_BZP_PT.models;
 using HH.WCS.Mobox3.YNJT_PT.api;
+using HH.WCS.Mobox3.YNJT_PT.dispatch;
 using HH.WCS.Mobox3.YNJT_PT.models;
 using HH.WCS.Mobox3.YNJT_PT.models.other;
 using HH.WCS.Mobox3.YNJT_PT.util;
@@ -338,7 +339,7 @@
             var offLineRecord = db.Queryable<OffLineRecord>().Where(a => a.S_RFID == record.S_RFID).First();
             if (offLineRecord != null)
             {
-                offLineRecord.S_LOC = record.S_LOC;
+                offLineRecord.S_DEVICE_NO = record.S_DEVICE_NO;
                 offLineRecord.N_IS_URGENT = record.N_IS_URGENT;
                 offLineRecord.T_OFF_TIME = record.T_OFF_TIME;
                 offLineRecord.N_IS_FULL = record.N_IS_FULL;
@@ -383,148 +384,421 @@
             return greenTireInformation;
         }
 
-        /// <summary>
+        /*/// <summary>
         /// 鏌ヨ鍏ュ簱缁堢偣璐т綅
+        /// 鍏ュ簱绛栫暐锛�+        /// 宸烽亾鍐呭悓瑙勬牸鏁伴噺 灏忎簬 10锛堟殏瀹氾級锛屾寜鐗╂枡鍧囪 璁$畻锛屽鏋滄墍鏈夌殑宸烽亾鍐呭悓瑙勬牸鏁伴噺閮藉ぇ浜�0锛屽垯鎸夌収宸烽亾鍧囪 璁$畻
         /// </summary>
-        /// <param name="itemCode"></param>
         /// <param name="locNum">1.鍗曡揣浣�2.鍙岃揣浣�/param>
         /// <returns></returns>
-        public static List<Location> getInStockEndLoc(string itemCode, int locNum) 
+        public static EndLocGroup getInStockEndLoc(int locNum , string itemCode) 
         {
             var db = new SqlHelper<object>().GetInstance();
+            EndLocGroup endLocGroup = new EndLocGroup();
             List<Location> locations = new List<Location>();
-            // 1.鎸夊绉巼浠庡ぇ鍒板皬锛屽宸烽亾杩涜鎺掑簭
-            var roadwayOrderList = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y")
-                .GroupBy(a => a.N_ROADWAY)
-                .Select(a => new { roadway = a.N_ROADWAY ,  num = SqlFunc.AggregateCount(a.S_CODE)})
-                .OrderByDescending(a => a.num)
+
+            List<int> roadwayList = new List<int>();
+
+            // 1.鎸夊贩閬撹繘琛屽垎缁勶紝鏌ヨ姣忎釜宸烽亾鍐呭悓瑙勬牸鐗╂枡鐨勬暟閲忥紝骞朵粠灏忓埌澶ф帓搴�+            var roadwayItemNumOrderGroup = db.Queryable<Location>()
+                .LeftJoin<LocCntrRel>((a,b) => a.S_CODE == b.S_LOC_CODE)
+                .LeftJoin<CntrItemRel>((a,b,c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
+                .Where((a, b, c) => a.S_AREA_CODE == Settings.stockArea && a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y" && c.S_ITEM_CODE == itemCode)
+                .GroupBy((a, b, c) => a.N_ROADWAY)
+                .Select((a, b, c) => new { roadway = a.N_ROADWAY, num = SqlFunc.AggregateCount(a.S_CODE) })
+                .OrderBy(a => a.num)
                 .ToList();
 
-            // 鏌ヨ鍗曡揣浣�-            if (locNum == 1) 
+            roadwayList = roadwayItemNumOrderGroup.Where(a => a.num < 10).OrderBy(a => a.num).Select(a => a.roadway).ToList();
+
+            // 2.鎸夊贩閬撹繘琛屽垎缁勶紝鏌ヨ姣忎釜宸烽亾绌鸿揣浣嶆暟閲忥紝骞朵粠澶у埌灏忔帓搴�+            if (roadwayList.Count == 0) 
             {
-                foreach (var order in roadwayOrderList)
+                var roadwayEmptyNumOrderGroup = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y")
+                    .GroupBy(a => a.N_ROADWAY)
+                    .Select(a => new { roadway = a.N_ROADWAY, num = SqlFunc.AggregateCount(a.S_CODE) })
+                    .OrderByDescending(a => a.num)
+                    .ToList();
+                roadwayList = roadwayEmptyNumOrderGroup.Select(a => a.roadway).ToList();
+            }
+
+            if (roadwayList.Count > 0) 
+            {
+                // 鏌ヨ鍗曡揣浣�+                foreach (var roadway in roadwayList)
                 {
-                    // 1. 鏌ヨ1鍙疯揣浣嶆槸鍚︽湁鐩稿悓鐗╂枡,鏈夛紝鍒欐煡璇㈠搴旂殑2鍙疯揣浣嶆槸鍚︿负绌�-                    var oneLocList = db.Queryable<Location>()
-                        .LeftJoin<LocCntrRel>((a,b) => a.S_CODE == b.S_LOC_CODE)
-                        .LeftJoin<CntrItemRel>((a,b,c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
-                        .Where((a, b, c) => a.S_AREA_CODE == Settings.stockArea 
-                                        && a.N_ROADWAY == order.roadway 
-                                        && a.N_COL % 2 == 1 
-                                        && a.N_CURRENT_NUM == 1 
-                                        && a.N_LOCK_STATE == 0 
-                                        && a.C_ENABLE == "Y"
-                                        && c.S_ITEM_CODE == itemCode
-                                        )
-                        .OrderBy(a => a.N_LAYER).OrderBy(a => a.N_COL)
-                        .ToList();
-                    if (oneLocList.Count > 0) 
+                    if (locNum == 1)
                     {
-                        foreach (var loc in oneLocList)
+                        // 鏌ヨ绌鸿揣浣�+                        var emptyLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == roadway && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").OrderBy(a => new { a.N_LAYER, a.N_COL }).First();
+                        if (emptyLoc != null)
                         {
-                            var twoLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL + 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
-                            if (twoLoc != null)
-                            {
-                                locations.Add(twoLoc);
-                                return locations;
-                            }
+                            locations.Add(emptyLoc);
+                            endLocGroup.endLocList = locations;
+                            return endLocGroup;
                         }
                     }
 
-                    // 2.鏌ヨ2鍙疯揣浣嶆槸鍚︽湁鐩稿悓鐗╂枡锛屾湁锛屽垯鏌ヨ瀵瑰簲鐨�鍙蜂綅鏄惁涓虹┖
-                    if (locations.Count == 0) 
+                    if (locNum == 2)
                     {
-                        var twoLocList = db.Queryable<Location>()
-                            .LeftJoin<LocCntrRel>((a, b) => a.S_CODE == b.S_LOC_CODE)
-                            .LeftJoin<CntrItemRel>((a, b, c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
-                            .Where((a, b, c) => a.S_AREA_CODE == Settings.stockArea 
-                                            && a.N_ROADWAY == order.roadway
-                                            && a.N_COL % 2 == 0
-                                            && a.N_CURRENT_NUM == 1
-                                            && a.N_LOCK_STATE == 0
-                                            && a.C_ENABLE == "Y"
-                                            && c.S_ITEM_CODE == itemCode
-                                            )
-                            .OrderBy(a => a.N_LAYER).OrderBy(a => a.N_COL)
-                            .ToList();
-
-                        if (twoLocList.Count > 0)
+                        var emptyLocList = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == roadway && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").OrderBy(a => new { a.N_LAYER, a.N_COL }).ToList();
+                        if (emptyLocList.Count > 0)
                         {
-                            foreach (var loc in twoLocList)
+                            // 浼樺厛鏌ヨ鐩搁偦鍙屾嫋绌鸿揣浣�+                            if (locations.Count == 0)
                             {
-                                var oneLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL - 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
-                                if (oneLoc != null)
+                                foreach (var loc in emptyLocList)
                                 {
-                                    locations.Add(oneLoc);
-                                    return locations;
-                                }
-                            }
-                        }
-                    }
+                                    // 鏌ヨ鐩搁偦宸︿晶鏄惁鏈夌┖璐т綅
+                                    var leftLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL - 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
+                                    if (leftLoc != null)
+                                    {
+                                        locations.Add(loc);
+                                        locations.Add(leftLoc);
+                                        break;
+                                    }
 
-                    // 3.娌℃湁鐩稿悓鐗╂枡鐨�浼樺厛鏀剧鐢ㄨ揣浣嶆梺杈癸紙鍗曚竴璐т綅锛�-                    if (locations.Count == 0) 
-                    {
-                       var  disableLocList= db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.C_ENABLE == "N").OrderBy(a => a.N_LAYER).ToList();
-                        foreach (var loc in disableLocList) 
-                        {
-                            // 璐т綅涓�鍙蜂綅锛屽垯鏌ヨ瀵瑰簲浜屽彿浣嶆槸鍚︿负绌�-                            if (loc.N_LAYER % 2 == 1) 
-                            {
-                                var twoLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL + 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
-                                if (twoLoc != null) 
-                                {
-                                    locations.Add(twoLoc);
-                                    return locations;
+                                    // 鏌ヨ鐩搁偦鍙充晶鏄惁鏈夌┖璐т綅
+                                    var rightLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL + 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
+                                    if (rightLoc != null)
+                                    {
+                                        locations.Add(loc);
+                                        locations.Add(rightLoc);
+                                        break;
+                                    }
                                 }
                             }
 
-                            // 璐т綅涓�鍙蜂綅锛屽垯鏌ヨ瀵瑰簲涓�彿浣嶆槸鍚︿负绌�-                            if (loc.N_LAYER % 2 == 0) 
+                            if (locations.Count < locNum) 
                             {
-                                var oneLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL - 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
-                                if (oneLoc != null)
+                                // 鏌ヨ涓嶇浉閭荤殑鍗曟嫋璐т綅
+                                foreach (var loc in emptyLocList)
                                 {
-                                    locations.Add(oneLoc);
-                                    return locations;
+                                    locations.Add(loc);
+                                    if (locations.Count == locNum)
+                                    {
+                                        break;
+                                    }
                                 }
                             }
-                        }
-                    }
 
-                    // 4.娌℃湁鐩稿悓鐗╂枡鐨勶紝涓旂鐢ㄨ揣浣嶆梺杈规病鏈夌┖璐т綅锛屽垯浼樺厛鏀�鍙蜂綅
-                    if (locations.Count == 0) 
-                    {
-                        oneLocList = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_COL % 2 == 1 && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").OrderBy(a => a.N_LAYER).OrderByDescending(a => a.N_COL).ToList();
-                        if (oneLocList.Count > 0) 
-                        {
-                            locations.Add(oneLocList[0]);
-                            return locations;
+                            if (locations.Count == locNum)
+                            {
+                                endLocGroup.endLocList = locations;
+                                // 鏍¢獙璐т綅鏄惁鏄悓宸烽亾锛屾槸鍒欑敓鎴愪换鍔$粍鍙�+                                var groupNum = locations.GroupBy(a => a.N_ROADWAY).Count();
+                                if (groupNum == 1) 
+                                {
+                                    endLocGroup.groupNo = WMSHelper.GenerateTaskGroupNo();
+                                }
+                                return endLocGroup;
+                            }
                         }
                     }
                 }
             }
+            return endLocGroup;
+        }*/
 
-            // 鏌ヨ鍙岃揣浣�-            if (locNum == 2) 
+        /// <summary>
+        /// 鏌ヨ鍏ュ簱缁堢偣璐т綅
+        /// 鍏ュ簱绛栫暐锛�+        /// 宸烽亾鍐呭悓瑙勬牸鏁伴噺 灏忎簬 10锛堟殏瀹氾級锛屾寜鐗╂枡鍧囪 璁$畻锛屽鏋滄墍鏈夌殑宸烽亾鍐呭悓瑙勬牸鏁伴噺閮藉ぇ浜�0锛屽垯鎸夌収宸烽亾鍧囪 璁$畻
+        /// </summary>
+        /// <param name="locNum"></param>
+        /// <param name="itemCode"></param>
+        /// <param name="roadway"></param>
+        /// <param name="excludeRoadway"></param>
+        /// <returns></returns>
+        public static EndLocGroup getInStockEndLoc(int locNum, string itemCode , int roadway = 0 ,int excludeRoadway = 0)
+        {
+            var db = new SqlHelper<object>().GetInstance();
+            EndLocGroup endLocGroup = new EndLocGroup { endLocList = new List<Location>() };
+
+            // 1. 鑾峰彇鍊欓�宸烽亾鍒楄〃锛堢墿鏂欏潎琛℃垨宸烽亾鍧囪 锛�+            List<int> candidateRoadways = new List<int>();
+            if (roadway == 0)
             {
-                foreach (var order in roadwayOrderList) 
+                candidateRoadways = GetCandidateRoadways(db, itemCode);
+                if (candidateRoadways.Count == 0) return endLocGroup;
+
+                if (excludeRoadway != 0)
                 {
-                   var oneLocList = db.Queryable<Location>().Where( a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_COL % 2 == 1 && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").OrderBy(a => a.N_LAYER).OrderBy(a => a.N_COL).ToList();
-                    foreach (var loc in oneLocList) 
-                    {
-                       var twoLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL + 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
-                        if (twoLoc != null)
-                        {
-                            locations.Add(loc);
-                            locations.Add(twoLoc);
-                            return locations;
-                        }
-                    }
+                    candidateRoadways.Remove(excludeRoadway);
                 }
             }
-            return locations;
+            else 
+            {
+                candidateRoadways.Add(roadway);
+            }
+           
+
+            // 2. 澶勭悊鍗曡揣浣嶅叆搴�+            if (locNum == 1)
+            {
+                return FindSingleLocation(db, candidateRoadways);
+            }
+
+            // 3. 澶勭悊鍙岃揣浣嶅叆搴�+            return FindDoubleLocations(db, candidateRoadways);
+        }
+
+        /// <summary>
+        /// 鑾峰彇鍊欓�宸烽亾鍒楄〃锛堟寜绛栫暐鎺掑簭锛�+        /// </summary>
+        private static List<int> GetCandidateRoadways(SqlSugarClient db, string itemCode)
+        {
+            var list = new List<int>();
+            // 绛栫暐1锛氬贩閬撳唴鍚岃鏍肩墿鏂�< 10 鐨勫贩閬擄紙鎸夋暟閲忓崌搴忥級
+            var materialRoadwayGroup = db.Queryable<Location>()
+                        // 琛ㄥ埆鍚嶏細a = Location, b = LocCntrRel, c = CntrItemRel
+                        .LeftJoin<LocCntrRel>((a, b) => a.S_CODE == b.S_LOC_CODE)
+                        .LeftJoin<CntrItemRel>((a, b, c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
+
+                        // 鍩虹绛涢�鏉′欢锛堟墍鏈変綅缃級
+                        .Where((a, b, c) =>
+                            a.S_AREA_CODE == Settings.stockArea &&  // 鎸囧畾鍖哄煙
+                            a.N_LOCK_STATE == 0 &&                 // 鏈攣瀹�+                            a.C_ENABLE == "Y")                     // 鍚敤鐘舵�
+
+                        // 鎸夊贩閬撳垎缁勶紙浣跨敤鍘熷琛ㄥ瓧娈碉級
+                        .GroupBy((a, b, c) => a.N_ROADWAY)
+
+                        // 閫夋嫨鍒嗙粍缁撴灉锛堝寘鍚仛鍚堣绠楋級
+                        .Select((a, b, c) => new
+                        {
+                            Roadway = a.N_ROADWAY,  // 宸烽亾缂栧彿
+
+                            // 缁熻婊¤冻鐗瑰畾鏉′欢鐨勬暟閲忥細
+                            // 1. 褰撳墠鏁伴噺=1 (a.N_CURRENT_NUM == 1)
+                            // 2. 鐗╂枡鍖归厤 (c.S_ITEM_CODE == itemCode)
+                            // 3. 瀹瑰櫒鍏宠仈瀛樺湪 (b.S_CNTR_CODE != null)
+                            validCount = SqlFunc.AggregateSum(SqlFunc.IIF(
+                                a.N_CURRENT_NUM == 1 &&
+                                c.S_ITEM_CODE == itemCode &&
+                                b.S_CNTR_CODE != null,
+                                1, 0))
+                        })
+                       .ToList();
+
+            
+
+            if (materialRoadwayGroup.Count > 0)
+            {
+                list = materialRoadwayGroup.Where(a => a.validCount < 10).OrderBy(a => a.validCount).Select(a => a.Roadway).ToList();
+            }
+
+            if (list.Count == 0)
+            {
+                // 绛栫暐2锛氭墍鏈夊贩閬撴寜绌鸿揣浣嶆暟闄嶅簭鎺掑簭
+                materialRoadwayGroup = db.Queryable<Location>()
+                    .Where(a =>
+                        a.S_AREA_CODE == Settings.stockArea &&
+                        a.N_CURRENT_NUM == 0 &&
+                        a.N_LOCK_STATE == 0 &&
+                        a.C_ENABLE == "Y")
+                    .GroupBy(a => a.N_ROADWAY)
+                    .Select(a => new { Roadway = a.N_ROADWAY, validCount = SqlFunc.AggregateCount(a.S_CODE) })
+                    .ToList();
+
+                list = materialRoadwayGroup.OrderByDescending(a => a.validCount).Select(a => a.Roadway).ToList();
+            }
+            return list;
+        }
+
+        /// <summary>
+        /// 鏌ユ壘鍗曡揣浣�+        /// </summary>
+        private static EndLocGroup FindSingleLocation(SqlSugarClient db, List<int> candidateRoadways)
+        {
+            foreach (var roadway in candidateRoadways)
+            {
+                var location = db.Queryable<Location>()
+                    .Where(a =>
+                        a.S_AREA_CODE == Settings.stockArea &&
+                        a.N_ROADWAY == roadway &&
+                        a.N_CURRENT_NUM == 0 &&
+                        a.N_LOCK_STATE == 0 &&
+                        a.C_ENABLE == "Y")
+                    .OrderBy(a => a.N_LAYER)
+                    .OrderBy(a => a.N_COL)
+                    .First();
+
+                if (location != null)
+                {
+                    return new EndLocGroup
+                    {
+                        endLocList = new List<Location> { location }
+                    };
+                }
+            }
+            return new EndLocGroup();
+        }
+
+        /// <summary>
+        /// 鏌ユ壘鍙岃揣浣嶏紙浼樺寲鐩搁偦璐т綅鏌ユ壘锛�+        /// </summary>
+        private static EndLocGroup FindDoubleLocations(SqlSugarClient db, List<int> candidateRoadways)
+        {
+            // 鍏堝皾璇曟壘鐩搁偦璐т綅
+            foreach (var roadway in candidateRoadways)
+            {
+                // 涓�鎬ц幏鍙栧贩閬撴墍鏈夌┖璐т綅锛堝噺灏慏B鏌ヨ锛�+                var emptyLocs = db.Queryable<Location>()
+                    .Where(a =>
+                        a.S_AREA_CODE == Settings.stockArea &&
+                        a.N_ROADWAY == roadway &&
+                        a.N_CURRENT_NUM == 0 &&
+                        a.N_LOCK_STATE == 0 &&
+                        a.C_ENABLE == "Y")
+                    .OrderBy(a => a.N_LAYER)
+                    .OrderBy(a => a.N_COL)
+                    .ToList();
+
+                if (emptyLocs.Count < 2) continue;
+
+                // 鍦ㄥ唴瀛樹腑鏌ユ壘鐩搁偦璐т綅锛堥珮鎬ц兘锛�+                var adjacentPair = FindAdjacentLocations(emptyLocs);
+                if (adjacentPair != null)
+                {
+                    return CreateDoubleLocGroup(adjacentPair);
+                }
+            }
+
+            // 娌℃湁鐩搁偦璐т綅鏃讹紝鍙栦换鎰忎袱涓揣浣�+            foreach (var roadway in candidateRoadways)
+            {
+                var emptyLocs = db.Queryable<Location>()
+                    .Where(a =>
+                        a.S_AREA_CODE == Settings.stockArea &&
+                        a.N_ROADWAY == roadway &&
+                        a.N_CURRENT_NUM == 0 &&
+                        a.N_LOCK_STATE == 0 &&
+                        a.C_ENABLE == "Y")
+                    .OrderBy(a => a.N_LAYER)
+                    .OrderBy(a => a.N_COL)
+                    .Take(2)
+                    .ToList();
+
+                if (emptyLocs.Count == 2)
+                {
+                    return CreateDoubleLocGroup(emptyLocs);
+                }
+            }
+
+            return new EndLocGroup();
+        }
+
+        /// <summary>
+        /// 鍦ㄥ唴瀛樹腑鏌ユ壘鐩搁偦璐т綅锛堥珮鏁堢畻娉曪級
+        /// </summary>
+        private static List<Location> FindAdjacentLocations(List<Location> locations)
+        {
+            // 鎸夊眰->鍒楁帓搴忥紝渚夸簬鏌ユ壘鐩搁偦
+            var sorted = locations
+                .OrderBy(l => l.N_LAYER)
+                .ThenBy(l => l.N_ROW)
+                .ThenBy(l => l.N_COL)
+                .ToList();
+
+            for (int i = 0; i < sorted.Count - 1; i++)
+            {
+                var current = sorted[i];
+                var next = sorted[i + 1];
+
+                // 鍒ゆ柇鏄惁鍚屼竴灞備笖鐩搁偦鍒�+                if (current.N_LAYER == next.N_LAYER &&
+                    current.N_COL + 1 == next.N_COL)
+                {
+                    return new List<Location> { current, next };
+                }
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// 鍒涘缓鍙岃揣浣嶈繑鍥炵粨鏋�+        /// </summary>
+        private static EndLocGroup CreateDoubleLocGroup(List<Location> locations)
+        {
+            return new EndLocGroup
+            {
+                endLocList = locations,
+                groupNo = locations.GroupBy(a => a.N_ROADWAY).Count() == 1
+                    ? WMSHelper.GenerateTaskGroupNo()
+                    : null
+            };
+        }
+
+        public class EndLocGroup
+        {
+            public string groupNo { get; set; }
+            public List<Location> endLocList { get; set; }
+        }
+
+        /// <summary>
+        /// 鏌ヨ鍑哄簱寮�璐т綅
+        /// 1.璁$畻锛�.宸烽亾涓嶆姤璀︺�2.鐗╂枡鐘舵�OK銆�.灏忎簬澶辨晥鏃堕棿 澶т簬绛変簬鐢熸晥鏃堕棿 4.鍔犳�鏂欏厛鍑恒�5.鍏堝叆鍏堝嚭锛堢敓浜ф椂闂达級锛夊嚭搴撶墿鏂�+        /// 2.鍚岀瓑鏉′欢涓嬶紝浼樺厛鍙栧墠涓�墭璐х殑鐩搁偦璐т綅(鏆傛椂涓嶅仛鑰冭檻锛岄渶纭畾鍏堝叆鍏堝嚭锛堢敓浜ф椂闂达級鏄寜澶╃畻锛岃繕鏄簿纭埌鏃跺垎绉�
+        /// </summary>
+        /// <param name="itemCode"></param>
+        /// <param name="prevLoc"></param>
+        public static Location getOutStockStartLoc(string itemCode, Location prevLoc = null) 
+        {
+            var db = new SqlHelper<object>().GetInstance();
+            Location startLoc = null;
+
+            // 1.鏌ヨ锛堢墿鏂欑姸鎬丱K 锛屼笖灏忎簬澶辨晥鏃堕棿锛屽ぇ浜庣瓑浜庣敓鏁堟椂闂达級鍑哄簱鐗╂枡锛屽苟鎸夊姞鎬ユ枡鍏堝嚭锛屽厛鍏ュ厛鍑猴紙鐢熶骇鏃堕棿锛夌殑鍘熷垯杩涜鎺掑簭
+            var query = db.Queryable<Location>()
+               .LeftJoin<LocCntrRel>((a, b) => a.S_CODE == b.S_LOC_CODE)
+               .LeftJoin<CntrItemRel>((a, b, c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
+               .Where((a, b, c) => a.S_AREA_CODE == Settings.stockArea
+                               && a.N_CURRENT_NUM == 1
+                               && a.N_LOCK_STATE == 0
+                               && a.C_ENABLE == "Y"
+                               && b.S_CNTR_CODE != null
+                               );
+
+            if (itemCode != null)
+            {
+                query = query.Where((a, b, c) => c.S_ITEM_CODE == itemCode
+                               && c.S_ITEM_STATE == "OK"
+                               && SqlFunc.ToDate(c.S_EFFECTIVE_TIME) <= SqlFunc.GetDate()  // 鐢熸晥鏃堕棿鏃╀簬褰撳墠鏃堕棿
+                               && SqlFunc.ToDate(c.S_EXPIRATION_TIME) >= SqlFunc.GetDate() // 澶辨晥鏃堕棿鏅氫簬褰撳墠鏃堕棿
+                               && c.S_EFFECTIVE_TIME != null
+                               && c.S_EXPIRATION_TIME != null)
+                            .OrderByDescending((a, b, c) => c.N_URGENT_FLAG)
+                            .OrderBy((a, b, c) => c.S_TXNDATE);
+            }
+            else 
+            {
+                query = query.Where((a, b, c) => c.S_ITEM_CODE == itemCode);
+            }
+            var outLocList = query.ToList();
+
+            if (outLocList.Count > 0)
+            {
+                foreach (var loc in outLocList)
+                {
+                    // 鏌ヨ宸烽亾鏄惁姝e父锛屽紓甯歌烦杩�+                    var stackerStates = WCSDispatch.getStackerState(loc.N_ROADWAY);
+                    if ( false  /*stackerStates.Count == 0 || stackerStates[0].roadway_state == "0" || stackerStates[0].roadway_state == "3"*/) 
+                    {
+                        continue;
+                    }
+
+                    startLoc = loc;
+                    break;
+                }
+            }
+            return startLoc;
+
+        }
+
+        public class StartLocGroup
+        {
+            public string groupNo {  get; set; }
+            public List<Location> startLocList { get; set; }
         }
 
         /// <summary>
@@ -543,29 +817,69 @@
         /// 鏌ヨ宸烽亾浠诲姟鏈�皯鐨勬帴椹充綅
         /// </summary>
         /// <returns></returns>
-        public static Location getMinTaskMiddleLoc(int type) 
+        public static Location getMinTaskMiddleLoc(int type , int roadway = 0 , int excludeRoadway = 0) 
         {
             Location location = new Location();
             var db = new SqlHelper<object>().GetInstance();
-            var roadwayGroup = db.Queryable<Location>()
-                .LeftJoin<WCSTask>((a,b) => a.S_CODE == b.S_END_LOC && b.N_B_STATE < 3)
-                .Where((a, b) => a.S_AREA_CODE == Settings.stockArea && b.S_CODE != null )
-                .GroupBy((a, b) => a.N_ROADWAY)
-                .Select( (a, b) => new { roadway = a.N_ROADWAY  , num = SqlFunc.AggregateDistinctCount(a.S_CODE)})
-                .OrderBy(a => a.num)
-                .ToList();
+
+            var query = db.Queryable<Location>()
+                    .LeftJoin<WCSTask>((a, b) => a.S_CODE == b.S_END_LOC && b.N_B_STATE < 3)
+                    .Where((a, b) => a.S_AREA_CODE == Settings.stockArea);
+
+            if (roadway != 0) 
+            {
+                query = query.Where((a, b) => a.N_ROADWAY == roadway);
+            }
+            if (excludeRoadway != 0) 
+            {
+                query = query.Where((a, b) => a.N_ROADWAY != excludeRoadway);
+            }
+
+            var roadwayGroup = query.GroupBy((a, b) => a.N_ROADWAY)
+                    .Select((a, b) => new { roadway = a.N_ROADWAY, num = SqlFunc.AggregateDistinctCount(b.S_CODE != null) })
+                    .OrderBy(a => a.num)
+                    .ToList();
 
             foreach (var item in roadwayGroup)
             {
-                // 1.鏌ヨ宸烽亾鍐呯殑鍫嗗灈鏈虹姸鎬佹槸鍚︽甯�-
-                // 2.鏌ヨ鎺ラ┏浣�-                var connectLoc = Settings.connectLocList.Where(a => a.type == type && a.roadway == item.roadway).FirstOrDefault();
+                var connectLoc = Settings.connectLocList.Where(a => a.roadway == item.roadway).FirstOrDefault();
                 if (connectLoc != null) 
                 {
                     location = LocationHelper.GetLoc(connectLoc.locCode);
                     break;
                 }
+            }
+            return location;
+        }
+
+        /// <summary>
+        /// 鏌ヨ涓婄嚎璐т綅
+        /// </summary>
+        /// <param name="type"></param>
+        /// <returns></returns>
+        public static Location getOnlneLoc(int type)
+        {
+            Location location = null;
+            var connectLoc = Settings.onLineLocList.Where(a => a.type == type).FirstOrDefault();
+            if (connectLoc != null)
+            {
+                location = LocationHelper.GetLoc(connectLoc.locCode);
+            }
+            return location;
+        }
+
+        /// <summary>
+        /// 鏌ヨ鍙枡寮傚父鎺掑嚭浣�+        /// </summary>
+        /// <param name="row"></param>
+        /// <returns></returns>
+        public static Location getCallOutLoc(int row)
+        {
+            Location location = null;
+            var connectLoc = Settings.callOutLocList.Where(a => a.row == row).FirstOrDefault();
+            if (connectLoc != null)
+            {
+                location = LocationHelper.GetLoc(connectLoc.locCode);
             }
             return location;
         }
@@ -599,6 +913,12 @@
             return null;
         }
 
+        /// <summary>
+        /// 缁戝畾鏉$爜鐗╂枡淇℃伅
+        /// </summary>
+        /// <param name="cntrCode"></param>
+        /// <param name="greenTireInformation"></param>
+        /// <returns></returns>
         public static bool bindBarcodeItemInfo( string cntrCode,GreenTireInformation greenTireInformation) 
         {
             bool result = false;
@@ -655,5 +975,28 @@
             }
             return result;
         }
+
+        /// <summary>
+        /// 鏌ヨ纭寲宸ュ崟
+        /// </summary>
+        /// <param name="dateShift"></param>
+        /// <param name="mcn"></param>
+        /// <param name="shift"></param>
+        /// <returns></returns>
+        public static ProductionShedule getProductionShedule(string dateShift ,string mcn ,string shift) 
+        {
+            var db = new SqlHelper<object>().GetInstance();
+            return db.Queryable<ProductionShedule>().Where(a => a.DATESHIFT == dateShift && a.MCN == mcn && a.SHIFT == shift).First();
+        }
+
+        /// <summary>
+        /// 鏌ヨ鑳氳儙瀹屾垚纭寲鐨勬暟閲�+        /// </summary>
+        /// <returns></returns>
+        public static int getEmbryoFinishNum(string dateShift, string mcn, string shift) 
+        {
+            var db = new SqlHelper<object>().GetInstance();
+            return db.Queryable<EmbryoFinishRecord>().Where(a => a.DATE_SHIFT == dateShift && a.CUR_MCN == mcn && a.CUR_SHIFT == shift).Count();
+        }
     }    
 }

--
Gitblit v1.9.1