Commit 4b69d55c zshaohui

1.增加双库位获取库位号,移库功能

1 个父辈 a6ad05c1
package com.neotel.smfcore.core.device.rest;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.neotel.smfcore.common.bean.ReelLockPosInfo;
import com.neotel.smfcore.common.bean.ResultBean;
import com.neotel.smfcore.common.exception.ValidateException;
import com.neotel.smfcore.common.utils.Constants;
import com.neotel.smfcore.common.utils.ReelLockPosUtil;
import com.neotel.smfcore.common.utils.StringUtils;
import com.neotel.smfcore.core.api.SmfApi;
import com.neotel.smfcore.core.api.bean.CodeValidateParam;
import com.neotel.smfcore.core.barcode.service.manager.IBarcodeManager;
import com.neotel.smfcore.core.barcode.service.po.Barcode;
import com.neotel.smfcore.core.barcode.utils.CodeResolve;
import com.neotel.smfcore.core.device.enums.OP;
import com.neotel.smfcore.core.device.enums.OP_STATUS;
import com.neotel.smfcore.core.device.util.DataCache;
import com.neotel.smfcore.core.language.util.MessageUtils;
import com.neotel.smfcore.core.message.util.DeviceMessageUtil;
import com.neotel.smfcore.core.storage.service.manager.IStoragePosManager;
import com.neotel.smfcore.core.storage.service.po.Storage;
import com.neotel.smfcore.core.storage.service.po.StoragePos;
import com.neotel.smfcore.core.system.service.dao.IAlarmInfoDao;
import com.neotel.smfcore.core.system.service.po.AlarmInfo;
import com.neotel.smfcore.core.system.service.po.DataLog;
import com.neotel.smfcore.core.system.util.TaskService;
import com.neotel.smfcore.security.annotation.AnonymousAccess;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
@Slf4j
@Api(tags = "双库位设备")
@RequestMapping("/dualPosNameDevice")
@RestController
public class DualPosNameDeviceController {
@Autowired
private DataCache dataCache;
@Autowired
private SmfApi smfApi;
@Autowired
private TaskService taskService;
@Autowired
private IStoragePosManager storagePosManager;
@Autowired
private CodeResolve codeResolve;
@Autowired
private IAlarmInfoDao alarmInfoDao;
@Autowired
private IBarcodeManager barcodeManager;
/**
* 流水线提示消息
*/
private static String lineMsg = "";
/**
* 流水线入库查找空的料格
*/
@ApiOperation("环行线扫码获取库位号")
@PostMapping(value = "/emptyPosForPutin")
@ResponseBody
@AnonymousAccess
public Map<String, Object> emptyPosForPutin(HttpServletRequest request) {
String code = request.getParameter("code");
String cids = request.getParameter("cids");
String rfid = request.getParameter("rfid");
String rfidLoc = request.getParameter("rfidLoc");
String lastPosId = request.getParameter("lastPosId");
lineMsg = "";
log.info("流水线[" + cids + "]获取[" + rfid + "][" + code + "]的入库库位");
Map<String, Object> resultMap = Maps.newHashMap();
if (dataCache.getCache(Constants.CACHE_StopOut)) {
lineMsg = "系统更新中,暂停出入库";
DeviceMessageUtil.updateLineMsg(lineMsg, code, cids, "", "smfcore.linemsg.update", null);
resultMap.put("result", "100");
resultMap.put("msg", lineMsg);
return resultMap;
}
String okMsg = "";
String errorMsg = "";
// List<String> needRemoveReelLockPosIdList = new ArrayList<>();
if (Strings.isNullOrEmpty(cids)) {
resultMap.put("result", "101");
resultMap.put("msg", "未指定料仓 cids ");
} else {
List<Storage> storageList = Lists.newArrayList();
List<String> cidList = Lists.newArrayList();
for (String cid : cids.split(",")) {
String notIntoCids = dataCache.getSettings().getNotIntoCids();
if (notIntoCids != null) {
if (notIntoCids.contains(cid)) {
log.info("料仓[" + cid + "]已被屏蔽入库");
continue;
}
}
Storage storage = dataCache.getStorage(cid);
if (storage != null) {
storageList.add(storage);
cidList.add(cid);
}
}
if (storageList.isEmpty()) {
resultMap.put("result", "99");
errorMsg = "无可用的料仓";
resultMap.put("msg", errorMsg);
} else {
try {
CodeValidateParam params = new CodeValidateParam("", "", "", code, "");
params.setStorageList(storageList);
Barcode barcode = resolveBarcodeFromApi(params);
if (barcode == null) {
throw new ValidateException("smfcore.error.barcode.invalid", "未找到有效的条码");
}
//判断是否有出入库任务
for (DataLog dataLog : taskService.getAllTasks()) {
if (dataLog.getBarcode().equals(barcode.getBarcode()) && !dataLog.isCancel() && !dataLog.isFinished()) {
if (dataLog.isPutInTask()) {
//已有入库任务
errorMsg = "物料[" + dataLog.getBarcode() + "]已有入库任务,需继续执行入库动作";
resultMap.put("pos", dataLog.getPosName());
resultMap.put("barcode", barcode.getBarcode());
resultMap.put("cid", dataLog.getCid());
return resultMap;
} else {
//已有出库任务
errorMsg = "物料[" + dataLog.getBarcode() + "]已有出库任务,需继续执行出库动作";
resultMap.put("result", "98");
resultMap.put("msg", errorMsg);
resultMap.put("posId", dataLog.getPosName());
resultMap.put("plateW", barcode.getPlateSize());
resultMap.put("plateH", barcode.getHeight());
resultMap.put("singleOut", dataLog.isSingleOut() + "");
//紧急料
resultMap.put("urgentReel", dataLog.isUrgentReel() + "");
//需要分盘,进入分盘料
resultMap.put("cutReel", dataLog.isCutReel() + "");
resultMap.put("rfid", "");
resultMap.put("realRfid", "");
resultMap.put("rfidLoc", "");
resultMap.put("barcode", dataLog.getBarcode());
boolean smallReel = barcode.isSmallReel();
resultMap.put("smallReel", smallReel + "");
return resultMap;
}
}
}
//判断对应的尺寸,外侧的库位,是否保留5个
List<String> findCidList = new ArrayList<>();
List<Storage> findNewStorageList = new ArrayList<>();
for (Storage storage : storageList) {
int count = storagePosManager.getRemainPosCountByStorage(storage, barcode, taskService.excludePosIds(), "", "_F");
if (count > 5) {
findCidList.add(storage.getCid());
findNewStorageList.add(storage);
} else {
log.info(storage.getCid() + "对应的尺寸:" + barcode.getPlateSize() + "x" + barcode.getHeight() + "外侧库位数量小于等于5个,忽略不入库");
}
}
if (findNewStorageList == null || findNewStorageList.isEmpty()) {
throw new ValidateException("smfcore.noValidStorage", "[{0}]料仓列表中未找到可用的料仓", new String[]{barcode.getBarcode()});
}
//先移除被锁定的库位
ReelLockPosUtil.removeReelLockPosInfo(barcode.getBarcode());
log.info(barcode.getBarcode() + "料盘重新入库,先移除被锁定的库位");
StoragePos pos = null;
int loopCount = 0;
List<String> needRemoveLockPosId = new ArrayList<>();
String endStr = "B";
while (pos == null) {
loopCount++;
if (loopCount >= 30) {
log.info(barcode.getBarcode() + "已循环查找30次 直接跳出循环");
break;
}
if (loopCount >= 15) {
endStr = "F";
}
pos = taskService.dualPosNameFindEmptyPosForPutIn(findNewStorageList, barcode, rfid, lastPosId, barcode.getBarcode(), endStr);
if (pos == null) {
if ("B".equals(endStr)) {
endStr = "F";
} else {
endStr = "B";
}
pos = taskService.dualPosNameFindEmptyPosForPutIn(findNewStorageList, barcode, rfid, lastPosId, barcode.getBarcode(), endStr);
}
if (pos == null) {
break;
}
//如果是以S结尾的,则判断不带S的有没有料
String posName = pos.getPosName();
if (posName.endsWith("B") || posName.endsWith("b")) {
log.info(posName + "以B结尾,需要判断外层有没有物料");
posName = posName.substring(0, posName.length() - 1);
posName = posName + "F";
StoragePos storagePos = storagePosManager.getByPosName(posName);
if (storagePos != null) {
Set<String> allLockPosIds = ReelLockPosUtil.getAllLockPosIds();
boolean contains = allLockPosIds.contains(storagePos.getId());
if (storagePos.getBarcode() != null || contains) {
log.info(posName + "有物料信息,重新查找库位,清除条码[" + barcode.getBarcode() + "]锁定库位");
ReelLockPosUtil.removeReelLockPosInfo(barcode.getBarcode());
ReelLockPosInfo reelLocInfo = new ReelLockPosInfo();
reelLocInfo.setBarcode(pos.getId());
reelLocInfo.setCid(dataCache.getStorageById(pos.getStorageId()).getCid());
reelLocInfo.setLockPosName(pos.getPosName());
reelLocInfo.setLockPosId(pos.getId());
ReelLockPosUtil.addReelLockPosInfo(reelLocInfo, findCidList);
needRemoveLockPosId.add(pos.getId());
pos = null;
}
}
}
}
//判断有没有锁定的异常库位
if (needRemoveLockPosId != null && !needRemoveLockPosId.isEmpty()) {
for (String posId : needRemoveLockPosId) {
ReelLockPosUtil.removeReelLockPosInfo(posId);
}
}
if (pos != null) {
Storage theStorage = dataCache.getStorageById(pos.getStorageId());
resultMap.put("result", "0");
resultMap.put("msg", "");
okMsg = "[" + rfid + "][" + barcode.getBarcode() + "]锁定库位[" + pos.getPosName() + "]优先级[" + pos.getPriority() + "] 上个库位号[" + lastPosId + "]";
ReelLockPosInfo oldLockInfo = ReelLockPosUtil.getLockPosInfoByCode(barcode.getBarcode());
if (oldLockInfo != null) {
if (!oldLockInfo.getLockPosId().equals(pos.getId())) {
String result = "-1";
okMsg = rfid + "[" + rfidLoc + "][" + barcode.getBarcode() + "]锁定库位[" + pos.getPosName() + "],清理旧有锁定信息";
resultMap.put("result", result);
resultMap.put("msg", okMsg);
//已经锁定过库位,但不是同一个条码,需要把对应位置的锁定信息清理掉
ReelLockPosUtil.removeReelLockPosInfo(oldLockInfo.getBarcode());
log.info("清理锁定库位:库位号[" + oldLockInfo.getLockPosName() + "]上物料[" + oldLockInfo.getBarcode() + "]锁定的库位");
}
}
log.info(okMsg + oldLockInfo);
ReelLockPosInfo reelLocInfo = new ReelLockPosInfo();
reelLocInfo.setBarcode(barcode.getBarcode());
reelLocInfo.setCid(theStorage.getCid());
reelLocInfo.setLockPosName(pos.getPosName());
reelLocInfo.setLockPosId(pos.getId());
reelLocInfo = ReelLockPosUtil.addReelLockPosInfo(reelLocInfo, findCidList);
if (reelLocInfo == null) {
errorMsg = "[" + barcode.getBarcode() + "]库位[" + reelLocInfo.getLockPosName() + "]已被锁定,暂停入库";
lineMsg = errorMsg;
DeviceMessageUtil.updateLineMsg(lineMsg, code, cids, reelLocInfo.getLockPosName(), "smfcore.linemsg.posLock", new String[]{barcode.getBarcode(), reelLocInfo.getLockPosName()});
resultMap.put("result", "99");
resultMap.put("msg", errorMsg);
return resultMap;
} else {
resultMap.put("pos", pos.getPosName());
resultMap.put("barcode", barcode.getBarcode());
resultMap.put("cid", theStorage.getCid());
}
} else {
resultMap.put("result", "104");
errorMsg = "[" + barcode.getBarcode() + "]未找到可用的[" + barcode.getPlateSize() + "x" + barcode.getHeight() + "]仓位";
resultMap.put("msg", errorMsg);
}
} catch (ValidateException ve) {
errorMsg = ve.getMessage();
errorMsg = MessageUtils.getText(ve.getMsgKey(), ve.getMsgParam(), MessageUtils.getDefaultLocal(), ve.getDefaultMsg());
log.info("查找空库位失败:" + errorMsg);
resultMap.put("result", "105");
resultMap.put("msg", errorMsg);
} catch (Exception e) {
errorMsg = e.getMessage();
log.info("查找空库位失败,", e);
resultMap.put("result", "105");
resultMap.put("msg", errorMsg);
}
}
}
//没入成功
if (!errorMsg.isEmpty()) {
//有错误,记录日志
AlarmInfo alarmInfo = new AlarmInfo();
alarmInfo.setBoxId("0");
alarmInfo.setStorageName("流水线");
alarmInfo.setInOutStatus("1");
alarmInfo.setAlarmType("入库");
Date date = new Date();
alarmInfo.setStartTime(date);
alarmInfo.setEndTime(date);
String msg = "[" + code + "]" + errorMsg;
alarmInfo.setAlarmMsg(msg);
alarmInfoDao.save(alarmInfo);
lineMsg = errorMsg;
DeviceMessageUtil.updateLineMsg(lineMsg, code, cids, "", "", null);
} else {
lineMsg = okMsg;
DeviceMessageUtil.lastLineMsg = null;
}
return resultMap;
}
@ApiOperation("获取需要移动的库位是否有料")
@RequestMapping("/needMovePosHasReel")
@ResponseBody
@AnonymousAccess
public ResultBean needMovePosHasReel(@RequestBody Map<String, String> paramMap) {
String checkOutPosName = paramMap.get("checkOutPosName");
String needMovePosName = paramMap.get("needMovePosName");
log.info("出库的库位为:" + checkOutPosName + ",需要移动的库位为:" + needMovePosName);
StoragePos checkOutPos = storagePosManager.getByPosName(checkOutPosName);
if (checkOutPos == null) {
return ResultBean.newErrorResult(-1, "smfcore.valueNotExist", "{0}[{1}]不存在", new String[]{"posName", checkOutPosName});
}
StoragePos needMovePos = storagePosManager.getByPosName(needMovePosName);
if (needMovePos == null) {
return ResultBean.newErrorResult(-1, "smfcore.valueNotExist", "{0}[{1}]不存在", new String[]{"posName", needMovePosName});
}
//如果barcode不为空,则提前锁定目标库位
boolean hasReel = true;
Barcode barcode = needMovePos.getBarcode();
String posName = "";
if (barcode != null) {
log.info("需要移动的库位" + needMovePosName + ",对应的barcode为:" + barcode.getBarcode() + ",尺寸为:" + barcode.getPlateSize() + "x" + barcode.getHeight());
//有料,先查找锁定的lockS库位,有的话返回
ReelLockPosInfo lockPosInfo = ReelLockPosUtil.getLockPosInfoByCode(getLockPosSKey(needMovePos.getStorageId()));
if (lockPosInfo != null && ObjectUtil.isNotEmpty(lockPosInfo.getLockPosName())) {
posName = lockPosInfo.getLockPosName();
log.info("查找到锁定的内侧库位为目标库位:" + posName + " ");
StoragePos pos = storagePosManager.getByPosName(posName);
if (pos != null) {
if (pos.getW() != needMovePos.getW() || pos.getH() != needMovePos.getH()) {
log.info(posName + "对应的w{},h{}与移动的宽{},高{}不一致,重新找", pos.getW(), pos.getH(), needMovePos.getW(), needMovePos.getH());
posName = "";
}
} else {
posName = "";
}
}
if (StringUtils.isEmpty(posName)) {
ReelLockPosUtil.removeReelLockPosInfo(getLockPosSKey(needMovePos.getStorageId()));
}
if (StringUtils.isEmpty(posName)) {
//查找一个库位号
StoragePos pos = null;
int loopCount = 0;
List<Storage> storageList = new ArrayList<>();
Storage storage = dataCache.getStorageById(needMovePos.getStorageId());
storageList.add(storage);
List<String> cidList = new ArrayList<>();
cidList.add(storage.getCid());
List<String> needRemoveLockPosId = new ArrayList<>();
while (pos == null) {
loopCount++;
if (loopCount >= 20) {
log.info(barcode.getBarcode() + "已循环查找20次 直接跳出循环");
break;
}
//优先找B结束的,如果没有再找F的
String endStr = "B";
if (loopCount >= 10) {
endStr = "F";
}
pos = taskService.dualPosNameFindEmptyPosForPutIn(storageList, barcode, "", "", needMovePosName, endStr);
if (pos == null) {
if ("F".equals(endStr)) {
} else {
endStr = "F";
pos = taskService.dualPosNameFindEmptyPosForPutIn(storageList, barcode, "", "", needMovePosName, endStr);
}
}
if (pos == null) {
log.info("需要移动的库位" + needMovePosName + "未找到对应的库位信息");
break;
}
//如果是以S结尾的,则判断不带S的有没有料
posName = pos.getPosName();
String wPosName = "";
if (posName.endsWith("B") || posName.endsWith("b")) {
log.info(posName + "以B结尾,需要判断外层有没有物料");
wPosName = posName.substring(0, posName.length() - 1);
wPosName = wPosName + "F";
StoragePos storagePos = storagePosManager.getByPosName(wPosName);
if (storagePos != null) {
if (storagePos.getBarcode() != null) {
log.info("查找到目标库位:" + pos.getPosName() + " 的外侧库位" + wPosName + "有物料信息,重新查找库位 ");
ReelLockPosInfo reelLocInfo = new ReelLockPosInfo();
reelLocInfo.setBarcode(pos.getId());
reelLocInfo.setCid(dataCache.getStorageById(pos.getStorageId()).getCid());
reelLocInfo.setLockPosName(pos.getPosName());
reelLocInfo.setLockPosId(pos.getId());
ReelLockPosUtil.addReelLockPosInfo(reelLocInfo, cidList);
needRemoveLockPosId.add(pos.getId());
pos = null;
posName = "";
} else {
log.info("查找到目标库位:" + pos.getPosName() + " 且外侧库位" + wPosName + "无料,锁定两个库位 :" + pos.getPosName() + "=" +
getLockPosSKey(needMovePos.getStorageId()) + ",wPosName=" + getLockPosKey(needMovePos.getStorageId()));
//是内侧库位,且外侧库位也无料,锁定两个库位
AddLock(pos, getLockPosSKey(needMovePos.getStorageId()), cidList);
AddLock(storagePos, getLockPosKey(needMovePos.getStorageId()), cidList);
//如果外侧有任务,则改成新库位一样的
DataLog dataLog = null;
for (DataLog queueTask : taskService.getQueueTasks()) {
if (barcode.getBarcode().equals(queueTask)) {
dataLog = queueTask;
break;
}
}
if (dataLog != null) {
log.info("posName:[{}],barcode为[{}]有任务,需要重新设置任务库位:[{}]", dataLog.getPosName(), barcode.getBarcode(), pos.getPosName());
dataLog.setPosName(pos.getPosName());
dataLog.setPosId(pos.getId());
if (dataLog.isExecuting() || dataLog.isWait()) {
dataLog.setStatus(OP_STATUS.WAIT.name());
taskService.updateQueueTask(dataLog);
} else {
taskService.updateFinishedTask(dataLog);
}
}
}
}
} else {
//是外侧库位,直接锁定外侧库位
log.info("查找到外侧库位作为目标库位,锁定库位 :" + pos.getPosName() + "=" + getLockPosKey(needMovePos.getStorageId()));
AddLock(pos, getLockPosKey(needMovePos.getStorageId()), cidList);
//如果外侧有任务,则改成新库位一样的
DataLog dataLog = null;
for (DataLog queueTask : taskService.getQueueTasks()) {
if (barcode.getBarcode().equals(queueTask)) {
dataLog = queueTask;
break;
}
}
if (dataLog != null) {
log.info("posName:[{}],barcode为[{}]有任务,需要重新设置任务库位:[{}]", dataLog.getPosName(), barcode.getBarcode(), pos.getPosName());
dataLog.setPosName(pos.getPosName());
dataLog.setPosId(pos.getId());
if (dataLog.isExecuting() || dataLog.isWait()) {
dataLog.setStatus(OP_STATUS.WAIT.name());
taskService.updateQueueTask(dataLog);
} else {
taskService.updateFinishedTask(dataLog);
}
}
}
}
//判断有没有锁定的异常库位
if (needRemoveLockPosId != null && !needRemoveLockPosId.isEmpty()) {
for (String posId : needRemoveLockPosId) {
ReelLockPosUtil.removeReelLockPosInfo(posId);
}
}
}
} else {
hasReel = false;
}
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("hasReel", hasReel);
if (hasReel) {
resultMap.put("barcode", barcode.getBarcode());
resultMap.put("partNumber", barcode.getPartNumber());
if (ObjectUtil.isEmpty(posName)) {
return ResultBean.newErrorResult(-1, "smfcore.shelf.msg.inError", "未找到适合[{0}]的库位", new String[]{needMovePosName});
} else {
resultMap.put("posName", posName);
}
}
return ResultBean.newOkResult(resultMap);
}
@ApiOperation("移动物料到另外一个库位")
@RequestMapping("/moveToOtherPos")
@ResponseBody
@AnonymousAccess
public ResultBean moveToOtherPos(@RequestBody Map<String, String> paramMap) {
String needMovePosName = paramMap.get("needMovePosName"); //需要移动的库位
String targetPosName = paramMap.get("targetPosName"); //目标库位
log.info("需要移动的库位为:" + needMovePosName + ",目标库位为:" + targetPosName);
//判断目标库位是否存在
StoragePos targetPos = storagePosManager.getByPosName(targetPosName);
if (targetPos == null) {
return ResultBean.newErrorResult(-1, "smfcore.valueNotExist", "{0}[{1}]不存在", new String[]{"posName", targetPosName});
}
Barcode targetBarcode = targetPos.getBarcode();
//判断有没有物料
StoragePos needMovePos = storagePosManager.getByPosName(needMovePosName);
Barcode barcode = needMovePos.getBarcode();
//如果目标库位不为空,当前库位为空,直接返回ok
if (barcode == null) {
if (targetBarcode == null) {
return ResultBean.newErrorResult(-1, "smfcore.valueNotExist", "{0}[{1}]不存在", new String[]{needMovePosName, "barcode"});
} else {
return ResultBean.newOkResult("");
}
}
//把外侧相同的任务给改成内侧的
List<DataLog> allTasks = taskService.getAllTasks();
for (DataLog dataLog : allTasks) {
if (dataLog.isCheckOutTask()) {
if (!dataLog.isFinished() && !dataLog.isCancel()) {
if (dataLog.getPosId().equals(needMovePos.getId())) {
dataLog.setPosId(targetPos.getId());
dataLog.setPosName(targetPos.getPosName());
taskService.updateQueueTask(dataLog);
log.info(dataLog.getBarcode() + ":外测有任务,原始库位为:" + dataLog.getPosName() + "更改后的库位为:" + targetPos.getPosName());
break;
}
}
}
}
//生成一条出库任务
Storage storage = dataCache.getStorageById(needMovePos.getStorageId());
DataLog needMovePosTask = new DataLog(storage, barcode, needMovePos);
needMovePosTask.setOperator("admin-move");
needMovePosTask.setType(OP.CHECKOUT);
needMovePosTask.setStatus(OP_STATUS.FINISHED.name());
taskService.updateFinishedTask(needMovePosTask);
needMovePos.setBarcode(null);
needMovePos.setUsed(false);
storagePosManager.save(needMovePos);
log.info(barcode.getBarcode() + "转移库位,清空仓位: " + needMovePos.getId() + "[" + needMovePos.getPosName() + "]");
dataCache.updateInventory(needMovePos, barcode);
//重新设置barcode的库位
barcode.setPosName(targetPos.getPosName());
barcodeManager.save(barcode);
//生成一条入库任务
DataLog targetPosTask = new DataLog(storage, barcode, targetPos);
targetPosTask.setOperator("admin-move");
targetPosTask.setType(OP.PUT_IN);
targetPosTask.setStatus(OP_STATUS.FINISHED.name());
taskService.updateFinishedTask(targetPosTask);
targetPos.setBarcode(barcode);
targetPos.setUsed(true);
targetPos.setCanCheckOutTime(System.currentTimeMillis());
storagePosManager.save(targetPos);
log.info(barcode.getBarcode() + "转移库位,入库库位: " + targetPos.getId() + "[" + targetPos.getPosName() + "]");
dataCache.updateInventory(targetPos, barcode);
//解除库位绑定
ReelLockPosUtil.removeReelLockPosInfo(barcode.getBarcode());
ReelLockPosInfo lockS = ReelLockPosUtil.getLockPosInfoByCode(getLockPosSKey(needMovePos.getStorageId()));
if (lockS != null && ObjectUtil.isNotEmpty(lockS.getLockPosName()) && lockS.getLockPosName().equals(targetPosName)) {
ReelLockPosUtil.removeReelLockPosInfo(getLockPosSKey(needMovePos.getStorageId()));
} else {
ReelLockPosInfo lock = ReelLockPosUtil.getLockPosInfoByCode(getLockPosKey(needMovePos.getStorageId()));
if (lock != null && ObjectUtil.isNotEmpty(lock.getLockPosName()) && lock.getLockPosName().equals(targetPosName)) {
ReelLockPosUtil.removeReelLockPosInfo(getLockPosKey(needMovePos.getStorageId()));
lock = null;
}
if (lock == null) {
if (needMovePosName.endsWith("F") || needMovePosName.endsWith("f")) {
log.info("需要移动的库位为:" + needMovePosName + "是内侧库位,不需要锁定库位");
} else {
needMovePosName = needMovePosName.substring(0, needMovePosName.length() - 1);
String sPosname = needMovePosName + "B";
StoragePos sPos = storagePosManager.getByPosName(sPosname);
if (sPos != null) {
String cid = dataCache.getStorageById(sPos.getStorageId()).getCid();
List<String> cidList = new ArrayList<>();
cidList.add(cid);
//如果两个库位锁定都为空了,将当前库位锁定为缓存库位
log.info("重新锁定两个缓存库位 :" + sPos.getPosName() + "=" + getLockPosSKey(needMovePos.getStorageId()) + "," + needMovePos.getPosName() + "=" + getLockPosKey(needMovePos.getStorageId()));
//是内侧库位,且外侧库位也无料,锁定两个库位
AddLock(sPos, getLockPosSKey(needMovePos.getStorageId()), cidList);
AddLock(needMovePos, getLockPosKey(needMovePos.getStorageId()), cidList);
}
}
}
}
return ResultBean.newOkResult("");
}
public Barcode resolveBarcodeFromApi(CodeValidateParam params) {
Barcode barcodeSave = smfApi.canPutInBeforeResolve(params);
if (barcodeSave == null) {
barcodeSave = codeResolve.resolveOneValideBarcode(params.getCode());
}
//从API验证
Barcode barcodeFromApi = smfApi.canPutInAfterResolve(params, barcodeSave);
if (barcodeFromApi != null) {
barcodeSave = barcodeFromApi;
}
return barcodeSave;
}
private void AddLock(StoragePos pos, String key, List<String> cidList) {
ReelLockPosInfo lockS = new ReelLockPosInfo();
lockS.setBarcode(key);
lockS.setCid(dataCache.getStorageById(pos.getStorageId()).getCid());
lockS.setLockPosName(pos.getPosName());
lockS.setLockPosId(pos.getId());
ReelLockPosUtil.addReelLockPosInfo(lockS, cidList);
}
private String getLockPosSKey(String storageId) {
return Constants.XLR_lockPosS + "_" + storageId;
}
private String getLockPosKey(String storageId) {
return Constants.XLR_lockPos + "_" + storageId;
}
}
...@@ -100,4 +100,8 @@ public interface IStoragePosManager extends IBaseManager<StoragePos> { ...@@ -100,4 +100,8 @@ public interface IStoragePosManager extends IBaseManager<StoragePos> {
List<StoragePos> findPosListByPartNumber(List<String> storageIdList, String pn, Collection<String> excludePosIds, CHECKOUT_TYPE checkOutType,Map<String,String> appendData); List<StoragePos> findPosListByPartNumber(List<String> storageIdList, String pn, Collection<String> excludePosIds, CHECKOUT_TYPE checkOutType,Map<String,String> appendData);
List<StoragePos> findPosListByMpn(List<String> availableStorageIds, String mpn, Collection<String> excludePosIds, CHECKOUT_TYPE checkoutType, Map<String, String> appendDate); List<StoragePos> findPosListByMpn(List<String> availableStorageIds, String mpn, Collection<String> excludePosIds, CHECKOUT_TYPE checkoutType, Map<String, String> appendDate);
int getRemainPosCountByStorage(Storage storage, Barcode barcode, Collection<String> excludePosIds, String lastPosId, String endStr) throws ValidateException;
StoragePos dualPosNameGetEmptyPosByStorage(Storage storage, Barcode barcode, Collection<String> excludePosIds,String lastPosId,String needMovePosName,String endStr,List<String> needExcludePosNameList) throws ValidateException;
} }
...@@ -1033,4 +1033,95 @@ public class StoragePosManagerImpl implements IStoragePosManager { ...@@ -1033,4 +1033,95 @@ public class StoragePosManagerImpl implements IStoragePosManager {
q.with(sort); q.with(sort);
return storagePosDao.findByQuery(q); return storagePosDao.findByQuery(q);
} }
@Override
public int getRemainPosCountByStorage(Storage storage, Barcode barcode, Collection<String> excludePosIds, String lastPosId, String endStr) throws ValidateException {
Criteria c = Criteria.where("storageId").is(storage.getId());
COMPATIBLE_TYPE compatibleType = storage.getCompatibleType();
if (compatibleType == COMPATIBLE_TYPE.EXACT_MATCH) {//完全匹配
c = c.and("w").is(barcode.getPlateSize()).and("h").is(barcode.getHeight());
} else if (compatibleType == COMPATIBLE_TYPE.FULLY_COMPATIBLE) {//同厚度兼容
c = c.and("w").gte(barcode.getPlateSize()).and("h").gte(barcode.getHeight());//除7寸外,完全兼容
} else if (compatibleType == COMPATIBLE_TYPE.SIZE_COMPATIBLE) {//同尺寸兼容
c = c.and("w").is(barcode.getPlateSize()).and("h").gte(barcode.getHeight());//宽度等于料盘宽度,高度大于等于料盘高度
}
c = c.and("enabled").is(true)//可用
.and("used").is(false);//未使用
//去除的仓位
if (excludePosIds != null && !excludePosIds.isEmpty()) {
c = c.and("id").nin(excludePosIds);
}
if (StringUtils.isNotEmpty(endStr)) {
String regex = "" + endStr + "$";
c.and("posName").regex(Pattern.compile(regex));
}
Query query = new Query(c);
query.with(Sort.by(Sort.Direction.ASC, "w").and(Sort.by(Sort.Direction.ASC, "h")).and(Sort.by(Sort.Direction.DESC, "priority")));
return storagePosDao.countByQuery(query);
}
private static boolean max = true;
@Override
public StoragePos dualPosNameGetEmptyPosByStorage(Storage storage, Barcode barcode, Collection<String> excludePosIds,String lastPosId,String needMovePosName,String endStr,List<String> needExcludePosNameList) throws ValidateException {
Criteria c = Criteria.where("storageId").is(storage.getId());
COMPATIBLE_TYPE compatibleType = storage.getCompatibleType();
if (compatibleType == COMPATIBLE_TYPE.EXACT_MATCH) {//完全匹配
c = c.and("w").is(barcode.getPlateSize()).and("h").is(barcode.getHeight());
} else if (compatibleType == COMPATIBLE_TYPE.FULLY_COMPATIBLE) {//同厚度兼容
c = c.and("w").gte(barcode.getPlateSize()).and("h").gte(barcode.getHeight());//除7寸外,完全兼容
} else if (compatibleType == COMPATIBLE_TYPE.SIZE_COMPATIBLE) {//同尺寸兼容
c = c.and("w").is(barcode.getPlateSize()).and("h").gte(barcode.getHeight());//宽度等于料盘宽度,高度大于等于料盘高度
}
c = c.and("enabled").is(true)//可用
.and("used").is(false);//未使用
//去除的仓位
if (excludePosIds != null && !excludePosIds.isEmpty()) {
c = c.and("id").nin(excludePosIds);
}
if (StringUtils.isNotEmpty(needMovePosName) && StringUtils.isNotEmpty(endStr)) {
Criteria posNameCriteria = new Criteria();
String regex = ""+endStr+"$";
posNameCriteria.andOperator(Criteria.where("posName").ne(needMovePosName), Criteria.where("posName").regex(Pattern.compile(regex)));
c.andOperator(posNameCriteria);
}
if (needExcludePosNameList != null && !needExcludePosNameList.isEmpty()){
c.and("posName").nin(needExcludePosNameList);
}
Query query = new Query(c);
String msg = "";
// if (lastPosId == null || lastPosId.equals("")) {
//优先放入最合适的位置(根据尺寸),相同尺寸按优先级排序
if (max){
query.with(Sort.by(Sort.Direction.ASC, "w").and(Sort.by(Sort.Direction.ASC, "h")).and(Sort.by(Sort.Direction.DESC, "priority")));
max = true;
} else {
query.with(Sort.by(Sort.Direction.ASC, "w").and(Sort.by(Sort.Direction.ASC, "h")).and(Sort.by(Sort.Direction.ASC, "priority")));
max = false;
}
StoragePos pos = storagePosDao.findOne(query);
if ((!ObjectUtil.isNotEmpty(msg) )&& (pos != null)) {
Point targetP = PointUtil.getPosPoint(lastPosId, false);
log.debug(msg + "结果:[" + pos.getPosName() + "][" + targetP.getX() + "," + targetP.getY() + "]");
}
return pos;
}
} }
...@@ -1448,4 +1448,169 @@ public class TaskService { ...@@ -1448,4 +1448,169 @@ public class TaskService {
} }
} }
} }
public StoragePos dualPosNameFindEmptyPosForPutIn(List<Storage> storageList, Barcode barcode, String inRFID, String lastPosId,String needMovePosName,String endStr) throws ValidateException {
verifyBarcodePutIn(storageList, barcode, inRFID);
List<String> storageIds=new ArrayList<>();
//查找任务数最少的料仓
final Map<String, Integer> storageTaskCountMap = new HashMap<>();
for (Storage storage : storageList) {
storageTaskCountMap.put(storage.getId(), 0);
storageIds.add(storage.getId());
}
Set<String> hasOutTaskStorageIds = new HashSet<>();
//如果有正在执行的任务,把库位发过去
Collection<DataLog> allTasks = taskMap.values();
for (DataLog task : allTasks) {
if (barcode.getBarcode().equals(task.getBarcode())) {
String posId = task.getPosId();
log.info(barcode.getBarcode() + " 已有任务,返回任务中的库位:" + task.getPosName());
return storagePosManager.get(posId);
}
String storageId = task.getStorageId();
if (!Strings.isNullOrEmpty(storageId)) {
Integer taskCount = storageTaskCountMap.get(storageId);
if (taskCount != null) {
taskCount = taskCount + 1;
storageTaskCountMap.put(storageId, taskCount);
}
if (task.isCheckOutTask()) {
hasOutTaskStorageIds.add(storageId);
}
}
}
String lockPosId = ReelLockPosUtil.getReelLockPosId(barcode.getBarcode());
StoragePos pos = null;
if (!Strings.isNullOrEmpty(lockPosId)) {
//已有锁定库位
pos = storagePosManager.get(lockPosId);
if (pos != null) {
if(!storageIds.contains(pos.getStorageId())){
log.info("条码[" + barcode.getBarcode() + "]已有锁定库位[" + pos.getPosName() + "],料仓ID["+pos.getStorageId()+"]不在请求列表["+String.join(",",storageIds)+"]中,重新查找库位");
pos = null;
}
else if (pos.getW() != barcode.getPlateSize() || pos.getH() != barcode.getHeight()) {
log.info("条码[" + barcode.getBarcode() + "]尺寸已改变,无法放入已锁定库位[" + pos.getPosName() + "],重新查找库位");
pos = null;
} else {
Barcode posBarcode = pos.getBarcode();
if (posBarcode == null) {
log.info("条码[" + barcode.getBarcode() + "]已锁定库位[" + pos.getPosName() + "],返回锁定中的库位");
} else {
log.info("条码[" + barcode.getBarcode() + "]已锁定库位[" + pos.getPosName() + "]中已有物料[" + posBarcode.getBarcode() + "],重新查找库位");
pos = null;
}
}
}
}
if (pos != null) {
return pos;
}
//可用的料仓(在线,且可以放入)
List<Storage> availbleStorageList = new ArrayList<>();
for (Storage storage : storageList) {
if (storage.canPutIn(barcode.getPlateSize(), barcode.getHeight())) {
availbleStorageList.add(storage);
}
}
if (availbleStorageList.isEmpty()) {
throw new ValidateException("smfcore.noValidStorage", "[{0}]料仓列表中未找到可用的料仓",new String[]{barcode.getBarcode()});
}
availbleStorageList.sort(new Comparator<Storage>() {
@Override
public int compare(Storage o1, Storage o2) {
Integer taskCount1 = storageTaskCountMap.get(o1.getId());
Integer taskCount2 = storageTaskCountMap.get(o2.getId());
return taskCount1.compareTo(taskCount2);
}
});
return dualPosNameFindEmptyPosInStorages(barcode, availbleStorageList, hasOutTaskStorageIds, lastPosId,needMovePosName,endStr);
}
private synchronized StoragePos dualPosNameFindEmptyPosInStorages(Barcode barcode, List<Storage> availbleStorageList, final Set<String> hasOutTaskStorageIds, String lastPosId,String needMovePosName,String endStr) {
List<String> needExcludePosName = new ArrayList<>();
//新增外侧有料,里侧没料,排除里侧的库位信息
List<StoragePos> allUsePosList = new ArrayList<>();
for (Storage storage : availbleStorageList) {
Map<String, StoragePos> usedPosList = dataCache.getUsedPosList(storage.getCid());
for (StoragePos pos : usedPosList.values()) {
allUsePosList.add(pos);
}
}
for (StoragePos pos : allUsePosList) {
String posName = pos.getPosName();
if (posName.endsWith("_F")) {
boolean hasEndBPos = false;
String posName_B = posName.substring(0, posName.length() - 1) + "B";
for (StoragePos usePos : allUsePosList) {
if (posName_B.equals(usePos.getPosName())) {
hasEndBPos = true;
break;
}
}
if (!hasEndBPos) {
needExcludePosName.add(posName_B);
}
}
}
//第一遍查找,先不查找有出库任务的料仓
for (Storage storage : availbleStorageList) {
if(!storage.isSmdDuo()){//DUO料仓无论是否有出库任务,都可以查找空库位
if(hasOutTaskStorageIds.contains(storage.getId())){
continue;
}
}
try {
Collection<String> operatingPosIds = excludePosIds();
log.debug("尝试从[" + storage.getCid() + "]中为[" + barcode.getBarcode() + "]查找空位");
StoragePos pos = storagePosManager.dualPosNameGetEmptyPosByStorage(storage, barcode, operatingPosIds, lastPosId,needMovePosName,endStr,needExcludePosName);
if (pos != null) {
return pos;
}
} catch (Exception e) {
log.error("尝试从[" + storage.getCid() + "]中为[" + barcode.getBarcode() + "]查找空位失败:" + e.getMessage());
}
}
//第二遍查找,从所有料仓中查找
for (Storage storage : availbleStorageList) {
try {
Collection<String> operatingPosIds = excludePosIds();
log.debug("尝试从[" + storage.getCid() + "]中为[" + barcode.getBarcode() + "]查找空位");
StoragePos pos = storagePosManager.dualPosNameGetEmptyPosByStorage(storage, barcode, operatingPosIds, lastPosId,needMovePosName,endStr,needExcludePosName);
if (pos != null) {
return pos;
}
} catch (Exception e) {
log.error("尝试从[" + storage.getCid() + "]中为[" + barcode.getBarcode() + "]查找空位失败:" + e.getMessage());
}
}
try {
String cids = "";
for (Storage storage : availbleStorageList) {
cids = cids + storage.getCid() + ",";
}
log.info(barcode.getBarcode() + " 未找到可用库位,可用料仓:" + cids);
} catch (Exception e) {
log.error("打印可用料仓出错", e);
}
return null;
}
} }
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!