Commit f97ca246 sunke

补料出库时,按slot循环取数量最大的一盘

清理Qisda库存接口调用
1 个父辈 3b3c8ba9
......@@ -156,9 +156,9 @@ public class DataLog extends BaseMongoBean /*implements Comparable<DataLog>*/ {
private String operator;
/**
* 关联条码,夹具时关联相关的物料,用于入库完成时插入相关物料
* 出库顺序,补料时需要按此顺序从小到大执行出库
*/
private List<String> relationCodes;
private int outOrder = 0;
public String getStorageName() {
return storageName;
......@@ -476,25 +476,10 @@ public class DataLog extends BaseMongoBean /*implements Comparable<DataLog>*/ {
return eq;
}
@Override
public int hashCode() {
return getId().hashCode();
}
public List<String> getRelationCodes() {
return relationCodes;
}
public void setRelationCodes(List<String> relationCodes) {
this.relationCodes = relationCodes;
}
public void addRelationCode(String relationCode){
if(relationCodes == null){
relationCodes = Lists.newArrayList();
}
relationCodes.add(relationCode);
}
// @Override
// public int hashCode() {
// return getId().hashCode();
// }
public boolean isSingleOut() {
return singleOut;
......@@ -623,4 +608,12 @@ public class DataLog extends BaseMongoBean /*implements Comparable<DataLog>*/ {
public void setLocInfo(String locInfo) {
this.locInfo = locInfo;
}
public int getOutOrder() {
return outOrder;
}
public void setOutOrder(int outOrder) {
this.outOrder = outOrder;
}
}
......@@ -3,9 +3,10 @@ package com.myproject.util;
import com.csvreader.CsvWriter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.*;
import com.myproject.Constants;
import com.myproject.bean.qisda.AppendInfo;
import com.myproject.bean.update.DataLog;
import com.myproject.bean.update.qisda.OutItem;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
......@@ -202,30 +203,76 @@ public final class DateUtil {
}
public static void main(String args[]) throws Exception {
List<Date> list = new ArrayList<>();
Calendar c = Calendar.getInstance();
c.set(Calendar.DAY_OF_YEAR,5);
list.add(c.getTime());
c.set(Calendar.DAY_OF_YEAR,10);
list.add(c.getTime());
c.set(Calendar.DAY_OF_YEAR,1);
list.add(c.getTime());
c.set(Calendar.DAY_OF_YEAR,111);
list.add(c.getTime());
c.set(Calendar.DAY_OF_YEAR,9);
list.add(c.getTime());
list.sort(new Comparator<Date>() {
List<DataLog> list = new ArrayList<>();
list.add(newDataLog(14,2000));
list.add(newDataLog(14,4000));
list.add(newDataLog(2,3000));
list.add(newDataLog(2,1000));
list.add(newDataLog(2,2000));
list.add(newDataLog(2,4000));
list.add(newDataLog(3,2000));
list.add(newDataLog(1,1000));
list.add(newDataLog(1,2000));
list.add(newDataLog(1,3000));
List<DataLog> sortList = sortTailTasks(list);
sortList.sort(new Comparator<DataLog>() {
@Override
public int compare(Date o1, Date o2) {
//按优先级排序,如果没有优先级,使用
return o1.compareTo(o2);
public int compare(DataLog o1, DataLog o2) {
return o1.getOutOrder() - o2.getOutOrder();
}
});
for (Date date : list) {
System.out.println(DateUtil.toDateString(date));
for (DataLog d : sortList) {
System.out.println("["+d.getOutOrder()+"]" +d.getAppendInfo().getSlotIndex()+ " - " + d.getNum());
}
}
/**
* 对补料任务进行出库排序
*/
private static List<DataLog> sortTailTasks(List<DataLog> tailTasks){
Multimap<Integer,DataLog> slotTaskMap = HashMultimap.create();
Set<Integer> slotSet = new HashSet<>();
for (DataLog dataLog : tailTasks) {
slotTaskMap.put(dataLog.getAppendInfo().getSlotIndex(), dataLog);
slotSet.add(dataLog.getAppendInfo().getSlotIndex());
}
List<DataLog> sortList = new ArrayList<>();
int outOrder = 0;
while(outOrder < tailTasks.size()){
for (Integer slot : slotSet) {
Collection<DataLog> slotTasks = slotTaskMap.get(slot);
DataLog maxNumtask = null;
for (DataLog slotTask : slotTasks) {
if(maxNumtask == null || slotTask.getNum() > maxNumtask.getNum()){
maxNumtask = slotTask;
}
}
if(maxNumtask != null){
outOrder = outOrder + 1;
maxNumtask.setOutOrder(outOrder);
sortList.add(maxNumtask);
slotTaskMap.remove(slot,maxNumtask);
}
}
}
return sortList;
}
private static DataLog newDataLog(int slotIndex, int num){
DataLog d1 = new DataLog();
AppendInfo appendInfo = new AppendInfo();
appendInfo.setSlotIndex(slotIndex);
d1.setAppendInfo(appendInfo);
d1.setNum(num);
return d1;
}
}
......@@ -607,4 +607,22 @@ public class QisdaApi {
}
return null;
}
/**
* 清理Qisda库存
*/
public static void ClearStockBy(String posName){
String url = "http://10.85.17.233/ESMTCommonInterface/CommonService.asmx/ClearStockBy";
Map<String,Object> paramMap = new HashMap<String,Object>();
paramMap.put("location",posName);
paramMap.put("userName",USER_NAME);
log.info("清理Qisda库存(ClearStockBy):posName=" + posName);
try {
String result = HttpHelper.postParam(url,paramMap);
log.info("清理Qisda库存["+posName+"](ClearStockBy)返回:" + result);
return;
} catch (Exception e) {
log.error("清理Qisda库存["+posName+"](ClearStockBy)接口出错",e);
}
}
}
......@@ -5,6 +5,7 @@ import com.myproject.bean.search.PageList;
import com.myproject.dao.mongo.IAlarmInfoDao;
import com.myproject.util.DateUtil;
import com.myproject.webapp.controller.storage.BaseSearchController;
import org.displaytag.properties.SortOrderEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
......@@ -53,7 +54,14 @@ public class AlarmInfoSearchController extends BaseSearchController {
super.addLikeParam(request,baseCriteria,"alarmMsg");
query.addCriteria(baseCriteria);
PageList pageList = alarmInfoDao.findByQuery(query, searchCriteria.getPageList());
PageList pageList = searchCriteria.getPageList();
if(pageList.getSortCriterion().equals("id")){
pageList.setSortCriterion("updateDate");
pageList.setSortDirection(SortOrderEnum.DESCENDING);
searchCriteria.setPageList(pageList);
}
pageList = alarmInfoDao.findByQuery(query, searchCriteria.getPageList());
searchCriteria.setPageList(pageList);
return SUCCESS_VIEW;
......
package com.myproject.webapp.controller.qisda.util;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.myproject.bean.qisda.AppendInfo;
import com.myproject.bean.qisda.InquiryShelfBean;
import com.myproject.bean.qisda.ResultBean;
......@@ -799,6 +801,11 @@ public class OutInfoCache {
resetTaskNum(hSerial, outReelNum);
//补料出库,且不是缺料重发,需要重新排序,按站位序号循环出,每次出最大的盘
if(outInfo.isTailAction() && !outInfoExecuted){
tasks = sortTailTasks(tasks);
}
//先出小料盘,再出大料盘
for (DataLog task : tasks) {
if(task.isSmallReel()){
......@@ -827,6 +834,40 @@ public class OutInfoCache {
return ResultBean.newOkResult(msg,"ok");
}
/**
* 对补料任务进行出库排序
*/
private List<DataLog> sortTailTasks(List<DataLog> tailTasks){
Multimap<Integer,DataLog> slotTaskMap = HashMultimap.create();
Set<Integer> slotSet = new HashSet<>();
for (DataLog dataLog : tailTasks) {
slotTaskMap.put(dataLog.getAppendInfo().getSlotIndex(), dataLog);
slotSet.add(dataLog.getAppendInfo().getSlotIndex());
}
List<DataLog> sortList = new ArrayList<>();
int outOrder = 0;
while(outOrder < tailTasks.size()){
for (Integer slot : slotSet) {
Collection<DataLog> slotTasks = slotTaskMap.get(slot);
DataLog maxNumtask = null;
for (DataLog slotTask : slotTasks) {
if(maxNumtask == null || slotTask.getNum() > maxNumtask.getNum()){
maxNumtask = slotTask;
}
}
if(maxNumtask != null){
outOrder = outOrder + 1;
slotTaskMap.remove(slot,maxNumtask);
maxNumtask.setOutOrder(outOrder);
DataLog tailOrderTask = dataLogDao.save(maxNumtask);
sortList.add(tailOrderTask);
}
}
}
return sortList;
}
private List<DataLog> checkOutUrgent(OutItem outItem){
......
......@@ -8,6 +8,7 @@ import com.myproject.dao.mongo.IBarcodeDao;
import com.myproject.exception.ValidateException;
import com.myproject.manager.IBarcodeManager;
import com.myproject.manager.IStoragePosManager;
import com.myproject.util.QisdaApi;
import com.myproject.util.StorageConstants;
import com.myproject.webapp.controller.webService.DataCache;
import org.apache.commons.lang.StringUtils;
......@@ -63,6 +64,8 @@ public class StoragePosUpdateController extends BaseUpdateController {
StoragePos storagePos = storagePosManager.get(pid);
if(storagePos != null){
try {
log.info("清理库位["+storagePos.getPosName()+"]");
QisdaApi.ClearStockBy(storagePos.getPosName());
Barcode barcode = storagePos.getBarcode();
if(barcode != null){
......
......@@ -472,12 +472,12 @@ public class QisdaDeviceController extends BaseController {
return null;
}
if(task.isExecuting() || task.isCancel()){
log.error("料盘["+barcode+"]的任务未完成,补发出库通知到Qisda");
log.error("料盘["+barcode+"]的任务未完成,清空库位信息");
try {
taskService.checkoutFinished(task);
task = taskService.getFinishedTask(barcode);
} catch (ValidateException e) {
log.error("补发通知出错",e);
log.error("清空未完成任务的库位信息出错",e);
}
}else if(task.isFinished()){
log.error("料盘["+barcode+"]的任务已完成");
......@@ -594,7 +594,7 @@ public class QisdaDeviceController extends BaseController {
String rfidLoc = request.getParameter("rfidLoc");
log.debug("收到["+cid+"]紧急/分盘料[" + barcode + "]放入"+rfid+"[" + rfidLoc + "]指令");
DataLog task = findFinishedTask(barcode);
if(task != null){
if(task != null && !task.isCancel()){
ShelfLoc shelfLoc = InquiryShelfBean.putInCutReel(task,rfid, Integer.valueOf(rfidLoc));
if(shelfLoc != null){
log.info("["+cid+"]紧急/分盘料[" + barcode + "]放入"+rfid+"[" + rfidLoc + "]成功");
......@@ -781,7 +781,7 @@ public class QisdaDeviceController extends BaseController {
alarmInfoDao.save(alarmInfo);
return putResult;
}else{
log.info("料盘["+cacheTask.getBarcode()+"]放入位置"+rfid+"["+rfidLoc+"]成功");
log.info("料盘["+cacheTask.getBarcode()+"]放入位置"+rfid+"["+rfidLoc+"]成功 outOrder="+cacheTask.getOutOrder());
cacheTask.setStatus(StorageConstants.OP_STATUS.FINISHED.name());
appendInfo.setRfid(rfid);
......
......@@ -313,9 +313,9 @@ public class TaskService implements ITaskService {
barcodeManager.save(barcodeSave);
}
}
QisdaCache.removeReelLockPosInfo(barcodeSave.getBarcode());
String trayRfid = statusBean.getTrayRfid();
addPutInTaskToExecute(storage, barcodeSave, storagePos, trayRfid);
QisdaCache.removeReelLockPosInfo(barcodeSave.getBarcode());
}
......@@ -464,7 +464,7 @@ public class TaskService implements ITaskService {
* @return
*/
@Override
public synchronized StoragePos findEmptyPosForPutIn(List<Storage> storageList, Barcode barcode, String inRFID) throws ValidateException{
public StoragePos findEmptyPosForPutIn(List<Storage> storageList, Barcode barcode, String inRFID) throws ValidateException{
verifyBarcodePutIn(storageList ,barcode, inRFID);
//如果有正在执行的任务,把库位发过去
......@@ -509,27 +509,38 @@ public class TaskService implements ITaskService {
if(status.timeOut()){
continue;
}
if(!status.isBoxCanPutIn()){
//料仓不可入库
continue;
}
if(hasOutTaskStorageIds.contains(storage.getId())){
//有正在执行的出库任务
continue;
}
if(storage.canPutIn(barcode.getPlateSize(),barcode.getHeight())){
availbleStorageList.add(storage);
}
}
if(availbleStorageList.isEmpty()){
throw new ValidateException("料仓列表中未找到可用的料仓");
}
return findEmptyPosInStorages(barcode, availbleStorageList, executingTaskCountMap);
}
private synchronized StoragePos findEmptyPosInStorages(Barcode barcode, List<Storage> availbleStorageList, Map<String,Integer> executingTaskCountMap){
//优先从没有出库任务的料仓中查找库位
for (Storage storage : availbleStorageList) {
if(hasOutTaskStorageIds.contains(storage.getId())){
//流水线有出库任务的,暂不分配入库任务(出库优先)
continue;
}
Integer executingTaskCount = executingTaskCountMap.get(storage.getId());
if(executingTaskCount >= 1){
continue;
}
try{
log.info("尝试从无出库任务的料仓"+storage.getName()+"["+storage.getCid()+"]查找空位,当前料仓正在执行任务数:" + executingTaskCount);
log.info("尝试从无出库任务的料仓["+storage.getCid()+"]中为["+barcode.getBarcode()+"]查找空位,当前料仓正在执行任务数:" + executingTaskCount);
return findLineEmptyPosForPutIn(storage,barcode);
}catch(Exception e){
log.info("从"+storage.getName()+"["+storage.getCid()+"]查找空位失败:" + e.getMessage());
log.info("尝试从["+storage.getCid()+"]中为["+barcode.getBarcode()+"]查找空位失败:" + e.getMessage());
}
}
......@@ -540,10 +551,10 @@ public class TaskService implements ITaskService {
}
try{
log.info("尝试从"+storage.getName()+"["+storage.getCid()+"]查找空位,当前料仓正在执行任务数:" + executingTaskCount);
log.info("尝试从["+storage.getCid()+"]为["+barcode.getBarcode()+"]查找空位,当前料仓正在执行任务数:" + executingTaskCount);
return findLineEmptyPosForPutIn(storage,barcode);
}catch(Exception e){
log.info("从"+storage.getName()+"["+storage.getCid()+"]查找空位失败:" + e.getMessage());
log.info("尝试从["+storage.getCid()+"]中为["+barcode.getBarcode()+"]查找空位失败:" + e.getMessage());
}
}
......@@ -551,15 +562,14 @@ public class TaskService implements ITaskService {
log.info("可用料仓太少,不按任务数分配,重新查找...");
for (Storage storage : availbleStorageList) {
try{
log.info("不按任务数分配,尝试从"+storage.getName()+"["+storage.getCid()+"]查找空位");
log.info("不按任务数分配,尝试从["+storage.getCid()+"]中为["+barcode.getBarcode()+"]查找空位");
return findLineEmptyPosForPutIn(storage,barcode);
}catch(Exception e){
log.info("从"+storage.getName()+"["+storage.getCid()+"]查找空位失败:" + e.getMessage());
log.info("尝试从["+storage.getCid()+"]中为["+barcode.getBarcode()+"]查找空位失败:" + e.getMessage());
}
}
return null;
}
/**
* 为 barcode 查找流水线料仓中空闲的仓位
......@@ -1025,6 +1035,8 @@ public class TaskService implements ITaskService {
return null;
}
/**
* 查找补料任务
* @return
......@@ -1035,12 +1047,25 @@ public class TaskService implements ITaskService {
return findPackageMinTask(storage, minARfidIndex);
}else{
//一次性把D料架出完,再出C料架,包装料可以同时出
for (DataLog task : taskMap.values()) {
Collection<DataLog> waitTasks = taskMap.values();
List<DataLog> allTaskList = new ArrayList<>();
if(!waitTasks.isEmpty()){
allTaskList.addAll(waitTasks);
allTaskList.sort(new Comparator<DataLog>() {
@Override
public int compare(DataLog o1, DataLog o2) {
return o1.getOutOrder() - o2.getOutOrder();
}
});
}
for (DataLog task : allTaskList) {
if(storage.getCid().equals(task.getCid()) && task.isCheckOutTask() && task.isWait()){
//还有小料架出库任务,出小料架
if(minDRfidIndex != -1){
if(task.isSmallReel()){
log.info("出库小料任务"+task.getBarcode()+"["+task.getPosName()+"]");
log.info("出库小料任务"+task.getBarcode()+"["+task.getPosName()+"] outOrder=" + task.getOutOrder());
return task;
}
}else{
......@@ -1048,7 +1073,7 @@ public class TaskService implements ITaskService {
if(!task.isSmallReel()){
//未完成的大料数量(正在执行和未放上料架的)
int unFinishedBigTaskCount = 0;
for (DataLog dataLog : taskMap.values()) {
for (DataLog dataLog : allTaskList) {
if(!dataLog.isPackageReel() && !dataLog.isSmallReel() && dataLog.isExecuting()){
unFinishedBigTaskCount = unFinishedBigTaskCount + 1;
}
......@@ -1456,6 +1481,7 @@ public class TaskService implements ITaskService {
DataLog task = newTask(pos);
//手动出库的当做是紧急料,放到料串上
task.setUrgentReel(true);
AppendInfo appendInfo = task.getAppendInfo();
appendInfo.setShelfType(StorageConstants.SHEFL_TYPE.B);
task.setAppendInfo(appendInfo);
......@@ -1625,7 +1651,7 @@ public class TaskService implements ITaskService {
finishedTaskMap.put(task.getBarcode(),task);
}catch (Exception e){
log.error("addTaskToFinished Error:",e);
}
}
......@@ -1796,10 +1822,9 @@ public class TaskService implements ITaskService {
Barcode barcode = storagePos.getBarcode();
if(barcode == null){
//记录日志
task.setStatus(StorageConstants.OP_STATUS.OUTBOX.name());
task.setStatus(StorageConstants.OP_STATUS.CANCEL.name());
taskMap.remove(task.getId());
finishedTaskMap.put(task.getBarcode(),task);
log.warn("任务:"+task.getBarcode() +" 仓位:"+task.getPosName()+" 的 Barcode 为null, 之前可能处理过直接返回");
return;
}
......@@ -1829,12 +1854,15 @@ public class TaskService implements ITaskService {
AppendInfo appendInfo = task.getAppendInfo();
String outItemId = appendInfo.getOutItemId();
log.info("出库完成,清空仓位: " + storagePos.getId() + "[" + storagePos.getPosName() + "]outItemId"+ outItemId);
log.info(task.getBarcode() + "出库完成,清空仓位: " + storagePos.getId() + "[" + storagePos.getPosName() + "]outItemId"+ outItemId);
//更新缓存中的库存信息
dataCache.updateInventory(storagePos,barcode);
//记录日志
task.setStatus(StorageConstants.OP_STATUS.OUTBOX.name());
if(isCancelTask){
task.setStatus(StorageConstants.OP_STATUS.CANCEL.name());
}
dataLogDao.save(task);
//从队列里面移除操作
......@@ -1853,7 +1881,8 @@ public class TaskService implements ITaskService {
if(!isCancelTask){
updateOutInfo(outItemId, task, barcode);
}else{
log.info(task.getBarcode()+"的出库任务["+task.getId()+"]已被取消,不再更新需求单信息");
log.info(task.getBarcode()+"的出库任务["+task.getId()+"]已被取消,仅清除Qisda库存["+task.getPosName()+"],不再更新需求单信息");
QisdaApi.ClearStockBy(task.getPosName());
}
}
......@@ -1899,8 +1928,8 @@ public class TaskService implements ITaskService {
String latest = outInfo.getOutLatest();
QisdaApiController.OutFinished(task, barcode, latest);
if(task.isLessSendReel()){
outInfo = outInfoCache.incTaskFinishNum(outItem.gethSerial(),outItem.getSlotlocation(), task.getNum());
if(outInfo != null) {
......@@ -1916,6 +1945,9 @@ public class TaskService implements ITaskService {
boolean lessBind = false;
QisdaApi.VMILocationOutFeedback(outItemList, lessBind);
}
}else{
log.info(task.getBarcode()+"的出库任务["+task.getId()+"]无需求单信息,清除Qisda库存");
QisdaApi.ClearStockBy(task.getPosName());
}
}
}
......
......@@ -315,11 +315,11 @@
<td class="posInfo${slot.id}">
<c:if test="${not empty slot.barcode.plateSize}">
${slot.barcode.plateSize} x ${slot.barcode.height}
[
<a onclick="clearPos('${slot.id}');">
<fmt:message key="storage.clearPos"/>
</a>]
</c:if>
[
<a onclick="clearPos('${slot.id}');">
<fmt:message key="storage.clearPos"/>
</a>]
</td>
<td class="posInfo${slot.id}">
<c:out value="${slot.barcode.partNumber}"/>
......
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!