Commit e72e0052 sunke

工单出库挑料逻辑修改

1 个父辈 c80451cc
package com.neotel.smfcore.common.base;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.query.Query;
import java.util.List;
public interface IExcelDownLoad {
List<List<String>> getHeader();
List<List<Object>> getPageData(Query query, Pageable pageable);
}
......@@ -19,6 +19,10 @@ import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.poi.excel.BigExcelWriter;
import cn.hutool.poi.excel.ExcelUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.neotel.smfcore.common.base.IExcelDownLoad;
import com.neotel.smfcore.common.exception.ValidateException;
import com.neotel.smfcore.core.language.util.MessageUtils;
import org.apache.commons.collections4.CollectionUtils;
......@@ -26,6 +30,9 @@ import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
......@@ -36,6 +43,7 @@ import java.net.URLEncoder;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
......@@ -209,6 +217,35 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
return null;
}
public static void downloadExcel(Query query, Pageable pageable, HttpServletResponse response, IExcelDownLoad excelDownLoad) throws IOException {
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
//String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
String fileName = SYS_TEM_DIR + IdUtil.fastSimpleUUID() + ".xlsx";
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
// 这里 需要指定写用哪个class去写
try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).head(excelDownLoad.getHeader()).build()) {
// 这里注意 如果同一个sheet只要创建一次
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
// 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来
PageRequest page = PageRequest.ofSize(10000);
if(pageable != null){
page.withSort(pageable.getSort());
}
while (true){
List<List<Object>> data = excelDownLoad.getPageData(query,page);
if(data == null || data.isEmpty()){
break;
}
excelWriter.write(data, writeSheet);
page = page.next();
}
}
}
/**
* 导出excel
*/
......
......@@ -349,6 +349,7 @@ public class LiteOrderCache implements ITaskListener {
public synchronized String checkOutLiteOrder(String userName, String orderNo) {
return checkOutLiteOrder(userName,orderNo,false,false);
}
/**
* 工单出库
* @param userName 操作人
......@@ -388,12 +389,6 @@ public class LiteOrderCache implements ITaskListener {
return "smfcore.order.out.maxOrder";
}
// //先查找是否已经锁定过库位,如果已经锁定过,出锁定的库位
// List<StoragePos> lockPosList = storagePosManager.findLockPos(cacheOrder.getOrderNo());
// if(lockPosList!=null&& lockPosList.size()>0){
// return checkOutOrder(cacheOrder).getMsgKey();
// }
// 出库策略(系统判断逻辑由上到下依次满足):
//①湿敏超期物料所在仓位锁定,不允许备料;
//②贵重物料,不允许超发,按实际需求发料;
......@@ -426,191 +421,298 @@ public class LiteOrderCache implements ITaskListener {
List<String> availableStorageIds = dataCache.getAvailableStorageIds();
Map<String ,List<StoragePos>> needOutPosMap=new HashMap<>();//挑出的需要出库的料列表,key=pn,value=库位
Map<String ,List<StoragePos>> itemOutPosMap=new HashMap<>();//挑出的需要出库的料列表,key=itemId,value=库位
Map<String,Integer> jieliaoPosMap=new HashMap<>();//需要截料的物料列表,key=PosName,value=此工单使用数量
List<String> excludePosIds = Lists.newArrayList();
excludePosIds.addAll(taskService.excludePosIds());
List<String> outPosNameList = new ArrayList<>();
//获取此工单出库的所有物料
for (LiteOrderItem orderItem : cacheOrder.getOrderItems()) {
String pn = orderItem.getMaterialNo();
//需求数量
int needNum = orderItem.getQty() + orderItem.getIncrement()-orderItem.getOutNum();
if (needNum <= 0) {
continue;
}
////②贵重物料,不允许超发,按实际需求发料;
boolean isGuizhong = orderItem.getOverFlag()==1;
//判断是否需要截料
boolean needJieliao =false;
//查找PN的所有库存,PN=pn,未锁定,qty 从大到小,批次正序, 入库时间正序
List<StoragePos> posList = storagePosManager.findOrderItemInStorage(availableStorageIds, pn, excludePosIds);
int storageNum=0;
int reelNum=posList.size();
for (StoragePos pos :posList) {
for (StoragePos pos :posList) {
log.info(pos.getBarcode().getBatch() + " = " + pos.getBarcode().getAmount() + " " + pos.getBarcode().getBarcode());
storageNum+=pos.getBarcode().getAmount();
}
Component component = componentManager.findOneByPN(pn);
if(component==null){
if(isShortageOut) {
log.info("工单[" + cacheOrder.getOrderNo() + "]缺料出库: 物料号[" + pn + "] ,需求数量[" + orderItem.getWemng() + "], 未找到元器件信息 ");
shortage = true;
//判断库存 使用最小库存盘数:当前盘数<=最小库存盘数时,需要截料
// if(component.getMinStoreNum()>0&& reelNum<=component.getMinStoreNum()){
// needJieliao=true;
// }
}else {
log.info("工单[" + cacheOrder.getOrderNo() + "] 物料号[" + pn + "] ,需求数量[" + orderItem.getWemng() + "], 未找到元器件信息, 缺料 ");
return materialShortPro(userName, cacheOrder);
}
}
//判断库存数量是否小于需求数量,小于直接返回缺料
if(storageNum<orderItem.getQty()){
if(isShortageOut){
shortage=true;
log.info("工单[" + cacheOrder.getOrderNo() + "]缺料出库: 物料号[" + pn + "] ,需求数量[" + orderItem.getWemng() + "], 库存总数量[" + storageNum + "] ");
}
else {
//不满足实际需求,不发,报缺料
else {
//不满足实际需求,不发,报缺料
log.info("工单[" + cacheOrder.getOrderNo() + "] 物料号[" + pn + "] ,需求数量[" + orderItem.getWemng() + "], 库存总数量[" + storageNum + "], 不满足实际需求,缺料 ");
return materialShortPro(userName, cacheOrder);
}
}
int wholeReelCount = 0;
int needWholeReelCount = 0;
//判断整盘散盘比
if (orderItem.getWemng() > 200) {
if (component.getWholeReel() >= 0) {
wholeReelCount = needNum * (component.getWholeReel() / (component.getWholeReel() + component.getHalfReel())) / component.getAmount();
needWholeReelCount = wholeReelCount;
log.info("工单[" + cacheOrder.getOrderNo() + "] 物料号[" + pn + "] ,订单数量[" + orderItem.getWemng() + "],计算的整盘数量:" + wholeReelCount);
Component component = componentManager.findOneByPN(pn);
if(component==null){
if(isShortageOut) {
log.info("工单[" + cacheOrder.getOrderNo() + "]缺料出库: 物料号[" + pn + "] ,需求数量[" + orderItem.getWemng() + "], 未找到元器件信息 ");
shortage = true;
}else {
log.info("工单[" + cacheOrder.getOrderNo() + "] 物料号[" + pn + "] ,需求数量[" + orderItem.getWemng() + "], 未找到元器件信息, 缺料 ");
return materialShortPro(userName, cacheOrder);
}
}
//判断库存 使用最小库存盘数:当前盘数<=最小库存盘数时,需要截料
if(component.getMinStoreNum()>0&& reelNum<=component.getMinStoreNum()){
needJieliao=true;
}
List<StoragePos> itemPosList = new ArrayList<>();
List<String> itemPosNameList = new ArrayList<>();
//此PN未完成
int targetNum = needNum;
for (int i=0;i<posList.size();i++) {
List<StoragePos> forPosList=new ArrayList<>();
for (StoragePos pos : posList) {
if(!itemPosNameList.contains(pos.getPosName())){
forPosList.add(pos);
List<StoragePos> outPosList = new ArrayList<>();
if(cacheOrder.isRepleOrder()){
//产线补料出库,补料逻辑:单盘最大5000 需求补料1000,按照满足需求最少料盘补料,补料需求6000时首发最大盘第二盘发满足需求最小盘
outPosList = pickRepleReels(outPosNameList, posList, targetNum);
}else{
if (orderItem.getWemng() > 200){
// 2.1、订单数量>200;
// 2.1.1 散盘:整盘=3:7(比例可调,物料数量)
// 2.1.2 整盘数量=需求数量*整盘占比/最小包装(四舍五入)
// 2.1.3 剩余发散盘,优先取散盘(由多到少发送),
// 散盘不满足情况下补充整盘
int needWholeReelCount = 0;
//判断整盘散盘比
if (component.getWholeReel() >= 0) {
Float wholeReelCount = 1.0f * needNum * component.getWholeReel() / (component.getWholeReel() + component.getHalfReel()) / component.getAmount();
needWholeReelCount = wholeReelCount.intValue();
if(wholeReelCount - needWholeReelCount > 0.5){
needWholeReelCount = needWholeReelCount + 1;
}
log.info("工单[" + cacheOrder.getOrderNo() + "] 物料号[" + pn + "] ,订单数量[" + orderItem.getWemng() + "],计算的整盘数量:" + needWholeReelCount);
}
}
//循环剩余的库位,查找
int forIndex=-1;
for (StoragePos pos : forPosList) {
forIndex++;
boolean isLast=(forIndex==(forPosList.size()-1));
//已经在出库列表
if (itemPosNameList.contains(pos.getPosName())) {
continue;
int oneReelNum = component.getAmount();
//挑选整盘
log.info("开始挑选整盘料,共需要"+needWholeReelCount+"盘");
for (int i = 0; i < needWholeReelCount; i++) {
//先取整盘
StoragePos outPos = pickWholeReel(outPosNameList,posList,targetNum,oneReelNum);
if(outPos == null){
break;
}else{
log.info("挑选批次["+outPos.getBarcode().getBatch()+"]的整盘物料:" + outPos.getBarcode().getBarcode() + " 数量:" + outPos.getBarcode().getAmount());
outPosList.add(outPos);
outPosNameList.add(outPos.getPosName());
targetNum = targetNum - outPos.getBarcode().getAmount();
}
}
//截料料规则
if (isGuizhong || needJieliao) {
if (pos.getBarcode().getAmount() >= targetNum) {
int jieliaoNum=targetNum;
//一盘刚好满足
targetNum -= pos.getBarcode().getAmount();
itemPosList.add(pos);
itemPosNameList.add(pos.getPosName());
if (targetNum < 0) {
jieliaoPosMap.put(pos.getPosName(), jieliaoNum);
}
//挑选散盘
log.info("开始挑选散盘料,剩余需求"+targetNum);
while (true){
//取散盘
StoragePos outPos = pickNotWholeReel(outPosNameList,posList,targetNum,oneReelNum);
if(outPos == null){
break;
} else if (isLast) {
int jieliaoNum=targetNum;
//一盘料不足,直接加入
itemPosList.add(pos);
itemPosNameList.add(pos.getPosName());
targetNum -= pos.getBarcode().getAmount();
if (targetNum < 0) {
jieliaoPosMap.put(pos.getPosName(), jieliaoNum);
}else{
log.info("挑选批次["+outPos.getBarcode().getBatch()+"]的散盘物料:" + outPos.getBarcode().getBarcode() + " 数量:" + outPos.getBarcode().getAmount());
outPosList.add(outPos);
outPosNameList.add(outPos.getPosName());
targetNum = targetNum - outPos.getBarcode().getAmount();
if(targetNum <=0){
break;
}
break;
}
} else if (wholeReelCount > 0) {
boolean isWholeReel = pos.getBarcode().getAmount() >= component.getAmount();
if (needWholeReelCount > 0) {
//判断数量,先出整盘料
if (pos.getBarcode().getAmount() >= targetNum) {
if (isWholeReel) {
needWholeReelCount--;
}
itemPosList.add(pos);
itemPosNameList.add(pos.getPosName());
targetNum -= pos.getBarcode().getAmount();
}
} else {
//整盘已出完,按照数量满足或最后一盘来出
if (!isWholeReel) {
if (pos.getBarcode().getAmount() >= targetNum || isLast) {
itemPosList.add(pos);
itemPosNameList.add(pos.getPosName());
targetNum -= pos.getBarcode().getAmount();
}
if(targetNum > 0){
log.info("剩余需求"+targetNum+"开始补充整盘");
while(true){
StoragePos outPos = pickFitWholeReel(outPosNameList,posList,targetNum);
if(outPos == null){
break;
}else{
log.info("挑选批次["+outPos.getBarcode().getBatch()+"]的散盘物料:" + outPos.getBarcode().getBarcode() + " 数量:" + outPos.getBarcode().getAmount());
outPosList.add(outPos);
outPosNameList.add(outPos.getPosName());
targetNum = targetNum - outPos.getBarcode().getAmount();
if(targetNum <=0){
break;
}
}
}
} else {
//不需要截料,也不按照整盘比,按照数量满足或最后一盘来出
if (pos.getBarcode().getAmount() >= targetNum || isLast) {
itemPosList.add(pos);
itemPosNameList.add(pos.getPosName());
targetNum -= pos.getBarcode().getAmount();
break;
}
}
if (targetNum <= 0) {
break;
}
}
if (targetNum <= 0) {
break;
else{
//2.2、订单数量≤200;(料盘最少原则)
// 2.2.1 优先发单盘
// 2.2.1 单盘不满足,发最大量+补充盘
outPosList = pickRepleReels(outPosNameList, posList, targetNum);
}
}
// else{
// //工单出库
// ////②贵重物料,不允许超发,按实际需求发料;
// boolean isGuizhong = orderItem.getOverFlag()==1;
// //判断是否需要截料
// boolean needJieliao =false;
//
// int wholeReelCount = 0;
// int needWholeReelCount = 0;
// //判断整盘散盘比
// if (orderItem.getWemng() > 200) {
// if (component.getWholeReel() >= 0) {
// wholeReelCount = needNum * (component.getWholeReel() / (component.getWholeReel() + component.getHalfReel())) / component.getAmount();
// needWholeReelCount = wholeReelCount;
// log.info("工单[" + cacheOrder.getOrderNo() + "] 物料号[" + pn + "] ,订单数量[" + orderItem.getWemng() + "],计算的整盘数量:" + wholeReelCount);
// }
// }
//
// //判断库存 使用最小库存盘数:当前盘数<=最小库存盘数时,需要截料
// if(component.getMinStoreNum()>0&& reelNum<=component.getMinStoreNum()){
// needJieliao=true;
// }
//
// List<StoragePos> itemPosList = new ArrayList<>();
// //此PN未完成
// for (int i=0;i<posList.size();i++) {
// List<StoragePos> forPosList=new ArrayList<>();
// for (StoragePos pos : posList) {
// if(!outPosNameList.contains(pos.getPosName())){
// forPosList.add(pos);
// }
// }
//
// //循环剩余的库位,查找
// int forIndex=-1;
// for (StoragePos pos : forPosList) {
// forIndex++;
// boolean isLast=(forIndex==(forPosList.size()-1));
// //已经在出库列表
// if (outPosNameList.contains(pos.getPosName())) {
// continue;
// }
//
// //截料料规则
// if (isGuizhong || needJieliao) {
// if (pos.getBarcode().getAmount() >= targetNum) {
// int jieliaoNum=targetNum;
// //一盘刚好满足
// targetNum -= pos.getBarcode().getAmount();
// itemPosList.add(pos);
// outPosNameList.add(pos.getPosName());
// if (targetNum < 0) {
// jieliaoPosMap.put(pos.getPosName(), jieliaoNum);
// }
// break;
// } else if (isLast) {
// int jieliaoNum=targetNum;
// //一盘料不足,直接加入
// itemPosList.add(pos);
// outPosNameList.add(pos.getPosName());
// targetNum -= pos.getBarcode().getAmount();
// if (targetNum < 0) {
// jieliaoPosMap.put(pos.getPosName(), jieliaoNum);
// }
// break;
// }
// } else if (wholeReelCount > 0) {
//
// boolean isWholeReel = pos.getBarcode().getAmount() >= component.getAmount();
// if (needWholeReelCount > 0) {
// //判断数量,先出整盘料
// if (pos.getBarcode().getAmount() >= targetNum) {
// if (isWholeReel) {
// needWholeReelCount--;
// }
// itemPosList.add(pos);
// outPosNameList.add(pos.getPosName());
// targetNum -= pos.getBarcode().getAmount();
// }
// } else {
// //整盘已出完,按照数量满足或最后一盘来出
// if (!isWholeReel) {
// if (pos.getBarcode().getAmount() >= targetNum || isLast) {
// itemPosList.add(pos);
// outPosNameList.add(pos.getPosName());
// targetNum -= pos.getBarcode().getAmount();
// break;
// }
// }
// }
//
//
// } else {
// //不需要截料,也不按照整盘比,按照数量满足或最后一盘来出
// if (pos.getBarcode().getAmount() >= targetNum || isLast) {
// itemPosList.add(pos);
// outPosNameList.add(pos.getPosName());
// targetNum -= pos.getBarcode().getAmount();
// break;
// }
// }
//
// if (targetNum <= 0) {
// break;
// }
// }
// if (targetNum <= 0) {
// break;
// }
// }
//
// }
//可以出库
int outNum = 0;
itemOutPosMap.put(orderItem.getId(), outPosList);
//排除掉这些库位,以免重复挑取同一盘料
for (StoragePos storagePos : outPosList) {
excludePosIds.add(storagePos.getId());
int reelAmount = storagePos.getBarcode().getAmount();
outNum = outNum + reelAmount;
}
//判断数量是否满足
if (targetNum > 0) {
int outNum = needNum - targetNum;
if (outNum < orderItem.getQty()) {
if(isShortageOut){
shortage=true;
log.info("工单[" + cacheOrder.getOrderNo() + "]缺料出库: 物料号[" + pn + "] ,需求数量[" + orderItem.getWemng() + "], 库存可发数量[" + outNum + "], 不满足实际需求 ");
int excessNum = outNum - orderItem.getQty();//超发的数量
if (excessNum < 0) {
if(isShortageOut){
shortage=true;
log.info("工单[" + cacheOrder.getOrderNo() + "]缺料出库: 物料号[" + pn + "] ,需求数量[" + orderItem.getWemng() + "], 库存可发数量[" + outNum + "], 不满足实际需求 ");
}
else {
//不满足实际需求,不发,报缺料
log.info("工单[" + cacheOrder.getOrderNo() + "] 物料号[" + pn + "] ,需求数量[" + orderItem.getWemng() + "], 库存可发数量[" + outNum + "], 不满足实际需求,缺料 ");
return materialShortPro(userName, cacheOrder);
}
}else if(excessNum > 0){
////②贵重物料,不允许超发,按实际需求发料;
boolean isGuizhong = orderItem.getOverFlag()==1;
//判断是否需要截料
boolean needJieliao =false;
//判断库存 使用最小库存盘数:当前盘数<=最小库存盘数时,需要截料
if(component.getMinStoreNum()>0&& posList.size() <=component.getMinStoreNum()){
needJieliao=true;
}
if(isGuizhong || needJieliao){
StoragePos minAmountReelPos = null;
//找大于超出数量的最小的一盘进行截料
for (StoragePos storagePos : outPosList) {
int reelAmount = storagePos.getBarcode().getAmount();
if(reelAmount > excessNum){
if(minAmountReelPos == null || reelAmount <= minAmountReelPos.getBarcode().getAmount()){
minAmountReelPos = storagePos;
}
}
}
else {
//不满足实际需求,不发,报缺料
log.info("工单[" + cacheOrder.getOrderNo() + "] 物料号[" + pn + "] ,需求数量[" + orderItem.getWemng() + "], 库存可发数量[" + outNum + "], 不满足实际需求,缺料 ");
return materialShortPro(userName, cacheOrder);
//如果需要截料,找最小的一盘
if(minAmountReelPos != null){
int reelNeedNum = minAmountReelPos.getBarcode().getAmount() - excessNum;
log.info("需要对料盘["+minAmountReelPos.getBarcode().getBarcode()+"]进行截料,需求数量");
jieliaoPosMap.put(minAmountReelPos.getPosName(),reelNeedNum);
}
}
}
//可以出库
needOutPosMap.put(pn, itemPosList);
//排除掉这些库位,以免重复挑取同一盘料
for (StoragePos storagePos : itemPosList) {
excludePosIds.add(storagePos.getId());
}
}
log.info("开始执行工单[" + orderNo + "] ");
......@@ -627,13 +729,16 @@ public class LiteOrderCache implements ITaskListener {
int taskReelCount = 0;
//物料筛选完成,开始生成出库任务
for (LiteOrderItem orderItem : cacheOrder.getOrderItems()) {
int itemReelCount=0;
int itemOutCount=0;
List<StoragePos> posList=needOutPosMap.get(orderItem.getMaterialNo());
boolean hasFirst = false;//是否已设定首盘
List<StoragePos> posList=itemOutPosMap.get(orderItem.getId());
if(posList == null){
posList = new ArrayList<>();
}
for (StoragePos pos : posList) {
DataLog task = taskService.newTask(pos) ;
......@@ -654,7 +759,8 @@ public class LiteOrderCache implements ITaskListener {
task.setNeedQty(count);
task.setLightColor(ORDER_COLOR.PURPLE.getRgb());//截料料 颜色:PURPLE
}
else if(itemReelCount==0){
else if(!hasFirst){
hasFirst = true;
task.setFirstReel(true);
task.setLightColor(ORDER_COLOR.CYAN.getRgb());//首盘料 颜色:CYAN
} else{
......@@ -670,6 +776,7 @@ public class LiteOrderCache implements ITaskListener {
//产线补料
task.setLightColor(ORDER_COLOR.FORESTGREEN.getRgb());//产线补料出库 颜色:FORESTGREEN
}
try{
taskService.addTaskToExecute(task);
}catch (Exception e){
......@@ -715,372 +822,9 @@ public class LiteOrderCache implements ITaskListener {
return "";
}
// /**
// * 工单出库
// * @param userName 操作人
// * @param orderNo 工单号
// * @param isShortageOut 是否缺料继续出库
// * @param addOutbound 是否补料出库
// * @return
// */
// public synchronized String checkOutLiteOrder(String userName, String orderNo,boolean isShortageOut,boolean addOutbound) {
// LiteOrder cacheOrder = findOrderByNo(orderNo);
//
// if (cacheOrder == null) {
// return "smfcore.order.out.notFound";
// }
// if(!addOutbound) {
// if (cacheOrder.isExecuting()) {
// log.info("工单[" + orderNo + "]正在执行");
// return "smfcore.order.out.executing";
// }
// }
//
// if(cacheOrder.isClosed()) {
// log.info("工单[" + orderNo + "]已关闭,无法出库");
// return "smfcore.order.hasClose";
// }
//
// updateOrderFromApi(userName,cacheOrder);
// //如果更新完工单已关闭,直接提示
// if(cacheOrder.isClosed()) {
// log.info("工单[" + orderNo + "]已关闭,无法出库");
// return "smfcore.order.hasClose";
// }
//
// ORDER_COLOR nextColor = getNextColor();
// if (nextColor == null) {
// log.info("执行工单[" + orderNo + "] 时, 已达最大可执行工单数");
// return "smfcore.order.out.maxOrder";
// }
//
//// //先查找是否已经锁定过库位,如果已经锁定过,出锁定的库位
//// List<StoragePos> lockPosList = storagePosManager.findLockPos(cacheOrder.getOrderNo());
//// if(lockPosList!=null&& lockPosList.size()>0){
//// return checkOutOrder(cacheOrder).getMsgKey();
//// }
//
//// 出库策略(系统判断逻辑由上到下依次满足):
////①湿敏超期物料所在仓位锁定,不允许备料;
////②贵重物料,不允许超发,按实际需求发料;
////③截料:库存物料的盘数≤设定值,SMF仓位分配
//// 锁定时要标识需要截料并按工单实际需求发料,料
//// 盘相同要先进先出
////④发料盘分配逻辑:
//// 1、散盘与整盘如何分配;
//// 2、订单发料:
//// 2.1、订单数量>200;
//// 2.1.1 散盘:整盘=3:7(比例可调,物料数量)
//// 2.1.2 整盘数量=需求数量*整盘占比/最小包装(四
//// 舍五入)
//// 2.1.3 剩余发散盘,优先取散盘(由多到少发送),
//// 散盘不满足情况下补充整盘
//// 2.2、订单数量≤200;(料盘最少原则)
//// 2.2.1 优先发单盘
//// 2.2.1 单盘不满足,发最大量+补充盘
//// 3 MES传输实际需求+超发需求
//// 3.1 优先满足实际需求+超发需求
//// 3.2 只满足实际需求,不满足超发需求,发出
//// 3.3 不满足实际需求,不发,报缺料
//// 料盘相同要先进先出(物料配置小单标准不需要再
//// 单独写逻辑考虑)
////⑤ 锁定仓位要指定首件所在的仓位,首件取经过①
////②③④筛选锁定料盘中的最大料盘
//
// log.info("开始为工单[" + orderNo + "]挑选出库物料 ");
// boolean shortage=false;
//
// List<String> availableStorageIds = dataCache.getAvailableStorageIds();
//
// Map<String ,List<StoragePos>> needOutPosMap=new HashMap<>();//挑出的需要出库的料列表,key=pn,value=库位
// Map<String,Integer> jieliaoPosMap=new HashMap<>();//需要截料的物料列表,key=PosName,value=此工单使用数量
// //获取此工单出库的所有物料
// for (LiteOrderItem orderItem : cacheOrder.getOrderItems()) {
//
//
// String pn = orderItem.getMaterialNo();
//
// //需求数量
// int needNum = orderItem.getQty() + orderItem.getIncrement()-orderItem.getOutNum();
// if (needNum <= 0) {
// continue;
// }
// ////②贵重物料,不允许超发,按实际需求发料;
// boolean isGuizhong = orderItem.getOverFlag()==1;
// //判断是否需要截料
// boolean needJieliao =false;
//
//
// List<StoragePos> itemPosList = new ArrayList<>();
// List<String> itemPosNameList = new ArrayList<>();
// //查找PN的所有库存,PN=pn,未锁定,qty 从大到小,入库时间正序
// List<StoragePos> posList = storagePosManager.findOrderItemInStorage(availableStorageIds, pn, taskService.excludePosIds());
//
// int storageNum=0;
// int reelNum=posList.size();
// for (StoragePos pos :posList
// ) {
// storageNum+=pos.getBarcode().getAmount();
// }
//
// Component component = componentManager.findOneByPN(pn);
// if(component==null){
// if(isShortageOut) {
// log.info("工单[" + cacheOrder.getOrderNo() + "]缺料出库: 物料号[" + pn + "] ,需求数量[" + orderItem.getWemng() + "], 未找到元器件信息 ");
// shortage = true;
// }else {
// log.info("工单[" + cacheOrder.getOrderNo() + "] 物料号[" + pn + "] ,需求数量[" + orderItem.getWemng() + "], 未找到元器件信息, 缺料 ");
// return materialShortPro(userName, cacheOrder);
// }
// }
// //判断库存 使用最小库存盘数:当前盘数<=最小库存盘数时,需要截料
// if(reelNum<=component.getMinStoreNum()){
// needJieliao=true;
// }
// //判断库存数量是否小于需求数量,小于直接返回缺料
// if(storageNum<orderItem.getQty()){
// if(isShortageOut){
// shortage=true;
// log.info("工单[" + cacheOrder.getOrderNo() + "]缺料出库: 物料号[" + pn + "] ,需求数量[" + orderItem.getWemng() + "], 库存总数量[" + storageNum + "] ");
// }
// else {
// //不满足实际需求,不发,报缺料
// log.info("工单[" + cacheOrder.getOrderNo() + "] 物料号[" + pn + "] ,需求数量[" + orderItem.getWemng() + "], 库存总数量[" + storageNum + "], 不满足实际需求,缺料 ");
// return materialShortPro(userName, cacheOrder);
// }
// }
//
// int wholeReelCount = 0;
// int needWholeReelCount = 0;
// //判断整盘散盘比
// if (orderItem.getWemng() > 200) {
//
// if (component.getWholeReel() >= 0) {
// wholeReelCount = needNum * (component.getWholeReel() / (component.getWholeReel() + component.getHalfReel())) / component.getAmount();
// needWholeReelCount = wholeReelCount;
// log.info("工单[" + cacheOrder.getOrderNo() + "] 物料号[" + pn + "] ,订单数量[" + orderItem.getWemng() + "],计算的整盘数量:" + wholeReelCount);
// }
// }
//
//
// //此PN未完成
// int targetNum = needNum;
// StoragePos tempPos = null;
// for (StoragePos pos :
// posList) {
// //已经在出库列表
// if (itemPosNameList.contains(pos.getPosName())) {
// continue;
// }
//
// if (isGuizhong || needJieliao) {
// //一盘是否满足
// if (pos.getBarcode().getAmount() > targetNum) {
// tempPos = pos;
// } else if (pos.getBarcode().getAmount() == targetNum) {
// //一盘刚好满足
// targetNum = 0;
// itemPosList.add(pos);
// itemPosNameList.add(pos.getPosName());
// break;
// } else {
//
// //数量不满足,如果暂存有料,使用暂存物料,一盘料满足
// if (tempPos != null) {
// itemPosList.add(tempPos);
// itemPosNameList.add(tempPos.getPosName());
// targetNum -= tempPos.getBarcode().getAmount();
// //截料的数量
// if (targetNum < 0) {
// jieliaoPosMap.put(tempPos.getPosName(), targetNum);
// }
// } else {
// //一盘料不足,直接加入
// itemPosList.add(pos);
// itemPosNameList.add(pos.getPosName());
// targetNum -= pos.getBarcode().getAmount();
// if (targetNum < 0) {
// jieliaoPosMap.put(tempPos.getPosName(), targetNum);
// }
// }
//
// }
// } else if (wholeReelCount > 0) {
//
// boolean isWholeReel = pos.getBarcode().getAmount() >= component.getAmount();
// if (needWholeReelCount > 0) {
// //判断数量,先出整盘料
// if (pos.getBarcode().getAmount() >= targetNum) {
// if (isWholeReel) {
// needWholeReelCount--;
// }
// itemPosList.add(pos);
// itemPosNameList.add(pos.getPosName());
// targetNum -= pos.getBarcode().getAmount();
// }
// } else {
// //整盘已出完
// if (!isWholeReel) {
// itemPosList.add(pos);
// itemPosNameList.add(pos.getPosName());
// targetNum -= pos.getBarcode().getAmount();
// }
// }
//
//
// } else {
// //不需要截料,也不按照整盘比,直接数量最大的发料
// itemPosList.add(pos);
// itemPosNameList.add(pos.getPosName());
// targetNum -= pos.getBarcode().getAmount();
// }
//
// if (targetNum <= 0) {
// break;
// }
// }
//
// if(targetNum>0&&isGuizhong || needJieliao) {
// if (tempPos != null) {
// if (!itemPosNameList.contains(tempPos.getPosName())) {
// itemPosList.add(tempPos);
// itemPosNameList.add(tempPos.getPosName());
// targetNum -= tempPos.getBarcode().getAmount();
// //截料的数量
// if (targetNum < 0) {
// jieliaoPosMap.put(tempPos.getPosName(), targetNum);
// }
// }
// }
// }
//
// //第一轮循环完,判断是否需要再次循环
// if (targetNum > 0 && wholeReelCount > 0) {
//
// //如果是散盘料不足,需要再次循环
// for (StoragePos pos :
// posList) {
// //已经在出库列表
// if (itemPosNameList.contains(pos.getPosName())) {
// continue;
// }
// itemPosList.add(pos);
// itemPosNameList.add(pos.getPosName());
// targetNum -= pos.getBarcode().getAmount();
// if (targetNum <= 0) {
// break;
// }
// }
// }
//
// //判断数量是否满足
// if (targetNum > 0) {
// int outNum = needNum - targetNum;
// if (outNum < orderItem.getQty()) {
// if(isShortageOut){
// shortage=true;
// log.info("工单[" + cacheOrder.getOrderNo() + "]缺料出库: 物料号[" + pn + "] ,需求数量[" + orderItem.getWemng() + "], 库存可发数量[" + outNum + "], 不满足实际需求 ");
// }
// else {
// //不满足实际需求,不发,报缺料
// log.info("工单[" + cacheOrder.getOrderNo() + "] 物料号[" + pn + "] ,需求数量[" + orderItem.getWemng() + "], 库存可发数量[" + outNum + "], 不满足实际需求,缺料 ");
// return materialShortPro(userName, cacheOrder);
// }
// }
// }
// //可以出库
// needOutPosMap.put(pn, itemPosList);
// }
//
// log.info("开始执行工单[" + orderNo + "] ");
// if(!addOutbound){
// cacheOrder.setTaskReelCount(0);
// cacheOrder.setTaskFinishedTime(-1);
// cacheOrder.setFinishedReelCount(0);
// }
// cacheOrder.setStatus(LITEORDER_STATUS.EXECUTING);
// //设置出库操作人
// cacheOrder.setOperateUser(userName);
// cacheOrder.setStartDate(new Date());
//
//
// int taskReelCount = 0;
// //物料筛选完成,开始生成出库任务
// for (LiteOrderItem orderItem : cacheOrder.getOrderItems()) {
// int itemReelCount=0;
// int itemOutCount=0;
// List<StoragePos> posList=needOutPosMap.get(orderItem.getMaterialNo());
// for (StoragePos pos :
// posList) {
// DataLog task = taskService.newTask(pos) ;
//
// task.setSourceId(cacheOrder.getId());
// task.setSourceName(cacheOrder.getOrderNo());
// task.setSubSourceId(orderItem.getId());
// task.setSubSourceInfo(orderItem.getStation());
// task.setType(OP.CHECKOUT);
// task.setLightColor(nextColor.getRgb());
// task.setStatus(OP_STATUS.WAIT.name());
// task.setOperator(userName);
//
// task.setOutType(10);//工单出库类型为10
// if(jieliaoPosMap.containsKey(pos.getPosName())){
// //需要截料
// int count=jieliaoPosMap.get(pos.getPosName());
// task.setNeedSplitting(true);
// task.setNeedQty(count);
// task.setLightColor(ORDER_COLOR.PURPLE.getRgb());//截料料 颜色:PURPLE
// }
// else if(itemReelCount==0){
// task.setFirstReel(true);
// task.setLightColor(ORDER_COLOR.CYAN.getRgb());//首盘料 颜色:CYAN
// } else{
// task.setLightColor(ORDER_COLOR.SKYBLUE.getRgb());//普通工单 颜色:SKYBLUE
// }
// if(addOutbound){
// task.setAddOutbound(true);
// task.setLightColor(ORDER_COLOR.PINK.getRgb());//补料出库 颜色:PINK
// }
// taskService.addTaskToExecute(task);
// log.info("工单[" + orderNo + "],任务数[" + taskReelCount + "]仓位【" + pos.getPosName() + "】RI=[" + pos.getBarcode().getBarcode() + "] PN=[" + orderItem.getMaterialNo() + "] Amount[" + pos.getBarcode().getAmount()+
// "] 首盘["+task.isFirstReel()+"] 截料["+task.isNeedSplitting()+"]["+task.getNeedQty()+"] 补料出库["+task.isAddOutbound()+"]");
//
// taskReelCount++;
// itemReelCount++;
// itemOutCount+=pos.getBarcode().getAmount();
//
// }
//// orderItem.setTotalOutReelCount(orderItem.getTotalOutReelCount()+itemReelCount);
//// orderItem.setTotalOutNum(orderItem.getTotalOutNum()+itemOutCount);
// orderItem.setOutReelCount(itemReelCount);
// orderItem.setOutNum(itemOutCount);
// liteOrderItemManager.save(orderItem);
//
// }
//
// cacheOrder.setTaskReelCount(taskReelCount);
// cacheOrder.setTotalFinishedReelCount(0);
// cacheOrder.setTotalTaskReelCount(cacheOrder.getTotalTaskReelCount()+taskReelCount);
// if(addOutbound){
//
// }
// else if(shortage) {
// cacheOrder.setShortageOut(true);
// }
// log.info("工单[" + orderNo + "]任务分配结束,任务数[" + taskReelCount + "]");
// //有需要出库的
// if (taskReelCount <= 0) {
// cacheOrder.finishedTasks();
// }
//
// liteOrderManager.save(cacheOrder);
// liteOrderMap.put(cacheOrder.getOrderNo(), cacheOrder);
// if (taskReelCount <= 0) {
// //return "工单无可执行的任务";
// return "smfcore.order.out.noTask";
// }
// return "";
// }
public void pickOrderReel(){
}
public String materialShortPro(String userName, LiteOrder liteOrder){
......@@ -1144,4 +888,109 @@ public class LiteOrderCache implements ITaskListener {
}
return null;
}
/**
* //产线补料出库,补料逻辑:单盘最大5000 需求补料1000,按照满足需求最少料盘补料,补料需求6000时首发最大盘第二盘发满足需求最小盘
* @param outPosNameList
* @param posList
* @param targetNum
* @return
*/
private List<StoragePos> pickRepleReels(List<String> outPosNameList, List<StoragePos> posList, int targetNum){
List<String> excludePosNameList = new ArrayList<>(outPosNameList);
List<StoragePos> itemPickPosList = new ArrayList<>();
boolean pickMaxQtyReel = true;
do {
//第一盘取最大的, 从第二盘开始取满足
StoragePos outPos = pickOneReel(true, excludePosNameList,posList,targetNum, pickMaxQtyReel, -1);
if(outPos == null){
break;
}else{
log.info("挑选到批次["+outPos.getBarcode().getBatch()+"]物料:" + outPos.getBarcode().getBarcode() + " 数量:" + outPos.getBarcode().getAmount());
itemPickPosList.add(outPos);
excludePosNameList.add(outPos.getPosName());
targetNum = targetNum - outPos.getBarcode().getAmount();
if(targetNum <=0){
break;
}
pickMaxQtyReel = false;
}
} while(true);
return itemPickPosList;
}
/**
* 取整盘
*/
private StoragePos pickWholeReel(List<String> excluedPosNameList, List<StoragePos> posList, int targetNum, int oneReelNum){
StoragePos outPos = pickOneReel(true,excluedPosNameList,posList,targetNum,true,oneReelNum);
return outPos;
}
/**
* 取散盘,从大到小取
*/
private StoragePos pickNotWholeReel(List<String> excluedPosNameList, List<StoragePos> posList, int targetNum, int oneReelNum){
StoragePos outPos = pickOneReel(false,excluedPosNameList,posList,targetNum,true,oneReelNum);
return outPos;
}
/**
* 取最小满足数量的盘
*/
private StoragePos pickFitWholeReel(List<String> excluedPosNameList, List<StoragePos> posList, int targetNum){
StoragePos outPos = pickOneReel(true,excluedPosNameList,posList,targetNum,false,-1);
return outPos;
}
/**
*
* @param takeWholeReel 是否取整盘, 如果整盘数量小于0,此参数无效, 取整盘时,整盘料数量要大于0
* @param excluedPosNameList
* @param posList
* @param targetNum
* @param pickMaxQtyReel
* @param oneReelNum 整盘料的数量, 挑盘散盘时要小于此值
* @return
*/
private StoragePos pickOneReel(boolean takeWholeReel, List<String> excluedPosNameList, List<StoragePos> posList, int targetNum, boolean pickMaxQtyReel, int oneReelNum){
StoragePos outPos = null;
if(targetNum > 0){
for (StoragePos pos : posList) {
if(!excluedPosNameList.contains(pos.getPosName())){
int qty = pos.getBarcode().getAmount();
if(oneReelNum > 0){
if(takeWholeReel){
//需要取整盘,即小于此值的盘无效
if(qty < oneReelNum){
continue;
}
}else{
//需要取散盘,即大于此值的盘无效
if(qty >= oneReelNum){
continue;
}
}
}
if(outPos == null){
//先取第一盘(数量最大的盘)
outPos = pos;
if(pickMaxQtyReel){
return outPos;
}
}
if(qty < outPos.getBarcode().getAmount() && qty >= targetNum){
//如果当前盘小于已挑料盘并且这盘料出库后可以满足需求,那么替换已挑料盘
outPos = pos;
}
if(qty < targetNum){
//当前料盘挑完还不满足需求
return outPos;
}
}
}
}
return outPos;
}
}
......@@ -316,10 +316,9 @@ public class StoragePosController {
@ApiOperation("导出查找出库列表")
@GetMapping(value = "/find/download")
@PreAuthorize("@el.check('checkOut')")
public void download(HttpServletResponse response, StoragePosFindCriteria criteria,HttpServletRequest request) throws IOException {
public void download(HttpServletResponse response, StoragePosFindCriteria criteria,Pageable pageable, HttpServletRequest request) throws IOException {
Query query=getPosFindCriteria(criteria);
List<StoragePos> storagePos = storagePosManager.findByQuery(query );
storagePosManager.download(storagePos, response,request.getLocale());
storagePosManager.download(query,pageable,response,request.getLocale());
}
//UID出库
@ApiOperation("查找出库列表")
......
......@@ -8,6 +8,8 @@ import com.neotel.smfcore.core.storage.bean.InventoryItem;
import com.neotel.smfcore.core.storage.enums.CHECKOUT_TYPE;
import com.neotel.smfcore.core.storage.service.po.Storage;
import com.neotel.smfcore.core.storage.service.po.StoragePos;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.query.Query;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
......@@ -59,7 +61,7 @@ public interface IStoragePosManager extends IBaseManager<StoragePos> {
public void updateBarcodeMsd(String pn,String msl,String thickness);
void download(List<StoragePos> storagePos, HttpServletResponse response, Locale locale) throws IOException;
void download(Query query, Pageable pageable, HttpServletResponse response, Locale locale) throws IOException;
List<StoragePos> findPosList(String storageId, List<String> posNames);
......
......@@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.neotel.smfcore.common.base.IExcelDownLoad;
import com.neotel.smfcore.common.bean.PageData;
import com.neotel.smfcore.common.exception.ValidateException;
import com.neotel.smfcore.common.utils.DateUtil;
......@@ -495,41 +496,63 @@ public class StoragePosManagerImpl implements IStoragePosManager {
}
@Override
public void download(List<StoragePos> storagePos, HttpServletResponse response,Locale locale) throws IOException {
String barcodeStr= MessageUtils.getText("smfcore.storagePos.barcode",locale,"条码编号");
String partNumberStr= MessageUtils.getText("smfcore.storagePos.partNumber",locale,"物料编号");
String proDateStr= MessageUtils.getText("smfcore.storagePos.proDate",locale,"生产日期");
String expireDateStr= MessageUtils.getText("smfcore.storagePos.expireDate",locale,"过期时间");
String posNameStr= MessageUtils.getText("smfcore.storagePos.posName",locale,"库位号");
String lockNameStr= MessageUtils.getText("smfcore.storagePos.lockName",locale,"工单号");
String amountStr= MessageUtils.getText("smfcore.storagePos.amount",locale,"数量");
String putInTimeStr= MessageUtils.getText("smfcore.storagePos.putInTime",locale,"首次入库时间");
String putInDateStr= MessageUtils.getText("smfcore.storagePos.putInDate",locale,"入库时间");
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:SS");
List<Map<String, Object>> list = new ArrayList<>();
for (StoragePos pos : storagePos) {
Map<String, Object> map = new LinkedHashMap<>();
map.put(barcodeStr, pos.getBarcode().getBarcode());
map.put(partNumberStr, pos.getBarcode().getPartNumber());
String proDate = pos.getBarcode().getProduceDate() == null ? "" : dateFormat.format(pos.getBarcode().getProduceDate());
map.put(proDateStr, proDate);
map.put(expireDateStr, pos.getBarcode().getExpireDate());
map.put(posNameStr, pos.getPosName());
map.put(lockNameStr, pos.getBarcode().getLockName());
map.put(amountStr, pos.getBarcode().getAmount());
String putInTime = (pos.getBarcode().getPutInTime() == -1) ? "" : dateFormat.format(new Date(pos.getBarcode().getPutInTime()));
if(ObjectUtil.isNotEmpty(putInTime)){
putInTime=dateFormat.format(pos.getBarcode().getPutInDate());
public void download(Query query, Pageable pageable, HttpServletResponse response,Locale locale) throws IOException {
FileUtil.downloadExcel(query,pageable,response, new IExcelDownLoad() {
@Override
public List<List<String>> getHeader() {
String barcodeStr= MessageUtils.getText("smfcore.storagePos.barcode",locale,"条码编号");
String partNumberStr= MessageUtils.getText("smfcore.storagePos.partNumber",locale,"物料编号");
String providerStr= MessageUtils.getText("smfcore.barcode.provider",locale,"供应商");
String batchStr= MessageUtils.getText("smfcore.barcode.batch",locale,"批次");
String proDateStr= MessageUtils.getText("smfcore.storagePos.proDate",locale,"生产日期");
String expireDateStr= MessageUtils.getText("smfcore.storagePos.expireDate",locale,"过期时间");
String posNameStr= MessageUtils.getText("smfcore.storagePos.posName",locale,"库位号");
String lockNameStr= MessageUtils.getText("smfcore.storagePos.lockName",locale,"工单号");
String amountStr= MessageUtils.getText("smfcore.storagePos.amount",locale,"数量");
String distanceStr= MessageUtils.getText("smfcore.storagePos.distance",locale,"间距");
String putInTimeStr= MessageUtils.getText("smfcore.storagePos.putInTime",locale,"首次入库时间");
String putInDateStr= MessageUtils.getText("smfcore.storagePos.putInDate",locale,"入库时间");
List<List<String>> header = new ArrayList<>();
header.add(Lists.newArrayList(barcodeStr));
header.add(Lists.newArrayList(partNumberStr));
header.add(Lists.newArrayList(providerStr));
header.add(Lists.newArrayList(batchStr));
header.add(Lists.newArrayList(posNameStr));
header.add(Lists.newArrayList(amountStr));
header.add(Lists.newArrayList(distanceStr));
header.add(Lists.newArrayList(putInTimeStr));
header.add(Lists.newArrayList(putInDateStr));
return header;
}
map.put(putInTimeStr, putInTime);
map.put(putInDateStr, dateFormat.format(pos.getBarcode().getPutInDate()));
list.add(map);
}
FileUtil.downloadExcel(list, response);
@Override
public List<List<Object>> getPageData(Query query, Pageable pageable) {
List<List<Object>> dataList = new ArrayList<>();
List<StoragePos> storagePos = storagePosDao.findByQuery(query, pageable);
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:SS");
for (StoragePos pos : storagePos) {
List<Object> data = new ArrayList<>();
data.add(pos.getBarcode().getBarcode());
data.add(pos.getBarcode().getPartNumber());
data.add(pos.getBarcode().getProvider());
data.add(pos.getBarcode().getBatch());
data.add(pos.getPosName());
data.add(pos.getBarcode().getAmount());
data.add(pos.getBarcode().getDistance());
String putInTime = (pos.getBarcode().getPutInTime() == -1) ? "" : dateFormat.format(new Date(pos.getBarcode().getPutInTime()));
if(ObjectUtil.isNotEmpty(putInTime)){
putInTime=dateFormat.format(pos.getBarcode().getPutInDate());
}
data.add(putInTime);
data.add(dateFormat.format(pos.getBarcode().getPutInDate()));
dataList.add(data);
}
return dataList;
}
});
}
/**
* 查找同尺寸连续的库位,合并库位放置料盘,仅用于智能料架
......@@ -600,10 +623,10 @@ public class StoragePosManagerImpl implements IStoragePosManager {
}
Query q = new Query(c);
//数量从大到小,出库先进先出
Sort sort = Sort.by(Sort.Direction.DESC, "barcode.amount");
sort.and(Sort.by(Sort.Direction.ASC, "barcode.batch"));
Sort amountSort = Sort.by(Sort.Direction.DESC, "barcode.amount");
Sort batchSort = Sort.by(Sort.Direction.ASC, "barcode.batch");
//sort.and(Sort.by(Sort.Direction.ASC, "canCheckOutTime"));
q.with(sort);
q.with(amountSort).with(batchSort);
List<StoragePos> posList = storagePosDao.findByQuery(q);
if (posList == null || posList.size() <= 0) {
log.info("findOrderItemInStorage 挑料 partNumber=" + pn + ",未找到可以出库的物料 ");
......
......@@ -17,6 +17,7 @@ import com.neotel.smfcore.core.system.rest.bean.dto.SettingsDto;
import com.neotel.smfcore.core.system.rest.bean.dto.SysSettingsDto;
import com.neotel.smfcore.core.system.rest.bean.mapstruct.SettingsMapper;
import com.neotel.smfcore.core.system.service.po.Settings;
import com.neotel.smfcore.security.annotation.AnonymousGetMapping;
import com.neotel.smfcore.security.rest.bean.dto.MenuDto;
import com.neotel.smfcore.security.rest.bean.query.UserQueryCriteria;
import com.neotel.smfcore.security.service.po.Menu;
......@@ -57,8 +58,7 @@ public class SettingsController {
private String version;
@ApiOperation("获取系统设置信息")
@GetMapping("/sysSettings")
@PreAuthorize("@el.check('sysSetting')")
@AnonymousGetMapping("/sysSettings")
public SysSettingsDto getSysSettings() {
Settings settings = dataCache.getSettings();
......@@ -82,8 +82,7 @@ public class SettingsController {
}
@ApiOperation("获取出库策略信息")
@GetMapping("/checkoutSettings")
@PreAuthorize("@el.check('outSetting')")
@AnonymousGetMapping("/checkoutSettings")
public Map<String,String> getCheckOutSettings() {
String outSet = dataCache.getCheckOutType().name();
Map<String, String> map = new HashMap<>();
......@@ -105,8 +104,7 @@ public class SettingsController {
@ApiOperation("获取工单设置")
@GetMapping("/order")
@PreAuthorize("@el.check('orderSetting')")
@AnonymousGetMapping("/order")
public OrderSetting getOrderSetting() {
OrderSetting orderSetting = dataCache.getOrderSetting();
orderSetting.setShowLightType(false);
......
......@@ -11,6 +11,7 @@ import com.neotel.smfcore.core.barcode.bean.CodeBean;
import com.neotel.smfcore.core.barcode.utils.CodeResolve;
import com.neotel.smfcore.core.device.enums.OP_STATUS;
import com.neotel.smfcore.core.device.util.DataCache;
import com.neotel.smfcore.core.storage.rest.query.StoragePosFindCriteria;
import com.neotel.smfcore.core.storage.service.po.Storage;
import com.neotel.smfcore.core.system.rest.bean.dto.TaskDto;
import com.neotel.smfcore.core.system.rest.bean.mapstruct.TaskMapper;
......@@ -36,6 +37,8 @@ import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Set;
......@@ -64,17 +67,8 @@ public class TaskController {
@Autowired
protected CodeResolve codeResolve;
// @ApiOperation("导出用户数据")
// @GetMapping(value = "/download")
// @PreAuthorize("@el.check('user:list')")
// public void download(HttpServletResponse response, UserQueryCriteria criteria) throws IOException {
// userService.download(userService.queryAll(criteria), response);
// }
@ApiOperation("查询出入库日志")
@GetMapping("/history")
@PreAuthorize("@el.check('taskLog')")
public PageData<TaskDto> query(TaskQueryCondition criteria, Pageable pageable) {
private Query getQuery(TaskQueryCondition criteria){
String barcode = criteria.getBarcode();
if(Strings.isNotBlank(barcode)){
CodeBean codebean = codeResolve.resolveSingleCode(criteria.getBarcode());
......@@ -111,12 +105,28 @@ public class TaskController {
}else if(finished){
query.addCriteria(Criteria.where("status").in(OP_STATUS.END.name(), OP_STATUS.FINISHED.name()));
}
return query;
}
@ApiOperation("查询出入库日志")
@GetMapping("/history")
@PreAuthorize("@el.check('taskLog')")
public PageData<TaskDto> query(TaskQueryCondition criteria, Pageable pageable) {
Query query = getQuery(criteria);
// query.with(Sort.by(Sort.Direction.DESC,"updateDate","createDate"));
PageData<DataLog> taskList = dataLogManager.findByPage(query, pageable);
PageData<TaskDto> result= taskMapper.toDto(taskList);
return result;
}
@ApiOperation("导出查找出入库日志")
@GetMapping(value = "/history/download")
@PreAuthorize("@el.check('taskLog')")
public void download(HttpServletResponse response, TaskQueryCondition criteria, Pageable pageable, HttpServletRequest request) throws IOException {
Query query = getQuery(criteria);
dataLogManager.download(query, pageable, response,request.getLocale());
}
@ApiOperation("获取某个分组队列中的任务")
@GetMapping("/{groupId}")
@PreAuthorize("@el.check('taskLog')")
......
......@@ -2,11 +2,18 @@ package com.neotel.smfcore.core.system.service.manager;
import com.neotel.smfcore.common.base.IBaseManager;
import com.neotel.smfcore.core.system.service.po.DataLog;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.query.Query;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
public interface IDataLogManager extends IBaseManager<DataLog> {
List<DataLog> findUnFinishedTasks();
DataLog findLastOutTask(String barcode,boolean addOutbound);
void download(Query query, Pageable pageable, HttpServletResponse response, Locale locale) throws IOException;
}
package com.neotel.smfcore.core.system.service.manager.impl;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import com.neotel.smfcore.common.base.IExcelDownLoad;
import com.neotel.smfcore.common.bean.PageData;
import com.neotel.smfcore.common.exception.ValidateException;
import com.neotel.smfcore.common.utils.FileUtil;
import com.neotel.smfcore.core.device.enums.OP_STATUS;
import com.neotel.smfcore.core.language.util.MessageUtils;
import com.neotel.smfcore.core.storage.service.po.StoragePos;
import com.neotel.smfcore.core.system.service.dao.IDataLogDao;
import com.neotel.smfcore.core.system.service.manager.IDataLogManager;
import com.neotel.smfcore.core.system.service.po.DataLog;
......@@ -13,9 +19,11 @@ import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
@Service
public class DataLogManagerImpl implements IDataLogManager {
......@@ -82,4 +90,54 @@ public class DataLogManagerImpl implements IDataLogManager {
DataLog dataLog = dataLogDao.findOne(query);
return dataLog;
}
@Override
public void download(Query query, Pageable pageable, HttpServletResponse response, Locale locale) throws IOException {
FileUtil.downloadExcel(query, pageable, response, new IExcelDownLoad() {
@Override
public List<List<String>> getHeader() {
List<List<String>> header = new ArrayList<>();
header.add(Lists.newArrayList("类型"));
header.add(Lists.newArrayList("单号"));
header.add(Lists.newArrayList("料仓名称"));
header.add(Lists.newArrayList("条码编号"));
header.add(Lists.newArrayList("料件编号"));
header.add(Lists.newArrayList("批次"));
header.add(Lists.newArrayList("数量"));
header.add(Lists.newArrayList("用户"));
header.add(Lists.newArrayList("供应商"));
header.add(Lists.newArrayList("来源二"));
header.add(Lists.newArrayList("状态"));
header.add(Lists.newArrayList("更新时间"));
return header;
}
@Override
public List<List<Object>> getPageData(Query query, Pageable pageable) {
List<List<Object>> dataList = new ArrayList<>();
List<DataLog> dataLogList = dataLogDao.findByQuery(query, pageable);
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:SS");
for (DataLog dataLog : dataLogList) {
List<Object> data = new ArrayList<>();
data.add(dataLog.getDetailTypeStr());//"类型"
data.add(dataLog.getSourceName());//"单号"
data.add(dataLog.getPosName());//"料仓名称"
data.add(dataLog.getBarcode());//"条码编号"
data.add(dataLog.getPartNumber());//"料件编号"
data.add(dataLog.getBatchInfo());//"批次"
data.add(dataLog.getReelQty());//"数量"
data.add(dataLog.getOperator());//"用户"
data.add(dataLog.getProvider());//"供应商"
data.add(dataLog.getSubSourceInfo());//"来源二"
data.add(dataLog.getStatusStr());//"状态"
data.add("更新时间");
dataList.add(data);
}
return dataList;
}
});
}
}
......@@ -467,6 +467,36 @@ public class DataLog extends BasePo implements Serializable {
}
}
public String getDetailTypeStr(){
int detailType = getDetailType();
String detailTypeStr = "";
//1=普通入库,2=并盘入库,3=截料入库,4=退料入库
if(detailType == 1){
detailTypeStr = "普通入库";
}else if(detailType == 2){
detailTypeStr = "并盘入库";
}else if(detailType == 3){
detailTypeStr = "截料入库";
}else if(detailType == 4){
detailTypeStr = "退料入库";
}else if(detailType == 100){
//0普通出库,1并盘出库 ,2湿敏出库 3线边仓间转储出库 ,10=工单出库
// * 4=转外协出库,发运单出库,成本中心领料:对应4,预留单出库;
detailTypeStr = "普通出库";
}else if(detailType == 101){
detailTypeStr = "并盘出库";
}else if(detailType == 102){
detailTypeStr = "湿敏出库";
}else if(detailType == 103){
detailTypeStr = "线边仓间转储出库";
}else if(detailType == 104){
detailTypeStr = "预留单出库";
}else if(detailType == 110){
detailTypeStr = "工单出库";
}
return detailTypeStr;
}
public int getReelQty(){
if(type == OP.PUT_IN){
return num;
......@@ -474,4 +504,13 @@ public class DataLog extends BasePo implements Serializable {
return 0 - num;
}
}
public String getStatusStr() {
String statusStr = "";
String statusValue = getStatus();
if(statusValue.equals(OP_STATUS.WAIT)){
statusStr = "等待中";
}
return statusStr;
}
}
......@@ -92,6 +92,7 @@ public class MenuController {
Query query = QueryHelp.getQuery(criteria);
query.addCriteria(Criteria.where("type").ne(2));
//Query query=new Query(Criteria.where("type").ne(2));
menuManager.download(menuManager.findByQuery(query), response,request.getLocale());
}
......@@ -102,8 +103,7 @@ public class MenuController {
public ResponseEntity<Object> query(@RequestParam String pid,HttpServletRequest servletRequest) {
List<Menu> menus=menuManager.getMenusByPid(pid);
Locale locale=servletRequest.getLocale();
for (Menu menu :menus
) {
for (Menu menu :menus) {
menu.UpdateTitle(locale);
}
List<MenuDto> dtos=menuMapper.toDto(menus);
......
......@@ -129,7 +129,7 @@ public class UserController {
if(resources.getGroups()==null){
resources.setGroups(new HashSet<String>());
}
resources.setEnabled(false);
resources.setEnabled(true);
if(resources.getCheckCode()==null){
resources.setCheckCode("");
}
......
......@@ -81,21 +81,21 @@ public class UserDetailsServiceImpl implements UserDetailsService {
if (user == null) {
throw new ValidateException("smfcore.valueNotExist","{0}[{1}]不存在",new String[]{"username",username});
} else {
if(user.getEnabled()==null){
throw new ValidateException("smfcore.notActivated","账号未激活");
}
if (!user.getEnabled()) {
throw new ValidateException("smfcore.notActivated","账号未激活");
}
if(user.getUsername().equals(Constants.SUPER_USERNAME)){
}else {
//判断激活码是否正确
String code = Md5Utls.getMd5(user.getId(), user.getCreateDate());
if (!code.equals(user.getCheckCode())) {
throw new ValidateException("smfcore.notActivated","账号未激活");
}
}
// if(user.getEnabled()==null){
// throw new ValidateException("smfcore.notActivated","账号未激活");
// }
// if (!user.getEnabled()) {
// throw new ValidateException("smfcore.notActivated","账号未激活");
// }
// if(user.getUsername().equals(Constants.SUPER_USERNAME)){
//
// }else {
// //判断激活码是否正确
// String code = Md5Utls.getMd5(user.getId(), user.getCreateDate());
// if (!code.equals(user.getCheckCode())) {
// throw new ValidateException("smfcore.notActivated","账号未激活");
// }
// }
List<Long> dataScopes = new ArrayList<>();
jwtUserDto = new JwtUserDto(
user,
......
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!