Commit 102bc5b0 zshaohui

1.增加虚拟仓功能

2.nexim增加用户名和密码配置
1 个父辈 47f1f5dd
正在显示 32 个修改的文件 包含 1116 行增加461 行删除
......@@ -6,4 +6,6 @@ public class BARCODE_SOURCE {
//虚拟仓
public static final String VIRTUAL = "virtual";
public static final String ALL = "ALL";
}
......@@ -208,8 +208,8 @@ public class BarcodeDto implements Serializable {
private Date openTime;
@ApiModelProperty("描述")
private String describe;
//@ApiModelProperty("描述")
//private String describe;
@ApiModelProperty("器件厚度")
private String thickness="";
......
......@@ -217,7 +217,7 @@ public class Barcode extends BasePo implements Serializable {
/**
* 描述
*/
private String describe;
//private String describe;
/**
* 厚度
* 请选择
......@@ -237,6 +237,11 @@ public class Barcode extends BasePo implements Serializable {
private Map<String,Object> appendData = new HashMap<>();
/**
* 是否自动创建
*/
private boolean autoCreate = false;
/**
* 添加或更新自定义附加信息
* @param appendKey
* @param appendValue
......@@ -493,6 +498,32 @@ public class Barcode extends BasePo implements Serializable {
return null;
}
public Barcode getSubCodeByMpn(String mpn) {
if (subCodeList == null) {
return null;
}
for (Barcode barcode : subCodeList
) {
if (mpn.equals(barcode.getMpn())) {
return barcode;
}
}
return null;
}
public Barcode getSubCodeByBarcodeId(String id) {
if (subCodeList == null) {
return null;
}
for (Barcode barcode : subCodeList
) {
if (barcode.getId().equals(id)) {
return barcode;
}
}
return null;
}
public void UpdateSubCode(Barcode barcode) {
if (subCodeList == null) {
......
......@@ -5,6 +5,8 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
......@@ -51,4 +53,9 @@ public class MsgInfo implements Serializable {
* 模块
*/
private String moudle="";
/**
* 当前收到时间
*/
private long lastReceiveTime = System.currentTimeMillis();
}
......@@ -771,7 +771,7 @@ public class StatusBean {
}
if (msgArray.length == 1) {
msgList.add(new MsgInfo(msg, msgType, msgEn, msgJp, msgCode, msgParam, "", "",""));
msgList.add(new MsgInfo(msg, msgType, msgEn, msgJp, msgCode, msgParam, "", "","",System.currentTimeMillis()));
} else {
msgList.add(new MsgInfo(msg, msgType));
}
......
......@@ -123,7 +123,7 @@ public class XLCBoxHandler extends BaseDeviceHandler {
dto.setBarcode(barcode.getBarcode());
dto.setPartNumber(barcode.getPartNumber());
dto.setId(barcode.getId());
dto.setDescribe(barcode.getDescribe());
dto.setMemo(barcode.getMemo());
return dto;
}
......
......@@ -22,7 +22,7 @@ public class XLCPosBarcodeDto implements Serializable {
private int amount;
@ApiModelProperty("描述")
private String describe;
private String memo;
/**
* 料箱中的物料信息
*/
......
......@@ -476,7 +476,7 @@ public class DataCache {
/**
* 入库时增加使用库位列表
*/
private void addUsedPosList(String cid, StoragePos pos) {
public void addUsedPosList(String cid, StoragePos pos) {
Map<String,StoragePos> usedPosList = getUsedPosList(cid);
usedPosList.put(pos.getPosName(),pos);
usedPosMap.put(cid, usedPosList);
......
......@@ -448,39 +448,35 @@ public class LiteOrderCache {
/**
* 执行工单出库
*/
public synchronized String checkOutLiteOrder(String orderNo, boolean outBom,boolean singleOut,boolean needCheck,List<String> cidList) {
public synchronized String checkOutLiteOrder(String orderNo, boolean outBom, boolean singleOut, boolean needCheck, List<String> cidList) {
//判断工单是否存在
LiteOrder cacheOrder = liteOrderMap.get(orderNo);
if (cacheOrder == null) {
cacheOrder = liteOrderManager.findByOrderNo(orderNo);
}
if (cacheOrder == null) {
return "smfcore.order.out.notFound";
}
if ( !cacheOrder.isTaskFinished() && !cacheOrder.isNew()) {
//判断工单状态是否可执行
if (!cacheOrder.isTaskFinished() && !cacheOrder.isNew()) {
log.info("工单[" + orderNo + "]正在执行");
return "smfcore.order.out.executing";
}
if(cacheOrder.isClosed()) {
if (cacheOrder.isClosed()) {
log.info("工单[" + orderNo + "]已关闭,无法出库");
return "smfcore.order.hasClose";
}
//判断是否达到可执行的最大数量
ORDER_COLOR nextColor = getNextColor();
if (nextColor == null) {
log.info("执行工单[" + orderNo + "] outBom=" + outBom + "时,已达最大可执行工单数");
return "smfcore.order.out.maxOrder";
}
//先查找是否已经锁定过库位,如果已经锁定过,出锁定的库位
List<StoragePos> lockPosList = storagePosManager.findLockPos(cacheOrder.getOrderNo());
if(lockPosList!=null&& lockPosList.size()>0){
return checkOutOrder(cacheOrder).getMsgKey();
if (lockPosList != null && lockPosList.size() > 0) {
return checkOutOrder(cacheOrder).getMsgKey();
}
log.info("开始执行工单[" + orderNo + "] outBom=" + outBom);
cacheOrder.setTaskReelCount(0);
cacheOrder.setTaskFinishedTime(-1);
......@@ -490,35 +486,26 @@ public class LiteOrderCache {
} else {
cacheOrder.setStatus(LITEORDER_STATUS.TAILS);
}
//liteOrderMap.put(cacheOrder.getOrderNo(), cacheOrder);
int taskReelCount = 0;
CHECKOUT_TYPE checkoutType = dataCache.getCheckOutType();
if(needCheck&&(shortageCheck(cacheOrder,outBom,cidList))) {
//缺料检查
if (needCheck && (shortageCheck(cacheOrder, outBom, cidList))) {
return "smfcore.order.out.noTask";
}
int taskReelCount = 0;
CHECKOUT_TYPE checkoutType = dataCache.getCheckOutType();
List<String> availableStorageIds = dataCache.getAvailableStorageIds(cidList);
//需要出库的料箱信息
boolean shortage = false;
List<String> needOutPosId = new ArrayList<>();
boolean shortage=false;
//其他出库模式一次性全部生成任务
//开始循环处理数据
for (LiteOrderItem orderItem : cacheOrder.getOrderItems()) {
//当前已出数量置为空
orderItem.setOutNum(0);
orderItem.setOutReelCount(0);
liteOrderItemManager.save(orderItem);
//剩余未出数量
Float totalNum = orderItem.getNeedNum() * cacheOrder.getOrderTimes();
int remainNum = totalNum.intValue() - orderItem.getTotalOutNum();
//剩余未出盘数
int remainReelCount = orderItem.getNeedReelCount() - orderItem.getTotalOutReelCount();
//此PN未完成
if (remainNum > 0 || remainReelCount > 0) {
if (outBom) {
//套料出库,设置剩余数量为1,这样就只会出一盘
......@@ -528,130 +515,165 @@ public class LiteOrderCache {
int assignNum = 0;
int assignReelCount = 0;
while (assignNum < remainNum || assignReelCount < remainReelCount) {
Collection<String> excludePosIds = excludeOutPosIds();
String partNumber = orderItem.getPn();
String reelId = orderItem.getRi();
//判断是否ri出库
String ri = orderItem.getRi();
String pn = orderItem.getPn();
String mpn = orderItem.getMpn();
StoragePos pos = null;
if(!Strings.isNullOrEmpty(reelId)){
//RI
pos=storagePosManager.getByBarcode(reelId);
if(pos != null){
if(excludePosIds.contains(pos.getId())) {
log.info("工单[" + orderNo + "]RI出库,任务数[" + taskReelCount + "]出库位置仓位【" + pos.getPosName() + "】RI=[" + pos.getBarcode().getBarcode() + "]已在操作队列中,跳过不处理");
break;
if (StringUtils.isNotEmpty(ri)) {
StoragePos pos = findPosByRi(ri, excludeOutPosIds(), orderNo, taskReelCount);
if (pos == null) {
shortage = true;
log.info("工单[" + orderNo + "]RI出库时,库存中未找到料盘[" + ri + "]");
break;
} else {
//判断是在料箱,还是在物料中
Barcode barcode = pos.getBarcode();
if (barcode != null) {
List<Barcode> subCodeList = barcode.getSubCodeList();
if (subCodeList != null && !subCodeList.isEmpty()) {
Barcode subCode = barcode.getSubCodeByBarcode(ri);
if (subCode != null) {
log.info(subCode.getBarcode() + "对应的料箱为:" + barcode.getBarcode() + ",需要进行标记,进行出库,工单为:" + orderNo);
subCode = updateSubCodeAppendData(cacheOrder, orderItem, subCode);
//同时更新barcode和库位信息
barcode.UpdateSubCode(subCode);
barcodeManager.save(subCode);
barcodeManager.save(barcode);
pos.setBarcode(barcode);
storagePosManager.save(pos);
needOutPosId.add(pos.getId());
assignReelCount = assignReelCount + 1;
taskReelCount = taskReelCount + 1;
assignNum = assignNum + subCode.getAmount();
}
} else {
log.info(barcode.getBarcode() + "对应的库位为:" + barcode.getPosName() + ",需要进行标记,进行出库,工单为:" + orderNo);
assignNum = assignNum + pos.getBarcode().getAmount();
assignReelCount = assignReelCount + 1;
taskReelCount = taskReelCount + 1;
generateOrderTask(pos, cacheOrder, orderItem, nextColor, singleOut);
}
}
}else{
shortage=true;
log.info("工单[" + orderNo + "]RI出库时,库存中未找到料盘["+reelId+"]");
}
}else if (Strings.isNullOrEmpty(reelId) && !Strings.isNullOrEmpty(partNumber)){
//PN
pos=storagePosManager.findPartNumberInStorages(availableStorageIds,"", partNumber, excludePosIds, checkoutType,orderItem.getAppendData());
} else if (Strings.isNullOrEmpty(reelId) && Strings.isNullOrEmpty(partNumber) && !Strings.isNullOrEmpty(mpn)){
pos=storagePosManager.findMpnInStorages(availableStorageIds, mpn, excludePosIds, checkoutType,orderItem.getAppendData());
}
if (pos == null) {
// log.error("未找到可以出库的物料[" + partNumber + "]");
shortage=true;
break;
} else {
//判断是属于料箱还是料盘
Barcode posBarcode = pos.getBarcode();
List<Barcode> subCodeList = posBarcode.getSubCodeList();
if (subCodeList == null || subCodeList.isEmpty()) {
assignNum = assignNum + pos.getBarcode().getAmount();
assignReelCount = assignReelCount + 1;
taskReelCount = taskReelCount + 1;
log.info("工单[" + orderNo + "],任务数[" + taskReelCount + "]出库位置仓位【" + pos.getPosName() + "】RI=[" + pos.getBarcode().getBarcode() + "] PN=[" + partNumber + "] num:" + pos.getBarcode().getAmount());
DataLog task = newTask(pos);
task.setSourceId(cacheOrder.getId());
task.setSourceName(cacheOrder.getOrderNo());
task.setSubSourceId(orderItem.getId());
task.setSubSourceInfo(orderItem.getFeederInfo());
task.setType(OP.CHECKOUT);
task.setLightColor(nextColor.getRgb());
task.setStatus(OP_STATUS.WAIT.name());
task.setSingleOut(singleOut);
task.setLine(cacheOrder.getLine());
// task = dataLogDao.save(task);
taskService.addTaskToExecute(task);
} else {
Barcode subCode = null;
if (!Strings.isNullOrEmpty(reelId)) {
subCode = posBarcode.getSubCodeByBarcode(reelId);
} else if (Strings.isNullOrEmpty(reelId) && !Strings.isNullOrEmpty(partNumber)) {
subCode = posBarcode.getSubCode(partNumber);
} else if (StringUtils.isEmpty(ri) && StringUtils.isNotEmpty(pn)) {
List<Barcode> barcodeList = findPosByPartNumberAndSort(availableStorageIds, pn, excludeOutPosIds(), checkoutType, orderItem.getAppendData());
if (barcodeList == null || barcodeList.isEmpty()) {
break;
}
for (Barcode barcode : barcodeList) {
//判断库位是否存在
if (assignNum >= remainNum && assignReelCount >= remainReelCount) {
break;
}
if (subCode != null) {
//设置出库数量
int amount = subCode.getAmount();
int awaitingNum = remainNum - assignNum;
if (awaitingNum - amount >= 0) {
assignNum = assignNum + amount;
subCode.updateAppendData("awaiting", amount);
} else {
subCode.updateAppendData("awaiting", amount - awaitingNum);
assignNum = assignNum + amount - awaitingNum;
if (StringUtils.isEmpty(barcode.getPosName())) {
continue;
}
if (StringUtils.isEmpty(barcode.getHostBarcodeId())) {
log.info(barcode.getBarcode() + "对应的库位为:" + barcode.getPosName() + ",需要进行标记,进行出库,工单为:" + orderNo);
StoragePos pos = storagePosManager.getByBarcode(barcode.getBarcode());
generateOrderTask(pos, cacheOrder, orderItem, nextColor, singleOut);
assignNum = assignNum + pos.getBarcode().getAmount();
assignReelCount = assignReelCount + 1;
taskReelCount = taskReelCount + 1;
} else {
StoragePos pos = storagePosManager.getByBarcodeId(barcode.getHostBarcodeId());
Barcode posBarcode = pos.getBarcode();
if (posBarcode != null) {
Barcode subCode = posBarcode.getSubCodeByBarcode(barcode.getBarcode());
if (subCode != null) {
log.info(subCode.getBarcode() + "对应的料箱为:" + posBarcode.getBarcode() + ",需要进行标记,进行出库,工单为:" + orderNo);
subCode = updateSubCodeAppendData(cacheOrder, orderItem, subCode);
//同时更新barcode和库位信息
posBarcode.UpdateSubCode(subCode);
barcodeManager.save(subCode);
barcodeManager.save(posBarcode);
pos.setBarcode(posBarcode);
storagePosManager.save(pos);
needOutPosId.add(pos.getId());
assignReelCount = assignReelCount + 1;
taskReelCount = taskReelCount + 1;
assignNum = assignNum + subCode.getAmount();
}
}
}
}
} else if (StringUtils.isEmpty(ri) && StringUtils.isEmpty(pn) && StringUtils.isNotEmpty(mpn)) {
List<Barcode> barcodeList = findPosByMpnAndSort(availableStorageIds, mpn, excludeOutPosIds(), checkoutType, orderItem.appendData);
if (barcodeList == null || barcodeList.isEmpty()) {
break;
}
for (Barcode barcode : barcodeList) {
//判断库位是否存在
if (assignNum >= remainNum && assignReelCount >= remainReelCount) {
break;
}
if (StringUtils.isEmpty(barcode.getPosName())) {
continue;
}
if (StringUtils.isEmpty(barcode.getHostBarcodeId())) {
log.info(barcode.getBarcode() + "对应的库位为:" + barcode.getPosName() + ",需要进行标记,进行出库,工单为:" + orderNo);
StoragePos pos = storagePosManager.getByBarcode(barcode.getBarcode());
generateOrderTask(pos, cacheOrder, orderItem, nextColor, singleOut);
assignNum = assignNum + pos.getBarcode().getAmount();
assignReelCount = assignReelCount + 1;
taskReelCount = taskReelCount + 1;
subCode.updateAppendData("orderItemId", orderItem.getId());
subCode.updateAppendData("orderNo", cacheOrder.getOrderNo());
subCode.updateAppendData("orderId", cacheOrder.getId());
posBarcode.UpdateSubCode(subCode);
barcodeManager.save(subCode);
barcodeManager.save(posBarcode);
pos.setBarcode(posBarcode);
storagePosManager.save(pos);
needOutPosId.add(pos.getId());
} else {
StoragePos pos = storagePosManager.getByBarcodeId(barcode.getHostBarcodeId());
Barcode posBarcode = pos.getBarcode();
if (posBarcode != null) {
Barcode subCode = posBarcode.getSubCodeByMpn(barcode.getMpn());
if (subCode != null) {
log.info(subCode.getBarcode() + "对应的料箱为:" + posBarcode.getBarcode() + ",需要进行标记,进行出库,工单为:" + orderNo);
subCode = updateSubCodeAppendData(cacheOrder, orderItem, subCode);
//同时更新barcode和库位信息
posBarcode.UpdateSubCode(subCode);
barcodeManager.save(subCode);
barcodeManager.save(posBarcode);
pos.setBarcode(posBarcode);
storagePosManager.save(pos);
needOutPosId.add(pos.getId());
assignReelCount = assignReelCount + 1;
taskReelCount = taskReelCount + 1;
assignNum = assignNum + subCode.getAmount();
}
}
}
}
}
//如果是RI出库,只有一盘,出完就结束
if(!Strings.isNullOrEmpty(reelId)){
if (assignNum < remainNum || assignReelCount < remainReelCount) {
shortage = true;
break;
}
}
}
}
//判断要出的箱子是否为空
if (needOutPosId != null && !needOutPosId.isEmpty()) {
needOutPosId = needOutPosId.stream().distinct().collect(Collectors.toList());
for (String posId : needOutPosId) {
StoragePos pos = storagePosManager.get(posId);
DataLog task = newTask(pos);
task.setSourceName(cacheOrder.getOrderNo());
task.setSourceId(cacheOrder.getId());
task.setType(OP.CHECKOUT);
task.setLightColor(nextColor.getRgb());
task.setStatus(OP_STATUS.WAIT.name());
task.setSingleOut(singleOut);
task.setLine(cacheOrder.getLine());
taskService.addTaskToExecute(task);
generateOrderTask(pos, cacheOrder, null, nextColor, singleOut);
taskReelCount = taskReelCount + 1;
}
}
if(shortage){
cacheOrder.addAppendDate("shortage","true");
}else{
cacheOrder.addAppendDate("shortage","false");
//标记工单是否缺料
if (shortage) {
cacheOrder.addAppendDate("shortage", "true");
} else {
cacheOrder.addAppendDate("shortage", "false");
}
cacheOrder.setTaskReelCount(taskReelCount);
cacheOrder.setTotalTaskReelCount(cacheOrder.getTotalTaskReelCount()+taskReelCount);
cacheOrder.setTotalTaskReelCount(cacheOrder.getTotalTaskReelCount() + taskReelCount);
log.info("工单[" + orderNo + "]任务分配结束,任务数[" + taskReelCount + "]");
smfApi.onOrderStatusChange(cacheOrder);
//有需要出库的
if (taskReelCount <= 0) {
finishedOrderTasks(cacheOrder);
}
liteOrderManager.save(cacheOrder);
liteOrderMap.put(cacheOrder.getOrderNo(), cacheOrder);
if (taskReelCount <= 0) {
//return "工单无可执行的任务";
......@@ -1069,4 +1091,100 @@ public class LiteOrderCache {
return "";
}
public StoragePos findPosByRi(String reelId, Collection<String> excludeOutPosIds, String orderNo, int taskReelCount) {
StoragePos pos = storagePosManager.getByBarcode(reelId);
if (pos == null) {
return null;
}
if (excludeOutPosIds.contains(pos.getId())) {
log.info("工单[" + orderNo + "]RI出库,任务数[" + taskReelCount + "]出库位置仓位【" + pos.getPosName() + "】RI=[" + pos.getBarcode().getBarcode() + "]已在操作队列中,跳过不处理");
return null;
}
return pos;
}
public List<Barcode> findPosByPartNumberAndSort(List<String> availableStorageIds, String partNumber, Collection<String> excludePosIds, CHECKOUT_TYPE checkoutType, Map<String, String> appendDate) {
List<Barcode> barcodeList = new ArrayList<>();
List<StoragePos> posList = storagePosManager.findPosListByPartNumber(availableStorageIds, partNumber, excludePosIds, checkoutType, appendDate);
if (posList == null || posList.isEmpty()) {
return barcodeList;
}
//提取出来所有Barcode信息
for (StoragePos pos : posList) {
Barcode barcode = pos.getBarcode();
if (barcode != null) {
List<Barcode> subCodeList = barcode.getSubCodeList();
if (subCodeList != null && !subCodeList.isEmpty()) {
for (Barcode subCode : subCodeList) {
Integer awaiting = subCode.getAppendData("awaiting");
if (awaiting != null){
continue;
}
if (partNumber.equals(subCode.getPartNumber())) {
barcodeList.add(subCode);
}
}
} else {
barcodeList.add(barcode);
}
}
}
barcodeList = taskService.barcodeListByCheckOutType(checkoutType,barcodeList);
return barcodeList;
}
public List<Barcode> findPosByMpnAndSort(List<String> availableStorageIds, String mpn, Collection<String> excludePosIds, CHECKOUT_TYPE checkoutType, Map<String, String> appendDate) {
List<Barcode> barcodeList = new ArrayList<>();
List<StoragePos> posList = storagePosManager.findPosListByMpn(availableStorageIds, mpn, excludePosIds, checkoutType, appendDate);
if (posList == null || posList.isEmpty()) {
return barcodeList;
}
//提取出来所有Barcode信息
for (StoragePos pos : posList) {
Barcode barcode = pos.getBarcode();
if (barcode != null) {
List<Barcode> subCodeList = barcode.getSubCodeList();
if (subCodeList != null && !subCodeList.isEmpty()) {
for (Barcode subCode : subCodeList) {
Integer awaiting = subCode.getAppendData("awaiting");
if (awaiting != null){
continue;
}
if (mpn.equals(subCode.getMpn())) {
barcodeList.add(subCode);
}
}
} else {
barcodeList.add(barcode);
}
}
}
barcodeList = taskService.barcodeListByCheckOutType(checkoutType, barcodeList);
return barcodeList;
}
private Barcode updateSubCodeAppendData(LiteOrder cacheOrder, LiteOrderItem orderItem, Barcode subCode) {
subCode.updateAppendData("orderItemId", orderItem.getId());
subCode.updateAppendData("orderNo", cacheOrder.getOrderNo());
subCode.updateAppendData("orderId", cacheOrder.getId());
subCode.updateAppendData("awaiting", subCode.getAmount());
return subCode;
}
public void generateOrderTask(StoragePos pos,LiteOrder cacheOrder,LiteOrderItem orderItem,ORDER_COLOR nextColor,boolean singleOut){
DataLog task = newTask(pos);
task.setSourceId(cacheOrder.getId());
task.setSourceName(cacheOrder.getOrderNo());
if (orderItem != null) {
task.setSubSourceId(orderItem.getId());
task.setSubSourceInfo(orderItem.getFeederInfo());
}
task.setType(OP.CHECKOUT);
task.setLightColor(nextColor.getRgb());
task.setStatus(OP_STATUS.WAIT.name());
task.setSingleOut(singleOut);
task.setLine(cacheOrder.getLine());
taskService.addTaskToExecute(task);
}
}
......@@ -322,25 +322,24 @@ public class OrderController {
for (Map<String,StoragePos> list :
allPosLists) {
for (StoragePos pos : list.values()) {
boolean isItemPos = false;
if (ObjectUtil.isNotEmpty(item.getRi())) {
if (pos.getBarcode().getBarcode().equals(item.getRi())) {
isItemPos = true;
}
} else if (ObjectUtil.isNotEmpty(item.getPn())) {
if (ObjectUtil.isNotEmpty(pos.getBarcode().getPartNumber()) && pos.getBarcode().getPartNumber().startsWith(item.getPn())) {
isItemPos = true;
}
} else if (ObjectUtil.isNotEmpty(item.getMpn())) {
if (ObjectUtil.isNotEmpty(pos.getBarcode().getMpn()) && pos.getBarcode().getMpn().equals(item.getMpn())) {
isItemPos = true;
}
}
boolean isItemPos = isItemPos(item, pos.getBarcode());
if (isItemPos) {
inventoryReelCount += 1;
inventoryQty += pos.getBarcode().getAmount();
} else {
Barcode barcode = pos.getBarcode();
if (barcode != null){
List<Barcode> subCodeList = barcode.getSubCodeList();
if (subCodeList != null && !subCodeList.isEmpty()){
for (Barcode subCode : subCodeList) {
boolean isItemBox = isItemPos(item,subCode);
if (isItemBox){
inventoryReelCount += 1;
inventoryQty += subCode.getAmount();
}
}
}
}
}
}
}
......@@ -798,4 +797,22 @@ public class OrderController {
List<String> allLineList = liteOrderManager.findAllLines();
return allLineList;
}
private boolean isItemPos(LiteOrderItem item, Barcode barcode) {
boolean isItemPos = false;
if (ObjectUtil.isNotEmpty(item.getRi())) {
if (barcode.getBarcode().equals(item.getRi())) {
isItemPos = true;
}
} else if (ObjectUtil.isNotEmpty(item.getPn())) {
if (ObjectUtil.isNotEmpty(barcode.getPartNumber()) && barcode.getPartNumber().startsWith(item.getPn())) {
isItemPos = true;
}
} else if (ObjectUtil.isNotEmpty(item.getMpn())) {
if (ObjectUtil.isNotEmpty(barcode.getMpn()) && barcode.getMpn().equals(item.getMpn())) {
isItemPos = true;
}
}
return isItemPos;
}
}
......@@ -109,7 +109,7 @@ public class MaterialBoxController {
if(describe==null){
throw new ValidateException("smfcore.valueCanotNull","{0}不能为空",new String[]{"describe"} );
}
barcode.setDescribe(describe);
barcode.setMemo(describe);
barcodeManager.saveBarcode(barcode);
log.info("更改料盒[" + code + "]的描述信息为:" + describe);
return ResultBean.newOkResult("");
......@@ -544,7 +544,7 @@ public class MaterialBoxController {
* @param opQty 数量
* @throws ValidateException
*/
private void finishTask(Barcode pidBarcode, int opType, DataLog currentTask, Barcode subBarcode, int opQty) throws ValidateException {
private synchronized void finishTask(Barcode pidBarcode, int opType, DataLog currentTask, Barcode subBarcode, int opQty) throws ValidateException {
//更新barcode缓存
......@@ -599,7 +599,7 @@ public class MaterialBoxController {
task = dataLogManager.save(task);
taskService.moveTaskToFinished(task);
// dataCache.updateInventoryAmount(task.getCid(), subBarcode.getPartNumber(), opQty);
// dataCache.updateInventoryAmount(task.getCid(), subBarcode.getPartNumber(), opQty);
}
}
......@@ -198,7 +198,10 @@ public class StorageController {
List<Storage> allStorages = storageManager.findAll();
List<Storage> myStorages = new ArrayList<>();
for (Storage s : allStorages) {
if (BARCODE_SOURCE.VIRTUAL.equals(type)){
if (BARCODE_SOURCE.ALL.equals(type)){
}
else if (BARCODE_SOURCE.VIRTUAL.equals(type)){
if (!s.isVirtual()){
continue;
}
......
......@@ -15,6 +15,7 @@ import com.neotel.smfcore.core.barcode.enums.BARCODE_SOURCE;
import com.neotel.smfcore.core.barcode.rest.bean.dto.BarcodeDto;
import com.neotel.smfcore.core.barcode.rest.bean.dto.CodeDto;
import com.neotel.smfcore.core.barcode.rest.bean.mapstruct.CodeMapper;
import com.neotel.smfcore.core.barcode.service.manager.IBarcodeManager;
import com.neotel.smfcore.core.barcode.service.po.Barcode;
import com.neotel.smfcore.core.barcode.utils.CodeResolve;
import com.neotel.smfcore.core.device.util.DataCache;
......@@ -54,6 +55,7 @@ import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@RestController
......@@ -79,6 +81,9 @@ public class StoragePosController {
@Autowired
private CodeMapper codeMapper;
@Autowired
private IBarcodeManager barcodeManager;
@ApiOperation("查询库位")
@GetMapping
......@@ -568,8 +573,10 @@ public class StoragePosController {
String isSingleOutStr = checkOutDto.getSingleOut();
boolean isSingleOut = Boolean.valueOf(isSingleOutStr);
List<String> needOutPosIdList = new ArrayList<>();
for (String pid : checkOutDto.getPids()) {
StoragePos pos = storagePosManager.get(pid);
StoragePos pos = storagePosManager.getByBarcodeId(pid);
if (pos == null) {
//throw new ValidateException("smfcore.valueNotExist", "{0}[{1}]不存在", new String[]{"pid", pid});
// throw new ValidateException("位置[" + pid + "]不存在");
......@@ -591,7 +598,7 @@ public class StoragePosController {
//如果料仓不可用,不能出库
if (!storage.isVirtual()) {
if (!dataCache.StorageIsAvailable(storage)) {
throw new ValidateException("smfcore.storage.notAvailable", "料仓{0}离线或不可用,无法出库", new String[]{storage.getName()});
//throw new ValidateException("smfcore.storage.notAvailable", "料仓{0}离线或不可用,无法出库", new String[]{storage.getName()});
}
}
......@@ -600,11 +607,29 @@ public class StoragePosController {
// if(!result) {
// throw new ValidateException("smfcore.error.getMaterialLot.out", "条码[{0}]验证失败,无法出库", new String[]{pos.getBarcode().getBarcode()});
// }
//判断是属于料箱还是物料
List<Barcode> subCodeList = posBarcode.getSubCodeList();
if(subCodeList != null && !subCodeList.isEmpty()){
Barcode subCode = posBarcode.getSubCodeByBarcodeId(pid);
if (subCode != null){
subCode.updateAppendData("awaiting", subCode.getAmount());
barcodeManager.save(subCode);
posBarcode.UpdateSubCode(subCode);
barcodeManager.save(posBarcode);
pos.setBarcode(posBarcode);
storagePosManager.save(pos);
}
}
log.info("手动出库:出库料仓【" + storage.getName() + "_" + storage.getCid() + "】位置仓位【" + pos.getPosName() + "】");
String outResult = taskService.checkout(storage, pos, isSingleOut,SecurityUtils.getCurrentUsername());
if (!Strings.isNullOrEmpty(outResult)) {
throw new ValidateException("smfcore.error", outResult);
needOutPosIdList.add(pos.getId());
}
if (needOutPosIdList != null && !needOutPosIdList.isEmpty()){
needOutPosIdList = needOutPosIdList.stream().distinct().collect(Collectors.toList());
for (String posId : needOutPosIdList) {
StoragePos pos = storagePosManager.get(posId);
Storage storage = dataCache.getStorageById(pos.getStorageId());
taskService.checkout(storage, pos, isSingleOut,SecurityUtils.getCurrentUsername());
}
}
return ResultBean.newOkResult("");
......
......@@ -95,5 +95,9 @@ public interface IStoragePosManager extends IBaseManager<StoragePos> {
StoragePos findOne(Query query);
Sort getSortByCheckOutType(CHECKOUT_TYPE checkoutType);
Sort getSortByCheckOutType(CHECKOUT_TYPE checkoutType);
List<StoragePos> findPosListByPartNumber(List<String> storageIdList, String pn, Collection<String> excludePosIds, CHECKOUT_TYPE checkOutType,Map<String,String> appendData);
List<StoragePos> findPosListByMpn(List<String> availableStorageIds, String mpn, Collection<String> excludePosIds, CHECKOUT_TYPE checkoutType, Map<String, String> appendDate);
}
......@@ -9,6 +9,7 @@ import com.neotel.smfcore.common.bean.PageData;
import com.neotel.smfcore.common.exception.ValidateException;
import com.neotel.smfcore.common.utils.DateUtil;
import com.neotel.smfcore.common.utils.PointUtil;
import com.neotel.smfcore.common.utils.StringUtils;
import com.neotel.smfcore.core.barcode.bean.PlateSizeBean;
import com.neotel.smfcore.core.barcode.service.po.Barcode;
import com.neotel.smfcore.core.storage.bean.InventoryItem;
......@@ -30,8 +31,10 @@ import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import java.awt.*;
import java.text.ParseException;
import java.util.*;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
......@@ -59,41 +62,87 @@ public class StoragePosManagerImpl implements IStoragePosManager {
return getInventory(-1, storageId);
}
private List<InventoryItem> inventory(int type,String... storageIds){
private List<InventoryItem> inventory(int type, String... storageIds) {
Criteria c = Criteria.where("barcode").exists(true).and("storageId").in(storageIds);
if(type != -1){
if (type != -1) {
c = c.and("barcode.type").is(type);
}
Aggregation agg = Aggregation.newAggregation(
Aggregation.match(c),
Aggregation.group("barcode.partNumber").sum("barcode.amount").as("stockCount").count().as("stockReel"),
Aggregation.project("stockCount", "stockReel").and("partNumber").previousOperation()
);
AggregationResults<InventoryItem> results = storagePosDao.getMongoTemplate().aggregate(agg, StoragePos.class, InventoryItem.class);
return results.getMappedResults();
Map<String, InventoryItem> resultMap = new HashMap<>();
List<StoragePos> storagePosList = storagePosDao.findByQuery(new Query(c));
for (StoragePos pos : storagePosList) {
Barcode barcode = pos.getBarcode();
if (barcode != null){
String partNumber = barcode.getPartNumber();
int amount = barcode.getAmount();
InventoryItem inventoryItem = resultMap.get(partNumber);
if (inventoryItem == null){
inventoryItem = new InventoryItem();
}
inventoryItem.setPartNumber(partNumber);
inventoryItem.setStockCount(inventoryItem.getStockCount()+amount);
inventoryItem.setStockReel(inventoryItem.getStockReel()+1);
resultMap.put(partNumber,inventoryItem);
List<Barcode> subCodeList = barcode.getSubCodeList();
if (subCodeList != null && !subCodeList.isEmpty()){
for (Barcode subCode : subCodeList) {
String subCodePartNumber = subCode.getPartNumber();
int subCodeAmount = subCode.getAmount();
InventoryItem subCodeInventoryItem = resultMap.get(subCodePartNumber);
if (subCodeInventoryItem == null){
subCodeInventoryItem = new InventoryItem();
}
subCodeInventoryItem.setPartNumber(subCodePartNumber);
subCodeInventoryItem.setStockCount(subCodeInventoryItem.getStockCount()+subCodeAmount);
subCodeInventoryItem.setStockReel(subCodeInventoryItem.getStockReel()+1);
resultMap.put(subCodePartNumber,subCodeInventoryItem);
}
}
}
}
return Lists.newArrayList(resultMap.values());
}
private List<InventoryItem> lockInventory(int type,String... storageIds){
//被锁定的仓位
// //TODO:这里还需要去掉被指定批次锁定的,因为出错,暂时不加了..
// Criteria c = Criteria.where("barcode").exists(true).and("storageId").in(storageIds)
// .andOperator(Criteria.where("canCheckOutTime").gt(System.currentTimeMillis()));
Criteria newC = Criteria.where("barcode.lockId").exists(true).ne("");
Criteria c = Criteria.where("barcode").exists(true)
.and("storageId").in(storageIds)
// .andOperator(Criteria.where("canCheckOutTime").gt(System.currentTimeMillis()))
.andOperator(newC);
if(type != -1){
private List<InventoryItem> lockInventory(int type, String... storageIds) {
Criteria c = Criteria.where("barcode").exists(true).and("storageId").in(storageIds);
if (type != -1) {
c = c.and("barcode.type").is(type);
}
Aggregation agg = Aggregation.newAggregation(
Aggregation.match(c),
Aggregation.group("barcode.partNumber").count().as("lockReel"),
Aggregation.project("lockReel").and("partNumber").previousOperation()
);
AggregationResults<InventoryItem> results = storagePosDao.getMongoTemplate().aggregate(agg, StoragePos.class, InventoryItem.class);
return results.getMappedResults();
Map<String, InventoryItem> resultMap = new HashMap<>();
List<StoragePos> storagePosList = storagePosDao.findByQuery(new Query(c));
for (StoragePos pos : storagePosList) {
Barcode barcode = pos.getBarcode();
if (barcode != null) {
String lockId = barcode.getLockId();
String partNumber = barcode.getPartNumber();
if (StringUtils.isNotEmpty(lockId)) {
InventoryItem inventoryItem = resultMap.get(partNumber);
if (inventoryItem == null) {
inventoryItem = new InventoryItem();
}
inventoryItem.setPartNumber(partNumber);
inventoryItem.setLockReel(inventoryItem.getLockReel() + 1);
resultMap.put(partNumber, inventoryItem);
}
List<Barcode> subCodeList = barcode.getSubCodeList();
if (subCodeList != null && !subCodeList.isEmpty()) {
for (Barcode subCode : subCodeList) {
String subCodeLockId = subCode.getLockId();
if (StringUtils.isNotEmpty(subCodeLockId)){
String subCodePartNumber = subCode.getPartNumber();
InventoryItem inventoryItem = resultMap.get(subCodePartNumber);
if (inventoryItem == null) {
inventoryItem = new InventoryItem();
}
inventoryItem.setPartNumber(subCodePartNumber);
inventoryItem.setLockReel(inventoryItem.getLockReel() + 1);
resultMap.put(subCodePartNumber, inventoryItem);
}
}
}
}
}
return Lists.newArrayList(resultMap.values());
}
private Map<String, InventoryItem> getInventory(int type,String... storageIds){
......@@ -145,29 +194,77 @@ public class StoragePosManagerImpl implements IStoragePosManager {
* @param inHours
* @return
*/
private List<InventoryItem> expireInventory(int type, int inHours,String[] storageIds){
private List<InventoryItem> expireInventory(int type, int inHours, String[] storageIds) {
//过期的仓位
Criteria c = Criteria.where("barcode").exists(true).and("storageId").in(storageIds);
if(type != -1){
if (type != -1) {
c = c.and("barcode.type").is(type);
}
Criteria expireCriteria = Criteria.where("expireTime").gt(System.currentTimeMillis());
if(inHours > 0){
expireCriteria = Criteria.where("expireTime").gt(System.currentTimeMillis()).lte(System.currentTimeMillis() + inHours * 60 * 60 * 1000);
}else{
expireCriteria = Criteria.where("expireTime").lte(System.currentTimeMillis());
Map<String, InventoryItem> resultMap = new HashMap<>();
List<StoragePos> storagePosList = storagePosDao.findByQuery(new Query(c));
for (StoragePos pos : storagePosList) {
Barcode barcode = pos.getBarcode();
if (barcode != null) {
Date expireDate = barcode.getExpireDate();
if (expireDate != null) {
if (inHours > 0) {
if (expireDate.getTime() > System.currentTimeMillis() && expireDate.getTime() < System.currentTimeMillis() + inHours * 60 * 60 * 1000) {
String partNumber = barcode.getPartNumber();
InventoryItem inventoryItem = resultMap.get(partNumber);
if (inventoryItem == null) {
inventoryItem = new InventoryItem();
}
inventoryItem.setPartNumber(partNumber);
inventoryItem.setExpireReel(inventoryItem.getExpireReel() + 1);
resultMap.put(partNumber, inventoryItem);
}
} else {
if (expireDate.getTime() < System.currentTimeMillis()) {
String partNumber = barcode.getPartNumber();
InventoryItem inventoryItem = resultMap.get(partNumber);
if (inventoryItem == null) {
inventoryItem = new InventoryItem();
}
inventoryItem.setPartNumber(partNumber);
inventoryItem.setExpireReel(inventoryItem.getExpireReel() + 1);
resultMap.put(partNumber, inventoryItem);
}
}
}
List<Barcode> subCodeList = barcode.getSubCodeList();
if (subCodeList != null && !subCodeList.isEmpty()) {
for (Barcode subCode : subCodeList) {
Date subCodeExpireDate = subCode.getExpireDate();
if (subCodeExpireDate != null) {
if (inHours > 0) {
if (subCodeExpireDate.getTime() > System.currentTimeMillis() && subCodeExpireDate.getTime() < System.currentTimeMillis() + inHours * 60 * 60 * 1000) {
String partNumber = subCode.getPartNumber();
InventoryItem inventoryItem = resultMap.get(partNumber);
if (inventoryItem == null) {
inventoryItem = new InventoryItem();
}
inventoryItem.setPartNumber(partNumber);
inventoryItem.setExpireReel(inventoryItem.getExpireReel() + 1);
resultMap.put(partNumber, inventoryItem);
}
} else {
if (subCodeExpireDate.getTime() < System.currentTimeMillis()) {
String partNumber = subCode.getPartNumber();
InventoryItem inventoryItem = resultMap.get(partNumber);
if (inventoryItem == null) {
inventoryItem = new InventoryItem();
}
inventoryItem.setPartNumber(partNumber);
inventoryItem.setExpireReel(inventoryItem.getExpireReel() + 1);
resultMap.put(partNumber, inventoryItem);
}
}
}
}
}
}
}
Aggregation agg = Aggregation.newAggregation(
Aggregation.match(c),
Aggregation.project("barcode").andExpression("barcode.putInTime + barcode.maxStorageTime * 60 * 60 * 1000").as("expireTime"),
Aggregation.match(expireCriteria),
Aggregation.group("barcode.partNumber").count().as("expireReel"),
Aggregation.project("expireReel").and("partNumber").previousOperation()
);
AggregationResults<InventoryItem> results = storagePosDao.getMongoTemplate().aggregate(agg, StoragePos.class, InventoryItem.class);
return results.getMappedResults();
return Lists.newArrayList(resultMap.values());
}
@Override
......@@ -573,7 +670,11 @@ public class StoragePosManagerImpl implements IStoragePosManager {
@Override
public StoragePos getByBarcodeId(String barcodeId) {
return storagePosDao.findOneByCondition(new String[]{"barcode.id"}, new String[]{barcodeId});
List<Criteria> orCriterialList = Lists.newArrayList();
orCriterialList.add(Criteria.where("barcode.id").is(barcodeId));
orCriterialList.add(Criteria.where("barcode.subCodeList.id").is(barcodeId));
Criteria c = new Criteria().orOperator(orCriterialList);
return storagePosDao.findOne(new Query(c));
}
@Override
......@@ -886,4 +987,50 @@ public class StoragePosManagerImpl implements IStoragePosManager {
public StoragePos findOne(Query query) {
return storagePosDao.findOne(query);
}
@Override
public List<StoragePos> findPosListByPartNumber(List<String> storageIdList, String pn, Collection<String> excludePosIds, CHECKOUT_TYPE checkOutType,Map<String,String> appendData) {
Criteria c = Criteria.where("id").nin(excludePosIds)
.and("enabled").is(true)//可用
.and("barcode.lockId").is(null);//没有被锁定的仓位;
if (storageIdList != null) {
c = c.and("storageId").in(storageIdList);
}
if (appendData != null) {
c = addAppendData(c, appendData);
}
List<Criteria> orCriterialList = Lists.newArrayList();
orCriterialList.add(Criteria.where("barcode.partNumber").is(pn));
orCriterialList.add(Criteria.where("barcode.subCodeList.partNumber").is(pn));
c.orOperator(orCriterialList);
Query q = new Query(c);
Sort sort = getSortByCheckOutType(checkOutType);
q.with(sort);
return storagePosDao.findByQuery(q);
}
@Override
public List<StoragePos> findPosListByMpn(List<String> storageIdList, String mpn, Collection<String> excludePosIds, CHECKOUT_TYPE checkOutType, Map<String, String> appendData) {
Criteria c = Criteria.where("id").nin(excludePosIds)
.and("enabled").is(true)//可用
.and("barcode.lockId").is(null);//没有被锁定的仓位;
if (storageIdList != null) {
c = c.and("storageId").in(storageIdList);
}
if (appendData != null) {
c = addAppendData(c, appendData);
}
List<Criteria> orCriterialList = Lists.newArrayList();
orCriterialList.add(Criteria.where("barcode.mpn").is(mpn));
orCriterialList.add(Criteria.where("barcode.subCodeList.mpn").is(mpn));
c.orOperator(orCriterialList);
Query q = new Query(c);
Sort sort = getSortByCheckOutType(checkOutType);
q.with(sort);
return storagePosDao.findByQuery(q);
}
}
......@@ -171,6 +171,9 @@ public class DevicesStatusUtil {
// return statusBean;
// }
//缓存信息
private static Map<String, List<MsgInfo>> cacheMsgMap = Maps.newConcurrentMap();
/**
* 更新客户端发上来的消息(设备故障等消息)
*/
......@@ -195,6 +198,38 @@ public class DevicesStatusUtil {
}
}
if (newMsg) {
List<MsgInfo> cacheMsgList = cacheMsgMap.get(cid);
if (cacheMsgList == null || cacheMsgList.isEmpty()) {
cacheMsgList = new ArrayList<>();
}
List<MsgInfo> newCacheList = new ArrayList<>();
for (MsgInfo msgInfo : cacheMsgList) {
if (System.currentTimeMillis() - msgInfo.getLastReceiveTime() > 1000 * 60 * 5) {
continue;
}
String msgKey = msg.getMsgKey();
String msgStr = msg.getMsg();
if (StringUtils.isNotEmpty(msgKey)) {
if (msgKey.equals(msgInfo.getMsgKey())) {
newMsg = false;
msgInfo.setLastReceiveTime(System.currentTimeMillis());
}
}
if (StringUtils.isNotEmpty(msgStr)) {
if (msgStr.equals(msgInfo.getMsg())) {
newMsg = false;
msgInfo.setLastReceiveTime(System.currentTimeMillis());
}
}
newCacheList.add(msgInfo);
}
if (newMsg){
newCacheList.add(msg);
}
cacheMsgMap.put(cid, newCacheList);
}
if (newMsg) {
String msgType= msg.getType();
if(ObjectUtil.isEmpty(msgType)){
msgType=MessageType.ERROR.name();
......
......@@ -272,6 +272,7 @@ public class TaskService {
task.setUpdateDate(new Date());
updateFinishedTask(task);
log.info("任务[" + task.getId() + "] posName[" + task.getPosName() + "] Reel Id[" + task.getBarcode() + "]取消成功");
clearBarcodeAppenddata(task);
return true;
}
return false;
......@@ -1236,46 +1237,144 @@ public class TaskService {
CHECKOUT_TYPE checkoutType = dataCache.getCheckOutType();
List<String> availableStorageIds;
List<String> groupStorageId = SecurityUtils.getUserGroupStorageId();
if (groupStorageId != null && !groupStorageId.isEmpty()){
if (groupStorageId != null && !groupStorageId.isEmpty()) {
availableStorageIds = groupStorageId;
} else {
availableStorageIds = dataCache.getAvailableStorageIds();
}
List<String> needOutPosId = new ArrayList<>();
//其他出库模式一次性全部生成任务
for (TacticsOutDto item : tacticsOutDtos) {
log.info("开始执行策略出库[" + item.getPartNumber() + "] [" + item.getStorageId() + "] 盘数=" + item.getPlateNumber()+",数量="+item.getNeedNum());
log.info("开始执行策略出库[" + item.getPartNumber() + "] [" + item.getStorageId() + "] 盘数=" + item.getPlateNumber() + ",数量=" + item.getNeedNum());
String partNumber = item.getPartNumber();
int currNum=0;
int reelNum=0;
while (reelNum<item.getPlateNumber()||currNum<item.getNeedNum())
// for (int i = 1; i <= item.getPlateNumber(); i++) {
{ Collection<String> excludePosIds = excludePosIds();
StoragePos pos = null;
if (item.getStorageId() != null) {
String[] storageIds = new String[]{item.getStorageId()};
pos = storagePosManager.findPartNumberInStorages(Lists.newArrayList(storageIds), partNumber, excludePosIds, checkoutType);
} else {
pos = storagePosManager.findPartNumberInStorages(availableStorageIds, partNumber, excludePosIds, checkoutType);
int currNum = 0;
int reelNum = 0;
List<StoragePos> posList = null;
Collection<String> excludePosIds = excludePosIds();
if (item.getStorageId() != null) {
String[] storageIds = new String[]{item.getStorageId()};
posList = storagePosManager.findPosListByPartNumber(Lists.newArrayList(storageIds), partNumber, excludePosIds, checkoutType,null);
} else {
posList = storagePosManager.findPosListByPartNumber(availableStorageIds, partNumber, excludePosIds, checkoutType,null);
}
if (posList == null || posList.isEmpty()) {
log.error("策略出库[" + item.getPartNumber() + "] 未找到可以出库的物料[" + partNumber + "]");
} else {
//提取出来所有PartNumber信息
List<Barcode> barcodeList = new ArrayList<>();
for (StoragePos pos : posList) {
Barcode barcode = pos.getBarcode();
if (barcode != null) {
List<Barcode> subCodeList = barcode.getSubCodeList();
if (subCodeList != null && !subCodeList.isEmpty()) {
for (Barcode subCode : subCodeList) {
if (partNumber.equals(subCode.getPartNumber())) {
barcodeList.add(subCode);
}
}
} else {
barcodeList.add(barcode);
}
}
}
if (pos == null) {
log.error("策略出库[" + item.getPartNumber() + "] 未找到可以出库的物料[" + partNumber + "]");
barcodeList = barcodeListByCheckOutType(checkoutType, barcodeList);
//开始循环处理数据
while (reelNum < item.getPlateNumber() || currNum < item.getNeedNum()) {
for (Barcode barcode : barcodeList) {
if (reelNum >= item.getPlateNumber() && currNum >= item.getNeedNum()) {
break;
}
String posName = barcode.getPosName();
if (StringUtils.isEmpty(posName)) {
continue;
}
String hostBarcodeId = barcode.getHostBarcodeId();
if (StringUtils.isEmpty(hostBarcodeId)) {
StoragePos pos = storagePosManager.getByBarcode(barcode.getBarcode());
if (pos != null) {
currNum += pos.getBarcode().getAmount();
reelNum += 1;
log.info("策略出库,PN[" + item.getPartNumber() + "]第[" + reelNum + "]盘, 出库位置仓位【" + pos.getPosName() + "】RI=[" + pos.getBarcode().getBarcode() + "] PN=[" + partNumber + "] num:" + pos.getBarcode().getAmount() + ",累计数量:" + currNum);
DataLog task = newTask(pos);
task.setType(OP.CHECKOUT);
task.setOperator(SecurityUtils.getCurrentUsername());
task.setSingleOut(true);
task.setSourceId(null);
task.setSourceName("PN");
addTaskToExecute(task);
}
} else {
StoragePos pos = storagePosManager.getByBarcodeId(hostBarcodeId);
if (pos != null) {
Barcode posBarcode = pos.getBarcode();
if (posBarcode != null) {
Barcode subCode = posBarcode.getSubCodeByBarcode(barcode.getBarcode());
if (subCode != null) {
subCode.updateAppendData("awaiting", subCode.getAmount());
posBarcode.UpdateSubCode(subCode);
barcodeManager.save(subCode);
barcodeManager.save(posBarcode);
pos.setBarcode(posBarcode);
storagePosManager.save(pos);
needOutPosId.add(pos.getId());
currNum += subCode.getAmount();
reelNum += 1;
}
}
}
}
}
//循环一遍没有找到合适的,直接跳过
break;
} else {
currNum+=pos.getBarcode().getAmount();
reelNum+=1;
log.info("策略出库,PN[" + item.getPartNumber() + "]第[" + reelNum + "]盘, 出库位置仓位【" + pos.getPosName() + "】RI=[" + pos.getBarcode().getBarcode() + "] PN=[" + partNumber + "] num:" + pos.getBarcode().getAmount()+",累计数量:"+currNum);
DataLog task = newTask(pos);
task.setType(OP.CHECKOUT);
task.setOperator(SecurityUtils.getCurrentUsername());
task.setSingleOut(true);
task.setSourceId(null);
task.setSourceName("PN");
addTaskToExecute(task);
}
}
}
if (needOutPosId != null && !needOutPosId.isEmpty()) {
needOutPosId = needOutPosId.stream().distinct().collect(Collectors.toList());
for (String posId : needOutPosId) {
StoragePos pos = storagePosManager.get(posId);
DataLog task = newTask(pos);
task.setType(OP.CHECKOUT);
task.setOperator(SecurityUtils.getCurrentUsername());
task.setSingleOut(true);
task.setSourceId(null);
task.setSourceName("PN");
addTaskToExecute(task);
}
}
}
public List<Barcode> barcodeListByCheckOutType(CHECKOUT_TYPE checkoutType, List<Barcode> barcodeList) {
//按时间进行排序
if (CHECKOUT_TYPE.EXPIRE_FIRST.equals(checkoutType)) {//先过期先出
barcodeList = barcodeList.stream().sorted(Comparator.comparing(Barcode::getExpireDate,Comparator.naturalOrder())
.thenComparing(Barcode::getPutInDate,Comparator.naturalOrder())).collect(Collectors.toList());
} else if (CHECKOUT_TYPE.FIFO.equals(checkoutType)) {//严格的先进先出
barcodeList = barcodeList.stream().sorted(Comparator.comparing(Barcode::getPutInDate,Comparator.naturalOrder())
.thenComparing(Barcode::getUsedCount)).collect(Collectors.toList());
} else if (CHECKOUT_TYPE.USED_FIRST.equals(checkoutType)) {//尾料优先
barcodeList = barcodeList.stream().sorted(Comparator.comparing(Barcode::getAmount)
.thenComparing(Barcode::getPutInDate,Comparator.naturalOrder())).collect(Collectors.toList());
} else if (CHECKOUT_TYPE.PRODUCE_DATE.equals(checkoutType)) {
barcodeList = barcodeList.stream().sorted(Comparator.comparing(Barcode::getProduceDate,Comparator.naturalOrder())
.thenComparing(Barcode::getAmount)
.thenComparing(Barcode::getPutInDate,Comparator.naturalOrder())).collect(Collectors.toList());
} else if (CHECKOUT_TYPE.BATCH_FIRST.equals(checkoutType)) {
barcodeList = barcodeList.stream().sorted(Comparator.comparing(Barcode::getBatch,Comparator.naturalOrder())
.thenComparing(Barcode::getProduceDate,Comparator.naturalOrder())
.thenComparing(Barcode::getAmount)
.thenComparing(Barcode::getPutInDate,Comparator.naturalOrder())).collect(Collectors.toList());
} else {//效率优先
barcodeList = barcodeList.stream().sorted(Comparator.comparing(Barcode::getPutInDate,Comparator.naturalOrder())
.thenComparing(Barcode::getCreateDate))
.collect(Collectors.toList());
}
return barcodeList;
}
public void moveTaskToFinished(DataLog task) {
......@@ -1303,4 +1402,36 @@ public class TaskService {
}
}
}
private void clearBarcodeAppenddata(DataLog dataLog) {
if (dataLog.isPutInTask()) {
return;
}
String barcodeStr = dataLog.getBarcode();
if (StringUtils.isNotEmpty(barcodeStr)) {
StoragePos pos = storagePosManager.getByBarcode(barcodeStr);
if (pos != null) {
Barcode barcode = pos.getBarcode();
if (barcode != null) {
List<Barcode> subCodeList = barcode.getSubCodeList();
if (subCodeList != null && !subCodeList.isEmpty()){
for (Barcode subCode : subCodeList) {
Integer awaiting = subCode.getAppendData("awaiting");
if (awaiting != null) {
subCode.updateAppendData("orderItemId", null);
subCode.updateAppendData("orderNo", null);
subCode.updateAppendData("orderId", null);
subCode.updateAppendData("awaiting", null);
barcodeManager.save(subCode);
barcode.UpdateSubCode(subCode);
barcodeManager.save(barcode);
pos.setBarcode(barcode);
storagePosManager.save(pos);
}
}
}
}
}
}
}
}
......@@ -8,6 +8,7 @@ import com.neotel.smfcore.common.utils.StringUtils;
import com.neotel.smfcore.core.barcode.bean.CodeBean;
import com.neotel.smfcore.core.barcode.enums.BARCODE_SOURCE;
import com.neotel.smfcore.core.barcode.enums.COMPONENT_TYPE;
import com.neotel.smfcore.core.barcode.rest.bean.dto.BarcodeDto;
import com.neotel.smfcore.core.barcode.rest.bean.mapstruct.BarcodeMapper;
import com.neotel.smfcore.core.barcode.service.manager.IBarcodeManager;
import com.neotel.smfcore.core.barcode.service.manager.IComponentManager;
......@@ -24,7 +25,7 @@ import com.neotel.smfcore.core.system.rest.bean.mapstruct.TaskMapper;
import com.neotel.smfcore.core.system.service.manager.IDataLogManager;
import com.neotel.smfcore.core.system.service.po.DataLog;
import com.neotel.smfcore.core.system.util.TaskService;
import com.neotel.smfcore.security.annotation.AnonymousAccess;
import com.neotel.smfcore.core.virtual.util.ShortUniqueCodeUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
......@@ -37,7 +38,6 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
......@@ -74,204 +74,243 @@ public class VirtualOperateController {
@Autowired
private TaskMapper taskMapper;
@ApiOperation("查询料盒信息")
@PostMapping("/materialBox")
//@PreAuthorize("@el.check('materialBox')")
public BarcodeDto manualOut(@RequestBody String code) {
// String code = paramMap.get("barcode");
CodeBean codeBean = new CodeBean();
try {
codeBean = codeResolve.resolveSingleCode(code.trim(), COMPONENT_TYPE.FIXTURE);
} catch (ValidateException e) {
codeBean.setError(e.getMessage());
}
if (codeBean == null || codeBean.getBarcode() == null) {
throw new ValidateException("smfcore.error.barcode.invalid", "未找到有效的条码");
}
if (codeBean.getErrorCode() != null) {
throw new ValidateException(codeBean.getErrorCode(), codeBean.getError(), codeBean.getParams());
}
List<BarcodeDto> codeDtos = new ArrayList<BarcodeDto>();
Barcode barcode = codeBean.getBarcode();
//此处需要判断是否是料盒
Component component=componentManager.findOneByPN(barcode.getPartNumber() );
if(component==null||(component.getType()!=COMPONENT_TYPE.FIXTURE)){
throw new ValidateException("smfcore.materialBox.invalid", "未找到料盒信息{0}", new String[]{code});
}
//判断是否有任务,有任务直接完成,不清空库存信息
DataLog dataLog = null;
List<DataLog> allTasks = taskService.getAllTasks();
for (DataLog task : allTasks) {
if (task.isCheckOutTask() && !task.isFinished() && !task.isCancel()) {
if (barcode.getBarcode().equals(task.getBarcode())){
dataLog = task;
break;
}
}
}
if (dataLog != null){
dataLog.setStatus(OP_STATUS.FINISHED.name());
taskService.removeQueueTask(dataLog);
taskService.updateFinishedTask(dataLog);
}
BarcodeDto barcodeDto=barcodeMapper.toDto(barcode);
// if(barcodeDto.getSubCodeMap()==null){
// barcodeDto.setSubCodeMap(new HashMap<>());
// }
if(barcodeDto.getSubCodeList()==null){
barcodeDto.setSubCodeList(new ArrayList<>());
}
return barcodeDto;
}
@ApiOperation("扫描条码返回具体的信息")
@RequestMapping("/scanReelPutIn")
@AnonymousAccess
public ResultBean scanPutInReel(@RequestBody Map<String, String> paramMap) {
@ApiOperation("(唯一码)物料放入料盒中")
@PostMapping(value = "/reelToBox")
//@AnonymousAccess
public ResultBean reelToBox(@RequestBody Map<String, String> paramMap) {
String code = paramMap.get("barcode");//料盒条码
String operageStr = paramMap.get("operatePN");//操作信息
//判断条码是否存在
Barcode barcode = codeResolve.resolveOneValideBarcode(code);
log.info("收到物料放入料箱,boxStr:" + code + ",operageStr:" + operageStr);
//判断料箱是否存在
Barcode barcode = barcodeManager.findByBarcode(code);
if (barcode == null) {
throw new ValidateException("smfcore.error.barcode.invalid", "{0}不是有效的条码", new String[]{code});
}
Map<String, Object> resultMap = new HashMap<>();
//判断是不是按料号进行入库
//判断是否在库位中
StoragePos pos = storagePosManager.getByBarcode(barcode.getBarcode());
if (pos != null) {
barcode = pos.getBarcode();
}
//如果物料编码存在,则按物料编码进行入库
Component component = componentManager.findOneByPN(operageStr);
if (component != null) {
resultMap.put("type", "pn");
resultMap.put("partNumber", operageStr);
return ResultBean.newOkResult(resultMap);
ResultBean resultBean = ResultBean.newOkResult(operageStr);
resultBean.setCode(99);
return resultBean;
}
//解析物料信息
//如果解析失败,则按物料编码进行入库
String newCodeStr = "=1x1=" + operageStr;
CodeBean codeBean = codeResolve.resolveSingleCode(newCodeStr);
if (!codeBean.isValid()) {
resultMap.put("type", "pn");
resultMap.put("partNumber", operageStr);
return ResultBean.newOkResult(resultMap);
ResultBean resultBean = ResultBean.newOkResult(operageStr);
resultBean.setCode(99);
return resultBean;
}
//判断是否存在其他料箱中
Barcode subCode = codeBean.getBarcode();
//判断是否存在其他料盒中
String hostBarcodeId = subCode.getHostBarcodeId();
if (StringUtils.isNotEmpty(hostBarcodeId)) {
if (!hostBarcodeId.equals(barcode.getId())) {
throw new ValidateException("smfcore.materialBox.inOtherBox", "物料已在料盒{0}中", new String[]{barcode.getBarcode()});
Barcode hostBarcode = barcodeManager.get(hostBarcodeId);
if (hostBarcode != null) {
throw new ValidateException("smfcore.materialBox.inOtherBox", "物料已在料盒{0}中", new String[]{hostBarcode.getBarcode()});
}
}
}
//如果是物料信息,返回ri
resultMap.put("type", "ri");
resultMap.put("amount", subCode.getAmount());
return ResultBean.newOkResult(resultMap);
//判断库位是否为空
String posName = subCode.getPosName();
if (StringUtils.isNotEmpty(posName)) {
throw new ValidateException("smfcore.materialBox.inPos", "物料已在库位{0}中", new String[]{posName});
}
subCode.setHostBarcodeId(barcode.getId());
subCode.setPosName(barcode.getBarcode());
subCode.setPutInTime(System.currentTimeMillis());
barcodeManager.saveBarcode(subCode);
barcode = finishTask(barcode, OP.PUT_IN, subCode, subCode.getAmount(), OP_STATUS.FINISHED.name(), subCode.getAmount());
log.info("条码" + subCode.getBarcode() + "[" + subCode.getPartNumber() + "]入库到料盒[" + barcode.getBarcode() + "]数量:" + barcode.getAmount());
//如果在库位中,则同步更新库位信息
if (pos != null) {
pos.setBarcode(barcode);
storagePosManager.save(pos);
Storage storage = dataCache.getStorageById(pos.getStorageId());
dataCache.addUsedPosList(storage.getCid(),pos);
dataCache.updateInventoryAmount(storage.getCid(),subCode.getPartNumber(),subCode.getAmount(),subCode.getBarcode());
}
return ResultBean.newOkResult(barcodeMapper.toDto(barcode));
}
@ApiOperation("物料放入料盒中")
@PostMapping(value = "/reelToBox")
@ApiOperation("(物料编码)物料放入料盒中")
@PostMapping(value = "/partNumberToBox")
//@AnonymousAccess
public ResultBean reelToBox(@RequestBody Map<String, String> paramMap) {
public ResultBean partNumberToBox(@RequestBody Map<String, String> paramMap) {
String code = paramMap.get("barcode");//料盒条码
String operageStr = paramMap.get("operatePN");//操作信息
String putInType = paramMap.get("putInType"); //判断是ri还是pn入库
String reelType = paramMap.get("reelType");
String amountStr = paramMap.get("amount");
log.info("收到物料放入料箱,boxStr:" + code
+ ",operageStr:" + operageStr
+ ",putInType:" + putInType
+ ",reelType:" + reelType
+ ",amountStr=" + amountStr);
String amountStr = paramMap.get("amount"); //数量
log.info("收到物料放入料箱,boxStr:" + code + ",operageStr:" + operageStr + ",amountStr=" + amountStr);
//判断料箱是否存在
Barcode barcode = barcodeManager.findByBarcode(code);
if (barcode == null) {
throw new ValidateException("smfcore.error.barcode.invalid", "{0}不是有效的条码", new String[]{code});
}
//判断是否在库位中
StoragePos pos = storagePosManager.getByBarcode(barcode.getBarcode());
if (pos != null) {
barcode = pos.getBarcode();
}
//判断数量是否为正确的
int opQty = Integer.valueOf(amountStr);
int opType = OP.NON_OP;
if (opQty > 0) {
opType = OP.PUT_IN;
} else {
if (opQty <= 0) {
throw new ValidateException("smfcore.materialBox.qtyError", "请输入正确的数量");
}
if ("pn".equals(putInType)) {
Barcode subBarcode = barcode.getSubCode(operageStr);
if (subBarcode == null) {
Component component = autoGetComponent(operageStr, opQty);
subBarcode = autoGetBarcode(barcode, component, operageStr, opQty);
} else {
int oldAmount = subBarcode.getAmount();
subBarcode.setHostBarcodeId(barcode.getId());
subBarcode.setAmount(oldAmount + opQty);
}
subBarcode.setPutInTime(System.currentTimeMillis());
subBarcode = barcodeManager.save(subBarcode);
barcode = finishTask(barcode, opType, subBarcode, opQty,OP_STATUS.FINISHED.name());
log.info("条码" + subBarcode.getBarcode() + "[" + subBarcode.getPartNumber() + "]入库到料盒[" + barcode.getBarcode() + "]数量:" + barcode.getAmount());
} else if ("ri".equals(putInType)) {
//解析条码
Barcode subCode = codeResolve.resolveOneValideBarcode("=1x1="+operageStr);
if (subCode == null) {
throw new ValidateException("smfcore.error.barcode.invalid", "{0}不是有效的条码", new String[]{operageStr});
}
String hostBarcodeId = subCode.getHostBarcodeId();
if (StringUtils.isNotEmpty(hostBarcodeId)) {
if (!hostBarcodeId.equals(barcode.getId())) {
Barcode hostBarcode = barcodeManager.get(hostBarcodeId);
if (hostBarcode != null) {
throw new ValidateException("smfcore.materialBox.inOtherBox", "物料已在料盒{0}中", new String[]{hostBarcode.getBarcode()});
}
}
}
//判断物料是否存在料箱中
String posName = subCode.getPosName();
if (StringUtils.isNotEmpty(posName)) {
throw new ValidateException("smfcore.materialBox.inPos", "物料已在库位{0}中", new String[]{posName});
}
subCode.setHostBarcodeId(barcode.getId());
subCode.setAmount(opQty);
subCode.setPutInTime(System.currentTimeMillis());
barcodeManager.saveBarcode(subCode);
barcode = finishTask(barcode, opType, subCode, opQty,OP_STATUS.FINISHED.name());
log.info("条码" + subCode.getBarcode() + "[" + subCode.getPartNumber() + "]入库到料盒[" + barcode.getBarcode() + "]数量:" + barcode.getAmount());
//不进行合并,每次入库都是新的唯一码
Component component = autoGetComponent(operageStr, opQty);
Barcode subBarcode = autoGetBarcode(barcode, component, operageStr, opQty);
subBarcode.setHostBarcodeId(barcode.getId());
subBarcode.setPosName(barcode.getBarcode());
subBarcode.setPutInTime(System.currentTimeMillis());
subBarcode = barcodeManager.save(subBarcode);
barcode = finishTask(barcode, OP.PUT_IN, subBarcode, opQty, OP_STATUS.FINISHED.name(), subBarcode.getAmount());
log.info("条码" + subBarcode.getBarcode() + "[" + subBarcode.getPartNumber() + "]入库到料盒[" + barcode.getBarcode() + "]数量:" + barcode.getAmount());
if (pos != null) {
pos.setBarcode(barcode);
storagePosManager.save(pos);
Storage storage = dataCache.getStorageById(pos.getStorageId());
dataCache.addUsedPosList(storage.getCid(),pos);
dataCache.updateInventoryAmount(storage.getCid(),subBarcode.getPartNumber(),subBarcode.getAmount(),subBarcode.getBarcode());
}
return ResultBean.newOkResult(barcodeMapper.toDto(barcode));
}
@ApiOperation("物料从料盒中取出")
@ApiOperation("物料从料盒中取出(唯一码出库)")
@PostMapping(value = "/reelFromBox")
//@AnonymousAccess
public ResultBean reelFromBox(@RequestBody Map<String, String> paramMap) {
String code = paramMap.get("barcode");//料盒条码
String operageStr = paramMap.get("operatePN");//操作信息
String checkOutType = paramMap.get("checkOutType");
String amountStr = paramMap.get("amount");
String type = paramMap.get("type");
if ("pn".equals(type)){
if (StringUtils.isEmpty(amountStr)){
throw new ValidateException("smfcore.materialBox.qtyError", "请输入正确的数量");
}
}
//判断料箱是不是有效的参数
Barcode barcode = barcodeManager.findByBarcode(code);
if (barcode == null) {
throw new ValidateException("smfcore.error.barcode.invalid", "{0}不是有效的条码", new String[]{code});
}
//判断是否在库位中
String posName = barcode.getPosName();
if (StringUtils.isNotEmpty(posName)) {
throw new ValidateException("smfcore.virtual.boxInPos", "[{0}]已在库位[{1}]中,请先取出", new String[]{barcode.getBarcode(), posName});
//判断是否在库位中
StoragePos pos = storagePosManager.getByBarcode(barcode.getBarcode());
if (pos != null) {
barcode = pos.getBarcode();
}
int opQty = Integer.valueOf(amountStr);
int opType = OP.NON_OP;
if (opQty > 0) {
opType = OP.CHECKOUT;
} else {
//请输入正确的数量
//判断输入的条码是否正确
CodeBean codeBean = codeResolve.resolveSingleCode("=1x1=" + operageStr);
if (!codeBean.isValid()) {
throw new ValidateException("smfcore.error.barcode.invalid", "{0}不是有效的条码", new String[]{operageStr});
}
Barcode subBarcode = codeBean.getBarcode();
int opQty = subBarcode.getAmount();
if (StringUtils.isNotEmpty(amountStr)) {
opQty = Integer.valueOf(amountStr);
}
if (opQty <= 0) {
throw new ValidateException("smfcore.materialBox.qtyError", "请输入正确的数量");
}
//判断是pn还是ri出
if ("pn".equals(checkOutType)) {
//查看该库位中是否有相同的物料,有的话,数量累加
Barcode subBarcode = barcode.getSubCode(operageStr);
if (subBarcode == null) {
throw new ValidateException("smfcore.materialBox.noReel", "料盒中未找到对应物料");
}
int oldAmount = subBarcode.getAmount();
if (oldAmount < opQty) {
throw new ValidateException("smfcore.materialBox.quantityshort", "物料数量不足");
}
Integer awaitingNum = subBarcode.getAppendData("awaiting");
if (awaitingNum != null) {
if (opQty < awaitingNum) {
throw new ValidateException("smfcore.virtual.quantityError", "取出数量应为[{0}]",new String[]{awaitingNum+""});
}
}
int newAmount = oldAmount - opQty;
subBarcode.setHostBarcodeId(barcode.getId());
subBarcode.setAmount(newAmount);
subBarcode = barcodeManager.save(subBarcode);
barcode = finishTask(barcode, opType, subBarcode, opQty,OP_STATUS.FINISHED.name());
log.info(subBarcode.getPartNumber() + "从料盒[" + barcode.getPosName() + "]出库,物料数量:" + oldAmount + " - " + opQty + " = " + newAmount);
} else if ("ri".equals(checkOutType)) {
CodeBean codeBean = codeResolve.resolveSingleCode("=1x1="+operageStr);
if (!codeBean.isValid()) {
throw new ValidateException("smfcore.error.barcode.invalid", "{0}不是有效的条码", new String[]{operageStr});
}
//判断是否在此料箱中
Barcode subBarcode = codeBean.getBarcode();
String hostBarcodeId = subBarcode.getHostBarcodeId();
if (StringUtils.isEmpty(hostBarcodeId)) {
throw new ValidateException("smfcore.materialBox.noReel", "料盒中未找到对应物料");
}
if (!hostBarcodeId.equals(barcode.getId())) {
Barcode hostBarcode = barcodeManager.get(hostBarcodeId);
if (hostBarcode != null) {
throw new ValidateException("smfcore.materialBox.inOtherBox", "物料已在料盒{0}中", new String[]{hostBarcode.getBarcode()});
}
}
int qty = subBarcode.getAmount() - opQty;
if (qty < 0) {
qty = 0;
//判断是否在此料箱中
String hostBarcodeId = subBarcode.getHostBarcodeId();
if (StringUtils.isEmpty(hostBarcodeId)) {
throw new ValidateException("smfcore.materialBox.noReel", "料盒中未找到对应物料");
}
if (!hostBarcodeId.equals(barcode.getId())) {
Barcode hostBarcode = barcodeManager.get(hostBarcodeId);
if (hostBarcode != null) {
throw new ValidateException("smfcore.materialBox.inOtherBox", "物料已在料盒{0}中", new String[]{hostBarcode.getBarcode()});
}
Integer awaitingNum = subBarcode.getAppendData("awaiting");
if (awaitingNum != null) {
if (opQty < awaitingNum) {
throw new ValidateException("smfcore.virtual.quantityError", "取出数量应为[{0}]",new String[]{awaitingNum+""});
}
}
int amount = subBarcode.getAmount();
int qty = amount - opQty;
if (qty < 0) {
qty = 0;
}
Integer awaitingNum = subBarcode.getAppendData("awaiting");
if (awaitingNum != null) {
if (opQty < awaitingNum) {
throw new ValidateException("smfcore.virtual.quantityError", "取出数量应为[{0}]", new String[]{awaitingNum + ""});
}
//出库
subBarcode.setAmount(qty);
subBarcode = barcodeManager.save(subBarcode);
finishTask(barcode, OP.CHECKOUT, subBarcode, opQty,OP_STATUS.FINISHED.name());
log.info("条码" + subBarcode.getBarcode() + "[" + subBarcode.getPartNumber() + "]从料盒[" + barcode.getBarcode() + "]出库,数量:" + qty);
}
//出库
subBarcode.setAmount(qty);
subBarcode = barcodeManager.save(subBarcode);
barcode = finishTask(barcode, OP.CHECKOUT, subBarcode, opQty, OP_STATUS.FINISHED.name(), amount);
log.info("条码" + subBarcode.getBarcode() + "[" + subBarcode.getPartNumber() + "]从料盒[" + barcode.getBarcode() + "]出库,数量:" + qty);
if (pos != null) {
pos.setBarcode(barcode);
storagePosManager.save(pos);
Storage storage = dataCache.getStorageById(pos.getStorageId());
dataCache.addUsedPosList(storage.getCid(),pos);
dataCache.updateInventoryAmount(storage.getCid(), subBarcode.getPartNumber(), -opQty, subBarcode.getBarcode());
}
return ResultBean.newOkResult("");
}
......@@ -285,7 +324,7 @@ public class VirtualOperateController {
String describe = paramMap.get("describe");
//判断料箱是否存在
Barcode barcode = codeResolve.resolveOneValideBarcode("=1x1="+boxStr);
Barcode barcode = codeResolve.resolveOneValideBarcode("=1x1=" + boxStr);
if (barcode == null) {
throw new ValidateException("smfcore.error.barcode.invalid", "{0}不是有效的条码", new String[]{boxStr});
}
......@@ -293,6 +332,13 @@ public class VirtualOperateController {
if (StringUtils.isNotEmpty(barcode.getPosName())) {
throw new ValidateException("smfcore.materialBox.inPos", "物料已在库位{0}中", new String[]{barcode.getPosName()});
}
String hostBarcodeId = barcode.getHostBarcodeId();
if (StringUtils.isNotEmpty(hostBarcodeId)) {
Barcode hostBarcode = barcodeManager.get(hostBarcodeId);
if (hostBarcode != null) {
throw new ValidateException("smfcore.materialBox.inOtherBox", "物料已在料盒{0}中", new String[]{hostBarcode.getBarcode()});
}
}
//判断库位是否存在
StoragePos pos = storagePosManager.getByPosName(posNameStr);
if (pos == null) {
......@@ -307,20 +353,28 @@ public class VirtualOperateController {
if (!storage.isVirtual()) {
throw new ValidateException("smfcore.pos.noVirtual", "[{0}]不是虚拟仓的库位", new String[]{posNameStr});
}
barcode.setDescribe(describe);
barcode.setMemo(describe);
List<Barcode> subCodeList = barcode.getSubCodeList();
if (subCodeList != null && !subCodeList.isEmpty()) {
for (Barcode subCode : subCodeList) {
Integer awaiting = subCode.getAppendData("awaiting");
if (awaiting != null) {
barcode = finishTask(barcode, OP.CHECKOUT, subCode, awaiting, OP_STATUS.CANCEL.name());
barcode = finishTask(barcode, OP.CHECKOUT, subCode, awaiting, OP_STATUS.CANCEL.name(), subCode.getAmount());
}
}
}
//开始入库
taskService.addTaskToFinished(pos, barcode, SecurityUtils.getLoginUsername());
//同时更新subCode的缓存信息
if (subCodeList != null && !subCodeList.isEmpty()) {
for (Barcode subCode : subCodeList) {
dataCache.updateInventoryAmount(storage.getCid(),subCode.getPartNumber(),subCode.getAmount(),subCode.getBarcode());
}
}
return ResultBean.newOkResult("");
}
......@@ -330,7 +384,7 @@ public class VirtualOperateController {
public ResultBean boxOutFromPosName(@RequestBody Map<String, String> paramMap) {
String boxStr = paramMap.get("boxStr");
//判断料箱是否存在
Barcode barcode = codeResolve.resolveOneValideBarcode("=1x1="+boxStr);
Barcode barcode = codeResolve.resolveOneValideBarcode("=1x1=" + boxStr);
if (barcode == null) {
throw new ValidateException("smfcore.error.barcode.invalid", "{0}不是有效的条码", new String[]{boxStr});
}
......@@ -340,45 +394,19 @@ public class VirtualOperateController {
throw new ValidateException("smfcore.virtual.posNoBarcode", "[{0}]不在库位中", new String[]{barcode.getBarcode()});
}
Storage storage = dataCache.getStorageById(pos.getStorageId());
if (!storage.isVirtual()){
throw new ValidateException("smfcore.virtual.barcodeNotExistVirtualPos", "[{0}]库位为[{1}],不属于虚拟仓库位", new String[]{barcode.getBarcode(),pos.getPosName()});
if (!storage.isVirtual()) {
throw new ValidateException("smfcore.virtual.barcodeNotExistVirtualPos", "[{0}]库位为[{1}],不属于虚拟仓库位", new String[]{barcode.getBarcode(), pos.getPosName()});
}
//开始入库
taskService.addTaskToFinished(pos, barcode, SecurityUtils.getLoginUsername());
return ResultBean.newOkResult("");
}
@ApiOperation("取出物料")
@PostMapping("exeOut")
//@PreAuthorize("@el.check('materialBox')")
public ResultBean exeOut(@RequestBody Map<String, String> paramMap) {
String code = paramMap.get("barcode");//料盒条码
String subPN = paramMap.get("subPN");//物料条码
String qtyStr = paramMap.get("qty");//数量
Barcode barcode = barcodeManager.findByBarcode(code);
if (barcode == null) {
throw new ValidateException("smfcore.error.barcode.invalid", "{0}不是有效的条码", new String[]{code});
}
Barcode subBarcode = barcode.getSubCode(subPN);
if (subBarcode == null) {
throw new ValidateException("smfcore.materialBox.noReel", "料盒中未找到对应物料");
}
int opQty = Integer.valueOf(qtyStr);
int oldAmount = subBarcode.getAmount();
if (oldAmount < opQty) {
throw new ValidateException("smfcore.materialBox.quantityshort", "物料数量不足");
dataCache.addUsedPosList(storage.getCid(),pos);
//同时更新subCode的缓存信息
List<Barcode> subCodeList = barcode.getSubCodeList();
if (subCodeList != null && !subCodeList.isEmpty()) {
for (Barcode subCode : subCodeList) {
dataCache.updateInventoryAmount(storage.getCid(),subCode.getPartNumber(),-subCode.getAmount(),subCode.getBarcode());
}
}
int newAmount = oldAmount - opQty;
subBarcode.setAmount(newAmount);
subBarcode = barcodeManager.save(subBarcode);
finishTask(barcode, OP.CHECKOUT, subBarcode, opQty,OP_STATUS.FINISHED.name());
log.info(subBarcode.getPartNumber() + "从料盒[" + barcode.getPosName() + "]出库,物料数量:" + oldAmount + " - " + opQty + " = " + newAmount);
return ResultBean.newOkResult("");
}
......@@ -431,12 +459,12 @@ public class VirtualOperateController {
if (storagePosList != null && !storagePosList.isEmpty()) {
for (StoragePos pos : storagePosList) {
Barcode barcode = pos.getBarcode();
if (barcode != null){
if (barcode != null) {
//COMPONENT_TYPE.FIXTURE 为料箱数据
if (barcode.getType() == COMPONENT_TYPE.FIXTURE){
boxCount ++;
if (barcode.getType() == COMPONENT_TYPE.FIXTURE) {
boxCount++;
} else {
reelCount ++;
reelCount++;
}
}
}
......@@ -444,30 +472,30 @@ public class VirtualOperateController {
//获取到进入出入库数据
Date startDate = DateUtil.addDaysFromToday(0);
Date endDate = DateUtil.addDays(startDate,1);
c = Criteria.where("createDate").gte(startDate).lt(endDate).and("status").in(OP_STATUS.FINISHED.name(),OP_STATUS.END.name());
Date endDate = DateUtil.addDays(startDate, 1);
c = Criteria.where("createDate").gte(startDate).lt(endDate).and("status").in(OP_STATUS.FINISHED.name(), OP_STATUS.END.name());
q = new Query(c);
q.fields().include("storageId","sourceType");
q.fields().include("storageId", "sourceType", "type");
List<DataLog> dataLogList = dataLogManager.findByQuery(q);
if (dataLogList != null && !dataLogList.isEmpty()){
if (dataLogList != null && !dataLogList.isEmpty()) {
for (DataLog dataLog : dataLogList) {
String storageId = dataLog.getStorageId();
if (StringUtils.isNotEmpty(storageId)){
if (StringUtils.isNotEmpty(storageId)) {
Storage storage = dataCache.getStorageById(storageId);
if (storage.isVirtual()) {
if (dataLog.isCheckOutTask()){
todayOutCount ++;
if (dataLog.isCheckOutTask()) {
todayOutCount++;
} else {
todayInCount ++;
todayInCount++;
}
continue;
}
}
if (BARCODE_SOURCE.VIRTUAL.equals(dataLog.getSourceType())){
if (dataLog.isCheckOutTask()){
todayOutCount ++;
if (BARCODE_SOURCE.VIRTUAL.equals(dataLog.getSourceType())) {
if (dataLog.isCheckOutTask()) {
todayOutCount++;
} else {
todayInCount ++;
todayInCount++;
}
}
}
......@@ -480,31 +508,45 @@ public class VirtualOperateController {
return ResultBean.newOkResult(resultMap);
}
/**
/**
* 完成出入库任务
*
* @param pidBarcode 料箱
* @param subBarcode 箱内物料
* @param opQty 数量
* @throws ValidateException*/
* @param opQty 数量
* @throws ValidateException
*/
private Barcode finishTask(Barcode pidBarcode, int opType, Barcode subBarcode, int opQty,String status) throws ValidateException {
private Barcode finishTask(Barcode pidBarcode, int opType, Barcode subBarcode, int opQty, String status, int amount) throws ValidateException {
String orderItemId = subBarcode.getAppendData("orderItemId");
String orderNo = subBarcode.getAppendData("orderNo");
String orderId = subBarcode.getAppendData("orderId");
subBarcode.updateAppendData("orderItemId",null);
subBarcode.updateAppendData("orderNo",null);
subBarcode.updateAppendData("orderId",null);
subBarcode.updateAppendData("awaiting",null);
subBarcode.updateAppendData("orderItemId", null);
subBarcode.updateAppendData("orderNo", null);
subBarcode.updateAppendData("orderId", null);
subBarcode.updateAppendData("awaiting", null);
barcodeManager.save(subBarcode);
//更新barcode缓存
pidBarcode.UpdateSubCode(subBarcode);
if (opType == OP.CHECKOUT && subBarcode.getAmount() <= 0) {
if (subBarcode.getAmount() <= 0) {
if (subBarcode.isAutoCreate()){
barcodeManager.delete(subBarcode);
} else {
subBarcode.setHostBarcodeId("");
subBarcode.setPosName("");
subBarcode.setAmount(amount);
barcodeManager.save(subBarcode);
}
}
/*if (opType == OP.CHECKOUT && subBarcode.getAmount() <= 0) {
//数量为0直接删除
barcodeManager.delete(subBarcode);
}
}*/
barcodeManager.saveBarcode(pidBarcode);
DataLog task = new DataLog();
task.setStatus(status);
......@@ -520,24 +562,25 @@ public class VirtualOperateController {
task.setPosName(pidBarcode.getBarcode());
task.setOperator(SecurityUtils.getLoginUsername());
task.setSourceType(BARCODE_SOURCE.VIRTUAL);
if (StringUtils.isNotEmpty(orderItemId)){
if (StringUtils.isNotEmpty(orderItemId)) {
task.setSubSourceId(orderItemId);
}
if (StringUtils.isNotEmpty(orderNo)){
if (StringUtils.isNotEmpty(orderNo)) {
task.setSourceName(orderNo);
}
if (StringUtils.isNotEmpty(orderId)){
if (StringUtils.isNotEmpty(orderId)) {
task.setSourceId(orderId);
}
task = dataLogManager.save(task);
taskService.updateFinishedTask(task);
//dataCache.updateInventoryAmount(getVirtialCid(),task.getPartNumber(),opQty,task.getBarcode());
return pidBarcode;
}
private Barcode autoGetBarcode(Barcode barcode,Component component, String pnStr,int opQty){
private Barcode autoGetBarcode(Barcode barcode, Component component, String pnStr, int opQty) {
//条码设置为P+PosId+C+ComponentId
String barcodeStr = "P" + barcode.getId() + "C" + component.getId();
Barcode subBarcode = barcodeManager.findByBarcode(barcodeStr);
String barcodeStr = ShortUniqueCodeUtil.generate().toUpperCase(Locale.ROOT);
Barcode subBarcode = barcodeManager.findByBarcode(barcodeStr);
if (subBarcode == null) {
//不存在,需要创建条码和库位
subBarcode = new Barcode();
......@@ -552,13 +595,14 @@ public class VirtualOperateController {
subBarcode.updateSluggishTime(dataCache.getPNsluggishDay(barcode.getPartNumber()));
subBarcode.setCheckOutDate(null, "");
subBarcode.setHostBarcodeId(barcode.getId());
subBarcode.setAutoCreate(true);
subBarcode = barcodeManager.save(subBarcode);
return subBarcode;
}
private Component autoGetComponent(String pnStr,int opQty){
private Component autoGetComponent(String pnStr, int opQty) {
Component component = componentManager.findOneByPN(pnStr);
if(component == null){
if (component == null) {
component = new Component();
component.setHeight(1);
component.setPartNumber(pnStr);
......@@ -569,5 +613,4 @@ public class VirtualOperateController {
}
return component;
}
}
package com.neotel.smfcore.core.virtual.util;
import java.util.concurrent.atomic.AtomicInteger;
public class ShortUniqueCodeUtil {
// 使用36进制(0-9,a-z)可以表示更多组合
private static final int RADIX = 36;
// 最后时间戳和序列号
private static volatile long lastTimestamp = 0L;
private static final AtomicInteger sequence = new AtomicInteger(0);
// 序列号最大值(保留2位36进制数)
private static final int MAX_SEQUENCE = RADIX * RADIX;
/**
* 生成6位不重复的唯一码
*
* @return 6位36进制的唯一码(包含数字和小写字母)
*/
public static synchronized String generate() {
long currentTime = System.currentTimeMillis();
// 如果同一毫秒内,增加序列号
if (currentTime == lastTimestamp) {
int seq = sequence.incrementAndGet();
if (seq >= MAX_SEQUENCE) {
// 序列号用尽,等待到下一毫秒
while (currentTime <= lastTimestamp) {
currentTime = System.currentTimeMillis();
}
sequence.set(0);
}
} else {
sequence.set(0);
}
lastTimestamp = currentTime;
// 将时间戳和序列号转换为36进制字符串
String timePart = Long.toString(currentTime, RADIX);
String seqPart = String.format("%02d", sequence.get());
// 组合并确保长度为6
String fullCode = timePart + seqPart;
if (fullCode.length() > 6) {
fullCode = fullCode.substring(fullCode.length() - 6);
} else if (fullCode.length() < 6) {
fullCode = String.format("%6s", fullCode).replace(' ', '0');
}
return fullCode;
}
}
......@@ -182,8 +182,8 @@ public class FujiApi extends BaseSmfApiListener {
*/
public String getAccessToken() {
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("userName", FujiUrlConfig.userName);
paramMap.put("password", FujiUrlConfig.password);
paramMap.put("userName", getAuthUserName());
paramMap.put("password", getAuthPassword());
String paramStr = JSON.toJSONString(paramMap);
log.info("获取Fuji的token参数为:" + paramStr);
String accessToken = "";
......@@ -218,6 +218,22 @@ public class FujiApi extends BaseSmfApiListener {
return config.getAuthUrl();
}
private String getAuthUserName(){
FujiConfig config = dataCache.getCache(FujiCacheConfig.FujiConfig_Cache_Name);
if (config == null) {
config = new FujiConfig();
}
return config.getUserName();
}
private String getAuthPassword(){
FujiConfig config = dataCache.getCache(FujiCacheConfig.FujiConfig_Cache_Name);
if (config == null) {
config = new FujiConfig();
}
return config.getPassword();
}
private String getInventoryDids(){
FujiConfig config = dataCache.getCache(FujiCacheConfig.FujiConfig_Cache_Name);
if (config == null) {
......
......@@ -7,6 +7,8 @@ import java.util.Date;
@Data
public class FujiConfig {
private String authUrl = "";
private String userName = "";
private String password = "";
private String getDidInfoUrl = "";
private String registerDidInfoUrl = "";
private String result = "";
......
......@@ -7,9 +7,9 @@ public class FujiUrlConfig {
//private static final String baseUrl = "http://175.41.238.212/fujiopenwebapi/api/v1";
public static final String userName = "Neotel";
//public static final String userName = "Neotel";
public static final String password = "Neotel";
//public static final String password = "Neotel";
//private static final String authLogin = "/auth/login";
......
......@@ -62,6 +62,8 @@ public class FujiController {
config.setInputEto(newConfig.getInputEto());
config.setOutputEtn(newConfig.getOutputEtn());
config.setTime(newConfig.getTime());
config.setUserName(newConfig.getUserName());
config.setPassword(newConfig.getPassword());
dataCache.updateCache(FujiCacheConfig.FujiConfig_Cache_Name, config);
return ResultBean.newOkResult("");
}
......@@ -85,6 +87,8 @@ public class FujiController {
dto.setTime(config.getTime());
dto.setEtnUpdateDateStr(getUpdateDate(config.getOutputEtn()));
dto.setEtoUpdateDateStr(getUpdateDate(config.getInputEto()));
dto.setUserName(config.getUserName());
dto.setPassword(config.getPassword());
return ResultBean.newOkResult(dto);
}
......
......@@ -58,4 +58,9 @@ public class UserDto implements Serializable {
@ApiModelProperty("语言名称:简体中文,繁体中文 等")
private String lanName;
@ApiModelProperty("激活码")
private String checkCode;
@ApiModelProperty("是否启用")
private boolean active = false;
}
......@@ -238,6 +238,15 @@ public class UserManagerImpl implements IUserManager {
dtos.get(i).setRoleName(role.getName());
}
}
String username = dtos.get(i).getUsername();
String checkCode = dtos.get(i).getCheckCode();
if (Constants.SUPER_USERNAME.equals(username)){
dtos.get(i).setActive(true);
} else {
if (StringUtils.isNotEmpty(checkCode)){
dtos.get(i).setActive(true);
}
}
}
return dtos;
}
......
......@@ -433,4 +433,5 @@ smfcore.virtualLocationManager=\u865A\u62DF\u5E93\u4F4D\u7BA1\u7406
smfcore.virtualOperations=\u865A\u62DF\u4ED3\u64CD\u4F5C
smfcore.equipment.view.ncgroup=Neo Counter
smfcore.virtual.boxInPos=[{0}]\u5DF2\u5728\u5E93\u4F4D[{1}]\u4E2D,\u8BF7\u5148\u53D6\u51FA
smfcore.virtual.quantityError=\u53D6\u51FA\u6570\u91CF\u5E94\u4E3A[{0}]
\ No newline at end of file
smfcore.virtual.quantityError=\u53D6\u51FA\u6570\u91CF\u5E94\u4E3A[{0}]
smfcode.virtual.enter=\u8BF7\u626B\u63CF\u6216\u8F93\u5165\u6761\u7801\u540E\u6309\u56DE\u8F66\u786E\u8BA4
\ No newline at end of file
......@@ -423,4 +423,5 @@ smfcore.virtualLocationManager=Verwaltung virtueller Lagerpl\u00E4tze
smfcore.virtualOperations=Vorg\u00E4nge im virtuellen Lager
smfcore.equipment.view.ncgroup=Neo Counter
smfcore.virtual.boxInPos=[{0}] befindet sich bereits im Lagerplatz [{1}]. Bitte entnehmen Sie es zuerst
smfcore.virtual.quantityError=Die zu entnehmende Menge sollte [{0}] betragen
\ No newline at end of file
smfcore.virtual.quantityError=Die zu entnehmende Menge sollte [{0}] betragen
smfcode.virtual.enter=Bitte scannen Sie den Barcode oder geben Sie ihn ein und best\u00E4tigen Sie mit Enter
\ No newline at end of file
......@@ -146,7 +146,7 @@ smfcore.translation=Resource Translation
smfcore.languageCanotNull=Language type cannot be empty
smfcore.noLanguageSetAccess=No permission to edit the language
smfcore.languageCanotRemoveAll=Cannot delete all languages
smfcore.solderPaste=Solder Paste
smfcore.solderPaste=Solder Paste Management
smfcore.solderPasteKanban=Equipment Overview
smfcore.solderPasteManage=Inventory
smfcore.solderPasteData=Traceability
......@@ -424,4 +424,5 @@ smfcore.virtualLocationManager=Virtual Location Mgmt
smfcore.virtualOperations=Virtual Storage Op
smfcore.equipment.view.ncgroup=Neo Counter
smfcore.virtual.boxInPos=[{0}] is already in location [{1}]. Please remove it first
smfcore.virtual.quantityError=The quantity to be removed should be [{0}]
\ No newline at end of file
smfcore.virtual.quantityError=The quantity to be removed should be [{0}]
smfcode.virtual.enter=Please scan or enter the barcode, then press Enter
\ No newline at end of file
......@@ -423,4 +423,5 @@ smfcore.virtualLocationManager=Gestion des emplacements virtuels
smfcore.virtualOperations=Op\u00E9rations de l'entrep\u00F4t virtuel
smfcore.equipment.view.ncgroup=Neo Counter
smfcore.virtual.boxInPos=[{0}] est d\u00E9j\u00E0 dans l'emplacement [{1}]. Veuillez d'abord le retirer
smfcore.virtual.quantityError=La quantit\u00E9 \u00E0 retirer doit \u00EAtre [{0}]
\ No newline at end of file
smfcore.virtual.quantityError=La quantit\u00E9 \u00E0 retirer doit \u00EAtre [{0}]
smfcode.virtual.enter=Veuillez scanner ou saisir le code-barres, puis appuyer sur Entr\u00E9e
\ No newline at end of file
......@@ -420,4 +420,5 @@ smfcore.virtualLocationManager=\u4EEE\u60F3\u30ED\u30B1\u30FC\u30B7\u30E7\u30F3\
smfcore.virtualOperations=\u4EEE\u60F3\u5009\u5EAB\u64CD\u4F5C
smfcore.equipment.view.ncgroup=Neo Counter
smfcore.virtual.boxInPos=[{0}] \u306F\u65E2\u306B\u30ED\u30B1\u30FC\u30B7\u30E7\u30F3 [{1}] \u306B\u3042\u308A\u307E\u3059\u3002\u5148\u306B\u53D6\u308A\u51FA\u3057\u3066\u304F\u3060\u3055\u3044
smfcore.virtual.quantityError=\u53D6\u308A\u51FA\u3057\u6570\u91CF\u306F[{0}]\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059
\ No newline at end of file
smfcore.virtual.quantityError=\u53D6\u308A\u51FA\u3057\u6570\u91CF\u306F[{0}]\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059
smfcode.virtual.enter=\u30D0\u30FC\u30B3\u30FC\u30C9\u3092\u30B9\u30AD\u30E3\u30F3\u3001\u307E\u305F\u306F\u5165\u529B\u5F8C\u3001Enter\u30AD\u30FC\u3092\u62BC\u3057\u3066\u304F\u3060\u3055\u3044
\ No newline at end of file
......@@ -420,4 +420,5 @@ smfcore.virtualLocationManager=\u865A\u62DF\u5E93\u4F4D\u7BA1\u7406
smfcore.virtualOperations=\u865A\u62DF\u4ED3\u64CD\u4F5C
smfcore.equipment.view.ncgroup=Neo Counter
smfcore.virtual.boxInPos=[{0}]\u5DF2\u5728\u5E93\u4F4D[{1}]\u4E2D,\u8BF7\u5148\u53D6\u51FA
smfcore.virtual.quantityError=\u53D6\u51FA\u6570\u91CF\u5E94\u4E3A[{0}]
\ No newline at end of file
smfcore.virtual.quantityError=\u53D6\u51FA\u6570\u91CF\u5E94\u4E3A[{0}]
smfcode.virtual.enter=\u8BF7\u626B\u63CF\u6216\u8F93\u5165\u6761\u7801\u540E\u6309\u56DE\u8F66\u786E\u8BA4
\ No newline at end of file
......@@ -420,4 +420,5 @@ smfcore.virtualLocationManager=\u865B\u64EC\u5EAB\u4F4D\u7BA1\u7406
smfcore.virtualOperations=\u865B\u64EC\u5009\u64CD\u4F5C
smfcore.equipment.view.ncgroup=Neo Counter
smfcore.virtual.boxInPos=[{0}]\u5DF2\u5728\u5EAB\u4F4D[{1}]\u4E2D,\u8ACB\u5148\u53D6\u51FA
smfcore.virtual.quantityError=\u53D6\u51FA\u6578\u91CF\u61C9\u70BA[{0}]
\ No newline at end of file
smfcore.virtual.quantityError=\u53D6\u51FA\u6578\u91CF\u61C9\u70BA[{0}]
smfcode.virtual.enter=\u8ACB\u6383\u63CF\u6216\u8F38\u5165\u689D\u78BC\u5F8C\u6309\u56DE\u8ECA\u78BA\u8A8D
\ No newline at end of file
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!