Commit 9c5e4fc6 LN

Merge remote-tracking branch 'origin/master'

2 个父辈 4ece61d5 4b69d55c
...@@ -99,7 +99,18 @@ public class DateUtil { ...@@ -99,7 +99,18 @@ public class DateUtil {
} catch (Exception pe) { } catch (Exception pe) {
log.error("Parse ["+strDate+"] to date Exception: " + pe.getMessage()); log.error("Parse ["+strDate+"] to date Exception: " + pe.getMessage());
//throw new ParseException(pe.getMessage(), pe.getErrorOffset()); //throw new ParseException(pe.getMessage(), pe.getErrorOffset());
return null; date = null;
}
if (date == null){
try {
df.setLenient(true);
date = df.parse(strDate);
} catch (Exception pe) {
log.error("Parse ["+strDate+"] to date Exception: " + pe.getMessage());
//throw new ParseException(pe.getMessage(), pe.getErrorOffset());
return null;
}
} }
return (date); return (date);
......
...@@ -672,6 +672,7 @@ public class BarcodeRule { ...@@ -672,6 +672,7 @@ public class BarcodeRule {
b.setMemo(memo); b.setMemo(memo);
} }
reelId = reelId.trim();
b.setBarcode(reelId); b.setBarcode(reelId);
codeBean.setCodeStr(reelId); codeBean.setCodeStr(reelId);
partNumber = partNumber.trim(); partNumber = partNumber.trim();
......
...@@ -65,8 +65,9 @@ public class ComponentManagerImpl implements IComponentManager { ...@@ -65,8 +65,9 @@ public class ComponentManagerImpl implements IComponentManager {
@Override @Override
public Component findByPartNumberAndProvider(String partNumber, String provider) { public Component findByPartNumberAndProvider(String partNumber, String provider) {
if (StringUtils.isEmpty(partNumber)) if (StringUtils.isEmpty(partNumber)) {
return null; return null;
}
else { else {
Component component = componentDao.findOneByCondition(new String[]{"partNumber", "provider"}, new String[]{partNumber, provider}); Component component = componentDao.findOneByCondition(new String[]{"partNumber", "provider"}, new String[]{partNumber, provider});
if (component == null) { if (component == null) {
......
...@@ -11,6 +11,9 @@ import com.neotel.smfcore.core.barcode.service.po.Barcode; ...@@ -11,6 +11,9 @@ import com.neotel.smfcore.core.barcode.service.po.Barcode;
import com.neotel.smfcore.core.device.bean.StatusBean; import com.neotel.smfcore.core.device.bean.StatusBean;
import com.neotel.smfcore.core.device.enums.OP; import com.neotel.smfcore.core.device.enums.OP;
import com.neotel.smfcore.core.device.enums.OP_STATUS; import com.neotel.smfcore.core.device.enums.OP_STATUS;
import com.neotel.smfcore.core.message.enums.MessageType;
import com.neotel.smfcore.core.message.service.manager.IMessageManager;
import com.neotel.smfcore.core.message.service.po.Message;
import com.neotel.smfcore.core.order.enums.ORDER_COLOR; import com.neotel.smfcore.core.order.enums.ORDER_COLOR;
import com.neotel.smfcore.core.storage.enums.DeviceType; import com.neotel.smfcore.core.storage.enums.DeviceType;
import com.neotel.smfcore.core.storage.service.po.Storage; import com.neotel.smfcore.core.storage.service.po.Storage;
...@@ -18,9 +21,6 @@ import com.neotel.smfcore.core.storage.service.po.StoragePos; ...@@ -18,9 +21,6 @@ import com.neotel.smfcore.core.storage.service.po.StoragePos;
import com.neotel.smfcore.core.system.bean.OrderSetting; import com.neotel.smfcore.core.system.bean.OrderSetting;
import com.neotel.smfcore.core.system.service.po.DataLog; import com.neotel.smfcore.core.system.service.po.DataLog;
import com.neotel.smfcore.core.system.util.DevicesStatusUtil; import com.neotel.smfcore.core.system.util.DevicesStatusUtil;
import com.neotel.smfcore.core.system.websocket.MsgType;
import com.neotel.smfcore.core.system.websocket.SocketMsg;
import com.neotel.smfcore.core.system.websocket.WebSocketServer;
import com.neotel.smfcore.security.TokenProvider; import com.neotel.smfcore.security.TokenProvider;
import com.neotel.smfcore.security.annotation.AnonymousAccess; import com.neotel.smfcore.security.annotation.AnonymousAccess;
import com.neotel.smfcore.security.service.manager.IUserManager; import com.neotel.smfcore.security.service.manager.IUserManager;
...@@ -48,6 +48,9 @@ public class NLPShelfHandler extends BaseDeviceHandler { ...@@ -48,6 +48,9 @@ public class NLPShelfHandler extends BaseDeviceHandler {
@Autowired @Autowired
private IUserManager userManager; private IUserManager userManager;
@Autowired
private IMessageManager messageManager;
/** /**
* 扫码 * 扫码
*/ */
...@@ -327,11 +330,24 @@ public class NLPShelfHandler extends BaseDeviceHandler { ...@@ -327,11 +330,24 @@ public class NLPShelfHandler extends BaseDeviceHandler {
} }
} }
//先获取到上一次缓存的信息
List<List<String>> lastDeviceData = DevicesStatusUtil.getDeviceData(cid);
List<String> lastHasReelPosErrorList = new ArrayList<>();
List<String> lastNoReelPosErrorList = new ArrayList<>();
if (lastDeviceData != null && lastDeviceData.size() == 2){
lastHasReelPosErrorList = lastDeviceData.get(0);
lastNoReelPosErrorList = lastDeviceData.get(1);
}
List<List<String>> data = new ArrayList<>(); List<List<String>> data = new ArrayList<>();
data.add(Arrays.asList(hasReelPosErrorList)); data.add(Arrays.asList(hasReelPosErrorList));
data.add(Arrays.asList(noReelPosErrorList)); data.add(Arrays.asList(noReelPosErrorList));
DevicesStatusUtil.updateDeviceData(cid, data); DevicesStatusUtil.updateDeviceData(cid, data);
//在这里进行对比
compareErrorDataWithMessage(cid, lastHasReelPosErrorList, lastNoReelPosErrorList, data.get(0), data.get(1));
List<String> inOkList = new ArrayList<>(); List<String> inOkList = new ArrayList<>();
List<String> inNgList = new ArrayList<>(); List<String> inNgList = new ArrayList<>();
List<String> outOkList = new ArrayList<>(); List<String> outOkList = new ArrayList<>();
...@@ -574,6 +590,95 @@ public class NLPShelfHandler extends BaseDeviceHandler { ...@@ -574,6 +590,95 @@ public class NLPShelfHandler extends BaseDeviceHandler {
return ResultBean.newOkResult(posList); return ResultBean.newOkResult(posList);
} }
private void compareErrorDataWithMessage(String cid,
List<String> lastHasReelPosErrorList, List<String> lastNoReelPosErrorList,
List<String> currentHasReelPosErrorList, List<String> currentNoReelPosErrorList) {
Storage storage = dataCache.getStorage(cid);
// 处理空值
if (lastHasReelPosErrorList == null) lastHasReelPosErrorList = new ArrayList<>();
if (lastNoReelPosErrorList == null) lastNoReelPosErrorList = new ArrayList<>();
if (currentHasReelPosErrorList == null) currentHasReelPosErrorList = new ArrayList<>();
if (currentNoReelPosErrorList == null) currentNoReelPosErrorList = new ArrayList<>();
// 对比有料异常数据
List<String> hasNewErrors = new ArrayList<>();
List<String> hasRecoveredErrors = new ArrayList<>();
List<String> hasPersistentErrors = new ArrayList<>();
for (String item : currentHasReelPosErrorList) {
if (!lastHasReelPosErrorList.contains(item)) {
hasNewErrors.add(item);
} else {
hasPersistentErrors.add(item);
}
}
for (String item : lastHasReelPosErrorList) {
if (!currentHasReelPosErrorList.contains(item)) {
hasRecoveredErrors.add(item);
}
}
// 对比无料异常数据
List<String> noNewErrors = new ArrayList<>();
List<String> noRecoveredErrors = new ArrayList<>();
List<String> noPersistentErrors = new ArrayList<>();
for (String item : currentNoReelPosErrorList) {
if (!lastNoReelPosErrorList.contains(item)) {
noNewErrors.add(item);
} else {
noPersistentErrors.add(item);
}
}
for (String item : lastNoReelPosErrorList) {
if (!currentNoReelPosErrorList.contains(item)) {
noRecoveredErrors.add(item);
}
}
// 打印有料异常日志
if (!hasNewErrors.isEmpty()) {
log.warn("料架[{}] 有料异常(实际有料但数据库无信息) 新增异常库位: {}", cid, String.join(", ", hasNewErrors));
//smfcode.nlp.posHasReelError=库位[{0}]检测到有物料,但系统无库存记录
for (String hasNewError : hasNewErrors) {
Message message = Message.newMsg(MessageType.ERROR.name(), storage.getName(), storage.getId(), hasNewError, "smfcode.nlp.posHasReelError", "库位[{0}]检测到有物料,但系统无库存记录", new String[]{hasNewError});
messageManager.save(message);
}
}
if (!hasRecoveredErrors.isEmpty()) {
log.info("料架[{}] 有料异常(实际有料但数据库无信息) 恢复正常库位: {}", cid, String.join(", ", hasRecoveredErrors));
for (String hasRecoveredError : hasRecoveredErrors) {
//smfcode.nlp.posRecovered=库位[{0}]恢复正常
Message message = Message.newMsg(MessageType.INFO.name(), storage.getName(), storage.getId(), hasRecoveredError, "smfcode.nlp.posRecovered", "库位[{0}]恢复正常", new String[]{hasRecoveredError});
messageManager.save(message);
}
}
if (!hasPersistentErrors.isEmpty()) {
//log.error("⚠️ 料架[{}] 有料异常(实际有料但数据库无信息) 持续异常库位: {}", cid, String.join(", ", hasPersistentErrors));
}
// 打印无料异常日志
if (!noNewErrors.isEmpty()) {
log.warn("料架[{}] 无料异常(实际无料但数据库有信息) 新增异常库位: {}", cid, String.join(", ", noNewErrors));
for (String noNewError : noNewErrors) {
//smfcode.nlp.posNoReelError=库位[{0}]检测到没有物料,但系统有库存记录
Message message = Message.newMsg(MessageType.ERROR.name(), storage.getName(), storage.getId(), noNewError, "smfcode.nlp.posNoReelError", "库位[{0}]检测到没有物料,但系统有库存记录", new String[]{noNewError});
messageManager.save(message);
}
}
if (!noRecoveredErrors.isEmpty()) {
log.info("料架[{}] 无料异常(实际无料但数据库有信息) 恢复正常库位: {}", cid, String.join(", ", noRecoveredErrors));
for (String noRecoveredError : noRecoveredErrors) {
//smfcode.nlp.posRecovered=库位[{0}]恢复正常
Message message = Message.newMsg(MessageType.INFO.name(), storage.getName(), storage.getId(), noRecoveredError, "smfcode.nlp.posRecovered", "库位[{0}]恢复正常", new String[]{noRecoveredError});
messageManager.save(message);
}
}
if (!noPersistentErrors.isEmpty()) {
//log.error("⚠️ 料架[{}] 无料异常(实际无料但数据库有信息) 持续异常库位: {}", cid, String.join(", ", noPersistentErrors));
}
}
@Override @Override
public DeviceType getDeviceType() { public DeviceType getDeviceType() {
return DeviceType.NLP; return DeviceType.NLP;
......
package com.neotel.smfcore.core.device.handler.impl;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.base.Strings;
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.DateUtil;
import com.neotel.smfcore.common.utils.ReelLockPosUtil;
import com.neotel.smfcore.common.utils.SecurityUtils;
import com.neotel.smfcore.common.utils.StringUtils;
import com.neotel.smfcore.core.api.bean.CodeValidateParam;
import com.neotel.smfcore.core.barcode.service.po.Barcode;
import com.neotel.smfcore.core.barcode.service.po.Component;
import com.neotel.smfcore.core.barcode.utils.CodeResolve;
import com.neotel.smfcore.core.device.bean.NLShelfOperateBean;
import com.neotel.smfcore.core.device.bean.StatusBean;
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.inList.util.InListCache;
import com.neotel.smfcore.core.language.util.MessageUtils;
import com.neotel.smfcore.core.order.enums.ORDER_COLOR;
import com.neotel.smfcore.core.order.service.manager.ILiteOrderManager;
import com.neotel.smfcore.core.order.service.po.LiteOrder;
import com.neotel.smfcore.core.storage.enums.DeviceType;
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.bean.OrderSetting;
import com.neotel.smfcore.core.system.service.po.DataLog;
import com.neotel.smfcore.core.system.util.DevicesStatusUtil;
import com.neotel.smfcore.core.system.util.TaskService;
import com.neotel.smfcore.security.TokenProvider;
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.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Api(tags = "尾料仓")
@RestController
@Slf4j
@RequestMapping("/tailingMaterialBox")
public class TailingMaterialBoxHandler extends BaseDeviceHandler {
private final String putInColor = "green";
private final String expiredColor = "red";
@Autowired
private CodeResolve codeResolve;
@Autowired
private IStoragePosManager storagePosManager;
@Autowired
private DataCache dataCache;
@Autowired
private TaskService taskService;
private Map<String,String> expirePosMap= new ConcurrentHashMap<>();
// 创建定时任务执行器
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
@PostConstruct
public void init() {
scheduler.scheduleAtFixedRate(() -> {
for (Storage storage : dataCache.getAllStorage().values()) {
if (storage.getType().equals(DeviceType.TAILING_MATERIAL.getName())) {
//只查询posName和barcode.expireTime的时间
Query query = new Query(Criteria.where("storageId").is(storage.getId()));
query.fields().include("posName", "barcode.subCodeList.expireDate", "barcode.subCodeList.barcode", "storageId");
List<StoragePos> storagePosList = storagePosManager.findByQuery(query);
if (storagePosList != null && !storagePosList.isEmpty()) {
for (StoragePos pos : storagePosList) {
Barcode posBarcode = pos.getBarcode();
if (posBarcode != null) {
List<Barcode> subCodeList = posBarcode.getSubCodeList();
if (subCodeList != null && !subCodeList.isEmpty()) {
for (Barcode subCode : subCodeList) {
if (subCode.isExpired()) {
log.info("加载到过期物料的库位:"+pos.getPosName()+"需要亮红灯");
expirePosMap.put(pos.getPosName(),storage.getCid());
break;
}
}
}
}
}
}
}
}
}, 1, 5, TimeUnit.MINUTES);
}
@ApiOperation("寻找柜体")
@RequestMapping("/findPosByCode")
@AnonymousAccess
public ResultBean findPosByCode(@RequestBody Map<String, String> paramMap) {
String id = paramMap.get("id");
String code = paramMap.get("code");
log.info("入库寻找有料的柜体,条码信息为:" + code);
Barcode codeBarcode = codeResolve.resolveOneValideBarcode("=2x2=" + code);
List<StoragePos> storagePosList = getStoragePosListByPn(codeBarcode.getPartNumber(), id);
if (storagePosList == null || storagePosList.isEmpty()) {
Storage storage = dataCache.getStorageById(id);
StoragePos pos = storagePosManager.getEmptyPosByStorage(storage, codeBarcode, taskService.excludePosIds());
if (pos == null) {
return ResultBean.newErrorResult(-1, "smfcore.tailingmaterial.noPos", "未找到可用的柜体");
}
storagePosList = new ArrayList<>();
storagePosList.add(pos);
}
//开始寻找最晚入库的库位
StoragePos pos = null;
Barcode barcode = null;
int amount = 0;
for (StoragePos storagePos : storagePosList) {
if (pos == null) {
pos = storagePos;
}
Barcode posBarcode = storagePos.getBarcode();
if (posBarcode == null) {
continue;
}
List<Barcode> subCodeList = posBarcode.getSubCodeList();
if (subCodeList == null) {
subCodeList = new ArrayList<>();
}
for (Barcode subCode : subCodeList) {
amount = subCode.getAmount() + amount;
if (barcode == null) {
barcode = subCode;
}
if (barcode.getPutInDate().getTime() <= subCode.getPutInDate().getTime()) {
barcode = subCode;
pos = storagePos;
}
}
}
log.info("找到最晚入库的库位为:" + pos.getPosName() + "开始亮灯");
opPosLight("open", pos, putInColor);
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("posName", pos.getPosName());
resultMap.put("partNumber", codeBarcode.getPartNumber());
resultMap.put("posReelNum", amount);
return ResultBean.newOkResult(resultMap);
}
@ApiOperation("寻找空柜体")
@RequestMapping("/findEmptyPosByCode")
@AnonymousAccess
public ResultBean findEmptyPosByCode(@RequestBody Map<String, String> paramMap) {
String id = paramMap.get("id");
//判断是不是有效的条码
String code = paramMap.get("code");
log.info("入库寻找新柜体,条码信息为:" + code + ",");
Barcode barcode = codeResolve.resolveOneValideBarcode("=2x2=" + code);
Storage storage = dataCache.getStorageById(id);
//开始查询空库位
StoragePos pos = storagePosManager.getEmptyPosByStorage(storage, barcode, taskService.excludePosIds());
if (pos == null) {
//smfcore.tailingmaterial.noPos=未找到可用的柜体
return ResultBean.newErrorResult(-1, "smfcore.tailingmaterial.noPos", "未找到可用的柜体");
}
//添加到绑定里边
//addLockPos(pos, cid);
//同时亮灯
opPosLight("open", pos, putInColor);
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("posName", pos.getPosName());
resultMap.put("partNumber", barcode.getPartNumber());
resultMap.put("posReelNum", 0);
return ResultBean.newOkResult(resultMap);
}
@ApiOperation("物料放入柜体中")
@RequestMapping("/putInPos")
@AnonymousAccess
public ResultBean putInPos(@RequestBody Map<String, String> paramMap) {
String posName = paramMap.get("posName");
String code = paramMap.get("code");
String num = paramMap.get("num");
log.info("物料放入柜体中,库位为:" + posName + ",条码为:" + code + ",数量为:" + num);
//解析条码,同时设置数量
Barcode barcode = codeResolve.resolveOneValideBarcode("=2x2=" + code);
barcode.setBarcode(barcode.getPartNumber()+"_"+barcode.getBatch()+"_"+System.currentTimeMillis());
barcode.setAmount(Integer.parseInt(num));
//查询过期天数,看看是不是已经过期了
if (barcode.getProduceDate() != null) {
Component component = componentManager.findByPartNumberAndProvider(barcode.getPartNumber(), barcode.getProvider());
if (component == null){
component = componentManager.findOneByPN(barcode.getPartNumber());
}
if (component != null) {
int validDay = component.getValidDay();
if (validDay > 0){
Date date = DateUtil.addDays(barcode.getProduceDate(), validDay);
barcode.setExpireDate(date);
}
}
}
//判断库位中的物料是否一样
StoragePos pos = storagePosManager.getByPosName(posName);
if (pos == null) {
return ResultBean.newErrorResult(-1, "smfcore.valueNotExist", "{0}[{1}]不存在", new String[]{"柜体", posName});
}
Barcode posBarcode = getPosBarcode(pos);
posBarcode.setPutInTime(System.currentTimeMillis());
//判断和放入的是否一样
List<Barcode> subCodeList = posBarcode.getSubCodeList();
if (subCodeList != null && !subCodeList.isEmpty()) {
for (Barcode subCode : subCodeList) {
if (!barcode.getPartNumber().equals(subCode.getPartNumber())) {
return ResultBean.newErrorResult(-1, "smfcore.tailingmaterial.pnError", "入库的物料[{0}]与柜体中[{1}]不同", new String[]{barcode.getPartNumber(), subCode.getPartNumber()});
}
}
}
barcode.setPosName(pos.getPosName());
barcode.setPutInTime(System.currentTimeMillis());
barcodeManager.saveBarcode(barcode);
posBarcode.UpdateSubCode(barcode);
int amount = 0;
for (Barcode subCode : posBarcode.getSubCodeList()) {
amount = amount + subCode.getAmount();
}
posBarcode.setAmount(amount);
posBarcode.setPartNumber(barcode.getPartNumber());
barcodeManager.saveBarcode(posBarcode);
pos.setBarcode(posBarcode);
pos.setUsed(true);
storagePosManager.save(pos);
//生成入库任务
Storage storage = dataCache.getStorageById(pos.getStorageId());
DataLog dataLog = new DataLog(storage, barcode, pos);
dataLog.setType(OP.PUT_IN);
dataLog.setNum(Integer.parseInt(num));
dataLog.setOperator(SecurityUtils.getLoginUsername());
dataLog.setStatus(OP_STATUS.FINISHED.name());
taskService.updateFinishedTask(dataLog);
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("posName", pos.getPosName());
resultMap.put("partNumber", barcode.getPartNumber());
resultMap.put("posReelNum", amount);
return ResultBean.newOkResult(resultMap);
}
@ApiOperation("需要要出库的柜体")
@RequestMapping("/findOutPosByCode")
@AnonymousAccess
public ResultBean findOutPosByCode(@RequestBody Map<String, String> paramMap) {
String partNumber = paramMap.get("partNumber");
String id = paramMap.get("id");
log.info("收到物料出库请求,partNumber为:" + partNumber + "id为:" + id);
List<StoragePos> storagePosList = getStoragePosListByPn(partNumber, id);
if (storagePosList == null || storagePosList.isEmpty()) {
return ResultBean.newErrorResult(-1, "smfcore.label.noReel", "未找到可出库的物料");
}
//找到最早入库的物料信息
StoragePos pos = null;
Barcode barcode = null;
for (StoragePos storagePos : storagePosList) {
if (pos == null) {
pos = storagePos;
}
Barcode posBarcode = storagePos.getBarcode();
List<Barcode> subCodeList = posBarcode.getSubCodeList();
for (Barcode subCode : subCodeList) {
if (barcode == null) {
barcode = subCode;
}
if (barcode.getPutInDate().getTime() >= subCode.getPutInDate().getTime()) {
barcode = subCode;
pos = storagePos;
}
}
}
log.info("找到最早入库的库位为:" + pos.getPosName() + ",入库日期为:" + barcode.getPutInDate(), "开始亮灯");
opPosLight("open", pos, putInColor);
int amount = 0;
Barcode posBarcode = pos.getBarcode();
if (posBarcode != null){
List<Barcode> subCodeList = posBarcode.getSubCodeList();
if (subCodeList != null && !subCodeList.isEmpty()){
for (Barcode subCode : subCodeList) {
amount = subCode.getAmount() + amount;
}
}
}
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("posName", pos.getPosName());
resultMap.put("partNumber", partNumber);
resultMap.put("posReelNum", amount);
return ResultBean.newOkResult(resultMap);
}
@ApiOperation("物料从柜体中出库")
@AnonymousAccess
@RequestMapping("/outFromPos")
public ResultBean outFromPos(@RequestBody Map<String, String> paramMap) {
String posName = paramMap.get("posName");
String partNumber = paramMap.get("partNumber");
String numStr = paramMap.get("num");
log.info("物料从柜体出库,库位为:" + posName + ",条码为:" + posName + ",数量为:" + numStr + ",partNumber为:" + partNumber);
//判断库位中的物料是否一样
StoragePos pos = storagePosManager.getByPosName(posName);
if (pos == null) {
return ResultBean.newErrorResult(-1, "smfcore.valueNotExist", "{0}[{1}]不存在", new String[]{"柜体", posName});
}
Storage storage = dataCache.getStorageById(pos.getStorageId());
Barcode posBarcode = getPosBarcode(pos);
//直到出库物料位置
int outNum = 0;
int num = Integer.parseInt(numStr);
while (outNum < num) {
int remainNum = num - outNum;
Barcode barcode = null;
List<Barcode> subCodeList = posBarcode.getSubCodeList();
for (Barcode subCode : subCodeList) {
if (barcode == null) {
barcode = subCode;
}
if (barcode.getPutInDate().getTime() >= subCode.getPutInDate().getTime()) {
barcode = subCode;
}
}
if (barcode == null){
break;
}
log.info("寻找到对应的料盘信息为:" + barcode.getBarcode() + ",对应的入库时间为:" + barcode.getPutInDate());
DataLog dataLog = new DataLog(storage, barcode, pos);
dataLog.setType(OP.CHECKOUT);
dataLog.setNum(remainNum);
if (remainNum >= barcode.getAmount()) {
dataLog.setNum(barcode.getAmount());
outNum = outNum + barcode.getAmount();
barcode.setAmount(0);
barcode.setPosName("");
barcodeManager.save(barcode);
} else {
outNum = outNum + remainNum;
barcode.setAmount(barcode.getAmount() - remainNum);
barcodeManager.saveBarcode(barcode);
}
dataLog.setStatus(OP_STATUS.FINISHED.name());
dataLog.setOperator(SecurityUtils.getLoginUsername());
taskService.updateFinishedTask(dataLog);
posBarcode.UpdateSubCode(barcode);
}
int amount = 0;
List<Barcode> subCodeList = posBarcode.getSubCodeList();
if (subCodeList == null || subCodeList.isEmpty()) {
posBarcode.setAmount(0);
pos.setBarcode(null);
pos.setUsed(false);
//如果为空了,就把当前库位的值给清空
expirePosMap.remove(posName);
} else {
for (Barcode barcode : posBarcode.getSubCodeList()) {
amount = amount + barcode.getAmount();
if (barcode.isExpired()){
expirePosMap.put(posName,storage.getCid());
}
}
posBarcode.setAmount(amount);
pos.setBarcode(posBarcode);
}
barcodeManager.save(posBarcode);
storagePosManager.save(pos);
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("posName", pos.getPosName());
resultMap.put("partNumber", partNumber);
resultMap.put("posReelNum", amount);
return ResultBean.newOkResult(resultMap);
}
@Override
public StatusBean handleClientRequest(StatusBean statusBean, HttpServletRequest request) {
if (expirePosMap != null && !expirePosMap.isEmpty()){
for (String key : expirePosMap.keySet()) {
log.info("添加亮灯执指令,cid为:"+expirePosMap.get(key)+",key为openLed"+",value为:"+key+"="+expiredColor);
DevicesStatusUtil.appendOp(expirePosMap.get(key), "openLed", key+"="+expiredColor);
}
}
statusBean.setClientIp(request.getRemoteHost());
handleMsg(statusBean);
statusBean = saveAlarmAndHumidity(statusBean);
if (statusBean != null) {
Map<String, String> opMap = DevicesStatusUtil.getAndRemoveOp(statusBean.getCid());
statusBean.addOp(opMap);
}
return statusBean;
}
private List<StoragePos> getStoragePosListByPn(String partNumber, String id) {
Storage storage = dataCache.getStorageById(id);
//查询信息
Criteria criteria = Criteria.where("barcode").exists(true)
.and("enabled").is(true)
.and("storageId").is(storage.getId())
.and("barcode.partNumber").is(partNumber);
Query query = new Query(criteria);
return storagePosManager.findByQuery(query);
}
private Barcode getPosBarcode(StoragePos pos) {
Barcode barcode = pos.getBarcode();
if (barcode == null) {
barcode = barcodeManager.findByBarcode(pos.getPosName());
if (barcode != null){
String id = barcode.getId();
barcode = new Barcode();
barcode.setId(id);
barcode.setBarcode(pos.getPosName());
barcode.setAmount(0);
barcodeManager.save(barcode);
}
}
if (barcode == null) {
barcode = new Barcode();
barcode.setBarcode(pos.getPosName());
barcode.setAmount(0);
barcodeManager.save(barcode);
}
return barcode;
}
/**
* 操作库位灯(开灯,或关灯)
*
* @param opKey
* @param pos
* @param colorStr
*/
private void opPosLight(String opKey, StoragePos pos, String colorStr) {
String opStr = pos.getPosName();
if (!Strings.isNullOrEmpty(colorStr)) {
opStr = opStr + "=" + colorStr;
}
Storage storage = dataCache.getStorageById(pos.getStorageId());
DevicesStatusUtil.appendOp(storage.getCid(), opKey, opStr);
log.info("操作库位[" + pos.getPosName() + "]" + opKey + " : " + opStr);
}
@Override
public DeviceType getDeviceType() {
return DeviceType.TAILING_MATERIAL;
}
}
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;
}
}
...@@ -17,6 +17,7 @@ import com.neotel.smfcore.core.device.util.DataCache; ...@@ -17,6 +17,7 @@ import com.neotel.smfcore.core.device.util.DataCache;
import com.neotel.smfcore.core.kanban.rest.bean.dto.*; import com.neotel.smfcore.core.kanban.rest.bean.dto.*;
import com.neotel.smfcore.core.kanban.rest.bean.mapstruct.BoxTaskMapper; import com.neotel.smfcore.core.kanban.rest.bean.mapstruct.BoxTaskMapper;
import com.neotel.smfcore.core.kanban.rest.bean.query.BoxTaskQueryCriter; import com.neotel.smfcore.core.kanban.rest.bean.query.BoxTaskQueryCriter;
import com.neotel.smfcore.core.kanban.rest.utils.NaturalOrderComparator;
import com.neotel.smfcore.core.message.util.DeviceMessageUtil; import com.neotel.smfcore.core.message.util.DeviceMessageUtil;
import com.neotel.smfcore.core.msd.bean.MSDSettiings; import com.neotel.smfcore.core.msd.bean.MSDSettiings;
import com.neotel.smfcore.core.solder.util.SolderBoxCache; import com.neotel.smfcore.core.solder.util.SolderBoxCache;
...@@ -107,7 +108,7 @@ public class BoxKanbanController { ...@@ -107,7 +108,7 @@ public class BoxKanbanController {
} }
} }
if(boxStatusDtos.size()>0){ if(boxStatusDtos.size()>0){
boxStatusDtos = boxStatusDtos.stream().sorted(Comparator.comparing(BoxStatusDto :: getName)).collect(Collectors.toList()); boxStatusDtos = boxStatusDtos.stream().sorted(Comparator.comparing(BoxStatusDto :: getName, new NaturalOrderComparator())).collect(Collectors.toList());
GroupStatusDto groupStatusDto = new GroupStatusDto(group.getId(),group.getGroupName(),boxStatusDtos,groupType); GroupStatusDto groupStatusDto = new GroupStatusDto(group.getId(),group.getGroupName(),boxStatusDtos,groupType);
groupStatusDtos.add(groupStatusDto); groupStatusDtos.add(groupStatusDto);
} }
......
package com.neotel.smfcore.core.kanban.rest.utils;
import java.util.Comparator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 自然排序比较器:字母按字典序,数字按数值大小排序
*/
public class NaturalOrderComparator implements Comparator<String> {
// 正则表达式:拆分字符串为"非数字"和"数字"交替的部分
private static final Pattern PATTERN = Pattern.compile("(\\D+)|(\\d+)");
@Override
public int compare(String s1, String s2) {
if (s1 == null && s2 == null) return 0;
if (s1 == null) return -1; // null放前面
if (s2 == null) return 1;
Matcher m1 = PATTERN.matcher(s1);
Matcher m2 = PATTERN.matcher(s2);
// 逐个匹配"非数字/数字"片段并比较
while (m1.find() && m2.find()) {
String group1 = m1.group();
String group2 = m2.group();
// 判断当前片段是数字还是非数字
if (group1.matches("\\d+") && group2.matches("\\d+")) {
// 数字片段:按数值大小比较(避免"10" < "2"的字符串排序问题)
Long num1 = Long.parseLong(group1);
Long num2 = Long.parseLong(group2);
int numCompare = num1.compareTo(num2);
if (numCompare != 0) {
return numCompare;
}
} else {
// 非数字片段:按字典序比较
int strCompare = group1.compareTo(group2);
if (strCompare != 0) {
return strCompare;
}
}
}
// 一个字符串是另一个的前缀,短的放前面
return Integer.compare(s1.length(), s2.length());
}
}
\ No newline at end of file \ No newline at end of file
...@@ -159,6 +159,11 @@ public enum DeviceType { ...@@ -159,6 +159,11 @@ public enum DeviceType {
* 26 smdOne * 26 smdOne
*/ */
SMD_ONE("storage.type.smdOne"), SMD_ONE("storage.type.smdOne"),
/**
* 尾料柜
*/
TAILING_MATERIAL("storage.type.tailingMaterial"),
; ;
private String key; private String key;
...@@ -180,6 +185,6 @@ public enum DeviceType { ...@@ -180,6 +185,6 @@ public enum DeviceType {
} }
public static List<DeviceType> availableTypeList(){ public static List<DeviceType> availableTypeList(){
return Lists.newArrayList(AUTO,LINE,BATCH,SOLDERPASTE,VERTICALBOX,SMD_XL,SMD_DUO,SMD_XLC,SMD_XLR,SMD_ONE,VIRTUAL,NL,NLP,NLM,NLL,NLS,NLSM,SMDBOX_THIRD,SMD_MIMO_G2,SMD_MIMO_G3); return Lists.newArrayList(AUTO,LINE,BATCH,SOLDERPASTE,VERTICALBOX,SMD_XL,SMD_DUO,SMD_XLC,SMD_XLR,SMD_ONE,VIRTUAL,NL,NLP,NLM,NLL,NLS,NLSM,SMDBOX_THIRD,SMD_MIMO_G2,SMD_MIMO_G3,TAILING_MATERIAL);
} }
} }
...@@ -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;
} }
...@@ -1038,4 +1038,95 @@ public class StoragePosManagerImpl implements IStoragePosManager { ...@@ -1038,4 +1038,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;
}
} }
...@@ -167,8 +167,8 @@ public class TaskService { ...@@ -167,8 +167,8 @@ public class TaskService {
* @param task * @param task
*/ */
private void tiggerTaskChangeListener(DataLog task) { private void tiggerTaskChangeListener(DataLog task) {
liteOrderCache.onTaskStatusChange(task);
smfApi.onTaskStatusChange(task); smfApi.onTaskStatusChange(task);
liteOrderCache.onTaskStatusChange(task);
selfAuditUtil.onTaskStatusChange(task); selfAuditUtil.onTaskStatusChange(task);
materialTraceUtil.onTaskStatusChange(task); materialTraceUtil.onTaskStatusChange(task);
} }
...@@ -1454,4 +1454,169 @@ public class TaskService { ...@@ -1454,4 +1454,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;
}
} }
...@@ -319,6 +319,27 @@ public class NeotelApi extends BaseSmfApiListener { ...@@ -319,6 +319,27 @@ public class NeotelApi extends BaseSmfApiListener {
*/ */
@Override @Override
public void onOrderStatusChange(String orderNotifyUrl, LiteOrder liteOrder) { public void onOrderStatusChange(String orderNotifyUrl, LiteOrder liteOrder) {
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("hSerial", liteOrder.getOrderNo());
String status = "Created";
if (liteOrder.isClosed()){
status = "Closed";
} else {
if (liteOrder.isTaskFinished()){
status = "Completed";
} else if (liteOrder.isOutBom() || liteOrder.isOutTails() || liteOrder.isOutOne()){
status = "Executed";
}
}
paramMap.put("status", status);
paramMap.put("total", liteOrder.getTotalTaskReelCount());
paramMap.put("out", liteOrder.getTotalFinishedReelCount());
try {
log.info(liteOrder.getOrderNo() + "工单状态改变,参数为:" + JsonUtil.toJsonStr(paramMap));
String result = HttpHelper.postJson(orderNotifyUrl, paramMap);
log.info(liteOrder.getOrderNo() + "工单状态改变,返回结果为:" + result);
} catch (Exception e) {
log.error("入库验证接口出错:" + e.getMessage());
}
} }
} }
...@@ -443,3 +443,8 @@ smf.nexim.getInventoryFaile=\u83B7\u53D6did\u4FE1\u606F\u5931\u8D25:[{0}] ...@@ -443,3 +443,8 @@ smf.nexim.getInventoryFaile=\u83B7\u53D6did\u4FE1\u606F\u5931\u8D25:[{0}]
smfcore.registerdid.false=[{0}]\u6CE8\u518Cdid\u5931\u8D25:[{1}] smfcore.registerdid.false=[{0}]\u6CE8\u518Cdid\u5931\u8D25:[{1}]
smfcore.accessToken.ng=\u83B7\u53D6AccessToken\u5931\u8D25 smfcore.accessToken.ng=\u83B7\u53D6AccessToken\u5931\u8D25
smfcore.barcode.hasOutTask=\u7269\u6599[{0}]\u5DF2\u6709\u51FA\u5E93\u4EFB\u52A1,\u9700\u7EE7\u7EED\u6267\u884C\u51FA\u5E93\u52A8\u4F5C smfcore.barcode.hasOutTask=\u7269\u6599[{0}]\u5DF2\u6709\u51FA\u5E93\u4EFB\u52A1,\u9700\u7EE7\u7EED\u6267\u884C\u51FA\u5E93\u52A8\u4F5C
smfcore.tailingmaterial.noPos=\u672A\u627E\u5230\u53EF\u7528\u7684\u67DC\u4F53
smfcore.tailingmaterial.pnError=\u5165\u5E93\u7684\u7269\u6599[{0}]\u4E0E\u67DC\u4F53\u4E2D[{1}]\u4E0D\u540C
smfcode.nlp.posRecovered=\u5E93\u4F4D[{0}]\u6062\u590D\u6B63\u5E38
smfcode.nlp.posNoReelError=\u5E93\u4F4D[{0}]\u68C0\u6D4B\u5230\u6CA1\u6709\u7269\u6599\uFF0C\u4F46\u7CFB\u7EDF\u6709\u5E93\u5B58\u8BB0\u5F55
smfcode.nlp.posHasReelError=\u5E93\u4F4D[{0}]\u68C0\u6D4B\u5230\u6709\u7269\u6599\uFF0C\u4F46\u7CFB\u7EDF\u65E0\u5E93\u5B58\u8BB0\u5F55
...@@ -430,4 +430,9 @@ smfcore.order.slotNum=Standnummer ...@@ -430,4 +430,9 @@ smfcore.order.slotNum=Standnummer
smf.nexim.getInventoryFaile=Fehler beim Abrufen der did-Information: [{0}] smf.nexim.getInventoryFaile=Fehler beim Abrufen der did-Information: [{0}]
smfcore.registerdid.false=[{0}] Registrierung von did fehlgeschlagen:[{1}] smfcore.registerdid.false=[{0}] Registrierung von did fehlgeschlagen:[{1}]
smfcore.accessToken.ng=Fehler beim Abrufen des AccessToken smfcore.accessToken.ng=Fehler beim Abrufen des AccessToken
smfcore.barcode.hasOutTask=Material [{0}] hat bereits einen Ausgangsauftrag; die Ausgangsaktion muss fortgesetzt werden
\ No newline at end of file \ No newline at end of file
smfcore.barcode.hasOutTask=Material [{0}] hat bereits einen Ausgangsauftrag; die Ausgangsaktion muss fortgesetzt werden
smfcore.tailingmaterial.noPos=Kein verf\u00FCgbarer Schrank gefunden
smfcore.tailingmaterial.pnError=Das eingelagerte Material [{0}] unterscheidet sich von dem im Schrank [{1}]
smfcode.nlp.posRecovered=Position [{0}] wieder normal
smfcode.nlp.posNoReelError=Position [{0}] hat kein Material erkannt, aber das System hat einen Bestandsdatensatz
smfcode.nlp.posHasReelError=Position [{0}] hat Material erkannt, aber das System hat keinen Bestandsdatensatz
\ No newline at end of file \ No newline at end of file
...@@ -431,4 +431,9 @@ smfcore.order.slotNum=Station Number ...@@ -431,4 +431,9 @@ smfcore.order.slotNum=Station Number
smf.nexim.getInventoryFaile=Failed to retrieve did information: [{0}] smf.nexim.getInventoryFaile=Failed to retrieve did information: [{0}]
smfcore.registerdid.false=[{0}] Failed to register did:[{1}] smfcore.registerdid.false=[{0}] Failed to register did:[{1}]
smfcore.accessToken.ng=Failed to obtain AccessToken smfcore.accessToken.ng=Failed to obtain AccessToken
smfcore.barcode.hasOutTask=Material [{0}] already has an outbound task; the outbound action needs to be continued.
\ No newline at end of file \ No newline at end of file
smfcore.barcode.hasOutTask=Material [{0}] already has an outbound task; the outbound action needs to be continued.
smfcore.tailingmaterial.noPos=No available cabinet found
smfcore.tailingmaterial.pnError=The material [{0}] put in is different from the one in the cabinet [{1}]
smfcode.nlp.posRecovered=Position [{0}] returned to normal
smfcode.nlp.posNoReelError=Position [{0}] detected no material, but system has inventory record
smfcode.nlp.posHasReelError=Position [{0}] detected material, but system has no inventory record
\ No newline at end of file \ No newline at end of file
...@@ -430,4 +430,9 @@ smfcore.order.slotNum=num\u00E9ro de position ...@@ -430,4 +430,9 @@ smfcore.order.slotNum=num\u00E9ro de position
smf.nexim.getInventoryFaile=\u00C9chec de r\u00E9cup\u00E9ration des informations did:[{0}] smf.nexim.getInventoryFaile=\u00C9chec de r\u00E9cup\u00E9ration des informations did:[{0}]
smfcore.registerdid.false=[{0}] \u00C9chec de l'enregistrement de did:[{1}] smfcore.registerdid.false=[{0}] \u00C9chec de l'enregistrement de did:[{1}]
smfcore.accessToken.ng=\u00C9chec de l'obtention de l'AccessToken smfcore.accessToken.ng=\u00C9chec de l'obtention de l'AccessToken
smfcore.barcode.hasOutTask=La mati\u00E8re [{0}] a d\u00E9j\u00E0 une t\u00E2che de sortie ; l'action de sortie doit \u00EAtre poursuivie
\ No newline at end of file \ No newline at end of file
smfcore.barcode.hasOutTask=La mati\u00E8re [{0}] a d\u00E9j\u00E0 une t\u00E2che de sortie ; l'action de sortie doit \u00EAtre poursuivie
smfcore.tailingmaterial.noPos=Aucun cabinet disponible trouv\u00E9
smfcore.tailingmaterial.pnError=Le mat\u00E9riau [{0}] mis en stock est diff\u00E9rent de celui dans le cabinet [{1}]
smfcode.nlp.posRecovered=Position [{0}] revenue \u00E0 la normale
smfcode.nlp.posNoReelError=Position [{0}] n'a d\u00E9tect\u00E9 aucun mat\u00E9riau, mais le syst\u00E8me a un enregistrement d'inventaire
smfcode.nlp.posHasReelError=Position [{0}] a d\u00E9tect\u00E9 du mat\u00E9riau, mais le syst\u00E8me n'a pas d'enregistrement d'inventaire
\ No newline at end of file \ No newline at end of file
...@@ -427,4 +427,9 @@ smfcore.order.slotNum=\u30B9\u30BF\u30F3\u30C9\u756A\u53F7 ...@@ -427,4 +427,9 @@ smfcore.order.slotNum=\u30B9\u30BF\u30F3\u30C9\u756A\u53F7
smf.nexim.getInventoryFaile=did \u60C5\u5831\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F: [{0}] smf.nexim.getInventoryFaile=did \u60C5\u5831\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F: [{0}]
smfcore.registerdid.false=[{0}] did \u306E\u767B\u9332\u306B\u5931\u6557\u3057\u307E\u3057\u305F:[{1}] smfcore.registerdid.false=[{0}] did \u306E\u767B\u9332\u306B\u5931\u6557\u3057\u307E\u3057\u305F:[{1}]
smfcore.accessToken.ng=AccessToken \u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F smfcore.accessToken.ng=AccessToken \u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F
smfcore.barcode.hasOutTask=\u8CC7\u6750 [{0}] \u306B\u306F\u65E2\u306B\u51FA\u5EAB\u30BF\u30B9\u30AF\u304C\u3042\u308A\u3001\u51FA\u5EAB\u30A2\u30AF\u30B7\u30E7\u30F3\u3092\u7D9A\u884C\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059
\ No newline at end of file \ No newline at end of file
smfcore.barcode.hasOutTask=\u8CC7\u6750 [{0}] \u306B\u306F\u65E2\u306B\u51FA\u5EAB\u30BF\u30B9\u30AF\u304C\u3042\u308A\u3001\u51FA\u5EAB\u30A2\u30AF\u30B7\u30E7\u30F3\u3092\u7D9A\u884C\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059
smfcore.tailingmaterial.noPos=\u5229\u7528\u53EF\u80FD\u306A\u30AD\u30E3\u30D3\u30CD\u30C3\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093
smfcore.tailingmaterial.pnError=\u5165\u5E93\u3055\u308C\u305F\u6750\u6599[{0}]\u306F\u30AD\u30E3\u30D3\u30CD\u30C3\u30C8\u5185\u306E[{1}]\u3068\u7570\u306A\u308A\u307E\u3059
smfcode.nlp.posRecovered=\u5EAB\u4F4D[{0}]\u304C\u6B63\u5E38\u306B\u623B\u308A\u307E\u3057\u305F
smfcode.nlp.posNoReelError=\u5EAB\u4F4D[{0}]\u306B\u7269\u6599\u304C\u691C\u51FA\u3055\u308C\u307E\u305B\u3093\u304C\u3001\u30B7\u30B9\u30C6\u30E0\u306B\u306F\u5728\u5EAB\u8A18\u9332\u304C\u3042\u308A\u307E\u3059
smfcode.nlp.posHasReelError=\u5EAB\u4F4D[{0}]\u306B\u7269\u6599\u304C\u691C\u51FA\u3055\u308C\u307E\u3057\u305F\u304C\u3001\u30B7\u30B9\u30C6\u30E0\u306B\u306F\u5728\u5EAB\u8A18\u9332\u304C\u3042\u308A\u307E\u305B\u3093
\ No newline at end of file \ No newline at end of file
...@@ -427,4 +427,9 @@ smfcore.order.slotNum=\u7AD9\u4F4D\u7F16\u53F7 ...@@ -427,4 +427,9 @@ smfcore.order.slotNum=\u7AD9\u4F4D\u7F16\u53F7
smf.nexim.getInventoryFaile=\u83B7\u53D6did\u4FE1\u606F\u5931\u8D25:[{0}] smf.nexim.getInventoryFaile=\u83B7\u53D6did\u4FE1\u606F\u5931\u8D25:[{0}]
smfcore.registerdid.false=[{0}]\u6CE8\u518Cdid\u5931\u8D25:[{1}] smfcore.registerdid.false=[{0}]\u6CE8\u518Cdid\u5931\u8D25:[{1}]
smfcore.accessToken.ng=\u83B7\u53D6AccessToken\u5931\u8D25 smfcore.accessToken.ng=\u83B7\u53D6AccessToken\u5931\u8D25
smfcore.barcode.hasOutTask=\u7269\u6599[{0}]\u5DF2\u6709\u51FA\u5E93\u4EFB\u52A1,\u9700\u7EE7\u7EED\u6267\u884C\u51FA\u5E93\u52A8\u4F5C
\ No newline at end of file \ No newline at end of file
smfcore.barcode.hasOutTask=\u7269\u6599[{0}]\u5DF2\u6709\u51FA\u5E93\u4EFB\u52A1,\u9700\u7EE7\u7EED\u6267\u884C\u51FA\u5E93\u52A8\u4F5C
smfcore.tailingmaterial.noPos=\u672A\u627E\u5230\u53EF\u7528\u7684\u67DC\u4F53
smfcore.tailingmaterial.pnError=\u5165\u5E93\u7684\u7269\u6599[{0}]\u4E0E\u67DC\u4F53\u4E2D[{1}]\u4E0D\u540C
smfcode.nlp.posRecovered=\u5E93\u4F4D[{0}]\u6062\u590D\u6B63\u5E38
smfcode.nlp.posNoReelError=\u5E93\u4F4D[{0}]\u68C0\u6D4B\u5230\u6CA1\u6709\u7269\u6599\uFF0C\u4F46\u7CFB\u7EDF\u6709\u5E93\u5B58\u8BB0\u5F55
smfcode.nlp.posHasReelError=\u5E93\u4F4D[{0}]\u68C0\u6D4B\u5230\u6709\u7269\u6599\uFF0C\u4F46\u7CFB\u7EDF\u65E0\u5E93\u5B58\u8BB0\u5F55
\ No newline at end of file \ No newline at end of file
...@@ -427,4 +427,9 @@ smfcore.order.slotNum = \u7AD9\u4F4D\u7DE8\u865F ...@@ -427,4 +427,9 @@ smfcore.order.slotNum = \u7AD9\u4F4D\u7DE8\u865F
smf.nexim.getInventoryFaile=\u53D6\u5F97 did \u8CC7\u8A0A\u5931\u6557:[{0}] smf.nexim.getInventoryFaile=\u53D6\u5F97 did \u8CC7\u8A0A\u5931\u6557:[{0}]
smfcore.registerdid.false=[{0}]\u8A3B\u518Adid\u5931\u6557:[{1}] smfcore.registerdid.false=[{0}]\u8A3B\u518Adid\u5931\u6557:[{1}]
smfcore.accessToken.ng=\u7372\u53D6AccessToken\u5931\u6557 smfcore.accessToken.ng=\u7372\u53D6AccessToken\u5931\u6557
smfcore.barcode.hasOutTask=\u7269\u6599[{0}]\u5DF2\u6709\u51FA\u5EAB\u4EFB\u52D9\uFF0C\u9700\u7E7C\u7E8C\u57F7\u884C\u51FA\u5EAB\u52D5\u4F5C
\ No newline at end of file \ No newline at end of file
smfcore.barcode.hasOutTask=\u7269\u6599[{0}]\u5DF2\u6709\u51FA\u5EAB\u4EFB\u52D9\uFF0C\u9700\u7E7C\u7E8C\u57F7\u884C\u51FA\u5EAB\u52D5\u4F5C
smfcore.tailingmaterial.noPos=\u672A\u627E\u5230\u53EF\u7528\u7684\u6AC3\u9AD4
smfcore.tailingmaterial.pnError=\u5165\u5EAB\u7684\u7269\u6599[{0}]\u8207\u6AC3\u9AD4\u4E2D[{1}]\u4E0D\u540C
smfcode.nlp.posRecovered=\u5EAB\u4F4D[{0}]\u6062\u5FA9\u6B63\u5E38
smfcode.nlp.posNoReelError=\u5EAB\u4F4D[{0}]\u6AA2\u6E2C\u5230\u6C92\u6709\u7269\u6599\uFF0C\u4F46\u7CFB\u7D71\u6709\u5EAB\u5B58\u8A18\u9304
smfcode.nlp.posHasReelError=\u5EAB\u4F4D[{0}]\u6AA2\u6E2C\u5230\u6709\u7269\u6599\uFF0C\u4F46\u7CFB\u7D71\u7121\u5EAB\u5B58\u8A18\u9304
\ No newline at end of file \ No newline at end of file
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!