From 611118f04720931e31f87ae5d395318c4085db5e Mon Sep 17 00:00:00 2001
From: zwl <1051256694@qq.com>
Date: 星期一, 27 四月 2026 23:40:38 +0800
Subject: [PATCH] 1.双伸空托盘入库规则完善 2.完善双伸只找一边的问题 3.完善重新分配库位问题

---
 src/main/java/com/zy/common/service/CommonService.java |  294 +++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 245 insertions(+), 49 deletions(-)

diff --git a/src/main/java/com/zy/common/service/CommonService.java b/src/main/java/com/zy/common/service/CommonService.java
index c4f7002..2f2aae0 100644
--- a/src/main/java/com/zy/common/service/CommonService.java
+++ b/src/main/java/com/zy/common/service/CommonService.java
@@ -28,6 +28,7 @@
 import java.time.format.DateTimeFormatter;
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
@@ -224,12 +225,32 @@
     }
 
     /**
-     * 渚� 6.15 閲嶅垎閰嶆帴鍙e鐢細鎸夊閮ㄦ寚瀹氱殑鍫嗗灈鏈洪『搴忥紝鍦ㄦ寚瀹氬簱鍖哄唴鎵炬柊鐨勫叆搴撲綅銆�
+     * 渚涢噸鍒嗛厤鎺ュ彛澶嶇敤锛氭寜澶栭儴鎸囧畾鐨勫爢鍨涙満椤哄簭鎵炬柊鐨勫叆搴撲綅銆�
      *
      * 杩欓噷涓嶆帹杩� row_lastno 娓告爣锛屽彧璐熻矗涓�娆℃�х殑璺緞鏍¢獙 + 璁惧鏍¢獙 + 绌哄簱浣嶆悳绱€��
      */
+    public StartupDto findRun2InboundLocByCandidateCrnNos(Integer sourceStaNo, Integer staDescId,
+                                                          List<Integer> candidateCrnNos, LocTypeDto locTypeDto) {
+        return findRun2InboundLocByCandidateCrnNos(sourceStaNo, staDescId, null, candidateCrnNos, locTypeDto, null);
+    }
+
+    public StartupDto findRun2InboundLocByCandidateCrnNos(Integer sourceStaNo, Integer staDescId,
+                                                          List<Integer> candidateCrnNos, LocTypeDto locTypeDto,
+                                                          Integer targetLev) {
+        return findRun2InboundLocByCandidateCrnNos(sourceStaNo, staDescId, null, candidateCrnNos, locTypeDto, targetLev);
+    }
+
+    /**
+     * 鍏煎鏃ц皟鐢細鎸夊閮ㄦ寚瀹氱殑鍫嗗灈鏈洪『搴忥紝鍦ㄦ寚瀹氬簱鍖哄唴鎵炬柊鐨勫叆搴撲綅銆�
+     */
     public StartupDto findRun2InboundLocByCandidateCrnNos(Integer sourceStaNo, Integer staDescId, Integer preferredArea,
                                                           List<Integer> candidateCrnNos, LocTypeDto locTypeDto) {
+        return findRun2InboundLocByCandidateCrnNos(sourceStaNo, staDescId, preferredArea, candidateCrnNos, locTypeDto, null);
+    }
+
+    private StartupDto findRun2InboundLocByCandidateCrnNos(Integer sourceStaNo, Integer staDescId, Integer preferredArea,
+                                                           List<Integer> candidateCrnNos, LocTypeDto locTypeDto,
+                                                           Integer targetLev) {
         if (sourceStaNo == null) {
             throw new CoolException("婧愮珯涓嶈兘涓虹┖");
         }
@@ -253,12 +274,9 @@
         if (Cools.isEmpty(rowLastnoType)) {
             throw new CoolException("鏁版嵁寮傚父锛岃鑱旂郴绠$悊鍛�===銆嬪簱浣嶈鍒欑被鍨嬫湭鐭�");
         }
-        if (rowLastnoType.getType() != 1 && rowLastnoType.getType() != 2) {
-            throw new CoolException("褰撳墠浠撳簱涓嶆敮鎸侀噸鏂板垎閰嶅叆搴撲綅");
-        }
         StartupDto startupDto = new StartupDto();
         LocMast locMast = findRun2EmptyLocByCrnNos(searchRowLastno, rowLastnoType, candidateCrnNos, locTypeDto,
-                staDescId, sourceStaNo, startupDto, preferredArea, null, "reassign-inbound");
+                staDescId, sourceStaNo, startupDto, preferredArea, null, "reassign-inbound", targetLev);
         if (Cools.isEmpty(locMast) || !"O".equals(locMast.getLocSts())) {
             return null;
         }
