我们现在讨论一下系统找库位方案, 如何实现,对现有找库位规则进行整改,数据库也要整改
1、要能方便的填写单伸堆垛机或双伸堆垛机的深浅库位配置
2、根据设备状态分配库位,离线设备不分配
3、库位分配要均衡到每一个设备
4、库位高度需要匹配到对应库位信息,低库位能向上兼容
5、空托盘优先放在locType2库位=1的库位,没有这种库位了,允许放到其他库位
6、给入库站点设置有限去那些堆垛机,其次去那些堆垛机,弄成页面可以配置入库站点
7、在系统配置新增优先放前几列的配置,当入库的货物是高频货物时放在前几列
8、组托中会标识该托盘是高频还是低频,如果是高频则从前往后找库位,如果是低频则从后往前找库位
9、找库位时locMast中whsType字段无用
| | |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.fasterxml.jackson.annotation.JsonProperty; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | |
| | | @ApiModelProperty("WMS ID") |
| | | private String wms_id; |
| | | |
| | | @ApiModelProperty("客户Id") |
| | | private String customerId; |
| | | |
| | | @ApiModelProperty("客户名称") |
| | | private String customerName; |
| | | |
| | | @ApiModelProperty("item编号") |
| | | private String item; |
| | | |
| | | @JsonProperty("package") |
| | | @JSONField(name = "package") |
| | | @ApiModelProperty("是否散货,0 非散货;1 散货") |
| | | private Integer packageFlag; |
| | | |
| | | @ApiModelProperty("外库门号") |
| | | private String outDoorNo; |
| | | |
| | | @ApiModelProperty("车牌号") |
| | | private String plateNo; |
| | | |
| | | @ApiModelProperty("车次号") |
| | | private String trainNo; |
| | | |
| | | @ApiModelProperty("货物频次:1=高频,2=低频") |
| | | private Integer freqType; |
| | | |
| | | @ApiModelProperty("立方数,单位:立方米") |
| | | private Double cubeNumber; |
| | | |
| | | @ApiModelProperty("集装箱号") |
| | | private String containerNo; |
| | | |
| | | @ApiModelProperty("teu,按orderId去重统计") |
| | | private Integer teu; |
| | | |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | |
| | | return R.error("当前目标库位不存在"); |
| | | } |
| | | |
| | | Integer preferredArea = resolveReassignArea(wrkMast, currentLoc); |
| | | if (preferredArea == null) { |
| | | LocTypeDto locTypeDto = buildReassignLocTypeDto(currentLoc); |
| | | List<Integer> areaOrder = buildReassignAreaOrder(wrkMast, currentLoc); |
| | | if (Cools.isEmpty(areaOrder)) { |
| | | return R.error("无法确定任务所属库区"); |
| | | } |
| | | |
| | | List<Integer> candidateCrnNos = buildReassignCandidateCrnNos(preferredArea, wrkMast.getCrnNo()); |
| | | if (candidateCrnNos.isEmpty()) { |
| | | return R.error("当前库区没有其他堆垛机可供重分配"); |
| | | StartupDto startupDto = null; |
| | | Integer preferredArea = null; |
| | | for (Integer area : areaOrder) { |
| | | List<Integer> candidateCrnNos = buildReassignCandidateCrnNos(area, wrkMast.getCrnNo()); |
| | | if (candidateCrnNos.isEmpty()) { |
| | | continue; |
| | | } |
| | | startupDto = commonService.findRun2InboundLocByCandidateCrnNos( |
| | | wrkMast.getSourceStaNo(), wrkMast.getIoType(), area, candidateCrnNos, locTypeDto); |
| | | if (startupDto != null && !Cools.isEmpty(startupDto.getLocNo())) { |
| | | preferredArea = area; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | LocTypeDto locTypeDto = buildReassignLocTypeDto(currentLoc); |
| | | StartupDto startupDto = commonService.findRun2InboundLocByCandidateCrnNos( |
| | | wrkMast.getSourceStaNo(), wrkMast.getIoType(), preferredArea, candidateCrnNos, locTypeDto); |
| | | if (startupDto == null || Cools.isEmpty(startupDto.getLocNo())) { |
| | | return R.error("当前库区没有可重新分配的空库位"); |
| | | } |
| | |
| | | } |
| | | |
| | | private Integer resolveReassignArea(WrkMast wrkMast, LocMast currentLoc) { |
| | | Integer stationArea = Utils.getStationStorageArea(wrkMast.getSourceStaNo()); |
| | | if (belongsToArea(stationArea, wrkMast.getCrnNo(), currentLoc)) { |
| | | return stationArea; |
| | | List<Integer> stationAreas = Utils.getStationStorageAreas(wrkMast.getSourceStaNo()); |
| | | if (!Cools.isEmpty(stationAreas)) { |
| | | for (Integer area : stationAreas) { |
| | | if (belongsToArea(area, wrkMast.getCrnNo(), currentLoc)) { |
| | | return area; |
| | | } |
| | | } |
| | | } |
| | | Integer fallbackArea = findAreaByCurrentTask(wrkMast.getCrnNo(), currentLoc); |
| | | if (fallbackArea != null) { |
| | | return fallbackArea; |
| | | } |
| | | return stationArea; |
| | | return Utils.getStationStorageArea(wrkMast.getSourceStaNo()); |
| | | } |
| | | |
| | | private Integer findAreaByCurrentTask(Integer currentCrnNo, LocMast currentLoc) { |
| | |
| | | return null; |
| | | } |
| | | |
| | | private List<Integer> buildReassignAreaOrder(WrkMast wrkMast, LocMast currentLoc) { |
| | | LinkedHashSet<Integer> areaOrder = new LinkedHashSet<>(); |
| | | List<Integer> stationAreas = Utils.getStationStorageAreas(wrkMast.getSourceStaNo()); |
| | | if (!Cools.isEmpty(stationAreas)) { |
| | | areaOrder.addAll(stationAreas); |
| | | } |
| | | Integer currentArea = findAreaByCurrentTask(wrkMast.getCrnNo(), currentLoc); |
| | | if (currentArea != null) { |
| | | areaOrder.add(currentArea); |
| | | } |
| | | if (areaOrder.isEmpty()) { |
| | | Integer resolvedArea = resolveReassignArea(wrkMast, currentLoc); |
| | | if (resolvedArea != null) { |
| | | areaOrder.add(resolvedArea); |
| | | } |
| | | } |
| | | return new ArrayList<>(areaOrder); |
| | | } |
| | | |
| | | private boolean belongsToArea(Integer area, Integer currentCrnNo, LocMast currentLoc) { |
| | | if (area == null || area <= 0) { |
| | | return false; |
| | |
| | | import com.baomidou.mybatisplus.plugins.Page; |
| | | import com.zy.asrs.entity.BasDevp; |
| | | import com.zy.asrs.entity.param.BasDevpInitParam; |
| | | import com.zy.asrs.service.BasCrnpService; |
| | | import com.zy.asrs.service.BasDevpService; |
| | | import com.zy.asrs.utils.Utils; |
| | | import com.zy.common.web.BaseController; |
| | | import com.core.annotations.ManagerAuth; |
| | | import com.core.common.BaseRes; |
| | | import com.core.common.Cools; |
| | | import com.core.common.DateUtils; |
| | | import com.core.common.R; |
| | | import com.core.exception.CoolException; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | |
| | | |
| | | @Autowired |
| | | private BasDevpService basDevpService; |
| | | @Autowired |
| | | private BasCrnpService basCrnpService; |
| | | |
| | | @RequestMapping(value = "/basDevp/init/auth") |
| | | @ManagerAuth(memo = "初始化站点") |
| | |
| | | @RequestMapping(value = "/basDevp/add/auth") |
| | | @ManagerAuth(memo = "站点添加") |
| | | public R add(BasDevp basDevp) { |
| | | normalizeInboundPriority(basDevp, null); |
| | | basDevp.setModiUser(getUserId()); |
| | | basDevp.setModiTime(new Date()); |
| | | basDevp.setAppeUser(getUserId()); |
| | |
| | | if (Cools.isEmpty(basDevp) || null==basDevp.getDevNo()){ |
| | | return R.error(); |
| | | } |
| | | BasDevp existing = basDevpService.selectById(basDevp.getDevNo()); |
| | | if (existing == null) { |
| | | return R.error("站点不存在"); |
| | | } |
| | | normalizeInboundPriority(basDevp, existing); |
| | | basDevp.setModiUser(getUserId()); |
| | | basDevp.setModiTime(new Date()); |
| | | basDevpService.updateById(basDevp); |
| | |
| | | return R.ok(); |
| | | } |
| | | |
| | | private void normalizeInboundPriority(BasDevp basDevp, BasDevp existing) { |
| | | if (basDevp == null) { |
| | | return; |
| | | } |
| | | String firstCsv = resolveCsvValue(basDevp.getInFirstCrnCsv(), existing == null ? null : existing.getInFirstCrnCsv()); |
| | | String secondCsv = resolveCsvValue(basDevp.getInSecondCrnCsv(), existing == null ? null : existing.getInSecondCrnCsv()); |
| | | |
| | | List<Integer> firstCrnNos = parseCrnPool("第一优先池", firstCsv); |
| | | List<Integer> secondCrnNos = parseCrnPool("第二优先池", secondCsv); |
| | | Set<Integer> duplicateCrnNos = new LinkedHashSet<>(firstCrnNos); |
| | | duplicateCrnNos.retainAll(secondCrnNos); |
| | | if (!duplicateCrnNos.isEmpty()) { |
| | | throw new CoolException("第一优先池和第二优先池不能重复配置同一台堆垛机:" + duplicateCrnNos); |
| | | } |
| | | |
| | | basDevp.setInFirstCrnCsv(Utils.normalizeCrnCsv(firstCrnNos)); |
| | | basDevp.setInSecondCrnCsv(Utils.normalizeCrnCsv(secondCrnNos)); |
| | | |
| | | if (existing == null) { |
| | | basDevp.setInFirstCrnCurrentNo(null); |
| | | basDevp.setInSecondCrnCurrentNo(null); |
| | | return; |
| | | } |
| | | |
| | | basDevp.setInFirstCrnCurrentNo(resolveCurrentNo(existing.getInFirstCrnCurrentNo(), firstCrnNos)); |
| | | basDevp.setInSecondCrnCurrentNo(resolveCurrentNo(existing.getInSecondCrnCurrentNo(), secondCrnNos)); |
| | | } |
| | | |
| | | private String resolveCsvValue(String incoming, String existing) { |
| | | if (incoming == null) { |
| | | return existing; |
| | | } |
| | | return incoming; |
| | | } |
| | | |
| | | private List<Integer> parseCrnPool(String label, String csv) { |
| | | List<Integer> crnNos; |
| | | try { |
| | | crnNos = Utils.parseCrnNos(csv); |
| | | } catch (CoolException e) { |
| | | throw new CoolException(label + e.getMessage()); |
| | | } |
| | | List<Integer> distinctCrnNos = Utils.distinctCrnNos(crnNos); |
| | | if (crnNos.size() != distinctCrnNos.size()) { |
| | | throw new CoolException(label + "存在重复堆垛机号"); |
| | | } |
| | | for (Integer crnNo : distinctCrnNos) { |
| | | if (basCrnpService.selectById(crnNo) == null) { |
| | | throw new CoolException(label + "包含不存在的堆垛机号:" + crnNo); |
| | | } |
| | | } |
| | | return distinctCrnNos; |
| | | } |
| | | |
| | | private Integer resolveCurrentNo(Integer currentNo, List<Integer> crnNos) { |
| | | if (currentNo == null || Cools.isEmpty(crnNos) || !crnNos.contains(currentNo)) { |
| | | return null; |
| | | } |
| | | return currentNo; |
| | | } |
| | | |
| | | } |
| | |
| | | return R.ok(digitalTwinService.getLocalDetal()); |
| | | } |
| | | |
| | | /** |
| | | * 按库位号查询库存明细 |
| | | * |
| | | * @param locNo 库位号 |
| | | */ |
| | | @RequestMapping(value = "/getLocalDetalByLocNo") |
| | | public R getLocalDetalByLocNo(@RequestParam(required = false) String locNo) { |
| | | if (locNo == null || locNo.trim().isEmpty()) { |
| | | return R.error("locNo不能为空"); |
| | | } |
| | | return R.ok(digitalTwinService.getLocalDetalByLocNo(locNo)); |
| | | } |
| | | |
| | | } |
| | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.*; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | /** |
| | | * Created by vincent on 2022/4/8 |
| | |
| | | private WaitPakinService waitPakinService; |
| | | @Autowired |
| | | private WrkDetlService wrkDetlService; |
| | | @Autowired |
| | | private WrkDetlLogService wrkDetlLogService; |
| | | @Autowired |
| | | private WrkMastService wrkMastService; |
| | | @Autowired |
| | |
| | | HttpServletRequest request) { |
| | | auth(appkey, param, request); |
| | | return R.ok().add(openService.pakinOrderComplete(param)); |
| | | } |
| | | |
| | | /** |
| | | * 托盘入库历史记录重报ERP |
| | | */ |
| | | @PostMapping("/order/pakin/erp/report/v1") |
| | | // @AppAuth(memo = "入库历史重报ERP") |
| | | public synchronized R reportPakinHistoryToErp(@RequestBody(required = false) List<String> barcodes) { |
| | | // auth(appkey, barcodes, request); |
| | | if (Cools.isEmpty(barcodes)) { |
| | | return R.parse(BaseRes.PARAM); |
| | | } |
| | | try { |
| | | return openService.reportPakinHistoryToErp(barcodes); |
| | | } catch (Exception e) { |
| | | return R.error(e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | List<WrkDetl> wrkDetls = wrkDetlService.selectByWrkNo(Integer.valueOf(param.getTaskNo())); |
| | | String costTime = resolveCostTime(wrkMast, wrkDetls); |
| | | |
| | | HashMap<String, Object> map = new HashMap<>(); |
| | | map.put("taskNo", param.getTaskNo()); |
| | | map.put("ioType", wrkMast.getIoType()); |
| | | map.put("costTime", costTime); |
| | | map.put("wrkDetls", wrkDetls); |
| | | |
| | | return R.ok().add(map); |
| | | } |
| | | |
| | | private String resolveCostTime(WrkMast wrkMast, List<WrkDetl> wrkDetls) { |
| | | Date createTime = resolveOrderCreateTime(resolveOrderNo(wrkMast, wrkDetls)); |
| | | if (createTime == null) { |
| | | createTime = resolveTaskCreateTime(wrkMast); |
| | | } |
| | | if (createTime == null) { |
| | | return "0"; |
| | | } |
| | | long minutes = TimeUnit.MILLISECONDS.toMinutes(System.currentTimeMillis() - createTime.getTime()); |
| | | if (minutes < 0L) { |
| | | minutes = 0L; |
| | | } |
| | | return String.valueOf(minutes); |
| | | } |
| | | |
| | | private String resolveOrderNo(WrkMast wrkMast, List<WrkDetl> wrkDetls) { |
| | | if (wrkMast != null && !Cools.isEmpty(wrkMast.getUserNo())) { |
| | | return wrkMast.getUserNo(); |
| | | } |
| | | if (Cools.isEmpty(wrkDetls)) { |
| | | return null; |
| | | } |
| | | for (WrkDetl wrkDetl : wrkDetls) { |
| | | if (wrkDetl != null && !Cools.isEmpty(wrkDetl.getOrderNo())) { |
| | | return wrkDetl.getOrderNo(); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private Date resolveOrderCreateTime(String orderNo) { |
| | | if (Cools.isEmpty(orderNo)) { |
| | | return null; |
| | | } |
| | | |
| | | Date historyCreateTime = minDate( |
| | | minCreateTime(wrkMastLogService.selectList(new EntityWrapper<WrkMastLog>().eq("user_no", orderNo))), |
| | | minCreateTime(wrkDetlLogService.selectList(new EntityWrapper<WrkDetlLog>().eq("order_no", orderNo))) |
| | | ); |
| | | if (historyCreateTime != null) { |
| | | return historyCreateTime; |
| | | } |
| | | |
| | | return minDate( |
| | | minCreateTime(wrkMastService.selectList(new EntityWrapper<WrkMast>().eq("user_no", orderNo))), |
| | | minCreateTime(wrkDetlService.selectList(new EntityWrapper<WrkDetl>().eq("order_no", orderNo))) |
| | | ); |
| | | } |
| | | |
| | | private Date minDate(Date first, Date second) { |
| | | if (first == null) { |
| | | return second; |
| | | } |
| | | if (second == null) { |
| | | return first; |
| | | } |
| | | return first.before(second) ? first : second; |
| | | } |
| | | |
| | | private Date resolveTaskCreateTime(WrkMast wrkMast) { |
| | | if (wrkMast == null) { |
| | | return null; |
| | | } |
| | | return firstDate(wrkMast.getAppeTime(), wrkMast.getIoTime(), wrkMast.getModiTime()); |
| | | } |
| | | |
| | | private Date firstDate(Date... dates) { |
| | | if (dates == null || dates.length == 0) { |
| | | return null; |
| | | } |
| | | for (Date date : dates) { |
| | | if (date != null) { |
| | | return date; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private Date minCreateTime(List<?> list) { |
| | | if (Cools.isEmpty(list)) { |
| | | return null; |
| | | } |
| | | Date min = null; |
| | | for (Object item : list) { |
| | | Date createTime = resolveCreateTime(item); |
| | | if (createTime == null) { |
| | | continue; |
| | | } |
| | | if (min == null || createTime.before(min)) { |
| | | min = createTime; |
| | | } |
| | | } |
| | | return min; |
| | | } |
| | | |
| | | private Date resolveCreateTime(Object item) { |
| | | if (item instanceof WrkMast) { |
| | | WrkMast wrkMast = (WrkMast) item; |
| | | return firstDate(wrkMast.getAppeTime(), wrkMast.getIoTime(), wrkMast.getModiTime()); |
| | | } |
| | | if (item instanceof WrkMastLog) { |
| | | WrkMastLog wrkMastLog = (WrkMastLog) item; |
| | | return firstDate(wrkMastLog.getAppeTime(), wrkMastLog.getIoTime(), wrkMastLog.getModiTime()); |
| | | } |
| | | if (item instanceof WrkDetl) { |
| | | WrkDetl wrkDetl = (WrkDetl) item; |
| | | return firstDate(wrkDetl.getAppeTime(), wrkDetl.getIoTime(), wrkDetl.getModiTime()); |
| | | } |
| | | if (item instanceof WrkDetlLog) { |
| | | WrkDetlLog wrkDetlLog = (WrkDetlLog) item; |
| | | return firstDate(wrkDetlLog.getAppeTime(), wrkDetlLog.getIoTime(), wrkDetlLog.getModiTime()); |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | @RequestMapping("/test/station/storage/crn/list") |
| | | @ManagerAuth(memo = "测试站点库区堆垛机顺序") |
| | | @ManagerAuth(memo = "测试站点入库优先堆垛机顺序") |
| | | public R testStationStorageCrnList(@RequestParam Integer stationId, |
| | | @RequestParam(required = false) Integer locType1, |
| | | @RequestParam(required = false) String matnr) { |
| | |
| | | import com.zy.system.service.UserService; |
| | | import com.core.common.Cools; |
| | | import com.core.common.SpringUtils; |
| | | import com.zy.asrs.utils.Utils; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.Locale; |
| | | |
| | | @Data |
| | |
| | | @TableField("io_time") |
| | | private Date ioTime; |
| | | |
| | | @ApiModelProperty(value= "绑定库区") |
| | | @ApiModelProperty(value= "绑定库区(仅管理用途)") |
| | | private String area; |
| | | |
| | | @ApiModelProperty(value= "入库第一优先堆垛机,CSV") |
| | | @TableField("in_first_crn_csv") |
| | | private String inFirstCrnCsv; |
| | | |
| | | @ApiModelProperty(value= "入库第二优先堆垛机,CSV") |
| | | @TableField("in_second_crn_csv") |
| | | private String inSecondCrnCsv; |
| | | |
| | | @ApiModelProperty(value= "入库第一优先池当前堆垛机号") |
| | | @TableField("in_first_crn_current_no") |
| | | private Integer inFirstCrnCurrentNo; |
| | | |
| | | @ApiModelProperty(value= "入库第二优先池当前堆垛机号") |
| | | @TableField("in_second_crn_current_no") |
| | | private Integer inSecondCrnCurrentNo; |
| | | |
| | | @ApiModelProperty(value= "") |
| | | @TableField("in_ok") |
| | |
| | | if (Cools.isEmpty(this.area)) { |
| | | return ""; |
| | | } |
| | | String normalized = this.area.trim(); |
| | | String upper = normalized.toUpperCase(Locale.ROOT); |
| | | if ("1".equals(normalized) || "A".equals(upper) || "A区".equals(upper) || "A库".equals(upper) || "A库区".equals(upper)) { |
| | | return "A库区"; |
| | | List<Integer> areas = Utils.parseStorageAreas(this.area); |
| | | if (!Cools.isEmpty(areas)) { |
| | | StringBuilder builder = new StringBuilder(); |
| | | for (Integer areaNo : areas) { |
| | | if (builder.length() > 0) { |
| | | builder.append("、"); |
| | | } |
| | | builder.append(Utils.formatStorageArea(areaNo)); |
| | | } |
| | | return builder.toString(); |
| | | } |
| | | if ("2".equals(normalized) || "B".equals(upper) || "B区".equals(upper) || "B库".equals(upper) || "B库区".equals(upper)) { |
| | | return "B库区"; |
| | | } |
| | | if ("3".equals(normalized) || "C".equals(upper) || "C区".equals(upper) || "C库".equals(upper) || "C库区".equals(upper)) { |
| | | return "C库区"; |
| | | } |
| | | return normalized; |
| | | return this.area.trim(); |
| | | } |
| | | public String getLocType1$() { |
| | | if (null == this.locType1){ return null; } |
| | |
| | | @ApiModelProperty(value= "建议入库区域:堆垛机号") |
| | | private String origin; |
| | | |
| | | @ApiModelProperty(value= "货物频次:1=高频,2=低频") |
| | | @TableField("freq_type") |
| | | private Integer freqType; |
| | | |
| | | @ApiModelProperty(value= "库位编码,若有,则存储到指定库位。为后续分区预留") |
| | | private String manu; |
| | | |
| | |
| | | @ApiModelProperty(value= "产地") |
| | | private String origin; |
| | | |
| | | @ApiModelProperty(value= "货物频次:1=高频,2=低频") |
| | | @TableField("freq_type") |
| | | private Integer freqType; |
| | | |
| | | @ApiModelProperty(value= "厂家") |
| | | private String manu; |
| | | |
| | |
| | | |
| | | private String matnr; |
| | | |
| | | private Integer freqType; |
| | | |
| | | private Short locType1; |
| | | |
| | | private Short locType2; |
| | |
| | | |
| | | private String orderNo; |
| | | |
| | | /** |
| | | * 货物频次:1=高频,2=低频 |
| | | */ |
| | | private Integer freqType; |
| | | |
| | | // 物料编号 |
| | | private String matnr = ""; |
| | | |
| | |
| | | private String batchId; |
| | | //货物状态,枚举:0 正常;1 异常; |
| | | private Integer status; |
| | | |
| | | //货物频次,1=高频,2=低频 |
| | | private Integer freqType; |
| | | |
| | | //是否满板,0 空板;1 满板;2 半板; |
| | | private Integer full; |
| | | //建议入库区域,枚举,1 A库;2 B库;3 C库;或某个巷道; |
| | |
| | | import com.zy.asrs.entity.WrkDetl; |
| | | import com.zy.asrs.entity.param.FullStoreParam; |
| | | |
| | | import java.util.List; |
| | | |
| | | public class FindLocNoAttributeVo { |
| | | private String matnr = ""; |
| | | private String specs = ""; |
| | |
| | | private String boxType2 = "1"; |
| | | private String boxType3 = "1"; |
| | | private Integer outArea; |
| | | private List<Integer> outAreas; |
| | | private Integer freqType; |
| | | |
| | | public FindLocNoAttributeVo() { |
| | | } |
| | |
| | | this.boxType1 = waitPakin.getBoxType1(); |
| | | this.boxType2 = waitPakin.getBoxType2(); |
| | | this.boxType3 = waitPakin.getBoxType3(); |
| | | this.freqType = waitPakin.getFreqType(); |
| | | } |
| | | |
| | | public FindLocNoAttributeVo(FullStoreParam.MatCodeStore matCodeStore) { |
| | |
| | | this.outArea = outArea; |
| | | } |
| | | |
| | | public List<Integer> getOutAreas() { |
| | | return outAreas; |
| | | } |
| | | |
| | | public void setOutAreas(List<Integer> outAreas) { |
| | | this.outAreas = outAreas; |
| | | } |
| | | |
| | | public Integer getFreqType() { |
| | | return freqType; |
| | | } |
| | | |
| | | public void setFreqType(Integer freqType) { |
| | | this.freqType = freqType; |
| | | } |
| | | |
| | | |
| | | public boolean beSimilar(LocDetl locDetl){ |
| | | return (this.matnr.equals(locDetl.getMatnr()) |
| | |
| | | import com.zy.asrs.entity.WaitPakinLog; |
| | | import org.apache.ibatis.annotations.Insert; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import org.springframework.stereotype.Repository; |
| | | |
| | | @Mapper |
| | | @Repository |
| | | public interface WaitPakinLogMapper extends BaseMapper<WaitPakinLog> { |
| | | |
| | | @Insert("insert into cust_wait_pakin_log select * from cust_wait_pakin where zpallet=#{zpallet}") |
| | | int save(String zpallet); |
| | | @Insert("insert into cust_wait_pakin_log (zpallet, anfme, loc_no, matnr, maktx, batch, order_no, origin, freq_type, manu, specs, model, color, brand, unit, price, sku, units, barcode, manu_date, item_num, safe_qty, weight, man_length, volume, three_code, supp, supp_code, be_batch, dead_time, dead_warn, source, inspect, danger, status, io_status, modi_time, modi_user, appe_time, appe_user, memo, standby1, standby2, standby3, box_type1, box_type2, box_type3) " + |
| | | "select zpallet, anfme, loc_no, matnr, maktx, batch, order_no, origin, freq_type, manu, specs, model, color, brand, unit, price, sku, units, barcode, manu_date, item_num, safe_qty, weight, man_length, volume, three_code, supp, supp_code, be_batch, dead_time, dead_warn, source, inspect, danger, status, io_status, modi_time, modi_user, appe_time, appe_user, memo, standby1, standby2, standby3, box_type1, box_type2, box_type3 from cust_wait_pakin where zpallet=#{zpallet}") |
| | | int save(@Param("zpallet") String zpallet); |
| | | |
| | | } |
| | |
| | | |
| | | List<Map<String, Object>> getLocalDetal(); |
| | | |
| | | List<Map<String, Object>> getLocalDetalByLocNo(String locNo); |
| | | |
| | | Map<String, Object> getLocInfo(); |
| | | } |
| | |
| | | */ |
| | | List<StockVo> queryStock(); |
| | | |
| | | /** |
| | | * 按托盘码批量重报入库历史到 ERP。 |
| | | */ |
| | | R reportPakinHistoryToErp(List<String> barcodes); |
| | | |
| | | // ------------------------------------------ |
| | | |
| | | // 打包上线 |
| | |
| | | |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public List<Map<String, Object>> getLocalDetalByLocNo(String locNo) { |
| | | if (locNo == null || locNo.trim().isEmpty()) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | List<LocDetl> locDetls = locDetlService.selectList(new EntityWrapper<LocDetl>() |
| | | .eq("loc_no", locNo.trim()) |
| | | .orderBy("appe_time", true)); |
| | | List<Map<String, Object>> result = new ArrayList<>(); |
| | | |
| | | for (LocDetl locDetl : locDetls) { |
| | | Map<String, Object> item = new LinkedHashMap<>(); |
| | | item.put("locNo", locDetl.getLocNo()); |
| | | item.put("zpallet", locDetl.getZpallet()); |
| | | item.put("matnr", locDetl.getMatnr()); |
| | | item.put("maktx", locDetl.getMaktx()); |
| | | item.put("specs", locDetl.getSpecs()); |
| | | item.put("batch", locDetl.getBatch()); |
| | | item.put("anfme", locDetl.getAnfme()); |
| | | item.put("orderNo", locDetl.getOrderNo()); |
| | | item.put("frozen", locDetl.getFrozen()); |
| | | result.add(item); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | public Map<String, Object> getLocInfo() { |
| | | List<LocMast> LocMasts = locMastMapper.selectList(new EntityWrapper<>()); |
| | | Map<String, Object> result = new HashMap<>(); |
| | |
| | | } |
| | | |
| | | Date now = new Date(); |
| | | Integer freqType = resolveCombFreqType(param.getCombMats()); |
| | | boolean allEmpty = true; |
| | | if (param.getCombMats() != null) { |
| | | for (CombParam.CombMat mat : param.getCombMats()) { |
| | |
| | | waitPakin.setZpallet(param.getBarcode()); // 托盘码 |
| | | waitPakin.setIoStatus("N"); // 入出状态 |
| | | waitPakin.setAnfme(detlDto.getAnfme()); // 数量 |
| | | waitPakin.setFreqType(freqType); |
| | | waitPakin.setStatus("Y"); // 状态 |
| | | waitPakin.setAppeUser(userId); |
| | | waitPakin.setAppeTime(now); |
| | |
| | | waitPakin.setZpallet(param.getBarcode()); // 托盘码 |
| | | waitPakin.setIoStatus("N"); // 入出状态 |
| | | waitPakin.setAnfme(detlDto.getAnfme()); // 数量 |
| | | waitPakin.setFreqType(freqType); |
| | | waitPakin.setStatus("Y"); // 状态 |
| | | waitPakin.setAppeUser(userId); |
| | | waitPakin.setAppeTime(now); |
| | |
| | | // orderService.updateSettle(order.getId(), 2L, userId); |
| | | OrderInAndOutUtil.updateOrder(Boolean.TRUE,order.getId(), 2L, userId); |
| | | } |
| | | } |
| | | |
| | | private Integer resolveCombFreqType(List<CombParam.CombMat> combMats) { |
| | | Integer resolvedFreqType = null; |
| | | if (Cools.isEmpty(combMats)) { |
| | | return null; |
| | | } |
| | | for (CombParam.CombMat combMat : combMats) { |
| | | if (combMat == null || combMat.getFreqType() == null || combMat.getFreqType() <= 0) { |
| | | continue; |
| | | } |
| | | if (resolvedFreqType == null) { |
| | | resolvedFreqType = combMat.getFreqType(); |
| | | continue; |
| | | } |
| | | if (!resolvedFreqType.equals(combMat.getFreqType())) { |
| | | throw new CoolException("组托货物频次不一致"); |
| | | } |
| | | } |
| | | return resolvedFreqType; |
| | | } |
| | | |
| | | |
| | |
| | | throw new CoolException(param.getBarcode() + "数据正在进行入库"); |
| | | } |
| | | Date now = new Date(); |
| | | Integer freqType = resolveCombFreqType(param.getCombMats()); |
| | | |
| | | boolean packDown = Parameter.get().getPackDown().equals("true"); |
| | | |
| | |
| | | waitPakin.setZpallet(param.getBarcode()); // 托盘码 |
| | | waitPakin.setIoStatus("N"); // 入出状态 |
| | | waitPakin.setAnfme(detlDto.getAnfme()); // 数量 |
| | | waitPakin.setFreqType(freqType); |
| | | waitPakin.setStatus("Y"); // 状态 |
| | | waitPakin.setAppeUser(userId); |
| | | waitPakin.setAppeTime(now); |
| | |
| | | import com.zy.asrs.utils.Utils; |
| | | import com.zy.common.constant.AgvConstant; |
| | | import com.zy.common.constant.ArmConstant; |
| | | import com.zy.common.entity.Parameter; |
| | | import com.zy.common.model.DetlDto; |
| | | import com.zy.common.model.LocDetlDto; |
| | | import com.zy.common.model.LocDto; |
| | |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | |
| | | @Slf4j |
| | | @Service |
| | | public class OpenServiceImpl implements OpenService { |
| | | |
| | | private static final Map<Integer, BigDecimal> INBOUND_WEIGHT_FACTOR_BY_SOURCE_STA; |
| | | private static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; |
| | | |
| | | static { |
| | | Map<Integer, BigDecimal> factorMap = new HashMap<>(); |
| | | factorMap.put(112, new BigDecimal("0.98")); |
| | | INBOUND_WEIGHT_FACTOR_BY_SOURCE_STA = Collections.unmodifiableMap(factorMap); |
| | | } |
| | | |
| | | @Autowired |
| | | private OrderService orderService; |
| | |
| | | private String stationAddress; |
| | | @Value("${erp.address.URL:}") |
| | | private String erpUrl; |
| | | @Value("${erp.switch.ErpReportOld}") |
| | | private boolean erpReportOld; |
| | | @Value("${erp.address.Inaddress:}") |
| | | private String erpInAddress; |
| | | @Value("${erp.address.OutErroraddress:}") |
| | | private String erpOutErrorAddress; |
| | | @Autowired |
| | | private WaitPakinService waitPakinService; |
| | | @Autowired |
| | | private WaitPakinLogService waitPakinLogService; |
| | | @Autowired |
| | | private WrkMastService wrkMastService; |
| | | @Autowired |
| | | private WrkMastLogService wrkMastLogService; |
| | | @Autowired |
| | | private WrkDetlLogService wrkDetlLogService; |
| | | @Autowired |
| | | private WcsApiService wcsApiService; |
| | | @Autowired |
| | |
| | | @Transactional |
| | | public List<StockVo> queryStock() { |
| | | return locDetlService.queryStockTotal(); |
| | | } |
| | | |
| | | @Override |
| | | public R reportPakinHistoryToErp(List<String> barcodes) { |
| | | List<String> normalizedBarcodes = normalizeBarcodes(barcodes); |
| | | if (normalizedBarcodes.isEmpty()) { |
| | | return R.error("托盘码集合不能为空"); |
| | | } |
| | | if (!isErpReportEnabled()) { |
| | | return R.error("ERP reporting is disabled"); |
| | | } |
| | | if (Cools.isEmpty(erpInAddress)) { |
| | | return R.error("ERP入库上报地址未配置"); |
| | | } |
| | | |
| | | Map<String, WrkMastLog> latestInboundLogMap = loadLatestInboundHistoryLogMap(normalizedBarcodes); |
| | | Map<Integer, List<WrkDetlLog>> wrkDetlLogMap = loadWrkDetlLogMap(latestInboundLogMap.values()); |
| | | Map<String, WaitPakinLog> waitPakinLogMap = loadWaitPakinLogMap(normalizedBarcodes); |
| | | String requestUrl = buildErpInboundRequestUrl(); |
| | | |
| | | List<Map<String, Object>> rows = new ArrayList<>(); |
| | | int successCount = 0; |
| | | int failCount = 0; |
| | | |
| | | for (String barcode : normalizedBarcodes) { |
| | | Map<String, Object> row = new LinkedHashMap<>(); |
| | | row.put("barcode", barcode); |
| | | |
| | | WrkMastLog wrkMastLog = latestInboundLogMap.get(barcode); |
| | | if (wrkMastLog == null) { |
| | | row.put("success", false); |
| | | row.put("message", "未找到最新入库历史记录"); |
| | | rows.add(row); |
| | | failCount++; |
| | | continue; |
| | | } |
| | | |
| | | WaitPakinLog waitPakinLog = waitPakinLogMap.get(barcode); |
| | | List<WrkDetlLog> wrkDetlLogs = wrkDetlLogMap.getOrDefault(wrkMastLog.getWrkNo(), Collections.emptyList()); |
| | | ErpPakinReportParam param = buildInboundErpParam(barcode, wrkMastLog, wrkDetlLogs, waitPakinLog); |
| | | if (Cools.isEmpty(param.getPalletId())) { |
| | | row.put("success", false); |
| | | row.put("message", "托盘码缺少上报字段[palletId]"); |
| | | rows.add(row); |
| | | failCount++; |
| | | continue; |
| | | } |
| | | if (Cools.isEmpty(param.getLocId())) { |
| | | row.put("success", false); |
| | | row.put("message", "托盘码缺少上报字段[locId]"); |
| | | rows.add(row); |
| | | failCount++; |
| | | continue; |
| | | } |
| | | |
| | | String request = JSON.toJSONString(param); |
| | | String response = ""; |
| | | boolean success = false; |
| | | String errorMsg = null; |
| | | try { |
| | | response = new HttpHandler.Builder() |
| | | .setUri(erpUrl) |
| | | .setPath(erpInAddress) |
| | | .setJson(request) |
| | | .build() |
| | | .doPost(); |
| | | success = isErpCallSuccess(response); |
| | | if (!success) { |
| | | errorMsg = extractErpCallError(response); |
| | | } |
| | | } catch (Exception e) { |
| | | errorMsg = e.getMessage(); |
| | | } finally { |
| | | try { |
| | | apiLogService.save( |
| | | "Inbound ERP Report", |
| | | requestUrl, |
| | | null, |
| | | "127.0.0.1", |
| | | request, |
| | | response, |
| | | success, |
| | | "barcode=" + barcode + ",workNo=" + wrkMastLog.getWrkNo() |
| | | ); |
| | | } catch (Exception logEx) { |
| | | log.error("save inbound erp api log failed", logEx); |
| | | } |
| | | } |
| | | |
| | | row.put("workNo", wrkMastLog.getWrkNo()); |
| | | Integer sourceStaNo = resolveInboundSourceStaNo(wrkMastLog); |
| | | row.put("sourceStaNo", sourceStaNo); |
| | | row.put("weightFactor", resolveInboundWeightFactor(sourceStaNo)); |
| | | row.put("erpWeight", param.getWeight()); |
| | | row.put("success", success); |
| | | row.put("message", success ? "OK" : errorMsg); |
| | | rows.add(row); |
| | | |
| | | if (success) { |
| | | successCount++; |
| | | } else { |
| | | failCount++; |
| | | } |
| | | } |
| | | |
| | | Map<String, Object> result = new LinkedHashMap<>(); |
| | | result.put("total", normalizedBarcodes.size()); |
| | | result.put("successCount", successCount); |
| | | result.put("failCount", failCount); |
| | | result.put("rows", rows); |
| | | return R.ok().add(result); |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | waitPakin.setIoStatus("N"); // 入出状态 |
| | | waitPakin.setAnfme(param.getAnfme()); // 数量 |
| | | waitPakin.setFreqType(param.getFreqType()); |
| | | waitPakin.setStatus("Y"); // 状态 |
| | | waitPakin.setAppeUser(9995L); |
| | | waitPakin.setAppeTime(now); |
| | |
| | | return response; |
| | | } |
| | | |
| | | private boolean isErpReportEnabled() { |
| | | if (!erpReportOld) { |
| | | return false; |
| | | } |
| | | String erpReport = Parameter.get().getErpReport(); |
| | | return Cools.isEmpty(erpReport) || "true".equalsIgnoreCase(erpReport); |
| | | } |
| | | |
| | | private List<String> normalizeBarcodes(List<String> barcodes) { |
| | | if (barcodes == null || barcodes.isEmpty()) { |
| | | return Collections.emptyList(); |
| | | } |
| | | LinkedHashSet<String> normalized = new LinkedHashSet<>(); |
| | | for (String barcode : barcodes) { |
| | | if (barcode == null) { |
| | | continue; |
| | | } |
| | | String value = barcode.trim(); |
| | | if (!value.isEmpty()) { |
| | | normalized.add(value); |
| | | } |
| | | } |
| | | return new ArrayList<>(normalized); |
| | | } |
| | | |
| | | private Map<String, WrkMastLog> loadLatestInboundHistoryLogMap(List<String> barcodes) { |
| | | Map<String, WrkMastLog> latestInboundLogMap = new LinkedHashMap<>(); |
| | | if (barcodes == null || barcodes.isEmpty()) { |
| | | return latestInboundLogMap; |
| | | } |
| | | List<WrkMastLog> wrkMastLogs = wrkMastLogService.selectList(new EntityWrapper<WrkMastLog>() |
| | | .in("barcode", barcodes) |
| | | .orderBy("barcode", true) |
| | | .orderBy("io_time", false) |
| | | .orderBy("wrk_no", false)); |
| | | if (Cools.isEmpty(wrkMastLogs)) { |
| | | return latestInboundLogMap; |
| | | } |
| | | for (WrkMastLog wrkMastLog : wrkMastLogs) { |
| | | if (wrkMastLog == null || Cools.isEmpty(wrkMastLog.getBarcode())) { |
| | | continue; |
| | | } |
| | | if (!isInboundHistoryLog(wrkMastLog.getIoType())) { |
| | | continue; |
| | | } |
| | | latestInboundLogMap.putIfAbsent(wrkMastLog.getBarcode(), wrkMastLog); |
| | | } |
| | | return latestInboundLogMap; |
| | | } |
| | | |
| | | private boolean isInboundHistoryLog(Integer ioType) { |
| | | if (ioType == null) { |
| | | return false; |
| | | } |
| | | // 历史表里既有入库完成,也有库存调整;这里只取真正的入库类记录。 |
| | | return ioType < 19 || ioType == 53 || ioType == 54 || ioType == 57; |
| | | } |
| | | |
| | | private Map<Integer, List<WrkDetlLog>> loadWrkDetlLogMap(Collection<WrkMastLog> wrkMastLogs) { |
| | | Map<Integer, List<WrkDetlLog>> wrkDetlLogMap = new HashMap<>(); |
| | | if (wrkMastLogs == null || wrkMastLogs.isEmpty()) { |
| | | return wrkDetlLogMap; |
| | | } |
| | | LinkedHashSet<Integer> wrkNos = new LinkedHashSet<>(); |
| | | for (WrkMastLog wrkMastLog : wrkMastLogs) { |
| | | if (wrkMastLog != null && wrkMastLog.getWrkNo() != null) { |
| | | wrkNos.add(wrkMastLog.getWrkNo()); |
| | | } |
| | | } |
| | | if (wrkNos.isEmpty()) { |
| | | return wrkDetlLogMap; |
| | | } |
| | | List<WrkDetlLog> wrkDetlLogs = wrkDetlLogService.selectList(new EntityWrapper<WrkDetlLog>().in("wrk_no", wrkNos)); |
| | | if (Cools.isEmpty(wrkDetlLogs)) { |
| | | return wrkDetlLogMap; |
| | | } |
| | | for (WrkDetlLog wrkDetlLog : wrkDetlLogs) { |
| | | if (wrkDetlLog == null || wrkDetlLog.getWrkNo() == null) { |
| | | continue; |
| | | } |
| | | wrkDetlLogMap.computeIfAbsent(wrkDetlLog.getWrkNo(), k -> new ArrayList<>()).add(wrkDetlLog); |
| | | } |
| | | return wrkDetlLogMap; |
| | | } |
| | | |
| | | private Map<String, WaitPakinLog> loadWaitPakinLogMap(List<String> barcodes) { |
| | | Map<String, WaitPakinLog> waitPakinLogMap = new LinkedHashMap<>(); |
| | | if (barcodes == null || barcodes.isEmpty()) { |
| | | return waitPakinLogMap; |
| | | } |
| | | List<WaitPakinLog> waitPakinLogs = waitPakinLogService.selectList(new EntityWrapper<WaitPakinLog>() |
| | | .in("zpallet", barcodes) |
| | | .orderBy("zpallet", true) |
| | | .orderBy("appe_time", false) |
| | | .orderBy("modi_time", false)); |
| | | if (Cools.isEmpty(waitPakinLogs)) { |
| | | return waitPakinLogMap; |
| | | } |
| | | for (WaitPakinLog waitPakinLog : waitPakinLogs) { |
| | | if (waitPakinLog == null || Cools.isEmpty(waitPakinLog.getZpallet())) { |
| | | continue; |
| | | } |
| | | waitPakinLogMap.putIfAbsent(waitPakinLog.getZpallet(), waitPakinLog); |
| | | } |
| | | return waitPakinLogMap; |
| | | } |
| | | |
| | | private ErpPakinReportParam buildInboundErpParam(String barcode, |
| | | WrkMastLog wrkMastLog, |
| | | List<WrkDetlLog> wrkDetlLogs, |
| | | WaitPakinLog waitPakinLog) { |
| | | ErpPakinReportParam param = new ErpPakinReportParam(); |
| | | param.setPalletId(resolvePalletId(barcode, wrkMastLog, wrkDetlLogs, waitPakinLog)); |
| | | param.setAnfme(resolveInboundAnfme(wrkDetlLogs, waitPakinLog)); |
| | | param.setLocId(transformInboundLocId(resolveInboundLocNo(wrkMastLog, waitPakinLog))); |
| | | param.setWeight(resolveInboundWeight(wrkMastLog, waitPakinLog)); |
| | | param.setCreateTime(formatDate(resolveInboundCreateTime(wrkMastLog))); |
| | | param.setBizNo(resolveInboundBizNo(wrkDetlLogs, waitPakinLog)); |
| | | param.setStartTime(formatDate(resolveInboundStartTime(wrkMastLog, waitPakinLog))); |
| | | return param; |
| | | } |
| | | |
| | | private String resolvePalletId(String barcode, |
| | | WrkMastLog wrkMastLog, |
| | | List<WrkDetlLog> wrkDetlLogs, |
| | | WaitPakinLog waitPakinLog) { |
| | | if (wrkMastLog != null && !Cools.isEmpty(wrkMastLog.getBarcode())) { |
| | | return wrkMastLog.getBarcode(); |
| | | } |
| | | if (wrkDetlLogs != null) { |
| | | for (WrkDetlLog wrkDetlLog : wrkDetlLogs) { |
| | | if (wrkDetlLog != null && !Cools.isEmpty(wrkDetlLog.getZpallet())) { |
| | | return wrkDetlLog.getZpallet(); |
| | | } |
| | | } |
| | | } |
| | | if (waitPakinLog != null && !Cools.isEmpty(waitPakinLog.getZpallet())) { |
| | | return waitPakinLog.getZpallet(); |
| | | } |
| | | return barcode; |
| | | } |
| | | |
| | | private Double resolveInboundAnfme(List<WrkDetlLog> wrkDetlLogs, WaitPakinLog waitPakinLog) { |
| | | double total = 0D; |
| | | boolean hasDetail = false; |
| | | if (wrkDetlLogs != null) { |
| | | for (WrkDetlLog wrkDetlLog : wrkDetlLogs) { |
| | | if (wrkDetlLog == null || wrkDetlLog.getAnfme() == null) { |
| | | continue; |
| | | } |
| | | total += wrkDetlLog.getAnfme(); |
| | | hasDetail = true; |
| | | } |
| | | } |
| | | if (hasDetail) { |
| | | return total; |
| | | } |
| | | if (waitPakinLog != null && waitPakinLog.getAnfme() != null) { |
| | | return waitPakinLog.getAnfme(); |
| | | } |
| | | return total; |
| | | } |
| | | |
| | | private BigDecimal resolveInboundWeight(WrkMastLog wrkMastLog, WaitPakinLog waitPakinLog) { |
| | | BigDecimal baseWeight = BigDecimal.ZERO; |
| | | if (wrkMastLog != null && wrkMastLog.getScWeight() != null) { |
| | | baseWeight = BigDecimal.valueOf(wrkMastLog.getScWeight()); |
| | | } else if (waitPakinLog != null && waitPakinLog.getWeight() != null) { |
| | | baseWeight = BigDecimal.valueOf(waitPakinLog.getWeight()); |
| | | } |
| | | Integer sourceStaNo = resolveInboundSourceStaNo(wrkMastLog); |
| | | return baseWeight.multiply(resolveInboundWeightFactor(sourceStaNo)); |
| | | } |
| | | |
| | | private Integer resolveInboundSourceStaNo(WrkMastLog wrkMastLog) { |
| | | if (wrkMastLog == null) { |
| | | return null; |
| | | } |
| | | if (wrkMastLog.getSourceStaNo() != null) { |
| | | return wrkMastLog.getSourceStaNo(); |
| | | } |
| | | return wrkMastLog.getStaNo(); |
| | | } |
| | | |
| | | private BigDecimal resolveInboundWeightFactor(Integer sourceStaNo) { |
| | | if (sourceStaNo == null) { |
| | | return BigDecimal.ONE; |
| | | } |
| | | BigDecimal factor = INBOUND_WEIGHT_FACTOR_BY_SOURCE_STA.get(sourceStaNo); |
| | | return factor == null ? BigDecimal.ONE : factor; |
| | | } |
| | | |
| | | private String resolveInboundLocNo(WrkMastLog wrkMastLog, WaitPakinLog waitPakinLog) { |
| | | if (wrkMastLog != null && !Cools.isEmpty(wrkMastLog.getLocNo())) { |
| | | return wrkMastLog.getLocNo(); |
| | | } |
| | | if (waitPakinLog != null && !Cools.isEmpty(waitPakinLog.getLocNo())) { |
| | | return waitPakinLog.getLocNo(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private Date resolveInboundCreateTime(WrkMastLog wrkMastLog) { |
| | | if (wrkMastLog == null) { |
| | | return new Date(); |
| | | } |
| | | if (wrkMastLog.getCrnEndTime() != null) { |
| | | return wrkMastLog.getCrnEndTime(); |
| | | } |
| | | if (wrkMastLog.getModiTime() != null) { |
| | | return wrkMastLog.getModiTime(); |
| | | } |
| | | if (wrkMastLog.getIoTime() != null) { |
| | | return wrkMastLog.getIoTime(); |
| | | } |
| | | return new Date(); |
| | | } |
| | | |
| | | private Date resolveInboundStartTime(WrkMastLog wrkMastLog, WaitPakinLog waitPakinLog) { |
| | | if (waitPakinLog != null && waitPakinLog.getAppeTime() != null) { |
| | | return waitPakinLog.getAppeTime(); |
| | | } |
| | | if (wrkMastLog == null) { |
| | | return new Date(); |
| | | } |
| | | if (wrkMastLog.getAppeTime() != null) { |
| | | return wrkMastLog.getAppeTime(); |
| | | } |
| | | if (wrkMastLog.getIoTime() != null) { |
| | | return wrkMastLog.getIoTime(); |
| | | } |
| | | if (wrkMastLog.getModiTime() != null) { |
| | | return wrkMastLog.getModiTime(); |
| | | } |
| | | return new Date(); |
| | | } |
| | | |
| | | private String resolveInboundBizNo(List<WrkDetlLog> wrkDetlLogs, WaitPakinLog waitPakinLog) { |
| | | if (wrkDetlLogs != null) { |
| | | for (WrkDetlLog wrkDetlLog : wrkDetlLogs) { |
| | | if (wrkDetlLog != null && !Cools.isEmpty(wrkDetlLog.getThreeCode())) { |
| | | return wrkDetlLog.getThreeCode(); |
| | | } |
| | | } |
| | | } |
| | | if (waitPakinLog != null && !Cools.isEmpty(waitPakinLog.getThreeCode())) { |
| | | return waitPakinLog.getThreeCode(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private String transformInboundLocId(String locId) { |
| | | if (Cools.isEmpty(locId)) { |
| | | return null; |
| | | } |
| | | String trimmed = locId.trim(); |
| | | if (trimmed.length() < 7) { |
| | | return trimmed; |
| | | } |
| | | String row = trimmed.substring(0, 2); |
| | | String col = trimmed.substring(2, 5); |
| | | String lev = trimmed.substring(5, 7); |
| | | try { |
| | | int rowNo = Integer.parseInt(row); |
| | | if (rowNo >= 37) { |
| | | row = "C" + row; |
| | | } else if (rowNo >= 13) { |
| | | row = "B" + row; |
| | | } else { |
| | | row = "A" + row; |
| | | } |
| | | } catch (Exception ignore) { |
| | | return trimmed; |
| | | } |
| | | return row + "-" + col + "-" + lev; |
| | | } |
| | | |
| | | private String formatDate(Date date) { |
| | | if (date == null) { |
| | | return null; |
| | | } |
| | | return new SimpleDateFormat(DATE_TIME_PATTERN).format(date); |
| | | } |
| | | |
| | | private String buildErpInboundRequestUrl() { |
| | | if (Cools.isEmpty(erpUrl)) { |
| | | return erpInAddress; |
| | | } |
| | | if (erpInAddress == null) { |
| | | return erpUrl; |
| | | } |
| | | if (erpUrl.endsWith("/") && erpInAddress.startsWith("/")) { |
| | | return erpUrl + erpInAddress.substring(1); |
| | | } |
| | | if (!erpUrl.endsWith("/") && !erpInAddress.startsWith("/")) { |
| | | return erpUrl + "/" + erpInAddress; |
| | | } |
| | | return erpUrl + erpInAddress; |
| | | } |
| | | |
| | | private String buildErpOutErrorRequestUrl() { |
| | | if (Cools.isEmpty(erpUrl)) { |
| | | return erpOutErrorAddress; |
| | |
| | | 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) { |
| | | return result; |
| | | } |
| | | |
| | | BasCrnpService basCrnpService = SpringUtils.getBean(BasCrnpService.class); |
| | | LocMastService locMastService = SpringUtils.getBean(LocMastService.class); |
| | | boolean emptyPallet = "emptyPallet".equalsIgnoreCase(matnr); |
| | | |
| | | // 先取当前库区对应的堆垛机。 |
| | | List<Integer> preferredCrnNos = getAreaCrnNos(storageArea, rowLastno); |
| | | List<Integer> preferredAvailableCrnNos = getAvailableCrnNos(preferredCrnNos, locType1, emptyPallet, basCrnpService, locMastService); |
| | | appendCrnLocTypeEntries(result, preferredAvailableCrnNos, locType1, emptyPallet, locMastService); |
| | | |
| | | appendCrnPoolEntries(result, 1, distinctCrnNos(station.getInFirstCrnCsv())); |
| | | appendCrnPoolEntries(result, 2, distinctCrnNos(station.getInSecondCrnCsv())); |
| | | 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 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; |
| | | } |
| | | |
| | | 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; |
| | | } |
| | | |
| | | 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; |
| | | } |
| | | } |
| | |
| | | |
| | | // run2 area C row config |
| | | private String run2Area3Rows; |
| | | |
| | | // 高频货物优先放前几列,0 表示关闭 |
| | | private String highFreqFrontBayCount; |
| | | } |
| | |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.time.temporal.ChronoUnit; |
| | | import java.util.ArrayList; |
| | | import java.util.Comparator; |
| | | import java.util.HashMap; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.List; |
| | | import java.util.Locale; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.Optional; |
| | | |
| | | /** |
| | |
| | | Integer whsType = Utils.GetWhsType(sourceStaNo); |
| | | RowLastno rowLastno = rowLastnoService.selectById(whsType); |
| | | RowLastnoType rowLastnoType = rowLastnoTypeService.selectById(rowLastno.getTypeId()); |
| | | List<Integer> stationAreas = Utils.getStationStorageAreas(sourceStaNo); |
| | | findLocNoAttributeVo.setOutAreas(stationAreas); |
| | | Integer preferredArea = resolvePreferredArea(sourceStaNo, findLocNoAttributeVo); |
| | | if (preferredArea != null) { |
| | | findLocNoAttributeVo.setOutArea(preferredArea); |
| | |
| | | } |
| | | StartupDto startupDto = new StartupDto(); |
| | | LocMast locMast = findRun2EmptyLocByCrnNos(searchRowLastno, rowLastnoType, candidateCrnNos, locTypeDto, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, "reassign-inbound"); |
| | | staDescId, sourceStaNo, startupDto, preferredArea, null, "reassign-inbound"); |
| | | if (Cools.isEmpty(locMast) || !"O".equals(locMast.getLocSts())) { |
| | | return null; |
| | | } |
| | |
| | | /** |
| | | * 空托盘固定按 4 段式找位: |
| | | * 1. 严格高度 + narrow |
| | | * 2. 严格高度 + any locType2 |
| | | * 3. 向上兼容高度 + narrow |
| | | * 4. 向上兼容高度 + any locType2 |
| | | * 2. 向上兼容高度 + narrow |
| | | * 3. 严格高度 + open |
| | | * 4. 向上兼容高度 + open |
| | | */ |
| | | private List<LocTypeDto> buildEmptyPalletSearchLocTypes(LocTypeDto locTypeDto) { |
| | | LinkedHashSet<LocTypeDto> searchLocTypes = new LinkedHashSet<LocTypeDto>(); |
| | | LocTypeDto narrowStrictLocType = copyLocTypeDto(locTypeDto == null ? new LocTypeDto() : locTypeDto); |
| | | if (narrowStrictLocType != null) { |
| | | narrowStrictLocType.setLocType2((short) 1); |
| | | searchLocTypes.add(narrowStrictLocType); |
| | | LocTypeDto openStrictLocType = copyLocTypeDto(narrowStrictLocType); |
| | | openStrictLocType.setLocType2(null); |
| | | searchLocTypes.add(openStrictLocType); |
| | | |
| | | LocTypeDto narrowCompatibleLocType = buildUpwardCompatibleLocTypeDto(narrowStrictLocType); |
| | | if (narrowCompatibleLocType != null) { |
| | | narrowCompatibleLocType.setLocType2((short) 1); |
| | | searchLocTypes.add(narrowCompatibleLocType); |
| | | LocTypeDto openCompatibleLocType = copyLocTypeDto(narrowCompatibleLocType); |
| | | openCompatibleLocType.setLocType2(null); |
| | | searchLocTypes.add(openCompatibleLocType); |
| | | } |
| | | List<LocTypeDto> searchLocTypes = new ArrayList<LocTypeDto>(); |
| | | LocTypeDto baseLocTypeDto = copyLocTypeDto(locTypeDto == null ? new LocTypeDto() : locTypeDto); |
| | | if (baseLocTypeDto == null) { |
| | | return searchLocTypes; |
| | | } |
| | | return new ArrayList<LocTypeDto>(searchLocTypes); |
| | | |
| | | LocTypeDto narrowStrictLocType = copyLocTypeDto(baseLocTypeDto); |
| | | narrowStrictLocType.setLocType2((short) 1); |
| | | searchLocTypes.add(narrowStrictLocType); |
| | | |
| | | LocTypeDto narrowCompatibleLocType = buildUpwardCompatibleLocTypeDto(narrowStrictLocType); |
| | | if (narrowCompatibleLocType != null) { |
| | | narrowCompatibleLocType.setLocType2((short) 1); |
| | | searchLocTypes.add(narrowCompatibleLocType); |
| | | } |
| | | |
| | | LocTypeDto openStrictLocType = copyLocTypeDto(baseLocTypeDto); |
| | | openStrictLocType.setLocType2((short) 0); |
| | | searchLocTypes.add(openStrictLocType); |
| | | |
| | | LocTypeDto openCompatibleLocType = buildUpwardCompatibleLocTypeDto(openStrictLocType); |
| | | if (openCompatibleLocType != null) { |
| | | openCompatibleLocType.setLocType2((short) 0); |
| | | searchLocTypes.add(openCompatibleLocType); |
| | | } |
| | | return searchLocTypes; |
| | | } |
| | | |
| | | private String buildEmptyPalletStageCode(LocTypeDto baseLocTypeDto, LocTypeDto stageLocTypeDto) { |
| | |
| | | * 解析本次找位应优先使用的库区,站点绑定优先于接口传参。 |
| | | */ |
| | | private Integer resolvePreferredArea(Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo) { |
| | | BasDevp sourceStation = basDevpService.selectById(sourceStaNo); |
| | | Integer stationArea = parseArea(sourceStation == null ? null : sourceStation.getArea()); |
| | | Integer stationArea = Utils.getStationStorageArea(sourceStaNo); |
| | | if (stationArea != null) { |
| | | return stationArea; |
| | | } |
| | | Integer requestArea = findLocNoAttributeVo.getOutArea(); |
| | | if (requestArea != null && requestArea >= 1 && requestArea <= 3) { |
| | | if (isValidArea(requestArea)) { |
| | | return requestArea; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 把站点维护的库区值统一解析成 1/2/3。 |
| | | */ |
| | | private Integer parseArea(String area) { |
| | | if (Cools.isEmpty(area)) { |
| | | return null; |
| | | } |
| | | String normalized = area.trim(); |
| | | if (normalized.isEmpty()) { |
| | | return null; |
| | | } |
| | | try { |
| | | int areaNo = Integer.parseInt(normalized); |
| | | return areaNo >= 1 && areaNo <= 3 ? areaNo : null; |
| | | } catch (NumberFormatException ignored) { |
| | | } |
| | | String upper = normalized.toUpperCase(Locale.ROOT); |
| | | if ("A".equals(upper) || "A区".equals(upper) || "A库".equals(upper) || "A库区".equals(upper)) { |
| | | return 1; |
| | | } |
| | | if ("B".equals(upper) || "B区".equals(upper) || "B库".equals(upper) || "B库区".equals(upper)) { |
| | | return 2; |
| | | } |
| | | if ("C".equals(upper) || "C区".equals(upper) || "C库".equals(upper) || "C库区".equals(upper)) { |
| | | return 3; |
| | | } |
| | | return null; |
| | | private boolean isValidArea(Integer area) { |
| | | return area != null && area >= 1 && area <= 3; |
| | | } |
| | | |
| | | /** |
| | |
| | | private LocMast findAgvLocByRows(RowLastno rowLastno, RowLastnoType rowLastnoType, List<Integer> rows, |
| | | int startBay, int endBay, int curRow, int nearRow, |
| | | LocTypeDto locTypeDto, boolean useDeepCheck) { |
| | | return findAgvLocByRows(rowLastno, rowLastnoType, rows, startBay, endBay, curRow, nearRow, locTypeDto, null, useDeepCheck); |
| | | } |
| | | |
| | | private LocMast findAgvLocByRows(RowLastno rowLastno, RowLastnoType rowLastnoType, List<Integer> rows, |
| | | int startBay, int endBay, int curRow, int nearRow, |
| | | LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo, boolean useDeepCheck) { |
| | | for (Integer row : rows) { |
| | | if (row == null) { |
| | | continue; |
| | |
| | | applyLocTypeFilters(wrapper, locTypeDto, true); |
| | | wrapper.orderBy("lev1", true).orderBy("bay1", true); |
| | | List<LocMast> locMasts = locMastService.selectList(wrapper); |
| | | for (LocMast candidate : locMasts) { |
| | | List<LocMast> sortedLocMasts = sortLocCandidates(locMasts, findLocNoAttributeVo); |
| | | for (LocMast candidate : sortedLocMasts) { |
| | | if (!VersionUtils.locMoveCheckLocTypeComplete(candidate, locTypeDto)) { |
| | | continue; |
| | | } |
| | |
| | | } |
| | | |
| | | /** |
| | | * 构造空托盘跨库区搜索顺序: |
| | | * 先当前库区,再依次补足其它库区,避免重复。 |
| | | * 读取站点配置的优先池堆垛机号并做去重。 |
| | | */ |
| | | private List<Integer> buildAreaSearchOrder(Integer preferredArea) { |
| | | private List<Integer> loadPriorityCrnNos(String csv) { |
| | | return Utils.distinctCrnNos(csv); |
| | | } |
| | | |
| | | /** |
| | | * 从候选堆垛机池中移除已经出现在排除列表里的堆垛机,保持原始顺序不变。 |
| | | */ |
| | | private List<Integer> excludePriorityCrnNos(List<Integer> crnNos, List<Integer> excludedCrnNos) { |
| | | List<Integer> result = new ArrayList<Integer>(); |
| | | if (Cools.isEmpty(crnNos)) { |
| | | return result; |
| | | } |
| | | LinkedHashSet<Integer> excludedCrnNoSet = new LinkedHashSet<Integer>(Utils.distinctCrnNos(excludedCrnNos)); |
| | | for (Integer crnNo : Utils.distinctCrnNos(crnNos)) { |
| | | if (crnNo == null || excludedCrnNoSet.contains(crnNo)) { |
| | | continue; |
| | | } |
| | | result.add(crnNo); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 从当前游标的下一台堆垛机开始轮转。 |
| | | */ |
| | | private List<Integer> rotatePriorityCrnNos(List<Integer> crnNos, Integer currentCrnNo) { |
| | | List<Integer> orderedCrnNos = Utils.distinctCrnNos(crnNos); |
| | | if (Cools.isEmpty(orderedCrnNos) || currentCrnNo == null) { |
| | | return orderedCrnNos; |
| | | } |
| | | int currentIndex = orderedCrnNos.indexOf(currentCrnNo); |
| | | if (currentIndex < 0) { |
| | | return orderedCrnNos; |
| | | } |
| | | List<Integer> rotatedCrnNos = new ArrayList<>(); |
| | | for (int index = currentIndex + 1; index < orderedCrnNos.size(); index++) { |
| | | rotatedCrnNos.add(orderedCrnNos.get(index)); |
| | | } |
| | | for (int index = 0; index <= currentIndex; index++) { |
| | | rotatedCrnNos.add(orderedCrnNos.get(index)); |
| | | } |
| | | return rotatedCrnNos; |
| | | } |
| | | |
| | | /** |
| | | * 按第一优先池 -> 第二优先池的顺序查找可用库位。 |
| | | */ |
| | | private LocMast findRun2PriorityLocInPools(BasDevp station, RowLastno rowLastno, RowLastnoType rowLastnoType, |
| | | Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, |
| | | LocTypeDto locTypeDto, StartupDto startupDto, boolean emptyPalletRequest) { |
| | | if (station == null) { |
| | | return null; |
| | | } |
| | | List<Integer> firstPoolCrnNos = loadPriorityCrnNos(station.getInFirstCrnCsv()); |
| | | List<Integer> secondPoolCrnNos = excludePriorityCrnNos(loadPriorityCrnNos(station.getInSecondCrnCsv()), firstPoolCrnNos); |
| | | if (Cools.isEmpty(firstPoolCrnNos) && Cools.isEmpty(secondPoolCrnNos)) { |
| | | throw new CoolException("站点=" + station.getDevNo() + " 未配置入库优先堆垛机"); |
| | | } |
| | | |
| | | if (emptyPalletRequest) { |
| | | for (int poolNo = 1; poolNo <= 2; poolNo++) { |
| | | List<Integer> poolCrnNos = poolNo == 1 ? firstPoolCrnNos : secondPoolCrnNos; |
| | | Integer currentCrnNo = poolNo == 1 ? station.getInFirstCrnCurrentNo() : station.getInSecondCrnCurrentNo(); |
| | | for (LocTypeDto searchLocTypeDto : buildEmptyPalletSearchLocTypes(locTypeDto)) { |
| | | LocMast locMast = findRun2PriorityLocInPool(rowLastno, rowLastnoType, station, poolCrnNos, currentCrnNo, |
| | | poolNo, searchLocTypeDto, staDescId, sourceStaNo, findLocNoAttributeVo, startupDto, true); |
| | | if (locMast != null) { |
| | | return locMast; |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | LocMast locMast = findRun2PriorityLocInPoolWithCompatibility(rowLastno, rowLastnoType, station, firstPoolCrnNos, |
| | | station.getInFirstCrnCurrentNo(), 1, locTypeDto, staDescId, sourceStaNo, findLocNoAttributeVo, startupDto, false); |
| | | if (locMast != null) { |
| | | return locMast; |
| | | } |
| | | return findRun2PriorityLocInPoolWithCompatibility(rowLastno, rowLastnoType, station, secondPoolCrnNos, |
| | | station.getInSecondCrnCurrentNo(), 2, locTypeDto, staDescId, sourceStaNo, findLocNoAttributeVo, startupDto, false); |
| | | } |
| | | |
| | | /** |
| | | * 在单个优先池内按轮转顺序找位。 |
| | | */ |
| | | private LocMast findRun2PriorityLocInPool(RowLastno rowLastno, RowLastnoType rowLastnoType, BasDevp station, |
| | | List<Integer> crnNos, Integer currentCrnNo, int poolNo, LocTypeDto locTypeDto, |
| | | Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, |
| | | StartupDto startupDto) { |
| | | return findRun2PriorityLocInPool(rowLastno, rowLastnoType, station, crnNos, currentCrnNo, poolNo, locTypeDto, |
| | | staDescId, sourceStaNo, findLocNoAttributeVo, startupDto, false); |
| | | } |
| | | |
| | | private LocMast findRun2PriorityLocInPool(RowLastno rowLastno, RowLastnoType rowLastnoType, BasDevp station, |
| | | List<Integer> crnNos, Integer currentCrnNo, int poolNo, LocTypeDto locTypeDto, |
| | | Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, |
| | | StartupDto startupDto, boolean ignoreFreqType) { |
| | | if (Cools.isEmpty(crnNos)) { |
| | | return null; |
| | | } |
| | | List<Integer> rotatedCrnNos = rotatePriorityCrnNos(crnNos, currentCrnNo); |
| | | if (Cools.isEmpty(rotatedCrnNos)) { |
| | | return null; |
| | | } |
| | | for (Integer candidateCrnNo : rotatedCrnNos) { |
| | | if (candidateCrnNo == null || !basCrnpService.checkSiteError(candidateCrnNo, true)) { |
| | | continue; |
| | | } |
| | | Integer targetStaNo = resolveTargetStaNo(rowLastno, staDescId, sourceStaNo, candidateCrnNo); |
| | | if (Utils.BooleanWhsTypeSta(rowLastno, staDescId) && targetStaNo == null) { |
| | | continue; |
| | | } |
| | | Integer preferredNearRow = getCrnStartRow(rowLastno, candidateCrnNo); |
| | | LocMast candidateLoc = findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, candidateCrnNo, |
| | | preferredNearRow, locTypeDto, findLocNoAttributeVo, ignoreFreqType); |
| | | if (Cools.isEmpty(candidateLoc)) { |
| | | continue; |
| | | } |
| | | if (!updatePriorityCursor(station, poolNo, currentCrnNo, candidateCrnNo)) { |
| | | throw new CoolException("站点=" + station.getDevNo() + " 优先池轮转更新失败,请重试"); |
| | | } |
| | | if (targetStaNo != null) { |
| | | startupDto.setStaNo(targetStaNo); |
| | | } |
| | | return candidateLoc; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 在单个优先池内先按当前规格找位,失败后再做一次 locType1 向上兼容。 |
| | | */ |
| | | private LocMast findRun2PriorityLocInPoolWithCompatibility(RowLastno rowLastno, RowLastnoType rowLastnoType, |
| | | BasDevp station, List<Integer> crnNos, Integer currentCrnNo, |
| | | int poolNo, LocTypeDto locTypeDto, Integer staDescId, |
| | | Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, |
| | | StartupDto startupDto, boolean ignoreFreqType) { |
| | | LocMast locMast = findRun2PriorityLocInPool(rowLastno, rowLastnoType, station, crnNos, currentCrnNo, poolNo, |
| | | locTypeDto, staDescId, sourceStaNo, findLocNoAttributeVo, startupDto, ignoreFreqType); |
| | | if (locMast != null) { |
| | | return locMast; |
| | | } |
| | | LocTypeDto compatibleLocTypeDto = buildRetryCompatibleLocTypeDto(staDescId, findLocNoAttributeVo, locTypeDto); |
| | | if (compatibleLocTypeDto == null) { |
| | | return null; |
| | | } |
| | | return findRun2PriorityLocInPool(rowLastno, rowLastnoType, station, crnNos, currentCrnNo, poolNo, |
| | | compatibleLocTypeDto, staDescId, sourceStaNo, findLocNoAttributeVo, startupDto, ignoreFreqType); |
| | | } |
| | | |
| | | /** |
| | | * 以乐观方式回写优先池游标。 |
| | | */ |
| | | private boolean updatePriorityCursor(BasDevp station, int poolNo, Integer expectedCurrentNo, Integer selectedCrnNo) { |
| | | if (station == null || station.getDevNo() == null || selectedCrnNo == null) { |
| | | return false; |
| | | } |
| | | BasDevp updateStation = new BasDevp(); |
| | | String cursorColumn; |
| | | if (poolNo == 1) { |
| | | updateStation.setInFirstCrnCurrentNo(selectedCrnNo); |
| | | cursorColumn = "in_first_crn_current_no"; |
| | | } else { |
| | | updateStation.setInSecondCrnCurrentNo(selectedCrnNo); |
| | | cursorColumn = "in_second_crn_current_no"; |
| | | } |
| | | EntityWrapper<BasDevp> wrapper = new EntityWrapper<>(); |
| | | wrapper.eq("dev_no", station.getDevNo()); |
| | | if (expectedCurrentNo == null) { |
| | | wrapper.isNull(cursorColumn); |
| | | } else { |
| | | wrapper.eq(cursorColumn, expectedCurrentNo); |
| | | } |
| | | if (basDevpService.update(updateStation, wrapper)) { |
| | | return true; |
| | | } |
| | | BasDevp latestStation = basDevpService.selectById(station.getDevNo()); |
| | | if (latestStation == null) { |
| | | return false; |
| | | } |
| | | Integer latestCurrentNo = poolNo == 1 ? latestStation.getInFirstCrnCurrentNo() : latestStation.getInSecondCrnCurrentNo(); |
| | | return Objects.equals(latestCurrentNo, selectedCrnNo); |
| | | } |
| | | |
| | | /** |
| | | * 组装优先池预览数据。 |
| | | */ |
| | | private Map<String, Object> buildPriorityPoolPreview(RowLastno rowLastno, RowLastnoType rowLastnoType, int poolNo, |
| | | List<Integer> crnNos, Integer currentCrnNo, Integer staDescId, |
| | | Integer sourceStaNo, LocTypeDto locTypeDto, |
| | | FindLocNoAttributeVo findLocNoAttributeVo) { |
| | | return buildPriorityPoolPreview(rowLastno, rowLastnoType, poolNo, crnNos, currentCrnNo, staDescId, sourceStaNo, |
| | | locTypeDto, findLocNoAttributeVo, false); |
| | | } |
| | | |
| | | private Map<String, Object> buildPriorityPoolPreview(RowLastno rowLastno, RowLastnoType rowLastnoType, int poolNo, |
| | | List<Integer> crnNos, Integer currentCrnNo, Integer staDescId, |
| | | Integer sourceStaNo, LocTypeDto locTypeDto, |
| | | FindLocNoAttributeVo findLocNoAttributeVo, boolean ignoreFreqType) { |
| | | Map<String, Object> item = new HashMap<String, Object>(); |
| | | List<Integer> configuredCrnNos = Utils.distinctCrnNos(crnNos); |
| | | List<Integer> rotatedCrnNos = rotatePriorityCrnNos(configuredCrnNos, currentCrnNo); |
| | | item.put("poolNo", poolNo); |
| | | item.put("currentCrnNo", currentCrnNo); |
| | | item.put("configuredCrnNos", configuredCrnNos); |
| | | item.put("rotatedCrnNos", rotatedCrnNos); |
| | | item.put("runnableCrnNos", getOrderedRunnableRun2CrnNos(rowLastno, staDescId, sourceStaNo, rotatedCrnNos)); |
| | | item.put("profiles", buildRun2ProfilePreview(rowLastno, rowLastnoType, rotatedCrnNos, staDescId, sourceStaNo, |
| | | locTypeDto, findLocNoAttributeVo, ignoreFreqType)); |
| | | return item; |
| | | } |
| | | |
| | | /** |
| | | * 构造空托盘跨库区搜索顺序: |
| | | * 先站点绑定库区,再补请求库区,最后回退全仓库区,避免重复。 |
| | | */ |
| | | private List<Integer> buildAreaSearchOrder(List<Integer> preferredAreas, Integer requestArea) { |
| | | LinkedHashSet<Integer> areaOrder = new LinkedHashSet<>(); |
| | | if (preferredArea != null && preferredArea >= 1 && preferredArea <= 3) { |
| | | areaOrder.add(preferredArea); |
| | | if (!Cools.isEmpty(preferredAreas)) { |
| | | for (Integer area : preferredAreas) { |
| | | if (isValidArea(area)) { |
| | | areaOrder.add(area); |
| | | } |
| | | } |
| | | } |
| | | if (isValidArea(requestArea)) { |
| | | areaOrder.add(requestArea); |
| | | } |
| | | for (int area = 1; area <= 3; area++) { |
| | | areaOrder.add(area); |
| | |
| | | } |
| | | |
| | | /** |
| | | * 预览 run2 当前会参与的库区、堆垛机顺序和深浅排画像,不落任务档。 |
| | | * 预览 run2 当前会参与的优先池、堆垛机顺序和深浅排画像,不落任务档。 |
| | | */ |
| | | public Map<String, Object> previewRun2Allocation(BasCrnDepthRuleRuntimePreviewParam param) { |
| | | if (param == null || param.getStaDescId() == null || param.getSourceStaNo() == null) { |
| | |
| | | FindLocNoAttributeVo findLocNoAttributeVo = new FindLocNoAttributeVo(); |
| | | findLocNoAttributeVo.setMatnr(param.getMatnr()); |
| | | findLocNoAttributeVo.setOutArea(param.getOutArea()); |
| | | findLocNoAttributeVo.setFreqType(param.getFreqType()); |
| | | |
| | | LocTypeDto locTypeDto = new LocTypeDto(); |
| | | locTypeDto.setLocType1(param.getLocType1()); |
| | |
| | | throw new CoolException("未找到仓库轮询规则"); |
| | | } |
| | | RowLastnoType rowLastnoType = rowLastnoTypeService.selectById(rowLastno.getTypeId()); |
| | | Integer preferredArea = resolvePreferredArea(param.getSourceStaNo(), findLocNoAttributeVo); |
| | | List<Integer> stationAreas = Utils.getStationStorageAreas(param.getSourceStaNo()); |
| | | boolean emptyPalletRequest = isEmptyPalletRequest(param.getStaDescId(), findLocNoAttributeVo); |
| | | BasDevp station = basDevpService.selectById(param.getSourceStaNo()); |
| | | if (Cools.isEmpty(station)) { |
| | | throw new CoolException("站点=" + param.getSourceStaNo() + " 未配置入库优先堆垛机"); |
| | | } |
| | | List<Integer> firstPoolCrnNos = loadPriorityCrnNos(station.getInFirstCrnCsv()); |
| | | List<Integer> secondPoolCrnNos = excludePriorityCrnNos(loadPriorityCrnNos(station.getInSecondCrnCsv()), firstPoolCrnNos); |
| | | |
| | | Map<String, Object> result = new HashMap<String, Object>(); |
| | | result.put("whsType", whsType); |
| | | result.put("preferredArea", preferredArea); |
| | | result.put("preferredArea", findLocNoAttributeVo.getOutArea()); |
| | | result.put("preferredAreas", stationAreas); |
| | | result.put("emptyPallet", emptyPalletRequest); |
| | | result.put("locType", locTypeDto); |
| | | result.put("stationPriorityEntries", Utils.getStationStorageAreaName( |
| | | param.getSourceStaNo(), |
| | | locTypeDto == null || locTypeDto.getLocType1() == null ? null : locTypeDto.getLocType1().intValue(), |
| | | findLocNoAttributeVo.getMatnr())); |
| | | result.put("firstPriorityCrnNos", firstPoolCrnNos); |
| | | result.put("secondPriorityCrnNos", secondPoolCrnNos); |
| | | result.put("firstPriorityCurrentNo", station.getInFirstCrnCurrentNo()); |
| | | result.put("secondPriorityCurrentNo", station.getInSecondCrnCurrentNo()); |
| | | result.put("firstPriorityRotatedCrnNos", rotatePriorityCrnNos(firstPoolCrnNos, station.getInFirstCrnCurrentNo())); |
| | | result.put("secondPriorityRotatedCrnNos", rotatePriorityCrnNos(secondPoolCrnNos, station.getInSecondCrnCurrentNo())); |
| | | |
| | | List<Integer> orderedCrnNos = getOrderedCrnNos(rowLastno, resolveRun2CrnNo(rowLastno)); |
| | | List<Integer> runnableCrnNos = getOrderedRunnableRun2CrnNos(rowLastno, param.getStaDescId(), param.getSourceStaNo(), orderedCrnNos); |
| | | result.put("orderedCrnNos", orderedCrnNos); |
| | | result.put("runnableCrnNos", runnableCrnNos); |
| | | List<Map<String, Object>> poolPreviews = new ArrayList<Map<String, Object>>(); |
| | | |
| | | if (emptyPalletRequest) { |
| | | List<Integer> areaSearchOrder = buildAreaSearchOrder(preferredArea); |
| | | List<Map<String, Object>> searchStages = new ArrayList<Map<String, Object>>(); |
| | | for (LocTypeDto stageLocTypeDto : buildEmptyPalletSearchLocTypes(locTypeDto)) { |
| | | List<Map<String, Object>> areaPreviews = new ArrayList<Map<String, Object>>(); |
| | | for (Integer area : areaSearchOrder) { |
| | | RowLastno areaRowLastno = getAreaRowLastno(area, rowLastno); |
| | | RowLastnoType areaRowLastnoType = rowLastnoTypeService.selectById(areaRowLastno.getTypeId()); |
| | | List<Integer> areaOrderedCrnNos = getOrderedCrnNos(areaRowLastno, resolveRun2CrnNo(areaRowLastno)); |
| | | List<Integer> areaRunnableCrnNos = getOrderedRunnableRun2CrnNos(areaRowLastno, param.getStaDescId(), |
| | | param.getSourceStaNo(), areaOrderedCrnNos, false); |
| | | Map<String, Object> areaItem = new HashMap<String, Object>(); |
| | | areaItem.put("area", area); |
| | | areaItem.put("orderedCrnNos", areaOrderedCrnNos); |
| | | areaItem.put("runnableCrnNos", areaRunnableCrnNos); |
| | | areaItem.put("profiles", buildRun2ProfilePreview(areaRowLastno, areaRowLastnoType, areaOrderedCrnNos, |
| | | param.getStaDescId(), param.getSourceStaNo(), stageLocTypeDto)); |
| | | areaPreviews.add(areaItem); |
| | | for (int poolNo = 1; poolNo <= 2; poolNo++) { |
| | | List<Integer> poolCrnNos = poolNo == 1 ? firstPoolCrnNos : secondPoolCrnNos; |
| | | Integer currentCrnNo = poolNo == 1 ? station.getInFirstCrnCurrentNo() : station.getInSecondCrnCurrentNo(); |
| | | Map<String, Object> poolPreview = buildPriorityPoolPreview(rowLastno, rowLastnoType, poolNo, poolCrnNos, |
| | | currentCrnNo, param.getStaDescId(), param.getSourceStaNo(), locTypeDto, findLocNoAttributeVo, true); |
| | | List<Map<String, Object>> stagePreviews = new ArrayList<Map<String, Object>>(); |
| | | for (LocTypeDto stageLocTypeDto : buildEmptyPalletSearchLocTypes(locTypeDto)) { |
| | | Map<String, Object> stagePreview = buildPriorityPoolPreview(rowLastno, rowLastnoType, poolNo, poolCrnNos, |
| | | currentCrnNo, param.getStaDescId(), param.getSourceStaNo(), stageLocTypeDto, findLocNoAttributeVo, true); |
| | | stagePreview.put("stageCode", buildEmptyPalletStageCode(locTypeDto, stageLocTypeDto)); |
| | | stagePreview.put("locType", stageLocTypeDto); |
| | | stagePreviews.add(stagePreview); |
| | | } |
| | | Map<String, Object> stageItem = new HashMap<String, Object>(); |
| | | stageItem.put("stageCode", buildEmptyPalletStageCode(locTypeDto, stageLocTypeDto)); |
| | | stageItem.put("locType", stageLocTypeDto); |
| | | stageItem.put("areaSearchOrder", areaSearchOrder); |
| | | stageItem.put("areaPreviews", areaPreviews); |
| | | searchStages.add(stageItem); |
| | | poolPreview.put("stagePreviews", stagePreviews); |
| | | poolPreviews.add(poolPreview); |
| | | } |
| | | result.put("areaSearchOrder", areaSearchOrder); |
| | | result.put("searchStages", searchStages); |
| | | result.put("poolPreviews", poolPreviews); |
| | | return result; |
| | | } |
| | | |
| | | if (preferredArea != null) { |
| | | List<Integer> preferredCrnNos = filterCrnNosByRows(rowLastno, orderedCrnNos, getRun2AreaRows(preferredArea, rowLastno)); |
| | | result.put("candidateCrnNos", preferredCrnNos); |
| | | result.put("profiles", buildRun2ProfilePreview(rowLastno, rowLastnoType, preferredCrnNos, |
| | | param.getStaDescId(), param.getSourceStaNo(), locTypeDto)); |
| | | result.put("areaMode", "preferred-area-only"); |
| | | return result; |
| | | } |
| | | |
| | | result.put("candidateCrnNos", orderedCrnNos); |
| | | result.put("profiles", buildRun2ProfilePreview(rowLastno, rowLastnoType, orderedCrnNos, |
| | | param.getStaDescId(), param.getSourceStaNo(), locTypeDto)); |
| | | result.put("areaMode", "warehouse-round-robin"); |
| | | poolPreviews.add(buildPriorityPoolPreview(rowLastno, rowLastnoType, 1, firstPoolCrnNos, |
| | | station.getInFirstCrnCurrentNo(), param.getStaDescId(), param.getSourceStaNo(), locTypeDto, |
| | | findLocNoAttributeVo)); |
| | | poolPreviews.add(buildPriorityPoolPreview(rowLastno, rowLastnoType, 2, secondPoolCrnNos, |
| | | station.getInSecondCrnCurrentNo(), param.getStaDescId(), param.getSourceStaNo(), locTypeDto, |
| | | findLocNoAttributeVo)); |
| | | result.put("poolPreviews", poolPreviews); |
| | | return result; |
| | | } |
| | | |
| | |
| | | * 组装某批堆垛机的运行时画像预览数据。 |
| | | */ |
| | | private List<Map<String, Object>> buildRun2ProfilePreview(RowLastno rowLastno, RowLastnoType rowLastnoType, List<Integer> crnNos, |
| | | Integer staDescId, Integer sourceStaNo, LocTypeDto locTypeDto) { |
| | | Integer staDescId, Integer sourceStaNo, LocTypeDto locTypeDto, |
| | | FindLocNoAttributeVo findLocNoAttributeVo) { |
| | | return buildRun2ProfilePreview(rowLastno, rowLastnoType, crnNos, staDescId, sourceStaNo, locTypeDto, findLocNoAttributeVo, false); |
| | | } |
| | | |
| | | private List<Map<String, Object>> buildRun2ProfilePreview(RowLastno rowLastno, RowLastnoType rowLastnoType, List<Integer> crnNos, |
| | | Integer staDescId, Integer sourceStaNo, LocTypeDto locTypeDto, |
| | | FindLocNoAttributeVo findLocNoAttributeVo, boolean ignoreFreqType) { |
| | | List<Map<String, Object>> profiles = new ArrayList<Map<String, Object>>(); |
| | | if (Cools.isEmpty(crnNos)) { |
| | | return profiles; |
| | |
| | | item.put("shallowRows", profile == null ? null : profile.getShallowRows()); |
| | | item.put("deepRows", profile == null ? null : profile.getDeepRows()); |
| | | LocMast firstMatchLoc = findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, crnNo, |
| | | getCrnStartRow(rowLastno, crnNo), locTypeDto); |
| | | getCrnStartRow(rowLastno, crnNo), locTypeDto, findLocNoAttributeVo, ignoreFreqType); |
| | | item.put("firstMatchLocNo", firstMatchLoc == null ? null : firstMatchLoc.getLocNo()); |
| | | item.put("assignableLocCount", countAssignableLocForCrn(rowLastno, rowLastnoType, crnNo, |
| | | getCrnStartRow(rowLastno, crnNo) == null ? 0 : getCrnStartRow(rowLastno, crnNo), locTypeDto)); |
| | |
| | | * 因为空托盘的业务口径已经切换成“按库区找堆垛机”,不是按推荐排找巷道。 |
| | | */ |
| | | private Run2AreaSearchResult findEmptyPalletRun2Loc(RowLastno defaultRowLastno, Integer staDescId, Integer sourceStaNo, |
| | | StartupDto startupDto, Integer preferredArea, LocTypeDto locTypeDto) { |
| | | StartupDto startupDto, FindLocNoAttributeVo findLocNoAttributeVo, |
| | | LocTypeDto locTypeDto) { |
| | | for (LocTypeDto stageLocTypeDto : buildEmptyPalletSearchLocTypes(locTypeDto)) { |
| | | String stageCode = buildEmptyPalletStageCode(locTypeDto, stageLocTypeDto); |
| | | Run2AreaSearchResult searchResult = findEmptyPalletRun2AreaLoc(defaultRowLastno, staDescId, sourceStaNo, |
| | | startupDto, preferredArea, stageLocTypeDto, stageCode); |
| | | startupDto, findLocNoAttributeVo, stageLocTypeDto, stageCode); |
| | | if (!Cools.isEmpty(searchResult) && !Cools.isEmpty(searchResult.locMast)) { |
| | | return searchResult; |
| | | } |
| | |
| | | } |
| | | |
| | | private Run2AreaSearchResult findEmptyPalletRun2AreaLoc(RowLastno defaultRowLastno, Integer staDescId, Integer sourceStaNo, |
| | | StartupDto startupDto, Integer preferredArea, LocTypeDto locTypeDto, |
| | | StartupDto startupDto, FindLocNoAttributeVo findLocNoAttributeVo, LocTypeDto locTypeDto, |
| | | String stageCode) { |
| | | for (Integer area : buildAreaSearchOrder(preferredArea)) { |
| | | List<Integer> areaSearchOrder = buildAreaSearchOrder( |
| | | findLocNoAttributeVo == null ? null : findLocNoAttributeVo.getOutAreas(), |
| | | findLocNoAttributeVo == null ? null : findLocNoAttributeVo.getOutArea()); |
| | | for (Integer area : areaSearchOrder) { |
| | | RowLastno areaRowLastno = getAreaRowLastno(area, defaultRowLastno); |
| | | if (Cools.isEmpty(areaRowLastno)) { |
| | | continue; |
| | |
| | | continue; |
| | | } |
| | | LocMast locMast = findRun2EmptyLocByCrnNos(areaRowLastno, areaRowLastnoType, runnableAreaCrnNos, locTypeDto, |
| | | staDescId, sourceStaNo, startupDto, area, stageCode + "-area-" + area, false); |
| | | staDescId, sourceStaNo, startupDto, area, findLocNoAttributeVo, stageCode + "-area-" + area, false); |
| | | if (!Cools.isEmpty(locMast)) { |
| | | return new Run2AreaSearchResult(locMast, areaRowLastno, runnableAreaCrnNos); |
| | | } |
| | |
| | | // 站点优先级只是“优先尝试”,没有命中时必须继续走默认/库区回退, |
| | | // 否则会把“优先候选无位”误判成“整仓无位”。 |
| | | LocMast locMast = findRun2EmptyLocByCrnLocTypeEntries(rowLastno, rowLastnoType, stationCrnLocTypes, |
| | | locTypeDto, staDescId, sourceStaNo, startupDto, preferredArea, "station-priority"); |
| | | locTypeDto, staDescId, sourceStaNo, startupDto, preferredArea, "station-priority", findLocNoAttributeVo); |
| | | if (!Cools.isEmpty(locMast)) { |
| | | return new Run2SearchResult(locMast, rowLastno, |
| | | getOrderedRunnableRun2CrnNos(rowLastno, staDescId, sourceStaNo, extractCrnNos(stationCrnLocTypes))); |
| | |
| | | } |
| | | List<Integer> runnableCrnNos = getOrderedRunnableRun2CrnNos(rowLastno, staDescId, sourceStaNo, candidateCrnNos); |
| | | LocMast locMast = findRun2EmptyLocByCrnNos(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, preferredArea == null ? "default" : "preferred-area"); |
| | | staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, |
| | | preferredArea == null ? "default" : "preferred-area"); |
| | | return new Run2SearchResult(locMast, rowLastno, runnableCrnNos); |
| | | } |
| | | |
| | |
| | | LocTypeDto locTypeDto, Integer staDescId, Integer sourceStaNo, StartupDto startupDto, |
| | | Integer preferredArea, String stage) { |
| | | return findRun2EmptyLocByCrnNos(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, stage, true); |
| | | staDescId, sourceStaNo, startupDto, preferredArea, null, stage, true); |
| | | } |
| | | |
| | | private LocMast findRun2EmptyLocByCrnNos(RowLastno rowLastno, RowLastnoType rowLastnoType, List<Integer> candidateCrnNos, |
| | | LocTypeDto locTypeDto, Integer staDescId, Integer sourceStaNo, StartupDto startupDto, |
| | | Integer preferredArea, String stage, boolean routeRequired) { |
| | | Integer preferredArea, FindLocNoAttributeVo findLocNoAttributeVo, String stage) { |
| | | return findRun2EmptyLocByCrnNos(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, stage, true); |
| | | } |
| | | |
| | | 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) { |
| | | if (Cools.isEmpty(candidateCrnNos)) { |
| | | log.warn("run2 skip empty candidate list. stage={}, sourceStaNo={}, preferredArea={}, spec={}", |
| | | stage, sourceStaNo, preferredArea, JSON.toJSONString(locTypeDto)); |
| | |
| | | List<Integer> noEmptyCrns = new ArrayList<>(); |
| | | List<Integer> locTypeBlockedCrns = new ArrayList<>(); |
| | | return findRun2EmptyLocByCrnNosRecursively(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, stage, routeRequired, 0, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, stage, routeRequired, 0, |
| | | crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns); |
| | | } |
| | | |
| | | private LocMast findRun2EmptyLocByCrnNosRecursively(RowLastno rowLastno, RowLastnoType rowLastnoType, |
| | | List<Integer> candidateCrnNos, LocTypeDto locTypeDto, |
| | | Integer staDescId, Integer sourceStaNo, StartupDto startupDto, |
| | | Integer preferredArea, String stage, boolean routeRequired, int index, |
| | | Integer preferredArea, FindLocNoAttributeVo findLocNoAttributeVo, |
| | | String stage, boolean routeRequired, int index, |
| | | List<Integer> crnErrorCrns, List<Integer> routeBlockedCrns, |
| | | List<Integer> noEmptyCrns, List<Integer> locTypeBlockedCrns) { |
| | | if (index >= candidateCrnNos.size()) { |
| | |
| | | if (!isCrnActive(candidateCrnNo)) { |
| | | crnErrorCrns.add(candidateCrnNo); |
| | | return findRun2EmptyLocByCrnNosRecursively(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, stage, routeRequired, index + 1, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, stage, routeRequired, index + 1, |
| | | crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns); |
| | | } |
| | | 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, stage, routeRequired, index + 1, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, stage, routeRequired, index + 1, |
| | | crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns); |
| | | } |
| | | Integer preferredNearRow = getCrnStartRow(rowLastno, candidateCrnNo); |
| | | LocMast candidateLoc = findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, candidateCrnNo, |
| | | preferredNearRow, locTypeDto); |
| | | preferredNearRow, locTypeDto, findLocNoAttributeVo); |
| | | if (Cools.isEmpty(candidateLoc)) { |
| | | int availableLocCount = countAssignableLocForCrn(rowLastno, rowLastnoType, candidateCrnNo, |
| | | preferredNearRow == null ? 0 : preferredNearRow, locTypeDto); |
| | |
| | | locTypeBlockedCrns.add(candidateCrnNo); |
| | | } |
| | | return findRun2EmptyLocByCrnNosRecursively(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, stage, routeRequired, index + 1, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, stage, routeRequired, index + 1, |
| | | crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns); |
| | | } |
| | | if (targetStaNo != null) { |
| | |
| | | private LocMast findRun2EmptyLocByCrnLocTypeEntries(RowLastno rowLastno, RowLastnoType rowLastnoType, |
| | | List<Map<String, Integer>> crnLocTypeEntries, LocTypeDto locTypeDto, |
| | | Integer staDescId, Integer sourceStaNo, StartupDto startupDto, |
| | | Integer preferredArea, String stage) { |
| | | Integer preferredArea, String stage, FindLocNoAttributeVo findLocNoAttributeVo) { |
| | | if (Cools.isEmpty(crnLocTypeEntries)) { |
| | | log.warn("run2 skip empty crn-locType list. stage={}, sourceStaNo={}, preferredArea={}, spec={}", |
| | | stage, sourceStaNo, preferredArea, JSON.toJSONString(locTypeDto)); |
| | |
| | | List<Integer> noEmptyCrns = new ArrayList<>(); |
| | | List<Integer> locTypeBlockedCrns = new ArrayList<>(); |
| | | return findRun2EmptyLocByCrnLocTypeEntriesRecursively(rowLastno, rowLastnoType, crnLocTypeEntries, locTypeDto, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, stage, 0, candidateCrnNos, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, stage, findLocNoAttributeVo, 0, candidateCrnNos, |
| | | crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns); |
| | | } |
| | | |
| | | private LocMast findRun2EmptyLocByCrnLocTypeEntriesRecursively(RowLastno rowLastno, RowLastnoType rowLastnoType, |
| | | List<Map<String, Integer>> crnLocTypeEntries, LocTypeDto locTypeDto, |
| | | Integer staDescId, Integer sourceStaNo, StartupDto startupDto, |
| | | Integer preferredArea, String stage, int index, |
| | | Integer preferredArea, String stage, FindLocNoAttributeVo findLocNoAttributeVo, int index, |
| | | List<Integer> candidateCrnNos, List<Integer> crnErrorCrns, |
| | | List<Integer> routeBlockedCrns, List<Integer> noEmptyCrns, |
| | | List<Integer> locTypeBlockedCrns) { |
| | |
| | | if (!isCrnActive(candidateCrnNo)) { |
| | | crnErrorCrns.add(candidateCrnNo); |
| | | return findRun2EmptyLocByCrnLocTypeEntriesRecursively(rowLastno, rowLastnoType, crnLocTypeEntries, locTypeDto, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, stage, index + 1, candidateCrnNos, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, stage, findLocNoAttributeVo, index + 1, candidateCrnNos, |
| | | crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns); |
| | | } |
| | | Integer targetStaNo = resolveTargetStaNo(rowLastno, staDescId, sourceStaNo, candidateCrnNo); |
| | | if (Utils.BooleanWhsTypeSta(rowLastno, staDescId) && targetStaNo == null) { |
| | | routeBlockedCrns.add(candidateCrnNo); |
| | | return findRun2EmptyLocByCrnLocTypeEntriesRecursively(rowLastno, rowLastnoType, crnLocTypeEntries, locTypeDto, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, stage, index + 1, candidateCrnNos, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, stage, findLocNoAttributeVo, index + 1, candidateCrnNos, |
| | | crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns); |
| | | } |
| | | LocTypeDto searchLocTypeDto = buildRun2SearchLocTypeDto(locTypeDto, candidateLocType1); |
| | | Integer preferredNearRow = getCrnStartRow(rowLastno, candidateCrnNo); |
| | | LocMast candidateLoc = findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, candidateCrnNo, |
| | | preferredNearRow, searchLocTypeDto); |
| | | preferredNearRow, searchLocTypeDto, findLocNoAttributeVo); |
| | | if (Cools.isEmpty(candidateLoc)) { |
| | | int availableLocCount = countAssignableLocForCrn(rowLastno, rowLastnoType, candidateCrnNo, |
| | | preferredNearRow == null ? 0 : preferredNearRow, searchLocTypeDto); |
| | |
| | | locTypeBlockedCrns.add(candidateCrnNo); |
| | | } |
| | | return findRun2EmptyLocByCrnLocTypeEntriesRecursively(rowLastno, rowLastnoType, crnLocTypeEntries, locTypeDto, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, stage, index + 1, candidateCrnNos, |
| | | staDescId, sourceStaNo, startupDto, preferredArea, stage, findLocNoAttributeVo, index + 1, candidateCrnNos, |
| | | crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns); |
| | | } |
| | | if (targetStaNo != null) { |
| | |
| | | */ |
| | | private LocMast findRun2OrderedEmptyLocByCrnLocType(RowLastnoType rowLastnoType, Integer candidateCrnNo, |
| | | Short candidateLocType1, LocTypeDto locTypeDto) { |
| | | return findRun2OrderedEmptyLocByCrnLocType(rowLastnoType, candidateCrnNo, candidateLocType1, locTypeDto, null); |
| | | } |
| | | |
| | | private LocMast findRun2OrderedEmptyLocByCrnLocType(RowLastnoType rowLastnoType, Integer candidateCrnNo, |
| | | Short candidateLocType1, LocTypeDto locTypeDto, |
| | | FindLocNoAttributeVo findLocNoAttributeVo) { |
| | | if (candidateCrnNo == null) { |
| | | return null; |
| | | } |
| | |
| | | wrapper.eq("loc_type1", candidateLocType1); |
| | | } |
| | | applyLocTypeFilters(wrapper, locTypeDto, false); |
| | | // 单伸堆垛机按层、列递增顺序找第一个空库位。 |
| | | if (rowLastnoType != null && rowLastnoType.getType() != null && (rowLastnoType.getType() == 1 || rowLastnoType.getType() == 2)) { |
| | | wrapper.orderBy("lev1", true).orderBy("bay1", true); |
| | | } else { |
| | | wrapper.orderBy("lev1", true).orderBy("bay1", true); |
| | | List<LocMast> locMasts = locMastService.selectList(wrapper); |
| | | List<LocMast> sortedLocMasts = sortLocCandidates(locMasts, findLocNoAttributeVo); |
| | | for (LocMast candidateLoc : sortedLocMasts) { |
| | | if (candidateLoc == null) { |
| | | continue; |
| | | } |
| | | if (locTypeDto != null && !VersionUtils.locMoveCheckLocTypeComplete(candidateLoc, locTypeDto)) { |
| | | continue; |
| | | } |
| | | return candidateLoc; |
| | | } |
| | | LocMast candidateLoc = locMastService.selectOne(wrapper); |
| | | if (Cools.isEmpty(candidateLoc)) { |
| | | return null; |
| | | } |
| | | if (locTypeDto != null && !VersionUtils.locMoveCheckLocTypeComplete(candidateLoc, locTypeDto)) { |
| | | return null; |
| | | } |
| | | return candidateLoc; |
| | | return null; |
| | | } |
| | | |
| | | private Optional<CrnRowInfo> findAvailableCrnAndNearRow(RowLastno rowLastno, int curRow, int crnNumber, int times, |
| | |
| | | } |
| | | |
| | | /** |
| | | * 查询某一排上的所有空库位,并按单伸/双伸策略排序。 |
| | | * 查询某一排上的所有空库位,并按单伸/双伸策略与频次排序。 |
| | | */ |
| | | private List<LocMast> findOpenLocsByRow(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer row, |
| | | Integer crnNo, LocTypeDto locTypeDto, boolean singleExtension) { |
| | | return findOpenLocsByRow(rowLastno, rowLastnoType, row, crnNo, locTypeDto, null, singleExtension, false); |
| | | } |
| | | |
| | | private List<LocMast> findOpenLocsByRow(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer row, |
| | | Integer crnNo, LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo, |
| | | boolean singleExtension) { |
| | | return findOpenLocsByRow(rowLastno, rowLastnoType, row, crnNo, locTypeDto, findLocNoAttributeVo, singleExtension, false); |
| | | } |
| | | |
| | | private List<LocMast> findOpenLocsByRow(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer row, |
| | | Integer crnNo, LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo, |
| | | boolean singleExtension, boolean ignoreFreqType) { |
| | | List<LocMast> result = new ArrayList<LocMast>(); |
| | | if (row == null) { |
| | | return result; |
| | | } |
| | | Wrapper<LocMast> wrapper = new EntityWrapper<LocMast>() |
| | | // .eq("row1", row) |
| | | .eq("loc_sts", "O"); |
| | | if (crnNo != null) { |
| | | wrapper.eq("crn_no", crnNo); |
| | | } |
| | | applyLocTypeFilters(wrapper, locTypeDto, true); |
| | | if (singleExtension) { |
| | | wrapper.orderBy("lev1", true).orderBy("bay1", true); |
| | | } else { |
| | | wrapper.orderBy("lev1", true).orderBy("bay1", true); |
| | | } |
| | | List<LocMast> locMasts = locMastService.selectList(wrapper); |
| | | for (LocMast locMast : locMasts) { |
| | | List<LocMast> sortedLocMasts = sortLocCandidates(locMasts, findLocNoAttributeVo, ignoreFreqType); |
| | | for (LocMast locMast : sortedLocMasts) { |
| | | if (matchesLocType(locMast, locTypeDto)) { |
| | | result.add(locMast); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private List<LocMast> sortLocCandidates(List<LocMast> locMasts, FindLocNoAttributeVo findLocNoAttributeVo) { |
| | | return sortLocCandidates(locMasts, findLocNoAttributeVo, false); |
| | | } |
| | | |
| | | private List<LocMast> sortLocCandidates(List<LocMast> locMasts, FindLocNoAttributeVo findLocNoAttributeVo, boolean ignoreFreqType) { |
| | | Integer freqType = ignoreFreqType ? null : (findLocNoAttributeVo == null ? null : findLocNoAttributeVo.getFreqType()); |
| | | return sortLocCandidates(locMasts, freqType, getHighFreqFrontBayCount()); |
| | | } |
| | | |
| | | private List<LocMast> sortLocCandidates(List<LocMast> locMasts, Integer freqType, Integer frontBayCount) { |
| | | List<LocMast> result = new ArrayList<LocMast>(); |
| | | if (Cools.isEmpty(locMasts)) { |
| | | return result; |
| | | } |
| | | result.addAll(locMasts); |
| | | |
| | | Integer normalizedFreqType = normalizeFreqType(freqType); |
| | | if (normalizedFreqType == null) { |
| | | result.sort(Comparator |
| | | .comparing(LocMast::getLev1, Comparator.nullsLast(Integer::compareTo)) |
| | | .thenComparing(LocMast::getBay1, Comparator.nullsLast(Integer::compareTo)) |
| | | .thenComparing(LocMast::getLocNo, Comparator.nullsLast(String::compareTo))); |
| | | return result; |
| | | } |
| | | |
| | | if (Objects.equals(normalizedFreqType, 2)) { |
| | | result.sort(Comparator |
| | | .comparing(LocMast::getLev1, Comparator.nullsLast(Integer::compareTo)) |
| | | .thenComparing(LocMast::getBay1, Comparator.nullsLast(Comparator.reverseOrder())) |
| | | .thenComparing(LocMast::getLocNo, Comparator.nullsLast(String::compareTo))); |
| | | return result; |
| | | } |
| | | |
| | | int normalizedFrontBayCount = frontBayCount == null ? 0 : frontBayCount; |
| | | if (normalizedFrontBayCount > 0) { |
| | | result.sort(Comparator |
| | | .comparingInt((LocMast loc) -> resolveFrontBayGroup(loc, normalizedFrontBayCount)) |
| | | .thenComparing(LocMast::getBay1, Comparator.nullsLast(Integer::compareTo)) |
| | | .thenComparing(LocMast::getLev1, Comparator.nullsLast(Integer::compareTo)) |
| | | .thenComparing(LocMast::getLocNo, Comparator.nullsLast(String::compareTo))); |
| | | } else { |
| | | result.sort(Comparator |
| | | .comparing(LocMast::getBay1, Comparator.nullsLast(Integer::compareTo)) |
| | | .thenComparing(LocMast::getLev1, Comparator.nullsLast(Integer::compareTo)) |
| | | .thenComparing(LocMast::getLocNo, Comparator.nullsLast(String::compareTo))); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private int resolveFrontBayGroup(LocMast locMast, int frontBayCount) { |
| | | if (locMast == null || locMast.getBay1() == null || locMast.getBay1() <= 0) { |
| | | return 1; |
| | | } |
| | | return locMast.getBay1() <= frontBayCount ? 0 : 1; |
| | | } |
| | | |
| | | private Integer normalizeFreqType(Integer freqType) { |
| | | if (freqType == null || (freqType != 1 && freqType != 2)) { |
| | | return null; |
| | | } |
| | | return freqType; |
| | | } |
| | | |
| | | private int getHighFreqFrontBayCount() { |
| | | Parameter parameter = Parameter.get(); |
| | | if (parameter == null || Cools.isEmpty(parameter.getHighFreqFrontBayCount())) { |
| | | return 0; |
| | | } |
| | | Integer parsedCount = safeParseInt(parameter.getHighFreqFrontBayCount()); |
| | | if (parsedCount == null || parsedCount <= 0) { |
| | | return 0; |
| | | } |
| | | return parsedCount; |
| | | } |
| | | |
| | | /** |
| | |
| | | if (crnNo != null) { |
| | | wrapper.eq("crn_no", crnNo); |
| | | } |
| | | Long whsType = resolveLocWhsType(rowLastno, rowLastnoType); |
| | | if (whsType != null) { |
| | | wrapper.eq("whs_type", whsType); |
| | | } |
| | | if (statuses != null && statuses.length > 0) { |
| | | if (statuses.length == 1) { |
| | | wrapper.eq("loc_sts", statuses[0]); |
| | |
| | | */ |
| | | private LocMast findPairAssignableLoc(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer crnNo, |
| | | Integer shallowRow, Integer deepRow, LocTypeDto locTypeDto) { |
| | | List<LocMast> shallowOpenLocs = findOpenLocsByRow(rowLastno, rowLastnoType, shallowRow, crnNo, locTypeDto, false); |
| | | return findPairAssignableLoc(rowLastno, rowLastnoType, crnNo, shallowRow, deepRow, locTypeDto, null); |
| | | } |
| | | |
| | | 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); |
| | | if (Cools.isEmpty(shallowOpenLocs)) { |
| | | return null; |
| | | } |
| | |
| | | * 按某台堆垛机的深浅排画像搜索第一个可分配空库位。 |
| | | */ |
| | | private LocMast findConfiguredEmptyLocForCrn(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer crnNo, |
| | | Integer preferredNearRow, LocTypeDto locTypeDto) { |
| | | Integer preferredNearRow, LocTypeDto locTypeDto) { |
| | | return findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, crnNo, preferredNearRow, locTypeDto, null, false); |
| | | } |
| | | |
| | | private LocMast findConfiguredEmptyLocForCrn(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer crnNo, |
| | | Integer preferredNearRow, LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo) { |
| | | return findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, crnNo, preferredNearRow, locTypeDto, findLocNoAttributeVo, false); |
| | | } |
| | | |
| | | private LocMast findConfiguredEmptyLocForCrn(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer crnNo, |
| | | Integer preferredNearRow, LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo, |
| | | boolean ignoreFreqType) { |
| | | if (rowLastno == null || crnNo == null) { |
| | | return null; |
| | | } |
| | |
| | | continue; |
| | | } |
| | | LocMast candidateLoc = findPairAssignableLoc(rowLastno, rowLastnoType, crnNo, searchRow, |
| | | profile.getPairedDeepRow(searchRow), locTypeDto); |
| | | profile.getPairedDeepRow(searchRow), locTypeDto, findLocNoAttributeVo); |
| | | if (!Cools.isEmpty(candidateLoc)) { |
| | | return candidateLoc; |
| | | } |
| | |
| | | continue; |
| | | } |
| | | LocMast candidateLoc = findPairAssignableLoc(rowLastno, rowLastnoType, crnNo, shallowRow, |
| | | searchRow, locTypeDto); |
| | | searchRow, locTypeDto, findLocNoAttributeVo); |
| | | if (!Cools.isEmpty(candidateLoc)) { |
| | | return candidateLoc; |
| | | } |
| | |
| | | } |
| | | } |
| | | } |
| | | List<LocMast> locMasts = findOpenLocsByRow(rowLastno, rowLastnoType, searchRow, crnNo, locTypeDto, singleExtension); |
| | | List<LocMast> locMasts = findOpenLocsByRow(rowLastno, rowLastnoType, searchRow, crnNo, locTypeDto, findLocNoAttributeVo, singleExtension, ignoreFreqType); |
| | | if (!Cools.isEmpty(locMasts)) { |
| | | return locMasts.get(0); |
| | | } |
| | |
| | | * run/run2 标准堆垛机统一的空库位查询入口。 |
| | | */ |
| | | private LocMast findStandardEmptyLoc(RowLastno rowLastno, RowLastnoType rowLastnoType, int crnNo, int nearRow, LocTypeDto locTypeDto) { |
| | | return findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto); |
| | | return findStandardEmptyLoc(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto, null); |
| | | } |
| | | |
| | | private LocMast findStandardEmptyLoc(RowLastno rowLastno, RowLastnoType rowLastnoType, int crnNo, int nearRow, |
| | | LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo) { |
| | | return findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto, findLocNoAttributeVo); |
| | | } |
| | | |
| | | /** |
| | |
| | | if (signRule1) { |
| | | if (nearRow != curRow) { |
| | | List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>() |
| | | .eq("row1", nearRow).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue())); |
| | | .eq("row1", nearRow).eq("loc_sts", "O")); |
| | | for (LocMast locMast1 : locMasts) { |
| | | //获取巷道 |
| | | // List<String> groupOutsideLocCrn = Utils.getGroupOutLocCrn(curRow,nearRow,locMast1.getLocNo(), curRow>nearRow); |
| | |
| | | // 靠近摆放规则 --- 空托 //互通版 |
| | | if (staDescId == 10 && Utils.BooleanWhsTypeStaIoType(rowLastno)) { |
| | | List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>() |
| | | .eq("loc_sts", "D").ge("row1", sRow).le("row1", eRow).eq("whs_type", rowLastnoType.getType().longValue())); |
| | | .eq("loc_sts", "D").ge("row1", sRow).le("row1", eRow)); |
| | | if (!locMasts.isEmpty()) { |
| | | for (LocMast loc : locMasts) { |
| | | if (Utils.isShallowLoc(slaveProperties, loc.getLocNo())) { |
| | |
| | | |
| | | // Search empty location ==============================>> |
| | | if (staDescId == 10 && Cools.isEmpty(locMast) && crnNo != 0) { |
| | | locMast = findStandardEmptyLoc(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto); |
| | | locMast = findStandardEmptyLoc(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto, findLocNoAttributeVo); |
| | | } |
| | | |
| | | |
| | | |
| | | if (Cools.isEmpty(locMast) && crnNo != 0) { |
| | | locMast = findStandardEmptyLoc(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto); |
| | | locMast = findStandardEmptyLoc(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto, findLocNoAttributeVo); |
| | | } |
| | | |
| | | if (!Cools.isEmpty(locMast) && !basCrnpService.checkSiteError(crnNo, true)) { |
| | |
| | | * run2 入库找位主流程。 |
| | | * |
| | | * 当前方法只保留“组织流程”和“统一收口”的职责,具体策略拆成独立方法: |
| | | * 1. 普通物料:按 row_lastno 自身轮询顺序 -> 站点优先库区/堆垛机 -> 其它库区。 |
| | | * 2. 空托盘:优先库区 loc_type2=1 -> 其它库区 loc_type2=1 -> loc_type1=2 兼容。 |
| | | * 3. 命中库位后分别回写普通物料游标或空托盘库区游标。 |
| | | * |
| | | * WCS 传入的推荐排不再参与 run2 选位,避免上游 row 参数把任务重新绑回固定堆垛机。 |
| | | * 1. 先按站点第一优先池找位,再找第二优先池。 |
| | | * 2. 池内按 current_no 轮转,从下一台堆垛机开始平均分配。 |
| | | * 3. 空托盘先按 loc_type2=1 搜索,同池无结果再允许其它库位。 |
| | | * 4. 低库位可向上兼容,兼容重试仍保持两层优先池顺序。 |
| | | */ |
| | | @Transactional |
| | | public StartupDto getLocNoRun2(Integer whsType, Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, Integer moveCrnNo, LocTypeDto locTypeDto, List<Integer> recommendRows, int times) { |
| | | |
| | | int crnNo = 0; |
| | | int nearRow = 0; |
| | | LocMast locMast = null; |
| | | |
| | | StartupDto startupDto = new StartupDto(); |
| | | RowLastno rowLastno = rowLastnoService.selectById(whsType); |
| | | |
| | | if (Cools.isEmpty(rowLastno)) { |
| | | throw new CoolException("数据异常,请联系管理员===>库位规则未知"); |
| | | } |
| | |
| | | if (Cools.isEmpty(rowLastnoType)) { |
| | | throw new CoolException("数据异常,请联系管理员===》库位规则类型未知"); |
| | | } |
| | | int curRow = rowLastno.getCurrentRow() == null ? 0 : rowLastno.getCurrentRow(); |
| | | crnNo = resolveRun2CrnNo(rowLastno); |
| | | Integer preferredArea = findLocNoAttributeVo.getOutArea(); |
| | | BasDevp station = basDevpService.selectById(sourceStaNo); |
| | | if (Cools.isEmpty(station)) { |
| | | throw new CoolException("站点=" + sourceStaNo + " 未配置入库优先堆垛机"); |
| | | } |
| | | List<Integer> firstPoolCrnNos = loadPriorityCrnNos(station.getInFirstCrnCsv()); |
| | | List<Integer> secondPoolCrnNos = loadPriorityCrnNos(station.getInSecondCrnCsv()); |
| | | if (Cools.isEmpty(firstPoolCrnNos) && Cools.isEmpty(secondPoolCrnNos)) { |
| | | throw new CoolException("站点=" + sourceStaNo + " 未配置入库优先堆垛机"); |
| | | } |
| | | boolean emptyPalletRequest = isEmptyPalletRequest(staDescId, findLocNoAttributeVo); |
| | | Run2AreaSearchResult emptyPalletAreaSearchResult = null; |
| | | Run2SearchResult normalRun2SearchResult = null; |
| | | |
| | | List<Integer> orderedCrnNos = getOrderedCrnNos(rowLastno, crnNo); |
| | | List<Integer> orderedRunnableCrnNos = getOrderedRunnableRun2CrnNos(rowLastno, staDescId, sourceStaNo, orderedCrnNos); |
| | | if (emptyPalletRequest) { |
| | | emptyPalletAreaSearchResult = findEmptyPalletRun2Loc(rowLastno, staDescId, sourceStaNo, startupDto, preferredArea, locTypeDto); |
| | | if (!Cools.isEmpty(emptyPalletAreaSearchResult)) { |
| | | locMast = emptyPalletAreaSearchResult.locMast; |
| | | } |
| | | } else { |
| | | normalRun2SearchResult = findNormalRun2Loc(rowLastno, rowLastnoType, sourceStaNo, staDescId, findLocNoAttributeVo, |
| | | locTypeDto, startupDto, preferredArea, orderedCrnNos); |
| | | if (normalRun2SearchResult != null) { |
| | | locMast = normalRun2SearchResult.locMast; |
| | | } |
| | | } |
| | | |
| | | if (!Cools.isEmpty(locMast)) { |
| | | crnNo = locMast.getCrnNo(); |
| | | nearRow = locMast.getRow1(); |
| | | } |
| | | if (emptyPalletRequest) { |
| | | advanceEmptyPalletRun2Cursor(emptyPalletAreaSearchResult, locMast); |
| | | } else if (!Cools.isEmpty(locMast)) { |
| | | List<Integer> cursorCrnNos = normalRun2SearchResult == null || Cools.isEmpty(normalRun2SearchResult.runnableCrnNos) |
| | | ? orderedRunnableCrnNos |
| | | : normalRun2SearchResult.runnableCrnNos; |
| | | advanceNormalRun2Cursor(rowLastno, curRow, cursorCrnNos, locMast.getCrnNo()); |
| | | } |
| | | |
| | | LocMast locMast = findRun2PriorityLocInPools(station, rowLastno, rowLastnoType, staDescId, sourceStaNo, |
| | | findLocNoAttributeVo, locTypeDto, startupDto, emptyPalletRequest); |
| | | if (Cools.isEmpty(locMast) || !locMast.getLocSts().equals("O")) { |
| | | if (emptyPalletRequest) { |
| | | log.error("No empty location found. spec={}, preferredArea={}, nearRow={}", |
| | | JSON.toJSONString(locTypeDto), preferredArea, nearRow); |
| | | log.error("No empty location found. spec={}, station={}, firstPool={}, secondPool={}", |
| | | JSON.toJSONString(locTypeDto), sourceStaNo, JSON.toJSONString(firstPoolCrnNos), |
| | | JSON.toJSONString(secondPoolCrnNos)); |
| | | throw new CoolException("没有空库位"); |
| | | } |
| | | LocTypeDto compatibleLocTypeDto = buildRetryCompatibleLocTypeDto(staDescId, findLocNoAttributeVo, locTypeDto); |
| | | if (compatibleLocTypeDto != null) { |
| | | log.warn("locType compatibility retry. source={}, target={}", JSON.toJSONString(locTypeDto), JSON.toJSONString(compatibleLocTypeDto)); |
| | | return getLocNoRun2(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, compatibleLocTypeDto, recommendRows, 0); |
| | | } |
| | | log.error("No empty location found. spec={}, preferredArea={}, nearRow={}", JSON.toJSONString(locTypeDto), preferredArea, nearRow); |
| | | log.error("No empty location found. spec={}, station={}, firstPool={}, secondPool={}", |
| | | JSON.toJSONString(locTypeDto), sourceStaNo, JSON.toJSONString(firstPoolCrnNos), JSON.toJSONString(secondPoolCrnNos)); |
| | | throw new CoolException("没有空库位"); |
| | | } |
| | | |
| | | int workNo = getWorkNo(0); |
| | | startupDto.setWorkNo(workNo); |
| | | startupDto.setCrnNo(crnNo); |
| | | startupDto.setCrnNo(locMast.getCrnNo()); |
| | | startupDto.setSourceStaNo(sourceStaNo); |
| | | startupDto.setLocNo(locMast.getLocNo()); |
| | | return startupDto; |
| | |
| | | * 单伸堆垛机复用统一画像算法查询空库位。 |
| | | */ |
| | | private LocMast findSingleExtensionEmptyLoc(RowLastno rowLastno, int crnNo, int nearRow, RowLastnoType rowLastnoType, LocTypeDto locTypeDto) { |
| | | return findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto); |
| | | return findSingleExtensionEmptyLoc(rowLastno, crnNo, nearRow, rowLastnoType, locTypeDto, null); |
| | | } |
| | | |
| | | private LocMast findSingleExtensionEmptyLoc(RowLastno rowLastno, int crnNo, int nearRow, RowLastnoType rowLastnoType, |
| | | LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo) { |
| | | return findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto, findLocNoAttributeVo); |
| | | } |
| | | |
| | | public StartupDto getLocNoRun4(Integer whsType, Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, Integer moveCrnNo, LocTypeDto locTypeDto, int times) { |
| | |
| | | crnNo = locNecessaryParameters[2]; |
| | | nearRow = locNecessaryParameters[3]; |
| | | List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>() |
| | | .eq("crn_no", crnNo).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue())); |
| | | .eq("crn_no", crnNo).eq("loc_sts", "O")); |
| | | if (locMasts.size() <= 5) { |
| | | nearRow = 0; |
| | | times++; |
| | |
| | | if (signRule1) { |
| | | if (nearRow != curRow) { |
| | | List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>() |
| | | .eq("row1", nearRow).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue())); |
| | | .eq("row1", nearRow).eq("loc_sts", "O")); |
| | | for (LocMast locMast1 : locMasts) { |
| | | //获取巷道 |
| | | // List<String> groupOutsideLocCrn = Utils.getGroupOutLocCrn(curRow,nearRow,locMast1.getLocNo(), curRow>nearRow); |
| | |
| | | if (Cools.isEmpty(locMast) && crnNo != 0) { |
| | | List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>() |
| | | .eq("row1", nearRow) |
| | | .eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue()) |
| | | .eq("loc_sts", "O") |
| | | .orderBy("lev1", true).orderBy("bay1", true));//最浅库位 |
| | | for (LocMast locMast1 : locMasts) { |
| | | if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) { |
| | |
| | | |
| | | // 开始查找库位 ==============================>> |
| | | |
| | | Integer preferredArea = findLocNoAttributeVo.getOutArea(); |
| | | Integer preferredArea = findLocNoAttributeVo == null ? null : findLocNoAttributeVo.getOutArea(); |
| | | List<Integer> areaSearchOrder = buildAreaSearchOrder(findLocNoAttributeVo == null ? null : findLocNoAttributeVo.getOutAreas(), preferredArea); |
| | | |
| | | if (Cools.isEmpty(locMast) && preferredArea == null) { |
| | | List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>() |
| | | .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)) { |
| | | if (Cools.isEmpty(locMast)) { |
| | | for (Integer area : areaSearchOrder) { |
| | | int[] bayRange = getAgvAreaBayRange(area); |
| | | List<Integer> areaRows = getAgvAreaRows(area, rowLastno); |
| | | if (Cools.isEmpty(areaRows)) { |
| | | 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; |
| | | } |
| | | locMast = findAgvLocByRows(rowLastno, rowLastnoType, areaRows, |
| | | bayRange[0], bayRange[1], curRow, nearRow, locTypeDto, findLocNoAttributeVo, false); |
| | | if (!Cools.isEmpty(locMast)) { |
| | | crnNo = locMast.getCrnNo(); |
| | | preferredArea = area; |
| | | break; |
| | | } |
| | | } |
| | | } else if (Cools.isEmpty(locMast)) { |
| | | int[] bayRange = getAgvAreaBayRange(preferredArea); |
| | | locMast = findAgvLocByRows(rowLastno, rowLastnoType, getAgvAreaRows(preferredArea, rowLastno), |
| | | bayRange[0], bayRange[1], curRow, nearRow, locTypeDto, false); |
| | | if (!Cools.isEmpty(locMast)) { |
| | | crnNo = locMast.getCrnNo(); |
| | | } |
| | | if (Cools.isEmpty(locMast)) { |
| | | locMast = findAgvLocByRows(rowLastno, rowLastnoType, getAgvFallbackRows(rowLastno), |
| | | 1, 19, curRow, nearRow, locTypeDto, true); |
| | | 1, 19, curRow, nearRow, locTypeDto, findLocNoAttributeVo, true); |
| | | if (!Cools.isEmpty(locMast)) { |
| | | crnNo = locMast.getCrnNo(); |
| | | } |
| | |
| | | |
| | | // 源站点状态检测 |
| | | BasDevp sourceStaNoEntity = basDevpService.checkSiteStatus(param.getSourceStaNo(), true); |
| | | sourceStaNoEntity.setLocType1(param.getLocType1()); |
| | | sourceStaNoEntity.setLocType1((short) (param.getLocType1()!=1?2:1)); |
| | | LocTypeDto locTypeDto = new LocTypeDto(sourceStaNoEntity); |
| | | if (waitPakins.get(0).getMatnr().equals("emptyPallet")) { |
| | | locTypeDto.setLocType2((short) 1); |
| | |
| | | #出库上报 |
| | | Outaddress: /api/Service/OutPalletCompleted |
| | | #出库异常上报 |
| | | OutErroraddress: /api/Service/OutPalletAbnormal |
| | | OutErroraddress: /api/Service/SubmitOutPalletMsg |
| | | #出库任务锁定上报 |
| | | OutLockaddress: /api/Service/OutPalletLocked |
| | | OutLockaddress: /api/Service/LockOutOrderPallet |
| | | |
| | | #wcs任务下发 |
| | | wcs: |
| | |
| | | <result column="row1" property="row1" /> |
| | | <result column="io_time" property="ioTime" /> |
| | | <result column="area" property="area" /> |
| | | <result column="in_first_crn_csv" property="inFirstCrnCsv" /> |
| | | <result column="in_second_crn_csv" property="inSecondCrnCsv" /> |
| | | <result column="in_first_crn_current_no" property="inFirstCrnCurrentNo" /> |
| | | <result column="in_second_crn_current_no" property="inSecondCrnCurrentNo" /> |
| | | <result column="in_ok" property="inOk" /> |
| | | <result column="out_ok" property="outOk" /> |
| | | <result column="loc_type1" property="locType1" /> |
| | |
| | | <result column="maktx" property="maktx" /> |
| | | <result column="batch" property="batch" /> |
| | | <result column="order_no" property="orderNo" /> |
| | | <result column="freq_type" property="freqType" /> |
| | | |
| | | <result column="specs" property="specs" /> |
| | | <result column="model" property="model" /> |
| | |
| | | <result column="maktx" property="maktx" /> |
| | | <result column="batch" property="batch" /> |
| | | <result column="order_no" property="orderNo" /> |
| | | <result column="freq_type" property="freqType" /> |
| | | |
| | | <result column="specs" property="specs" /> |
| | | <result column="model" property="model" /> |
| | |
| | | ,{field: 'barcode', align: 'center',title: '条形码'} |
| | | ,{field: 'inQty', align: 'center',title: '入库暂存'} |
| | | ,{field: 'area$', align: 'center',title: '绑定库区'} |
| | | ,{field: 'inFirstCrnCsv', align: 'center',title: '第一优先池'} |
| | | ,{field: 'inSecondCrnCsv', align: 'center',title: '第二优先池'} |
| | | // ,{field: 'row1', align: 'center',title: ''} |
| | | // ,{field: 'ioTime$', align: 'center',title: ''} |
| | | // ,{field: 'area', align: 'center',title: ''} |
| | |
| | | inQty: $('#inQty').val(), |
| | | row1: $('#row1').val(), |
| | | ioTime: top.strToDate($('#ioTime\\$').val()), |
| | | area: $('#area').val(), |
| | | area: getAreaSubmitValue(), |
| | | inFirstCrnCsv: $('#inFirstCrnCsv').val(), |
| | | inSecondCrnCsv: $('#inSecondCrnCsv').val(), |
| | | inFirstCrnCurrentNo: $('#inFirstCrnCurrentNo').val(), |
| | | inSecondCrnCurrentNo: $('#inSecondCrnCurrentNo').val(), |
| | | inOk: $('#inOk').val(), |
| | | outOk: $('#outOk').val(), |
| | | modiUser: $('#modiUser').val(), |
| | |
| | | } else { |
| | | $(el).val('N'); |
| | | } |
| | | }); |
| | | form.on('checkbox(areaCheckbox)', function () { |
| | | $('#area').val(getAreaSubmitValue()); |
| | | }); |
| | | |
| | | // 搜索栏搜索事件 |
| | |
| | | var find = el.find(":input[id='" + val + "']"); |
| | | var currentVal = data[val]; |
| | | if (val === 'area') { |
| | | currentVal = normalizeAreaValue(currentVal); |
| | | setAreaValues(currentVal); |
| | | if (find[0] != null) { |
| | | find.val(normalizeAreaValues(currentVal).join(',')); |
| | | } |
| | | continue; |
| | | } |
| | | if (find[0]!=null){ |
| | | if (find[0].type === 'checkbox'){ |
| | |
| | | find.remove("checked"); |
| | | find.val('N'); |
| | | } |
| | | continue; |
| | | } else if (find[0].type === 'select-multiple') { |
| | | find.val(currentVal || []); |
| | | continue; |
| | | } |
| | | } |
| | |
| | | return value; |
| | | } |
| | | |
| | | function normalizeAreaValues(value) { |
| | | if (value === undefined || value === null || value === '') { |
| | | return []; |
| | | } |
| | | var values = Object.prototype.toString.call(value) === '[object Array]' |
| | | ? value |
| | | : String(value).replace(/[,;、]/g, ',').split(/[,;]+/); |
| | | var result = []; |
| | | for (var i = 0; i < values.length; i++) { |
| | | var normalized = normalizeAreaValue(values[i]); |
| | | if (normalized === undefined || normalized === null || normalized === '') { |
| | | continue; |
| | | } |
| | | if (result.indexOf(normalized) < 0) { |
| | | result.push(normalized); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | function setAreaValues(value) { |
| | | var values = normalizeAreaValues(value); |
| | | $('#area').val(values.join(',')); |
| | | $('#areaBox input[type="checkbox"][name="areaOption"]').each(function () { |
| | | var checked = values.indexOf(this.value) >= 0; |
| | | $(this).prop('checked', checked); |
| | | if (checked) { |
| | | $(this).attr('checked', 'checked'); |
| | | } else { |
| | | $(this).removeAttr('checked'); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | function getAreaValues() { |
| | | var values = []; |
| | | $('#areaBox input[type="checkbox"][name="areaOption"]').each(function () { |
| | | if (this.checked && values.indexOf(this.value) < 0) { |
| | | values.push(this.value); |
| | | } |
| | | }); |
| | | return values; |
| | | } |
| | | |
| | | function getAreaSubmitValue() { |
| | | var values = getAreaValues(); |
| | | $('#area').val(values.join(',')); |
| | | return values.join(','); |
| | | } |
| | | |
| | | function clearFormVal(el) { |
| | | $(':input', el) |
| | | .val('') |
| | | .removeAttr('checked') |
| | | .removeAttr('selected'); |
| | | $(':input', el).each(function () { |
| | | if (this.type === 'checkbox' || this.type === 'radio') { |
| | | $(this).prop('checked', false).removeAttr('checked'); |
| | | return; |
| | | } |
| | | if (this.tagName === 'SELECT' && this.multiple) { |
| | | $(this).val([]).find('option').prop('selected', false); |
| | | return; |
| | | } |
| | | $(this).val(''); |
| | | }); |
| | | } |
| | | |
| | | function detailScreen(index) { |
| | |
| | | </div> |
| | | </div> |
| | | <div class="layui-form-item"> |
| | | <label class="layui-form-label">货物频次</label> |
| | | <div class="layui-input-block"> |
| | | <select class="layui-input" lay-ignore name="freqType"> |
| | | <option value="">默认</option> |
| | | <option value="1">高频</option> |
| | | <option value="2">低频</option> |
| | | </select> |
| | | </div> |
| | | </div> |
| | | <div class="layui-form-item"> |
| | | <label class="layui-form-label">物料编码</label> |
| | | <div class="layui-input-block"> |
| | | <input class="layui-input" name="matnr" placeholder="emptyPallet 表示空托盘"> |
| | |
| | | <input id="ioTime$" class="layui-input" type="text" autocomplete="off"> |
| | | </div> |
| | | </div> |
| | | <div class="layui-inline" style="width:31%;"> |
| | | <div class="layui-inline" style="width:94%;"> |
| | | <label class="layui-form-label">绑定库区:</label> |
| | | <div class="layui-input-inline"> |
| | | <select id="area" class="layui-input"> |
| | | <option value="">不限制</option> |
| | | <option value="A">A库区</option> |
| | | <option value="B">B库区</option> |
| | | <option value="C">C库区</option> |
| | | </select> |
| | | <div class="layui-input-block" id="areaBox" style="margin-left: 110px; min-height: 38px;"> |
| | | <input id="area" type="hidden"> |
| | | <input type="checkbox" name="areaOption" value="A" title="A库区" lay-skin="primary" lay-filter="areaCheckbox"> |
| | | <input type="checkbox" name="areaOption" value="B" title="B库区" lay-skin="primary" lay-filter="areaCheckbox"> |
| | | <input type="checkbox" name="areaOption" value="C" title="C库区" lay-skin="primary" lay-filter="areaCheckbox"> |
| | | <div class="layui-form-mid layui-word-aux" style="padding-left: 0;">仅用于站点绑定,不参与找位排序</div> |
| | | </div> |
| | | </div> |
| | | <div class="layui-inline" style="width:94%;"> |
| | | <label class="layui-form-label">第一优先池:</label> |
| | | <div class="layui-input-block" style="margin-left: 110px; min-height: 38px;"> |
| | | <input id="inFirstCrnCsv" class="layui-input" type="text" placeholder="请输入堆垛机号,按顺序填写,如 1,2,3"> |
| | | <input id="inFirstCrnCurrentNo" type="hidden"> |
| | | </div> |
| | | </div> |
| | | <div class="layui-inline" style="width:94%;"> |
| | | <label class="layui-form-label">第二优先池:</label> |
| | | <div class="layui-input-block" style="margin-left: 110px; min-height: 38px;"> |
| | | <input id="inSecondCrnCsv" class="layui-input" type="text" placeholder="请输入堆垛机号,按顺序填写,如 4,5,6"> |
| | | <input id="inSecondCrnCurrentNo" type="hidden"> |
| | | </div> |
| | | </div> |
| | | <div class="layui-inline" style="width:31%;display: none"> |