Commit ea58a9ac sunke

1 自动绑定逻辑:a)按soseq对需求单进行一次绑定 b)入库时对料盘进行绑定

2  自动出库逻辑: 分盘料,指定料直接出库, 首盘和补料根据建议时间和必须出库时间进行出库(出库到料架上)
3  缺料重发: 首盘和补料缺料时,自动重发到料串上
4  完成任务数比分配任务多的问题修正(机器人正在放料时又进行了扫码)
5  维护料盘厚度与实测厚度不一致时,到机器人扫码位NG的问题(修改为只有在入库时与维护料盘尺寸进行比对,出库时不比对)
6  DN单绑定信息保持(更新不影响已绑定的料串)
7  机器人料架信息保持(更新不影响正在出库的工单)
8  料串信息保持(更新不影响分盘料/指定料/缺料重发)
9  出入库任务保持(更新会记录更新前的任务,更新后继续之前的任务)
10 料盘尺寸与维护尺寸不一致时的提示信息
1 个父辈 6da4a903
正在显示 37 个修改的文件 包含 1682 行增加1624 行删除
......@@ -3,6 +3,7 @@ package com.myproject.bean.qisda;
import com.myproject.bean.update.DataLog;
import com.myproject.bean.update.qisda.OutItem;
import com.myproject.util.StorageConstants;
import com.myproject.webapp.controller.webService.QisdaCache;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
......@@ -29,7 +30,13 @@ public class InquiryShelfBean {
/**
* 料架管理Map, key为 hSerial, value的key为 tempRfid, value为料架
*/
public static Map<String,Map<String,ShelfInfo>> hSerialShelfMap = new ConcurrentHashMap<>();
public static Map<String,Map<String,ShelfInfo>> hSerialShelfMap;
public static void initShelfMap(){
if(hSerialShelfMap == null){
hSerialShelfMap = QisdaCache.loadShelfMap();
}
}
/**
* 清理使用过的料架
......@@ -40,6 +47,7 @@ public class InquiryShelfBean {
if(shelfMap != null){
log.info("清理["+hSerial+"]使用的过料架");
hSerialShelfMap.remove(hSerial);
QisdaCache.saveShelfMap(hSerialShelfMap);
}
}
}
......@@ -56,6 +64,7 @@ public class InquiryShelfBean {
shelfMap.remove(tempRfid);
hSerialShelfMap.put(hSerial, shelfMap);
clearResult = true;
QisdaCache.saveShelfMap(hSerialShelfMap);
}
}
}
......@@ -216,8 +225,8 @@ public class InquiryShelfBean {
if(task.isPackageReel()){
shelfType = StorageConstants.SHEFL_TYPE.A;
}else {
//需要分盘的料,且不是包装料,统一都放到料串上
if(task.isCutReel() || task.isUrgentReel()){
//需要分盘的料或紧急料或者缺料补发的料,且不是包装料,统一都放到料串上
if(task.isCutReel() || task.isUrgentReel() || task.isLessSendReel()){
//B料串
return StorageConstants.SHEFL_TYPE.B;
}else{
......@@ -242,7 +251,6 @@ public class InquiryShelfBean {
Map<String, ShelfInfo> shelfMap = hSerialShelfMap.get(hSerial);
int rfidIndex = 0;
if(shelfMap != null){
for (ShelfInfo shelfInfo : shelfMap.values()) {
if(StorageConstants.SHEFL_TYPE.judgeType(shelfInfo.getShelfType(), shelfType)){
if(shelfInfo != null && !shelfInfo.reachMaxLoc()){
......@@ -283,6 +291,7 @@ public class InquiryShelfBean {
}
shelfMap.put(shelfInfo.tempRfid(), shelfInfo);
hSerialShelfMap.put(hSerial, shelfMap);
QisdaCache.saveShelfMap(hSerialShelfMap);
}
private static synchronized DataLog addLoc(DataLog task, OutItem outItem, String barcode){
......@@ -316,10 +325,18 @@ public class InquiryShelfBean {
if(barcode != null && !barcode.isEmpty()){
appendInfo.setRfidLoc(loc);
}
String location = shelfType;
if(outItem.isFirstReelAction() && !task.isLessSendReel()){
location = emptyShelfInfo.getRfidIndex() + shelfType + "_" + loc;
}else if(task.isLessSendReel()){
int showLoc = task.resolveRfidLoc(loc+"");
location = shelfType + "_" + showLoc;
}
task.setSubSourceInfo(location);
task.setAppendInfo(appendInfo);
//非分盘和非紧急料的包装料需要在C型料架上预留位置
if(task.isPackageReel() && !task.isCutReel() && !task.isUrgentReel()){
//非分盘和非紧急料和非缺料补发的包装料需要在C型料架上预留位置
if(task.isPackageReel() && !task.isCutReel() && !task.isUrgentReel() && !task.isLessSendReel()){
String cShelf = StorageConstants.SHEFL_TYPE.C;
ShelfInfo packageCShelf = getOrAddShelfInfo(hSerial, cShelf);
int packageCLoc = packageCShelf.addLimitLoc(barcode, StorageConstants.REEL_TYPE.PACKAGE);
......@@ -363,7 +380,7 @@ public class InquiryShelfBean {
* @param bigRfid
* @return
*/
public ShelfInfo findBigShelf(String bigRfid){
public static ShelfInfo findBigShelf(String bigRfid){
if(bigRfid == null){
return null;
}
......@@ -398,7 +415,7 @@ public class InquiryShelfBean {
* @param packageRfid
* @return
*/
public ShelfInfo findPackageShelf(String hSerial, String packageRfid){
public static ShelfInfo findPackageShelf(String hSerial, String packageRfid){
if(packageRfid == null || packageRfid.isEmpty()){
return null;
}
......@@ -420,7 +437,7 @@ public class InquiryShelfBean {
* 获取某个需求单已经绑定的RFID
* @param hSerial 需求单号
*/
public List<String> getUsedRfidList(String hSerial){
public static List<String> getUsedRfidList(String hSerial){
List<String> usedRfidList = new ArrayList<>();
Map<String, ShelfInfo> shelfMap = hSerialShelfMap.get(hSerial);
if(shelfMap != null){
......@@ -437,7 +454,7 @@ public class InquiryShelfBean {
/**
* 首套料,获取分配好的库位
*/
public ShelfLoc getLimitLoc(DataLog task){
public static ShelfLoc getLimitLoc(DataLog task){
AppendInfo appendInfo = task.getAppendInfo();
String barcode = task.getBarcode();
String hSerial = appendInfo.gethSerial();
......@@ -458,7 +475,7 @@ public class InquiryShelfBean {
return null;
}
public ShelfInfo findMaxUsedShelf(String hSerial, String shelfType){
public static ShelfInfo findMaxUsedShelf(String hSerial, String shelfType){
Map<String, ShelfInfo> shelfMap = hSerialShelfMap.get(hSerial);
if(shelfMap == null){
return null;
......@@ -490,7 +507,7 @@ public class InquiryShelfBean {
/**
* 锁定架位
*/
public synchronized ShelfLoc lockShelfLoc(DataLog task, String rfid, String robotIndex){
public static synchronized ShelfLoc lockShelfLoc(DataLog task, String rfid, String robotIndex){
AppendInfo appendInfo = task.getAppendInfo();
String hSerial = appendInfo.gethSerial();
ShelfInfo shelfInfo = null;
......@@ -579,15 +596,17 @@ public class InquiryShelfBean {
String barcode = task.getBarcode();
String hSerial = appendInfo.gethSerial();
Map<String, ShelfInfo> shelfMap = hSerialShelfMap.get(hSerial);
if(shelfMap == null){
log.warn("["+task.getBarcode()+"]任务取消时未找到对应需求单["+hSerial+"]的料架缓存信息");
return;
}
if(appendInfo.isFirstReelAction()){
//首盘料,解除绑定的位置
if(shelfMap != null){
for (ShelfInfo shelfInfo : shelfMap.values()) {
boolean result = shelfInfo.cancelLimitLoc(barcode);
if(result){
log.info("首盘料["+task.getBarcode()+"]任务取消,解除料架" + shelfInfo.tempRfid() +"锁定架位绑定");
updateShelfInfo(shelfInfo);
}
for (ShelfInfo shelfInfo : shelfMap.values()) {
boolean result = shelfInfo.cancelLimitLoc(barcode);
if(result){
log.info("首盘料["+task.getBarcode()+"]任务取消,解除料架" + shelfInfo.tempRfid() +"锁定架位绑定");
updateShelfInfo(shelfInfo);
}
}
}else if(appendInfo.isTailAction()){
......@@ -634,7 +653,7 @@ public class InquiryShelfBean {
/**
* 紧急料/分盘料放入料架或料串
*/
public synchronized ShelfLoc putInCutReel(DataLog task, String rfid, int loc){
public static synchronized ShelfLoc putInCutReel(DataLog task, String rfid, int loc){
String barcode = task.getBarcode();
String shelfMapKey = task.getShelfMapKey();
Map<String, ShelfInfo> shelfMap = hSerialShelfMap.get(shelfMapKey);
......@@ -689,7 +708,7 @@ public class InquiryShelfBean {
return null;
}
public synchronized boolean putInShelf(DataLog task, String rfid, int loc){
public static synchronized boolean putInShelf(DataLog task, String rfid, int loc){
AppendInfo appendInfo = task.getAppendInfo();
String barcode = task.getBarcode();
String hSerial = appendInfo.gethSerial();
......
......@@ -12,21 +12,31 @@ public class ResultBean {
protected final static Logger log = LogManager.getLogger(ResultBean.class);
public static ResultBean newErrorResult(int code, String msg){
return newErrorResult(code, msg, true);
}
public static ResultBean newErrorResult(int code, String msg, boolean writeLog){
ResultBean result = new ResultBean();
result.setCode(code);
result.setMsg(msg);
log.info(msg);
if(writeLog){
log.info(msg);
}
return result;
}
public static ResultBean newOkResult(Object data){
public static ResultBean newOkResult(String msg, Object data){
ResultBean result = new ResultBean();
result.setCode(0);
result.setMsg("ok");
result.setMsg(msg);
result.setData(data);
return result;
}
public static ResultBean newOkResult(Object data){
return newOkResult("ok", data);
}
/**
* 结果码,0为正常,其他值表示异常
*/
......
......@@ -13,9 +13,12 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class ShelfInfo {
protected final Logger log = LogManager.getLogger(ShelfInfo.class);
private final static Logger log = LogManager.getLogger(ShelfInfo.class);
public ShelfInfo(String shelfType, int locCount) {
public ShelfInfo() {
}
private ShelfInfo(String shelfType, int locCount) {
this.shelfType = shelfType;
this.maxLocCount = locCount;
}
......@@ -235,13 +238,21 @@ public class ShelfInfo {
public boolean cancelLimitLoc(String barcode){
for (ShelfLoc shelfLoc : locMap.values()) {
if(shelfLoc.isInThisLoc(barcode)){
if(shelfLoc.isEmpty()){
shelfLoc.putIn(barcode);
if(isAShelf()){
//A料架,需要清空
shelfLoc.setEmpty(true);
locMap.put(shelfLoc.getLoc(), shelfLoc);
log.error("料盘["+barcode+"]解除绑定架位"+tempRfid()+"["+shelfLoc.getLoc()+"]成功");
return true;
}else {
log.error("料盘["+barcode+"]解除绑定架位"+shelfLoc.getTempRfid()+"["+shelfLoc.getLoc()+"]失败,此位置料盘已放入");
return false;
}else{
if(shelfLoc.isEmpty()){
shelfLoc.putIn(barcode);
locMap.put(shelfLoc.getLoc(), shelfLoc);
return true;
}else {
log.error("料盘["+barcode+"]解除绑定架位"+tempRfid()+"["+shelfLoc.getLoc()+"]失败,此位置料盘已放入");
return false;
}
}
}
}
......
......@@ -645,18 +645,6 @@ public class Barcode extends BaseMongoBean {
}
return true;
}
public boolean needToQisda(){
// if(appendInfo == null){
// return false;
// }else{
// String facility = appendInfo.getFacility();
// if(facility != null && facility.contains("AAA")){
// return false;
// }
// }
return true;
}
}
......@@ -68,6 +68,11 @@ public class DataLog extends BaseMongoBean /*implements Comparable<DataLog>*/ {
private boolean urgentReel = false;
/**
* 缺料补发(使用料串)
*/
private boolean lessSendReel = false;
/**
* 是否是包装料卷
*/
private boolean packageReel;
......@@ -378,7 +383,7 @@ public class DataLog extends BaseMongoBean /*implements Comparable<DataLog>*/ {
if (!Strings.isNullOrEmpty(sourceName)){
sourceStr = sourceName;
if(!Strings.isNullOrEmpty(subSourceInfo)){
sourceStr = sourceName + "【"+subSourceInfo+"】";
sourceStr = sourceName + " ["+subSourceInfo+"]";
}
}
return sourceStr;
......@@ -493,6 +498,18 @@ public class DataLog extends BaseMongoBean /*implements Comparable<DataLog>*/ {
this.appendInfo = appendInfo;
}
public int resolveRfidLoc(String loc){
int rfidLoc = Integer.valueOf(loc);
if(isLessSendReel()){
if(appendInfo.isFirstReelAction()){
rfidLoc = 1;
}else if(appendInfo.isTailAction()){
rfidLoc = 2;
}
}
return rfidLoc;
}
public int getH() {
return h;
}
......@@ -543,6 +560,14 @@ public class DataLog extends BaseMongoBean /*implements Comparable<DataLog>*/ {
this.urgentReel = urgentReel;
}
public boolean isLessSendReel() {
return lessSendReel;
}
public void setLessSendReel(boolean lessSendReel) {
this.lessSendReel = lessSendReel;
}
/**
* 获取物料类型,大料小料或者包装料
* @return
......
......@@ -169,6 +169,11 @@ public class Settings extends BaseMongoBean {
*/
private boolean stopOut = false;
/**
* 停止定时器任务
*/
private boolean stopJob = false;
public Date getLastPcbCheckDate() {
return lastPcbCheckDate;
}
......@@ -400,5 +405,13 @@ public class Settings extends BaseMongoBean {
public void setStopOut(boolean stopOut) {
this.stopOut = stopOut;
}
public boolean isStopJob() {
return stopJob;
}
public void setStopJob(boolean stopJob) {
this.stopJob = stopJob;
}
}
......@@ -68,7 +68,7 @@ public class OutInfo extends BaseMongoBean {
/**
* 绑定状态:0=未绑定 1=绑定缺料 2=绑定OK
*/
private int bindStatus = 0;
private int bindStatus = StorageConstants.BIND_STATUS.NO_BIND;
/**
* 发料状态: 0=未发料 1=发料缺料 2=发料OK(需求单完成):首盘和补料,发料与需求单一致为发料OK, 分盘料出库后又入库即真实绑定与需求量一致为发料OK, 紧急料出库数量与需求数量一致为发料OK
......@@ -85,6 +85,11 @@ public class OutInfo extends BaseMongoBean {
*/
private int taskFinishNum;
/**
* 第一次执行的时间,如果为0表示未执行过,如果小于0表示要优先执行,越小越优先
*/
private long firstExecuteTime;
@Transient
private Map<String, OutItem> outItemMap = new HashMap<>();
......@@ -162,6 +167,20 @@ public class OutInfo extends BaseMongoBean {
}
}
public OutItem findOutItem(int slotSeq){
for (OutItem outItem : getOutItems()) {
if(outItem.getSlotlocation() == slotSeq){
return outItem;
}
}
return null;
}
public OutItem findOutItemById(String outItemId){
return outItemMap.get(outItemId);
}
/**
* 分盘需求单
*/
......@@ -240,6 +259,17 @@ public class OutInfo extends BaseMongoBean {
this.bindStatus = bindStatus;
}
/**
* 真实绑定OK
*/
public boolean isRealBindOk(){
return this.bindStatus == StorageConstants.BIND_STATUS.REAL_BIND_OK;
}
public boolean isRealBindLess(){
return this.bindStatus == StorageConstants.BIND_STATUS.REAL_BIND_LESS;
}
public int getSendStatus() {
return sendStatus;
}
......@@ -269,7 +299,28 @@ public class OutInfo extends BaseMongoBean {
* 是否正在执行
*/
public boolean isExecuting(){
return taskNum > 0 && sendStatus == StorageConstants.SEND_STATUS.EXECUTING;
return sendStatus == StorageConstants.SEND_STATUS.EXECUTING;
}
/**
* 是否是新的需求单
*/
public boolean isNew(){
return sendStatus == StorageConstants.SEND_STATUS.NEW;
}
/**
* 是否是发料缺料的需求单
*/
public boolean isSendLess(){
return sendStatus == StorageConstants.SEND_STATUS.SEND_LESS;
}
/**
* 是否是需要优先执行的
*/
public boolean isPriority(){
return firstExecuteTime < 0;
}
public void setSendStatus(int sendStatus) {
......@@ -296,6 +347,22 @@ public class OutInfo extends BaseMongoBean {
this.soseq = soseq;
}
public long getFirstExecuteTime() {
return firstExecuteTime;
}
public void setFirstExecuteTime(long firstExecuteTime) {
this.firstExecuteTime = firstExecuteTime;
}
public boolean updateExecuteTime(long executeTime){
if(this.firstExecuteTime <= 0){
setFirstExecuteTime(executeTime);
return true;
}
return false;
}
@Override
public String toString() {
return "OutInfo{" +
......
......@@ -103,6 +103,11 @@ public class OutItem extends BaseMongoBean {
private int qty;
/**
* 补料时如果首盘没出,需要修正需求单的数量
*/
private int fixedQty;
/**
* 已出数量
*/
private int outQty;
......@@ -118,7 +123,7 @@ public class OutItem extends BaseMongoBean {
private int realLockQty;
/**
* 发料数量(放上小车的数量)
* 发料数量(放上小车的数量),分盘需求单中的发料数量是指整个soseq工单的发料数量
*/
private int sendQty;
......@@ -133,7 +138,7 @@ public class OutItem extends BaseMongoBean {
* 发料缺料
*/
public int sendLessQty(){
return qty - sendQty;
return getFixedQty() - sendQty;
}
/**
......@@ -289,13 +294,14 @@ public class OutItem extends BaseMongoBean {
//发料完成才算
return getSendQty() > 0;
}else if(isReelCutAction()){
//分盘需求,分盘料真实绑定与需求数相同,即认为完成
if(isCutMaterial()){
return realBindLessQty() <= 0;
}else{
//非分盘料
return true;
}
// //分盘需求,分盘料真实绑定与需求数相同,即认为完成
// if(isCutMaterial()){
// return realBindLessQty() <= 0;
// }else{
// //非分盘料
// return true;
// }
return sendLessQty() <= 0;
}else if(isUrgentAction()){
//紧急料,出库数量大于需求数量
......@@ -441,4 +447,16 @@ public class OutItem extends BaseMongoBean {
public void setSendQty(int sendQty) {
this.sendQty = sendQty;
}
public int getFixedQty() {
if(fixedQty == 0){
fixedQty = qty;
return fixedQty;
}
return fixedQty;
}
public void setFixedQty(int fixedQty) {
this.fixedQty = fixedQty;
}
}
......@@ -123,6 +123,11 @@ public abstract class AbstractMongoDao implements IMongoDao {
}
@Override
public void upsert(Query query, Update update){
getMongoTemplate().upsert(query,update, getEntityClass());
}
@Override
public PageList findByQuery(Query query, PageList pageList) {
String sortProperties = pageList.getSortCriterion();
if(sortProperties != null && !sortProperties.isEmpty()){
......
......@@ -30,10 +30,7 @@ public interface IDataLogDao extends IMongoDao {
DataLog findLastOut(String areaId, String barcode);
/**
* 查找未 执行的站位列表任务
*/
List<DataLog> findUnExecuteTasks(StorageConstants.TASK_SOURCE taskSource, String sourceId);
List<DataLog> findUnFinishedTasks(String hSerial);
List<InventoryItem> getStorageLockCount(String storageId);
......
......@@ -54,6 +54,8 @@ public interface IMongoDao {
void updateFirst(Query query, Update update);
void upsert(Query query, Update update);
PageList findByQuery(Query query, PageList pageList);
}
......@@ -60,7 +60,7 @@ public interface IStoragePosDao extends IMongoDao {
/**
* 获取工单的所有预绑定料盘
*/
List<StoragePos> findPreBindList(String so, int slotlocation);
List<StoragePos> findPreBindList(String soseq, int slotlocation);
StoragePos findSurplusPreBindReel(String soseq, int slotlocation, int surplusQty, String produceDateStr);
......@@ -73,12 +73,10 @@ public interface IStoragePosDao extends IMongoDao {
/**
* 获取工单的所有绑定料盘
*/
List<StoragePos> findBindList(String so, int slotlocation);
List<StoragePos> findBindList(String soseq, int slotlocation);
List<StoragePos> findBindByPn(String soseq, String pn);
List<StoragePos> allBindPos(String so);
List<StoragePos> listSoSeqBindPos(String soseq);
StoragePos findByBarcode(String barcode);
......
......@@ -99,11 +99,9 @@ public class DataLogDaoImpl extends AbstractMongoDao implements IDataLogDao {
return findOne(query);
}
@Override
public List<DataLog> findUnExecuteTasks(StorageConstants.TASK_SOURCE taskSource, String sourceId) {
Query query = Query.query(Criteria.where("sourceId").is(sourceId)
.and("sourceType").is(taskSource.name())
.and("status").in(StorageConstants.OP_STATUS.WAIT.name(),StorageConstants.OP_STATUS.EXECUTING.name(),StorageConstants.OP_STATUS.PAUSE.name()));
private List<DataLog> findUnExecuteTasks(String executingHSerial) {
Criteria c = Criteria.where("appendInfo.hSerial").ne(executingHSerial).and("status").in(StorageConstants.OP_STATUS.WAIT.name(),StorageConstants.OP_STATUS.EXECUTING.name(),StorageConstants.OP_STATUS.PAUSE.name());
Query query = Query.query(c);
List<DataLog> feederTasks = findByQuery(query);
if(feederTasks == null){
feederTasks = new ArrayList<>();
......@@ -112,6 +110,21 @@ public class DataLogDaoImpl extends AbstractMongoDao implements IDataLogDao {
}
@Override
public List<DataLog> findUnFinishedTasks(String executingHSerial){
Criteria c = Criteria.where("appendInfo.hSerial").is(executingHSerial).and("lessSendReel").is(false).and("status").nin(StorageConstants.OP_STATUS.FINISHED.name(),StorageConstants.OP_STATUS.CANCEL.name());
Query query = Query.query(c);
List<DataLog> unFinishedTasks = findByQuery(query);
if(unFinishedTasks == null){
unFinishedTasks = new ArrayList<>();
}
List<DataLog> unExecuteTasks = findUnExecuteTasks(executingHSerial);
for (DataLog unExecuteTask : unExecuteTasks) {
unFinishedTasks.add(unExecuteTask);
}
return unFinishedTasks;
}
@Override
public List<InventoryItem> getStorageLockCount(String storageId){
//被锁定的仓位
Criteria c = Criteria.where("sourceType").is(StorageConstants.TASK_SOURCE.FEEDER.name()).and("storageId").is(storageId)
......
......@@ -19,6 +19,7 @@ import com.myproject.exception.ValidateException;
import com.myproject.util.PLATE_SIZE;
import com.myproject.util.StorageConstants;
import com.myproject.util.StringHelper;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
......@@ -311,9 +312,9 @@ public class StoragePosDaoImpl extends AbstractMongoDao implements IStoragePosDa
* 获取工单的站位所有预绑定料盘
*/
@Override
public List<StoragePos> findPreBindList(String so, int slotlocation) {
public List<StoragePos> findPreBindList(String soseq, int slotlocation) {
String bindSlot = "" + slotlocation;
Criteria c = Criteria.where("barcode.appendInfo.so").is(so).and("barcode.appendInfo.preBindSlot").is(bindSlot).and("barcode.appendInfo.bindSlot").is(null);
Criteria c = Criteria.where("barcode.appendInfo.soseq").is(soseq).and("barcode.appendInfo.preBindSlot").is(bindSlot).and("barcode.appendInfo.bindSlot").is(null);
Query q = new Query(c);
q.with(new Sort(Sort.Direction.ASC, "barcode.amount"));
return findByQuery(q);
......@@ -395,9 +396,9 @@ public class StoragePosDaoImpl extends AbstractMongoDao implements IStoragePosDa
* 获取工单的所有绑定料盘
*/
@Override
public List<StoragePos> findBindList(String so, int slotlocation) {
public List<StoragePos> findBindList(String soseq, int slotlocation) {
String bindSlot = "" + slotlocation;
Criteria c = Criteria.where("barcode.appendInfo.so").is(so).and("barcode.appendInfo.bindSlot").is(bindSlot);
Criteria c = Criteria.where("barcode.appendInfo.soseq").is(soseq).and("barcode.appendInfo.bindSlot").is(bindSlot);
//去除的仓位
Query q = new Query(c);
q.with(new Sort(Sort.Direction.ASC, "barcode.amount"));
......@@ -422,17 +423,10 @@ public class StoragePosDaoImpl extends AbstractMongoDao implements IStoragePosDa
* 获取工单的所有绑定料盘
*/
@Override
public List<StoragePos> allBindPos(String so) {
Criteria c = Criteria.where("barcode.appendInfo.so").is(so);
Query q = new Query(c);
return findByQuery(q);
}
/**
* 获取工单的所有绑定料盘
*/
@Override
public List<StoragePos> listSoSeqBindPos(String soseq) {
if(Strings.isBlank(soseq)){
return new ArrayList<>();
}
Criteria c = Criteria.where("barcode.appendInfo.soseq").is(soseq);
Query q = new Query(c);
return findByQuery(q);
......
......@@ -10,6 +10,8 @@ public interface IOutInfoDao extends IMongoDao {
OutInfo findByHSerial(String hSerial);
OutInfo findCutActionOutInfo(String soseq);
List<OutInfo> listBySo(String so);
List<OutInfo> listBySoSeq(String soseq);
......@@ -21,4 +23,6 @@ public interface IOutInfoDao extends IMongoDao {
void updateTaskFinishNum(String hSerail, int taskFinishNum);
void updateOutReelNum(String hSerial, int outReelNum);
void updateExecuteTime(String hSerial, long firstExecuteTime);
}
......@@ -9,7 +9,13 @@ public interface IOutItemDao extends IMongoDao {
List<OutItem> findByHSerial(String hSerial);
List<OutItem> findCutItemList(List<String> soseqList, String pn, String facility);
OutItem findItem(String hSerial, int slotSeq);
void updateQty(String outItemId, int outQty, int sendQty);
void updateLockQty(String outItemId, int preLockQty, int realLockQty);
OutItem findCutItem(String soseq, int slotSeq);
}
......@@ -16,7 +16,7 @@ import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class OutIInfoDaoImpl extends AbstractMongoDao implements IOutInfoDao {
public class OutInfoDaoImpl extends AbstractMongoDao implements IOutInfoDao {
@Override
public OutInfo findByHSerial(String hSerial) {
......@@ -26,12 +26,18 @@ public class OutIInfoDaoImpl extends AbstractMongoDao implements IOutInfoDao {
return findOne(query);
}
@Override
public OutInfo findCutActionOutInfo(String soseq) {
return findOneByCondition(new String[]{"soseq","action"}, new String[]{soseq, "分盘"});
}
/**
* 查找所有发料状态不为2(未发料完成)的工单需求单
*/
@Override
public List<OutInfo> listBySo(String so){
Criteria c = new Criteria();
c.and("so").is(so);
Query query = new Query(c);
return findByQuery(query);
......@@ -63,7 +69,15 @@ public class OutIInfoDaoImpl extends AbstractMongoDao implements IOutInfoDao {
public synchronized void updateStatus(String hSerial, int bindStatus, int sendStatus){
Criteria c = Criteria.where("hSerial").is(hSerial);
Query query = Query.query(c);
Update update = Update.update("bindStatus",bindStatus).set("sendStatus",sendStatus);
Update update = new Update();
if(bindStatus != -1){
update.set("bindStatus",bindStatus);
}
if(sendStatus != -1){
update.set("sendStatus",sendStatus);
}
updateFirst(query,update);
}
......@@ -77,7 +91,12 @@ public class OutIInfoDaoImpl extends AbstractMongoDao implements IOutInfoDao {
update(hSerial, "outReelNum", outReelNum);
}
private void update(String hSerial, String key, int value){
@Override
public void updateExecuteTime(String hSerial, long firstExecuteTime){
update(hSerial, "firstExecuteTime", firstExecuteTime);
}
private void update(String hSerial, String key, Object value){
Criteria c = Criteria.where("hSerial").is(hSerial);
Query query = Query.query(c);
Update update = Update.update(key,value);
......
......@@ -6,6 +6,7 @@ import com.myproject.dao.mongo.qisda.IOutItemDao;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;
import java.util.List;
......@@ -23,6 +24,18 @@ public class OutItemDaoImpl extends AbstractMongoDao implements IOutItemDao {
}
@Override
public List<OutItem> findCutItemList(List<String> soseqList, String pn, String facility){
Criteria c = new Criteria();
c.and("action").is("分盘");
c.and("soseq").in(soseqList);
c.and("pn").is(pn);
c.and("facility").is(facility);
Query query = new Query(c);
query.with(new Sort(Sort.Direction.ASC,"createDate"));
return findByQuery(query);
}
@Override
public OutItem findItem(String hSerial, int slotSeq) {
Criteria c = new Criteria();
c.and("hSerial").is(hSerial);
......@@ -31,6 +44,37 @@ public class OutItemDaoImpl extends AbstractMongoDao implements IOutItemDao {
return findOne(query);
}
private void update(String outItemId, Update update){
Criteria c = Criteria.where("id").is(outItemId);
Query query = Query.query(c);
updateFirst(query,update);
}
@Override
public void updateQty(String outItemId, int outQty, int sendQty){
Update update = new Update();
if(outQty > 0){
update.set("outQty",outQty);
}
if(sendQty > 0){
update.set("sendQty",sendQty);
}
update(outItemId, update);
}
@Override
public void updateLockQty(String outItemId, int preLockQty, int realLockQty){
Update update = new Update();
if(preLockQty > 0){
update.set("lockQty",preLockQty);
}
if(realLockQty > 0){
update.set("realLockQty",realLockQty);
}
update(outItemId, update);
}
@Override
public OutItem findCutItem(String soseq, int slotSeq){
return findActionItem("分盘",soseq,slotSeq);
......
......@@ -576,7 +576,7 @@ public class BarcodeRule {
rule ="BATCH;PRODATEyyyyMMdd[1:8:-1]EXPD[-1:-4:-1];PN[1:12:-1]SP[13:5:-1]QTY[-1:-5:-1];RI";
codeStr = "=7x8=L00002019090199951797;E20190901 0365;B8C.R2003.V81506072019090103000;R506072019102200356";
codeStr = "=7x8=L0000000000000BF5NT8R;E20190605 0730 ;B7H.10524.5B1035042019060504000 ;R035042019060510182##";
codeStr = "=7x8=LRC11912020N1OR;E201912030365;BQT001100327706292019121915000;R06292019121900026";
codeStr = "=7x8=L0000000000SB1177082J;E20200316 0365;B7H.10421.2B1821872020031604000;R821872020031603034";
BarcodeRule br = BarcodeRule.newRule(rule);
Barcode barcode = br.toCodeBean(codeStr).getBarcode();
if(barcode != null){
......
......@@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.myproject.Constants;
import com.myproject.bean.update.qisda.OutItem;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.i18n.LocaleContextHolder;
......@@ -199,33 +200,9 @@ public final class DateUtil {
this.data = data;
}
}
public static void main(String args[]) throws Exception {
// Req req = new Req();
// req.setSeq("111");
// req.setOp(1);
// req.setStep(1);
// Map<String,String> codeMap = Maps.newHashMap();
// codeMap.put("CODEBBB","0");
// req.setData(codeMap);
//
// ObjectMapper mapper = new ObjectMapper();
// String json = mapper.writeValueAsString(req);
// System.out.println(json);
// CsvWriter csvWriter = new CsvWriter("/Volumes/SSD/code/storage/def.csv");
// csvWriter.writeRecord(new String[]{"AE","B","C","D"});
// csvWriter.flush();
// csvWriter.close();
String url = "http://10.85.17.233/ESMTCommonInterface/CommonService.asmx/VMIMateriaRecAss";
Map<String,Object> paramMap = new HashMap<String,Object>();
String materialInfo = "{\"flag\":\"\",\"slot\":\"2-17\",\"soseq\":\"2092475\",\"partNum\":\"6D.16905.6D1\",\"vendorCode\":\"20188\",\"vehicleLocation\":20,\"lot\":\"L0000000000S1952000EM\",\"reelID\":\"R201882019122300609\",\"hSerial\":\"233\",\"itme\":\"154819\",\"productCode\":\"20191201\",\"cloudLocation\":\"4D1201CC0002\",\"qty\":10000,\"action\":\"首盘\",\"location\":\"\",\"vehicleID\":\"D1\",\"so\":\"2388518\",\"facility\":\"ST\",\"idte\":\"20200119\",\"latest\":\"M\"}";
paramMap.put("materialInfo",materialInfo);
paramMap.put("userName","SMD-BOX");
String result = HttpHelper.postParam(url, paramMap);
System.out.println(result);
}
}
......@@ -74,6 +74,7 @@ public class HttpHelper {
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setConnectTimeout(20000);
// 获取URLConnection对象对应的输出流
//out = new PrintWriter(conn.getOutputStream());
out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(),"utf-8"));
......
......@@ -223,7 +223,7 @@ public class QisdaApi {
try {
String result = HttpHelper.postParam(url,paramMap);
log.info("DN单Facility收料判定接口返回:" + result);
log.info("DN单Facility收料("+barcode.getBarcode()+")判定接口返回:" + result);
String resultStr = XmlUtil.getNodeBody("string", result);
//0+提示信息/1/-1 0为NG,1为OK,-1为系统内部异常
if(resultStr.startsWith("1")){
......@@ -262,7 +262,7 @@ public class QisdaApi {
//0+提示信息/1+工单 0:为NG ;1:为OK 工单号码则表示该料卷被绑定在此工单上;-1为内部异常
String result = HttpHelper.postParam(url,paramMap);
//String result = "<?xml version=\"1.0\" encoding=\"utf-8\"?><string xmlns=\"http://tempuri.org/\">{\"state\":\"1\",\"msg\":\"入库判定OK\",\"info\":{\"so\":\"2388518\",\"facility\":\"ST\",\"company\":\"BACHS\",\"qty\":\"1\",\"soseq\":\"2092475\",\"slot\":\"5-4\"}}</string>";
log.info("收到纯入库判定接口返回:" + result);
log.info("收到("+reelid+")纯入库判定接口返回:" + result);
String resultStr = XmlUtil.getNodeBody("string", result);
//0+提示信息/1/-1 0为NG,1为OK,-1为系统内部异常
......@@ -287,6 +287,7 @@ public class QisdaApi {
if(so.equals("0")){
so = null;
soseq = null;
slot = null;
}
......@@ -354,9 +355,9 @@ public class QisdaApi {
log.info("纯入库操作完成时通知Qisda接口(VMILocationIn):reelID=" + reelID + "&location="+location);
try {
String result = HttpHelper.postParam(url,paramMap);
log.info("纯入库操作完成时通知Qisda接口(VMILocationIn)返回:" + result);
log.info(reelID + "纯入库操作完成时通知Qisda接口(VMILocationIn)返回:" + result);
} catch (ApiException e) {
log.error("纯入库操作完成时通知Qisda接口(VMILocationIn)出错",e);
log.error(reelID + "纯入库操作完成时通知Qisda接口(VMILocationIn)出错",e);
}
}
......@@ -386,10 +387,10 @@ public class QisdaApi {
Map<String,Object> paramMap = new HashMap<String,Object>();
paramMap.put("materialInfo",materialInfo);
paramMap.put("userName",USER_NAME);
log.info("DN单收料或Facility收料通知Qisda接口(VMIMateriaReceive)返回:" + materialInfo);
log.info("DN单收料或Facility收料通知Qisda接口(VMIMateriaReceive):" + materialInfo);
try {
String result = HttpHelper.postParam(url,paramMap);
log.info("DN单收料或Facility收料接口返回:" + result);
log.info("DN单收料或Facility收料["+barcode.getBarcode()+"]接口返回:" + result);
} catch (ApiException e) {
log.error("DN单收料或Facility收料接口出错",e);
}
......@@ -445,7 +446,15 @@ public class QisdaApi {
//错误状态不发料车编号
materialInfoMap.put("vehicleID","");//料车编号
}
materialInfoMap.put("vehicleLocation",appendInfo.getRfidLoc());//料车架位号
int rfidLoc = appendInfo.getRfidLoc();
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");
materialInfoMap.put("productCode",productCode);//生产日期
......@@ -467,9 +476,9 @@ public class QisdaApi {
try {
String result = HttpHelper.postParam(url,paramMap);
log.info("物料放上小车时通知Qisda(VMIMateriaRecAss)返回:" + result);
log.info(task.getBarcode() + "物料放上小车时通知Qisda(VMIMateriaRecAss)返回:" + result);
} catch (ApiException e) {
log.error("物料放上小车时通知Qisda(VMIMateriaRecAss)接口出错",e);
log.error(task.getBarcode() + "物料放上小车时通知Qisda(VMIMateriaRecAss)接口出错",e);
}
}
......
......@@ -675,6 +675,37 @@ public class StorageConstants {
}
/**
* 需求单绑定状态
*/
public static class BIND_STATUS{
/**
* 未绑定
*/
public static int NO_BIND = 0;
/**
* 预绑定缺料
*/
public static int PRE_BIND_LESS = 1;
/**
* 预绑定OK
*/
public static int PRE_BIND_OK = 2;
/**
* 真料绑定缺料
*/
public static int REAL_BIND_LESS = 3;
/**
* 真实绑定OK
*/
public static int REAL_BIND_OK = 4;
}
/**
* 需求单发料状态
*/
public static class SEND_STATUS{
......
......@@ -9,6 +9,7 @@ import com.myproject.bean.json.LiteOrder;
import com.myproject.bean.json.LiteOrderItem;
import com.myproject.bean.qisda.AppendInfo;
import com.myproject.bean.qisda.InquiryShelfBean;
import com.myproject.bean.qisda.ResultBean;
import com.myproject.bean.qisda.ShelfInfo;
import com.myproject.bean.update.Barcode;
import com.myproject.bean.update.DataLog;
......@@ -32,10 +33,7 @@ import com.myproject.util.QisdaApi;
import com.myproject.util.StorageConstants;
import com.myproject.webapp.controller.qisda.util.OutInfoCache;
import com.myproject.webapp.controller.storage.BaseController;
import com.myproject.webapp.controller.webService.DataCache;
import com.myproject.webapp.controller.webService.ITaskService;
import com.myproject.webapp.controller.webService.QisdaApiController;
import com.myproject.webapp.controller.webService.StorageDataController;
import com.myproject.webapp.controller.webService.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
......@@ -74,8 +72,6 @@ public class QisdaController extends BaseController {
@Autowired
private IOutItemDao outItemDao;
@Autowired
private IStoragePosDao storagePosDao;
@Autowired
private OutInfoCache outInfoCache;
......@@ -101,35 +97,6 @@ public class QisdaController extends BaseController {
private static DNInfo currentDnInfo;
/**
* RFID绑定DN单和Facility, Key为RFID, Value为DN单信息
*/
private static Map<String, DNInfo> rfidDnMap = new ConcurrentHashMap<>();
/**
* 根据入库时的RFID,获取入库方式
*/
public static DNInfo getDnInfo(String rfid){
if(rfid == null || rfid.equals("000")){
rfid = "";
}
DNInfo dnInfo = rfidDnMap.get(rfid);
String usedRfid = "=" + rfid;
if(dnInfo == null){
dnInfo = rfidDnMap.get(usedRfid);
}else{
//已经使用过,清除掉
rfidDnMap.remove(rfid);
rfidDnMap.put(usedRfid, dnInfo);
}
if(dnInfo == null){
//如果未找到料架对应的DNInfo,当作纯入库处理
dnInfo = new DNInfo();
dnInfo.setDnNo("");
}
return dnInfo;
}
/**
* VMI入料处的RFID, 用于绑定DN单或者Facility
* @param request
* @return
......@@ -139,7 +106,7 @@ public class QisdaController extends BaseController {
public String vmiRfid(HttpServletRequest request){
String rfid = request.getParameter("rfid");
vimRfid = rfid;
DNInfo dnInfo = rfidDnMap.get(rfid);
DNInfo dnInfo = QisdaCache.getDnInfo(rfid);
if(dnInfo != null){
return "move";
}else{
......@@ -164,9 +131,9 @@ public class QisdaController extends BaseController {
String rfid = request.getParameter("rfid");
log.info("上料机构上料完成后,清理RFID["+rfid+"]信息");
if(!Strings.isNullOrEmpty(rfid)){
rfidDnMap.remove(rfid);
QisdaCache.clearRfidDn(rfid);
String usedRfid = "=" + rfid;
rfidDnMap.remove(usedRfid);
QisdaCache.clearRfidDn(usedRfid);
}
return "OK";
}
......@@ -178,15 +145,27 @@ public class QisdaController extends BaseController {
@RequestMapping("/service/store/qisda/clearAllBind")
@ResponseBody
public String unBindAllReel(HttpServletRequest request){
String so = request.getParameter("so");
if(Strings.isNullOrEmpty(so)){
return "无工单序号参数so,无法解绑";
String soseq = request.getParameter("soseq");
if(Strings.isNullOrEmpty(soseq)){
return "无工单序号参数soseq,无法解绑";
}
String msg = outInfoCache.closeSo(so);
return msg;
ResultBean resultBean = outInfoCache.closeSoSeq(soseq);
return resultBean.getMsg();
}
/**
* 关闭需求单,不进行绑定
*/
@RequestMapping("/service/store/qisda/closeHSerial")
@ResponseBody
public String closeHSerial(HttpServletRequest request){
String hSerial = request.getParameter("hSerial");
ResultBean resultBean = outInfoCache.closeHSerial(hSerial);
return resultBean.getMsg();
}
/**
* 获取VMI线上当前的RFID
* @param request
* @return
......@@ -215,6 +194,7 @@ public class QisdaController extends BaseController {
if(Strings.isNullOrEmpty(rfid)){
return "x未读到RFID";
}
rfid = rfid.toUpperCase();
DNInfo newDnInfo = new DNInfo();
if(Strings.isNullOrEmpty(dnNo)){
......@@ -255,7 +235,7 @@ public class QisdaController extends BaseController {
}
currentDnInfo = newDnInfo;
rfidDnMap.put(rfid, currentDnInfo);
QisdaCache.bindRfidDnInfo(rfid, currentDnInfo);
String msg = "设置["+rfid+"]"+ newDnInfo.getShowStr()+"成功";
log.info(msg);
......@@ -269,8 +249,7 @@ public class QisdaController extends BaseController {
if(!newDnInfo.getDnNo().equals(currentDnNo)){
return "c是否停止当前操作:"+currentDnInfo.getShowStr()+"?";
}
rfidDnMap.put(rfid, currentDnInfo);
QisdaCache.bindRfidDnInfo(rfid, currentDnInfo);
String msg = "设置["+rfid+"]"+ newDnInfo.getShowStr()+"成功";
log.info(msg);
return "OK"+msg;
......@@ -278,15 +257,28 @@ public class QisdaController extends BaseController {
}
/**
* DN单收料
* @param request
* @return
* 需求单顺序调整页面
*/
@RequestMapping("/qisda/orderOut")
public String orderOut(HttpServletRequest request){
return "qisda/orderOut";
}
@RequestMapping("/service/store/qisda/changePriority")
public String changePriority(HttpServletRequest request){
String hSerialListStr = request.getParameter("hSerialList");
if(Strings.isNullOrEmpty(hSerialListStr)){
return "参数为空";
}
log.info("更改需求单出库优先级:" + hSerialListStr);
String[] hSerialArray = hSerialListStr.split(";");
List<String> hSerialList = Lists.newArrayList(hSerialArray);
outInfoCache.changePriority(hSerialList);
return "";
}
@RequestMapping(value = "/service/store/qisda/outInfoList")
@ResponseBody
public Collection<OutInfo> outInfoList(HttpServletRequest request){
......
package com.myproject.webapp.controller.qisda.util;
import com.google.common.collect.Lists;
import com.myproject.bean.qisda.AppendInfo;
import com.myproject.bean.qisda.InquiryShelfBean;
import com.myproject.bean.update.Barcode;
import com.myproject.bean.update.StoragePos;
import com.myproject.bean.qisda.ResultBean;
import com.myproject.bean.update.*;
import com.myproject.bean.update.qisda.OutInfo;
import com.myproject.bean.update.qisda.OutItem;
import com.myproject.dao.mongo.IDataLogDao;
import com.myproject.dao.mongo.IStoragePosDao;
import com.myproject.dao.mongo.qisda.IOutInfoDao;
import com.myproject.dao.mongo.qisda.IOutItemDao;
import com.myproject.manager.IComponentManager;
import com.myproject.util.DateUtil;
import com.myproject.util.QisdaApi;
import com.myproject.util.StorageConstants;
import com.myproject.webapp.controller.webService.DataCache;
import com.myproject.webapp.controller.webService.ITaskService;
import com.myproject.webapp.controller.webService.QisdaBindService;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
......@@ -30,33 +36,170 @@ public class OutInfoCache {
protected final Logger log = LogManager.getLogger(getClass());
//定时查询未完成的需求单
//未完成的需求单,key为需求单号,value为需求单详情
private static Map<String,OutInfo> outInfoMap = new ConcurrentHashMap<>();
@Autowired
protected ITaskService taskService;
@Autowired
private IOutInfoDao outInfoDao;
@Autowired
private IOutItemDao outItemDao;
@Autowired
private IStoragePosDao storagePosDao;
@Autowired
private SoseqCache soseqCache;
@Autowired
private QisdaBindService qisdaBindService;
@Autowired
private DataCache dataCache;
@Autowired
private IDataLogDao dataLogDao;
@Autowired
protected IComponentManager componentManager;
/**
* 当前正在执行的工单需求单(首盘,补料),未完成时,其他工单需求单不可执行
* 定时器,每3秒执行一次
*/
private static String currentOrderHSerial = "";
public void runTimer(){
if(!dataCache.getSettings().isStopJob()){
updateMustExeOutInfo();
executeBindTask();
executeOutTask();
}
public static void setCurrentOrderHSerial(String currentOrderHSerial) {
if(currentOrderHSerial == null){
currentOrderHSerial = "";
}
/**
* 绑定入库料盘
*/
public Barcode bindPutInReel(Barcode barcode){
OutItem bindItem = findNeedBindItem(barcode);
if(bindItem != null){
log.info("绑定入库料盘["+barcode.getBarcode()+"]到 "+bindItem.getSourceName());
barcode = qisdaBindService.addBindInfoToBarcode(barcode, bindItem);
}
OutInfoCache.currentOrderHSerial = currentOrderHSerial;
return barcode;
}
public String getCurrentOrderHSerial() {
return currentOrderHSerial;
public void executeOutTask(){
for (OutInfo unEndOutInfo : getCachedOutInfos()) {
//未执行过的,走双层线
checkOutOutItems(unEndOutInfo.gethSerial());
}
}
@Autowired
private IOutInfoDao outInfoDao;
/**
* 执行绑定任务
*/
public void executeBindTask(){
//绑定即将执行的工单(只绑定2个)
List<OutInfo> allUnExecuteCutInfoList = new ArrayList<>();
for (OutInfo unEndOutInfo : getCachedOutInfos()) {
if(unEndOutInfo.isFirstReelAction() || unEndOutInfo.isTailAction()){
if(!unEndOutInfo.isClosed()){
long firstExecuteTime = unEndOutInfo.getFirstExecuteTime();
if(firstExecuteTime <= 0){
OutInfo cutOutInfo = soseqCache.getCutActionInfoFromCache(unEndOutInfo.getSoseq());
if(cutOutInfo != null){
if(!allUnExecuteCutInfoList.contains(cutOutInfo)){
allUnExecuteCutInfoList.add(cutOutInfo);
}
}
@Autowired
private IOutItemDao outItemDao;
}
@Autowired
private IStoragePosDao storagePosDao;
}
}
}
int alreadyBindCount = 0;
for (OutInfo allUnExecuteCutInfo : allUnExecuteCutInfoList) {
if(!allUnExecuteCutInfo.isRealBindOk() && !allUnExecuteCutInfo.isRealBindLess()){
log.info("开始对soseq="+allUnExecuteCutInfo.getSoseq()+"进行真实绑定");
qisdaBindService.realBindOutInfo(allUnExecuteCutInfo);
}
alreadyBindCount = alreadyBindCount + 1;
if(alreadyBindCount >= 2){
break;
}
}
}
/**
* 入库完成时,查找需要绑定的需求单
*/
private OutItem findNeedBindItem(Barcode barcode){
List<String> soseqList = new ArrayList<>();
for (OutInfo unEndOutInfo : outInfoMap.values()) {
//查找执行过缺料和即将执行的,进行绑定
if(unEndOutInfo.isReelCutAction() && !unEndOutInfo.isClosed()){
if(unEndOutInfo.isSendLess() || unEndOutInfo.isPriority()){
soseqList.add(unEndOutInfo.getSoseq());
}
}
}
String pn = barcode.getPartNumber();
String facility = barcode.getAppendInfo().getFacility();
List<OutItem> cutItemList = outItemDao.findCutItemList(soseqList, pn, facility);
//优先绑定执行过的工单,如果没有,则绑定优先执行的工单
OutItem executedItem = null;
OutInfo executedOutInfo = null;
OutItem priorityItem = null;
OutInfo priorityOutInfo = null;
for (OutItem outItem : cutItemList) {
OutInfo outInfo = getOutInfoFromCache(outItem.gethSerial());
if(outInfo != null){
//真实绑定缺料
if(outItem.realBindLessQty() > 0){
long firstExecutTime = outInfo.getFirstExecuteTime();
if(firstExecutTime > 0){
//已经执行过的需求单
if(executedItem == null){
executedItem = outItem;
executedOutInfo = outInfo;
}else{
if(firstExecutTime < executedOutInfo.getFirstExecuteTime()){
executedItem = outItem;
executedOutInfo = outInfo;
}
}
}else if(firstExecutTime < 0){
//优先执行的需求单
if(priorityItem == null){
priorityItem = outItem;
priorityOutInfo = outInfo;
}else{
if(firstExecutTime > priorityOutInfo.getFirstExecuteTime()){
priorityItem = outItem;
priorityOutInfo = outInfo;
}
}
}
}
}
}
if(executedItem != null){
return executedItem;
}
return priorityItem;
}
/**
* 更新需求项
......@@ -67,14 +210,17 @@ public class OutInfoCache {
String hSerial = outItem.gethSerial();
OutInfo outInfo = outInfoMap.get(hSerial);
if(outInfo != null){
log.info("更新需求项"+ outItem);
log.debug("更新需求项"+ outItem);
outInfo.updateItem(outItem);
outInfoMap.put(hSerial, outInfo);
updateStatus(outInfo.gethSerial());
updateSendStatus(outInfo.gethSerial());
}
}
}
/**
* 将需求单加入到缓存
*/
public void addOutInfo(OutInfo outInfo){
//先把缓存清理掉,从数据库中查询
String hserial =outInfo.gethSerial();
......@@ -82,20 +228,20 @@ public class OutInfoCache {
log.info("将需求单"+ outInfo +"加入到缓存");
outInfo.setOutItemMap(new HashMap<String, OutItem>());
List<OutItem> outItemList = outItemDao.findByHSerial(hserial);
for (OutItem outItem : outItemList) {
outInfo.updateItem(outItem);;
}
outInfo.updateOutItems(outItemList);
if(!outInfo.getOutItemMap().isEmpty()){
outInfoMap.put(hserial, outInfo);
//加入到累计缓存里面
soseqCache.addTotalOutInfo(outInfo);
}else{
outInfo.setSendStatus(StorageConstants.SEND_STATUS.SEND_OK);
outInfoDao.save(outInfo);
}
}
}
/**
* 加载所有未完成的需求单
*/
......@@ -109,70 +255,85 @@ public class OutInfoCache {
if(!outInfo.isUrgentAction()){
String so = outInfo.getSo();
String mDataStr = DateUtil.toDateString(outInfo.getMdate(),"yyyy-MM-dd HH:mm");
log.info("工单["+so+"]的必须出库日期["+mDataStr+"]为3天前,关闭并解绑工单");
closeSo(outInfo.getSo());
log.info("需求单hSerial=["+outInfo.gethSerial()+"]工单so=["+so+"]soseq=["+outInfo.getSoseq()+"]的必须出库日期["+mDataStr+"]为3天前,关闭并解绑工单");
closeSoSeq(outInfo.getSoseq());
}
}else{
addOutInfo(outInfo);
updateStatus(outInfo.gethSerial());
updateSendStatus(outInfo.gethSerial());
}
}
}
public String closeSoSeq(String soseq){
/**
* 仅关闭需求单(不解除绑定),并从缓存中清除
* @param hSerial
* @return
*/
public ResultBean closeHSerial(String hSerial){
if(Strings.isBlank(hSerial)){
return ResultBean.newErrorResult(2201,"无需求单号参数hSerial,无法关闭");
}
log.info("开始关闭需求单hSerial=["+hSerial+"]");
int sendStatus = StorageConstants.SEND_STATUS.CLOSED;
outInfoDao.updateStatus(hSerial, -1 ,sendStatus);
removeFromCache(hSerial);
return ResultBean.newOkResult("需求单hSerial=["+hSerial+"]关闭成功","");
}
public ResultBean closeSoSeq(String soseq){
log.info("开始关闭并解绑工单soseq=["+soseq+"]的料盘");
List<OutInfo> outInfoList = outInfoDao.listBySoSeq(soseq);
if(outInfoList.isEmpty()){
return "未找到工单序号soseq为["+soseq+"]的数据";
return ResultBean.newErrorResult(2101,"未找到工单序号soseq为["+soseq+"]的数据");
}
soseqCache.closeSoseq(soseq);
for (OutInfo outInfo : outInfoList) {
if(!outInfo.isClosed() && !outInfo.isSendEnd()){
log.info("关闭需求单["+outInfo.gethSerial()+"]so=["+outInfo.getSo()+"]soseq=["+outInfo.getSoseq()+"]");
int sendStatus = StorageConstants.SEND_STATUS.CLOSED;
outInfoDao.updateStatus(outInfo.gethSerial(),outInfo.getBindStatus(),sendStatus);
outInfoDao.updateStatus(outInfo.gethSerial(), -1 ,sendStatus);
}
removeFromCache(outInfo.gethSerial());
}
int count = 0;
List<StoragePos> bindPosList = storagePosDao.listSoSeqBindPos(soseq);
for (StoragePos storagePos : bindPosList) {
Barcode barcode = storagePos.getBarcode();
storagePosDao.unbindReel(storagePos);
count = count + 1;
log.info("解除["+barcode.getBarcode()+"]的工单so=["+barcode.getAppendInfo().getSo()+"]soseq=["+barcode.getAppendInfo().getSoseq()+"]绑定,累计解除"+count);
}
return "";
}
public String closeSo(String so){
if(Strings.isBlank(so)){
return "无效的工单序号";
}
List<OutInfo> outInfoList = outInfoDao.listBySo(so);
for (OutInfo outInfo : outInfoList) {
if(!outInfo.isClosed() && !outInfo.isSendEnd()){
log.info("关闭需求单["+outInfo.gethSerial()+"]");
int sendStatus = StorageConstants.SEND_STATUS.CLOSED;
outInfoDao.updateStatus(outInfo.gethSerial(),outInfo.getBindStatus(),sendStatus);
}
}
int count = 0;
List<StoragePos> bindPosList = storagePosDao.allBindPos(so);
for (StoragePos storagePos : bindPosList) {
storagePosDao.unbindReel(storagePos);
count = count + 1;
log.info("解除["+storagePos.getBarcode().getBarcode()+"]的工单so=["+so+"]绑定,累计解除"+count);
}
return "";
return ResultBean.newOkResult("解除工单soseq=["+soseq+"]绑定,累计解除["+count+"]盘物料","");
}
/**
* 获取缓存的需求单信息
*/
public Collection<OutInfo> getCachedOutInfos(){
return outInfoMap.values();
public List<OutInfo> getCachedOutInfos(){
List<OutInfo> outInfoList = Lists.newArrayList(outInfoMap.values());
//未执行过的,并且达到了必须出库时间,取出来放到优先执行中
outInfoList.sort(new Comparator<OutInfo>() {
@Override
public int compare(OutInfo o1, OutInfo o2) {
//按优先级排序,如果没有优先级,使用
long executeTime1 = o1.getFirstExecuteTime();
long executeTime2 = o2.getFirstExecuteTime();
if(executeTime1 != executeTime2){
//手动更改优先级的,排在最前面
long result = executeTime1 - executeTime2;
return result > 0 ? 1 : -1;
}
//都为0即未执行过的,到这里的,理论上都是未达到必须出库时间(达到必须出库时间的,已经修改过优先级)
Date sdate1 = o1.getSdate();
Date sdate2 = o2.getSdate();
return sdate1.compareTo(sdate2);
}
});
return outInfoList;
}
/**
......@@ -191,48 +352,105 @@ public class OutInfoCache {
}else{
outInfo.setSendStatus(StorageConstants.SEND_STATUS.SEND_LESS);
}
outInfo = outInfoDao.save(outInfo);
outInfoMap.put(hSerial, outInfo);
}
}
private OutInfo getOutInfoFromCache(String hSerial){
OutInfo outInfo = outInfoMap.get(hSerial);
if(outInfo == null){
log.info("未找到需求单["+hSerial+"]的缓存信息,从数据库中加载");
outInfo = outInfoDao.findByHSerial(hSerial);
addOutInfo(outInfo);
}
return outInfo;
}
/**
* 任务出库数量+1
*/
public synchronized OutInfo incOutNum(String hSerial){
public synchronized OutInfo incOutNum(String hSerial, String outItemId, int outNum){
OutInfo outInfo = getOutInfoFromCache(hSerial);
if(outInfo != null){
int outReelNum = outInfo.getOutReelNum() + 1;
outInfo.setOutReelNum(outReelNum);
log.info("需求单["+outInfo.gethSerial()+"]任务出库数量:" + outInfo.getOutReelNum() + "/" + outInfo.getTaskNum());
if(outNum > 0) {
OutItem outItem = outInfo.findOutItemById(outItemId);
if (outItem == null) {
outItem = outItemDao.findOneById(outItemId);
log.warn("出库完成时,未找到outItem,从数据库中加载hSerial=" + hSerial + " outItemId=" + outItemId);
}
if(outItem != null){
//分盘料需求单,不需要更新出库数量,出库数量作为首盘料的发料数量
if(!outItem.isReelCutAction()){
int outQty = outItem.getOutQty();
outQty = outQty + outNum;
outItem.setOutQty(outQty);
int sendQty = 0;
if(outItem.isUrgentAction()){
//紧急料,设置出库数量与发料数量一样
sendQty = outQty;
outItem.setSendQty(outQty);
}
outItemDao.updateQty(outItem.getId(), outItem.getOutQty(), sendQty);
outInfo.updateItem(outItem);
}
}else{
log.error("出库完成时,未找到hSerial="+hSerial +" outItemId=" +outItemId+"的outItem");
}
}
outInfoMap.put(hSerial, outInfo);
outInfoDao.updateOutReelNum(hSerial,outReelNum);
updateSendStatus(outInfo.gethSerial());
return outInfo;
}
return null;
}
private OutInfo getOutInfoFromCache(String hSerial){
OutInfo outInfo = outInfoMap.get(hSerial);
if(outInfo == null){
log.info("未找到需求单["+hSerial+"]的缓存信息,从数据库中加载");
outInfo = outInfoDao.findByHSerial(hSerial);
}
return outInfo;
}
/**
* 任务发料数量+1
* slotSeq的发料完成, 任务发料数量+1, 工单料(sendNum大于0)发料完成时更新发料数量,同时更新工单缓存中的发料数量
*/
public synchronized OutInfo incTaskFinishNum(String hSerial){
public synchronized OutInfo incTaskFinishNum(String hSerial, int slotSeq, int sendNum){
OutInfo outInfo = getOutInfoFromCache(hSerial);
if(outInfo != null){
int taskFinishNum = outInfo.getTaskFinishNum() + 1;
outInfo.setTaskFinishNum(taskFinishNum);
log.info("需求单["+outInfo.gethSerial()+"]任务发料数量:" + outInfo.getTaskFinishNum() + "/" + outInfo.getTaskNum());
if(slotSeq > 0 && sendNum > 0){
OutItem outItem = outInfo.findOutItem(slotSeq);
if(outItem == null){
outItem = outItemDao.findItem(hSerial, slotSeq);
log.warn("发料完成时,未找到outItem,从数据库中加载hSerial="+hSerial +" slotSeq=" +slotSeq);
}
if(outItem != null){
int sendQty = outItem.getSendQty();
sendQty = sendQty + sendNum;
outItem.setSendQty(sendQty);
outItemDao.updateQty(outItem.getId(), 0, outItem.getSendQty());
outInfo.updateItem(outItem);
if(outItem.isFirstReelAction() || outItem.isTailAction()){
//首盘或者尾料,需要更新分盘料中的发料数量
soseqCache.addToTotalSendQty(outItem, sendNum);
}
}else{
log.error("发料完成时,未找到hSerial="+hSerial +" slotSeq=" +slotSeq+"的outItem");
}
}
outInfoMap.put(hSerial, outInfo);
outInfoDao.updateTaskFinishNum(hSerial,taskFinishNum);
updateSendStatus(outInfo.gethSerial());
return outInfo;
}
return null;
}
......@@ -240,17 +458,15 @@ public class OutInfoCache {
/**
* 更新需求单的发料状态
*/
public void updateStatus(String hSerial){
public void updateSendStatus(String hSerial){
OutInfo outInfo = outInfoMap.get(hSerial);
if(outInfo != null){
if(outInfo.isClosed()){
log.info("更新需求单["+hSerial+"]已关闭,不更新发料状态");
return;
}
log.info("更新需求单["+hSerial+"]的发料状态 [" + outInfo.getSendStatus()+"]");
log.debug("更新需求单["+hSerial+"]的发料状态 [" + outInfo.getSendStatus()+"]");
boolean sendEnd = true;
//默认为绑定OK,
int bindStatus = 2;
for (OutItem outItem : outInfo.getOutItemMap().values()) {
if(outItem.isUrgentAction()){
//紧急料,设置发料数量与出库数量一致
......@@ -259,10 +475,6 @@ public class OutInfoCache {
if(!outItem.isItemEnd()){
sendEnd = false;
}
if(!outItem.isBindOk()){
//有绑定缺料的情况,即认为是绑定缺料
bindStatus = 1;
}
}
if(sendEnd){
outInfo.setSendStatus(StorageConstants.SEND_STATUS.SEND_OK);
......@@ -270,19 +482,474 @@ public class OutInfoCache {
//有出库的,状态为发料缺料
if(outInfo.isTaskEnd()){
outInfo.setSendStatus(StorageConstants.SEND_STATUS.SEND_LESS);
}else{
outInfo.setSendStatus(StorageConstants.SEND_STATUS.EXECUTING);
}
}
outInfo.setBindStatus(bindStatus);
outInfoMap.put(outInfo.gethSerial(),outInfo);
outInfoDao.updateStatus(outInfo.gethSerial(),outInfo.getBindStatus(), outInfo.getSendStatus());
outInfoDao.updateStatus(outInfo.gethSerial(), -1 , outInfo.getSendStatus());
if(outInfo.isSendEnd()){
outInfoMap.remove(outInfo.gethSerial());
InquiryShelfBean.clearShelf(outInfo.gethSerial());
log.info("需求单["+hSerial+"]发料已完成,从缓存中清除,同时清理使用过的料串");
removeFromCache(outInfo.gethSerial());
}
}
}
private void removeFromCache(String hSerial){
outInfoMap.remove(hSerial);
InquiryShelfBean.clearShelf(hSerial);
log.info("需求单["+hSerial+"]发料已完成或关闭,从缓存中清除,同时清理使用过的料串");
}
public void changePriority(List<String> hSerialList) {
long sortOrder = - System.currentTimeMillis();
for (String hSerial : hSerialList) {
if(Strings.isBlank(hSerial)){
continue;
}
OutInfo outInfo = getOutInfoFromCache(hSerial);
if(outInfo != null){
updateExecuteTime(outInfo, sortOrder);
sortOrder = sortOrder - 1;
}
}
}
private OutInfo updateExecuteTime(OutInfo outInfo,long executeTime){
boolean updateResult = outInfo.updateExecuteTime(executeTime);
if(updateResult){
outInfoDao.updateExecuteTime(outInfo.gethSerial(), outInfo.getFirstExecuteTime());
outInfoMap.put(outInfo.gethSerial(),outInfo);
}
return outInfo;
}
/**
* 将到达必须执行时间的需求单提到优先执行的列表中
*/
public void updateMustExeOutInfo(){
Date now = new Date();
for (OutInfo outInfo : outInfoMap.values()) {
if(outInfo.getFirstExecuteTime() == 0){
boolean needToWaitQueue = false;
//未执行过的,已到达必须执行时间,任务提前到优先执行中
Date mustDate = outInfo.getMdate();
if (outInfo.isReelCutAction() || outInfo.isUrgentAction()){
needToWaitQueue = true;
}else if(mustDate.before(now)){
needToWaitQueue = true;
}
if(needToWaitQueue){
log.info("需求单hSerial=["+outInfo.gethSerial()+"]加入到优先执行队列中");
long sortOrder = - mustDate.getTime();
updateExecuteTime(outInfo, sortOrder);
}
}
}
}
/**
* 检查需求单是否可以出库
* @param outInfo
* @return
*/
private ResultBean checkOutInfoCanOut(OutInfo outInfo){
if(dataCache.getSettings().isStopOut()){
return ResultBean.newErrorResult(100, "系统更新中,暂停出库,请稍后再试",false);
}
if(outInfo == null){
return ResultBean.newErrorResult(1001,"未找到需求单",false);
}
if(outInfo.isExecuting()){
return ResultBean.newErrorResult(1003,"需求单["+outInfo.gethSerial()+"]正在执行",false);
}
//如果有其他任务在执行,不允许出库
Collection<DataLog> queueTasks = taskService.getQueueTasks();
List<DataLog> allTasks = taskService.getFinishedTasks();
if(!queueTasks.isEmpty()){
allTasks.addAll(queueTasks);
}
//是否有工单料任务
boolean hasOrderTask = false;
boolean hasUrgenReel = false;
for (DataLog dataLog : allTasks) {
if(dataLog.isCheckOutTask()){
if(!dataLog.isUrgentReel() && !dataLog.isCutReel() && !dataLog.isLessSendReel()){
//工单料(不是指定料也不是分盘料即首盘或补料)
hasOrderTask = true;
}else{
//分盘和紧急料或缺料补发的料
String taskHSerial = dataLog.getAppendInfo().gethSerial();
if(taskHSerial.equals(outInfo.gethSerial())){
return ResultBean.newErrorResult(1002,"当前需求单还有未完成的任务",false);
}
hasUrgenReel = true;
}
}
}
if(!hasUrgenReel){
//log.info("执行需求单["+outInfo.gethSerial()+"]时,发现已无紧急料和分盘料任务,清空紧急料/分盘料料架");
InquiryShelfBean.clearShelf(InquiryShelfBean.URGENT_SHELF_MAP_KEY);
InquiryShelfBean.clearShelf(InquiryShelfBean.CUT_SHELF_MAP_KEY);
}
boolean outInfoExecuted = outInfo.getFirstExecuteTime() > 0;
//首盘和补料
if(!outInfo.isReelCutAction() && !outInfo.isUrgentAction()){
if(!outInfoExecuted && hasOrderTask){
//未执行过且还有未完成的任务
return ResultBean.newErrorResult(1003,"全部任务完成后才可执行",false);
}
}
List<StoragePos> bindList = storagePosDao.listSoSeqBindPos(outInfo.getSoseq());
if(outInfoExecuted && bindList.isEmpty()){
//已经执行过
return ResultBean.newErrorResult(1004,"无可出的料盘",false);
}
if(outInfo.isReelCutAction()){
boolean hasCutReel = false;
for (StoragePos storagePos : bindList) {
if(storagePos.getBarcode().hasCutInfo()){
hasCutReel = true;
break;
}
}
if(!hasCutReel){
return ResultBean.newErrorResult(1005,"未找到需要分盘的物料",false);
}
}
return null;
}
public synchronized ResultBean checkOutOutItems(String hSerial){
//OutInfo outInfo = outInfoDao.findByHSerial(hSerial);
OutInfo outInfo = getOutInfoFromCache(hSerial);
ResultBean resultBean = checkOutInfoCanOut(outInfo);
if(resultBean != null){
return resultBean;
}
//非分盘料才进行真实绑定
if(!outInfo.isReelCutAction()){
OutInfo cutOutInfo = soseqCache.getCutActionInfoFromCache(outInfo.getSoseq());
if(cutOutInfo != null && !cutOutInfo.isRealBindOk() && !cutOutInfo.isRealBindLess()){
log.warn("需求单["+outInfo.gethSerial()+"]出库时,发现未进行真实绑定,开始对soseq="+outInfo.getSoseq()+"进行真实绑定");
qisdaBindService.realBindOutInfo(cutOutInfo);
}
}
boolean outInfoExecuted = outInfo.getFirstExecuteTime() > 0;
if(!outInfoExecuted){
if(outInfo.isFirstReelAction() || outInfo.isTailAction()){
QisdaCache.setCurrentOrderHSerial(outInfo.gethSerial());
}
}
log.info("执行需求单["+hSerial+"]出库");
outInfo = updateExecuteTime(outInfo, System.currentTimeMillis());
List<DataLog> tasks = new ArrayList<>();
List<OutItem> itemList = outInfo.getOutItems();
itemList.sort(new Comparator<OutItem>(){
@Override
public int compare(OutItem o1, OutItem o2) {
return o1.getSlotlocation() - o2.getSlotlocation();
}
});
for (OutItem outItem : itemList) {
List<DataLog> itemTasks = new ArrayList<>();
//首盘料需求单
if(outItem.isFirstReelAction()){
itemTasks = checkOutFirst(outItem, outInfoExecuted);
}else if(outItem.isReelCutAction()){
itemTasks = checkOutCut(outItem);
}else if(outItem.isTailAction()){
itemTasks = checkOutTail(outItem, outInfoExecuted);
}else if(outItem.isUrgentAction()){
itemTasks = checkOutUrgent(outItem);
}
if(itemTasks != null && !itemTasks.isEmpty()){
for (DataLog itemTask : itemTasks) {
tasks.add(itemTask);
}
}
updateOutItem(outItem.getId());
}
int outReelNum = tasks.size();
if(outReelNum > 0){
log.info("需求单"+outInfo.gethSerial()+"已出("+outInfo.getOutReelNum()+")/已发("+outInfo.getTaskFinishNum()+") 本次出库料盘数量:" + outReelNum);
resetTaskNum(hSerial, outReelNum);
//先出小料盘,再出大料盘
for (DataLog task : tasks) {
if(task.isSmallReel()){
taskService.addTaskToExecute(task);
}
}
for (DataLog task : tasks) {
if(!task.isSmallReel()){
taskService.addTaskToExecute(task);
}
}
}else{
log.info("需求单"+outInfo.gethSerial()+"本次出库料盘数量为0");
}
if(outInfo.isReelCutAction() || outInfo.isFirstReelAction()){
if(outReelNum == 0){
List<OutItem> outItemList = outItemDao.findByHSerial(outInfo.gethSerial());
boolean lessBind = false;
QisdaApi.VMILocationOutFeedback(outItemList, lessBind);
}
}
String msg = "需求单"+hSerial+"任务分配完成,共["+outReelNum+"]盘任务";
log.info(msg);
return ResultBean.newOkResult(msg,"ok");
}
private List<DataLog> checkOutUrgent(OutItem outItem){
List<DataLog> tasks = new ArrayList<>();
//紧急料,直接出库
String reelID = outItem.getReelID();
if(reelID != null){
//指定出某盘料或单独出库
StoragePos pos = storagePosDao.findByBarcode(reelID);
if(pos != null){
DataLog task = newTask(outItem, pos);
task = InquiryShelfBean.addUnlimitLoc(task, outItem);
task = dataLogDao.save(task);
tasks.add(task);
}
}else{
//紧急料,未绑定数量=需求单数量-已出库数量-已绑数量
int needNum = outItem.getQty() - outItem.getOutQty() - outItem.getRealLockQty();
if(needNum >= 0){
log.info("紧急料,查找未绑定料盘进行出库,未绑数量为"+needNum+"=(需求单"+ outItem.getQty() + ") - (已出" + outItem.getOutQty() + ")-已绑(" + outItem.getRealLockQty()+")");
while(needNum >= 0){
StoragePos pos = storagePosDao.findNoBindMinQty(outItem.getPn(), outItem.getFacility());
if(pos != null){
//找到了,进行出库
DataLog task = newTask(outItem, pos);
task = InquiryShelfBean.addUnlimitLoc(task, outItem);
task = dataLogDao.save(task);
tasks.add(task);
outItem.setRealLockQty(outItem.getRealLockQty() + task.getNum());
needNum = outItem.getQty() - outItem.getRealLockQty();
}else{
//未找到未绑定的物料了
break;
}
}
}
}
return tasks;
}
private List<DataLog> checkOutCut(OutItem outItem){
List<DataLog> tasks = new ArrayList<>();
if(outItem.isCutMaterial()){
//出分盘料
List<StoragePos> cutPosList = storagePosDao.findCutList(outItem.getSo(), outItem.getSlotlocation(),outItem.getSoseq());
for (StoragePos pos : cutPosList) {
DataLog task = newTask(outItem, pos);
task = InquiryShelfBean.addUnlimitLoc(task, outItem);
task = dataLogDao.save(task);
tasks.add(task);
}
}
return tasks;
}
/**
* 生成补料盘任务
* @param outItem 出库任务项
* @param lessSend 是否是缺料补发
* @return
*/
private List<DataLog> checkOutTail(OutItem outItem, boolean lessSend){
List<DataLog> tasks = new ArrayList<>();
if(outItem.getSendQty() > outItem.getQty()){
//出经发完料
return tasks;
}
List<StoragePos> bindPosList = storagePosDao.findBindList(outItem.getSoseq(), outItem.getSlotlocation());
StoragePos maxQtyReelPos = null;
OutItem totalOutInfo = soseqCache.getCutOutItem(outItem.getSoseq(), outItem.getSlotlocation());
if(totalOutInfo.getOutQty() == 0){
//首盘未出,需要预留一盘最大的给首盘
maxQtyReelPos = storagePosDao.findMaxQtyBindReel(outItem.getSoseq(), outItem.getSlotlocation());
}
//没有顺序
int sendQty = outItem.getSendQty();
int fixQty = outItem.getFixedQty();
for (StoragePos pos : bindPosList) {
if(sendQty >= fixQty){
break;
}
if(maxQtyReelPos != null && maxQtyReelPos.getId().equals(pos.getId())){
if(totalOutInfo.getFixedQty() == totalOutInfo.getQty()){
//未修正过
fixQty = totalOutInfo.getQty() - maxQtyReelPos.getBarcode().getAmount();
outItem.setFixedQty(fixQty);
outItemDao.save(outItem);
updateOutItem(outItem.getId());
log.info("首盘未出,预留最大的一盘["+pos.getBarcode().getBarcode()+"]给首盘,补料的需求数量为:"+fixQty);
continue;
}
}
Barcode posBarcode = pos.getBarcode();
DataLog task = newTask(outItem, pos);
if(lessSend){
task.setLessSendReel(lessSend);
}
task = InquiryShelfBean.addUnlimitLoc(task, outItem);
task = dataLogDao.save(task);
tasks.add(task);
sendQty = sendQty + posBarcode.getAmount();
}
return tasks;
}
/**
* 生成首盘料任务
* @param outItem 首盘料任务项
* @param lessSend 是否是缺料重发(已经执行过)
* @return
*/
private List<DataLog> checkOutFirst(OutItem outItem, boolean lessSend){
List<DataLog> tasks = new ArrayList<>();
if(outItem.getSendQty() > 0){
//出经发完料
return tasks;
}
//bindSamePnFromOtherSlotForFirstAction(outItem,outReelIdList);
List<StoragePos> bindPosList = storagePosDao.findBindList(outItem.getSoseq(), outItem.getSlotlocation());
//首盘料,出到双层线上,按站位顺序,只出最大的一盘
StoragePos maxQtyPos = null;
for (StoragePos pos : bindPosList) {
//不是需要分盘但未分盘的料
Barcode posBarcode = pos.getBarcode();
if(!posBarcode.hasCutInfo()){
if(maxQtyPos == null){
maxQtyPos = pos;
}
if(posBarcode.getAmount() > maxQtyPos.getBarcode().getAmount()){
maxQtyPos = pos;
}
}
}
if(maxQtyPos != null){
//加入料架
log.info(outItem.toString() + "找到最大数量料盘["+maxQtyPos.getBarcode().getBarcode()+"],准备出库");
DataLog task = newTask(outItem, maxQtyPos);
if(lessSend){
task.setLessSendReel(lessSend);
InquiryShelfBean.addUnlimitLoc(task, outItem);
}else{
task = InquiryShelfBean.addLimitLoc(task, outItem);
}
task = dataLogDao.save(task);
tasks.add(task);
}else{
//缺料重发不需要保留位置
if(!lessSend){
//缺料,查看是否有本工单,同PN的,如果有抢一个过来
//缺料,料架留空
boolean hasBigSizePn = false;
List<Component> pnList = componentManager.listByPn(outItem.getPn());
for (Component c : pnList) {
if(c.getPlateSize() > 7 || c.getHeight() > 12){
hasBigSizePn = true;
break;
}
}
if(pnList.isEmpty()){
log.error("未找到物料["+outItem.getPn()+"]的尺寸信息,保留C类型架位");
InquiryShelfBean.addEmptyLoc(outItem, StorageConstants.SHEFL_TYPE.C);
}else if(hasBigSizePn){
log.info(outItem.getSlotlocation() + "["+outItem.getPn()+"]缺料,且PN数据中有大料,保留C类型架位");
InquiryShelfBean.addEmptyLoc(outItem, StorageConstants.SHEFL_TYPE.C);
}else {
log.info(outItem.getSlotlocation() + "["+outItem.getPn()+"]缺料,保留D类型架位");
InquiryShelfBean.addEmptyLoc(outItem, StorageConstants.SHEFL_TYPE.D);
}
}
}
return tasks;
}
private DataLog newTask(OutItem outItem, StoragePos pos){
DataLog task = new DataLog();
task.setType(StorageConstants.OP.CHECKOUT);
task.setStatus(StorageConstants.OP_STATUS.WAIT.name());
Barcode barcode = pos.getBarcode();
if(barcode != null){
task.setPartNumber(barcode.getPartNumber());
task.setBarcode(barcode.getBarcode());
task.setNum(barcode.getInitialAmount());
task.setW(barcode.getPlateSize());
task.setH(barcode.getHeight());
task.setSourceName(outItem.getSourceName());
AppendInfo appendInfo = barcode.getAppendInfo();
appendInfo.setSo(outItem.getSo());
appendInfo.setSoseq(outItem.getSoseq());
appendInfo.setRefno(outItem.getRefno());
appendInfo.sethSerial(outItem.gethSerial());
appendInfo.setSlotStr(outItem.getSlotStr());
appendInfo.setSlotIndex(outItem.getSlotlocation());
appendInfo.setAction(outItem.getAction());
appendInfo.setOutItemId(outItem.getId());
task.setAppendInfo(appendInfo);
if(barcode.hasCutInfo()){
task.setCutReel(true);
}
}
if(outItem.isUrgentAction()){
task.setUrgentReel(true);
}
Storage storage = dataCache.getStorageById(pos.getStorageId());
if(storage.isPackage()){
//包装料仓
task.setPackageReel(true);
}
task.setCid(storage.getCid());
task.setStorageId(storage.getId());
task.setStorageName(storage.getName());
task.setPosId(pos.getId());
task.setPosName(pos.getPosName());
return task;
}
}
......@@ -85,6 +85,7 @@ public class SettingsController extends BaseUpdateController {
oldSettings.setInactionDay(settings.getInactionDay());
oldSettings.setStopOut(settings.isStopOut());
oldSettings.setStopJob(settings.isStopJob());
dataCache.updateSettings(oldSettings);
saveMessage(request, getText("storage.saveSuccess", request.getLocale()));
......
......@@ -298,27 +298,7 @@ public class DataCache{
try {
Component component = getComponent(barcode);
codeBeanFromRule.setError(null);
if(component.isSizeConfirmed()){
//尺寸已经确认的,判断尺寸,如果大小不符合,直接NG,如果大小符合,尺寸差别在4mm内的修改尺寸
if(barcode.getPlateSize() != component.getPlateSize()){
String msg = barcode.getBarcode() + "测量尺寸["+barcode.getSizeStr()+"]与给定尺寸["+component.getSizeStr()+"]不符";
codeBeanFromRule.setError(msg);
throw new ValidateException(msg);
}else{
//如果厚度小于4mm,使用确认的尺寸入库
int diffHeight = barcode.getHeight() - component.getHeight();
if(Math.abs(diffHeight) > 4){
String msg = barcode.getBarcode() + "测量厚度["+barcode.getSizeStr()+"]与给定厚度["+component.getSizeStr()+"]误差过大";
//codeBeanFromRule.setError(msg);
throw new ValidateException(msg);
}else if(diffHeight !=0 && Math.abs(diffHeight) <= 4){
log.info(barcode.getBarcode() + "测量尺寸["+barcode.getSizeStr()+"]与给定尺寸["+component.getSizeStr()+"]厚度误差在4mm以内,使用给定尺寸进行入库");
barcode.setHeight(component.getHeight());
barcodeManager.save(barcode);
}
}
}
} catch (ValidateException e) {
codeBeanFromRule.setError(e.getMessage());
log.info(e.getMessage());
......@@ -337,25 +317,7 @@ public class DataCache{
}
Component component = getComponent(barcodeFromRule);
if(component.isSizeConfirmed()){
//尺寸已经确认的,判断尺寸,如果大小不符合,直接NG,如果大小符合,尺寸差别在4mm内的修改尺寸
if(barcodeFromRule.getPlateSize() != component.getPlateSize()){
String msg = barcodeFromRule.getBarcode() + "测量尺寸["+barcodeFromRule.getSizeStr()+"]与给定尺寸["+component.getSizeStr()+"]不符";
codeBeanFromRule.setError(msg);
throw new ValidateException(msg);
}else{
//如果厚度小于4mm,使用确认的尺寸入库
int diffHeight = barcodeFromRule.getHeight() - component.getHeight();
if(Math.abs(diffHeight) > 4){
String msg = barcodeFromRule.getBarcode() + "测量厚度["+barcodeFromRule.getSizeStr()+"]与给定厚度["+component.getSizeStr()+"]误差过大";
codeBeanFromRule.setError(msg);
throw new ValidateException(msg);
}else if(diffHeight !=0 && Math.abs(diffHeight) <= 4){
log.info(barcodeFromRule.getBarcode() + "测量尺寸["+barcodeFromRule.getSizeStr()+"]与给定寸["+component.getSizeStr()+"]厚度误差在4mm以内,使用给定尺寸进行入库");
barcodeFromRule.setHeight(component.getHeight());
}
}
}
//codeBeanFromRule.setShowImg(component.getShowImg());
Date produceDate = barcodeFromRule.getProduceDate();
if(produceDate != null && barcodeFromRule.getExpireDate() == null){
......@@ -408,8 +370,29 @@ public class DataCache{
Barcode barcode = null;
for (CodeBean codeBean : codeBeans) {
if(codeBean.isValid()){
Barcode barcodeFromRule = codeBean.getBarcode();
Component component = getComponent(barcodeFromRule);
if(component.isSizeConfirmed()){
//尺寸已经确认的,判断尺寸,如果大小不符合,直接NG,如果大小符合,尺寸差别在4mm内的修改尺寸
if(barcodeFromRule.getPlateSize() != component.getPlateSize()){
String msg = barcodeFromRule.getBarcode() + "测量尺寸["+barcodeFromRule.getSizeStr()+"]与给定尺寸["+component.getSizeStr()+"]不符";
throw new ValidateException(msg);
}else{
//如果厚度小于4mm,使用确认的尺寸入库
int diffHeight = barcodeFromRule.getHeight() - component.getHeight();
if(Math.abs(diffHeight) > 4){
String msg = barcodeFromRule.getBarcode() + "测量厚度["+barcodeFromRule.getSizeStr()+"]与给定厚度["+component.getSizeStr()+"]误差过大";
throw new ValidateException(msg);
}else if(diffHeight !=0 && Math.abs(diffHeight) <= 4){
log.info(barcodeFromRule.getBarcode() + "测量尺寸["+barcodeFromRule.getSizeStr()+"]与给定寸["+component.getSizeStr()+"]厚度误差在4mm以内,使用给定尺寸进行入库");
barcodeFromRule.setHeight(component.getHeight());
barcodeFromRule = barcodeManager.save(barcodeFromRule);
}
}
}
if(barcode == null){
barcode = codeBean.getBarcode();
barcode = barcodeFromRule;
}else{
throw new ValidateException("找到多个有效的条码");
}
......@@ -676,7 +659,6 @@ public class DataCache{
String cid = storage.getCid();
String partNumber = barcode.getPartNumber();
int amount = 0;
String sizeStr = pos.getSizeStr();
if(pos.getBarcode() == null){
//出库
amount = - barcode.getAmount();
......
......@@ -44,7 +44,7 @@ public class ExpireMailUtil {
protected final transient Logger log = LogManager.getLogger(getClass());
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);
//ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);
@Autowired
private JavaMailSender mailSender;
......@@ -55,23 +55,23 @@ public class ExpireMailUtil {
@Autowired
private IStoragePosDao storagePosDao;
private static boolean isRunning = false;
//private static boolean isRunning = false;
@PostConstruct
public void init(){
dataCache.getAllStorage();
if(!isRunning){
isRunning = true;
log.info("开启 PCB过期发邮件检测任务");
//5 分钟之后执行,每分钟执行一次
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
checkExpirePcbTask();
}
}, 2, 1, TimeUnit.MINUTES);
}
// if(!isRunning){
// isRunning = true;
// log.info("开启 PCB过期发邮件检测任务");
// //5 分钟之后执行,每分钟执行一次
// scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
//
// @Override
// public void run() {
// checkExpirePcbTask();
// }
// }, 2, 1, TimeUnit.MINUTES);
// }
}
public String sendTestMail(){
......
package com.myproject.webapp.controller.webService;
import com.myproject.bean.qisda.InquiryShelfBean;
import com.myproject.bean.update.DataLog;
import com.myproject.dao.mongo.IDataLogDao;
import com.myproject.webapp.controller.qisda.util.OutInfoCache;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
......@@ -7,6 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
......@@ -25,21 +29,58 @@ public class MainTimer {
@Autowired
private OutInfoCache outInfoCache;
@PostConstruct
@Autowired
private QisdaCache qisdaCache;
@Autowired
private IDataLogDao dataLogDao;
@Autowired
private ITaskService taskService;
public void init(){
String currentorderHSerial = qisdaCache.getCurrentOrderHSerial();
log.info("加载未完成的任务,当前执行需求单["+currentorderHSerial+"]");
List<DataLog> unExecuteTasks = dataLogDao.findUnFinishedTasks(currentorderHSerial);
for (DataLog unExecuteTask : unExecuteTasks) {
if(unExecuteTask.isExecuting() || unExecuteTask.isWait()){
taskService.addTaskToExecute(unExecuteTask);
}else{
taskService.updateFinishedTask(unExecuteTask);
}
}
log.info("加载DN单绑定信息和出库料架信息");
qisdaCache.initRfidDnMap();
InquiryShelfBean.initShelfMap();
outInfoCache.loadUnEndOutInfos();
// log.info("主定时器开启,每1s执行一次");
// //1 分钟之后执行,每秒钟执行一次
// scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
// @Override
// public void run() {
// timerTask();
// }
// }, 20, 1, TimeUnit.SECONDS);
log.info("主定时器开启,60秒后开始执行, 每10s执行一次");
//1 分钟之后执行,每秒钟执行一次
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
timerTask();
}
}, 60, 10, TimeUnit.SECONDS);
}
private void timerTask(){
private boolean isProcessTask = false;
private void timerTask(){
try{
if(isProcessTask){
return;
}
isProcessTask = true;
outInfoCache.runTimer();
}catch (Exception e){
log.error("定时器执行出错",e);
}finally {
isProcessTask = false;
}
}
......
......@@ -40,9 +40,6 @@ public class QisdaApiController extends BaseController {
protected ITaskService taskService;
@Autowired
protected IComponentManager componentManager;
@Autowired
private IStoragePosDao storagePosDao;
@Autowired
......@@ -52,16 +49,14 @@ public class QisdaApiController extends BaseController {
private IOutInfoDao outInfoDao;
@Autowired
private IBarcodeDao barcodeDao;
@Autowired
private DataCache dataCache;
@Autowired
private IDataLogDao dataLogDao;
private OutInfoCache outInfoCache;
@Autowired
private OutInfoCache outInfoCache;
private QisdaBindService qisdaBindService;
protected final static Logger log = LogManager.getLogger(QisdaApiController.class);
/**
......@@ -118,11 +113,9 @@ public class QisdaApiController extends BaseController {
@RequestMapping("/executeOut")
@ResponseBody
public String executeOut(HttpServletRequest request){
if(dataCache.getSettings().isStopOut()){
return "系统更新中,暂停出库,请稍后再试";
}
String hSerial = request.getParameter("hSerial");
return checkOutOutItems(hSerial);
ResultBean resultBean = outInfoCache.checkOutOutItems(hSerial);
return resultBean.getMsg();
}
/**
......@@ -201,20 +194,15 @@ public class QisdaApiController extends BaseController {
*/
@RequestMapping(value = "/closeSoSeq",method = RequestMethod.POST)
@ResponseBody
public ResultBean closeSo(HttpServletRequest request) {
List<Map<String, String>> bindReelInfos = new ArrayList<>();
public ResultBean closeSoSeq(HttpServletRequest request) {
try {
String soseq = receiveParamInfo(request,"soseq");
log.info("收到检测锁定工单请求:"+soseq);
log.info("收到关闭工单请求soseq="+soseq);
if(soseq == null){
return ResultBean.newErrorResult(-1,"未找到soseq参数");
}
String result = outInfoCache.closeSoSeq(soseq);
if(result.isEmpty()){
return ResultBean.newOkResult("OK");
}else{
return ResultBean.newErrorResult(2003,result);
}
ResultBean resultBean = outInfoCache.closeSoSeq(soseq);
return resultBean;
} catch (Exception e) {
log.error("需求单请求处理出错", e);
return ResultBean.newErrorResult(1001,"内部错误:" + e.getMessage());
......@@ -248,12 +236,9 @@ public class QisdaApiController extends BaseController {
if(outInfo == null){
outInfo = outInfoDao.findByHSerial(hSerial);
if(outInfo == null){
log.info("创建出库需求单["+hSerial+"]");
outInfo = new OutInfo(outItem);
outInfo = outInfoDao.save(outInfo);
}
}
String reelID = outItem.getReelID();
if(reelID != null && !reelID.isEmpty()){
//指定出某盘料或单独出库,如果已经绑定,不允许出,如果未绑定直接进行绑定
......@@ -301,9 +286,17 @@ public class QisdaApiController extends BaseController {
}
}
bindOutInfoList(outInfoMap.values());
//分盘需求单进行预绑定
qisdaBindService.preBindCutOutInfoList(outInfoMap.values());
for (OutInfo outInfo : outInfoMap.values()) {
log.info("创建出库需求单["+outInfo.gethSerial()+"]" + outInfo.getAction());
outInfoDao.save(outInfo);
//新的需求单,更新缓存
outInfoCache.addOutInfo(outInfo);
}
log.info("需求单请求处理完成");
} catch (Exception e) {
log.error("需求单请求处理出错", e);
return ResultBean.newErrorResult(1001,"内部错误:" + e.getMessage());
......@@ -315,461 +308,8 @@ public class QisdaApiController extends BaseController {
return ResultBean.newOkResult("");
}
private void bindOutInfoList(Collection<OutInfo> outInfoList){
for (OutInfo outInfo : outInfoList) {
if(outInfo.isReelCutAction() || outInfo.isFirstReelAction()){
//首盘和分盘进行缺料反馈
log.info("需求单["+outInfo+"]开始进行绑定");
for (OutItem outItem : outInfo.getOutItems()) {
if(outItem.isReelCutAction()){//分盘
firstBindCutReel(outItem);
preBindReel(outItem);
}else if(outItem.isFirstReelAction()){//首盘
firstBindCutReel(outItem);
secondBindCutReel(outItem);
realBindReel(outItem);
bindSamePnFromOtherSlotForFirstAction(outItem,new ArrayList<String>());
}else{//补料盘,急料,指定料,单独出库
}
}
}else{
log.info("需求单["+outInfo+"]不需要进行绑定");
}
}
for (OutInfo outInfo : outInfoList) {
if(outInfo.isReelCutAction()){
//首盘和分盘进行缺料反馈
log.info("分盘需求单["+outInfo+"]开始进行二次分盘绑定");
for (OutItem outItem : outInfo.getOutItems()) {
if(outItem.isReelCutAction()){//分盘
secondBindCutReel(outItem);
}
}
}
}
for (OutInfo outInfo : outInfoList) {
//新的需求单,更新缓存
outInfoCache.addOutInfo(outInfo);
if(outInfo.isReelCutAction() || outInfo.isFirstReelAction()){
//首盘和分盘进行缺料反馈
List<OutItem> outItemList = outItemDao.findByHSerial(outInfo.gethSerial());
boolean lessBind = true;
QisdaApi.VMILocationOutFeedback(outItemList, lessBind);
}else{
log.info("需求单["+outInfo+"]不需要进行缺料反馈");
}
}
}
/**
* 检查首盘料中不同Slot上相同的PN, 如果缺料,出首盘时要保证每一个Slot上都有料
*/
private void bindSamePnFromOtherSlotForFirstAction(OutItem outItem, Collection<String> excludeBarcodeList){
if(outItem.getRealLockQty() == 0){
//绑定数量为0,说明缺料,查找是否有绑定的本工单的其他Slot相同PN的料
List<StoragePos> posList = storagePosDao.findBindByPn(outItem.getSoseq(), outItem.getPn());
if(posList != null && !posList.isEmpty()){
//站位的绑定的料盘数量,大于2盘才可以抢
Map<String,Integer> slotReelCountMap = new HashMap<>();
for (StoragePos storagePos : posList) {
//其他工位绑定至少两盘才可以抢
Barcode barcode = storagePos.getBarcode();
String bindSlot = barcode.getAppendInfo().getBindSlot();
if(bindSlot != null){
Integer reelCount = slotReelCountMap.get(bindSlot);
if(reelCount == null){
reelCount = 0;
}
reelCount = reelCount + 1;
slotReelCountMap.put(bindSlot, reelCount);
}
}
List<String> canRobSlotList = new ArrayList<>();
for (StoragePos storagePos : posList) {
//其他工位绑定至少两盘才可以抢
Barcode barcode = storagePos.getBarcode();
String bindSlot = barcode.getAppendInfo().getBindSlot();
if(bindSlot != null){
Integer reelCount = slotReelCountMap.get(bindSlot);
if(reelCount >= 2){
canRobSlotList.add(bindSlot);
}
}
}
//抢最大的一盘
StoragePos robPos = null;
for (StoragePos storagePos : posList) {
//其他工位绑定至少两盘才可以抢
Barcode barcode = storagePos.getBarcode();
String bindSlot = barcode.getAppendInfo().getBindSlot();
if(bindSlot != null && canRobSlotList.contains(bindSlot)){
if(!excludeBarcodeList.contains(barcode.getBarcode())){
//这盘料可以抢
if(robPos == null || robPos.getBarcode().getAmount() < barcode.getAmount()){
robPos = storagePos;
}
}
}
}
if(robPos != null){
Barcode barcode = robPos.getBarcode();
AppendInfo appendInfo = barcode.getAppendInfo();
String hSerial = outItem.gethSerial();
int reelQty = barcode.getAmount();
String oldSlot = appendInfo.getBindSlot();
log.info("首盘需求单["+hSerial+"]站位["+outItem.getSlotlocation()+"]缺料,从站位["+oldSlot+"]绑定料盘中抢夺料盘"+barcode.getBarcode()+"["+reelQty+"]进行绑定");
OutItem oldItem = outItemDao.findItem(hSerial,Integer.valueOf(oldSlot));
if(oldItem != null){
//不是预绑定的物料
oldItem.setRealLockQty(oldItem.getRealLockQty() - reelQty);
outItemDao.save(oldItem);
}
appendInfo.setBindSlot(outItem.getSlotlocation() + "");
barcode.setAppendInfo(appendInfo);
barcodeDao.save(barcode);
robPos.setBarcode(barcode);
storagePosDao.save(robPos);
outItem.setRealLockQty(outItem.getRealLockQty() + reelQty);
outItemDao.save(outItem);
outInfoCache.updateOutItem(oldItem.getId());
outInfoCache.updateOutItem(outItem.getId());
}
}
}
}
//-------------------------Private Method----------------------------------------
/**
* 尝试真实绑定
* @param pos 包含料盘的库位
* @param outItem 出库需求项
* @return 如果库位为null,返回null;否则返回更新后的出库需求项
*/
private OutItem tryRealBind(StoragePos pos, OutItem outItem){
if(pos == null){
log.info("\t真实绑定"+outItem.getSlotlocation() + "的pn=["+outItem.getPn()+"]facility = "+outItem.getFacility()+"时无库存,跳出绑定");
return null;
}else{
Barcode barcode = pos.getBarcode();
int dbQty = barcode.getAmount();
int realLockQty = outItem.getRealLockQty();
int newRealLockQty = realLockQty + dbQty;
log.info("\t真实绑定["+pos.getBarcode().getBarcode()+"]到So=["+outItem.getSo()+"]hSerial=["+outItem.gethSerial()+"]refno=["+outItem.getRefno()+"]的["+outItem.getSlotlocation()+"] 绑定数量:" + outItem.getRealLockQty() +"/" + outItem.getQty());
AppendInfo appendInfo = barcode.getAppendInfo();
appendInfo.sethSerial(outItem.gethSerial());
appendInfo.setRefno(outItem.getRefno());
appendInfo.setSo(outItem.getSo());
appendInfo.setSoseq(outItem.getSoseq());
appendInfo.setSlotStr(outItem.getSlotStr());
appendInfo.setBindSlot(outItem.getSlotlocation()+"");
appendInfo.setSlotIndex(outItem.getSlotlocation());
barcode.setAppendInfo(appendInfo);
pos.setBarcode(barcode);
storagePosDao.save(pos);
outItem.setRealLockQty(newRealLockQty);
outItem = outItemDao.save(outItem);
return outItem;
}
}
private OutItem updateRealLockQty(OutItem outItem){
//查找真实绑定
List<StoragePos> bindPosList = storagePosDao.findBindList(outItem.getSo(), outItem.getSlotlocation());
int realBindQty = 0;
for (StoragePos bindPos : bindPosList) {
realBindQty = realBindQty + bindPos.getBarcode().getAmount();
}
outItem.setRealLockQty(realBindQty);
int lockQty = outItem.getLockQty();
if(lockQty < realBindQty){
lockQty = realBindQty;
outItem.setLockQty(lockQty);
}
if(outItem.isCutMaterial()){
//分盘料,需要将已绑定未出库的物料也计算进去
List<StoragePos> cutReels = storagePosDao.findCutList(outItem.getSo(), outItem.getSlotlocation(), outItem.getSoseq());
for (StoragePos cutReel : cutReels) {
List<Map<String, Object>> cutItems = cutReel.getBarcode().getCutItems();
for (Map<String, Object> cutItem : cutItems) {
String so = cutItem.get("so").toString();
String soseqStr = cutItem.get("soseq").toString();
String slotlocation = cutItem.get("slotlocation").toString();
if(outItem.getSo().equals(so) && outItem.getSoseq().equals(soseqStr) && outItem.getSlotlocation() == Integer.valueOf(slotlocation)){
log.info("查找到未出库的分盘料信息["+cutItem+"],更新预绑定数量");
String qty = cutItem.get("qty").toString();
lockQty = outItem.getLockQty() + Integer.valueOf(qty);
outItem.setLockQty(lockQty);
}
}
}
}
outItem = outItemDao.save(outItem);
log.info("更新["+outItem.getSlotlocation()+"]"+outItem.getPn()+"真实绑定数量为["+realBindQty+"/"+outItem.getQty()+"]");
return outItem;
}
/**
* 真实绑定非分盘料
*/
private void realBindReel(OutItem outItem){
if(!outItem.isCutMaterial()){
//先从预绑定料盘中进行绑定,如果还有缺料的,从未使用的物料中查找,如果还缺料,从预绑定的物料中查找
updateRealLockQty(outItem);
log.info("绑定非分盘料:So=["+outItem.getSo()+"]hSerial=["+outItem.gethSerial()+"]+refno=["+outItem.getRefno()+"]的slotLoction"+outItem.getSlotlocation()+"]pn=["+outItem.getPn()+"]当前绑定数量["+outItem.getRealLockQty()+"/"+outItem.getQty()+"]当前出库/发料数量["+outItem.getOutQty()+"/"+outItem.getSendQty()+"]");
List<StoragePos> preBindPosList = storagePosDao.findPreBindList(outItem.getSo(), outItem.getSlotlocation());
for (StoragePos pos : preBindPosList) {
outItem = tryRealBind(pos, outItem);
}
//所需数量=需求单数量-已发料数量-真实绑定数量
int needNum = outItem.getQty() - outItem.getSendQty() - outItem.getRealLockQty();
log.info("将预绑定转为真实绑定结束,所需数量("+needNum+")=需求单数量("+outItem.getQty()+")-已发料数量("+ outItem.getSendQty()+")-真实绑定数量"+ outItem.getRealLockQty() +")");
if(needNum >= 0){
log.info("预绑定数量不足,查找未绑定料盘进行真实绑定结束,当前数量:"+outItem.getSendQty()+"+"+ outItem.getRealLockQty() +"/" + outItem.getQty());
while(needNum >= 0){
StoragePos pos = storagePosDao.findNoBindMinQty(outItem.getPn(), outItem.getFacility());
OutItem resultOutItem = tryRealBind(pos, outItem);
if(resultOutItem == null){
break;
}
outItem = resultOutItem;
if(outItem.getRealLockQty() > outItem.getQty()){
//已经满足需求了,直接跳出
break;
}
}
}
needNum = outItem.getQty() - outItem.getSendQty() - outItem.getRealLockQty();
if(needNum >= 0 ){
log.info("未绑定料盘数量不足,开始抢其他工单的预绑定物料进行真实绑定,当前数量:"+outItem.getSendQty()+"+"+ outItem.getRealLockQty() +"/" + outItem.getQty());
//抢其他工单的预绑定
while(needNum >= 0){
StoragePos pos = storagePosDao.findOtherPreBindMinQty(outItem.getPn(), outItem.getFacility());
OutItem resultOutItem = tryRealBind(pos, outItem);
if(resultOutItem == null){
break;
}
outItem = resultOutItem;
if(outItem.getRealLockQty() + outItem.getSendQty() > outItem.getQty()){
//已经满足需求了,直接跳出
break;
}
}
}
//多出数量
int surplusQty = -needNum;
if(surplusQty >= 0){
//已经预绑定的所有料盘中与最大盘日期相同,且与超出数量最接近的料盘剔除掉
StoragePos maxBindReelPos = storagePosDao.findMaxQtyBindReel(outItem.getSoseq(), outItem.getSlotlocation());
if(maxBindReelPos != null){
Barcode maxQtyBindReelBarcode = maxBindReelPos.getBarcode();
StoragePos needToUnBindPos = storagePosDao.findSurplusBindReel(outItem.getSoseq(), outItem.getSlotlocation(), surplusQty, maxQtyBindReelBarcode.getProduceDateStr());
if(needToUnBindPos != null){
int unbindAmount = needToUnBindPos.getBarcode().getAmount();
log.info("找到与最大料盘["+maxQtyBindReelBarcode.getBarcode()+"]相同日期["+maxQtyBindReelBarcode.getProduceDateStr()+"]与超绑数量["+surplusQty+"]接近的料盘["+needToUnBindPos.getBarcode().getBarcode()+"]数量为["+unbindAmount+"]解除绑定");
storagePosDao.unbindReel(needToUnBindPos);
int newLockQty = outItem.getRealLockQty() - unbindAmount;
outItem.setLockQty(newLockQty);
outItem = outItemDao.save(outItem);
}
}
}
//首盘,如果此站位一盘也没有,查找是否有同工单不同站位的PN,如果有,抢一盘过来
log.info("So=["+outItem.getSo()+"]hSerial=["+outItem.gethSerial()+"]+refno=["+outItem.getRefno()+"]的slot"+outItem.getSlotlocation()+"]pn=["+outItem.getPn()+"]真实绑定结束,当前数量:"+outItem.getSendQty()+"+"+ outItem.getRealLockQty() +"/" + outItem.getQty());
}
}
/**
* 预绑定非分盘料
*/
private void preBindReel(OutItem outItem){
if(!outItem.isCutMaterial()){
log.info("预绑定非分盘料:So=["+outItem.getSo()+"]hSerial=["+outItem.gethSerial()+"]+refno=["+outItem.getRefno()+"]的slot"+outItem.getSlotlocation()+"]pn=["+outItem.getPn()+"]当前预绑定数量["+outItem.getLockQty()+"/"+outItem.getQty()+"]");
while (true){
StoragePos pos = storagePosDao.findNoBindMinQty(outItem.getPn(), outItem.getFacility());
if(pos == null){
log.info("\t预绑定"+outItem.getSlotlocation() + "的pn=["+outItem.getPn()+"]facility = "+outItem.getFacility()+"时无库存,跳出预绑定");
break;
}else{
int dbQty = pos.getBarcode().getAmount();
int lockQty = outItem.getLockQty();
int newLockQty = lockQty + dbQty;
log.info("\t预绑定["+pos.getBarcode().getBarcode()+"]到So=["+outItem.getSo()+"]hSerial=["+outItem.gethSerial()+"]refno=["+outItem.getRefno()+"]的["+outItem.getSlotlocation()+"] 数量:" + newLockQty +"/" + outItem.getQty());
Barcode barcode = pos.getBarcode();
AppendInfo appendInfo = barcode.getAppendInfo();
appendInfo.sethSerial(outItem.gethSerial());
appendInfo.setRefno(outItem.getRefno());
appendInfo.setSo(outItem.getSo());
appendInfo.setSoseq(outItem.getSoseq());
appendInfo.setPreBindSlot(outItem.getSlotlocation()+"");
barcode.setAppendInfo(appendInfo);
pos.setBarcode(barcode);
storagePosDao.save(pos);
outItem.setLockQty(newLockQty);
outItem = outItemDao.save(outItem);
//多出数量
int surplusQty = newLockQty - outItem.getQty();
if(surplusQty >= 0){
//已经满足需求了,剔除同日期的小料盘后直接跳出
//已经预绑定的所有料盘中与最大盘日期相同,且与超出数量最接近的料盘剔除掉
StoragePos needToUnBindPos = storagePosDao.findSurplusPreBindReel(outItem.getSoseq(), outItem.getSlotlocation(), surplusQty, barcode.getProduceDateStr());
if(needToUnBindPos != null){
int unbindAmount = needToUnBindPos.getBarcode().getAmount();
log.info("找到与最大料盘["+barcode.getBarcode()+"]相同日期["+barcode.getProduceDateStr()+"]与超绑数量["+surplusQty+"]接近的料盘["+needToUnBindPos.getBarcode().getBarcode()+"]数量为["+unbindAmount+"]解除预绑定");
storagePosDao.unbindReel(needToUnBindPos);
newLockQty = newLockQty - unbindAmount;
outItem.setLockQty(newLockQty);
outItem = outItemDao.save(outItem);
}
break;
}
}
}
}
}
/**
* 分盘需求第一次绑定: 第一轮挑料:
1.料卷数量等于需求
2.料卷数量,从小到大去挑选,加总数量小于等于需求
*/
private void firstBindCutReel(OutItem outItem){
if(outItem.isCutMaterial()){
updateRealLockQty(outItem);
log.info("第一轮绑定分盘料:So=["+outItem.getSo()+"]hSerial=["+outItem.gethSerial()+"]的slot"+outItem.getSlotlocation()+"]pn=["+outItem.getPn()+"]当前绑定数量["+outItem.getLockQty()+"/"+outItem.getQty()+"]");
//剩余需求数量
int needNum = outItem.getQty() - outItem.getLockQty();
while(needNum > 0){
//分盘料
StoragePos pos = storagePosDao.findNoBindNoCutMinQty(outItem.getPn(), outItem.getFacility());
if(pos == null){
log.info("\t第一轮绑定分盘料"+outItem.getSlotlocation() + "的pn=["+outItem.getPn()+"]facility = "+outItem.getFacility()+"时无库存,跳出绑定");
break;
}else{
Barcode barcode = pos.getBarcode();
int totalLockQty = outItem.getLockQty() + barcode.getAmount();
if(totalLockQty > outItem.getQty()){
log.info("加总数量["+totalLockQty+"]大于需求数量["+outItem.getQty()+"]跳出第一轮绑定");
break;
}
if(!barcode.hasCutInfo()){
log.info("\t第一轮绑定分盘料["+barcode.getBarcode()+"]绑定到So=["+outItem.getSo()+"]hSerial=["+outItem.gethSerial()+"]refno=["+outItem.getRefno()+"]的["+outItem.getSlotlocation()+"] 数量:" + totalLockQty +"/" + outItem.getQty());
//没有分盘信息,可以直接绑定
AppendInfo appendInfo = barcode.getAppendInfo();
appendInfo.sethSerial(outItem.gethSerial());
appendInfo.setRefno(outItem.getRefno());
appendInfo.setSo(outItem.getSo());
appendInfo.setSoseq(outItem.getSoseq());
appendInfo.setSlotStr(outItem.getSlotStr());
appendInfo.setBindSlot(outItem.getSlotlocation() + "");
appendInfo.setSlotIndex(outItem.getSlotlocation());
barcode.setAppendInfo(appendInfo);
int realLockQty = outItem.getRealLockQty() + barcode.getAmount();
outItem.setRealLockQty(realLockQty);
barcode = barcodeDao.save(barcode);
pos.setBarcode(barcode);
storagePosDao.save(pos);
outItem.setLockQty(totalLockQty);
outItemDao.save(outItem);
needNum = outItem.getQty() - totalLockQty;
}else{
log.error("这句不应该出现,第一轮绑定分盘料时查到分盘信息的物料,分盘料["+barcode.getBarcode()+"]分盘信息:" + barcode.getAppendInfo().getCutMap());
break;
}
}
}
}
}
/**
* 1.料卷数量等于余量(需分盘的数量)的总数量
2.By SO逐一挑选,料卷数量,从小到大去挑选
* @param outItem
*/
private void secondBindCutReel(OutItem outItem){
if(outItem.isCutMaterial()){
log.info("第二轮绑定分盘料:So=["+outItem.getSo()+"]hSerial=["+outItem.gethSerial()+"]+refno=["+outItem.getRefno()+"]的slot"+outItem.getSlotlocation()+"]pn=["+outItem.getPn()+"]当前预绑定数量["+outItem.getLockQty()+"/"+outItem.getQty()+"]");
//剩余需求数量
int needNum = outItem.getQty() - outItem.getLockQty();
while(needNum > 0){
//分盘料
StoragePos pos = storagePosDao.findNoBindMinQty(outItem.getPn(), outItem.getFacility());
if(pos == null){
log.info("\t第二轮分盘料绑定"+outItem.getSlotlocation() + "的pn=["+outItem.getPn()+"]facility = "+outItem.getFacility()+"时无库存,跳出绑定");
break;
}else{
Barcode barcode = pos.getBarcode();
int lockQty = outItem.getLockQty();
int remainQty = outItem.getQty() - lockQty;
//还有未绑定的需求
int reelRemainNum = barcode.cutCount(outItem.getSoseq(), outItem.getSo(), outItem.getSlotlocation(), outItem.getSlotStr(), outItem.gethSerial(), remainQty);
if(reelRemainNum > 0){
//母盘还有剩余,说明该需求slot已经满足
lockQty = outItem.getQty();
}else {
//母盘正好用完或全部用完也达不到需求量,此母盘绑定slot后,继续寻找其他盘进行绑定
lockQty = lockQty + barcode.getAmount();
}
log.info("\t分盘料["+barcode.getBarcode()+"]绑定到Soseq=["+outItem.getSoseq()+"]So=["+outItem.getSo()+"]hSerial=["+outItem.gethSerial()+"]refno=["+outItem.getRefno()+"]的["+outItem.getSlotlocation()+"] 数量:" + lockQty +"/" + outItem.getQty());
if(!barcode.hasCutInfo()){
//没有分盘信息,可以直接绑定
AppendInfo appendInfo = barcode.getAppendInfo();
appendInfo.sethSerial(outItem.gethSerial());
appendInfo.setRefno(outItem.getRefno());
appendInfo.setSo(outItem.getSo());
appendInfo.setSoseq(outItem.getSoseq());
appendInfo.setSlotStr(outItem.getSlotStr());
appendInfo.setBindSlot(outItem.getSlotlocation() + "");
appendInfo.setSlotIndex(outItem.getSlotlocation());
barcode.setAppendInfo(appendInfo);
int realLockQty = outItem.getRealLockQty() + barcode.getAmount();
outItem.setRealLockQty(realLockQty);
}else{
AppendInfo appendInfo = barcode.getAppendInfo();
appendInfo.setSo(outItem.getSo());
appendInfo.setSoseq(outItem.getSoseq());
barcode.setAppendInfo(appendInfo);
log.info("分盘料["+barcode.getBarcode()+"]分盘信息:" + barcode.getAppendInfo().getCutMap());
}
barcode = barcodeDao.save(barcode);
pos.setBarcode(barcode);
storagePosDao.save(pos);
outItem.setLockQty(lockQty);
outItemDao.save(outItem);
needNum = outItem.getQty() - lockQty;
}
}
}
}
......@@ -804,7 +344,7 @@ public class QisdaApiController extends BaseController {
Object slotlocation = cutItem.get("slotlocation");
materialInfoMap.put("slotserial", slotlocation + "");
log.info("发送分盘料信息:" + cutItem);
log.info(barcode.getBarcode() + "发送分盘料信息:" + cutItem);
QisdaApi.VMILocationOut(materialInfoMap);
}
}else{
......@@ -846,277 +386,6 @@ public class QisdaApiController extends BaseController {
private List<DataLog> checkOutUrgent(OutItem outItem){
List<DataLog> tasks = new ArrayList<>();
//紧急料,直接出库
String reelID = outItem.getReelID();
if(reelID != null){
//指定出某盘料或单独出库
StoragePos pos = storagePosDao.findByBarcode(reelID);
if(pos != null){
DataLog task = newTask(outItem, pos);
task = InquiryShelfBean.addUnlimitLoc(task, outItem);
task = dataLogDao.save(task);
tasks.add(task);
}
}else{
//紧急料,未绑定数量=需求单数量-已出库数量-已绑数量
int needNum = outItem.getQty() - outItem.getOutQty() - outItem.getRealLockQty();
if(needNum >= 0){
log.info("紧急料,查找未绑定料盘进行出库,未绑数量为"+needNum+"=(需求单"+ outItem.getQty() + ") - (已出" + outItem.getOutQty() + ")-已绑(" + outItem.getRealLockQty()+")");
while(needNum >= 0){
StoragePos pos = storagePosDao.findNoBindMinQty(outItem.getPn(), outItem.getFacility());
if(pos != null){
//找到了,进行出库
DataLog task = newTask(outItem, pos);
task = InquiryShelfBean.addUnlimitLoc(task, outItem);
task = dataLogDao.save(task);
tasks.add(task);
outItem.setRealLockQty(outItem.getRealLockQty() + task.getNum());
needNum = outItem.getQty() - outItem.getRealLockQty();
}else{
//未找到未绑定的物料了
break;
}
}
}
}
return tasks;
}
private List<DataLog> checkOutCut(OutItem outItem){
List<DataLog> tasks = new ArrayList<>();
if(outItem.isCutMaterial()){
//分盘料
secondBindCutReel(outItem);
//出分盘料
List<StoragePos> cutPosList = storagePosDao.findCutList(outItem.getSo(), outItem.getSlotlocation(),outItem.getSoseq());
for (StoragePos pos : cutPosList) {
DataLog task = newTask(outItem, pos);
task = InquiryShelfBean.addUnlimitLoc(task, outItem);
task = dataLogDao.save(task);
tasks.add(task);
}
}
return tasks;
}
private List<DataLog> checkOutTail(OutItem outItem){
List<DataLog> tasks = new ArrayList<>();
if(outItem.getSendQty() > outItem.getQty()){
//出经发完料
return tasks;
}
//再绑定一遍
firstBindCutReel(outItem);
secondBindCutReel(outItem);
realBindReel(outItem);
List<StoragePos> bindPosList = storagePosDao.findBindList(outItem.getSo(), outItem.getSlotlocation());
//没有顺序
int sendQty = outItem.getSendQty();
for (StoragePos pos : bindPosList) {
Barcode posBarcode = pos.getBarcode();
DataLog task = newTask(outItem, pos);
task = InquiryShelfBean.addUnlimitLoc(task, outItem);
task = dataLogDao.save(task);
tasks.add(task);
sendQty = sendQty + posBarcode.getAmount();
if(sendQty >= outItem.getQty()){
break;
}
}
return tasks;
}
private List<DataLog> checkOutFirst(OutItem outItem,List<String> outReelIdList){
List<DataLog> tasks = new ArrayList<>();
//再绑定一遍
firstBindCutReel(outItem);
secondBindCutReel(outItem);
realBindReel(outItem);
if(outItem.getSendQty() > 0){
//出经发完料
return tasks;
}
bindSamePnFromOtherSlotForFirstAction(outItem,outReelIdList);
//taskService
List<StoragePos> bindPosList = storagePosDao.findBindList(outItem.getSo(), outItem.getSlotlocation());
//首盘料,出到双层线上,按站位顺序,只出最大的一盘
StoragePos maxQtyPos = null;
for (StoragePos pos : bindPosList) {
//不是需要分盘但未分盘的料
Barcode posBarcode = pos.getBarcode();
if(!posBarcode.hasCutInfo()){
if(maxQtyPos == null){
maxQtyPos = pos;
}
if(posBarcode.getAmount() > maxQtyPos.getBarcode().getAmount()){
maxQtyPos = pos;
}
}
}
if(maxQtyPos != null){
//加入料架
log.info(outItem.toString() + "找到最大数量料盘["+maxQtyPos.getBarcode().getBarcode()+"],准备出库");
DataLog task = newTask(outItem, maxQtyPos);
task = InquiryShelfBean.addLimitLoc(task, outItem);
task = dataLogDao.save(task);
tasks.add(task);
}else{
//缺料,查看是否有本工单,同PN的,如果有抢一个过来
//缺料,料架留空
boolean hasBigSizePn = false;
List<Component> pnList = componentManager.listByPn(outItem.getPn());
for (Component c : pnList) {
if(c.getPlateSize() > 7 || c.getHeight() > 12){
hasBigSizePn = true;
break;
}
}
if(pnList.isEmpty()){
log.error("未找到物料["+outItem.getPn()+"]的尺寸信息,保留C类型架位");
InquiryShelfBean.addEmptyLoc(outItem, StorageConstants.SHEFL_TYPE.C);
}else if(hasBigSizePn){
log.info(outItem.getSlotlocation() + "["+outItem.getPn()+"]缺料,且PN数据中有大料,保留C类型架位");
InquiryShelfBean.addEmptyLoc(outItem, StorageConstants.SHEFL_TYPE.C);
}else {
log.info(outItem.getSlotlocation() + "["+outItem.getPn()+"]缺料,保留D类型架位");
InquiryShelfBean.addEmptyLoc(outItem, StorageConstants.SHEFL_TYPE.D);
}
}
return tasks;
}
private synchronized String checkOutOutItems(String hSerial){
log.info("执行需求单["+hSerial+"]出库");
OutInfo outInfo = outInfoDao.findByHSerial(hSerial);
if(outInfo == null){
return "未找到需求单["+hSerial+"]";
}
//如果有其他任务在执行,不允许出库
Collection<DataLog> queueTasks = taskService.getQueueTasks();
List<DataLog> allTasks = taskService.getFinishedTasks();
if(!queueTasks.isEmpty()){
allTasks.addAll(queueTasks);
}
//是否有工单料任务
boolean hasOrderTask = false;
boolean hasUrgenReel = false;
for (DataLog dataLog : allTasks) {
if(dataLog.isCheckOutTask()){
if(!dataLog.isUrgentReel() && !dataLog.isCutReel()){
//工单料(不是指定料也不是分盘料即首盘或补料)
hasOrderTask = true;
}else{
//分盘和紧急料
String taskHSerial = dataLog.getAppendInfo().gethSerial();
if(taskHSerial.equals(hSerial)){
return "当前需求单还有未完成的任务";
}
hasUrgenReel = true;
}
}
}
if(!hasUrgenReel){
log.info("已无紧急料和分盘料任务,清空紧急料/分盘料料架");
InquiryShelfBean.clearShelf(InquiryShelfBean.URGENT_SHELF_MAP_KEY);
InquiryShelfBean.clearShelf(InquiryShelfBean.CUT_SHELF_MAP_KEY);
}
//首盘和补料
if(!outInfo.isReelCutAction() && !outInfo.isUrgentAction() && hasOrderTask){
return "全部任务完成后才可执行";
}
//如果是工单需求单,设置当前正在执行的工单需求单
if(outInfo.isFirstReelAction() || outInfo.isTailAction()){
String oldHSerial = outInfoCache.getCurrentOrderHSerial();
log.info("设置当前正在执行的工单料需求为:" + outInfo.gethSerial()+"清理之前["+oldHSerial+"]出库使用的料架");
InquiryShelfBean.clearShelf(oldHSerial);
outInfoCache.setCurrentOrderHSerial(outInfo.gethSerial());
}
List<DataLog> tasks = new ArrayList<>();
List<String> outReelIdList = new ArrayList<>();
List<OutItem> itemList = outItemDao.findByHSerial(hSerial);
for (OutItem outItem : itemList) {
outItem = updateRealLockQty(outItem);
List<DataLog> itemTasks = null;
if(outItem.isUrgentAction()){
itemTasks = checkOutUrgent(outItem);
}else if(outItem.isReelCutAction()){
//分盘需求单
itemTasks = checkOutCut(outItem);
}else if(outItem.isFirstReelAction()){
//首盘料需求单
itemTasks = checkOutFirst(outItem,outReelIdList);
}else{
//尾料需求单
itemTasks = checkOutTail(outItem);
}
if(itemTasks != null && !itemTasks.isEmpty()){
for (DataLog itemTask : itemTasks) {
tasks.add(itemTask);
outReelIdList.add(itemTask.getBarcode());
}
}
outInfoCache.updateOutItem(outItem.getId());
}
int outReelNum = tasks.size();
if(outReelNum > 0){
log.info("需求单"+outInfo.gethSerial()+"已出("+outInfo.getOutReelNum()+")/已发("+outInfo.getTaskFinishNum()+") 本次出库料盘数量:" + outReelNum);
outInfo.setOutReelNum(0);
outInfo.setTaskFinishNum(0);
outInfo.setTaskNum(outReelNum);
outInfo.setSendStatus(StorageConstants.SEND_STATUS.EXECUTING);
outInfo = outInfoDao.save(outInfo);
outInfoCache.resetTaskNum(hSerial, outReelNum);
//先出小料盘,再出大料盘
for (DataLog task : tasks) {
if(task.isSmallReel()){
taskService.addTaskToExecute(task);
}
}
for (DataLog task : tasks) {
if(!task.isSmallReel()){
taskService.addTaskToExecute(task);
}
}
}else{
log.info("需求单"+outInfo.gethSerial()+"本次出库料盘数量为0");
}
if(outInfo.isReelCutAction() || outInfo.isFirstReelAction()){
if(outReelNum == 0){
List<OutItem> outItemList = outItemDao.findByHSerial(outInfo.gethSerial());
boolean lessBind = false;
QisdaApi.VMILocationOutFeedback(outItemList, lessBind);
}
}
String msg = "需求单"+hSerial+"任务分配完成,共["+outReelNum+"]盘任务";
log.info(msg);
return msg;
}
/**
* 获取接收参数
*/
......@@ -1130,54 +399,7 @@ public class QisdaApiController extends BaseController {
return paramInfo;
}
private DataLog newTask(OutItem outItem, StoragePos pos){
DataLog task = new DataLog();
task.setType(StorageConstants.OP.CHECKOUT);
task.setStatus(StorageConstants.OP_STATUS.WAIT.name());
Barcode barcode = pos.getBarcode();
if(barcode != null){
task.setPartNumber(barcode.getPartNumber());
task.setBarcode(barcode.getBarcode());
task.setNum(barcode.getInitialAmount());
task.setW(barcode.getPlateSize());
task.setH(barcode.getHeight());
task.setSourceName(outItem.getSourceName());
AppendInfo appendInfo = barcode.getAppendInfo();
appendInfo.setSo(outItem.getSo());
appendInfo.setSoseq(outItem.getSoseq());
appendInfo.setRefno(outItem.getRefno());
appendInfo.sethSerial(outItem.gethSerial());
appendInfo.setSlotStr(outItem.getSlotStr());
appendInfo.setSlotIndex(outItem.getSlotlocation());
appendInfo.setAction(outItem.getAction());
appendInfo.setOutItemId(outItem.getId());
task.setAppendInfo(appendInfo);
if(barcode.hasCutInfo()){
task.setCutReel(true);
}
}
if(outItem.isUrgentAction()){
task.setUrgentReel(true);
}
Storage storage = dataCache.getStorageById(pos.getStorageId());
if(storage.isPackage()){
//包装料仓
task.setPackageReel(true);
}
task.setCid(storage.getCid());
task.setStorageId(storage.getId());
task.setStorageName(storage.getName());
task.setPosId(pos.getId());
task.setPosName(pos.getPosName());
return task;
}
private Map<String, String> getParamMapFromBody(HttpServletRequest request){
Map<String,String> paramMap = new HashMap<>();
......
......@@ -47,21 +47,12 @@ public class QisdaDeviceController extends BaseController {
private IBarcodeManager barcodeManager;
@Autowired
private IStoragePosDao storagePosDao;
@Autowired
private DataCache dataCache;
@Autowired
private IDataLogDao dataLogDao;
@Autowired
private IOutInfoDao outInfoDao;
@Autowired
private IOutItemDao outItemDao;
@Autowired
private OutInfoCache outInfoCache;
@Autowired
......@@ -70,11 +61,6 @@ public class QisdaDeviceController extends BaseController {
protected final static Logger log = LogManager.getLogger(QisdaDeviceController.class);
/**
* 需求单料架管理map, key为outInquiryId, value为料架信息
*/
InquiryShelfBean inquiryShelfBean = new InquiryShelfBean();
/**
* 第一台机器人缓存位置信息(流水线扫码后获取尺寸时更新)
*/
private DataLog firstRobotTask = null;
......@@ -107,31 +93,50 @@ public class QisdaDeviceController extends BaseController {
//清空扫码缓存信息
updateScanTask(robotIndex, null);
Barcode barcode = dataCache.resolveOneValideBarcode(barcodeStr);
//Barcode barcode = dataCache.resolveOneValideBarcode(barcodeStr);
Collection<CodeBean> codeBeans = dataCache.resolveCodeStr(barcodeStr);
Barcode barcode = null;
for (CodeBean codeBean : codeBeans) {
if(codeBean.isValid()){
if(barcode != null){
String msg = "找到多个有效条码";
throw new ValidateException(msg);
}else{
barcode = codeBean.getBarcode();
}
//防止条码重复发送,现在已经不需要了
// boolean firstScanSame = isSameTask(barcode,firstScanTask);
// boolean firstRobtoSame = isSameTask(barcode,firstRobotTask);
// boolean secondScanSame = isSameTask(barcode,secondScanTask);
// boolean secondRobtoSame = isSameTask(barcode,secondRobotTask);
// if(firstScanSame || firstRobtoSame || secondScanSame || secondRobtoSame){
// String msg = "条码["+barcode.getBarcode()+"]与已有任务重复,获取尺寸信息失败";
// log.error(msg);
//
// return ResultBean.newErrorResult(105, msg);
// }
}
}
if(barcode == null){
String msg = "未找到有效条码";
throw new ValidateException(msg);
}
DataLog task = taskService.getFinishedTask(barcode.getBarcode());
if(task == null){
String msg = "未找到待分配位置的条码["+barcode.getBarcode()+"]尺寸信息";
log.error(msg);
return ResultBean.newErrorResult(103, msg);
}else if(task.isFinished()){
String msg = "条码["+barcode.getBarcode()+"]的任务已完成,不返回尺寸信息";
log.error(msg);
return ResultBean.newErrorResult(104, msg);
}else{
if(task.isFinished()){
String msg = "条码["+barcode.getBarcode()+"]的任务已完成,不返回尺寸信息";
return ResultBean.newErrorResult(104, msg);
}else {
String hSerial = task.getAppendInfo().gethSerial();
String executingHSerial = QisdaCache.getCurrentOrderHSerial();
if(!executingHSerial.equals(hSerial)){
String msg = "料盘["+barcode.getBarcode()+"]任务的需求单号与当前正在执行的需求单号不一致,不返回尺寸信息";
return ResultBean.newErrorResult(106, msg);
}
boolean firstRobtoSame = isSameTask(barcode,firstRobotTask);
boolean secondRobtoSame = isSameTask(barcode,secondRobotTask);
if (firstRobtoSame || secondRobtoSame){
String msg = "机器人正在将料盘["+barcode.getBarcode()+"]的放上料架,不返回尺寸信息";
return ResultBean.newErrorResult(106, msg);
}
}
}
updateScanTask(robotIndex, task);
......@@ -141,7 +146,7 @@ public class QisdaDeviceController extends BaseController {
}catch(ValidateException e){
log.warn("流水线获取尺寸信息出错:"+e.getMessage());
return ResultBean.newErrorResult(105,"流水线获取尺寸信息内部错误:" + e.getMessage());
return ResultBean.newErrorResult(105,"流水线获取尺寸信息错误:" + e.getMessage());
}catch(Exception e){
log.error("流水线获取尺寸信息出错",e);
return ResultBean.newErrorResult(-1,"流水线获取尺寸信息内部错误:" + e.getMessage());
......@@ -216,7 +221,7 @@ public class QisdaDeviceController extends BaseController {
String bigRfid = request.getParameter("bigRfid");
//包装料RFID
String packageRfid = request.getParameter("packageRfid");
String hSerial = outInfoCache.getCurrentOrderHSerial();
String hSerial = QisdaCache.getCurrentOrderHSerial();
if(hSerial.isEmpty()){
return ResultBean.newErrorResult(-2, "未找到大料架["+bigRfid+"]");
}
......@@ -224,7 +229,7 @@ public class QisdaDeviceController extends BaseController {
for (DataLog task : allTasks) {
//如果还有小料任务未完成,说明换了需求单了,放行大料架
if(task.isCheckOutTask() && task.isSmallReel() && !task.isPackageReel()){
if(task.isCheckOutTask() && task.isSmallReel() && !task.isPackageReel() && !task.isLessSendReel()){
AppendInfo appendInfo = task.getAppendInfo();
if(appendInfo.isFirstReelAction() || appendInfo.isTailAction()){
return ResultBean.newErrorResult(-3, "还有小料任务,需求单已更换,大料架["+bigRfid+"]放行");
......@@ -233,14 +238,14 @@ public class QisdaDeviceController extends BaseController {
}
log.info("收到机器人[3]获取包装料摆放位置信息请求:[packageRfid=" + packageRfid + "]bigRfid=" + bigRfid + "当前工单料需求:["+hSerial+"]");
ShelfInfo packageShelf = inquiryShelfBean.findPackageShelf(hSerial, packageRfid);
ShelfInfo packageShelf = InquiryShelfBean.findPackageShelf(hSerial, packageRfid);
ShelfInfo bigShelf = inquiryShelfBean.findSameShelf(hSerial,bigRfid);
ShelfInfo bigShelf = InquiryShelfBean.findSameShelf(hSerial,bigRfid);
//未找到,说明是未绑定过的新料架,找相同类型的进行绑定
//未找到已经有实际RFID的料架,查找库位最多的料架
if(bigShelf == null){
log.info("未找到实际绑定的["+bigRfid+"]料架,开始查找序号最小的C型料架");
ShelfInfo maxLocShelf = inquiryShelfBean.findMaxUsedShelf(hSerial, StorageConstants.SHEFL_TYPE.C);
ShelfInfo maxLocShelf = InquiryShelfBean.findMaxUsedShelf(hSerial, StorageConstants.SHEFL_TYPE.C);
if(maxLocShelf != null){
bigShelf = maxLocShelf;
}else{
......@@ -394,9 +399,9 @@ public class QisdaDeviceController extends BaseController {
ShelfLoc shelfLoc = null;
if(appendInfo.isFirstReelAction()){
//首盘料已经固定好库位了
shelfLoc = inquiryShelfBean.getLimitLoc(task);
shelfLoc = InquiryShelfBean.getLimitLoc(task);
}else{
shelfLoc = inquiryShelfBean.lockShelfLoc(task, rfid, robotIndex);
shelfLoc = InquiryShelfBean.lockShelfLoc(task, rfid, robotIndex);
}
if(shelfLoc == null){
String msg = "机器人["+robotIndex+"]获取料架["+rfid+"]位置信息失败";
......@@ -422,7 +427,7 @@ public class QisdaDeviceController extends BaseController {
String hSerial = appendInfo.gethSerial();
List<String> usedRfidList = inquiryShelfBean.getUsedRfidList(hSerial);
List<String> usedRfidList = InquiryShelfBean.getUsedRfidList(hSerial);
Map<String,Object> resultMap = new HashMap<>();
resultMap.put("barcode", task.getBarcode());
......@@ -587,21 +592,33 @@ public class QisdaDeviceController extends BaseController {
log.debug("收到["+cid+"]紧急/分盘料[" + barcode + "]放入"+rfid+"[" + rfidLoc + "]指令");
DataLog task = findFinishedTask(barcode);
if(task != null){
ShelfLoc shelfLoc = inquiryShelfBean.putInCutReel(task,rfid, Integer.valueOf(rfidLoc));
ShelfLoc shelfLoc = InquiryShelfBean.putInCutReel(task,rfid, Integer.valueOf(rfidLoc));
if(shelfLoc != null){
log.info("["+cid+"]紧急/分盘料[" + barcode + "]放入"+rfid+"[" + rfidLoc + "]成功");
task.setStatus(StorageConstants.OP_STATUS.FINISHED.name());
rfidLoc = shelfLoc.getLoc() + "";
}else{
log.info(""+cid+"紧急/分盘料[" + barcode + "]放入"+rfid+"[" + rfidLoc + "]失败");
task.setStatus(StorageConstants.OP_STATUS.INSHELF.toString());
if(task.isLessSendReel()){
task.setStatus(StorageConstants.OP_STATUS.FINISHED.toString());
}else{
log.info(""+cid+"紧急/分盘料[" + barcode + "]放入"+rfid+"[" + rfidLoc + "]失败");
task.setStatus(StorageConstants.OP_STATUS.FINISHED.toString());
}
}
AppendInfo appendInfo = task.getAppendInfo();
//完成任务数量+1
outInfoCache.incTaskFinishNum(appendInfo.gethSerial(), 0, 0);
appendInfo.setRfid(rfid);
appendInfo.setRfidLoc(Integer.valueOf(rfidLoc));
int loc = task.resolveRfidLoc(rfidLoc);
appendInfo.setRfidLoc(loc);
task.setAppendInfo(appendInfo);
task = dataLogDao.save(task);
taskService.updateFinishedTask(task);
}
int cutPackageTask = 0;
......@@ -626,7 +643,7 @@ public class QisdaDeviceController extends BaseController {
cutTask = cutTask + 1;
}
}else if(unFinishedTask.isUrgentReel()){
}else if(unFinishedTask.isUrgentReel() || unFinishedTask.isLessSendReel()){
totalUrgentTask = totalUrgentTask + 1;
if(unFinishedTask.isPackageReel()) {
if (unFinishedTask.getCid().equals(cid)) {
......@@ -691,6 +708,13 @@ public class QisdaDeviceController extends BaseController {
return ResultBean.newErrorResult(301, "任务不存在");
}
if(task.isFinished()){
return ResultBean.newErrorResult(302, "任务已完成");
}
if(task.isCancel()){
return ResultBean.newErrorResult(303, "更新状态时"+task.getBarcode()+"的出库任务["+task.getId()+"]已被取消");
}
statusStr = statusStr.toUpperCase();
log.info("更新料盘["+barcode+"]的任务状态["+task.getStatus()+"=" + task.getLocInfo() + "]为["+statusStr+"="+locInfo+"]");
task.setStatus(statusStr);
......@@ -704,7 +728,7 @@ public class QisdaDeviceController extends BaseController {
String[] infos = locInfo.split("@");
String rfid = infos[0];
String rfidLoc = infos[1];
inquiryShelfBean.putInShelf(task,rfid, Integer.valueOf(rfidLoc));
InquiryShelfBean.putInShelf(task,rfid, Integer.valueOf(rfidLoc));
//剩余任务数
String taskCid = task.getCid();
......@@ -735,9 +759,9 @@ public class QisdaDeviceController extends BaseController {
private synchronized boolean reelPutInFinished(DataLog cacheTask, String rfid, String rfidLoc){
if(cacheTask != null){
AppendInfo appendInfo = cacheTask.getAppendInfo();
boolean putResult = inquiryShelfBean.putInShelf(cacheTask,rfid, Integer.valueOf(rfidLoc));
boolean putResult = InquiryShelfBean.putInShelf(cacheTask,rfid, Integer.valueOf(rfidLoc));
//紧急料和分盘料放入失败不影响
boolean isCutTask = cacheTask.isUrgentReel() || cacheTask.isCutReel();
boolean isCutTask = cacheTask.isUrgentReel() || cacheTask.isCutReel() || cacheTask.isLessSendReel();
if(!isCutTask && !putResult){
//记录日志
String errorMsg = "料盘["+cacheTask.getBarcode()+"]放入位置"+rfid+"["+rfidLoc+"]失败,原分配位置"+cacheTask.getTempRfid()+"["+appendInfo.getRfidLoc()+"],不更改状态,不进行发料";
......@@ -757,32 +781,33 @@ public class QisdaDeviceController extends BaseController {
log.info("料盘["+cacheTask.getBarcode()+"]放入位置"+rfid+"["+rfidLoc+"]成功");
cacheTask.setStatus(StorageConstants.OP_STATUS.FINISHED.name());
appendInfo.setRfid(rfid);
appendInfo.setRfidLoc(Integer.valueOf(rfidLoc));
int loc = cacheTask.resolveRfidLoc(rfidLoc);
appendInfo.setRfidLoc(loc);
cacheTask.setAppendInfo(appendInfo);
cacheTask = dataLogDao.save(cacheTask);
taskService.updateFinishedTask(cacheTask);
String hSerial = appendInfo.gethSerial();
if(Strings.isNotBlank(hSerial)){
OutInfo outInfo = outInfoCache.incTaskFinishNum(hSerial);
int slotSeq = appendInfo.getSlotIndex();
int sendQty = cacheTask.getNum();
//发料完成,更新发料数量
OutInfo outInfo = outInfoCache.incTaskFinishNum(hSerial,slotSeq, sendQty);
if(outInfo != null){
if(cacheTask.isUrgentReel() || cacheTask.isCutReel()){
log.info("分盘料和紧急料不需要通知Qisda");
}else{
}else if(cacheTask.isLessSendReel()){
log.info("缺料补发料需要通知Qisda");
Barcode barcodeObj = barcodeManager.findByBarcode(cacheTask.getBarcode());
String latest = outInfo.getShelfLatest();
QisdaApi.VMIMateriaRecAss(cacheTask, barcodeObj,latest);
} else{
Barcode barcodeObj = barcodeManager.findByBarcode(cacheTask.getBarcode());
String latest = outInfo.getShelfLatest();
QisdaApi.VMIMateriaRecAss(cacheTask, barcodeObj,latest);
//发料完成,更新发料数量
int slotSeq = appendInfo.getSlotIndex();
OutItem outItem = outItemDao.findItem(hSerial, slotSeq);
int sendQty = outItem.getSendQty();
sendQty = sendQty + cacheTask.getNum();
outItem.setSendQty(sendQty);
outItemDao.save(outItem);
outInfoCache.updateOutItem(outItem.getId());
}
}
}
......@@ -814,7 +839,7 @@ public class QisdaDeviceController extends BaseController {
boolean putInResult = reelPutInFinished(cacheTask,bigRfid, bigLoc);
if(putInResult){
//清理包装料架的位置
ShelfInfo packageShelf = inquiryShelfBean.findPackageShelf(cacheTask.getAppendInfo().gethSerial(), packageRfid);
ShelfInfo packageShelf = InquiryShelfBean.findPackageShelf(cacheTask.getAppendInfo().gethSerial(), packageRfid);
if(packageShelf != null){
log.info(msg + "成功,清空包装料架信息");
Map<Integer, ShelfLoc> packageLocMap = packageShelf.getLocMap();
......@@ -823,7 +848,7 @@ public class QisdaDeviceController extends BaseController {
shelfLoc.setEmpty(true);
packageLocMap.put(shelfLoc.getLoc(), shelfLoc);
packageShelf.setLocMap(packageLocMap);
inquiryShelfBean.updateShelfInfo(packageShelf);
InquiryShelfBean.updateShelfInfo(packageShelf);
return ResultBean.newOkResult(null);
}
}
......@@ -894,12 +919,12 @@ public class QisdaDeviceController extends BaseController {
for (DataLog task : allTasks) {
if(!task.isFinished() && !task.isCancel() && task.isCheckOutTask()){
if(task.isPackageReel()){
if(task.isCutReel() || task.isUrgentReel()){
if(task.isCutReel() || task.isUrgentReel() || task.isLessSendReel()){
cutPackageTask = cutPackageTask + 1;
}else{
packageTask = packageTask + 1;
}
}else if(task.isCutReel() || task.isUrgentReel()){
}else if(task.isCutReel() || task.isUrgentReel() || task.isLessSendReel()){
cutTask = cutTask + 1;
}else if(task.isSmallReel()){
smallTask = smallTask + 1;
......@@ -914,11 +939,11 @@ public class QisdaDeviceController extends BaseController {
int bigEmpty = 0;
int packageEmpty = 0;
String hSerial = outInfoCache.getCurrentOrderHSerial();
String hSerial = QisdaCache.getCurrentOrderHSerial();
if(cacheTask != null){
hSerial = cacheTask.getAppendInfo().gethSerial();
}
ShelfInfo shelfInfo = inquiryShelfBean.findSameShelf(hSerial,rfid);
ShelfInfo shelfInfo = InquiryShelfBean.findSameShelf(hSerial,rfid);
if(shelfInfo != null){
Map<Integer, ShelfLoc> locMap = shelfInfo.getLocMap();
for (ShelfLoc shelfLoc : locMap.values()) {
......@@ -945,7 +970,7 @@ public class QisdaDeviceController extends BaseController {
packageEmpty = 100;
}
List<String> usedRfidList = inquiryShelfBean.getUsedRfidList(hSerial);
List<String> usedRfidList = InquiryShelfBean.getUsedRfidList(hSerial);
//剩余的任务数
Map<String,Object> resultMap = new HashMap<>();
......
......@@ -589,6 +589,7 @@ public class StorageDataController extends BaseController {
Storage theStorage = dataCache.getStorageById(pos.getStorageId());
resultMap.put("cid",theStorage.getCid());
okMsg = "["+rfid+"]["+barcode.getBarcode()+"]准备入库到["+pos.getPosName()+"]";
log.info(okMsg);
taskService.addPutInTaskToExecute(theStorage, barcode, pos);
}else{
resultMap.put("result","104");
......
......@@ -3,7 +3,6 @@ package com.myproject.webapp.controller.webService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Strings;
import com.google.common.collect.*;
import com.myproject.api.ITaskNotify;
import com.myproject.bean.CodeBean;
import com.myproject.bean.json.LiteOrder;
import com.myproject.bean.json.LiteOrderItem;
......@@ -26,12 +25,10 @@ import com.myproject.manager.IHumitureManager;
import com.myproject.manager.IStoragePosManager;
import com.myproject.model.User;
import com.myproject.service.UserManager;
import com.myproject.util.HttpHelper;
import com.myproject.util.QisdaApi;
import com.myproject.util.StorageConstants;
import com.myproject.webapp.controller.qisda.QisdaController;
import com.myproject.webapp.controller.qisda.util.OutInfoCache;
import org.apache.commons.lang.StringUtils;
import com.myproject.webapp.controller.qisda.util.SoseqCache;
import org.apache.commons.lang.math.RandomUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
......@@ -90,6 +87,9 @@ public class TaskService implements ITaskService {
@Autowired
private OutInfoCache outInfoCache;
@Autowired
private SoseqCache soseqCache;
/**
* 任务队列,Key 为dataLog的ID,value 为本区域待执行的任务
*/
......@@ -208,7 +208,11 @@ public class TaskService implements ITaskService {
if(barcode == null){
return null;
}
return finishedTaskMap.get(barcode);
DataLog task = finishedTaskMap.get(barcode);
if(task == null){
}
return task;
}
/**
......@@ -237,7 +241,7 @@ public class TaskService implements ITaskService {
String errorMsg = "";
String barcode = statusBean.getCode();
try {
Barcode barcodeSave = resolveBarcode(barcode);
Barcode barcodeSave = dataCache.resolveOneValideBarcode(barcode);
//入库时的RFID
String inRFID = statusBean.getInRfid();
verifyBarcodePutIn(Lists.<Storage>newArrayList(storage),barcodeSave,inRFID);
......@@ -348,78 +352,6 @@ public class TaskService implements ITaskService {
return statusBean;
}
private Barcode findFixtureCode(Collection<CodeBean> codeBeans) throws ValidateException {
if(codeBeans.isEmpty()){
throw new ValidateException("未扫描到条码");
}
Barcode fixtureCode = null;
for (CodeBean codeBean : codeBeans) {
Barcode barcode = codeBean.getBarcode();
if(codeBean.isFixtureCode()){
if (fixtureCode == null) {
fixtureCode = barcode;
log.info("找到夹具编码:"+ fixtureCode.getBarcode());
}else{
String msg = "出现两个夹具编码["+fixtureCode.getBarcode()+"]和["+barcode.getBarcode()+"]";
log.info(msg);
throw new ValidateException(msg);
}
}else{
if(barcode == null){
log.info("条码为空,Error:"+ codeBean.getError());
}else{
log.info(barcode.getBarcode() + "不是夹具" + "codeBean Error:" + codeBean.getError() + " type:"+ barcode.getType());
}
}
}
return fixtureCode;
}
private Barcode resolveBarcode(String barcodeStr)throws ValidateException {
Collection<CodeBean> codeBeans = dataCache.resolveCodeStr(barcodeStr);
Barcode fixtureCode = findFixtureCode(codeBeans);
List<Barcode> allBarcode = Lists.newArrayList();
for (CodeBean codeBean : codeBeans) {
if(!codeBean.isFixtureCode()){
if(codeBean.getError() == null){
Barcode barcode = codeBean.getBarcode();
if(barcode != null){
if(fixtureCode != null){//有夹具条码,判断夹具与编码是否一致
//物料对应无夹具,或夹具与此夹具不一致,不可放入
if(Strings.isNullOrEmpty(barcode.getFixtureNumber()) || !fixtureCode.getPartNumber().equals(barcode.getFixtureNumber())){
throw new ValidateException(barcode.getPartNumber() + "不能放入夹具"+fixtureCode.getPartNumber()+"中");
}
fixtureCode.addRelationCode(barcode.getBarcode());
}else{
//条码中无夹具,但物料需要放入夹具
if(!Strings.isNullOrEmpty(barcode.getFixtureNumber())){
throw new ValidateException(barcode.getPartNumber() + "需要放入对应夹具中才可入库");
}
}
allBarcode.add(barcode);
}
}else{
//throw new ValidateException(codeBean.getError());
}
}
}
//有夹具条码,可以直接返回
if(fixtureCode != null){
return fixtureCode;
}
int codeSize = allBarcode.size();
if(codeSize == 0){
throw new ValidateException(barcodeStr + "不是有效的条码");
}else if(codeSize > 1){
throw new ValidateException("找到"+codeSize+"个有效条码,无法入库");
}
return allBarcode.get(0);
}
/**
* 检查二维码是否合法并且可以入库,没问题的话存入到数据库
......@@ -430,17 +362,6 @@ public class TaskService implements ITaskService {
throw new ValidateException("条码无效");
}
// Date expireDate = barcodeSave.getExpireDate();
// if(expireDate != null){
// if(System.currentTimeMillis() > expireDate.getTime()){
// throw new ValidateException("物料已过期,无法入库.");
// }
// }
// if(barcodeSave.getPlateSize() <=0 || barcodeSave.getHeight() <= 0){
// throw new ValidateException("无法入库,请先设置料盘尺寸");
// }
StoragePos pos;
//夹具,查询 relationCode
......@@ -493,7 +414,7 @@ public class TaskService implements ITaskService {
appendInfo.setDnNo("");
appendInfo.setFacility("");
DNInfo dnInfo = QisdaController.getDnInfo(inRFID);
DNInfo dnInfo = QisdaCache.getDnInfo(inRFID);
if(dnInfo.isDNIn()){
String pn = barcodeSave.getPartNumber();
DNItem dnItem = dnInfo.getItem(pn);
......@@ -519,23 +440,16 @@ public class TaskService implements ITaskService {
//3. CIS入库判定接口 (没绑过料串的条码调用此接口)
//6. CIS收料判定接口(绑过料串的条码扫码入库时判断)
if(DataCache.isProductionFor(DataCache.CUSTOMER.QISDA)){
if(barcodeSave.needToQisda()){
Barcode result = QisdaApiController.CISInCheck(dnInfo, barcodeSave);
if(result != null){
barcodeSave = result;
}
barcodeSave = barcodeManager.save(barcodeSave);
}else{
log.info("条码["+barcodeSave.getBarcode()+"]不需要到Qisda验证");
appendInfo.setFacility("AAA");
barcodeSave.setAppendInfo(appendInfo);
barcodeSave = barcodeManager.save(barcodeSave);
}
}else{
log.info("Qisda接口验证已关闭");
Barcode result = QisdaApiController.CISInCheck(dnInfo, barcodeSave);
if(result != null){
barcodeSave = result;
}
String bindSoseq = barcodeSave.getAppendInfo().getSoseq();
if(Strings.isNullOrEmpty(bindSoseq)){
//未绑定(不是分盘入库)
barcodeSave = outInfoCache.bindPutInReel(barcodeSave);
}
barcodeSave = barcodeManager.save(barcodeSave);
return barcodeSave;
}
......@@ -708,8 +622,12 @@ public class TaskService implements ITaskService {
statusBean.addPosInfo(posName,plateW,plateH, isSingleOut);
AppendInfo appendInfo = task.getAppendInfo();
boolean urgentReel = task.isUrgentReel();
if(task.isLessSendReel()){
urgentReel = true;
}
//紧急料
statusBean.addData("urgentReel",task.isUrgentReel() + "");
statusBean.addData("urgentReel",urgentReel + "");
//需要分盘,进入分盘料
statusBean.addData("cutReel",task.isCutReel() + "");
statusBean.addData("rfid", task.getTempRfid());
......@@ -786,13 +704,22 @@ public class TaskService implements ITaskService {
taskMap.remove(task.getId());
String barcode = task.getBarcode();
if(!Strings.isNullOrEmpty(barcode)){
finishedTaskMap.put(task.getBarcode(), task);
task.setStatus(StorageConstants.OP_STATUS.CANCEL.name());
finishedTaskMap.put(barcode, task);
}
task.setStatus(StorageConstants.OP_STATUS.CANCEL.name());
dataLogDao.save(task);
log.info("任务["+task.getId() + "] posName["+task.getPosName()+"] Reel Id["+task.getBarcode()+"]取消成功");
finishedOrderTask(task);
InquiryShelfBean.cancelReelTask(task);
if(task.isCheckOutTask()) {
AppendInfo taskAppendInfo = task.getAppendInfo();
if(taskAppendInfo.isFirstReelAction() || taskAppendInfo.isTailAction()) {
OutInfo outInfo = outInfoCache.incTaskFinishNum(taskAppendInfo.gethSerial(), 0, 0);
if(outInfo != null) {
InquiryShelfBean.cancelReelTask(task);
Barcode barcodeObj = barcodeManager.findByBarcode(barcode);
QisdaApi.VMIMateriaRecAss(task, barcodeObj, "E");
}
}
}
return true;
}
return false;
......@@ -801,10 +728,10 @@ public class TaskService implements ITaskService {
@Override
public boolean cancelTask(String taskId) {
DataLog task = dataLogDao.findOneById(taskId);
if(task.isCheckOutTask()){
log.info(task.getBarcode() + "出库任务取消失败: 不允许取消");
return false;
}
// if(task.isCheckOutTask()){
// log.info(task.getBarcode() + "出库任务取消失败: 不允许取消");
// return false;
// }
return cancelTask(task);
}
......@@ -827,7 +754,7 @@ public class TaskService implements ITaskService {
if(taskAppendInfo.isFirstReelAction() || taskAppendInfo.isTailAction()){
Barcode barcode = barcodeManager.findByBarcode(task.getBarcode());
log.info("["+task.getBarcode()+"]任务已出库完成,但未放上小车,发送E状态到佳世达,同时解除料架架位,发料任务完成数量+1");
OutInfo outInfo = outInfoCache.incTaskFinishNum(taskAppendInfo.gethSerial());
OutInfo outInfo = outInfoCache.incTaskFinishNum(taskAppendInfo.gethSerial(), 0, 0);
if(outInfo != null) {
InquiryShelfBean.cancelReelTask(task);
QisdaApi.VMIMateriaRecAss(task, barcode, "E");
......@@ -922,7 +849,7 @@ public class TaskService implements ITaskService {
for (DataLog task : waitTasks) {
if(cid.equals(task.getCid()) && task.isCheckOutTask() && task.isWait()) {
//分盘料,紧急料和包装料,可以按时间顺序先出
if(task.isCutReel() || task.isUrgentReel() || task.isPackageReel()){
if(task.isCutReel() || task.isUrgentReel() || task.isPackageReel() || task.isLessSendReel()){
if(urgentTask == null || urgentTask.getCreateDate().after(task.getCreateDate())){
urgentTask = task;
}
......@@ -1391,7 +1318,7 @@ public class TaskService implements ITaskService {
String posName = boxStatus.getPosId();
if(!Strings.isNullOrEmpty(posName)){//客户端发一次完成之后,会发空的 posName,不需要处理
if (StorageConstants.BOX_STATUS.IN_FINISHED == status) {//入仓完成
DataLog task = findExecutingTask(statusBeanToSave.getCid(), boxStatus.getPosId());
DataLog task = findExecutingTask(statusBeanToSave.getCid(), boxStatus.getPosId(), StorageConstants.OP.PUT_IN);
if (task != null && task.isPutInTask()) {
log.info(task.getBarcode() + "入仓位[" + task.getPosName() + "]完成");
DataLog cancelTask = findFinishedTask(statusBeanToSave.getCid(), boxStatus.getPosId());
......@@ -1417,7 +1344,7 @@ public class TaskService implements ITaskService {
//暂不处理
} else if (StorageConstants.BOX_STATUS.OUT_FINISHED == status) {//出仓完成
DataLog task = findExecutingTask(statusBeanToSave.getCid(), boxStatus.getPosId());
DataLog task = findExecutingTask(statusBeanToSave.getCid(), boxStatus.getPosId(), StorageConstants.OP.CHECKOUT);
if (task != null) {
log.info("任务["+task.getId()+"]"+task.getBarcode() + "出仓位[" + task.getPosName() + "]完成,当前状态:" + task.getStatus());
DataLog cancelTask = findFinishedTask(statusBeanToSave.getCid(), boxStatus.getPosId());
......@@ -1470,9 +1397,9 @@ public class TaskService implements ITaskService {
/**
* 根据cid 和 posName 查找正在执行的任务,不存在时返回 null
*/
private DataLog findExecutingTask(String cid, String posName) {
private DataLog findExecutingTask(String cid, String posName, int opType) {
for (DataLog task : taskMap.values()) {
if (task.getCid().equals(cid) && task.getPosName().equals(posName)) {
if (task.getCid().equals(cid) && task.getPosName().equals(posName) && task.getType() == opType) {
return task;
}
}
......@@ -1706,15 +1633,20 @@ public class TaskService implements ITaskService {
*/
@Override
public synchronized DataLog addPutInTaskToExecute(Storage storage, Barcode barcode, StoragePos storagePos) throws ValidateException {
Collection<DataLog> tasks = taskMap.values();
for (DataLog task : tasks) {
boolean sameBarcode = task.getBarcode().equals(barcode.getBarcode());
boolean samePos = task.getPosId().equals(storagePos.getId());
//检查 barcode
if (task.getBarcode().equals(barcode.getBarcode())) {
if(sameBarcode && samePos){
log.info("二维码[" + barcode.getBarcode() + "]入库到["+task.getPosName()+"]已在入库队列中,返回队列中的任务");
return task;
}
if (sameBarcode) {
String msg = "二维码:[" + barcode.getBarcode() + "]已在操作队列中,操作失败";
log.info(msg);
throw new ValidateException(msg);
} else if (task.getPosId().equals(storagePos.getId())) {
} else if (samePos) {
String msg = "位置:[" + storagePos.getPosName() + "]已在操作队列中,操作失败";
log.info(msg);
throw new ValidateException(msg);
......@@ -1756,114 +1688,30 @@ public class TaskService implements ITaskService {
StoragePos storagePos = storagePosManager.get(task.getPosId());
//二维码状态
Barcode barcode = barcodeManager.findByBarcode(task.getBarcode());
if(StorageConstants.COMPONENT_TYPE.FIXTURE == barcode.getType()){//条码是夹具
//夹具编码,需要将相应的位置全部填上
String posLabel = storagePos.getLabelStr();
List<StoragePos> allPos = storagePosManager.findByLabel(storagePos.getStorageId(), posLabel);
List<String> relationCodeStrs = task.getRelationCodes();
log.info("夹具【"+task.getBarcode()+"】入库到["+posLabel+"]完成,夹具上物料条码:"+StringUtils.join(relationCodeStrs," , "));
//此夹具的可出库时间
long canCheckOutTime = 0;
List<Barcode> relationBarcodes = Lists.newArrayList();
long now = System.currentTimeMillis();
for (String relationCodeStr : relationCodeStrs) {
Barcode relationBarcode = barcodeManager.findByBarcode(relationCodeStr);
//入库时间,如果之前已入过库是不会更改的
relationBarcode.setPutInTime(now);
relationBarcode.setInOpor(task.getOperator());
long reachWarmTime = relationBarcode.getReachWarmTime();
if(reachWarmTime > canCheckOutTime){
canCheckOutTime = reachWarmTime;
}
relationBarcodes.add(relationBarcode);
}
barcode.setUsedCount(barcode.getUsedCount() + 1);
barcode.setUsedDate(new Date());
barcode.setPutInTime(System.currentTimeMillis());
barcode.setInOpor(task.getOperator());
barcode.setCheckOutDate(null,"");
barcode.setPosName(task.getPosName());
barcode.setInitialAmount(barcode.getAmount());
int relationCount = relationBarcodes.size();
for (int i = 0; i < allPos.size(); i++) {
StoragePos componentPos = allPos.get(i);
Barcode componentBarcode = new Barcode();
if(i < relationCount){//夹具上有料
componentBarcode = relationBarcodes.get(i);
componentBarcode.setInFixture(barcode.getBarcode());
componentBarcode.setUsedCount(barcode.getUsedCount() + 1);
componentBarcode.setPutInTime(now);
componentBarcode.setInOpor(task.getOperator());
componentBarcode.setPosName(task.getPosName());
//入库后设置出库时间为-1
componentBarcode.setCheckOutDate(null,"");
barcodeManager.save(componentBarcode);
//TODO: 进行绑定或者预绑定
}else{
componentBarcode.setFixtureNumber(barcode.getPartNumber());
componentBarcode.setInFixture(barcode.getBarcode());
componentBarcode.setType(barcode.getType());
componentBarcode.setBarcode(barcode.getBarcode());
componentBarcode.setPutInTime(now);
componentBarcode.setInOpor(task.getOperator());
componentBarcode.setPartNumber(barcode.getPartNumber());
componentBarcode.setInitialAmount(1);
componentBarcode.setAmount(1);
}
/**
* 仓位状态
*/
componentPos.setBarcode(componentBarcode);
componentPos.setUsed(true);
componentPos.setCanCheckOutTime(canCheckOutTime);
storagePosManager.save(componentPos);
barcodeManager.save(barcode);
//更新缓存中的库存信息
int stockReel = dataCache.updateInventory(storagePos,componentBarcode);
//dataCache.updateStorage(task.getCid());
log.info("入库"+componentBarcode.getPartNumber()+"["+componentBarcode.getBarcode()+"]当前库存:"+stockReel+"到"+componentPos.getPosName()+"可出库时间:"+new Date(canCheckOutTime));
}
}else{//条码不是夹具
barcode.setUsedCount(barcode.getUsedCount() + 1);
barcode.setUsedDate(new Date());
barcode.setPutInTime(System.currentTimeMillis());
barcode.setInOpor(task.getOperator());
barcode.setCheckOutDate(null,"");
barcode.setPosName(task.getPosName());
barcode.setInitialAmount(barcode.getAmount());
// if(Strings.isNullOrEmpty(barcode.getProviderNumber())){//补上供应商编号
// Component component = componentManager.findByPartNumber(barcode.getPartNumber());
// barcode.setProviderNumber(component.getProviderNumber());
// }
// AppendInfo appendInfo = barcode.getAppendInfo();
// appendInfo.setDnNo(task.getSourceName());
// appendInfo.setFacility(task.getSubSourceInfo());
// appendInfo.setCompany(task.getSubSourceInfo());
// barcode.setAppendInfo(appendInfo);
barcodeManager.save(barcode);
/**
* 仓位状态
*/
storagePos.setBarcode(barcode);
storagePos.setUsed(true);
storagePos.setCanCheckOutTime(System.currentTimeMillis());
storagePosManager.save(storagePos);
//更新缓存中的库存信息
dataCache.updateInventory(storagePos,barcode);
/**
* 仓位状态
*/
storagePos.setBarcode(barcode);
storagePos.setUsed(true);
storagePos.setCanCheckOutTime(System.currentTimeMillis());
storagePosManager.save(storagePos);
//dataCache.updateStorage(task.getCid());
//
// Storage storage = dataCache.getStorage(task.getCid());
// if(storage != null){
// postInNotification(dataCache.getSettings().getInNotifyApi(), task.getBarcode(), task.getStorageId());
// }
}
//更新缓存中的库存信息
dataCache.updateInventory(storagePos,barcode);
//记录日志,完成 task
......@@ -1884,6 +1732,7 @@ public class TaskService implements ITaskService {
if(task.isPutInTask() && !task.isCancel()){
//更新DN单收料数量
AppendInfo appendInfo = barcode.getAppendInfo();
if(!appendInfo.isCISIn()){
DNItem dnItem = dNItemDao.findDnItem(appendInfo.getDnNo(), barcode.getPartNumber(), appendInfo.getFacility(), appendInfo.getCompany());
//Facility入库
......@@ -1912,34 +1761,25 @@ public class TaskService implements ITaskService {
dnItem.setInQty(inQty + task.getNum());
dnItem.setInNum(dnItem.getInNum() + 1);
dnItem.setFirstReelDate(new Date());
dnItem = dNItemDao.save(dnItem);
}else{
//纯入库,更新绑定数量
String soseq = appendInfo.getSoseq();
if(soseq != null && !soseq.isEmpty()){
int slotIndex = appendInfo.getSlotIndex();
OutItem cutItem = outItemDao.findCutItem(soseq, slotIndex);
if(cutItem != null){
int realBindQty = cutItem.getRealLockQty() + barcode.getAmount();
log.info(barcode.getBarcode() + "纯入库完成,分盘需求单soseq=["+soseq+"]slotSeq=["+slotIndex+"]绑定数量增加"+barcode.getAmount()+"="+ realBindQty);
cutItem.setRealLockQty(realBindQty);
outItemDao.save(cutItem);
outInfoCache.updateOutItem(cutItem.getId());
}
}
}
if(DataCache.isProductionFor(DataCache.CUSTOMER.QISDA)){
//通知VMI入库完成
if(barcode.needToQisda()){
QisdaApiController.PutInFinished(barcode, task);
}else{
log.info("入库完成,条码["+barcode.getBarcode()+"]不需要通知Qisda");
dNItemDao.save(dnItem);
}
}else{
log.info("入库完成通知Qisda接口关闭");
//入库更新绑定数量
String soseq = appendInfo.getSoseq();
if(soseq != null && !soseq.isEmpty()){
int slotIndex = appendInfo.getSlotIndex();
OutItem cutItem = outItemDao.findCutItem(soseq, slotIndex);
if(cutItem != null){
int realBindQty = cutItem.getRealLockQty() + barcode.getAmount();
log.info(barcode.getBarcode() + "纯入库完成,分盘需求单soseq=["+soseq+"]slotSeq=["+slotIndex+"]绑定数量增加"+barcode.getAmount()+"="+ realBindQty);
cutItem.setRealLockQty(realBindQty);
soseqCache.updateTotalRealLockQty(cutItem,realBindQty);
}
}
//通知VMI入库完成
QisdaApiController.PutInFinished(barcode, task);
}
}
......@@ -1950,6 +1790,7 @@ public class TaskService implements ITaskService {
@Override
public void checkoutFinished(DataLog task) throws ValidateException {
boolean isCancelTask = task.isCancel();
StoragePos storagePos = storagePosManager.get(task.getPosId());
Barcode barcode = storagePos.getBarcode();
......@@ -2007,13 +1848,13 @@ public class TaskService implements ITaskService {
}
finishedTaskMap.put(task.getBarcode(),task);
//dataCache.updateStorage(task.getCid());
//finishedOrderTask(task);
//checkTaskSetFinished(task);
updateOutInfo(outItemId, task, barcode);
//任务已经被取消就不再更新需求单信息
if(!isCancelTask){
updateOutInfo(outItemId, task, barcode);
}else{
log.info(task.getBarcode()+"的出库任务["+task.getId()+"]已被取消,不再更新需求单信息");
}
}
private synchronized void updateOutInfo(String outItemId, DataLog task, Barcode barcode){
......@@ -2021,46 +1862,53 @@ public class TaskService implements ITaskService {
if(!Strings.isNullOrEmpty(outItemId)){
OutItem outItem = outItemDao.findOneById(outItemId);
if(outItem != null){
OutInfo outInfo = outInfoCache.incOutNum(outItem.gethSerial());
if(outItem.isUrgentAction() || outItem.isReelCutAction()){
outInfo = outInfoCache.incTaskFinishNum(outItem.gethSerial());
}
if(barcode.hasCutInfo()){
//分盘料,需要更新对应的需求单出库数量
final List<Map<String, Object>> cutItems = barcode.getCutItems();
for (Map<String, Object> cutItem : cutItems) {
String soseqStr = cutItem.get("soseq").toString();
String slotlocation = cutItem.get("slotlocation").toString();
String qty = cutItem.get("qty").toString();
OutItem cutInfoItem = outItemDao.findCutItem(soseqStr, Integer.valueOf(slotlocation));
if(cutInfoItem == null){
log.error("未找到soseq=["+soseqStr+"]slotseq=["+slotlocation+"]的需求信息");
continue;
}
int outQty = outItem.getOutQty() + Integer.valueOf(qty);
log.info("分盘需求单["+cutInfoItem.gethSerial()+"]["+slotlocation+"]的出库数量增加"+qty+"="+outQty);
outItem.setOutQty(outQty);
outItem = outItemDao.save(outItem);
outInfoCache.updateOutItem(outItem.getId());
}
}else{
int outQty = outItem.getOutQty() + task.getNum();
outItem.setOutQty(outQty);
//int slotIndex = task.getAppendInfo().getSlotIndex();
OutInfo outInfo = outInfoCache.incOutNum(outItem.gethSerial(),outItem.getId(), task.getNum());
// if(barcode.hasCutInfo()){
// //分盘料,需要更新对应的需求单出库数量
// final List<Map<String, Object>> cutItems = barcode.getCutItems();
// for (Map<String, Object> cutItem : cutItems) {
// String soseqStr = cutItem.get("soseq").toString();
// String slotlocation = cutItem.get("slotlocation").toString();
// String qty = cutItem.get("qty").toString();
// OutItem cutInfoItem = outItemDao.findCutItem(soseqStr, Integer.valueOf(slotlocation));
// if(cutInfoItem == null){
// log.error("未找到soseq=["+soseqStr+"]slotseq=["+slotlocation+"]的需求信息");
// continue;
// }
// int outQty = outItem.getOutQty() + Integer.valueOf(qty);
// log.info("分盘需求单["+cutInfoItem.gethSerial()+"]["+slotlocation+"]的出库数量增加"+qty+"="+outQty);
// outItem.setOutQty(outQty);
// outItem = outItemDao.save(outItem);
// outInfoCache.updateOutItem(outItem.getId());
// }
// }else{
// int outQty = outItem.getOutQty() + task.getNum();
// outItem.setOutQty(outQty);
//
// if(outItem.isUrgentAction()){
// log.info("紧急料设置发料数量与出库数量一致");
// //紧急料发料数量与出库数量一致
// outItem.setSendQty(outQty);
// }
// outItem = outItemDao.save(outItem);
// outInfoCache.updateOutItem(outItem.getId());
// }
if(outItem.isUrgentAction()){
log.info("紧急料设置发料数量与出库数量一致");
//紧急料发料数量与出库数量一致
outItem.setSendQty(outQty);
}
outItem = outItemDao.save(outItem);
outInfoCache.updateOutItem(outItem.getId());
}
String latest = outInfo.getOutLatest();
QisdaApiController.OutFinished(task, barcode, latest);
if(task.isLessSendReel()){
outInfo = outInfoCache.incTaskFinishNum(outItem.gethSerial(),outItem.getSlotlocation(), task.getNum());
if(outInfo != null) {
//缺料补发的需求,需要进行发料
Barcode barcodeObj = barcodeManager.findByBarcode(task.getBarcode());
QisdaApi.VMIMateriaRecAss(task, barcodeObj,latest);
}
}
if (latest.equals("L")) {
log.info("工单[" + outItem.getSo() + "]需求单["+outItem.gethSerial()+"]的最后一盘出库完成,发送缺料通知");
......@@ -2068,58 +1916,9 @@ public class TaskService implements ITaskService {
boolean lessBind = false;
QisdaApi.VMILocationOutFeedback(outItemList, lessBind);
}
}
}
}
/**
* 更新工单状态信息
*/
private synchronized void finishedOrderTask(DataLog task){
// if(StorageConstants.OP.CHECKOUT == task.getType()){
// //更新工单状态
// String orderNo = task.getSourceName();
// if(!Strings.isNullOrEmpty(orderNo)){
// LiteOrder order = liteOrderMap.get(orderNo);
// if(order == null){
// log.info("缓存中未找到["+orderNo+"],从数据库中重新加载");
// order = liteOrderDao.findWithItemsByOrderNo(orderNo);
// }
// if(order != null){
// //任务是取消的,需要将总待出库数量-1
// if(task.isCancel()){
// order.setTaskReelCount(order.getTaskReelCount() -1);
// log.info("工单["+orderNo+"]的任务"+task.getPartNumber()+"["+task.getBarcode()+"]已取消,任务数-1="+order.getFinishedReelCount() + "/" + order.getTaskReelCount());
// }else if(task.isFinished()){
// order.setFinishedReelCount(order.getFinishedReelCount() + 1);
// String orderItemId = task.getSubSourceId();
// List<LiteOrderItem> items = new ArrayList<>();
// for (LiteOrderItem liteOrderItem : order.getOrderItems()) {
// if(liteOrderItem.getId().equals(orderItemId)){
// log.info("工单["+orderNo+"]的任务"+task.getPartNumber()+"["+task.getBarcode()+"]出库完成,已完成数量+1="+order.getFinishedReelCount()+"/" + order.getTaskReelCount());
// //更新对应条目的已出库数量和出库盘数
// liteOrderItem.setOutNum(liteOrderItem.getOutNum() + task.getNum());
// liteOrderItem.setOutReelCount(liteOrderItem.getOutReelCount() + 1);
// liteOrderItem = liteOrderItemDao.save(liteOrderItem);
// }
// items.add(liteOrderItem);
// }
// }else{
// log.error("工单["+orderNo+"]的任务["+task.getBarcode()+"]完成时,状态为:"+ task.getStatus());
// }
// if(order.getFinishedReelCount() >= order.getTaskReelCount()){
// log.info("工单["+orderNo+"]的出库任务已完成,共出库:"+ order.getFinishedReelCount() +" 盘");
// order.finishedTasks();
// }
// liteOrderDao.save(order);
// liteOrderMap.put(orderNo, order);
// } else{
// log.error("完成任务时,未找到工单["+orderNo+"]信息");
// }
// }
// }
}
}
......@@ -149,12 +149,12 @@ public class StartupListener implements ServletContextListener {
mainTimer.init();
TcpServer tcpServer = (TcpServer) ctx.getBean("tcpServer");
tcpServer.init();
// TcpServer tcpServer = (TcpServer) ctx.getBean("tcpServer");
// tcpServer.init();
OrderFileWatch orderFileWatch = (OrderFileWatch) ctx.getBean("orderFileWatch");
orderFileWatch.init();
// OrderFileWatch orderFileWatch = (OrderFileWatch) ctx.getBean("orderFileWatch");
// orderFileWatch.init();
}
private static void doReindexing(GenericManager manager) {
......
......@@ -20,15 +20,19 @@
margin-left:10px;
}
.row{
margin-bottom: 10px;
}
</style>
<link href="${ctx}/scripts/lobibox/css/lobibox.min.css?id=2" rel="stylesheet" type="text/css"/>
<div class="row">
<div class="portlet box yellow">
<div class="portlet box green">
<div class="portlet-title">
<div class="caption">
<i class="fa fa-gift"></i>需求单出库
<i class="fa fa-gift"></i>执行队列
</div>
<div class="tools">
</div>
......@@ -40,38 +44,36 @@
<h4 class="panel-title">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#executing" href="#executingOrder">
<i class="icon-cursor-move"></i>
[首盘] 需求单: 80 工单: 879235 备料单: F001_879235N_1 <span class="right">建议时间: 2019-11-18 08:59</span>
[首盘] 需求单: 40 工单: 879235 备料单: F001_879235N_1 <span class="right">建议时间: 2019-11-18 08:59</span>
</a>
</h4>
</div>
<div id="executingOrder" class="panel-collapse collapse">
<div class="panel-body">
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th>料号</th>
<th>厂别</th>
<th>料站</th>
<th>数量</th>
</tr>
</thead>
<tbody>
<tr>
<td>7H.47134.1F1</td>
<td>SU</td>
<td>1-11</td>
<td>2006</td>
</tr>
<tr>
<td>7H.47134.1F1</td>
<td>SU</td>
<td>1-12</td>
<td>1000</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="portlet box blue">
<div class="portlet-title">
<div class="caption">
<i class="fa fa-gift"></i>优先队列
</div>
<div class="tools">
</div>
</div>
<div class="portlet-body">
<div class="panel-group accordion" id="priority">
<div class="panel panel-success">
<div class="panel-heading">
<h4 class="panel-title">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#executing" href="#priorityOrder">
<i class="icon-cursor-move"></i>
[首盘] 需求单: 808 工单: 879235 备料单: F001_879235N_1 <span class="right">建议时间: 2019-11-18 08:59</span>
</a>
</h4>
</div>
</div>
</div>
......@@ -79,78 +81,104 @@
</div>
</div>
<div class="row">
<div class="portlet box yellow">
<div class="portlet-title">
<div class="caption">
<i class="fa fa-gift"></i>等待队列
</div>
<div class="tools">
</div>
</div>
<div class="portlet-body">
<div class="panel-group accordion" id="wait">
<div class="panel panel-success">
<div class="panel-heading">
<h4 class="panel-title">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#executing" href="#priorityOrder">
<i class="icon-cursor-move"></i>
[首盘] 需求单: 808 工单: 879235 备料单: F001_879235N_1 <span class="right">建议时间: 2019-11-18 08:59</span>
</a>
</h4>
</div>
</div>
</div>
</div>
</div>
</div>
<c:set var="scripts" scope="request">
<script src="${ctx}/scripts/Sortable.min.js"></script>
<script type="text/javascript">
endFunc = function(evt){
var targetSort = "";
$(evt.to).find(".panel-collapse").each(function(){
targetSort = targetSort + $(this).attr('id') + ",";
});
alert(targetSort);
}
function getOutInfoHtml(outInfo){
//var index = parseInt(i) + 1;
//var outItems = outInfo.outItems;
var moveHandle = '';
if(!outInfo.executing && !outInfo.sendLess){
moveHandle = '<i class="icon-cursor-move"></i>';
}
var pannelColor = 'panel-default';
if(outInfo.executing){
pannelColor = 'panel-success';
}
var mdate = new Date(outInfo.mdate).Format("yyyy-MM-dd hh:mm:ss");
var sdate = new Date(outInfo.sdate).Format("yyyy-MM-dd hh:mm:ss");
var infoHtml = '<div class="panel '+pannelColor+'">' +
'<div class="panel-heading">' +
'<h4 class="panel-title">' +
'<a class="accordion-toggle" data-toggle="collapse" href="#'+outInfo.hSerial+'">' +
moveHandle +
'需求单:'+ 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>' +
'</a></h4></div>' +
'<div id="'+outInfo.hSerial+'" class="panel-collapse collapse">' +
'<div class="panel-body">' +
'<ul class="list-inline">' +
'<li><i class="fa fa-tasks"></i>工单: '+outInfo.so+'</li>' +
'<li><i class="fa fa-briefcase"></i>备料单: '+outInfo.refno+'</li>' +
'<li><i class="fa fa-calendar"></i>建议时间:'+sdate+'</li>' +
'<li><i class="fa fa-star"></i>必须出仓日期:'+mdate+'</li>' +
'</ul>' +
'</div></div></div></div>';
return infoHtml;
}
function flushOutInfos(){
$.post("${ctx}/service/store/qisda/outInfoList", {}, function (data) {
var html = '';
var executingHtml = '';
var priorityHtml = '';
var waitHtml = '';
for(var i in data){
var outInfo = data[i];
var index = parseInt(i) + 1;
var outItems = data[i].outItems;
var tdHtml = '';
for(var j in outItems){
var outItem = outItems[j];
tdHtml = tdHtml +
'<tr>' +
'<td>'+outItem.slotlocation+'</td>' +
'<td>'+outItem.slotStr+'</td>' +
'<td>'+outItem.pn+'</td>' +
'<td>'+outItem.facility+'</td>' +
'<td>'+outItem.reelcut+'</td>' +
'<td>'+outItem.qty+'</td>' +
'<td>'+outItem.realLockQty+'</td>' +
'<td>'+outItem.outQty+'</td>' +
'<td>'+outItem.sendQty+'</td>' +
'</tr>';
}
var tableHtml = '<table class="table table-striped table-bordered table-hover">' +
'<thead><tr><th>料站序号</th><th>料站</th><th>料号</th><th>厂别</th><th>分盘料</th><th>需求数量</th><th>绑定数量</th><th>出库数量</th><th>发料数量</th></tr></thead>' +
'<tbody>' +
tdHtml +
'</tbody></table>';
var mdate = new Date(outInfo.mdate).Format("yyyy-MM-dd hh:mm:ss");
var sdate = new Date(outInfo.sdate).Format("yyyy-MM-dd hh:mm:ss");
var infoHtml = '<div class="panel panel-default">' +
'<div class="panel-heading">' +
'<h4 class="panel-title">' +
'<a class="accordion-toggle" data-toggle="collapse" data-parent="#executing" href="#'+data[i].hSerial+'">' +
'<i class="icon-cursor-move"></i>' +
' ['+data[i].action+'] 需求单:'+ data[i].hSerial+' 工单: ' + data[i].so +' 备料单: ' + data[i].refno + '[' + data[i].sendStatus +']' +
'<span class="right">建议时间: '+sdate+'</span>' +
'</a></h4></div>' +
'<div id="'+data[i].hSerial+'" class="panel-collapse collapse">' +
'<div class="panel-body">' +
'<ul class="list-inline">' +
'<li><i class="fa fa-tasks"></i>工单: '+data[i].so+'</li>' +
'<li><i class="fa fa-briefcase"></i>备料单: '+data[i].refno+'</li>' +
'<li><i class="fa fa-calendar"></i>建议时间:'+sdate+'</li>' +
'<li><i class="fa fa-star"></i>必须出仓日期:'+mdate+'</li>' +
'</ul>' +
tableHtml +
'</div></div></div></div>';
html = html + infoHtml;
var infoHtml = getOutInfoHtml(outInfo);
if(outInfo.executing || outInfo.sendLess){
executingHtml = executingHtml + infoHtml;
}else if(outInfo.priority){
priorityHtml = priorityHtml + infoHtml;
}else{
waitHtml = waitHtml + infoHtml;
}
}
$("#executing").html(html);
$("#executing").html(executingHtml);
$("#priority").html(priorityHtml);
$("#wait").html(waitHtml);
});
}
//setInterval(function(){
flushOutInfos();
//}, 1000);
var moving = false;
setInterval(function(){
if(!moving){
flushOutInfos();
}
}, 3000);
// var dragOptions = {
......@@ -161,5 +189,48 @@
// };
// var el = document.getElementById('accordion3');
// var sortable = Sortable.create(el,dragOptions);
onSort = function(evt){
moving = true;
var targetSort = "";
$(evt.to).find(".panel-collapse").each(function(){
targetSort = targetSort + $(this).attr('id') + ";";
});
$.post("${ctx}/service/store/qisda/changePriority", {hSerialList: targetSort}, function (data) {
moving = false;
});
}
onStart = function(evt){
moving = true;
}
onEnd = function(evt){
moving = false;
}
var waitBox = document.getElementById('wait');
var executingBox = document.getElementById("executing");
var priorityBox = document.getElementById('priority');
new Sortable(waitBox, {
group: {
name: 'shared',
put: false // 不允许拖拽进这个列表
},
animation: 150,
sort: false, // 设为false,禁止sort
onStart:onStart,
onEnd: onEnd,
});
new Sortable(priorityBox, {
group: 'shared',
animation: 150,
ghostClass: 'panel-move',
onSort:onSort,
onStart:onStart,
onEnd: onEnd,
});
</script>
</c:set>
\ No newline at end of file
......@@ -554,7 +554,7 @@
if(!task){
cidTasks[taskId] = Lobibox.notify('success', options);
}else{
if(showClass != task.$options["showClass"]){
if(showClass != task.$options["showClass"] || position != task.$options["position"]){
task.remove();
delete cidTasks[taskId];
cidTasks[taskId] = Lobibox.notify('success', options);
......
......@@ -81,12 +81,18 @@
</div>
</div>
<div class="portlet-body" style="padding-left: 30px;">
<%--<div class="col-md-6">--%>
<div class="col-md-12">
<div class="input-group">
<label class="control-label"><fmt:message key="系统更新,暂停出库"/> </label>
<form:checkbox path="stopOut"/>
</div>
<%--</div>--%>
</div>
<div class="col-md-12">
<div class="input-group">
<label class="control-label"><fmt:message key="暂停自动任务"/> </label>
<form:checkbox path="stopJob"/>
</div>
</div>
</div>
......
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!