@@ -1569,6 +1587,22 @@
     private LocMast findRun2EmptyLocByCrnNos(RowLastno rowLastno, RowLastnoType rowLastnoType, List<Integer> candidateCrnNos,
                                              LocTypeDto locTypeDto, Integer staDescId, Integer sourceStaNo, StartupDto startupDto,
                                              Integer preferredArea, FindLocNoAttributeVo findLocNoAttributeVo, String stage, boolean routeRequired) {
+        return findRun2EmptyLocByCrnNos(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto,
+                staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, stage, routeRequired, null);
+    }
+
+    private LocMast findRun2EmptyLocByCrnNos(RowLastno rowLastno, RowLastnoType rowLastnoType, List<Integer> candidateCrnNos,
+                                             LocTypeDto locTypeDto, Integer staDescId, Integer sourceStaNo, StartupDto startupDto,
+                                             Integer preferredArea, FindLocNoAttributeVo findLocNoAttributeVo, String stage,
+                                             Integer targetLev) {
+        return findRun2EmptyLocByCrnNos(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto,
+                staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, stage, true, targetLev);
+    }
+
+    private LocMast findRun2EmptyLocByCrnNos(RowLastno rowLastno, RowLastnoType rowLastnoType, List<Integer> candidateCrnNos,
+                                             LocTypeDto locTypeDto, Integer staDescId, Integer sourceStaNo, StartupDto startupDto,
+                                             Integer preferredArea, FindLocNoAttributeVo findLocNoAttributeVo, String stage,
+                                             boolean routeRequired, Integer targetLev) {
         if (Cools.isEmpty(candidateCrnNos)) {
             log.warn("run2 skip empty candidate list. stage={}, sourceStaNo={}, preferredArea={}, spec={}",
                     stage, sourceStaNo, preferredArea, JSON.toJSONString(locTypeDto));
@@ -1580,7 +1614,7 @@
         List<Integer> locTypeBlockedCrns = new ArrayList<>();
         return findRun2EmptyLocByCrnNosRecursively(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto,
                 staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, stage, routeRequired, 0,
-                crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns);
+                crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns, targetLev);
     }
 
     private LocMast findRun2EmptyLocByCrnNosRecursively(RowLastno rowLastno, RowLastnoType rowLastnoType,
@@ -1589,7 +1623,8 @@
                                                         Integer preferredArea, FindLocNoAttributeVo findLocNoAttributeVo,
                                                         String stage, boolean routeRequired, int index,
                                                         List<Integer> crnErrorCrns, List<Integer> routeBlockedCrns,
-                                                        List<Integer> noEmptyCrns, List<Integer> locTypeBlockedCrns) {
+                                                        List<Integer> noEmptyCrns, List<Integer> locTypeBlockedCrns,
+                                                        Integer targetLev) {
         if (index >= candidateCrnNos.size()) {
             logRun2NoMatch(stage, sourceStaNo, preferredArea, candidateCrnNos, locTypeDto,
                     crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns);
@@ -1600,18 +1635,18 @@
             crnErrorCrns.add(candidateCrnNo);
             return findRun2EmptyLocByCrnNosRecursively(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto,
                     staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, stage, routeRequired, index + 1,
-                    crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns);
+                    crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns, targetLev);
         }
         Integer targetStaNo = routeRequired ? resolveTargetStaNo(rowLastno, staDescId, sourceStaNo, candidateCrnNo) : null;
         if (routeRequired && Utils.BooleanWhsTypeSta(rowLastno, staDescId) && targetStaNo == null) {
             routeBlockedCrns.add(candidateCrnNo);
             return findRun2EmptyLocByCrnNosRecursively(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto,
                     staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, stage, routeRequired, index + 1,
-                    crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns);
+                    crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns, targetLev);
         }
         Integer preferredNearRow = getCrnStartRow(rowLastno, candidateCrnNo);
         LocMast candidateLoc = findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, candidateCrnNo,
