Commit a606fb89 sunke

解除绑定时,绑定到新的需求单

缺料补料时料架编号使用B
入库验证失败时,清理锁定库位
缺料重发时任务数量双倍的问题
1 个父辈 f97ca246
......@@ -322,4 +322,22 @@ IP: 10.85.160.181
>> - cid: 库位中料盘的锁定库位对应的料仓编号
>> - lockPos: 库位中料盘的锁定库位
12. 包装线AGV获取料架中的任务数,如果当前料架的任务数不为0,需要用当前料架去其他包装仓继续放料
>地址:
>>/rest/api/qisda/device/getShelfLockInfo
>
>参数:
>>rfid : RFID
>
> 返回:
>>` {"code":0,"msg":"ok","data":{"taskCount":0,"rfid":"A2"}}`
>>
>> - code: 0为正常,其他为异常,
>> - msg:消息,
>> - data:
>> - rfid: 料架RFID
>> - taskCount: 当前料架剩余任务数(即还有几盘料没放上去)
......@@ -297,6 +297,14 @@ public class AppendInfo {
return action.equals("补料");
}
public boolean isUrgentAction(){
if(action == null){
return false;
}
return getAction().contains("急料") || getAction().contains("指定") || getAction().contains("单独出库");
}
public String getDnOrFacility(){
if(isFacilityIn()){
return facility;
......
......@@ -6,6 +6,7 @@ import com.myproject.util.StorageConstants;
import com.myproject.webapp.controller.webService.QisdaCache;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.util.Strings;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
......@@ -118,14 +119,14 @@ public class InquiryShelfBean {
ShelfInfo nextShelf = cAndDShelfList.get(i + 1);
if(nextShelf.isDShelf()){
//下一个料架如果是小料架,不允许出
log.info("还有两个小料架["+shelfInfo.tempRfid()+"," + nextShelf.tempRfid()+"]未放满,大料任务["+task.getBarcode()+"]暂停出库");
//log.info("还有两个小料架["+shelfInfo.tempRfid()+"," + nextShelf.tempRfid()+"]未放满,大料任务["+task.getBarcode()+"]暂停出库");
return false;
}else{
//下一个料架是大料架,最多只能出一个料架的大料
int emptyLocCount = nextShelf.getEmptyLocCount();
boolean canOut = unFinishedBigTaskCount + 1 <= emptyLocCount;
if(!canOut){
log.info("未完成的大料数量["+unFinishedBigTaskCount+"]已可放满下一料架"+nextShelf.tempRfid()+"["+emptyLocCount+"],大料任务["+task.getBarcode()+"]暂停出库");
//log.info("未完成的大料数量["+unFinishedBigTaskCount+"]已可放满下一料架"+nextShelf.tempRfid()+"["+emptyLocCount+"],大料任务["+task.getBarcode()+"]暂停出库");
}
return canOut;
}
......@@ -376,38 +377,23 @@ public class InquiryShelfBean {
}
/**
* 3号机器人放入时查找大料架,如果没有相同RFID,查找未绑定的相同类型料架
* @param bigRfid
* @return
* 查找料架相同RFID的料架,用于AGV判断是否还有任务
*/
public static ShelfInfo findBigShelf(String bigRfid){
if(bigRfid == null){
public static ShelfInfo findShelf(String rfid){
if(Strings.isEmpty(rfid)){
return null;
}
ShelfInfo minIndexShelf = null;
for (Map<String, ShelfInfo> shelfInfoMap : hSerialShelfMap.values()) {
for (ShelfInfo shelf : shelfInfoMap.values()) {
String shelfRFID = shelf.getRealRfid();
if(StorageConstants.SHEFL_TYPE.judgeType(bigRfid, shelf.getShelfType())){
if(shelfRFID.equals(bigRfid)){
//已经绑定过该Temp料架
return shelf;
}else{
if(shelf.isFull()){
//已经放满,查找下一个
continue;
}
if(minIndexShelf == null){
minIndexShelf = shelf;
}else if(shelf.getRfidIndex() < minIndexShelf.getRfidIndex()){
minIndexShelf = shelf;
}
}
if(shelfRFID.equals(rfid)){
//已经绑定过该Temp料架
return shelf;
}
}
}
return minIndexShelf;
return null;
}
/**
......
......@@ -42,6 +42,8 @@ public interface IStoragePosManager extends IManager<StoragePos> {
List<StoragePos> getEmptyPosByLimitPn(String storageId, String limitPn);
List<StoragePos> getEmptyPosList(List<Storage> storageList, Barcode barcode, Collection<String> excludePosIds);
StoragePos getEmptyPosByStorage(Storage storage, Barcode barcode, Collection<String> excludePosIds) throws ValidateException;
int countTotalStorageSize(String storageId);
......
......@@ -69,6 +69,7 @@ public class StoragePosManagerImpl implements IStoragePosManager {
.and("specifiedPartNumber").is(partNumber)
.and("enabled").is(true)//可用
.and("used").is(false);//未使用;
//去除的仓位
if(excludePosIds != null && !excludePosIds.isEmpty()){
c = c.and("id").nin(excludePosIds);
......@@ -91,6 +92,55 @@ public class StoragePosManagerImpl implements IStoragePosManager {
}
@Override
public List<StoragePos> getEmptyPosList(List<Storage> storageList, Barcode barcode, Collection<String> excludePosIds){
List<String> exactMatchStorageIdList = new ArrayList<>();
List<String> sizeCompatibleStorageIdList = new ArrayList<>();
List<String> heightCompatibleStorageIdList = new ArrayList<>();
for (Storage storage : storageList) {
StorageConstants.COMPATIBLE_TYPE compatibleType = storage.getCompatibleType();
if(compatibleType == StorageConstants.COMPATIBLE_TYPE.EXACT_MATCH) {//完全匹配
exactMatchStorageIdList.add(storage.getId());
}else if(compatibleType == StorageConstants.COMPATIBLE_TYPE.FULLY_COMPATIBLE){//同厚度兼容
if(barcode.getPlateSize() != 7){
heightCompatibleStorageIdList.add(storage.getId());
}else{
//=7寸使用完全匹配
exactMatchStorageIdList.add(storage.getId());
}
}else if(compatibleType == StorageConstants.COMPATIBLE_TYPE.SIZE_COMPATIBLE){//同尺寸兼容
sizeCompatibleStorageIdList.add(storage.getId());
}
}
Criteria c = Criteria.where("id").nin(excludePosIds).and("used").is(false).and("enabled").is(true);
//if(!exactMatchStorageIdList.isEmpty()){
Criteria exactMatchCriteria = Criteria.where("storageId").in(exactMatchStorageIdList).and("w").is(barcode.getPlateSize()).and("h").is(barcode.getHeight());
//conditionCriteria.orOperator(exactMatchCriteria);
//c.andOperator(exactMatchCriteria);
// }
//
// if(!sizeCompatibleStorageIdList.isEmpty()){
Criteria sizeCompatibleCriteria = Criteria.where("storageId").in(sizeCompatibleStorageIdList).and("w").is(barcode.getPlateSize()).and("h").gte(barcode.getHeight());
// conditionCriteria.orOperator(sizeCompatibleCriteria);
// }
//
// if(!heightCompatibleStorageIdList.isEmpty()){
Criteria heightCompatibleCriteria = Criteria.where("storageId").in(heightCompatibleStorageIdList).and("w").gte(barcode.getPlateSize()).and("h").is(barcode.getHeight());
// conditionCriteria.orOperator(heightCompatibleCriteria);
// }
Criteria conditionCriteria = new Criteria().orOperator(exactMatchCriteria,sizeCompatibleCriteria,heightCompatibleCriteria);
Query query = new Query(new Criteria().andOperator(c, conditionCriteria));
//优先放入最合适的位置(根据尺寸),相同尺寸按优先级排序
query.with(new Sort(Sort.Direction.ASC, "w").and(new Sort(Sort.Direction.ASC, "h")).and(new Sort(Sort.Direction.DESC, "priority")));
query.limit(1);
return storagePosDao.findByQuery(query);
}
@Override
public StoragePos getEmptyPosByStorage(Storage storage, Barcode barcode, Collection<String> excludePosIds) throws ValidateException {
if(storage == null){
......
......@@ -516,20 +516,19 @@ public class QisdaApi {
materialInfoMap.put("latest",latest);//本次工单第几盘料(F 第一次,L 最后一次, M 中间, E是错误)
materialInfoMap.put("cloudLocation",task.getPosName());//云料仓的库位
materialInfoMap.put("location","");//料架库位
materialInfoMap.put("vehicleID",appendInfo.getRfid());//料车编号
String rfid = appendInfo.getRfid();
if(task.isLessSendReel()){
rfid = "B";
}
if(latest.equals("E")){
//错误状态不发料车编号
materialInfoMap.put("vehicleID","");//料车编号
rfid = "";
}
materialInfoMap.put("vehicleID",rfid);//料车编号
int rfidLoc = appendInfo.getRfidLoc();
rfidLoc = task.resolveRfidLoc(rfidLoc + "");
// if(task.isLessSendReel()){
// if(appendInfo.isFirstReelAction()){
// rfidLoc = 1;
// }else if(appendInfo.isTailAction()){
// rfidLoc = 2;
// }
// }
materialInfoMap.put("vehicleLocation",rfidLoc);//料车架位号
materialInfoMap.put("lot", barcode.getBatch());//生产批次(批次号)
String productCode = DateUtil.toDateString(barcode.getProduceDate(),"yyyyMMdd");
......
......@@ -125,7 +125,7 @@ public class OutInfoCache {
soseqCache.udpateTotalPreLockQty(cutItem,preBindQty);
log.info("\t分盘料["+barcode.getBarcode()+"]绑定到Soseq=["+cutItem.getSoseq()+"]So=["+cutItem.getSo()+"]的["+cutItem.getSlotlocation()+"] 数量:" + preBindQty +"/" + cutItem.getQty());
log.info("\t分盘料["+barcode.getBarcode()+"]绑定到soseq=["+cutItem.getSoseq()+"]so=["+cutItem.getSo()+"]的["+cutItem.getSlotlocation()+"] 数量:" + preBindQty +"/" + cutItem.getQty());
}
if(!barcode.hasCutInfo()){
......@@ -164,8 +164,8 @@ public class OutInfoCache {
//未执行过的或任务已完成的才可以执行
if(unEndOutInfo.isTaskEnd() || unEndOutInfo.isNew()){
long lastEndTime = unEndOutInfo.getTaskEndTime();
//距离上次任务完成2分钟后才可再次执行
if(now - lastEndTime >= 2 * 60 * 1000){
//距离上次任务完成5分钟后才可再次执行
if(now - lastEndTime >= 5 * 60 * 1000){
checkOutOutItems(unEndOutInfo.gethSerial());
}
}
......@@ -380,7 +380,15 @@ public class OutInfoCache {
Barcode barcode = storagePos.getBarcode();
count = count + 1;
log.info("解除["+barcode.getBarcode()+"]的工单so=["+barcode.getAppendInfo().getSo()+"]soseq=["+barcode.getAppendInfo().getSoseq()+"]绑定,累计解除"+count);
storagePosDao.unbindReel(storagePos);
storagePos = storagePosDao.unbindReel(storagePos);
barcode = storagePos.getBarcode();
barcode = bindPutInReel(barcode);
String bindSoseq = barcode.getAppendInfo().getSoseq();
if(!Strings.isEmpty(bindSoseq)){
log.info("料盘["+barcode.getBarcode()+"]绑定到新工单soseq="+bindSoseq);
storagePos.setBarcode(barcode);
storagePosDao.save(storagePos);
}
}
return ResultBean.newOkResult("解除工单soseq=["+soseq+"]绑定,累计解除["+count+"]盘物料","");
}
......
......@@ -329,7 +329,7 @@ public class QisdaBindService {
*/
public void unbindSurplusReel(OutItem outItem){
//多出数量
int surplusQty = outItem.getSendQty() + outItem.getRealLockQty() - outItem.getQty();
int surplusQty = /*outItem.getSendQty() + */outItem.getRealLockQty() - outItem.getQty();
if(surplusQty > 0){
//已经预绑定的所有料盘中与最大盘日期相同,且与超出数量最接近的料盘剔除掉
StoragePos maxBindReelPos = storagePosDao.findMaxQtyBindReel(outItem.getSoseq(), outItem.getSlotlocation());
......@@ -344,6 +344,11 @@ public class QisdaBindService {
outItem.setRealLockQty(newRealLockQty);
//outItem = outItemDao.save(outItem);
soseqCache.updateTotalRealLockQty(outItem, newRealLockQty);
int newPreBindQty = outItem.getLockQty() - unbindAmount;
outItem.setLockQty(newPreBindQty);
soseqCache.udpateTotalPreLockQty(outItem, newPreBindQty);
surplusQty = outItem.getSendQty() + outItem.getRealLockQty() - outItem.getQty();
if(surplusQty > 0){
unbindSurplusReel(outItem);
......
......@@ -612,7 +612,9 @@ public class QisdaDeviceController extends BaseController {
AppendInfo appendInfo = task.getAppendInfo();
//完成任务数量+1
outInfoCache.incTaskFinishNum(appendInfo.gethSerial(), 0, 0);
if(!task.isLessSendReel()){
outInfoCache.incTaskFinishNum(appendInfo.gethSerial(), 0, 0);
}
appendInfo.setRfid(rfid);
int loc = task.resolveRfidLoc(rfidLoc);
......@@ -723,7 +725,11 @@ public class QisdaDeviceController extends BaseController {
task.setStatus(statusStr);
task.setLocInfo(locInfo);
task = dataLogDao.save(task);
taskService.updateFinishedTask(task);
if(!task.isStopSendToQisda()){
//未关闭
taskService.updateFinishedTask(task);
}
//包装料
......@@ -1022,15 +1028,6 @@ public class QisdaDeviceController extends BaseController {
public ResultBean getShelfLockInfo(HttpServletRequest request){
String rfid = request.getParameter("rfid");
List<ReelLockPosInfo> shelfLockInfoList = QisdaCache.getShelfLockPosInfo(rfid);
ReelLockPosInfo shelfLockInfo = new ReelLockPosInfo();
shelfLockInfo.setBarcode("S20052301213");
shelfLockInfo.setCid("packing-20");
shelfLockInfo.setRfidLoc("3");
shelfLockInfo.setRfid("A12");
shelfLockInfo.setLockPosId("1231");
shelfLockInfo.setLockPos("4D2001AA0006");
shelfLockInfoList.add(shelfLockInfo);
return ResultBean.newOkResult(shelfLockInfoList);
}
......@@ -1039,7 +1036,7 @@ public class QisdaDeviceController extends BaseController {
*/
@RequestMapping(value = "/emptyStoragePosCount")
@ResponseBody
public Object emptyStoragePosCount(HttpServletRequest request) {
public ResultBean emptyStoragePosCount(HttpServletRequest request) {
Map<String,Object> resultMap = new HashMap<>();
try {
Map<String, Storage> allStorage = dataCache.getAllStorage();
......@@ -1056,4 +1053,40 @@ public class QisdaDeviceController extends BaseController {
return ResultBean.newOkResult(resultMap);
}
/**
* 包装线AGV获取料架中的任务数,如果当前料架的任务数不为0,需要用当前料架去其他包装仓继续放料
*/
@RequestMapping(value = "/shelfTaskCount")
@ResponseBody
public ResultBean taskInShelf(HttpServletRequest request){
String rfid = request.getParameter("rfid");
ShelfInfo shelfInfo = InquiryShelfBean.findShelf(rfid);
int taskCount = 0;
if(shelfInfo != null){
Map<Integer, ShelfLoc> locMap = shelfInfo.getLocMap();
for (ShelfLoc shelfLoc : locMap.values()) {
if(shelfLoc.isEmpty()){
taskCount = taskCount + 1;
}
}
}
Map<String,Object> resultMap = new HashMap<>();
resultMap.put("taskCount",taskCount);
resultMap.put("rfid",rfid);
return ResultBean.newOkResult(resultMap);
}
/**
* 库位物料检测接口
*/
@RequestMapping(value = "/posReelCheck")
@ResponseBody
public ResultBean posReelCheck(HttpServletRequest request){
String cid = request.getParameter("cid");
String posName = request.getParameter("pos");
String hasReel = request.getParameter("hasReel");
return ResultBean.newOkResult("");
}
}
......@@ -84,13 +84,13 @@ public class StorageDataController extends BaseController {
@RequestMapping(value = "/testEmail")
@ResponseBody
public String testEmail(HttpServletRequest request){
String expire = request.getParameter("expire");
if(Strings.isNullOrEmpty(expire)){
return expireMailUtil.sendTestMail();
}else{
return expireMailUtil.sendExpireMail();
}
public List<StoragePos> testEmail(HttpServletRequest request){
String b = request.getParameter("b");
Barcode barcode = barcodeManager.findByBarcode(b);
Collection<Storage> allStorage = dataCache.getAllStorage().values();
List<StoragePos> posList = storagePosManager.getEmptyPosList(new ArrayList<Storage>(allStorage), barcode, new ArrayList<String>());
return posList;
}
@RequestMapping(value = "/countExpirePcb")
......@@ -576,19 +576,36 @@ public class StorageDataController extends BaseController {
}
}
if(storageList.isEmpty()){
resultMap.put("result","102");
resultMap.put("result","99");
errorMsg = "无可用的料仓";
resultMap.put("msg",errorMsg);
}else{
try {
Barcode barcode = dataCache.resolveOneValideBarcode(code);
String lockPosId = QisdaCache.getReelLockPosId(barcode.getBarcode());
StoragePos pos;
StoragePos pos = null;
if(!Strings.isNullOrEmpty(lockPosId)){
//已有锁定库位
pos = storagePosManager.get(lockPosId);
log.info("条码["+barcode.getBarcode()+"]已锁定库位["+pos.getPosName()+"],返回锁定中的库位");
}else{
if(pos != null ){
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){
pos = taskService.findEmptyPosForPutIn(storageList,barcode, rfid);
}
......@@ -614,6 +631,7 @@ public class StorageDataController extends BaseController {
resultMap.put("result","104");
errorMsg = "未找到可用的["+barcode.getPlateSize() + "x" + barcode.getHeight()+"]仓位";
resultMap.put("msg",errorMsg);
}
} catch (ValidateException e) {
errorMsg = e.getMessage();
......
......@@ -240,8 +240,10 @@ public class TaskService implements ITaskService {
public StatusBean putInLine(Storage storage, StatusBean statusBean){
String errorMsg = "";
String barcode = statusBean.getCode();
String opBarcode = barcode;
try {
Barcode barcodeSave = dataCache.resolveOneValideBarcode(barcode);
opBarcode = barcodeSave.getBarcode();
//入库时的RFID
String inRFID = statusBean.getInRfid();
verifyBarcodePutIn(Lists.newArrayList(storage),barcodeSave,inRFID);
......@@ -286,7 +288,7 @@ public class TaskService implements ITaskService {
throw new ValidateException("库位【"+posName+"】与料仓["+storage.getCid()+"]不匹配,无法入库");
};
if(storagePos.getBarcode() != null){
throw new ValidateException("库位【"+posName+"】中已有物料,无法入库");
throw new ValidateException("库位【"+posName+"】中已有物料["+storagePos.getBarcode().getBarcode()+"],无法入库");
}
if(!storage.canPutInPos(barcodeSave.getPlateSize(),barcodeSave.getHeight(), storagePos.getW(), storagePos.getH())){
......@@ -353,6 +355,7 @@ public class TaskService implements ITaskService {
String msg = "["+barcode+"]"+errorMsg;
alarmInfo.setAlarmMsg(msg);
alarmInfoDao.save(alarmInfo);
QisdaCache.removeReelLockPosInfo(opBarcode);
}
return statusBean;
......@@ -522,6 +525,7 @@ public class TaskService implements ITaskService {
availbleStorageList.add(storage);
}
}
if(availbleStorageList.isEmpty()){
throw new ValidateException("料仓列表中未找到可用的料仓");
}
......@@ -760,22 +764,31 @@ public class TaskService implements ITaskService {
if(task != null && task.isCheckOutTask()){
log.info("清除任务["+task.getBarcode()+"]");
//发送取消(发料)指令到佳世达
AppendInfo taskAppendInfo = task.getAppendInfo();
boolean stopSendToQisda = task.isStopSendToQisda();
finishedTaskMap.remove(task.getBarcode());
task.setStopSendToQisda(true);
task = dataLogDao.save(task);
//发送取消(发料)指令到佳世达
AppendInfo taskAppendInfo = task.getAppendInfo();
if(taskAppendInfo.isFirstReelAction() || taskAppendInfo.isTailAction()){
Barcode barcode = barcodeManager.findByBarcode(task.getBarcode());
log.info("["+task.getBarcode()+"]任务已出库完成,但未放上小车,发送E状态到佳世达,同时解除料架架位,发料任务完成数量+1");
OutInfo outInfo = outInfoCache.incTaskFinishNum(taskAppendInfo.gethSerial(), 0, 0);
if(outInfo != null) {
InquiryShelfBean.cancelReelTask(task);
QisdaApi.VMIMateriaRecAss(task, barcode, "E");
if(!task.isLessSendReel()){
//缺料重发的不需要进行发料(已在出库进行过发料)
if(taskAppendInfo.isFirstReelAction() || taskAppendInfo.isTailAction()){
if(!stopSendToQisda){
Barcode barcode = barcodeManager.findByBarcode(task.getBarcode());
log.info("["+task.getBarcode()+"]任务已出库完成,但未放上小车,发送E状态到佳世达,同时解除料架架位,发料任务完成数量+1");
OutInfo outInfo = outInfoCache.incTaskFinishNum(taskAppendInfo.gethSerial(), 0, 0);
if(outInfo != null) {
InquiryShelfBean.cancelReelTask(task);
QisdaApi.VMIMateriaRecAss(task, barcode, "E");
}
}
}else if(taskAppendInfo.isUrgentAction()){
//紧急料,增加任务完成数量
}
}
}
}
......@@ -1940,6 +1953,7 @@ public class TaskService implements ITaskService {
}
if (latest.equals("L")) {
log.info("工单[" + outItem.getSo() + "]需求单["+outItem.gethSerial()+"]的最后一盘出库完成,发送缺料通知");
List<OutItem> outItemList = outItemDao.findByHSerial(outItem.gethSerial());
boolean lessBind = false;
......
......@@ -139,7 +139,7 @@
'需求单:'+ outInfo.hSerial+' ['+outInfo.action+'] 工单: ' + outInfo.so +' 备料单: ' + outInfo.refno + '[' + outInfo.sendStatus +'] 工单序号:' + outInfo.soseq +
'<span class="right">建议时间: '+sdate+'</span>' +
'<span class="right">必须时间: '+mdate+'</span>' +
'<span class="right">['+outInfo.firstExecuteTime+']</span>' +
//'<span class="right">['+outInfo.firstExecuteTime+']</span>' +
'</a></h4></div>' +
'<div id="'+outInfo.hSerial+'" class="panel-collapse collapse">' +
'<div class="panel-body">' +
......@@ -162,7 +162,7 @@
for(var i in data){
var outInfo = data[i];
var infoHtml = getOutInfoHtml(outInfo);
if(outInfo.executing || outInfo.sendLess){
if(outInfo.executing || outInfo.sendLess || outInfo.firstExecuteTime > 0){
executingHtml = executingHtml + infoHtml;
}else if(outInfo.priority){
priorityHtml = priorityHtml + infoHtml;
......
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!