Commit 090d75a6 sunke

天通对接

1 个父辈 41b405ee
......@@ -141,9 +141,13 @@ public class SmfApi {
if(isUrlExist(inCheckUrl)){
for (ISmfApiListener apiListener : apiListenerList) {
if(apiListener.isForThisApi(apiName)){
Barcode responseBarcode = apiListener.canPutIn(inCheckUrl, barcode);
if(responseBarcode != null){
return responseBarcode;
try{
Barcode responseBarcode = apiListener.canPutIn(inCheckUrl, barcode);
if(responseBarcode != null){
return responseBarcode;
}
}catch (Exception e){
throw new ValidateException("smfcore.api.error","API Error:" + e.getMessage());
}
}
}
......
......@@ -78,4 +78,13 @@ public abstract class BaseSmfApiListener implements ISmfApiListener {
public Barcode canPutInBeforeResolve(String codeResolveUrl, CodeValidateParam params) throws ValidateException {
return null;
}
protected String getData(Map<String, Object> dataMap, String dataKey) {
Object data = dataMap.get(dataKey);
if (data == null) {
return "";
} else {
return data.toString();
}
}
}
......@@ -19,6 +19,11 @@ public enum OP_STATUS {
EXECUTING,
/**
* 出仓完成
*/
OUT_BOX,
/**
* 已暂停
*/
PAUSE,
......
package com.neotel.smfcore.core.device.handler.impl;
import com.neotel.smfcore.core.device.bean.StatusBean;
import com.neotel.smfcore.core.device.enums.OP;
import com.neotel.smfcore.core.storage.enums.DeviceType;
import com.neotel.smfcore.core.storage.service.po.Storage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
/**
* XLR料仓
*/
@Service
@Slf4j
public class XLRBoxHandler extends BaseDeviceHandler {
@Override
public StatusBean handleClientRequest(StatusBean statusBean, HttpServletRequest request) {
statusBean.setClientIp(request.getRemoteHost());
String cid = statusBean.getCid();
Storage storage = dataCache.getStorage(cid);
if (storage == null) {
log.error("料仓cid: [" + cid + "]不存在");
return null;
}
handleMsg(statusBean);
statusBean = saveAlarmAndHumidity(statusBean);
statusBean = handleInOutFinished(statusBean);
StatusBean humidityResult = handleHumidity(statusBean);
if (humidityResult != null) {
return humidityResult;
}
if (statusBean.getOp() == OP.PUT_IN) {
log.debug("入库:" + statusBean.toString());
statusBean = putInLine(storage, statusBean);
} else {
//查看是否有要出库的操作
statusBean =taskService.checkOut(storage, statusBean);
}
return statusBean;
}
@Override
public DeviceType getDeviceType() {
return DeviceType.SMD_XLR;
}
}
......@@ -385,12 +385,12 @@ public class DeviceController {
}
StoragePos pos = storagePosManager.getByPosName(posId);
if (pos == null) {
return ResultBean.newErrorResult(1, "smfcore.valueNotFind", "未找到{0}[{1}]", new String[]{"PosId", posId});
return ResultBean.newErrorResult(1, "smfcore.valueNotFind", "未找到{0}[{1}]", new String[]{"posId", posId});
}
pos.setEnabled(false);
storagePosManager.save(pos);
dataCache.updateDisablePos(pos);
log.info("屏蔽库位:库位号[" + pos.getId() + "][" + pos.getPosName() + "]barcode[" + barcode + "]");
log.info("设备端屏蔽库位:库位号[" + pos.getId() + "][" + pos.getPosName() + "]barcode[" + barcode + "]");
DeviceMessageUtil.addEnabledPosMessage(pos,"");
return ResultBean.newOkResult("");
......
......@@ -199,7 +199,7 @@ public class DataLog extends BasePo implements Serializable {
/**
* 出库时记录此料在库时长 ,分钟
*/
private long inStoreTime=0l;
private long inStoreTime=0L;
/**
* 如果是出库任务,需要记录入库时间
*/
......@@ -252,6 +252,10 @@ public class DataLog extends BasePo implements Serializable {
return OP_STATUS.END.name().equals(status);
}
public boolean isStatus(OP_STATUS theStatus){
return theStatus.name().equals(status);
}
/**
* 是否是入库任务
......
package com.neotel.smfcore.custom.tiantong;
import com.neotel.smfcore.common.exception.ValidateException;
import com.neotel.smfcore.common.utils.DateUtil;
import com.neotel.smfcore.common.utils.HttpHelper;
import com.neotel.smfcore.common.utils.JsonUtil;
import com.neotel.smfcore.core.api.bean.ApiResult;
import com.neotel.smfcore.core.api.listener.BaseSmfApiListener;
import com.neotel.smfcore.core.barcode.service.manager.IComponentManager;
import com.neotel.smfcore.core.barcode.service.po.Barcode;
import com.neotel.smfcore.core.barcode.utils.CodeResolve;
import com.neotel.smfcore.core.device.enums.OP_STATUS;
import com.neotel.smfcore.core.order.service.manager.ILiteOrderItemManager;
import com.neotel.smfcore.core.order.service.po.LiteOrder;
import com.neotel.smfcore.core.order.service.po.LiteOrderItem;
import com.neotel.smfcore.core.system.service.po.DataLog;
import com.neotel.smfcore.custom.tiantong.bean.TianTongResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Service
@Slf4j
public class TianTongApi extends BaseSmfApiListener {
/**
* 出库通知
*/
@Value("${api.outBoxNotifyUrl:}")
protected String outBoxNotifyUrl = "";
@PostConstruct
public void init() {
outBoxNotifyUrl = dataCache.getConfigCache("api.outBoxNotifyUrl", outBoxNotifyUrl);
}
@Override
public boolean isForThisApi(String apiName) {
return apiName != null && apiName.equalsIgnoreCase("tiantong");
}
/**
* 入库完成通知
*/
@Override
public void inTaskStatusChange(String inNotifyUrl, DataLog task) {
if (task.isFinished()) {
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("RID", task.getBarcode());
paramMap.put("STORELOC_ID", task.getPosName());
try {
String requestParams = JsonUtil.toJsonStr(paramMap);
log.info(task.getBarcode() + "入库通知,参数" + requestParams);
String responseInfo = HttpHelper.postJson(inNotifyUrl, paramMap);
log.info(task.getBarcode() + "入库通知返回" + responseInfo);
//是否需要加入发送失败列表
} catch (Exception e) {
log.error("入库通知接口出错:" + e.getMessage());
}
}
}
/**
* 出库完成通知
*/
@Override
public void outTaskStatusChange(String outNotifyUrl, DataLog task) {
if (task.isStatus(OP_STATUS.OUT_BOX)) {
outBoxNotify(task);
}else if(task.isFinished()) {
outFinishedNotify(outNotifyUrl,task);
}
}
/**
* 出库完成通知
*/
private void outFinishedNotify(String outNotifyUrl,DataLog task){
/**
* {
* "RID":"",ReelID 单盘物料唯一码
* "STORELOC_ID": "",储位(库位)编码
* "TASK_ID": "",任务单号
* "TASK_SEQ": "" 任务行号
* }
*/
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("RID", task.getBarcode());
paramMap.put("STORELOC_ID", task.getPosName());
paramMap.put("TASK_ID", task.getSourceName());
paramMap.put("TASK_SEQ", task.getSubSourceId());
try {
String requestParams = JsonUtil.toJsonStr(paramMap);
log.info(task.getBarcode() + "出库完成通知,参数" + requestParams);
String responseInfo = HttpHelper.postJson(outNotifyUrl, paramMap);
log.info(task.getBarcode() + "出库完成通知返回" + responseInfo);
} catch (Exception e) {
log.error("出库完成通知接口出错:" + e.getMessage());
}
}
/**
* 下架完成通知
* @param task
*/
private void outBoxNotify(DataLog task){
if(Strings.isNotBlank(outBoxNotifyUrl)){
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("RID", task.getBarcode());
paramMap.put("MTRL_ID", task.getPartNumber());
try {
String requestParams = JsonUtil.toJsonStr(paramMap);
log.info(task.getBarcode() + "下架完成通知,参数" + requestParams);
String responseInfo = HttpHelper.postJson(outBoxNotifyUrl, paramMap);
log.info(task.getBarcode() + "下架完成通知返回" + responseInfo);
} catch (Exception e) {
log.error("下架完成通知接口出错:" + e.getMessage());
}
}
}
/**
* 入库判定
*
* @param inCheckUrl
* @param barcode
* @return
* @throws ValidateException
*/
@Override
public Barcode canPutIn(String inCheckUrl, Barcode barcode) throws ValidateException {
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("RID", barcode.getBarcode());
paramMap.put("MTRL_ID", barcode.getPartNumber());
try {
log.info(barcode.getBarcode() + "入库验证,参数" + JsonUtil.toJsonStr(paramMap));
String result = HttpHelper.postJson(inCheckUrl, paramMap);
log.info(barcode.getBarcode() + "入库验证返回" + result);
/**
* {
* "STATE":"1", 状态:1 入库判定OK ,0 失败 VARCHAR 1 Y 状态:1 入库判定OK ,0 失败
* "MSG":"OK", 状态信息 VARCHAR 50 Y 状态信息
* "INFO":{ 物料名称
* "MTRL_NAME":"", 物料规格 VARCHAR 100 Y 物料名称
* "MTRL_DESC":"", 物料规格 VARCHAR 100 N 物料规格
* "R_QTY":"", 数量 VARCHAR 10 Y 数量
* "FIFO_DATE":"" 先进先出判断日期 VARCHAR 20 Y 先进先出判断日期
* }
* }
*/
TianTongResult apiResult = JsonUtil.toObj(result, TianTongResult.class);
if (apiResult.isOk()) {
Map<String, Object> dataMap = (Map<String, Object>) apiResult.getInfo();
String qtyStr = getData(dataMap, "R_QTY");
if (Strings.isNotBlank(qtyStr)) {
int qty = Integer.valueOf(qtyStr);
if (qty > 0) {
barcode.setAmount(qty);
barcode = barcodeManager.saveBarcode(barcode);
}
}
return barcode;
} else {
throw new ValidateException("smfcore.mesApi.inCheck.error", "MES 返回NG["+apiResult.getState()+"]:" + apiResult.getMsg());
}
} catch (Exception e) {
log.error("入库验证接口出错:" + e.getMessage());
throw new ValidateException("smfcore.mesApi.inCheck.error", "MES验证出错:" + e.getMessage());
}
}
/**
* 任务单完成通知
* @param orderNotifyUrl
* @param liteOrder
*/
@Override
public void onOrderStatusChange(String orderNotifyUrl, LiteOrder liteOrder) {
if(liteOrder.isTaskFinished()){
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("TASK_ID", liteOrder.getOrderNo());
try {
log.info(liteOrder.getOrderNo() + "工单任务完成,通知MES" + JsonUtil.toJsonStr(paramMap));
String result = HttpHelper.postJson(orderNotifyUrl, paramMap);
log.info(liteOrder.getOrderNo() + "工单任务完成通知MES返回" + result);
} catch (Exception e) {
log.error("入库验证接口出错:" + e.getMessage());
throw new ValidateException("smfcore.mesApi.inCheck.error", "MES验证出错:" + e.getMessage());
}
}
}
}
package com.neotel.smfcore.custom.tiantong;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.neotel.smfcore.common.bean.ResultBean;
import com.neotel.smfcore.common.utils.JsonUtil;
import com.neotel.smfcore.common.utils.StorageConstants;
import com.neotel.smfcore.core.barcode.service.po.Barcode;
import com.neotel.smfcore.core.device.bean.BoxStatusBean;
import com.neotel.smfcore.core.device.bean.StatusBean;
import com.neotel.smfcore.core.device.util.DataCache;
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.order.service.po.LiteOrderItem;
import com.neotel.smfcore.core.storage.bean.UsageItem;
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.service.po.DataLog;
import com.neotel.smfcore.core.system.util.DevicesStatusUtil;
import com.neotel.smfcore.core.system.util.TaskService;
import com.neotel.smfcore.custom.tiantong.bean.TianTongResult;
import com.neotel.smfcore.security.annotation.AnonymousAccess;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
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 java.util.*;
@Slf4j
@RestController
@RequestMapping("/rest/api/tiantong")
public class TianTongController {
@Autowired
protected ILiteOrderManager liteOrderManager;
@Autowired
protected LiteOrderCache liteOrderCache;
@Autowired
private DataCache dataCache;
@Autowired
private IStoragePosManager storagePosManager;
@Autowired
private TaskService taskService;
@ApiOperation("创建需求单")
@RequestMapping("/outInfo")
@AnonymousAccess
public ResultBean outInfo(@RequestBody List<Map<String, Object>> paramList) {
log.info("{}收到数据为:{}", "创建需求单outInfo", JsonUtil.toJsonStr(paramList));
if (!paramList.isEmpty()) {
/**
* {
* "TASK_ID":""
* "TASK_TYPE":""
* "REF_TRX_CODE":""
* "TASK_DT":{
* [
* {
* "RID":"",
* "MTRL_ID":"",
* "STORELOC_ID":"",
* "R_QTY":""
* },
* {
* "RID":"",
* "MTRL_ID":"",
* "STORELOC_ID":"",
* "R_QTY":""
* },
* .......
* ]
* }
* }
*/
for (Map<String, Object> paramMap : paramList) {
if (paramMap.get("TASK_ID") == null) {
return ResultBean.newErrorResult(1, "smfcore.valueCanotNull", "{0}不能为空", new String[]{"TASK_ID"});
}
if (paramMap.get("TASK_DT") == null) {
return ResultBean.newErrorResult(1, "smfcore.valueCanotNull", "{0}不能为空", new String[]{"TASK_DT"});
}
String orderNo = paramMap.get("TASK_ID").toString(); //需求单号
LiteOrder order = liteOrderManager.findByOrderNo(orderNo);
if(order != null){
return ResultBean.newErrorResult(101, "smfcore.liteOrder.exist", "需求单{0}已存在", new String[]{orderNo});
}
boolean execute = false;
if (paramMap.get("execute") != null) {
execute = Boolean.valueOf(paramMap.get("execute").toString());
}
String source = paramMap.get("TASK_TYPE") == null ? "" : paramMap.get("TASK_TYPE").toString();
String so = paramMap.get("REF_TRX_CODE") == null ? "" : paramMap.get("REF_TRX_CODE").toString(); //工单号
//需求单详情数据
List<LiteOrderItem> orderItemList = new ArrayList<>();
List<Map> outItemList = JsonUtil.toList(paramMap.get("TASK_DT").toString(), Map.class);
if (!outItemList.isEmpty()) {
for (Map outItem : outItemList) {
LiteOrderItem orderItem = new LiteOrderItem();
if (outItem.get("RID") != null) {
String reelId = outItem.get("RID").toString();
orderItem.setRi(reelId); //料盘唯一码
}
if (outItem.get("R_QTY") != null) {
orderItem.setNeedNum(Integer.valueOf(outItem.get("R_QTY").toString()));
}
orderItemList.add(orderItem);
}
}
boolean singleOut = false;
if (paramMap.get("singleOut") != null) {
singleOut = Boolean.valueOf(paramMap.get("singleOut").toString());
}
//开始保存数据
LiteOrder liteOrder = new LiteOrder();
liteOrder.setOrderNo(orderNo);
liteOrder.setSource(source);
liteOrder.setSo(so);
liteOrder.setOrderItems(orderItemList);
liteOrder = liteOrderManager.createWithItems(liteOrder);
liteOrderCache.addOrderToMap(liteOrder);
if(execute){
liteOrderCache.checkOutLiteOrder(liteOrder.getOrderNo(),false, singleOut);
}
}
return ResultBean.newOkResult("");
}
return ResultBean.newErrorResult(1, "smfcore.valueCanotNull", "需求单信息不能为空");
}
@ApiOperation("取消出库任务单")
@RequestMapping("/cancelOutInfo")
@AnonymousAccess
public TianTongResult cancelOutInfo(@RequestBody Map<String, String> paramMap) {
String orderNo = paramMap.get("TASK_ID");
if (ObjectUtils.isEmpty(orderNo)) {
return TianTongResult.ngResult("TASK_ID 不能为空");
}
log.info("收到MES取消需求单"+orderNo+"的指令");
Collection<DataLog> queueTasks = taskService.getQueueTasks();
for (DataLog queueTask : queueTasks) {
if(queueTask.isWait() && queueTask.getSourceName().equals(orderNo)){
taskService.cancelTask(queueTask.getId());
}
}
LiteOrder order = liteOrderManager.findByOrderNo(orderNo);
if(order != null && order.isNew()){
//未执行过,直接关闭
liteOrderCache.closeOrder(orderNo);
}
return TianTongResult.okResult(new HashMap<>());
}
@ApiOperation("获取实时库存")
@RequestMapping("/inventory")
@AnonymousAccess
public TianTongResult inventory(@RequestBody Map<String, String> paramMap) {
List<StoragePos> storagePosList = storagePosManager.findNotEmpty();
if (storagePosList != null) {
List<Map<String, Object>> resultMapList = new ArrayList<>();
for (StoragePos storagePos : storagePosList) {
Barcode barcode = storagePos.getBarcode();
if (barcode != null) {
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("MTRL_ID", barcode.getBarcode());
resultMap.put("R_QTY", barcode.getAmount()+"");
resultMapList.add(resultMap);
}
}
return TianTongResult.okResult(resultMapList);
}
return TianTongResult.ngResult("未找到实时库存信息");
}
}
package com.neotel.smfcore.custom.tiantong.bean;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.HashMap;
/**
* @author sunke
* @date 2022/10/25 9:57 AM
*/
@Data
public class TianTongResult {
/**
* 状态:1 入库判定OK ,0 失败
*/
@JsonProperty("STATE")
private int state=-1;
@JsonProperty("MSG")
private String msg="";
@JsonProperty("INFO")
private Object info;
public boolean isOk(){
return state == 1;
}
public static TianTongResult okResult(Object data){
TianTongResult result = new TianTongResult();
result.setState(1);
result.setMsg("OK");
result.setInfo(data);
return result;
}
public static TianTongResult ngResult(String msg){
TianTongResult result = new TianTongResult();
result.setState(0);
result.setMsg(msg);
result.setInfo(new HashMap<>());
return result;
}
}
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!