-                preferredNearRow, locTypeDto, findLocNoAttributeVo);
+                preferredNearRow, locTypeDto, findLocNoAttributeVo, targetLev);
         if (Cools.isEmpty(candidateLoc)) {
             int availableLocCount = countAssignableLocForCrn(rowLastno, rowLastnoType, candidateCrnNo,
                     preferredNearRow == null ? 0 : preferredNearRow, locTypeDto);
@@ -1622,7 +1657,7 @@
             }
             return findRun2EmptyLocByCrnNosRecursively(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto,
                     staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, stage, routeRequired, index + 1,
-                    crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns);
+                    crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns, targetLev);
         }
         if (targetStaNo != null) {
             startupDto.setStaNo(targetStaNo);
@@ -1907,6 +1942,10 @@
         return locTypeDto == null || VersionUtils.locMoveCheckLocTypeComplete(locMast, locTypeDto);
     }
 
+    private boolean matchesTargetLev(LocMast locMast, Integer targetLev) {
+        return targetLev == null || targetLev <= 0 || (locMast != null && Objects.equals(locMast.getLev1(), targetLev));
+    }
+
     /**
      * 鏌ヨ鏌愪竴鎺掍笂鐨勬墍鏈夌┖搴撲綅锛屽苟鎸夊崟浼�/鍙屼几绛栫暐涓庨娆℃帓搴忋��
      */
