package com.zy.common.service; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.baomidou.mybatisplus.mapper.Wrapper; import com.core.common.Arith; import com.core.common.Cools; import com.core.exception.CoolException; import com.zy.asrs.entity.*; import com.zy.asrs.entity.result.FindLocNoAttributeVo; import com.zy.asrs.entity.result.KeyValueVo; import com.zy.asrs.service.*; import com.zy.asrs.utils.Utils; import com.zy.asrs.utils.VersionUtils; import com.zy.common.model.LocTypeDto; import com.zy.common.model.Shelves; import com.zy.common.model.StartupDto; import com.zy.common.properties.SlaveProperties; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; /** * 货架核心功能 * Created by vincent on 2020/6/11 */ @Slf4j @Service public class CommonService { private static final int MIN_SPARE_LOC_COUNT = 2; @Autowired private WrkMastService wrkMastService; @Autowired private WrkLastnoService wrkLastnoService; @Autowired private RowLastnoService rowLastnoService; @Autowired private RowLastnoTypeService rowLastnoTypeService; @Autowired private BasCrnpService basCrnpService; @Autowired private StaDescService staDescService; @Autowired private BasDevpService basDevpService; @Autowired private LocMastService locMastService; @Autowired private LocDetlService locDetlService; @Autowired private SlaveProperties slaveProperties; @Autowired private WrkDetlService wrkDetlService; /** * 生成工作号 * * @param wrkMk * @return workNo(工作号) */ public int getWorkNo(Integer wrkMk) { WrkLastno wrkLastno = wrkLastnoService.selectById(wrkMk); if (Cools.isEmpty(wrkLastno)) { throw new CoolException("数据异常,请联系管理员"); } int workNo = wrkLastno.getWrkNo(); int sNo = wrkLastno.getSNo(); int eNo = wrkLastno.getENo(); workNo = workNo >= eNo ? sNo : workNo + 1; while (true) { WrkMast wrkMast = wrkMastService.selectById(workNo); if (null != wrkMast) { workNo = workNo >= eNo ? sNo : workNo + 1; } else { break; } } // 修改序号记录 if (workNo > 0) { wrkLastno.setWrkNo(workNo); wrkLastnoService.updateById(wrkLastno); } // 检验 if (workNo == 0) { throw new CoolException("生成工作号失败,请联系管理员"); } else { if (wrkMastService.selectById(workNo) != null) { throw new CoolException("生成工作号" + workNo + "在工作档中已存在"); } } return workNo; } //拆盘机处空板扫码,驱动托盘向码垛位,不入库 @Transactional public StartupDto getScanBarcodeEmptyBoard() { StartupDto startupDto = new StartupDto(); Integer staNo = 0; if (wrkMastService.selectCount(new EntityWrapper().eq("io_type", 201).eq("staNo", 216)) < 2) { staNo = 216; } if (wrkMastService.selectCount(new EntityWrapper().eq("io_type", 201).eq("staNo", 220)) < 2) { staNo = 220; } startupDto.setStaNo(staNo); return startupDto; } /** * 检索库位号 * * @param staDescId 路径ID * @param sourceStaNo 源站 * @param findLocNoAttributeVo 属性 * @param locTypeDto 类型 * @return locNo 检索到的库位号 */ @Transactional public StartupDto getLocNo(Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, LocTypeDto locTypeDto) { return getLocNo(staDescId, sourceStaNo, findLocNoAttributeVo, locTypeDto, null); } @Transactional public StartupDto getLocNo(Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, LocTypeDto locTypeDto, List recommendRows) { try { Integer whsType = Utils.GetWhsType(sourceStaNo); RowLastno rowLastno = rowLastnoService.selectById(whsType); RowLastnoType rowLastnoType = rowLastnoTypeService.selectById(rowLastno.getTypeId()); if (rowLastnoType.getType() == 2) { return getLocNoRun2(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, 0, locTypeDto, 0); } /** * 库型 1: 标准堆垛机库 2: 平库 3: 穿梭板 4: 四向车 5: AGV 0: 未知 */ switch (rowLastnoType.getType()) { case 1: return getLocNoRun(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, 0, locTypeDto, 0); case 2: log.error("站点={} 未查询到对应的规则", sourceStaNo); break; case 3: log.error("站点={} 未查询到对应的规则", sourceStaNo); break; case 4: return getLocNoRun4(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, 4, locTypeDto, 0); case 5: return getLocNoRun5(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, 0, locTypeDto, recommendRows, 0); default: log.error("站点={} 未查询到对应的规则", sourceStaNo); break; } } catch (Exception e) { log.error("站点={} 未查询到对应的规则", sourceStaNo); } return null; } private Optional findAvailableCrnAndNearRow(RowLastno rowLastno, int curRow, int crnNumber, int times, FindLocNoAttributeVo findLocNoAttributeVo, LocTypeDto locTypeDto, RowLastnoType rowLastnoType) { int attempt = times; while (attempt < crnNumber * 4) { int[] params = Utils.LocNecessaryParameters(rowLastno, curRow, crnNumber); curRow = params[1]; int crnNo = params[2]; // if (!basCrnpService.checkSiteError(crnNo, true)) { // attempt++; // continue; // } int rowCount = params[0]; int nearRow = params[3]; // 只取数量判断,避免拉整 list int availableLocCount = locMastService.selectCount(new EntityWrapper() .eq("row1", nearRow) .eq("loc_sts", "O") .eq("whs_type", 1)); int crnCountO = wrkMastService.selectCount(new EntityWrapper() .eq("crn_no", crnNo).le("io_type", 100)); if (availableLocCount - crnCountO <= 2) { // 可以提成常量,比如 MIN_SPARE_SLOTS = 2 log.error("{}号堆垛机没有空库位!!! 尺寸规格: {}, 轮询次数:{}", crnNo, JSON.toJSONString(locTypeDto), attempt); attempt++; continue; } return Optional.of(new CrnRowInfo(crnNo, nearRow, curRow, rowCount, attempt)); } return Optional.empty(); } private Optional findBalancedCrnAndNearRow(RowLastno rowLastno, int curRow, int crnNumber, int times, FindLocNoAttributeVo findLocNoAttributeVo, LocTypeDto locTypeDto, RowLastnoType rowLastnoType) { int maxScanTimes = Math.max(crnNumber * 2, 1); int scanCurRow = curRow; Map availableLocCountCache = new HashMap<>(); Map crnTaskCountCache = new HashMap<>(); CrnRowInfo bestInfo = null; int bestTaskCount = Integer.MAX_VALUE; int bestSpareLocCount = Integer.MIN_VALUE; int bestOffset = Integer.MAX_VALUE; CrnRowInfo fallbackInfo = null; int fallbackTaskCount = Integer.MAX_VALUE; int fallbackAvailableLocCount = Integer.MIN_VALUE; int fallbackOffset = Integer.MAX_VALUE; for (int attempt = 0; attempt < maxScanTimes; attempt++) { int[] params = Utils.LocNecessaryParameters(rowLastno, scanCurRow, crnNumber); scanCurRow = params[1]; int rowCount = params[0]; int crnNo = params[2]; int nearRow = params[3]; if (attempt < times) { continue; } int availableLocCount = availableLocCountCache.computeIfAbsent(crnNo, key -> countAvailableLocForCrn(rowLastno, rowLastnoType, key, nearRow)); int crnTaskCount = crnTaskCountCache.computeIfAbsent(crnNo, key -> wrkMastService.selectCount(new EntityWrapper() .eq("crn_no", key) .le("io_type", 100))); int spareLocCount = availableLocCount - crnTaskCount; int offset = attempt - times; if (availableLocCount > 0 && isBetterCrnCandidate(crnTaskCount, availableLocCount, offset, fallbackTaskCount, fallbackAvailableLocCount, fallbackOffset)) { fallbackInfo = new CrnRowInfo(crnNo, nearRow, scanCurRow, rowCount, attempt); fallbackTaskCount = crnTaskCount; fallbackAvailableLocCount = availableLocCount; fallbackOffset = offset; } if (spareLocCount <= MIN_SPARE_LOC_COUNT) { log.warn("{}号堆垛机可用空库位余量不足,降级候选继续保留。尺寸规格:{},轮询次数:{}", crnNo, JSON.toJSONString(locTypeDto), attempt); continue; } if (isBetterCrnCandidate(crnTaskCount, spareLocCount, offset, bestTaskCount, bestSpareLocCount, bestOffset)) { bestInfo = new CrnRowInfo(crnNo, nearRow, scanCurRow, rowCount, attempt); bestTaskCount = crnTaskCount; bestSpareLocCount = spareLocCount; bestOffset = offset; } } if (bestInfo != null) { return Optional.of(bestInfo); } if (fallbackInfo != null) { log.warn("堆垛机均衡分配未找到满足余量阈值的候选,降级使用仍有空位的堆垛机: crnNo={}", fallbackInfo.getCrnNo()); } return Optional.ofNullable(fallbackInfo); } private boolean isBetterCrnCandidate(int taskCount, int spareLocCount, int offset, int bestTaskCount, int bestSpareLocCount, int bestOffset) { if (taskCount != bestTaskCount) { return taskCount < bestTaskCount; } if (spareLocCount != bestSpareLocCount) { return spareLocCount > bestSpareLocCount; } return offset < bestOffset; } private int countAvailableLocForCrn(RowLastno rowLastno, RowLastnoType rowLastnoType, int crnNo, int preferredNearRow) { List searchRows = getCrnSearchRows(rowLastno, crnNo, preferredNearRow); if (searchRows.isEmpty()) { return 0; } return locMastService.selectCount(new EntityWrapper() .in("row1", searchRows) .eq("loc_sts", "O") .eq("whs_type", rowLastnoType.getType().longValue())); } private int countAvailableSingleExtensionLocForCrn(RowLastno rowLastno, RowLastnoType rowLastnoType, int crnNo, int preferredNearRow, LocTypeDto locTypeDto) { List searchRows = getCrnSearchRows(rowLastno, crnNo, preferredNearRow); if (searchRows.isEmpty()) { return 0; } Wrapper wrapper = new EntityWrapper() .in("row1", searchRows) .eq("loc_sts", "O") .eq("whs_type", rowLastnoType.getType().longValue()); if (locTypeDto != null && locTypeDto.getLocType1() != null) { wrapper.eq("loc_type1", locTypeDto.getLocType1()); } return locMastService.selectCount(wrapper); } private Optional findBalancedSingleExtensionCrnAndNearRow(RowLastno rowLastno, int curRow, int crnNumber, int times, LocTypeDto locTypeDto, RowLastnoType rowLastnoType) { int maxScanTimes = Math.max(crnNumber * 2, 1); int scanCurRow = curRow; Map availableLocCountCache = new HashMap<>(); Map crnTaskCountCache = new HashMap<>(); CrnRowInfo bestInfo = null; int bestTaskCount = Integer.MAX_VALUE; int bestSpareLocCount = Integer.MIN_VALUE; int bestOffset = Integer.MAX_VALUE; CrnRowInfo fallbackInfo = null; int fallbackTaskCount = Integer.MAX_VALUE; int fallbackAvailableLocCount = Integer.MIN_VALUE; int fallbackOffset = Integer.MAX_VALUE; for (int attempt = 0; attempt < maxScanTimes; attempt++) { int[] params = Utils.LocNecessaryParameters(rowLastno, scanCurRow, crnNumber); scanCurRow = params[1]; int rowCount = params[0]; int crnNo = params[2]; int nearRow = params[3]; if (attempt < times) { continue; } int availableLocCount = availableLocCountCache.computeIfAbsent(crnNo, key -> countAvailableSingleExtensionLocForCrn(rowLastno, rowLastnoType, key, nearRow, locTypeDto)); int crnTaskCount = crnTaskCountCache.computeIfAbsent(crnNo, key -> wrkMastService.selectCount(new EntityWrapper() .eq("crn_no", key) .le("io_type", 100))); int spareLocCount = availableLocCount - crnTaskCount; int offset = attempt - times; if (availableLocCount > 0 && isBetterCrnCandidate(crnTaskCount, availableLocCount, offset, fallbackTaskCount, fallbackAvailableLocCount, fallbackOffset)) { fallbackInfo = new CrnRowInfo(crnNo, nearRow, scanCurRow, rowCount, attempt); fallbackTaskCount = crnTaskCount; fallbackAvailableLocCount = availableLocCount; fallbackOffset = offset; } if (spareLocCount <= MIN_SPARE_LOC_COUNT) { continue; } if (isBetterCrnCandidate(crnTaskCount, spareLocCount, offset, bestTaskCount, bestSpareLocCount, bestOffset)) { bestInfo = new CrnRowInfo(crnNo, nearRow, scanCurRow, rowCount, attempt); bestTaskCount = crnTaskCount; bestSpareLocCount = spareLocCount; bestOffset = offset; } } if (bestInfo != null) { return Optional.of(bestInfo); } return Optional.ofNullable(fallbackInfo); } private List getCrnSearchRows(RowLastno rowLastno, int crnNo, int preferredNearRow) { List searchRows = new ArrayList<>(); addSearchRow(searchRows, preferredNearRow, rowLastno); Integer rowSpan = getCrnRowSpan(rowLastno.getTypeId()); if (rowSpan == null) { return searchRows; } int crnOffset = crnNo - rowLastno.getsCrnNo(); if (crnOffset < 0) { return searchRows; } int startRow = rowLastno.getsRow() + crnOffset * rowSpan; switch (rowLastno.getTypeId()) { case 1: addSearchRow(searchRows, startRow + 1, rowLastno); addSearchRow(searchRows, startRow + 2, rowLastno); break; case 2: addSearchRow(searchRows, startRow, rowLastno); addSearchRow(searchRows, startRow + 1, rowLastno); break; default: break; } return searchRows; } private Integer getCrnRowSpan(Integer typeId) { if (typeId == null) { return null; } switch (typeId) { case 1: return 4; case 2: return 2; default: return null; } } private void addSearchRow(List searchRows, Integer row, RowLastno rowLastno) { if (row == null) { return; } if (row < rowLastno.getsRow() || row > rowLastno.geteRow()) { return; } if (!searchRows.contains(row)) { searchRows.add(row); } } private LocMast findStandardEmptyLoc(RowLastno rowLastno, RowLastnoType rowLastnoType, int crnNo, int nearRow, LocTypeDto locTypeDto) { for (Integer searchRow : getCrnSearchRows(rowLastno, crnNo, nearRow)) { List locMasts = locMastService.selectList(new EntityWrapper() .eq("row1", searchRow) .eq("loc_sts", "O") .eq("whs_type", rowLastnoType.getType().longValue()) .orderBy("lev1", true) .orderBy("bay1", true)); for (LocMast locMast1 : locMasts) { if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) { continue; } if (Utils.BooleanWhsTypeStaIoType(rowLastno)) { String shallowLoc = Utils.getDeepLoc(slaveProperties, locMast1.getLocNo()); LocMast locMast2 = locMastService.selectOne(new EntityWrapper() .eq("loc_no", shallowLoc) .eq("loc_sts", "O") .eq("whs_type", rowLastnoType.getType().longValue())); if (!Cools.isEmpty(locMast2)) { return locMast2; } } else if (!Cools.isEmpty(locMast1)) { return locMast1; } } if (!Utils.BooleanWhsTypeStaIoType(rowLastno)) { continue; } for (LocMast locMast1 : locMasts) { if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) { continue; } String shallowLoc = Utils.getDeepLoc(slaveProperties, locMast1.getLocNo()); LocMast locMast2 = locMastService.selectOne(new EntityWrapper() .eq("loc_no", shallowLoc) .eq("loc_sts", "O") .eq("whs_type", rowLastnoType.getType().longValue())); if (!Cools.isEmpty(locMast2)) { return locMast2; } locMast2 = locMastService.selectOne(new EntityWrapper() .eq("loc_no", shallowLoc) .eq("loc_sts", "F") .eq("whs_type", rowLastnoType.getType().longValue())); if (!Cools.isEmpty(locMast2)) { return locMast1; } locMast2 = locMastService.selectOne(new EntityWrapper() .eq("loc_no", shallowLoc) .eq("loc_sts", "D") .eq("whs_type", rowLastnoType.getType().longValue())); if (!Cools.isEmpty(locMast2)) { return locMast1; } } } return null; } private LocTypeDto buildUpwardCompatibleLocTypeDto(LocTypeDto locTypeDto) { if (locTypeDto == null || locTypeDto.getLocType1() == null || locTypeDto.getLocType1() >= 2) { return null; } LocTypeDto compatibleLocTypeDto = new LocTypeDto(); compatibleLocTypeDto.setLocType1((short) (locTypeDto.getLocType1() + 1)); compatibleLocTypeDto.setLocType2(locTypeDto.getLocType2()); compatibleLocTypeDto.setLocType3(locTypeDto.getLocType3()); compatibleLocTypeDto.setSiteId(locTypeDto.getSiteId()); return compatibleLocTypeDto; } /** * 检索库位号 * * @param whsType 类型 1:双深式货架 * @param staDescId 路径ID * @param sourceStaNo 源站 * @param findLocNoAttributeVo 属性 * @param moveCrnNo 源 * @param locTypeDto 类型 * @param times 轮询次数 * @return locNo 检索到的库位号 */ @Transactional public StartupDto getLocNoRun(Integer whsType, Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, Integer moveCrnNo, LocTypeDto locTypeDto, int times) { // 初始化参数 int crnNo = 0; //堆垛机号 int nearRow = 0; //最浅库位排 int curRow = 0; //最深库位排 int rowCount = 0; //轮询轮次 LocMast locMast = null; // 目标库位 StartupDto startupDto = new StartupDto(); RowLastno rowLastno = rowLastnoService.selectById(whsType); if (Cools.isEmpty(rowLastno)) { throw new CoolException("数据异常,请联系管理员===>库位规则未知"); } RowLastnoType rowLastnoType = rowLastnoTypeService.selectById(rowLastno.getTypeId()); if (Cools.isEmpty(rowLastnoType)) { throw new CoolException("数据异常,请联系管理员===》库位规则类型未知"); } int sRow = rowLastno.getsRow(); int eRow = rowLastno.geteRow(); int crnNumber = rowLastno.getCrnQty(); // ===============>>>> 开始执行 curRow = rowLastno.getCurrentRow(); if (!Cools.isEmpty(moveCrnNo) && moveCrnNo != 0) { crnNumber = moveCrnNo; if (times == 0) { curRow = moveCrnNo * 4 - 1; } else { curRow = moveCrnNo * 4 - 2; } } //此程序用于优化堆垛机异常时的运行时间 Optional infoOpt = findBalancedCrnAndNearRow(rowLastno, curRow, crnNumber, times, findLocNoAttributeVo, locTypeDto, rowLastnoType); if (!infoOpt.isPresent()) { infoOpt = findAvailableCrnAndNearRow(rowLastno, curRow, crnNumber, times, findLocNoAttributeVo, locTypeDto, rowLastnoType); } if (!infoOpt.isPresent()) { throw new CoolException("无可用堆垛机"); } CrnRowInfo info = infoOpt.get(); crnNo = info.getCrnNo(); nearRow = info.getNearRow(); curRow = info.getCurRow(); rowCount = info.getRowCount(); times = info.getTimes(); boolean signRule1 = false; boolean signRule2 = false; if (Utils.BooleanWhsTypeStaIoType(rowLastno)) { // 靠近摆放规则 --- 同天同规格物料 //分离版 if (!Cools.isEmpty(findLocNoAttributeVo.getMatnr()) && staDescId == 1) { signRule1 = true; } // 靠近摆放规则 --- 同天同规格物料 //互通版 if (!Cools.isEmpty(findLocNoAttributeVo.getMatnr()) && staDescId == 1) { signRule2 = true; } if (!Cools.isEmpty(findLocNoAttributeVo.getMatnr()) && (staDescId == 11 || staDescId == 111)) { signRule1 = true; } } if (signRule1) { if (nearRow != curRow) { List locMasts = locMastService.selectList(new EntityWrapper() .eq("row1", nearRow).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue())); for (LocMast locMast1 : locMasts) { //获取巷道 // List groupOutsideLocCrn = Utils.getGroupOutLocCrn(curRow,nearRow,locMast1.getLocNo(), curRow>nearRow); // LocMast locMastGro = locMastService.selectById(wrkMast.getLocNo()); //获取目标库位所在巷道最浅非空库位 LocMast locMastF = locMastService.selectLocByLocStsPakInF(curRow, nearRow, locMast1, rowLastnoType.getType().longValue()); if (!Cools.isEmpty(locMastF) && locMastF.getLocSts().equals("F")) { LocDetl locDetl = locDetlService.selectOne(new EntityWrapper().eq("loc_no", locMastF.getLocNo())); if (!Cools.isEmpty(locDetl) && findLocNoAttributeVo.beSimilar(locDetl)) { //获取目标库位所在巷道最深空库位 locMast = locMastService.selectLocByLocStsPakInO(curRow, nearRow, locMast1, rowLastnoType.getType().longValue()); break; } } } } } else if (signRule2) { List locNos = locDetlService.getSameDetlToday(findLocNoAttributeVo.getMatnr(), sRow, eRow); for (String locNo : locNos) { if (Utils.isShallowLoc(slaveProperties, locNo)) { continue; } String shallowLocNo = Utils.getShallowLoc(slaveProperties, locNo); // 检测目标库位是否为空库位 LocMast shallowLoc = locMastService.selectById(shallowLocNo); if (shallowLoc != null && shallowLoc.getLocSts().equals("O")) { if (VersionUtils.locMoveCheckLocTypeComplete(shallowLoc, locTypeDto)) { if (basCrnpService.checkSiteError(shallowLoc.getCrnNo(), true)) { locMast = shallowLoc; crnNo = locMast.getCrnNo(); break; } } } } } // 靠近摆放规则 --- 空托 //互通版 if (staDescId == 10 && Utils.BooleanWhsTypeStaIoType(rowLastno)) { List locMasts = locMastService.selectList(new EntityWrapper() .eq("loc_sts", "D").ge("row1", sRow).le("row1", eRow).eq("whs_type", rowLastnoType.getType().longValue())); if (!locMasts.isEmpty()) { for (LocMast loc : locMasts) { if (Utils.isShallowLoc(slaveProperties, loc.getLocNo())) { continue; } String shallowLocNo = Utils.getShallowLoc(slaveProperties, loc.getLocNo()); // 检测目标库位是否为空库位 LocMast shallowLoc = locMastService.selectById(shallowLocNo); if (shallowLoc != null && shallowLoc.getLocSts().equals("O")) { if (VersionUtils.locMoveCheckLocTypeComplete(shallowLoc, locTypeDto)) { if (basCrnpService.checkSiteError(shallowLoc.getCrnNo(), true)) { locMast = shallowLoc; crnNo = locMast.getCrnNo(); break; } } } } } } Wrapper wrapper = null; StaDesc staDesc = null; BasDevp staNo = null; if (Utils.BooleanWhsTypeSta(rowLastno, staDescId)) { // 获取目标站 wrapper = new EntityWrapper() .eq("type_no", staDescId) .eq("stn_no", sourceStaNo) .eq("crn_no", crnNo); staDesc = staDescService.selectOne(wrapper); if (Cools.isEmpty(staDesc)) { log.error("type_no={},stn_no={},crn_no={}", staDescId, sourceStaNo, crnNo); // throw new CoolException("入库路径不存在"); crnNo = 0; } else { staNo = basDevpService.selectById(staDesc.getCrnStn()); if (!staNo.getAutoing().equals("Y")) { log.error("目标站" + staDesc.getCrnStn() + "不可用"); // throw new CoolException("目标站"+staDesc.getCrnStn()+"不可用"); crnNo = 0; } startupDto.setStaNo(staNo.getDevNo()); } // 更新库位排号 if (Cools.isEmpty(locMast)) { rowLastno.setCurrentRow(curRow); rowLastnoService.updateById(rowLastno); } } // Search empty location ==============================>> if (staDescId == 10 && Cools.isEmpty(locMast) && crnNo != 0) { locMast = findStandardEmptyLoc(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto); } if (Cools.isEmpty(locMast) && crnNo != 0) { locMast = findStandardEmptyLoc(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto); } if (!Cools.isEmpty(locMast) && !basCrnpService.checkSiteError(crnNo, true)) { locMast = null; } // Retry search if (Cools.isEmpty(locMast) || !locMast.getLocSts().equals("O")) { // Scan next aisle first, then retry with upward-compatible locType1. if (times < rowCount * 2) { times = times + 1; return getLocNoRun(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, locTypeDto, times); } LocTypeDto compatibleLocTypeDto = buildUpwardCompatibleLocTypeDto(locTypeDto); if (compatibleLocTypeDto != null) { log.warn("locType1 upward compatibility retry. source={}, target={}", JSON.toJSONString(locTypeDto), JSON.toJSONString(compatibleLocTypeDto)); return getLocNoRun(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, compatibleLocTypeDto, 0); } log.error("No empty location found. spec={}, times={}", JSON.toJSONString(locTypeDto), times); throw new CoolException("\u6ca1\u6709\u7a7a\u5e93\u4f4d"); } String locNo = locMast.getLocNo(); // 生成工作号 int workNo = getWorkNo(0); // 返回dto startupDto.setWorkNo(workNo); startupDto.setCrnNo(crnNo); startupDto.setSourceStaNo(sourceStaNo); startupDto.setLocNo(locNo); return startupDto; } public StartupDto getLocNoRun2(Integer whsType, Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, Integer moveCrnNo, LocTypeDto locTypeDto, int times) { int crnNo = 0; int nearRow = 0; int curRow = 0; int rowCount = 0; LocMast locMast = null; StartupDto startupDto = new StartupDto(); RowLastno rowLastno = rowLastnoService.selectById(whsType); if (Cools.isEmpty(rowLastno)) { throw new CoolException("数据异常,请联系管理员===>库位规则未知"); } crnNo = rowLastno.getCurrentRow()/2+1; RowLastnoType rowLastnoType = rowLastnoTypeService.selectById(rowLastno.getTypeId()); if (Cools.isEmpty(rowLastnoType)) { throw new CoolException("数据异常,请联系管理员===》库位规则类型未知"); } int crnNumber = rowLastno.getCrnQty(); curRow = rowLastno.getCurrentRow(); Wrapper wrapper = null; StaDesc staDesc = null; BasDevp staNo = null; if (Utils.BooleanWhsTypeSta(rowLastno, staDescId)) { wrapper = new EntityWrapper() .eq("type_no", staDescId) .eq("stn_no", sourceStaNo) .eq("crn_no", crnNo); staDesc = staDescService.selectOne(wrapper); if (Cools.isEmpty(staDesc)) { log.error("type_no={},stn_no={},crn_no={}", staDescId, sourceStaNo, crnNo); crnNo = 0; } else { staNo = basDevpService.selectById(staDesc.getCrnStn()); if (!staNo.getAutoing().equals("Y")) { log.error("目标站{}不可用", staDesc.getCrnStn()); crnNo = 0; } startupDto.setStaNo(staNo.getDevNo()); } } LocMast locMast1 = locMastService.selectOne(new EntityWrapper() .eq("crn_no", crnNo) .eq("loc_sts", "O") .orderBy("lev1") .orderBy("bay1") .eq("loc_type1",locTypeDto.getLocType1())); if (!Cools.isEmpty(locMast1)) { locMast=locMast1; } if (curRow==rowLastno.geteRow()-1) { curRow = 1; }else{ curRow = curRow + 2; } rowLastno.setCurrentRow(curRow); rowLastnoService.updateById(rowLastno); if (!Cools.isEmpty(locMast) && !basCrnpService.checkSiteError(crnNo, true)) { locMast = null; } if (Cools.isEmpty(locMast) || !locMast.getLocSts().equals("O")) { if (times < rowCount * 2) { times = times + 1; return getLocNoRun2(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, locTypeDto, times); } LocTypeDto compatibleLocTypeDto = buildUpwardCompatibleLocTypeDto(locTypeDto); if (compatibleLocTypeDto != null) { log.warn("locType1 upward compatibility retry. source={}, target={}", JSON.toJSONString(locTypeDto), JSON.toJSONString(compatibleLocTypeDto)); return getLocNoRun2(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, compatibleLocTypeDto, 0); } log.error("No empty location found. spec={}, times={}", JSON.toJSONString(locTypeDto), times); throw new CoolException("\u6ca1\u6709\u7a7a\u5e93\u4f4d"); } int workNo = getWorkNo(0); startupDto.setWorkNo(workNo); startupDto.setCrnNo(crnNo); startupDto.setSourceStaNo(sourceStaNo); startupDto.setLocNo(locMast.getLocNo()); return startupDto; } private LocMast findSingleExtensionEmptyLoc(RowLastno rowLastno, int crnNo, int nearRow, RowLastnoType rowLastnoType, LocTypeDto locTypeDto) { for (Integer searchRow : getCrnSearchRows(rowLastno, crnNo, nearRow)) { List locMasts = locMastService.selectList(new EntityWrapper() .eq("row1", searchRow) .eq("loc_sts", "O") .eq("whs_type", rowLastnoType.getType().longValue()) .orderBy("bay1", true) .orderBy("lev1", true)); for (LocMast locMast : locMasts) { if (VersionUtils.locMoveCheckLocTypeComplete(locMast, locTypeDto)) { return locMast; } } } return null; } public StartupDto getLocNoRun4(Integer whsType, Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, Integer moveCrnNo, LocTypeDto locTypeDto, int times) { // 初始化参数 int crnNo = 0; //堆垛机号 int nearRow = 0; //最浅库位排 int curRow = 0; //最深库位排 int rowCount = 0; //轮询轮次 LocMast locMast = null; // 目标库位 StartupDto startupDto = new StartupDto(); RowLastno rowLastno = rowLastnoService.selectById(whsType); if (Cools.isEmpty(rowLastno)) { throw new CoolException("数据异常,请联系管理员===>库位规则未知"); } RowLastnoType rowLastnoType = rowLastnoTypeService.selectById(rowLastno.getTypeId()); if (Cools.isEmpty(rowLastnoType)) { throw new CoolException("数据异常,请联系管理员===》库位规则类型未知"); } int sRow = rowLastno.getsRow(); int eRow = rowLastno.geteRow(); int crnNumber = rowLastno.getCrnQty(); // ===============>>>> 开始执行 curRow = rowLastno.getCurrentRow(); if (!Cools.isEmpty(moveCrnNo) && moveCrnNo != 0) { crnNumber = moveCrnNo; // if (times==0){ // curRow = moveCrnNo*4-1; // }else { // curRow = moveCrnNo*4-2; // } } //此程序用于优化堆垛机异常时的运行时间 for (int i = times; i < crnNumber * 2; i++) { int[] locNecessaryParameters = Utils.LocNecessaryParameters(rowLastno, curRow, crnNumber); rowCount = locNecessaryParameters[0]; curRow = locNecessaryParameters[1]; crnNo = locNecessaryParameters[2]; nearRow = locNecessaryParameters[3]; List locMasts = locMastService.selectList(new EntityWrapper() .eq("crn_no", crnNo).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue())); if (locMasts.size() <= 5) { nearRow = 0; times++; continue; } break; } if (crnNo == 0) { throw new CoolException("无可用库位"); } // 相似工作档案 --- 同天同规格物料 if (!Cools.isEmpty(findLocNoAttributeVo.getMatnr()) && (staDescId == 1 || staDescId == 11 || staDescId == 111)) { //查询相似工作档案 List wrkMasts = wrkMastService.selectWrkMastWrkDetl(staDescId, findLocNoAttributeVo, crnNo); int nearbay = 0; //相似工作档案 目标库位列 int nearlev = 0; //相似工作档案 目标库位层 for (WrkMast wrkMast : wrkMasts) { int curRowW = curRow; //相似工作档案 最深库位排 int nearRowW = nearRow; //相似工作档案 最浅库位排 if (Cools.isEmpty(wrkMast.getLocNo())) { continue; } //目标排为最外层排 if (Utils.getRow(wrkMast.getLocNo()) == nearRow) { continue; } //起始站不一致 if (!wrkMast.getSourceStaNo().equals(sourceStaNo)) { continue; } //相同列、层过滤 if (Utils.getBay(wrkMast.getLocNo()) == nearbay && Utils.getLev(wrkMast.getLocNo()) == nearlev) { continue; } else { nearbay = Utils.getBay(wrkMast.getLocNo()); nearlev = Utils.getLev(wrkMast.getLocNo()); } //获取目标库位所在巷道并排序 // List groupOutsideLocCrn = Utils.getGroupOutLocCrn(curRow,nearRow,wrkMast.getLocNo(), curRow>nearRow); LocMast locMastGro = locMastService.selectById(wrkMast.getLocNo()); for (int i = 0; i < crnNumber * 2; i++) { if (!(Utils.getRow(locMastGro.getLocNo()) > nearRowW && Utils.getRow(locMastGro.getLocNo()) <= curRowW) && !(Utils.getRow(locMastGro.getLocNo()) < nearRowW && Utils.getRow(locMastGro.getLocNo()) >= curRowW)) { int[] locNecessaryParameters = Utils.LocNecessaryParameters(rowLastno, curRowW, crnNumber); curRowW = locNecessaryParameters[1]; nearRowW = locNecessaryParameters[3]; } else { break; } } //获取目标库位所在巷道最浅非空库位 LocMast locMast2 = locMastService.selectLocByLocStsPakInF(curRowW, nearRowW, locMastGro, rowLastnoType.getType().longValue()); //目标库位所在巷道最浅非空库位存在&&非最外侧库位&&入库状态 if (!Cools.isEmpty(locMast2) && Utils.getRow(locMast2.getLocNo()) != nearRowW && (locMast2.getLocSts().equals("S") || locMast2.getLocSts().equals("Q"))) { //获取库存明细 WrkDetl wrkDetl = wrkDetlService.selectOne(new EntityWrapper().eq("wrk_no", wrkMast.getWrkNo())); //判断同规格物料 if (!Cools.isEmpty(wrkDetl) && findLocNoAttributeVo.beSimilar(wrkDetl)) { int row2 = 0; if (Utils.getRow(locMast2.getLocNo()) > nearRowW) { row2 = Utils.getRow(locMast2.getLocNo()) - 1; } else { row2 = Utils.getRow(locMast2.getLocNo()) + 1; } String targetLocNo = zerofill(String.valueOf(row2), 2) + locMast2.getLocNo().substring(2); locMast = locMastService.selectOne(new EntityWrapper().eq("loc_no", targetLocNo).eq("loc_sts", "O")); if (Cools.isEmpty(locMast)) { continue; } break; } } } } // 相似工作档 --- 空托 if (Cools.isEmpty(locMast) && staDescId == 10) { List wrkMasts = wrkMastService.selectList(new EntityWrapper().eq("io_type", 10).eq("crn_no", crnNo).eq("whs_type", rowLastnoType.getType().longValue())); int nearbay = 0; int nearlev = 0; for (WrkMast wrkMast : wrkMasts) { int curRowW = curRow; //相似工作档案 最深库位排 int nearRowW = nearRow; //相似工作档案 最浅库位排 if (Cools.isEmpty(wrkMast.getLocNo())) { continue; } if (Utils.getRow(wrkMast.getLocNo()) == nearRow) { continue; } //起始站不一致 if (!wrkMast.getSourceStaNo().equals(sourceStaNo)) { continue; } if (Utils.getBay(wrkMast.getLocNo()) == nearbay && Utils.getLev(wrkMast.getLocNo()) == nearlev) { continue; } else { nearbay = Utils.getBay(wrkMast.getLocNo()); nearlev = Utils.getLev(wrkMast.getLocNo()); } // List groupOutsideLocCrn = Utils.getGroupOutLocCrn(curRow,nearRow,wrkMast.getLocNo(), curRow>nearRow); LocMast locMastGro = locMastService.selectById(wrkMast.getLocNo()); for (int i = 0; i < crnNumber * 2; i++) { if (!(Utils.getRow(locMastGro.getLocNo()) > nearRowW && Utils.getRow(locMastGro.getLocNo()) <= curRowW) && !(Utils.getRow(locMastGro.getLocNo()) < nearRowW && Utils.getRow(locMastGro.getLocNo()) >= curRowW)) { int[] locNecessaryParameters = Utils.LocNecessaryParameters(rowLastno, curRowW, crnNumber); curRowW = locNecessaryParameters[1]; nearRowW = locNecessaryParameters[3]; } else { break; } } LocMast locMast2 = locMastService.selectLocByLocStsPakInF(curRowW, nearRowW, locMastGro, rowLastnoType.getType().longValue()); if (!Cools.isEmpty(locMast2) && Utils.getRow(locMast2.getLocNo()) != nearRowW && locMast2.getLocSts().equals("S")) { int row2 = 0; if (Utils.getRow(locMast2.getLocNo()) > nearRowW) { row2 = Utils.getRow(locMast2.getLocNo()) - 1; } else { row2 = Utils.getRow(locMast2.getLocNo()) + 1; } String targetLocNo = zerofill(String.valueOf(row2), 2) + locMast2.getLocNo().substring(2); locMast = locMastService.selectOne(new EntityWrapper().eq("loc_no", targetLocNo).eq("loc_sts", "O")); if (Cools.isEmpty(locMast)) { continue; } break; } } } boolean signRule1 = false; boolean signRule2 = false; if (Utils.BooleanWhsTypeStaIoType(rowLastno)) { // 靠近摆放规则 --- 同天同规格物料 //分离版 if (!Cools.isEmpty(findLocNoAttributeVo.getMatnr()) && staDescId == 1) { // signRule1 = true; } // 靠近摆放规则 --- 同天同规格物料 //互通版 if (!Cools.isEmpty(findLocNoAttributeVo.getMatnr()) && staDescId == 1) { signRule2 = true; } if (!Cools.isEmpty(findLocNoAttributeVo.getMatnr()) && (staDescId == 11 || staDescId == 111)) { signRule1 = true; } } if (signRule1) { if (nearRow != curRow) { List locMasts = locMastService.selectList(new EntityWrapper() .eq("row1", nearRow).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue())); for (LocMast locMast1 : locMasts) { //获取巷道 // List groupOutsideLocCrn = Utils.getGroupOutLocCrn(curRow,nearRow,locMast1.getLocNo(), curRow>nearRow); //获取目标库位所在巷道最浅非空库位 LocMast locMastF = locMastService.selectLocByLocStsPakInF(curRow, nearRow, locMast1, rowLastnoType.getType().longValue()); if (!Cools.isEmpty(locMastF) && locMastF.getLocSts().equals("F")) { LocDetl locDetl = locDetlService.selectOne(new EntityWrapper().eq("loc_no", locMastF.getLocNo())); if (!Cools.isEmpty(locDetl) && findLocNoAttributeVo.beSimilar(locDetl)) { //获取目标库位所在巷道最深空库位 locMast = locMastService.selectLocByLocStsPakInO(curRow, nearRow, locMast1, rowLastnoType.getType().longValue()); break; } } } } } else if (signRule2) { List locNos = locDetlService.getSameDetlToday(findLocNoAttributeVo.getMatnr(), sRow, eRow); int nearbay = 0; int nearlev = 0; for (String locNo : locNos) { int curRowW = curRow; //相似工作档案 最深库位排 int nearRowW = nearRow; //相似工作档案 最浅库位排 if (Cools.isEmpty(locNo)) { continue; } if (Utils.getRow(locNo) == nearRow) { continue; } if (Utils.getBay(locNo) == nearbay && Utils.getLev(locNo) == nearlev) { continue; } else { nearbay = Utils.getBay(locNo); nearlev = Utils.getLev(locNo); } // List groupOutsideLocCrn = Utils.getGroupOutLocCrn(curRow,nearRow,wrkMast.getLocNo(), curRow>nearRow); LocMast locMastGro = locMastService.selectById(locNo); for (int i = 0; i < crnNumber * 2; i++) { if (!(Utils.getRow(locMastGro.getLocNo()) > nearRowW && Utils.getRow(locMastGro.getLocNo()) <= curRowW) && !(Utils.getRow(locMastGro.getLocNo()) < nearRowW && Utils.getRow(locMastGro.getLocNo()) >= curRowW)) { int[] locNecessaryParameters = Utils.LocNecessaryParameters(rowLastno, curRowW, crnNumber); curRowW = locNecessaryParameters[1]; nearRowW = locNecessaryParameters[3]; } else { break; } } LocMast locMast2 = locMastService.selectLocByLocStsPakInF(curRowW, nearRowW, locMastGro, rowLastnoType.getType().longValue()); if (!Cools.isEmpty(locMast2) && Utils.getRow(locMast2.getLocNo()) != nearRowW && locMast2.getLocSts().equals("S")) { int row2 = 0; if (Utils.getRow(locMast2.getLocNo()) > nearRowW) { row2 = Utils.getRow(locMast2.getLocNo()) - 1; } else { row2 = Utils.getRow(locMast2.getLocNo()) + 1; } String targetLocNo = zerofill(String.valueOf(row2), 2) + locMast2.getLocNo().substring(2); locMast = locMastService.selectOne(new EntityWrapper().eq("loc_no", targetLocNo).eq("loc_sts", "O")); if (Cools.isEmpty(locMast)) { continue; } break; } } } // // 靠近摆放规则 --- 空托 //分离版 // if (staDescId == 10 && Utils.BooleanWhsTypeStaIoType(rowLastno)) { // List locMasts = locMastService.selectList(new EntityWrapper().eq("row1", nearRow).eq("loc_sts", "O")); // for (LocMast locMast1:locMasts){ // //获取巷道 //// List groupOutsideLocCrn = Utils.getGroupOutLocCrn(curRow,nearRow,locMast1.getLocNo(), curRow>nearRow); // //获取目标库位所在巷道最浅非空库位 // LocMast locMastF = locMastService.selectLocByLocStsPakInF(curRow,nearRow,locMast1,rowLastnoType.getType().longValue()); // if (!Cools.isEmpty(locMastF) && locMastF.getLocSts().equals("D")){ // //获取目标库位所在巷道最浅非空库位 // locMast = locMastService.selectLocByLocStsPakInO(curRow,nearRow,locMast1,rowLastnoType.getType().longValue()); // break; // } // } // } // 靠近摆放规则 --- 空托 //互通版 if (staDescId == 10 && Utils.BooleanWhsTypeStaIoType(rowLastno)) { List locMasts = locMastService.selectList(new EntityWrapper().eq("loc_sts", "D").ge("row1", sRow).le("row1", eRow)); int nearbay = 0; int nearlev = 0; for (LocMast locMastSign : locMasts) { int curRowW = curRow; //相似工作档案 最深库位排 int nearRowW = nearRow; //相似工作档案 最浅库位排 if (Cools.isEmpty(locMastSign.getLocNo())) { continue; } if (Utils.getRow(locMastSign.getLocNo()) == nearRow) { continue; } if (Utils.getBay(locMastSign.getLocNo()) == nearbay && Utils.getLev(locMastSign.getLocNo()) == nearlev) { continue; } else { nearbay = Utils.getBay(locMastSign.getLocNo()); nearlev = Utils.getLev(locMastSign.getLocNo()); } // List groupOutsideLocCrn = Utils.getGroupOutLocCrn(curRow,nearRow,wrkMast.getLocNo(), curRow>nearRow); LocMast locMastGro = locMastService.selectById(locMastSign.getLocNo()); for (int i = 0; i < crnNumber * 2; i++) { if (!(Utils.getRow(locMastGro.getLocNo()) > nearRowW && Utils.getRow(locMastGro.getLocNo()) <= curRowW) && !(Utils.getRow(locMastGro.getLocNo()) < nearRowW && Utils.getRow(locMastGro.getLocNo()) >= curRowW)) { int[] locNecessaryParameters = Utils.LocNecessaryParameters(rowLastno, curRowW, crnNumber); curRowW = locNecessaryParameters[1]; nearRowW = locNecessaryParameters[3]; } else { break; } } LocMast locMast2 = locMastService.selectLocByLocStsPakInF(curRowW, nearRowW, locMastGro, rowLastnoType.getType().longValue()); if (!Cools.isEmpty(locMast2) && Utils.getRow(locMast2.getLocNo()) != nearRowW && locMast2.getLocSts().equals("S")) { int row2 = 0; if (Utils.getRow(locMast2.getLocNo()) > nearRowW) { row2 = Utils.getRow(locMast2.getLocNo()) - 1; } else { row2 = Utils.getRow(locMast2.getLocNo()) + 1; } String targetLocNo = zerofill(String.valueOf(row2), 2) + locMast2.getLocNo().substring(2); locMast = locMastService.selectOne(new EntityWrapper().eq("loc_no", targetLocNo).eq("loc_sts", "O")); if (Cools.isEmpty(locMast)) { continue; } break; } } } Wrapper wrapper = null; StaDesc staDesc = null; BasDevp staNo = null; if (Utils.BooleanWhsTypeSta(rowLastno, staDescId)) { // 获取目标站 wrapper = new EntityWrapper() .eq("type_no", staDescId) .eq("stn_no", sourceStaNo) .eq("crn_no", crnNo); staDesc = staDescService.selectOne(wrapper); if (Cools.isEmpty(staDesc)) { log.error("入库路径不存在:type_no={},stn_no={},crn_no={}", staDescId, sourceStaNo, crnNo); crnNo = 0; } else { staNo = basDevpService.selectById(staDesc.getCrnStn()); if (!staNo.getAutoing().equals("Y")) { log.error("目标站" + staDesc.getCrnStn() + "不可用"); crnNo = 0; } startupDto.setStaNo(staNo.getDevNo()); } } // 更新库位排号 if (Utils.BooleanWhsTypeSta(rowLastno, staDescId) && Cools.isEmpty(locMast)) { rowLastno.setCurrentRow(curRow); rowLastnoService.updateById(rowLastno); } // 开始查找库位 ==============================>> // 1.按规则查找库位 if (Cools.isEmpty(locMast) && crnNo != 0) { List locMasts = locMastService.selectList(new EntityWrapper() .eq("row1", nearRow) .eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue()) .orderBy("lev1", true).orderBy("bay1", true));//最浅库位 for (LocMast locMast1 : locMasts) { if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) { continue; } if (Utils.BooleanWhsTypeStaIoType(rowLastno)) { //获取目标库位所在巷道最深空库位 LocMast locMast2 = locMastService.selectLocByLocStsPakInO(curRow, nearRow, locMast1, rowLastnoType.getType().longValue()); if (!Cools.isEmpty(locMast2) && locMast2.getBay1() == curRow) { locMast = locMast2; break; } } } //未找到 允许混料 if (Cools.isEmpty(locMast) && Utils.BooleanWhsTypeStaIoType(rowLastno)) { for (LocMast locMast1 : locMasts) { if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) { continue; } if (Utils.BooleanWhsTypeStaIoType(rowLastno)) { // ????????????? // List groupOutsideLocCrn = Utils.getGroupOutLocCrn(curRow,nearRow,locMast1.getLocNo(), curRow>nearRow); // ???????????????? LocMast locMast2 = locMastService.selectLocByLocStsPakInF(curRow, nearRow, locMast1, rowLastnoType.getType().longValue()); if (Cools.isEmpty(locMast2)) { LocMast locMast3 = locMastService.selectLocByLocStsPakInO(curRow, nearRow, locMast1, rowLastnoType.getType().longValue()); if (!Cools.isEmpty(locMast3)) { locMast = locMast3; break; } } else { if ((locMast2.getLocSts().equals("F") && staDescId == 1) || (locMast2.getLocSts().equals("D") && staDescId == 10)) { LocMast locMast3 = locMastService.selectLocByLocStsPakInO(curRow, nearRow, locMast1, rowLastnoType.getType().longValue()); if (!Cools.isEmpty(locMast3)) { locMast = locMast3; break; } } } } } } } // Retry search if (Cools.isEmpty(locMast) || !locMast.getLocSts().equals("O")) { // Scan next aisle first, then retry with upward-compatible locType1. if (times < rowCount * 2) { times = times + 1; return getLocNoRun4(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, locTypeDto, times); } LocTypeDto compatibleLocTypeDto = buildUpwardCompatibleLocTypeDto(locTypeDto); if (compatibleLocTypeDto != null) { log.warn("locType1 upward compatibility retry. source={}, target={}", JSON.toJSONString(locTypeDto), JSON.toJSONString(compatibleLocTypeDto)); return getLocNoRun4(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, compatibleLocTypeDto, 0); } log.error("No empty location found. spec={}, times={}", JSON.toJSONString(locTypeDto), times); throw new CoolException("\u6ca1\u6709\u7a7a\u5e93\u4f4d"); } String locNo = locMast.getLocNo(); // 生成工作号 int workNo = getWorkNo(0); // 返回dto startupDto.setWorkNo(workNo); startupDto.setCrnNo(crnNo); startupDto.setSourceStaNo(sourceStaNo); startupDto.setLocNo(locNo); return startupDto; } public StartupDto getLocNoRun5(Integer whsType, Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, Integer moveCrnNo, LocTypeDto locTypeDto, List recommendRows, int times) { // 初始化参数 int crnNo = 0; //堆垛机号 int nearRow = 0; //最浅库位排 int curRow = 0; //最深库位排 int rowCount = 0; //轮询轮次 LocMast locMast = null; // 目标库位 StartupDto startupDto = new StartupDto(); RowLastno rowLastno = rowLastnoService.selectById(whsType); if (Cools.isEmpty(rowLastno)) { throw new CoolException("数据异常,请联系管理员===>库位规则未知"); } RowLastnoType rowLastnoType = rowLastnoTypeService.selectById(rowLastno.getTypeId()); if (Cools.isEmpty(rowLastnoType)) { throw new CoolException("数据异常,请联系管理员===》库位规则类型未知"); } int sRow = rowLastno.getsRow(); int eRow = rowLastno.geteRow(); int crnNumber = eRow - sRow + 1; // ===============>>>> 开始执行 curRow = rowLastno.getCurrentRow(); if (!Cools.isEmpty(moveCrnNo) && moveCrnNo != 0) { crnNumber = moveCrnNo; } //此程序用于优化堆垛机异常时的运行时间 int[] locNecessaryParameters = Utils.LocNecessaryParameters(rowLastno, curRow, crnNumber); curRow = locNecessaryParameters[1]; crnNo = 6; rowCount = locNecessaryParameters[0]; nearRow = locNecessaryParameters[3]; Wrapper wrapper = null; StaDesc staDesc = null; BasDevp staNo = null; // if (Utils.BooleanWhsTypeSta(rowLastno, staDescId)) { // 获取目标站 // wrapper = new EntityWrapper() // .eq("type_no", staDescId) // .eq("stn_no", sourceStaNo) // .eq("crn_no", crnNo); // staDesc = staDescService.selectOne(wrapper); // if (Cools.isEmpty(staDesc)) { // log.error("type_no={},stn_no={},crn_no={}", staDescId, sourceStaNo, crnNo); //// throw new CoolException("入库路径不存在"); // crnNo = 0; // } // else { // staNo = basDevpService.selectById(staDesc.getCrnStn()); // if (!staNo.getAutoing().equals("Y")) { // log.error("目标站" + staDesc.getCrnStn() + "不可用"); //// throw new CoolException("目标站"+staDesc.getCrnStn()+"不可用"); // crnNo = 0; // } // startupDto.setStaNo(staNo.getDevNo()); // } // } // 更新库位排号 if (Utils.BooleanWhsTypeSta(rowLastno, staDescId) && Cools.isEmpty(locMast)) { rowLastno.setCurrentRow(curRow); rowLastnoService.updateById(rowLastno); } // 开始查找库位 ==============================>> if (Cools.isEmpty(locMast) && !Cools.isEmpty(recommendRows)) { for (Integer recommendRow : recommendRows) { if (Cools.isEmpty(recommendRow)) { continue; } LocMast recommendLoc = locMastService.queryFreeLocMast(recommendRow, locTypeDto.getLocType1(), rowLastnoType.getType().longValue()); if (!Cools.isEmpty(recommendLoc) && VersionUtils.locMoveCheckLocTypeComplete(recommendLoc, locTypeDto)) { locMast = recommendLoc; crnNo = recommendLoc.getCrnNo(); break; } } } if (Cools.isEmpty(locMast) && sourceStaNo != 4006) {//si'lou'p四楼盘点选择区域 List locMasts = locMastService.selectList(new EntityWrapper() .eq("row1", nearRow) .eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue()) .orderBy("lev1", true).orderBy("bay1", true)); // 最浅库位 for (LocMast locMast1 : locMasts) { if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) { continue; } if (Utils.BooleanWhsTypeStaIoType(rowLastno)) { // 获取目标库位所在巷道最深空库位 LocMast locMast2 = locMastService.selectLocByLocStsPakInO(curRow, nearRow, locMast1, rowLastnoType.getType().longValue()); if (!Cools.isEmpty(locMast2) && locMast2.getRow1() == curRow) { locMast = locMast2; break; } } } } else { // 根据 findLocNoAttributeVo.getOutArea() 设置列范围 int startBay = 1; int endBay = 19; switch (findLocNoAttributeVo.getOutArea()) { case 3: startBay = 15; endBay = 19; break; case 2: startBay = 8; endBay = 14; break; case 1: startBay = 1; endBay = 8; break; default: break; } // 优先从指定列范围查找 boolean found = false; // 按照排号从38到32递减查找,优先查找指定列范围(如1-8、8-14、15-19) for (int row = 38; row >= 32; row--) { List locMasts = locMastService.selectList(new EntityWrapper() .eq("row1", row) .ge("bay1", startBay) .le("bay1", endBay) .eq("loc_sts", "O") .eq("whs_type", rowLastnoType.getType().longValue()) .orderBy("lev1", true) .orderBy("bay1", true)); // 最浅库位 for (LocMast locMast1 : locMasts) { if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) { continue; } if(locMast1!= null){ locMast = locMast1; found = true; break; } // if (Utils.BooleanWhsTypeStaIoType(rowLastno)) { // // 获取目标库位所在巷道最深空库位 // LocMast locMast2 = locMastService.selectLocByLocStsPakInO(curRow, nearRow, locMast1, rowLastnoType.getType().longValue()); // if (!Cools.isEmpty(locMast2) && locMast2.getRow1() == curRow) { // locMast = locMast2; // found = true; // break; // } // } } if (found) { break; // 找到目标库位后跳出循环 } } // 如果没有在优先范围内找到合适库位,继续进行全局查找(1-19列) if (!found) { // 从排号38到32查找所有列(1-19) for (int row = 38; row >= 32; row--) { List locMasts = locMastService.selectList(new EntityWrapper() .eq("row1", row) .ge("bay1", 1) // 查找1到19列 .le("bay1", 19) .eq("loc_sts", "O") .eq("whs_type", rowLastnoType.getType().longValue()) .orderBy("lev1", true) .orderBy("bay1", true)); // 最浅库位 for (LocMast locMast1 : locMasts) { if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) { continue; } if (Utils.BooleanWhsTypeStaIoType(rowLastno)) { // ??????????????? LocMast locMast2 = locMastService.selectLocByLocStsPakInO(curRow, nearRow, locMast1, rowLastnoType.getType().longValue()); if (!Cools.isEmpty(locMast2) && locMast2.getRow1() == curRow) { locMast = locMast2; found = true; break; } } } if (found) { break; // ??????????? } } } } // Retry search if (Cools.isEmpty(locMast) || !locMast.getLocSts().equals("O")) { // Scan next aisle first, then retry with upward-compatible locType1. if (times < rowCount * 2) { times = times + 1; return getLocNoRun5(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, locTypeDto, recommendRows, times); } LocTypeDto compatibleLocTypeDto = buildUpwardCompatibleLocTypeDto(locTypeDto); if (compatibleLocTypeDto != null) { log.warn("locType1 upward compatibility retry. source={}, target={}", JSON.toJSONString(locTypeDto), JSON.toJSONString(compatibleLocTypeDto)); return getLocNoRun5(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, compatibleLocTypeDto, recommendRows, 0); } log.error("No empty location found. spec={}, times={}", JSON.toJSONString(locTypeDto), times); throw new CoolException("\u6ca1\u6709\u7a7a\u5e93\u4f4d"); } String locNo = locMast.getLocNo(); // 生成工作号 int workNo = getWorkNo(0); // 返回dto startupDto.setWorkNo(workNo); startupDto.setCrnNo(crnNo); startupDto.setSourceStaNo(sourceStaNo); startupDto.setLocNo(locNo); return startupDto; } public static String zerofill(String msg, Integer count) { if (msg.length() == count) { return msg; } else if (msg.length() > count) { return msg.substring(0, 16); } else { StringBuilder msgBuilder = new StringBuilder(msg); for (int i = 0; i < count - msg.length(); ++i) { msgBuilder.insert(0, "0"); } return msgBuilder.toString(); } } }