| | |
| | | import java.util.LinkedHashSet; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.Locale; |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | |
| | | public static Integer getStationStorageArea(Integer stationId) { |
| | | public static List<Integer> getStationStorageAreas(Integer stationId) { |
| | | if (stationId == null || stationId <= 0) { |
| | | return null; |
| | | return new ArrayList<>(); |
| | | } |
| | | BasDevpService basDevpService = SpringUtils.getBean(BasDevpService.class); |
| | | BasDevp station = basDevpService.selectById(stationId); |
| | | if (station == null) { |
| | | return new ArrayList<>(); |
| | | } |
| | | return parseStorageAreas(station.getArea()); |
| | | } |
| | | |
| | | public static Integer getStationStorageArea(Integer stationId) { |
| | | List<Integer> storageAreas = getStationStorageAreas(stationId); |
| | | if (Cools.isEmpty(storageAreas)) { |
| | | return null; |
| | | } |
| | | return parseStorageArea(station.getArea()); |
| | | return storageAreas.get(0); |
| | | } |
| | | |
| | | /** |
| | | * 生成入库找库位时的堆垛机优先顺序。 |
| | | * |
| | | * <p>处理规则: |
| | | * 1. 先根据入库站点查询所属库区。 |
| | | * 2. 先提取该库区内的堆垛机,并按可用空库位过滤不可用堆垛机。 |
| | | * 3. 当 {@code locType1 = 1} 时,先返回低库位堆垛机,再把同批堆垛机的高库位追加到后面。 |
| | | * 4. 对不存在、故障、不可入以及无空库位的堆垛机直接剔除。 |
| | | * |
| | | * <p>这里是只读排序工具,不再写回 {@code asr_row_lastno.crn_qty}。 |
| | | * {@code crn_qty} 在主数据里表示“堆垛机数量”,不能再被拿来当轮询游标,否则会把整仓配置写坏。 |
| | | * <p>当前语义已经切换为“站点第一优先池 + 第二优先池”的配置预览, |
| | | * 不再沿用旧的 area 顺序。 |
| | | * |
| | | * <p>返回结果中的每一项格式为: |
| | | * {@code {crnNo: 堆垛机号, locType1: 库位高低类型}} |
| | | * {@code {pool: 优先池编号, seq: 池内顺序, crnNo: 堆垛机号}} |
| | | * |
| | | * @param stationId 入库站点 |
| | | * @param locType1 目标库位高低类型,1=低库位,2=高库位 |
| | | * @param matnr 物料编码,传入 {@code emptyPallet} 时使用空板排序规则 |
| | | * @return 按优先级排好序的堆垛机列表 |
| | | * @param locType1 保留兼容参数,当前不参与排序 |
| | | * @param matnr 保留兼容参数,当前不参与排序 |
| | | * @return 按优先池顺序排好的堆垛机列表 |
| | | */ |
| | | public static List<Map<String, Integer>> getStationStorageAreaName(Integer stationId, Integer locType1, String matnr) { |
| | | List<Map<String, Integer>> result = new ArrayList<>(); |
| | | // 先定位入库站点所属库区。 |
| | | Integer storageArea = getStationStorageArea(stationId); |
| | | Integer whsType = GetWhsType(stationId); |
| | | if (storageArea == null || whsType == null || whsType <= 0) { |
| | | BasDevpService basDevpService = SpringUtils.getBean(BasDevpService.class); |
| | | BasDevp station = basDevpService.selectById(stationId); |
| | | if (station == null) { |
| | | return result; |
| | | } |
| | | RowLastnoService rowLastnoService = SpringUtils.getBean(RowLastnoService.class); |
| | | RowLastno rowLastno = rowLastnoService.selectById(whsType); |
| | | if (rowLastno == null) { |
| | | appendCrnPoolEntries(result, 1, distinctCrnNos(station.getInFirstCrnCsv())); |
| | | appendCrnPoolEntries(result, 2, distinctCrnNos(station.getInSecondCrnCsv())); |
| | | return result; |
| | | } |
| | | |
| | | BasCrnpService basCrnpService = SpringUtils.getBean(BasCrnpService.class); |
| | | LocMastService locMastService = SpringUtils.getBean(LocMastService.class); |
| | | boolean emptyPallet = "emptyPallet".equalsIgnoreCase(matnr); |
| | | public static List<Integer> parseCrnNos(String csv) { |
| | | List<Integer> crnNos = new ArrayList<>(); |
| | | if (Cools.isEmpty(csv)) { |
| | | return crnNos; |
| | | } |
| | | String normalized = csv.replace(",", ",") |
| | | .replace(";", ",") |
| | | .replace("、", ",") |
| | | .replaceAll("\\s+", ""); |
| | | if (normalized.isEmpty()) { |
| | | return crnNos; |
| | | } |
| | | for (String segment : normalized.split("[,;]")) { |
| | | if (segment == null || segment.isEmpty()) { |
| | | continue; |
| | | } |
| | | Integer crnNo = safeParseInt(segment); |
| | | if (crnNo == null || crnNo <= 0) { |
| | | throw new CoolException("堆垛机号格式错误:" + segment); |
| | | } |
| | | crnNos.add(crnNo); |
| | | } |
| | | return crnNos; |
| | | } |
| | | |
| | | // 先取当前库区对应的堆垛机。 |
| | | List<Integer> preferredCrnNos = getAreaCrnNos(storageArea, rowLastno); |
| | | List<Integer> preferredAvailableCrnNos = getAvailableCrnNos(preferredCrnNos, locType1, emptyPallet, basCrnpService, locMastService); |
| | | appendCrnLocTypeEntries(result, preferredAvailableCrnNos, locType1, emptyPallet, locMastService); |
| | | public static List<Integer> distinctCrnNos(String csv) { |
| | | return distinctCrnNos(parseCrnNos(csv)); |
| | | } |
| | | |
| | | public static List<Integer> distinctCrnNos(List<Integer> crnNos) { |
| | | List<Integer> result = new ArrayList<>(); |
| | | if (Cools.isEmpty(crnNos)) { |
| | | return result; |
| | | } |
| | | LinkedHashSet<Integer> orderedCrnNos = new LinkedHashSet<>(); |
| | | for (Integer crnNo : crnNos) { |
| | | if (crnNo == null || crnNo <= 0) { |
| | | continue; |
| | | } |
| | | orderedCrnNos.add(crnNo); |
| | | } |
| | | result.addAll(orderedCrnNos); |
| | | return result; |
| | | } |
| | | |
| | | private static void appendCrnLocTypeEntries(List<Map<String, Integer>> result, List<Integer> crnNos, Integer locType1, boolean emptyPallet, LocMastService locMastService) { |
| | | Short normalizedLocType1 = normalizeLocType1(locType1); |
| | | if (normalizedLocType1 == null) { |
| | | appendCrnLocTypeEntries(result, crnNos, (short) 1, emptyPallet, locMastService); |
| | | appendCrnLocTypeEntries(result, crnNos, (short) 2, emptyPallet, locMastService); |
| | | public static String normalizeCrnCsv(String csv) { |
| | | return normalizeCrnCsv(parseCrnNos(csv)); |
| | | } |
| | | |
| | | public static String normalizeCrnCsv(List<Integer> crnNos) { |
| | | return joinCrnNos(distinctCrnNos(crnNos)); |
| | | } |
| | | |
| | | public static String joinCrnNos(List<Integer> crnNos) { |
| | | if (Cools.isEmpty(crnNos)) { |
| | | return ""; |
| | | } |
| | | StringBuilder builder = new StringBuilder(); |
| | | for (Integer crnNo : crnNos) { |
| | | if (crnNo == null || crnNo <= 0) { |
| | | continue; |
| | | } |
| | | if (builder.length() > 0) { |
| | | builder.append(","); |
| | | } |
| | | builder.append(crnNo); |
| | | } |
| | | return builder.toString(); |
| | | } |
| | | |
| | | private static void appendCrnPoolEntries(List<Map<String, Integer>> result, int pool, List<Integer> crnNos) { |
| | | if (result == null || Cools.isEmpty(crnNos)) { |
| | | return; |
| | | } |
| | | appendCrnLocTypeEntries(result, crnNos, normalizedLocType1, emptyPallet, locMastService); |
| | | if (normalizedLocType1 == 1) { |
| | | appendCrnLocTypeEntries(result, crnNos, (short) 2, emptyPallet, locMastService); |
| | | int seq = 1; |
| | | for (Integer crnNo : crnNos) { |
| | | if (crnNo == null || crnNo <= 0) { |
| | | continue; |
| | | } |
| | | Map<String, Integer> item = new LinkedHashMap<>(); |
| | | item.put("pool", pool); |
| | | item.put("seq", seq++); |
| | | item.put("crnNo", crnNo); |
| | | result.add(item); |
| | | } |
| | | } |
| | | |
| | | private static void appendCrnLocTypeEntries(List<Map<String, Integer>> result, List<Integer> crnNos, Short targetLocType1, boolean emptyPallet, LocMastService locMastService) { |
| | | public static List<Integer> parseStorageAreas(String area) { |
| | | List<Integer> areas = new ArrayList<>(); |
| | | if (Cools.isEmpty(area)) { |
| | | return areas; |
| | | } |
| | | LinkedHashSet<Integer> orderedAreas = new LinkedHashSet<>(); |
| | | String normalized = area.replace(",", ",") |
| | | .replace(";", ";") |
| | | .replace("、", ",") |
| | | .replaceAll("\\s+", ""); |
| | | if (normalized.isEmpty()) { |
| | | return areas; |
| | | } |
| | | for (String segment : normalized.split("[,;]")) { |
| | | if (segment == null || segment.isEmpty()) { |
| | | continue; |
| | | } |
| | | Integer areaNo = parseStorageArea(segment); |
| | | if (areaNo != null) { |
| | | orderedAreas.add(areaNo); |
| | | } |
| | | } |
| | | areas.addAll(orderedAreas); |
| | | return areas; |
| | | } |
| | | |
| | | public static String formatStorageArea(Integer area) { |
| | | if (area == null) { |
| | | return ""; |
| | | } |
| | | switch (area) { |
| | | case 1: |
| | | return "A库区"; |
| | | case 2: |
| | | return "B库区"; |
| | | case 3: |
| | | return "C库区"; |
| | | default: |
| | | return String.valueOf(area); |
| | | } |
| | | } |
| | | |
| | | private static void appendCrnLocTypeEntries(List<Map<String, Integer>> result, List<Integer> crnNos, Integer locType1, |
| | | boolean emptyPallet, LocMastService locMastService, Integer area) { |
| | | Short normalizedLocType1 = normalizeLocType1(locType1); |
| | | if (normalizedLocType1 == null) { |
| | | appendCrnLocTypeEntries(result, crnNos, (short) 1, emptyPallet, locMastService, area); |
| | | appendCrnLocTypeEntries(result, crnNos, (short) 2, emptyPallet, locMastService, area); |
| | | return; |
| | | } |
| | | appendCrnLocTypeEntries(result, crnNos, normalizedLocType1, emptyPallet, locMastService, area); |
| | | if (normalizedLocType1 == 1) { |
| | | appendCrnLocTypeEntries(result, crnNos, (short) 2, emptyPallet, locMastService, area); |
| | | } |
| | | } |
| | | |
| | | private static void appendCrnLocTypeEntries(List<Map<String, Integer>> result, List<Integer> crnNos, Short targetLocType1, |
| | | boolean emptyPallet, LocMastService locMastService, Integer area) { |
| | | if (targetLocType1 == null || Cools.isEmpty(crnNos)) { |
| | | return; |
| | | } |
| | | for (Integer crnNo : crnNos) { |
| | | if (!hasAvailableLoc(crnNo, targetLocType1, emptyPallet, locMastService) || containsCrnLocType(result, crnNo, targetLocType1)) { |
| | | if (!hasAvailableLoc(crnNo, targetLocType1, emptyPallet, locMastService) || containsCrnLocType(result, area, crnNo, targetLocType1)) { |
| | | continue; |
| | | } |
| | | Map<String, Integer> item = new LinkedHashMap<>(); |
| | | item.put("area", area); |
| | | item.put("crnNo", crnNo); |
| | | item.put("locType1", targetLocType1.intValue()); |
| | | result.add(item); |
| | | } |
| | | } |
| | | |
| | | private static boolean containsCrnLocType(List<Map<String, Integer>> result, Integer crnNo, Short locType1) { |
| | | private static boolean containsCrnLocType(List<Map<String, Integer>> result, Integer area, Integer crnNo, Short locType1) { |
| | | for (Map<String, Integer> item : result) { |
| | | if (item == null) { |
| | | continue; |
| | | } |
| | | if (crnNo.equals(item.get("crnNo")) && locType1.intValue() == item.get("locType1")) { |
| | | if (crnNo.equals(item.get("crnNo")) |
| | | && locType1.intValue() == item.get("locType1") |
| | | && Objects.equals(area, item.get("area"))) { |
| | | return true; |
| | | } |
| | | } |