@@ -1924,6 +1963,13 @@
     private List<LocMast> findOpenLocsByRow(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer row,
                                             Integer crnNo, LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo,
                                             boolean singleExtension, boolean ignoreFreqType) {
+        return findOpenLocsByRow(rowLastno, rowLastnoType, row, crnNo, locTypeDto, findLocNoAttributeVo,
+                singleExtension, ignoreFreqType, null);
+    }
+
+    private List<LocMast> findOpenLocsByRow(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer row,
+                                            Integer crnNo, LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo,
+                                            boolean singleExtension, boolean ignoreFreqType, Integer targetLev) {
         List<LocMast> result = new ArrayList<LocMast>();
         if (row == null) {
             return result;
@@ -1933,11 +1979,14 @@
         if (crnNo != null) {
             wrapper.eq("crn_no", crnNo);
         }
+        if (targetLev != null && targetLev > 0) {
+            wrapper.eq("lev1", targetLev);
+        }
         applyLocTypeFilters(wrapper, locTypeDto, true);
         List<LocMast> locMasts = locMastService.selectList(wrapper);
         List<LocMast> sortedLocMasts = sortLocCandidates(locMasts, findLocNoAttributeVo, ignoreFreqType);
         for (LocMast locMast : sortedLocMasts) {
-            if (matchesLocType(locMast, locTypeDto)) {
+            if (matchesLocType(locMast, locTypeDto) && matchesTargetLev(locMast, targetLev)) {
                 result.add(locMast);
             }
         }
@@ -2046,26 +2095,27 @@
 
     /**
      * 鍙屼几鍫嗗灈鏈哄悓璐т紭鍏堬細
-     * 鍏堟壘娣卞簱浣嶄腑 standby1 鐩稿悓涓旂姸鎬佷负 F 鐨勮揣浣嶏紝鍐嶆鏌ュ叾瀵瑰簲娴呭簱浣嶆槸鍚︿负绌恒��
+     * 鍏堟壘娣卞簱浣嶄腑鍚岃揣涓旂姸鎬佷负 F 鐨勮揣浣嶏紝鍐嶆鏌ュ叾瀵瑰簲娴呭簱浣嶆槸鍚︿负绌恒��
+     * 绌烘墭鐩樿姹傚垯鎸� matnr=emptyPallet 璇嗗埆锛屾繁浣嶅凡鏈夌┖鎵樼洏鏃朵紭鍏堣繑鍥炲搴旀祬浣嶃��
      */
     private LocMast findDoubleExtensionSameGoodsPreferredLoc(RowLastno rowLastno, RowLastnoType rowLastnoType,
                                                              Integer crnNo, CrnDepthRuleProfile profile,
                                                              LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo) {
-        if (profile == null || !profile.isDoubleExtension() || findLocNoAttributeVo == null
-                || Cools.isEmpty(findLocNoAttributeVo.getStandby1())) {
+        if (profile == null || !profile.isDoubleExtension() || findLocNoAttributeVo == null) {
             return null;
         }
+        boolean emptyPalletRequest = "emptyPallet".equalsIgnoreCase(findLocNoAttributeVo.getMatnr());
         String standby1 = findLocNoAttributeVo.getStandby1();
-        LinkedHashSet<Integer> processedDeepRows = new LinkedHashSet<Integer>();
-        for (Integer searchRow : profile.getSearchRows()) {
-            if (searchRow == null || !profile.isDeepRow(searchRow) || !processedDeepRows.add(searchRow)) {
+        if (!emptyPalletRequest && Cools.isEmpty(standby1)) {
+            return null;
+        }
+        List<Integer> orderedShallowRows = orderDoubleExtensionShallowRows(rowLastno, rowLastnoType, crnNo, profile);
+        for (Integer shallowRow : orderedShallowRows) {
+            Integer deepRow = profile.getPairedDeepRow(shallowRow);
+            if (deepRow == null) {
                 continue;
             }
-            Integer shallowRow = profile.getPairedShallowRow(searchRow);
-            if (shallowRow == null) {
-                continue;
-            }
-            List<LocMast> deepLocs = findOccupiedLocsByRow(searchRow, crnNo, findLocNoAttributeVo);
+            List<LocMast> deepLocs = findOccupiedLocsByRow(deepRow, crnNo, findLocNoAttributeVo);
             if (Cools.isEmpty(deepLocs)) {
                 continue;
             }
@@ -2079,9 +2129,14 @@
             if (Cools.isEmpty(deepLocNos)) {
                 continue;
             }
-            List<LocDetl> sameGoodsLocDetls = locDetlService.selectList(new EntityWrapper<LocDetl>()
-                    .eq("standby1", standby1)
-                    .in("loc_no", deepLocNos));
+            EntityWrapper<LocDetl> detlWrapper = new EntityWrapper<LocDetl>();
+            detlWrapper.in("loc_no", deepLocNos);
+            if (emptyPalletRequest) {
+                detlWrapper.eq("matnr", findLocNoAttributeVo.getMatnr());
+            } else {
+                detlWrapper.eq("standby1", standby1);
+            }
+            List<LocDetl> sameGoodsLocDetls = locDetlService.selectList(detlWrapper);
             if (Cools.isEmpty(sameGoodsLocDetls)) {
                 continue;
             }
@@ -2107,6 +2162,115 @@
             }
         }
         return null;
+    }
+
+    /**
+     * 鍙屼几鍫嗗灈鏈烘寜褰撳墠涓や晶璐熻浇鎺掑簭娴呬綅鎼滅储椤哄簭銆�
+     *
+     * 璐熻浇瓒婁綆鐨勬祬/娣遍厤瀵硅秺浼樺厛锛岄伩鍏嶉暱鏈熷彧鍛戒腑鍚屼竴渚с��
+     */
+    private List<Integer> orderDoubleExtensionShallowRows(RowLastno rowLastno, RowLastnoType rowLastnoType,
+                                                          Integer crnNo, CrnDepthRuleProfile profile) {
+        List<Integer> orderedShallowRows = new ArrayList<Integer>();
+        if (profile == null || !profile.isDoubleExtension() || Cools.isEmpty(profile.getShallowRows())) {
+            return orderedShallowRows;
+        }
+        orderedShallowRows.addAll(profile.getShallowRows());
+        final Map<Integer, Integer> originalOrder = new HashMap<Integer, Integer>();
+        for (int index = 0; index < orderedShallowRows.size(); index++) {
+            originalOrder.put(orderedShallowRows.get(index), index);
+        }
+        final Map<Integer, Integer> pairLoadCache = new HashMap<Integer, Integer>();
+        for (Integer shallowRow : orderedShallowRows) {
+            pairLoadCache.put(shallowRow, countDoubleExtensionPairLoad(rowLastno, rowLastnoType, crnNo, profile, shallowRow));
+        }
+        orderedShallowRows.sort(Comparator
+                .comparingInt((Integer row) -> pairLoadCache.getOrDefault(row, Integer.MAX_VALUE))
+                .thenComparingInt(row -> originalOrder.getOrDefault(row, Integer.MAX_VALUE)));
+        return rotateEqualLoadGroupsByCurrentRow(orderedShallowRows, rowLastno, pairLoadCache);
+    }
+
+    /**
+     * 绛夎浇鏃讹紝鎸夊綋鍓嶆帓娓告爣鏃嬭浆缁勫唴椤哄簭锛岄伩鍏嶉暱鏈熷浐瀹氬懡涓悓涓�渚ф繁搴撲綅銆�
+     */
+    private List<Integer> rotateEqualLoadGroupsByCurrentRow(List<Integer> orderedRows, RowLastno rowLastno,
+                                                            Map<Integer, Integer> pairLoadCache) {
+        if (Cools.isEmpty(orderedRows) || rowLastno == null) {
+            return orderedRows;
+        }
+        Integer currentRow = rowLastno.getCurrentRow();
+        if (currentRow == null || currentRow <= 0) {
+            return orderedRows;
+        }
+        List<Integer> rotatedRows = new ArrayList<Integer>(orderedRows.size());
+        int index = 0;
+        while (index < orderedRows.size()) {
+            Integer currentLoad = pairLoadCache.get(orderedRows.get(index));
+            int groupStart = index;
+            while (index < orderedRows.size() && Objects.equals(pairLoadCache.get(orderedRows.get(index)), currentLoad)) {
+                index++;
+            }
+            List<Integer> sameLoadRows = new ArrayList<Integer>(orderedRows.subList(groupStart, index));
+            rotateShallowRowsByCurrentRow(sameLoadRows, currentRow);
+            rotatedRows.addAll(sameLoadRows);
+        }
+        return rotatedRows;
+    }
+
+    private void rotateShallowRowsByCurrentRow(List<Integer> shallowRows, Integer currentRow) {
+        if (Cools.isEmpty(shallowRows) || shallowRows.size() <= 1 || currentRow == null) {
+            return;
+        }
+        int pivotIndex = -1;
+        for (int i = 0; i < shallowRows.size(); i++) {
+            Integer row = shallowRows.get(i);
+            if (row != null && row > currentRow) {
+                pivotIndex = i;
+                break;
+            }
+        }
+        if (pivotIndex <= 0) {
+            return;
+        }
+        List<Integer> rotated = new ArrayList<Integer>(shallowRows.size());
+        rotated.addAll(shallowRows.subList(pivotIndex, shallowRows.size()));
+        rotated.addAll(shallowRows.subList(0, pivotIndex));
+        shallowRows.clear();
+        shallowRows.addAll(rotated);
+    }
+
+    /**
+     * 缁熻鍙屼几娴�/娣遍厤瀵圭殑褰撳墠宸插崰鐢ㄥ簱浣嶆暟閲忋��
+     */
+    private int countDoubleExtensionPairLoad(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer crnNo,
+                                             CrnDepthRuleProfile profile, Integer shallowRow) {
+        if (profile == null || shallowRow == null) {
+            return Integer.MAX_VALUE;
+        }
+        int count = countOccupiedLocsByRow(rowLastno, rowLastnoType, shallowRow, crnNo);
+        Integer deepRow = profile.getPairedDeepRow(shallowRow);
+        if (deepRow != null) {
+            count += countOccupiedLocsByRow(rowLastno, rowLastnoType, deepRow, crnNo);
+        }
+        return count;
+    }
+
+    /**
+     * 缁熻鏌愪竴鎺掑綋鍓嶅凡鍗犵敤/棰勭害鐨勫簱瀛樻暟閲忋��
+     *
+     * 杩欓噷鎶� S/R/P/Q/D/X 閮界畻浣滆礋杞斤紝閬垮厤鎵归噺鍏ュ簱鏃跺彧鐪� F 瀵艰嚧鍒氶绾﹀嚭鍘荤殑搴撲綅涓嶅弬涓庡潎琛°��
+     */
+    private int countOccupiedLocsByRow(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer row, Integer crnNo) {
+        if (row == null) {
+            return Integer.MAX_VALUE;
+        }
+        Wrapper<LocMast> wrapper = new EntityWrapper<LocMast>()
+                .eq("row1", row)
+                .in("loc_sts", Arrays.asList("F", "S", "R", "P", "Q", "D", "X"));
+        if (crnNo != null) {
+            wrapper.eq("crn_no", crnNo);
+        }
+        return locMastService.selectCount(wrapper);
     }
 
     /**
@@ -2143,7 +2307,13 @@
     private LocMast findPairAssignableLoc(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer crnNo,
                                           Integer shallowRow, Integer deepRow, LocTypeDto locTypeDto,
                                           FindLocNoAttributeVo findLocNoAttributeVo) {
-        List<LocMast> shallowOpenLocs = findOpenLocsByRow(rowLastno, rowLastnoType, shallowRow, crnNo, locTypeDto, findLocNoAttributeVo, false);
+        return findPairAssignableLoc(rowLastno, rowLastnoType, crnNo, shallowRow, deepRow, locTypeDto, findLocNoAttributeVo, null);
+    }
+
+    private LocMast findPairAssignableLoc(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer crnNo,
+                                          Integer shallowRow, Integer deepRow, LocTypeDto locTypeDto,
+                                          FindLocNoAttributeVo findLocNoAttributeVo, Integer targetLev) {
+        List<LocMast> shallowOpenLocs = findOpenLocsByRow(rowLastno, rowLastnoType, shallowRow, crnNo, locTypeDto, findLocNoAttributeVo, false, false, targetLev);
         if (Cools.isEmpty(shallowOpenLocs)) {
             return null;
         }
@@ -2186,7 +2356,21 @@
 
     private LocMast findConfiguredEmptyLocForCrn(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer crnNo,
                                                  Integer preferredNearRow, LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo,
+                                                 Integer targetLev) {
+        return findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, crnNo, preferredNearRow, locTypeDto, findLocNoAttributeVo,
+                false, targetLev);
+    }
+
+    private LocMast findConfiguredEmptyLocForCrn(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer crnNo,
+                                                 Integer preferredNearRow, LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo,
                                                  boolean ignoreFreqType) {
+        return findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, crnNo, preferredNearRow, locTypeDto, findLocNoAttributeVo,
+                ignoreFreqType, null);
+    }
+
+    private LocMast findConfiguredEmptyLocForCrn(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer crnNo,
+                                                 Integer preferredNearRow, LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo,
+                                                 boolean ignoreFreqType, Integer targetLev) {
         if (rowLastno == null || crnNo == null) {
             return null;
         }
@@ -2196,43 +2380,55 @@
         }
         LocMast sameGoodsPreferredLoc = findDoubleExtensionSameGoodsPreferredLoc(rowLastno, rowLastnoType, crnNo,
                 profile, locTypeDto, findLocNoAttributeVo);
-        if (!Cools.isEmpty(sameGoodsPreferredLoc)) {
+        if (!Cools.isEmpty(sameGoodsPreferredLoc) && matchesTargetLev(sameGoodsPreferredLoc, targetLev)) {
             return sameGoodsPreferredLoc;
         }
-        LinkedHashSet<Integer> processedShallowRows = new LinkedHashSet<Integer>();
         boolean singleExtension = profile.isSingleExtension();
+        if (!singleExtension) {
+            List<Integer> orderedShallowRows = orderDoubleExtensionShallowRows(rowLastno, rowLastnoType, crnNo, profile);
+            for (Integer shallowRow : orderedShallowRows) {
+                if (shallowRow == null) {
+                    continue;
+                }
+                LocMast candidateLoc = findPairAssignableLoc(rowLastno, rowLastnoType, crnNo, shallowRow,
+                        profile.getPairedDeepRow(shallowRow), locTypeDto, findLocNoAttributeVo, targetLev);
+                if (!Cools.isEmpty(candidateLoc)) {
+                    return candidateLoc;
+                }
+            }
+            return null;
+        }
+        LinkedHashSet<Integer> processedShallowRows = new LinkedHashSet<Integer>();
         for (Integer searchRow : profile.getSearchRows()) {
             if (searchRow == null) {
                 continue;
             }
-            if (!singleExtension) {
-                if (profile.isShallowRow(searchRow)) {
-                    if (!processedShallowRows.add(searchRow)) {
+            if (profile.isShallowRow(searchRow)) {
+                if (!processedShallowRows.add(searchRow)) {
+                    continue;
+                }
+                LocMast candidateLoc = findPairAssignableLoc(rowLastno, rowLastnoType, crnNo, searchRow,
+                        profile.getPairedDeepRow(searchRow), locTypeDto, findLocNoAttributeVo, targetLev);
+                if (!Cools.isEmpty(candidateLoc)) {
+                    return candidateLoc;
+                }
+                continue;
+            }
+            if (profile.isDeepRow(searchRow)) {
+                Integer shallowRow = profile.getPairedShallowRow(searchRow);
+                if (shallowRow != null) {
+                    if (!processedShallowRows.add(shallowRow)) {
                         continue;
                     }
-                    LocMast candidateLoc = findPairAssignableLoc(rowLastno, rowLastnoType, crnNo, searchRow,
-                            profile.getPairedDeepRow(searchRow), locTypeDto, findLocNoAttributeVo);
+                    LocMast candidateLoc = findPairAssignableLoc(rowLastno, rowLastnoType, crnNo, shallowRow,
+                            searchRow, locTypeDto, findLocNoAttributeVo, targetLev);
                     if (!Cools.isEmpty(candidateLoc)) {
                         return candidateLoc;
                     }
                     continue;
                 }
-                if (profile.isDeepRow(searchRow)) {
-                    Integer shallowRow = profile.getPairedShallowRow(searchRow);
-                    if (shallowRow != null) {
-                        if (!processedShallowRows.add(shallowRow)) {
-                            continue;
-                        }
-                        LocMast candidateLoc = findPairAssignableLoc(rowLastno, rowLastnoType, crnNo, shallowRow,
-                                searchRow, locTypeDto, findLocNoAttributeVo);
-                        if (!Cools.isEmpty(candidateLoc)) {
-                            return candidateLoc;
-                        }
-                        continue;
-                    }
-                }
             }
-            List<LocMast> locMasts = findOpenLocsByRow(rowLastno, rowLastnoType, searchRow, crnNo, locTypeDto, findLocNoAttributeVo, singleExtension, ignoreFreqType);
+            List<LocMast> locMasts = findOpenLocsByRow(rowLastno, rowLastnoType, searchRow, crnNo, locTypeDto, findLocNoAttributeVo, singleExtension, ignoreFreqType, targetLev);
             if (!Cools.isEmpty(locMasts)) {
                 return locMasts.get(0);
             }

--
Gitblit v1.9.1