Commit 8e65d489 LN

Merge remote-tracking branch 'origin/master'

2 个父辈 969c0a43 ea5f0a85
正在显示 35 个修改的文件 包含 711 行增加32 行删除
......@@ -235,6 +235,7 @@ public class MenuInit {
Menu poutSet = Menu.CreatePMenu("设置", 13, "system","system",null);
addDefaultFunctionMenu(101, poutSet, "设备管理", "bunker", "storage/storage/index", "database",DEFAULT_SHOW_MENU);
addDefaultFunctionMenu(102,poutSet, "库位管理", "storagePos", "storagePos/storagePos/index", "tree-table",DEFAULT_SHOW_MENU);
addDefaultFunctionMenu(103,poutSet, "合并库位", "selectDevice", "neolight/selectDevice/index", "selectDevice");
addDefaultFunctionMenu(103, poutSet, "菜单管理", "menu", "system/menu/index", "menu");
// Menu sysSetting = new Menu(, "barcode", "条码设置", "barcodeSetting", "system/barcodeSetting/index", "database");
// Menu outSet = new Menu(, "outSetting", "出库策略", "outSetting", "system/outSetting/index", "outSet");
......
......@@ -666,7 +666,7 @@ public class HttpHelper {
List<NameValuePair> params = toNameValuePair(paramMap);
URI uri = new URIBuilder(url).setParameters(params).build();
log.info("getParam请求,地址为:"+uri);
//log.info("getParam请求,地址为:"+uri);
HttpGet httpGet = new HttpGet(uri);
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECTION_TIMEOUT).build();
httpGet.setConfig(requestConfig);
......
......@@ -9,6 +9,7 @@ import com.neotel.smfcore.core.api.bean.CodeValidateParam;
import com.neotel.smfcore.core.device.util.DataCache;
import com.neotel.smfcore.core.inList.service.po.InList;
import com.neotel.smfcore.core.order.service.po.LiteOrder;
import com.neotel.smfcore.core.storage.service.po.StoragePos;
import com.neotel.smfcore.core.system.service.po.DataLog;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
......@@ -85,6 +86,12 @@ public class SmfApi {
@Value("${api.deviceStatusUrl:}")
protected String deviceStatusUrl = "";
@Value("${api.mergePosUrl:}")
protected String mergePosUrl = "";
@Value("${api.splitPosUrl:}")
protected String splitPosUrl = "";
@PostConstruct
public void init(){
apiName = dataCache.getConfigCache("api.name",apiName);
......@@ -100,6 +107,8 @@ public class SmfApi {
fetchOrderUrl = dataCache.getConfigCache("api.fetchOrderUrl",fetchOrderUrl);
loginCheckUrl=dataCache.getConfigCache("api.loginCheckUrl",loginCheckUrl);
deviceStatusUrl=dataCache.getConfigCache("api.deviceStatusUrl",deviceStatusUrl);
mergePosUrl = dataCache.getConfigCache("api.mergePosUrl",mergePosUrl);
splitPosUrl = dataCache.getConfigCache("api.splitPosUrl",splitPosUrl);
}
/**
......@@ -294,6 +303,37 @@ public class SmfApi {
}
return true;
}
public void splitPos(String splitPosName) {
if(isUrlExist(splitPosUrl)){
threadPool.execute(new Runnable() {
@Override
public void run() {
for (ISmfApiListener apiListener : apiListenerList) {
if(apiListener.isForThisApi(apiName)){
apiListener.splitPos(splitPosUrl,splitPosName);
}
}
}
});
}
}
public void mergePos(StoragePos storagePos) {
if(isUrlExist(mergePosUrl)){
threadPool.execute(new Runnable() {
@Override
public void run() {
for (ISmfApiListener apiListener : apiListenerList) {
if(apiListener.isForThisApi(apiName)){
apiListener.mergePos(mergePosUrl,storagePos);
}
}
}
});
}
}
public String getApiName(){
return apiName;
}
......
......@@ -20,6 +20,7 @@ import com.neotel.smfcore.core.inList.util.InListCache;
import com.neotel.smfcore.core.order.LiteOrderCache;
import com.neotel.smfcore.core.order.service.manager.ILiteOrderManager;
import com.neotel.smfcore.core.order.service.po.LiteOrder;
import com.neotel.smfcore.core.storage.service.po.StoragePos;
import com.neotel.smfcore.core.system.service.po.DataLog;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
......@@ -152,4 +153,14 @@ public abstract class BaseSmfApiListener implements ISmfApiListener {
public boolean deviceStatusChanges(String deviceStatusUrl, String[] cids,Integer[] status) {
return true;
}
@Override
public void splitPos(String splitPosUrl, String splitPosName) {
}
@Override
public void mergePos(String mergePosUrl, StoragePos storagePos) {
}
}
......@@ -6,6 +6,7 @@ import com.neotel.smfcore.core.barcode.service.po.Barcode;
import com.neotel.smfcore.core.api.bean.CodeValidateParam;
import com.neotel.smfcore.core.inList.service.po.InList;
import com.neotel.smfcore.core.order.service.po.LiteOrder;
import com.neotel.smfcore.core.storage.service.po.StoragePos;
import com.neotel.smfcore.core.system.service.po.DataLog;
public interface ISmfApiListener {
......@@ -80,4 +81,9 @@ public interface ISmfApiListener {
* @return
*/
boolean deviceStatusChanges(String deviceStatusUrl, String[] cids,Integer[] status );
void splitPos(String splitPosUrl, String splitPosName);
void mergePos(String mergePosUrl, StoragePos storagePos);
}
......@@ -18,6 +18,7 @@ import com.neotel.smfcore.core.dashboard.bean.dto.first.InOutDataDto;
import com.neotel.smfcore.core.inout.service.manager.IInOutDataManager;
import com.neotel.smfcore.core.inout.service.po.InOutData;
import com.neotel.smfcore.core.kanban.rest.bean.dto.BoxStatusDto;
import com.neotel.smfcore.core.kanban.rest.utils.NaturalOrderComparator;
import com.neotel.smfcore.core.language.util.MessageUtils;
import com.neotel.smfcore.core.message.rest.bean.dto.MessageDto;
import com.neotel.smfcore.core.message.rest.bean.mapstruct.MessageMapper;
......@@ -105,7 +106,18 @@ public class SmdBoxMimoController {
posCount += item.getTotalCount();
usePosCount += item.getUsedCount();
}
InventoryBoxDto boxDto = new InventoryBoxDto(storage.getId(), storage.getName(), storage.getCid(), storage.getType(), storage.getUsageMap(), posCount, usePosCount);
Map<String, UsageItem> sortUsageMap = new LinkedHashMap<>();
Map<String, UsageItem> usageMap = storage.getUsageMap();
if (usageMap != null && !usageMap.isEmpty()) {
List<UsageItem> usageList = new ArrayList<>(usageMap.values());
usageList = usageList.stream().sorted(Comparator.comparing(UsageItem :: getW).thenComparing(UsageItem :: getH)).collect(Collectors.toList());
for (UsageItem usageItem : usageList) {
sortUsageMap.put(usageItem.getSizeStr(),usageItem);
}
}
InventoryBoxDto boxDto = new InventoryBoxDto(storage.getId(), storage.getName(), storage.getCid(), storage.getType(), sortUsageMap, posCount, usePosCount);
boxDtos.add(boxDto);
}
if (boxDtos.size() > 0) {
......
......@@ -823,6 +823,7 @@ public class BaseDeviceHandler implements IDeviceHandler {
//仓位状态
barcodeDB.setCheckOutDate(new Date(), task.getOperator());
barcodeDB.setPosName("");
barcodeDB.setOnlySingleOut(false);
barcodeManager.save(barcodeDB);
task.setBatchInfo(barcodeDB.getBatch());
......
package com.neotel.smfcore.core.device.handler.impl;
import com.neotel.smfcore.core.storage.enums.DeviceType;
import org.springframework.stereotype.Service;
@Service
public class MimoG4BoxHandler extends MimoG3BoxHandler{
@Override
public DeviceType getDeviceType() {
return DeviceType.SMD_MIMO_G4;
}
}
......@@ -242,32 +242,32 @@ public class NLPShelfHandler extends BaseDeviceHandler {
//亮灯
Collection<DataLog> queueTasks = taskService.getQueueTasks(statusBean.getCid());
for (DataLog queueTask : queueTasks) {
if (queueTask.isWait() && queueTask.isCheckOutTask()) {
queueTask.setStatus(OP_STATUS.EXECUTING.name());
taskService.updateQueueTask(queueTask);
String rgb = queueTask.getLightColor();
ORDER_COLOR color = ORDER_COLOR.fromRgb(rgb);
if (color == null) {
if (openZhiYin && ObjectUtil.isNotEmpty(queueTask.getSourceId())) {
List<DataLog> dataLogList = outMap.get(queueTask.getSourceId());
if (dataLogList == null) {
dataLogList = new ArrayList<>();
}
dataLogList.add(queueTask);
outMap.put(queueTask.getSourceId(), dataLogList);
} else {
if (StringUtils.isNotBlank(rgb)){
log.info(queueTask.getPosName() + "库位亮灯:" + "#" + rgb);
statusBean.addData("open", queueTask.getPosName() + "=#" + rgb);
if (!openZhiYin || StringUtils.isBlank(queueTask.getSourceId())) {
if (queueTask.isWait()) {
String rgb = queueTask.getLightColor();
ORDER_COLOR color = ORDER_COLOR.fromRgb(rgb);
if (color == null) {
if (queueTask.isPutInTask()) {
color = ORDER_COLOR.FORESTGREEN;
} else {
color = ORDER_COLOR.BLUE;
}
}
}
if (color != null){
queueTask.setStatus(OP_STATUS.EXECUTING.name());
taskService.updateQueueTask(queueTask);
statusBean.addData("open", queueTask.getPosName() + "=" + color.name());
log.info("库位[" + queueTask.getPosName() + "]+亮灯:" + color.name());
log.info("库位[" + queueTask.getPosName() + "][" + queueTask.getType() + "]+亮灯:" + color.name());
}
} else {
if (queueTask.isWait() || queueTask.isExecuting()) {
List<DataLog> dataLogList = outMap.get(queueTask.getSourceId());
if (dataLogList == null) {
dataLogList = new ArrayList<>();
}
dataLogList.add(queueTask);
outMap.put(queueTask.getSourceId(), dataLogList);
}
}
}
......
......@@ -820,7 +820,7 @@ public class DataCache {
public List<String> getAvailableStorageIds() {
List<String> availableStorageIds = new ArrayList<>();
for (Storage storage : getAllStorage().values()) {
if (!storage.isVirtual()) {
if (!storage.isVirtual() && !storage.isNLPHBShelf()) {
StatusBean bean = DevicesStatusUtil.getStatusBean(storage.getCid());
if (bean == null || bean.timeOut() || !bean.isAvailable()) {
continue;
......@@ -832,6 +832,7 @@ public class DataCache {
}
return availableStorageIds;
}
public List<String> getAvailableStorageIds(List<String> cidList) {
if (cidList == null || cidList.size() <= 0) {
return getAvailableStorageIds();
......@@ -841,7 +842,7 @@ public class DataCache {
if (!cidList.contains(storage.getCid())) {
continue;
}
if (!storage.isVirtual()) {
if (!storage.isVirtual() && !storage.isNLPHBShelf()) {
StatusBean bean = DevicesStatusUtil.getStatusBean(storage.getCid());
if (bean == null || bean.timeOut() || !bean.isAvailable()) {
continue;
......@@ -853,6 +854,7 @@ public class DataCache {
}
return availableStorageIds;
}
public List<String> getAvailableStorageIds(DeviceType deviceType) {
List<String> availableStorageIds = new ArrayList<>();
for (Storage storage : getAllStorage().values()) {
......
......@@ -455,7 +455,7 @@ public class BoxKanbanController {
boxDto.setOnLine(false);
//如果是虚拟仓,默认在线
if (storage.isVirtual()) {
if (storage.isVirtual() || storage.isNLPHBShelf()) {
boxDto.setOnLine(true);
boxDto.setStatus(1);
}
......
......@@ -33,16 +33,16 @@ public enum ORDER_COLOR {
//MAGENTA("FF00FF"),
CYAN("00FFFF"),
FIREBRICK("B22222"),
PURPLE("A020F0"),
//PURPLE("A020F0"),
//SKYBLUE("6CA6CD"),
//PINK("FF1493"),
FORESTGREEN("228B22"),
//LIGHTBLUE("8470FF"),
//INDIANRED("8B3A3A"),
DARKGREEN("556B2F"),
//DARKGREEN("556B2F"),
RED("FF0000"),
YELLOW("FFFF00"),
ORANGE("FFA500"),
//ORANGE("FFA500"),
WHITE("FFFFFF")
;
......
......@@ -161,9 +161,21 @@ public enum DeviceType {
SMD_ONE("storage.type.smdOne"),
/**
* 尾料柜
* 27 尾料柜
*/
TAILING_MATERIAL("storage.type.tailingMaterial"),
/**
* 28 SMD_MIMO_G4
*/
SMD_MIMO_G4("storage.type.smdMimoG4"),
/**
* 29 感应料架NLP(浩博)
*/
NLP_HB("storage.type.nlpHb"),
;
private String key;
......@@ -185,6 +197,6 @@ public enum DeviceType {
}
public static List<DeviceType> availableTypeList(){
return Lists.newArrayList(AUTO,LINE,BATCH,SOLDERPASTE,VERTICALBOX,SMD_XL,SMD_DUO,SMD_XLC,SMD_XLR,SMD_ONE,VIRTUAL,NL,NLP,NLM,NLL,NLS,NLSM,SMDBOX_THIRD,SMD_MIMO_G2,SMD_MIMO_G3,TAILING_MATERIAL);
return Lists.newArrayList(AUTO,LINE,BATCH,SOLDERPASTE,VERTICALBOX,SMD_XL,SMD_DUO,SMD_XLC,SMD_XLR,SMD_ONE,VIRTUAL,NL,NLP,NLP_HB,NLM,NLL,NLS,NLSM,SMDBOX_THIRD,SMD_MIMO_G2,SMD_MIMO_G3,SMD_MIMO_G4,TAILING_MATERIAL);
}
}
......@@ -107,4 +107,5 @@ public interface IStoragePosManager extends IBaseManager<StoragePos> {
StoragePos getSpEmptyPosByStorage(Storage storage, Barcode barcode, Collection<String> excludePosIds,String endStr) throws ValidateException;
void saveMergePos(StoragePos storagePos);
}
......@@ -1176,4 +1176,9 @@ public class StoragePosManagerImpl implements IStoragePosManager {
StoragePos pos = storagePosDao.findOne(query);
return pos;
}
@Override
public void saveMergePos(StoragePos storagePos) {
storagePosDao.save(storagePos);
}
}
......@@ -207,6 +207,10 @@ public class Storage extends BasePo implements Serializable {
return DeviceType.SMD_XLC.name().equals(type);
}
public boolean isNLPHBShelf() {
return DeviceType.NLP_HB.name().equals(type);
}
public boolean isType(DeviceType[] types){
for (DeviceType str :
types) {
......
......@@ -157,7 +157,7 @@ public class SettingsController {
List<Storage> storages = new ArrayList<>(dataCache.getAllStorage().values());
for (Storage storage : storages
) {
if (storage.isType(new DeviceType[]{DeviceType.NLP,DeviceType.NL,DeviceType.NLS})) {
if (storage.isType(new DeviceType[]{DeviceType.NLP,DeviceType.NL,DeviceType.NLS,DeviceType.NLP_HB})) {
orderSetting.setShowLightType(true);
break;
}
......
package com.neotel.smfcore.custom.haobo;
import com.neotel.smfcore.core.api.SmfApi;
import com.neotel.smfcore.core.device.util.DataCache;
import com.neotel.smfcore.core.storage.service.po.Storage;
import com.neotel.smfcore.core.system.service.po.DataLog;
import com.neotel.smfcore.core.system.util.DevicesStatusUtil;
import com.neotel.smfcore.core.system.util.TaskService;
import com.neotel.smfcore.custom.haobo.bean.PosDiff;
import com.neotel.smfcore.custom.haobo.bean.PosTotalDiffResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class HaoBoNlpPosHandler {
@Autowired
private SmfApi smfApi;
@Autowired
private HaoboApi haoboApi;
@Autowired
private DataCache dataCache;
@Autowired
private TaskService taskService;
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);
@PostConstruct
private void init() {
scheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
String apiName = smfApi.getApiName();
if (haoboApi.isForThisApi(apiName)) {
handlePos();
}
}
}, 30, 5, TimeUnit.SECONDS);
}
private void handlePos() {
for (Storage storage : dataCache.getAllStorage().values()) {
String cid = storage.getCid(); // 提取CID,便于日志定位
if (storage.isNLPHBShelf()) {
// ========== 1. 获取旧数据(空值兜底,避免索引越界) ==========
List<List<String>> oldDeviceData = DevicesStatusUtil.getDeviceData(cid);
// ========== 2. 计算新的差异数据 ==========
List<String> inventoryPosName = haoboApi.getInventoryPosName(cid);
List<String> usedPosNameList = dataCache.getUsedPosNameList(cid);
PosDiff posDiff = calculatePosDiff(inventoryPosName, usedPosNameList);
List<String> newInventoryOnly = posDiff.getInventoryOnly() == null ? new ArrayList<>() : posDiff.getInventoryOnly();
List<String> newUsedOnly = posDiff.getUsedOnly() == null ? new ArrayList<>() : posDiff.getUsedOnly();
List<List<String>> newData = new ArrayList<>();
newData.add(newInventoryOnly);
newData.add(newUsedOnly);
//3.开始新增差异信息,亮灯或者灭灯
PosTotalDiffResult posTotalDiffResult = calculateAndPrintPosDiff(oldDeviceData, newData);
List<String> totalAddList = posTotalDiffResult.getTotalAddList();
List<String> totalReduceList = posTotalDiffResult.getTotalReduceList();
haoboApi.lightUpSomeLampBeads(totalAddList, totalReduceList);
DevicesStatusUtil.updateDeviceData(cid, newData);
}
}
}
/**
* 计算并打印新旧货位数据的差异,同时返回合并后的总新增/总减少列表
*
* @param oldDeviceData 旧设备数据(二维列表:[库存独有列表, 已用独有列表])
* @param newData 新计算的差异数据(二维列表:[库存独有列表, 已用独有列表])
* @return PosTotalDiffResult 合并后的总新增、总减少货位列表
*/
private PosTotalDiffResult calculateAndPrintPosDiff(List<List<String>> oldDeviceData, List<List<String>> newData) {
// ========== 1. 解析旧数据(空值兜底) ==========
List<String> oldInventoryOnly = new ArrayList<>();
List<String> oldUsedOnly = new ArrayList<>();
if (oldDeviceData != null && !oldDeviceData.isEmpty()) {
oldInventoryOnly = oldDeviceData.size() >= 1 ? oldDeviceData.get(0) : new ArrayList<>();
oldUsedOnly = oldDeviceData.size() >= 2 ? oldDeviceData.get(1) : new ArrayList<>();
}
oldInventoryOnly = oldInventoryOnly == null ? new ArrayList<>() : oldInventoryOnly;
oldUsedOnly = oldUsedOnly == null ? new ArrayList<>() : oldUsedOnly;
// ========== 2. 解析新数据(空值兜底) ==========
List<String> newInventoryOnly = new ArrayList<>();
List<String> newUsedOnly = new ArrayList<>();
if (newData != null && !newData.isEmpty()) {
newInventoryOnly = newData.size() >= 1 ? newData.get(0) : new ArrayList<>();
newUsedOnly = newData.size() >= 2 ? newData.get(1) : new ArrayList<>();
}
newInventoryOnly = newInventoryOnly == null ? new ArrayList<>() : newInventoryOnly;
newUsedOnly = newUsedOnly == null ? new ArrayList<>() : newUsedOnly;
// ========== 3. 计算细分维度差异 ==========
Set<String> oldInventorySet = new HashSet<>(oldInventoryOnly);
Set<String> newInventorySet = new HashSet<>(newInventoryOnly);
Set<String> inventoryAdd = new HashSet<>(newInventorySet);
inventoryAdd.removeAll(oldInventorySet);
Set<String> inventoryReduce = new HashSet<>(oldInventorySet);
inventoryReduce.removeAll(newInventorySet);
Set<String> oldUsedSet = new HashSet<>(oldUsedOnly);
Set<String> newUsedSet = new HashSet<>(newUsedOnly);
Set<String> usedAdd = new HashSet<>(newUsedSet);
usedAdd.removeAll(oldUsedSet);
Set<String> usedReduce = new HashSet<>(oldUsedSet);
usedReduce.removeAll(newUsedSet);
// ========== 4. 合并总差异(去重)并转List ==========
Set<String> totalAddSet = new HashSet<>();
totalAddSet.addAll(inventoryAdd);
totalAddSet.addAll(usedAdd);
List<String> totalAddList = new ArrayList<>(totalAddSet); // 转List更易用
Set<String> totalReduceSet = new HashSet<>();
totalReduceSet.addAll(inventoryReduce);
totalReduceSet.addAll(usedReduce);
List<String> totalReduceList = new ArrayList<>(totalReduceSet); // 转List更易用
// ========== 6. 返回合并后的差异结果 ==========
return new PosTotalDiffResult(totalAddList, totalReduceList);
}
/**
* 计算两个货位名称列表的双向差集(纯String类型,无DataItem依赖)
*
* @param inventoryPosNameList 库存货位名称列表
* @param usedPosNameList 已用货位名称列表
* @return PosDiff inventoryOnly=库存有但已用无的名称列表 | usedOnly=已用有但库存无的名称列表
*/
private PosDiff calculatePosDiff(List<String> inventoryPosNameList, List<String> usedPosNameList) {
// 1. 空值兜底:避免NPE
List<String> safeInventoryNames = inventoryPosNameList == null ? new ArrayList<>() : inventoryPosNameList;
List<String> safeUsedNames = usedPosNameList == null ? new ArrayList<>() : usedPosNameList;
// 2. 转Set去重+提高差集计算效率(纯String操作)
Set<String> inventoryPosSet = new HashSet<>(safeInventoryNames);
Set<String> usedPosSet = new HashSet<>(safeUsedNames);
// 3. 计算:库存有但已用无的货位名称列表
Set<String> inventoryOnlySet = new HashSet<>(inventoryPosSet);
inventoryOnlySet.removeAll(usedPosSet);
List<String> inventoryOnly = new ArrayList<>(inventoryOnlySet);
// 4. 计算:已用有但库存无的货位名称列表
Set<String> usedOnlySet = new HashSet<>(usedPosSet);
usedOnlySet.removeAll(inventoryPosSet);
List<String> usedOnly = new ArrayList<>(usedOnlySet);
// 5. 返回纯String类型的差集结果
return new PosDiff(inventoryOnly, usedOnly);
}
}
package com.neotel.smfcore.custom.haobo;
import com.alibaba.fastjson.JSON;
import com.neotel.smfcore.common.exception.ValidateException;
import com.neotel.smfcore.common.utils.StringUtils;
import com.neotel.smfcore.core.barcode.enums.SOLDER_STATUS;
import com.neotel.smfcore.core.barcode.service.manager.IBarcodeManager;
import com.neotel.smfcore.core.barcode.service.po.Barcode;
import com.neotel.smfcore.core.device.enums.OP;
import com.neotel.smfcore.core.device.enums.OP_STATUS;
import com.neotel.smfcore.core.device.handler.impl.BaseDeviceHandler;
import com.neotel.smfcore.core.device.util.DataCache;
import com.neotel.smfcore.core.order.enums.ORDER_COLOR;
import com.neotel.smfcore.core.storage.service.manager.IStoragePosManager;
import com.neotel.smfcore.core.storage.service.po.Storage;
import com.neotel.smfcore.core.storage.service.po.StoragePos;
import com.neotel.smfcore.core.system.bean.OrderSetting;
import com.neotel.smfcore.core.system.service.po.DataLog;
import com.neotel.smfcore.core.system.util.TaskService;
import com.neotel.smfcore.custom.haobo.bean.request.InStockCallbackRequest;
import com.neotel.smfcore.custom.haobo.bean.request.OutStockCallbackRequest;
import com.neotel.smfcore.custom.haobo.bean.response.HaoBoApiResponse;
import com.neotel.smfcore.security.annotation.AnonymousAccess;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Slf4j
@RestController
@RequestMapping("/hbNlp")
public class HaoboNlpController {
@Autowired
private TaskService taskService;
@Autowired
private DataCache dataCache;
@Autowired
private IStoragePosManager storagePosManager;
@Autowired
private IBarcodeManager barcodeManager;
@ApiOperation("入库完成回调")
@RequestMapping("/inStockCallback")
@AnonymousAccess
public HaoBoApiResponse inStockCallback(@RequestBody InStockCallbackRequest request) {
log.info("收到入库完成回调信息:" + JSON.toJSONString(request));
DataLog dataLog = null;
Collection<DataLog> queueTasks = taskService.getQueueTasks();
for (DataLog queueTask : queueTasks) {
if (queueTask.getBarcode().equals(request.getLabelId())) {
if (queueTask.isPutInTask() && queueTask.isWait()) {
dataLog = queueTask;
break;
}
}
}
if (dataLog == null) {
return new HaoBoApiResponse(false, "未找到对应的入库任务");
}
StoragePos pos = storagePosManager.getByPosName(request.getLocation());
if (pos == null) {
return new HaoBoApiResponse(false, "未找到对应的库位");
}
if (pos.getBarcode() != null) {
return new HaoBoApiResponse(false, "库位已被占用");
}
Storage storage = dataCache.getStorageById(pos.getStorageId());
dataLog.setCid(storage.getCid());
dataLog.setPosId(pos.getId());
dataLog.setPosName(pos.getPosName());
dataLog.setStorageId(storage.getId());
dataLog.setStorageName(storage.getName());
updatePutInData(dataLog);
return new HaoBoApiResponse(true, "入库完成");
}
@ApiOperation("出库完成回调")
@RequestMapping("/outStockCallback")
@AnonymousAccess
public HaoBoApiResponse outStockCallback(@RequestBody OutStockCallbackRequest request) {
log.info("收到出库完成回调信息:" + JSON.toJSONString(request));
DataLog dataLog = null;
Collection<DataLog> queueTasks = taskService.getQueueTasks();
for (DataLog queueTask : queueTasks) {
if (queueTask.getBarcode().equals(request.getLabelId())) {
if (queueTask.isCheckOutTask() && (queueTask.isWait() || queueTask.isExecuting())) {
dataLog = queueTask;
break;
}
}
}
if (dataLog != null) {
updateCheckoutData(dataLog, OP_STATUS.FINISHED);
return new HaoBoApiResponse(true, "出库完成");
} else {
//判断在不在库位中,如果不在库位中,则忽略
StoragePos pos = storagePosManager.getByBarcode(request.getLabelId());
if (pos == null) {
if (StringUtils.isNotEmpty(request.getLocation())) {
pos = storagePosManager.getByPosName(request.getLocation());
}
}
if (pos == null || pos.getBarcode() == null) {
log.info("根据库位名称和条码都未找到对应的库存信息,库位名称为:{},唯一码为:{}", request.getLocation(), request.getLabelId());
return new HaoBoApiResponse(true, "根据唯一码或者库位号都未找到对应的库存信息,默认已出库");
}
Storage storage = dataCache.getStorageById(pos.getStorageId());
DataLog createDataLog = new DataLog(storage, pos.getBarcode(), pos);
createDataLog.setType(OP.CHECKOUT);
createDataLog.setOperator("system");
createDataLog = taskService.updateQueueTask(createDataLog);
updateCheckoutData(createDataLog, OP_STATUS.FINISHED);
return new HaoBoApiResponse(true, "出库完成");
}
}
/**
* 入仓位完成
*/
protected void updatePutInData(DataLog task) throws ValidateException {
//从队列里面移除操作
taskService.removeQueueTask(task);
StoragePos storagePos = storagePosManager.get(task.getPosId());
//二维码状态
Barcode barcode = barcodeManager.findByBarcode(task.getBarcode());
if (barcode != null) {
barcode.setUsedCount(barcode.getUsedCount() + 1);
barcode.setPutInTime(System.currentTimeMillis());
barcode.updateSluggishTime(dataCache.getPNsluggishDay(barcode.getPartNumber()));
barcode.setInOpor(task.getOperator());
barcode.setCheckOutDate(null, "");
barcode.setPosName(task.getPosName());
if (barcode.isSolder()) {
if (storagePos.isWarmPos()) {
//回温仓位
barcode.setSolderStatus(SOLDER_STATUS.RETREAT_STORAGE.name());
} else {
barcode.setSolderStatus(SOLDER_STATUS.UNDER_REFRIGERATION.name());
}
barcode.setNeedOutDate(null);
}
barcodeManager.save(barcode);
}
storagePos.setBarcode(barcode);
storagePos.setUsed(true);
storagePos.setCanCheckOutTime(System.currentTimeMillis());
storagePosManager.saveMergePos(storagePos);
if (barcode != null) {
dataCache.updateInventory(storagePos, barcode);
//记录日志,完成 task
task.setBatchInfo(barcode.getBatch());
task.setNum(barcode.getAmount());
task.setProviderNumber(barcode.getProviderNumber());
}
//更新缓存中的库存信息
task.setStatus(OP_STATUS.FINISHED.name());
taskService.updateFinishedTask(task);
}
/**
* 出仓位完成
*/
private void updateCheckoutData(DataLog task, OP_STATUS outBoxStatus) throws ValidateException {
//从队列里面移除操作
taskService.removeQueueTask(task);
StoragePos storagePos = storagePosManager.get(task.getPosId());
Barcode barcode = storagePos.getBarcode();
if (barcode == null) {
log.warn("任务:" + task.getId() + " 仓位:" + task.getPosId() + " 的 Barcode 为null, 之前可能处理过,结束任务后直接返回");
//记录日志
task.setStatus(outBoxStatus.name());
taskService.updateFinishedTask(task);
return;
}
Barcode barcodeDB = barcodeManager.get(barcode.getId());
if (barcodeDB != null) {
//二维码状态
barcodeDB.setUsed(true);
barcodeDB.setUsedDate(new Date());
//仓位状态
barcodeDB.setCheckOutDate(new Date(), task.getOperator());
barcodeDB.setPosName("");
barcodeManager.save(barcodeDB);
task.setBatchInfo(barcodeDB.getBatch());
//记录在库时长
task.setInStoreTime(barcodeDB.getInStoreMiniute());
}
storagePos.setBarcode(null);
storagePos.setUsed(false);
storagePosManager.saveMergePos(storagePos);
log.info("出库完成,清空仓位: " + storagePos.getId() + "[" + storagePos.getPosName() + "]");
//更新缓存中的库存信息
dataCache.updateInventory(storagePos, barcode);
// 调用西门子接口
// SiemensApi.lotInOut(barcode.getBarcode(),2);
//记录日志
task.setStatus(outBoxStatus.name());
taskService.updateFinishedTask(task);
}
}
package com.neotel.smfcore.custom.haobo.bean;
import lombok.Data;
import java.util.List;
@Data
public class PosDiff {
List<String> inventoryOnly;
List<String> usedOnly;
public PosDiff(List<String> inventoryOnly, List<String> usedOnly) {
this.inventoryOnly = inventoryOnly;
this.usedOnly = usedOnly;
}
}
package com.neotel.smfcore.custom.haobo.bean;
import java.util.List;
public class PosTotalDiffResult {
// 所有新增(多的)货位列表
private List<String> totalAddList;
// 所有减少(少的)货位列表
private List<String> totalReduceList;
public PosTotalDiffResult(List<String> totalAddList, List<String> totalReduceList) {
this.totalAddList = totalAddList;
this.totalReduceList = totalReduceList;
}
// Getter方法(用于外部获取返回值)
public List<String> getTotalAddList() {
return totalAddList;
}
public List<String> getTotalReduceList() {
return totalReduceList;
}
}
package com.neotel.smfcore.custom.haobo.bean.request;
import lombok.Data;
@Data
public class InStockCallbackRequest {
private String labelId;
private String location;
private String detailsJson;
}
package com.neotel.smfcore.custom.haobo.bean.request;
import lombok.Data;
@Data
public class OutStockCallbackRequest {
private String labelId;
private String location;
private String detailsJson;
}
package com.neotel.smfcore.custom.haobo.bean.response;
import lombok.Data;
import java.util.List;
@Data
public class GetInventoryResponse {
private Result result;
private String targetUrl;
private boolean success;
private Object error;
private boolean unAuthorizedRequest;
@Data
public static class Result {
private boolean success;
private String message;
private List<DataItem> data;
}
@Data
public static class DataItem {
private String location;
private String labelId;
private String shelfCode;
private String operationTime;
private int status;
private String externalLocation;
private String presentInductionLocation;
private String transferShelfCode;
private String inStockDetailsJson;
private String outStockDetailsJson;
private boolean inStockCallbackSuccess;
private int inStockCallbackNum;
private boolean outStockCallbackSuccess;
private int outStockCallbackNum;
private String updateTime;
private long hardwareTime;
private String materialCode;
private String materialName;
private String materialSpec;
private Integer materialQuantity;
private String productionDate;
private String timeout;
private int id;
}
}
\ No newline at end of file
package com.neotel.smfcore.custom.haobo.bean.response;
import lombok.Data;
@Data
public class HaoBoApiResponse {
private boolean success;
private String message;
private Object data;
public HaoBoApiResponse(boolean success,String message) {
this.message = message;
this.success = success;
this.data = null;
}
}
......@@ -463,4 +463,11 @@ smfcore.reelPosMove.posIsNull=\u5E93\u4F4D[{1}]\u4E3A\u7A7A
smfcore.liteOrder.exist=\u9700\u6C42\u5355{0}\u5DF2\u5B58\u5728
smfcore.reelPosMove.barcodeError=\u5E93\u4F4D{0}\u6761\u7801\u4E3A{1}\uFF0C\u4E0E\u79FB\u5E93\u6761\u7801{1}\u4E0D\u4E00\u81F4
smfcore.barcode.notFindFeerder=\u672A\u627E\u5230[{0}]\u7AD9\u4F4D\u4FE1\u606F
smfcore.pos.merge.notNull=\u5E93\u4F4D\u4E0D\u80FD\u4E3A\u7A7A
smfcore.pos.merge.numError=\u8BF7\u9009\u62E9[{0}]\u4E2A\u8981\u5408\u5E76\u7684\u5E93\u4F4D
smfcore.pos.merge.hasMaterial=\u5E93\u4F4D[{0}]\u6709\u7269\u6599,\u4E0D\u80FD\u5408\u5E76
smfcore.pos.merge.hasMergePos=\u5E93\u4F4D[{0}]\u5DF2\u5408\u5E76,\u4E0D\u80FD\u7EE7\u7EED\u5408\u5E76
smfcore.pos.merge.notAdjacent=\u8BF7\u9009\u62E9\u76F8\u90BB\u7684\u5E93\u4F4D\u5408\u5E76
smfcore.pos.split.notNull=\u5E93\u4F4D\u4E0D\u80FD\u4E3A\u7A7A
smfcore.pos.split.notMergePos=\u5E93\u4F4D[{0}]\u672A\u5408\u5E76,\u4E0D\u80FD\u62C6\u5206
smfcore.pos.split.hasMaterial=\u5E93\u4F4D[{0}]\u6709\u7269\u6599,\u4E0D\u80FD\u62C6\u5206
......@@ -453,3 +453,11 @@ smfcore.liteOrder.exist=Bedarfsauftrag {0} existiert bereits
smfcore.reelPosMove.barcodeError=Der Barcode des Lagerorts {0} ist {1}, nicht identisch mit dem Umzugscode {1}
smfcore.barcode.notFindFeerder=Stationsinformation [{0}] nicht gefunden
smfcore.storagePos.provider=Lieferant
smfcore.pos.merge.notNull=Lagerposition darf nicht leer sein
smfcore.pos.merge.numError=W\u00E4hlen Sie [{0}] Lagerpositionen zum Zusammenf\u00FChren aus
smfcore.pos.merge.hasMaterial=Lagerposition [{0}] enth\u00E4lt Materialien und kann nicht zusammengef\u00FChrt werden
smfcore.pos.merge.hasMergePos=Lagerposition [{0}] wurde bereits zusammengef\u00FChrt und kann nicht weiter zusammengef\u00FChrt werden
smfcore.pos.merge.notAdjacent=W\u00E4hlen Sie benachbarte Lagerpositionen zum Zusammenf\u00FChren aus
smfcore.pos.split.notNull=Lagerposition darf nicht leer sein
smfcore.pos.split.notMergePos=Lagerposition [{0}] wurde nicht zusammengef\u00FChrt und kann nicht aufgeteilt werden
smfcore.pos.split.hasMaterial=Lagerposition [{0}] enth\u00E4lt Materialien und kann nicht aufgeteilt werden
......@@ -454,3 +454,11 @@ smfcore.liteOrder.exist=Requirement order {0} already exists
smfcore.reelPosMove.barcodeError=Location {0} barcode is {1}, inconsistent with the transfer barcode {1}
smfcore.barcode.notFindFeerder=Station information [{0}] not found
smfcore.storagePos.provider=Provider
smfcore.pos.merge.notNull=Storage position cannot be empty
smfcore.pos.merge.numError=Please select [{0}] storage positions to merge
smfcore.pos.merge.hasMaterial=Storage position [{0}] contains materials and cannot be merged
smfcore.pos.merge.hasMergePos=Storage position [{0}] has been merged and cannot be merged further
smfcore.pos.merge.notAdjacent=Please select adjacent storage positions to merge
smfcore.pos.split.notNull=Storage position cannot be empty
smfcore.pos.split.notMergePos=Storage position [{0}] has not been merged and cannot be split
smfcore.pos.split.hasMaterial=Storage position [{0}] contains materials and cannot be split
......@@ -453,3 +453,11 @@ smfcore.liteOrder.exist=Le bon de commande {0} existe d\u00E9j\u00E0
smfcore.reelPosMove.barcodeError=Le code-barres de l'emplacement {0} est {1}, incompatible avec le code-barres de transfert {1}
smfcore.barcode.notFindFeerder=Informations de station [{0}] non trouv\u00E9es
smfcore.storagePos.provider=Fournisseur
smfcore.pos.merge.notNull=L'emplacement de stockage ne peut pas \u00EAtre vide
smfcore.pos.merge.numError=Veuillez s\u00E9lectionner [{0}] emplacements de stockage \u00E0 fusionner
smfcore.pos.merge.hasMaterial=L'emplacement de stockage [{0}] contient des mati\u00E8res et ne peut pas \u00EAtre fusionn\u00E9
smfcore.pos.merge.hasMergePos=L'emplacement de stockage [{0}] a d\u00E9j\u00E0 \u00E9t\u00E9 fusionn\u00E9 et ne peut pas \u00EAtre fusionn\u00E9 davantage
smfcore.pos.merge.notAdjacent=Veuillez s\u00E9lectionner des emplacements de stockage adjacents \u00E0 fusionner
smfcore.pos.split.notNull=L'emplacement de stockage ne peut pas \u00EAtre vide
smfcore.pos.split.notMergePos=L'emplacement de stockage [{0}] n'a pas \u00E9t\u00E9 fusionn\u00E9 et ne peut pas \u00EAtre divis\u00E9
smfcore.pos.split.hasMaterial=L'emplacement de stockage [{0}] contient des mati\u00E8res et ne peut pas \u00EAtre divis\u00E9
......@@ -450,3 +450,11 @@ smfcore.liteOrder.exist=\u8981\u6C42\u5358 {0} \u306F\u65E2\u306B\u5B58\u5728\u3
smfcore.reelPosMove.barcodeError=\u5EAB\u4F4D {0} \u306E\u30D0\u30FC\u30B3\u30FC\u30C9\u306F {1} \u3067\u3001\u79FB\u5EAB\u30D0\u30FC\u30B3\u30FC\u30C9 {1} \u3068\u4E0D\u4E00\u81F4\u3067\u3059
smfcore.barcode.notFindFeerder=[{0}]\u30B9\u30C6\u30FC\u30B7\u30E7\u30F3\u60C5\u5831\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093
smfcore.storagePos.provider=\u4F9B\u7D66\u8005
smfcore.pos.merge.notNull=\u68DA\u4F4D\u7F6E\u3092\u7A7A\u306B\u3059\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093
smfcore.pos.merge.numError=\u7D71\u5408\u3059\u308B\u68DA\u4F4D\u7F6E\u3092[{0}]\u3064\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044
smfcore.pos.merge.hasMaterial=\u68DA\u4F4D\u7F6E[{0}]\u306B\u8CC7\u6750\u304C\u3042\u308B\u305F\u3081\u3001\u7D71\u5408\u3067\u304D\u307E\u305B\u3093
smfcore.pos.merge.hasMergePos=\u68DA\u4F4D\u7F6E[{0}]\u306F\u65E2\u306B\u7D71\u5408\u3055\u308C\u3066\u3044\u308B\u305F\u3081\u3001\u3055\u3089\u306B\u7D71\u5408\u3067\u304D\u307E\u305B\u3093
smfcore.pos.merge.notAdjacent=\u96A3\u63A5\u3059\u308B\u68DA\u4F4D\u7F6E\u3092\u9078\u629E\u3057\u3066\u7D71\u5408\u3057\u3066\u304F\u3060\u3055\u3044
smfcore.pos.split.notNull=\u68DA\u4F4D\u7F6E\u3092\u7A7A\u306B\u3059\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093
smfcore.pos.split.notMergePos=\u68DA\u4F4D\u7F6E[{0}]\u306F\u7D71\u5408\u3055\u308C\u3066\u3044\u306A\u3044\u305F\u3081\u3001\u5206\u5272\u3067\u304D\u307E\u305B\u3093
smfcore.pos.split.hasMaterial=\u68DA\u4F4D\u7F6E[{0}]\u306B\u8CC7\u6750\u304C\u3042\u308B\u305F\u3081\u3001\u5206\u5272\u3067\u304D\u307E\u305B\u3093
......@@ -450,3 +450,11 @@ smfcore.liteOrder.exist=\u9700\u6C42\u5355{0}\u5DF2\u5B58\u5728
smfcore.reelPosMove.barcodeError=\u5E93\u4F4D{0}\u6761\u7801\u4E3A{1}\uFF0C\u4E0E\u79FB\u5E93\u6761\u7801{1}\u4E0D\u4E00\u81F4
smfcore.barcode.notFindFeerder=\u672A\u627E\u5230[{0}]\u7AD9\u4F4D\u4FE1\u606F
smfcore.storagePos.provider=\u4F9B\u5E94\u5546
smfcore.pos.merge.notNull=\u5E93\u4F4D\u4E0D\u80FD\u4E3A\u7A7A
smfcore.pos.merge.numError=\u8BF7\u9009\u62E9[{0}]\u4E2A\u8981\u5408\u5E76\u7684\u5E93\u4F4D
smfcore.pos.merge.hasMaterial=\u5E93\u4F4D[{0}]\u6709\u7269\u6599,\u4E0D\u80FD\u5408\u5E76
smfcore.pos.merge.hasMergePos=\u5E93\u4F4D[{0}]\u5DF2\u5408\u5E76,\u4E0D\u80FD\u7EE7\u7EED\u5408\u5E76
smfcore.pos.merge.notAdjacent=\u8BF7\u9009\u62E9\u76F8\u90BB\u7684\u5E93\u4F4D\u5408\u5E76
smfcore.pos.split.notNull=\u5E93\u4F4D\u4E0D\u80FD\u4E3A\u7A7A
smfcore.pos.split.notMergePos=\u5E93\u4F4D[{0}]\u672A\u5408\u5E76,\u4E0D\u80FD\u62C6\u5206
smfcore.pos.split.hasMaterial=\u5E93\u4F4D[{0}]\u6709\u7269\u6599,\u4E0D\u80FD\u62C6\u5206
......@@ -450,3 +450,11 @@ smfcore.liteOrder.exist=\u9700\u6C42\u55AE {0} \u5DF2\u5B58\u5728
smfcore.reelPosMove.barcodeError=\u5EAB\u4F4D {0} \u689D\u78BC\u70BA {1}\uFF0C\u8207\u79FB\u5EAB\u689D\u78BC {1} \u4E0D\u4E00\u81F4
smfcore.barcode.notFindFeerder=\u672A\u627E\u5230[{0}]\u7AD9\u4F4D\u8CC7\u8A0A
smfcore.storagePos.provider=\u4F9B\u7D66\u8005
smfcore.pos.merge.notNull=\u5EAB\u4F4D\u4E0D\u80FD\u70BA\u7A7A
smfcore.pos.merge.numError=\u8ACB\u9078\u64C7[{0}]\u500B\u8981\u5408\u4F75\u7684\u5EAB\u4F4D
smfcore.pos.merge.hasMaterial=\u5EAB\u4F4D[{0}]\u6709\u7269\u6599,\u4E0D\u80FD\u5408\u4F75
smfcore.pos.merge.hasMergePos=\u5EAB\u4F4D[{0}]\u5DF2\u5408\u4F75,\u4E0D\u80FD\u7E7C\u7E8C\u5408\u4F75
smfcore.pos.merge.notAdjacent=\u8ACB\u9078\u64C7\u76F8\u9130\u7684\u5EAB\u4F4D\u5408\u4F75
smfcore.pos.split.notNull=\u5EAB\u4F4D\u4E0D\u80FD\u70BA\u7A7A
smfcore.pos.split.notMergePos=\u5EAB\u4F4D[{0}]\u672A\u5408\u4F75,\u4E0D\u80FD\u62C6\u5206
smfcore.pos.split.hasMaterial=\u5EAB\u4F4D[{0}]\u6709\u7269\u6599,\u4E0D\u80FD\u62C6\u5206
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!