package com.ruoyi.ams.business; import cn.hutool.core.lang.Assert; import com.alibaba.fastjson.JSON; import com.ruoyi.ams.agv.ndc.common.ByteUtil; import com.ruoyi.ams.agv.ndc.common.CRC16Util; import com.ruoyi.ams.agv.ndc.domain.AmsTask; import com.ruoyi.ams.agv.ndc.service.IAmsTaskService; import com.ruoyi.ams.asn.service.IWmsDocAsnHeaderService; import com.ruoyi.ams.box.service.IWmsBoxInfoService; import com.ruoyi.ams.config.domain.AsnSoStrategy; import com.ruoyi.ams.config.domain.dto.*; import com.ruoyi.ams.config.domain.vo.FlowConfigHeaderVO; import com.ruoyi.ams.config.mapper.AsnSoStrategyMapper; import com.ruoyi.ams.config.service.IFlowConfigHeaderService; import com.ruoyi.ams.config.service.LocationAllocationStrategy; import com.ruoyi.ams.inv.domain.vo.InvLotLocIdLotattVO; import com.ruoyi.ams.inv.mapper.InvLotLocIdMapper; import com.ruoyi.ams.inv.service.IInvLotAttService; import com.ruoyi.ams.inv.service.IInvLotLocIdService; import com.ruoyi.ams.task.domain.WcsTask; import com.ruoyi.ams.task.dto.WcsTaskLocationDTO; import com.ruoyi.ams.task.mapper.WcsTaskMapper; import com.ruoyi.ams.task.service.IWcsTaskService; import com.ruoyi.base.constant.Constant; import com.ruoyi.base.domain.BaseLocationInfo; import com.ruoyi.base.domain.BaseLocationZone; import com.ruoyi.base.domain.BaseSku; import com.ruoyi.base.domain.dto.BaseLocationInfoSameColDTO; import com.ruoyi.base.domain.vo.BaseLocationLotattVO; import com.ruoyi.base.mapper.BaseLocationInfoMapper; import com.ruoyi.base.service.IBaseLocationInfoService; import com.ruoyi.base.service.IBaseSkuService; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.core.redis.RedisKey; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.uuid.SnowflakeIdWorker; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; @Slf4j @Service public class BusinessServiceImpl implements IBusinessService { @Autowired private IBusinessService businessService; @Autowired private IBaseLocationInfoService baseLocationInfoService; @Autowired private LocationAllocationStrategy locationAllocationStrategy; @Autowired private InvLotLocIdMapper invLotLocIdMapper; @Autowired private IInvLotLocIdService invLotLocIdService; @Autowired private IInvLotAttService iInvLotAttService; @Autowired private WcsTaskMapper wcsTaskMapper; @Autowired private AsnSoStrategyMapper asnSoStrategyMapper; @Autowired private BaseLocationInfoMapper baseLocationInfoMapper; @Autowired private IBaseSkuService baseSkuService; @Autowired private RedisCache redisCache; @Autowired private IWmsDocAsnHeaderService wmsDocAsnHeaderService; @Autowired private IWmsBoxInfoService wmsBoxInfoService; @Autowired private IWcsTaskService wcsTaskService; @Autowired private IAmsTaskService amsTaskService; @Autowired private IFlowConfigHeaderService flowConfigHeaderService; public static int geniKey(String taskNo) { int res = CRC16Util.calcCrc16(ByteUtil.string2byteArray(taskNo)); if (res == 0) { BigDecimal t = new BigDecimal(taskNo); t = t.add(BigDecimal.ONE); return geniKey(t.toString()); } else { return res; } } @Transactional @Override public AjaxResult agvCall(Long flowId, AgvCallDTO agvCallDTO) { //查询所属流程 FlowConfigHeaderVO flowConfigHeaderVO = flowConfigHeaderService.selectFlowConfigHeaderById(flowId); List agvCallDTOList = new ArrayList<>(); agvCallDTO.setWarehouseId(Constant.WAREHOUSE_ID); agvCallDTOList.add(agvCallDTO); return businessService.agvCall(flowConfigHeaderVO, agvCallDTOList); } @Transactional @Override public AjaxResult agvCall(FlowConfigHeaderVO flowConfigHeaderVO, AgvCallDTO agvCallDTO) { List agvCallDTOList = new ArrayList<>(); List callItemDTOList = new ArrayList<>(); AgvCallItemDTO callItemDTO = new AgvCallItemDTO(); callItemDTO.setLotattDTO(new LotattDTO()); callItemDTO.setExtParam(agvCallDTO.getExtParam()); callItemDTOList.add(callItemDTO); agvCallDTO.setAgvCallItemDTOList(callItemDTOList); agvCallDTOList.add(agvCallDTO); return businessService.agvCall(flowConfigHeaderVO, agvCallDTOList); } @Transactional @Override public AjaxResult agvCall(FlowConfigHeaderVO flowConfigHeaderVO, List agvCallDTOList) { //唯一操作标识,用于redis标记。报错时根据该id进行删除 Long token = SnowflakeIdWorker.generateId(); try { //查询全局配置策略 AsnSoStrategy asnSoStrategy = asnSoStrategyMapper.selectAsnSoStrategy(); for (AgvCallDTO agvCallDTO : agvCallDTOList) { //如果是入库把起始库位相同的数据整合到一起生成库存记录 BaseLocationInfo locationFrom = null; BaseLocationInfo locationTo = null; List wcsTaskList = new ArrayList<>(); String paramLocationFrom = agvCallDTO.getLocationFrom(); String paramLocationTo = agvCallDTO.getLocationTo(); List zoneIdList = new ArrayList<>(); if (StringUtils.isEmpty(paramLocationFrom)) { paramLocationFrom = flowConfigHeaderVO.getLocationFrom(); } if (StringUtils.isEmpty(paramLocationTo)) { paramLocationTo = flowConfigHeaderVO.getLocationTo(); } if (!StringUtils.isEmpty(flowConfigHeaderVO.getLocationFrom())) { zoneIdList = Arrays.stream(flowConfigHeaderVO.getLocationFrom().split(",")).collect(Collectors.toList()); } if (flowConfigHeaderVO.getFlowType().equals("ASN")) { List locationFromList = this.convertLocation(paramLocationFrom, agvCallDTO.getWarehouseId(), null); List locationToList = this.convertLocation(paramLocationTo, agvCallDTO.getWarehouseId(), null); // ASN类型的且要到仓储区的任务进行判断入库条件 if (flowConfigHeaderVO.getId().equals(Long.valueOf("9")) || flowConfigHeaderVO.getId().equals(Long.valueOf("10")) || flowConfigHeaderVO.getId().equals(Long.valueOf("12")) || flowConfigHeaderVO.getId().equals(Long.valueOf("13"))){ // 查询同班组的库存 List agvCallItemDTOList = agvCallDTO.getAgvCallItemDTOList(); if (agvCallItemDTOList != null && agvCallItemDTOList.size() >= 0){ String team = agvCallItemDTOList.get(0).getLotattDTO().getLotatt09(); List locationInfos = new ArrayList(); String currentColNo = null;// 当前列 Long currentZoneId = null; // 当前库区 for(BaseLocationInfo baseLocationInfo : locationToList){ if (baseLocationInfo.getColNo().equals(currentColNo) && baseLocationInfo.getZoneId().equals(currentZoneId)){ continue; } // 标记当前列分配 Boolean columnAvailable = true; // 查询当前库位的库存包含批次属性 List invLotLocIdLotattVOS = invLotLocIdService.selectInvLocIdLotattByLocationId(baseLocationInfo.getId()); for (InvLotLocIdLotattVO invLotLocIdLotattVO : invLotLocIdLotattVOS){ // 库存当前某列有不同班组 if (Objects.nonNull(invLotLocIdLotattVO) && !invLotLocIdLotattVO.getLotatt09().equals(team)){ // 标记当前列不分配 columnAvailable = false; currentColNo = baseLocationInfo.getColNo(); currentZoneId = baseLocationInfo.getZoneId(); log.info("==========当前库位有不同班组批次{}{}",baseLocationInfo,invLotLocIdLotattVO.getLotatt09()); break; } } if (columnAvailable){ // 当前列同班组或者为空 // 判断当前库位同列是否有不同类型任务 List blsList = baseLocationInfoService.selectWcsSameColumnAndTeamNotFinish(baseLocationInfo.getColNo(), team, baseLocationInfo.getZoneId(), Constant.WAREHOUSE_ID, "ASN"); // 当前列有不同类型未完成任务 继续遍历下一库位 if (blsList != null && blsList.size() > 0){ log.info("==========当前库位同列有未完成的出库任务,库位编号{}列{}",baseLocationInfo.getId(),baseLocationInfo.getColNo()); continue; } locationInfos.add(baseLocationInfo); } } locationToList = locationInfos; } } locationFrom = this.zoneLocationAllocation(locationFromList, "locationFrom", "ASN", asnSoStrategy, token, flowConfigHeaderVO.getId()); locationTo = this.zoneLocationAllocation(locationToList, "locationTo", "ASN", asnSoStrategy, token, flowConfigHeaderVO.getId()); // 初始化库存 if (agvCallDTO.getAgvCallItemDTOList().size() > 0) { iInvLotAttService.deleteInvLotAttBylocationId(locationFrom.getId()); invLotLocIdService.deleteInvLotLocIdById(locationFrom.getId()); invLotLocIdService.initInv(locationFrom.getId().toString(), agvCallDTO); } wcsTaskList.addAll(this.genTask(locationFrom, locationTo, flowConfigHeaderVO, agvCallDTO, token)); } else if (flowConfigHeaderVO.getFlowType().equals("SO")) { List locationFromListEnd = new ArrayList<>(); boolean isLocation = baseLocationInfoService.checkIsLocation(paramLocationFrom, Constant.WAREHOUSE_ID); if (isLocation) { BaseLocationInfo info = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(paramLocationFrom, Constant.WAREHOUSE_ID); locationFromListEnd.add(info); } if (locationFromListEnd.size() == 0) { AgvCallItemDTO agvCall = agvCallDTO.getAgvCallItemDTOList().size() == 0 ? new AgvCallItemDTO() : agvCallDTO.getAgvCallItemDTOList().get(0); HashMap hashMap = JSON.parseObject(JSON.toJSONString(agvCall.getLotattDTO()), HashMap.class); List locationFromList = baseLocationInfoMapper.selectSortedLocationLotattListByZoneIdListOrderBy(zoneIdList , agvCallDTO.getWarehouseId(), hashMap, agvCall.getSku(), "inv.create_time"); locationFromListEnd = locationFromList; } List locationToList = this.convertLocation(paramLocationTo, agvCallDTO.getWarehouseId(), null); // 如果是从仓储区出库的任务 检查同列未完成任务类型是否相同 if (flowConfigHeaderVO.getId().equals(Long.valueOf("14")) || flowConfigHeaderVO.getId().equals(Long.valueOf("15"))){ Assert.isTrue(checkWcsSameColumnNotFinish(locationFromListEnd, "SO"),"同列有未完成的入库任务"); } locationFrom = this.zoneLocationAllocation(locationFromListEnd, "locationFrom", "SO", asnSoStrategy, token, flowConfigHeaderVO.getId()); locationTo = this.zoneLocationAllocation(locationToList, "locationTo", "SO", asnSoStrategy, token, flowConfigHeaderVO.getId()); wcsTaskList.addAll(this.genTask(locationFrom, locationTo, flowConfigHeaderVO, agvCallDTO, token)); } else if (flowConfigHeaderVO.getFlowType().equals("MV")) { List locationFromList = this.convertLocation(paramLocationFrom, agvCallDTO.getWarehouseId(), null); List locationToList = this.convertLocation(paramLocationTo, agvCallDTO.getWarehouseId(), null); locationFrom = this.zoneLocationAllocation(locationFromList, "locationFrom", "MV", asnSoStrategy, token, flowConfigHeaderVO.getId()); locationTo = this.zoneLocationAllocation(locationToList, "locationTo", "MV", asnSoStrategy, token, flowConfigHeaderVO.getId()); // 初始化库存 if (agvCallDTO.getAgvCallItemDTOList().size() > 0) { iInvLotAttService.deleteInvLotAttBylocationId(locationFrom.getId()); invLotLocIdService.deleteInvLotLocIdById(locationFrom.getId()); invLotLocIdService.initInv(locationFrom.getId().toString(), agvCallDTO); } wcsTaskList.addAll(this.genTask(locationFrom, locationTo, flowConfigHeaderVO, agvCallDTO, token)); } } return AjaxResult.success("任务下发成功"); } catch (Exception e) { log.error("任务下发失败!", e); redisCache.unlockCacheObject(token); // 异常捕获的话就不能释放锁 throw new ServiceException(e.getMessage(), token); } } /** * 检查同列的未完成任务类型是否与当前任务类型一致 * @param baseLocationInfoList * @param type * @return */ public Boolean checkWcsSameColumnNotFinish(List baseLocationInfoList,String type){ log.info("检查同列的未完成任务类型是否与当前任务类型一致============"); for(BaseLocationInfo locationInfo: baseLocationInfoList){ // 查询任务状态不为2(完成),6(卸货完成),7(取消)的同列任务 List blsList = baseLocationInfoService.selectWcsSameColumnNotFinish(locationInfo.getColNo(), locationInfo.getColIndex(), locationInfo.getZoneId(), Constant.WAREHOUSE_ID, type); // 如果同列有不同类型的未完成任务 if (blsList != null && blsList.size() > 0){ return false; } } return true; } /** * 检查同列的未完成任务类型及班组是否与当前任务类型一致 * @param baseLocationInfoList * @param type * @return */ public List checkWcsSameColumnAndTeamNotFinish(List baseLocationInfoList,String type,String team){ log.info("检查同列的未完成任务类型及班组是否与当前任务类型一致============"); List resultList = new ArrayList<>(); for(BaseLocationInfo locationInfo: baseLocationInfoList){ // 查询任务状态不为2(完成),6(卸货完成),7(取消)的同列任务 List blsList = baseLocationInfoService.selectWcsSameColumnAndTeamNotFinish(locationInfo.getColNo(), team, locationInfo.getZoneId(), Constant.WAREHOUSE_ID, type); // 如果同列有不同类型的未完成任务 if (blsList != null && blsList.size() > 0){ resultList.addAll(blsList); } } return resultList; } @Transactional @Override public BaseLocationInfo inLocationAllocation(InWarehouseDTO inWarehouseDTO, Long token) { /** * 根据sku查询可以存放的zone * 根据每个zone的配置去分配可以存放的库位 * * force * optimization * ignore */ if (!StringUtils.isEmpty(inWarehouseDTO.getLocationTo())) { //指定库位则直接返回库位 BaseLocationInfo baseLocationInfo = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(inWarehouseDTO.getLocationTo(), inWarehouseDTO.getWarehouseId()); return baseLocationInfo; } else { if (StringUtils.isEmpty(inWarehouseDTO.getLocationZoneTo()) && StringUtils.isEmpty(inWarehouseDTO.getLocationTo())) { //不指定目标库位和区域 // 没有指定目标的根据sku进行匹配并进行分配 // 如果可以混放的区域不匹配物料也可以选择,否则只选择可以存放的区域 AsnSoStrategy asnSoStrategy = asnSoStrategyMapper.selectAsnSoStrategy(); BaseSku baseSku = baseSkuService.selectBaseSkuByCustomerId(Constant.CUSTOMER_ID, inWarehouseDTO.getSku()); //判断是否强制同物料靠近, LotattDTO lotattDTO = inWarehouseDTO.getLotattDTO(); Map lotattMap = new HashMap<>(); if (asnSoStrategy.getAsnSameLotatt1Flag().equals("optimization")) { lotattMap.put(asnSoStrategy.getAsnSameLotatt1Value(), lotattDTO.getAttr(asnSoStrategy.getAsnSameLotatt1Value())); } if (asnSoStrategy.getAsnSameLotatt2Flag().equals("optimization")) { lotattMap.put(asnSoStrategy.getAsnSameLotatt2Value(), lotattDTO.getAttr(asnSoStrategy.getAsnSameLotatt2Value())); } List locationInfoList = new ArrayList<>(); if (asnSoStrategy.getAsnSameSku().equals("force")) { List colNo = baseLocationInfoMapper.selectSameSkuColNo(baseSku.getSku(), null, lotattMap); for (String s : colNo) { List locs = baseLocationInfoService.selectNeighborLocation(s, null); locationInfoList.addAll(locs); } if (colNo == null || colNo.size() == 0) { colNo = baseLocationInfoMapper.selectSameSkuTypeColNo(baseSku.getSkuType(), null); for (String s : colNo) { List locs = baseLocationInfoService.selectNeighborLocation(s, null); locationInfoList.addAll(locs); } } // List locs = baseLocationInfoMapper.selectLocationByColNos(colNo); } else if (asnSoStrategy.getAsnSameSku().equals("optimization") || asnSoStrategy.getAsnSameSkuType().equals("optimization")) { List skuColNo = baseLocationInfoMapper.selectSameSkuColNo(baseSku.getSku(), null, lotattMap); List skuTypeColNo = baseLocationInfoMapper.selectSameSkuColNo(baseSku.getSkuType(), null, lotattMap); List cols = new ArrayList<>(); cols.addAll(skuColNo); cols.addAll(skuTypeColNo); List locs = baseLocationInfoMapper.selectLocationByColNos(cols); locationInfoList.addAll(locs); } else { locationInfoList = baseLocationInfoMapper.selectLocationBindSku(baseSku.getSkuType()); } return locationAllocationStrategy.filterLockLocation(locationInfoList, inWarehouseDTO, asnSoStrategy, token); } else { // 指定区域的 List locationInfoList = baseLocationInfoService.selectSortedLocatinListByZoneId(Long.parseLong(inWarehouseDTO.getLocationZoneTo()), inWarehouseDTO.getWarehouseId(), null); return locationAllocationStrategy.filterLockLocation(locationInfoList, token); } } } @Transactional @Override public BaseLocationInfo outInvAllocation(OutWarehouseDTO outWarehouseDTO, Long token) { /** * 指定位置出库 */ if (!StringUtils.isEmpty(outWarehouseDTO.getLocationFrom())) { BaseLocationInfo baseLocationInfo = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(outWarehouseDTO.getLocationFrom(), outWarehouseDTO.getWarehouseId()); return baseLocationInfo; } else { //未指定明确位置出库 List zoneIdList = new ArrayList<>(); if (!StringUtils.isEmpty(outWarehouseDTO.getLocationZoneFrom())) { zoneIdList.add(Long.parseLong(outWarehouseDTO.getLocationZoneFrom())); } else { List zoneList = invLotLocIdMapper.selectInvZoneBySkuLotatt(outWarehouseDTO.getSku(), outWarehouseDTO.getSkuType(), outWarehouseDTO.getLotattDTO()); for (BaseLocationLotattVO vo : zoneList) { zoneIdList.add(vo.getZoneId()); } } LotattDTO lotattDTO = outWarehouseDTO.getLotattDTO(); List locationInfoList = baseLocationInfoMapper.selectSortedLocationLotattListByZoneIdList(zoneIdList, outWarehouseDTO.getWarehouseId(), lotattDTO.getAttr()); AsnSoStrategy asnSoStrategy = asnSoStrategyMapper.selectAsnSoStrategy(); return locationAllocationStrategy.filterLockInv(locationInfoList, outWarehouseDTO, asnSoStrategy, token); } } @Override public BaseLocationInfo zoneLocationAllocation(List locationInfoList, String locationType , String type, AsnSoStrategy asnSoStrategy, Long token, Long flowId) { BaseLocationInfo locationInfo = null; String fromMsg = ""; String toMsg = ""; if (type.equals("ASN")) { // 入库 if (locationType.equals("locationFrom")) { } else { //目标库位 } } else if (type.equals("SO")) { // 出库 if (locationType.equals("locationFrom")) { } else { //目标库位 } } else { //移库 if (locationType.equals("locationFrom")) { } else { } } if (locationType.equals("locationFrom")) { // 如果是从仓储区出库 调用无需判断阻挡的方法 if (type.equals("SO") && (flowId.equals(Long.valueOf("14")) || flowId.equals(Long.valueOf("15")))){ locationInfo = checkTheSameColumnLocationSO(locationInfoList, token); }else { locationInfo = checkTheSameColumnLocation(locationInfoList, token, false); } if (locationInfo == null) { if (type.equals("ASN")) { // 入库 fromMsg = "起始点没有可以分配的库存!"; } else if (type.equals("SO")) { // 出库 fromMsg = "起始点没有可以分配的库存!"; } else { //移库 fromMsg = "起始点没有可以分配的库位"; } throw new ServiceException(fromMsg, token); } } else { // 是到仓储区的入库任务 if (type.equals("ASN") && !flowId.equals(Long.valueOf("8")) && !flowId.equals(Long.valueOf("11"))){ locationInfo = checkTheSameColumnLocationASN(locationInfoList, token, true); }else { locationInfo = checkTheSameColumnLocation(locationInfoList, token, true); } if (locationInfo == null) { if (type.equals("ASN")) { // 入库 toMsg = "目标点没有可以分配的库位"; } else if (type.equals("SO")) { // 出库 toMsg = "目标点没有可以分配的库位"; } else { //移库 toMsg = "目标点没有可以分配的库位"; } throw new ServiceException(toMsg, token); } } return locationInfo; } /** * 入库判断目标点位 * @param locationInfoList * @param token * @param isReleaseGoods * @return */ private BaseLocationInfo checkTheSameColumnLocationASN(List locationInfoList, Long token, boolean isReleaseGoods) { BaseLocationInfo basLocation = null; //筛选2次 第2次去除同列占用和阻挡条件 todo 先筛选一次吧 for (int i = 0; i < 1 && basLocation == null; i++) { for (BaseLocationInfo location : locationInfoList) { // 目标点位必须空闲、空且没有被锁住 if (!location.getStockStatus().equals(Constant.STOCK_STATUS.STOCK00.getValue()) || !location.getIsEmpty().equals(Constant.IS_YES.Y.name()) || redisCache.checkIsLock(RedisKey.LOCK_LOCATION + location.getId())) { continue; } if (!redisCache.lockCacheObject(RedisKey.LOCK_LOCATION + location.getId() , location.getId().toString() , token)) { continue; } basLocation = location; break; } } return basLocation; } /** * 校验同列任务任务状态和阻挡 * * @param basLocationList * @param token * @param isReleaseGoods 是否目标点位 * @return */ public BaseLocationInfo checkTheSameColumnLocation(List basLocationList, Long token, boolean isReleaseGoods) { boolean isBlock = false; // 是否阻挡 BaseLocationInfo basLocation = null; //筛选2次 第2次去除同列占用和阻挡条件 todo 先筛选一次吧 for (int i = 0; i < 1 && basLocation == null; i++) { for (BaseLocationInfo location : basLocationList) { //如果库位类型不为地堆则不用判断同列占用和阻挡 if (location.getLocationType().equals("2")) { isBlock = true; } //只有第一次判断同列任务占用和阻挡 if (i == 0 && isBlock) { //同列是否有任务 List occupyByLocs = baseLocationInfoMapper.queryByListOccupyByLoc(location); if (occupyByLocs.size() > 0) { log.info("同列有任务=========={}",occupyByLocs); continue; } //同列前方是否有阻挡 List inStockByLocs = baseLocationInfoMapper.queryByListInStockByLoc(location); if (inStockByLocs.size() > 0) { log.info("同列有阻挡=========={}",inStockByLocs); continue; } } // 是否目标点 if (!isReleaseGoods) { // 起始点位状态必须空闲且没有被锁住 if (!location.getStockStatus().equals(Constant.STOCK_STATUS.STOCK00.getValue()) || redisCache.checkIsLock(RedisKey.LOCK_LOCATION + location.getId())) { continue; } } else { // 目标点状态为空闲、空、且没有被锁住 if (!location.getStockStatus().equals(Constant.STOCK_STATUS.STOCK00.getValue()) || !location.getIsEmpty().equals(Constant.IS_YES.Y.name()) || redisCache.checkIsLock(RedisKey.LOCK_LOCATION + location.getId())) { continue; } } if (!redisCache.lockCacheObject(RedisKey.LOCK_LOCATION + location.getId() , location.getId().toString() , token)) { continue; } basLocation = location; break; } } return basLocation; } /** * AGV出库任务生成时的起始位置不判断是否阻挡 * @param basLocationList * @param token * @return */ public BaseLocationInfo checkTheSameColumnLocationSO(List basLocationList, Long token) { BaseLocationInfo basLocation = null; //筛选2次 第2次去除同列占用和阻挡条件 todo 先筛选一次吧 for (int i = 0; i < 1 && basLocation == null; i++) { for (BaseLocationInfo location : basLocationList) { // 起始点位状态必须空闲且没有被锁住 if (!location.getStockStatus().equals(Constant.STOCK_STATUS.STOCK00.getValue()) || redisCache.checkIsLock(RedisKey.LOCK_LOCATION + location.getId())) { continue; } if (!redisCache.lockCacheObject(RedisKey.LOCK_LOCATION + location.getId() , location.getId().toString() , token)) { continue; } basLocation = location; break; } } return basLocation; } @Override public List convertLocation(String locationNoOrZoneId, Long warehouseId, String orderBy) { List locationInfoList = new ArrayList<>(); if (!StringUtils.isEmpty(locationNoOrZoneId)) { String[] arr = locationNoOrZoneId.split(","); for (String obj : arr) { boolean isLocation = baseLocationInfoService.checkIsLocation(obj, warehouseId); if (isLocation) { BaseLocationInfo info = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(obj, warehouseId); locationInfoList.add(info); } else { List infoList = baseLocationInfoService.selectSortedLocatinListByZoneId(Long.parseLong(obj), warehouseId, orderBy); locationInfoList.addAll(infoList); } } } return locationInfoList; } @Override public List genTask(BaseLocationInfo locationFrom, BaseLocationInfo locationTo, FlowConfigHeaderVO flowConfigHeaderVO, AgvCallDTO agvCallDTO, Long token) { if (flowConfigHeaderVO.getLocationFromStrategyFlag().equals("N")) { if (locationFrom == null) { throw new ServiceException("起始库位不能为空", token); } } if (flowConfigHeaderVO.getLocationToStrategyFlag().equals("N")) { if (locationTo == null) { throw new ServiceException("目标库位不能为空", token); } } List wcsTaskList = new ArrayList<>(); if (StringUtils.isEmpty(flowConfigHeaderVO.getRootFlow())) { String taskNo = System.currentTimeMillis() + ""; WcsTask wcsTask = new WcsTask(); wcsTask.setTaskNo(taskNo); if (locationFrom != null) { wcsTask.setAreaFrom(locationFrom.getZoneId().toString()); wcsTask.setLocationFrom(locationFrom.getId().toString()); } if (locationTo != null) { wcsTask.setAreaTo(locationTo.getZoneId() + ""); wcsTask.setLocationTo(locationTo.getId().toString()); } wcsTask.setState(9L); wcsTask.setPriority(1L); wcsTask.setShopId(Constant.WAREHOUSE_ID.toString()); wcsTask.setCreateDate(new Date()); wcsTask.setCreateUser(agvCallDTO.getCreateUser()); wcsTask.setBusinessType("01"); wcsTask.setTaskType(Constant.TASK_TYPE.FORWARD.getValue()); wcsTask.setExt8(token.toString()); wcsTask.setExt7(flowConfigHeaderVO.getId().toString()); // 是否复称 wcsTask.setExt3(agvCallDTO.getTheWeighing() == null ? "0000" : agvCallDTO.getTheWeighing() ? "0001" : "0000"); wcsTask.setExtParam(agvCallDTO.getExtParam()); wcsTaskList.add(wcsTask); businessService.addTask(wcsTask); } else { /*//获取对应的流程 List headerVOList = flowConfigHeaderService.sortFlowConfigHeader(Long.parseLong(flowConfigHeaderVO.getRootFlow())); AsnSoStrategy asnSoStrategy = asnSoStrategyMapper.selectAsnSoStrategy(); String taskNo = System.currentTimeMillis() + ""; WcsTask wcsTask = new WcsTask(); wcsTask.setTaskNo(taskNo); wcsTask.setAreaFrom(locationFrom.getZoneId().toString()); wcsTask.setLocationFrom(locationFrom.getId().toString()); wcsTask.setAreaTo(locationTo.getZoneId() + ""); wcsTask.setLocationTo(locationTo.getId().toString()); wcsTask.setState(9L); wcsTask.setPriority(1L); wcsTask.setCreateDate(new Date()); wcsTask.setBusinessType("01"); wcsTask.setTaskType(""); wcsTaskList.add(wcsTask); String beforeTaskNo = taskNo; for (FlowConfigHeader flowConfigHeader : headerVOList) { if (StringUtils.isEmpty(flowConfigHeader.getRelFlow()) && flowConfigHeader.getRootFlow().equals(flowConfigHeader.getId().toString())) { continue; } List locationFromList = this.convertLocation(flowConfigHeader.getLocationFrom(), 1L); List locationToList = this.convertLocation(flowConfigHeader.getLocationTo(), 1L); locationFrom = this.zoneLocationAllocation(locationFromList, "locationFrom", "MV", null, null); locationTo = this.zoneLocationAllocation(locationToList, "locationTo", "MV", null, null); String currentNo = SnowflakeIdWorker.generateId().toString(); WcsTask child = new WcsTask(); child.setTaskNo(currentNo); child.setParentTask(taskNo); child.setBeforeTask(beforeTaskNo); child.setAreaFrom(locationFrom.getZoneId().toString()); child.setLocationFrom(locationFrom.getId().toString()); child.setAreaTo(locationTo.getZoneId() + ""); child.setLocationTo(locationTo.getId().toString()); child.setState(9L); child.setPriority(1L); child.setCreateDate(new Date()); child.setBusinessType("01"); child.setTaskType(""); wcsTaskList.add(child); beforeTaskNo = currentNo; }*/ } return wcsTaskList; } @Transactional @Override public AjaxResult addTask(WcsTask wcsTask) { //锁定库位 if (!StringUtils.isEmpty(wcsTask.getLocationFrom())) { baseLocationInfoService.updateLocationStockStatus(Long.parseLong(wcsTask.getLocationFrom()), Constant.STOCK_STATUS.STOCK10.getValue()); } if (!StringUtils.isEmpty(wcsTask.getLocationTo())) { baseLocationInfoService.updateLocationStockStatus(Long.parseLong(wcsTask.getLocationTo()), Constant.STOCK_STATUS.STOCK10.getValue()); } Integer priority = 1; if (!wcsTask.getTaskType().equals("OB")) { if (wcsTask.getPriority() == 99) { int current = wcsTaskMapper.selectCurrentPriority(); priority = current - 100; } else { int current = wcsTaskMapper.selectCurrentPriority(); priority = current + 10; } } else { //倒库任务顺序由原任务中间插入不需要获取 priority = wcsTask.getPriority().intValue(); } wcsTask.setPriority((long) priority); int result = wcsTaskMapper.insertWcsTask(wcsTask); if (result > 0) { return AjaxResult.success("任务生成成功"); } else { throw new ServiceException("任务生成失败"); } } @Override public AjaxResult addTaskList(List wcsTaskList) { for (WcsTask wcsTask : wcsTaskList) { //锁定库位 if (!StringUtils.isEmpty(wcsTask.getLocationFrom())) { baseLocationInfoService.updateLocationStockStatus(Long.parseLong(wcsTask.getLocationFrom()), Constant.STOCK_STATUS.STOCK10.getValue()); } if (!StringUtils.isEmpty(wcsTask.getLocationTo())) { baseLocationInfoService.updateLocationStockStatus(Long.parseLong(wcsTask.getLocationTo()), Constant.STOCK_STATUS.STOCK10.getValue()); } Integer priority = 1; if (!wcsTask.getTaskType().equals("OB")) { if (wcsTask.getPriority() == 99) { int current = wcsTaskMapper.selectCurrentPriority(); priority = current - 100; } else { int current = wcsTaskMapper.selectCurrentPriority(); priority = current + 10; } } else { //倒库任务顺序由原任务中间插入不需要获取 priority = wcsTask.getPriority().intValue(); } wcsTask.setPriority((long) priority); int result = wcsTaskMapper.insertWcsTask(wcsTask); if (result > 0) { return AjaxResult.success("任务生成成功"); } else { throw new ServiceException("任务生成失败"); } } return AjaxResult.success(""); } @Override public AjaxResult sendTask(WcsTask wcsTask) { BaseLocationInfo locFrom = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(wcsTask.getLocationFrom(), Constant.WAREHOUSE_ID); BaseLocationInfo locTo = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(wcsTask.getLocationTo(), Constant.WAREHOUSE_ID); log.info("进入AMS任务下发=========={}",wcsTask); AmsTask amsTask = new AmsTask(); amsTask.setTaskNo(wcsTask.getTaskNo()); if (wcsTask.getBusinessType() == null || wcsTask.getBusinessType().equals("")) { amsTask.setBusinessType(Constant.TASK_BUSINESS_TYPE.TASK_01.getValue()); } else { amsTask.setBusinessType(wcsTask.getBusinessType()); } amsTask.setIsDelete(0); amsTask.setAciAccept(0); amsTask.setIkey((long) geniKey(amsTask.getTaskNo())); amsTask.setPriority(wcsTask.getPriority().intValue()); amsTask.setExt1(wcsTask.getExt1()); amsTask.setExt2(wcsTask.getExt2()); amsTask.setExt3(wcsTask.getExt3()); if(wcsTask.getBusinessType().equals(Constant.TASK_BUSINESS_TYPE.TASK_POWER.getValue())){ amsTask.setStFrom(Integer.valueOf(wcsTask.getLocationFrom())); amsTask.setStTo(Integer.valueOf(wcsTask.getLocationTo())); amsTask.setDeviceName(wcsTask.getDeviceName()); }else{ amsTask.setStFrom(locFrom.getAgvStation().intValue()); amsTask.setStTo(locTo.getAgvStation().intValue()); } if (wcsTask.getBusinessType().equals("m")) { //m类消息特殊处理 wcsTask.setState(2L); int result = wcsTaskService.updateWcsTask(wcsTask); if (result > 0) { //更新 return AjaxResult.success("下发成功"); } else { return AjaxResult.error("下发失败"); } } else { int result = amsTaskService.insertAmsTask(amsTask); if (result > 0) { //更新 return AjaxResult.success("下发成功"); } else { return AjaxResult.error("下发失败"); } } } @Override public AjaxResult sendTaskList(List wcsTaskList) { return null; } @Transactional @Override public void autoSend() { List wcsTaskList = wcsTaskService.selectWcsUnallocated(Constant.WAREHOUSE_ID); if (wcsTaskList != null && wcsTaskList.size() > 0) { for (WcsTask wcsTask : wcsTaskList) { //如果是充电任务直接下发 if (wcsTask.getBusinessType().equals(Constant.TASK_BUSINESS_TYPE.TASK_POWER.getValue()) || wcsTask.getBusinessType().equals(Constant.TASK_BUSINESS_TYPE.TASK_m.getValue())) { log.info("定时充电/盘点取消任务直接下发"); sendTask(wcsTask); wcsTask.setState(2L); wcsTaskService.updateWcsTask(wcsTask); break; } //转发任务 if (StringUtils.isNotEmpty(wcsTask.getTaskType()) && wcsTask.getTaskType().equals(Constant.TASK_TYPE.FORWARD.getValue())) { log.info("进入转发任务{}=={}========", wcsTask.getTaskType(), wcsTask.getExt7()); // 判断如果是出库任务 if (StringUtils.isNotEmpty(wcsTask.getExt7()) && (wcsTask.getExt7().equals(String.valueOf(Constant.FLOW_CONFIG_ID.FOURTEEN.getValue())) || wcsTask.getExt7().equals(String.valueOf(Constant.FLOW_CONFIG_ID.FIFTEEN.getValue())))) { log.info("出库任务下发AMS调用AGV{}", JSON.toJSONString(wcsTask)); // 根据起始地查询库位信息 BaseLocationInfo baseLocationInfo = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(wcsTask.getLocationFrom(), Constant.WAREHOUSE_ID); //同列外方是否有任务 List occupyByLocs = baseLocationInfoMapper.queryByListOccupyByLoc(baseLocationInfo); if (occupyByLocs.size() > 0) { log.info("同列外面有任务=========={}", occupyByLocs); continue; } //同列前方是否有阻挡 List inStockByLocs = baseLocationInfoMapper.queryByListInStockByLoc(baseLocationInfo); if (inStockByLocs.size() > 0) { log.info("同列有阻挡=========={}", inStockByLocs); continue; } } else if (StringUtils.isNotEmpty(wcsTask.getExt7()) // 判断如果是入库任务 && (wcsTask.getExt7().equals(String.valueOf(Constant.FLOW_CONFIG_ID.NINE.getValue())) || wcsTask.getExt7().equals(String.valueOf(Constant.FLOW_CONFIG_ID.TEN.getValue())) || wcsTask.getExt7().equals(String.valueOf(Constant.FLOW_CONFIG_ID.TWELVE.getValue())) || wcsTask.getExt7().equals(String.valueOf(Constant.FLOW_CONFIG_ID.THIRTEEN.getValue())))) { log.info("入库任务下发AMS调用AGV{}", JSON.toJSONString(wcsTask)); // 根据起始地查询库位信息 BaseLocationInfo baseLocationInfo = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(wcsTask.getLocationFrom(), Constant.WAREHOUSE_ID); //同列里面是否有任务 List occupyByLocs = baseLocationInfoMapper.queryByListOccupyByLocOR(baseLocationInfo); if (occupyByLocs.size() > 0) { log.info("同列里面有任务=========={}", occupyByLocs); continue; } //同列前方是否有阻挡 List inStockByLocs = baseLocationInfoMapper.queryByListInStockByLoc(baseLocationInfo); if (inStockByLocs.size() > 0) { log.info("同列有阻挡=========={}", inStockByLocs); continue; } sendTask(wcsTask); wcsTask.setState(10L); wcsTaskService.updateWcsTask(wcsTask); break; } try { //任务下发判断 businessService.taskDispatchStack(wcsTask); Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } } } } } @Transactional @Override public void autoSendTranSit() { List baseLocationInfos = baseLocationInfoService.selectSortedLocatinListByZoneId(Constant.ZONE_TYPE.TRANSIT.getValue() , Constant.WAREHOUSE_ID, null); for (BaseLocationInfo baseLocationInfo : baseLocationInfos) { // 判断是否有货并且空闲 // if (baseLocationInfo.getStockStatus().equals(Constant.STOCK_STATUS.STOCK00.getValue()) // && baseLocationInfo.getIsEmpty().equals(Constant.IS_YES.N.name())) { // if (baseLocationInfo.getUserdefine1().equals("ASN")) { // AgvCallDTO agvCallDTO = new AgvCallDTO(); // agvCallDTO.setLocationFrom(baseLocationInfo.getLocationNo()); // businessService.agvCall(Constant.TRAN_STO_FLOW_ID, agvCallDTO); // } else if (baseLocationInfo.getUserdefine1().equals("SO_HG")) { // AgvCallDTO agvCallDTO = new AgvCallDTO(); // agvCallDTO.setLocationFrom(baseLocationInfo.getLocationNo()); // businessService.agvCall(Constant.TRAN_OUT_FLOW_ID, agvCallDTO); // } else if (baseLocationInfo.getUserdefine1().equals("SO_BHG")) { // AgvCallDTO agvCallDTO = new AgvCallDTO(); // agvCallDTO.setLocationFrom(baseLocationInfo.getLocationNo()); // businessService.agvCall(Constant.TRAN_OUT_BHG_FLOW_ID, agvCallDTO); // } // } } } @Transactional @Override public boolean taskDispatchStack(WcsTask wcsTask) { /* boolean isSplit = taskService.taskSplit(wcsTask); //判断是否拆分如果拆分了直接跳过 if(isSplit){ return false; }*/ //最后要执行的任务 WcsTask currentTask = new WcsTask(); //来源库位 BaseLocationInfo basLocationInfoFrom = null; //目标区域 BaseLocationZone basLocationZoneTo = null; //起始库位 basLocationInfoFrom = baseLocationInfoService.selectBaseLocationInfoById(Long.parseLong(wcsTask.getLocationFrom())); //目标库位 BaseLocationInfo locationInfoTo = baseLocationInfoService.selectBaseLocationInfoById(Long.parseLong(wcsTask.getLocationTo())); //TODO 前置任务未完成不进行下发 if (businessService.taskDispatchCheck(wcsTask) == false) { return false; } if (basLocationInfoFrom != null) { if (basLocationInfoFrom.getIsEmpty().equals("Y")) { wcsTask.setRemark("起始库位为空无法进行任务"); wcsTaskService.updateWcsTask(wcsTask); return false; } //起始库位巷道检测(起始库位检测是否同巷道) if (!StringUtils.isEmpty(basLocationInfoFrom.getColNo())) { List locationInfoList = baseLocationInfoMapper.laneCheck(basLocationInfoFrom.getColNo(), "LANE_FROM", Constant.WAREHOUSE_ID); if (locationInfoList != null && locationInfoList.size() > 0) { wcsTask.setRemark("起始库位同列或同巷道有车辆在任务中,等待其他任务完成"); wcsTaskService.updateWcsTask(wcsTask); return false; } } } //起始库位是地堆需要判断是否有阻挡 if (basLocationInfoFrom.getLocationType().equals("2")) { //判断队列中是否有阻挡在当前任务之前 List locationDTOS = wcsTaskService.selectTaskByColNo(basLocationInfoFrom.getColNo(), basLocationInfoFrom.getColIndex(), basLocationInfoFrom.getZoneId(), null); if (locationDTOS.size() > 0) { wcsTask.setRemark("队列中有其他任务阻挡,让其他任务先执行"); wcsTaskService.updateWcsTask(wcsTask); return false; } //判断出库库位前是否有阻挡 List beforeLoc = baseLocationInfoService.selectBeforeLocationByColNo(basLocationInfoFrom.getColNo(), basLocationInfoFrom.getColIndex()); if (beforeLoc != null) { for (BaseLocationInfo b : beforeLoc) { //如果前面库位不为空,或者状态占用 //TODO 去除已经在任务中的 if (b.getIsEmpty().equals("N")) { wcsTask.setRemark("有阻挡物,任务无法执行"); wcsTaskService.updateWcsTask(wcsTask); return false; } } } } currentTask = wcsTask; //目标库位如果是地堆需要判断是否有阻挡 if (locationInfoTo != null && locationInfoTo.getLocationType().equals("2")) { List beforeLoc = baseLocationInfoService.selectBeforeLocationByColNo(locationInfoTo.getColNo(), locationInfoTo.getColIndex()); if (beforeLoc != null) { for (BaseLocationInfo b : beforeLoc) { //跳过起始库位 if (b.getId().equals(locationInfoTo.getId())) { continue; } //如果前面库位不为空,或者状态占用 //TODO 排除已经在任务中的 if (b.getIsEmpty().equals("N")) { currentTask.setRemark("目标库位前方有阻挡1"); currentTask.setUpdateDate(new Date()); wcsTaskService.updateWcsTask(currentTask); return false; } } } List dtos = wcsTaskService.selectTaskByColNoAfter(locationInfoTo.getColNo(), locationInfoTo.getColIndex(), locationInfoTo.getZoneId(), null); if (dtos != null && dtos.size() > 0) { currentTask.setRemark("目标库位同列有未完成的任务"); wcsTaskService.updateWcsTask(currentTask); return false; } } //查询是否有更里面的位置可以存放 if (locationInfoTo != null) { if (locationInfoTo.getZoneId() != 10) { String locationtoTmp = ""; List b = baseLocationInfoService.selectSameColCanToLoc(locationInfoTo.getColNo(), locationInfoTo.getColIndex()); for (BaseLocationInfoSameColDTO bt : b) { if (bt.getIsOb() == false) { locationtoTmp = bt.getId().toString(); } else { break; } } if (!StringUtils.isEmpty(locationtoTmp)) { wcsTask.setLocationTo(locationtoTmp); wcsTaskService.updateWcsTask(wcsTask); //释放原库位 locationInfoTo.setStockStatus("00"); baseLocationInfoService.updateBaseLocationInfo(locationInfoTo); //占用新库位 BaseLocationInfo newlocationInfoTo = baseLocationInfoService.selectBaseLocationInfoById(Long.parseLong(locationtoTmp)); newlocationInfoTo.setStockStatus("10"); baseLocationInfoService.updateBaseLocationInfo(newlocationInfoTo); } } } currentTask.setState(10L); currentTask.setRemark(""); if (wcsTaskService.updateWcsTask(currentTask) > 0) { AjaxResult result = businessService.sendTask(currentTask); if ((int) result.get(AjaxResult.CODE_TAG) == 500) { throw new ServiceException("自动下发任务失败:" + result.get("msg")); } return true; } else { return false; } } @Override public boolean taskDispatchCheck(WcsTask wcsTask) { if (!StringUtils.isEmpty(wcsTask.getBeforeTask())) { List taskFindBeforeRecord = wcsTaskMapper.selectBeforeTask(wcsTask.getBeforeTask()); if (taskFindBeforeRecord != null && taskFindBeforeRecord.size() > 0) { //log.info("前置任务未完成主任务无法下发{}",wcsTask); wcsTask.setRemark("前置任务未完成主任务无法下发"); wcsTaskService.updateWcsTask(wcsTask); return false; } } return true; } }