package com.vincent.rsf.openApi.service.impl;
|
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.cfg.CoercionAction;
|
import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
|
import com.vincent.rsf.framework.common.R;
|
import com.vincent.rsf.framework.exception.CoolException;
|
import com.vincent.rsf.openApi.config.PlatformProperties;
|
import com.vincent.rsf.openApi.entity.Loc;
|
import com.vincent.rsf.openApi.entity.constant.WmsConstant;
|
import com.vincent.rsf.openApi.entity.dto.CommonResponse;
|
import com.vincent.rsf.openApi.entity.constant.RcsConstant;
|
import com.vincent.rsf.openApi.entity.dto.SyncLocsDto;
|
import com.vincent.rsf.openApi.entity.dto.LocationAllocateResponse;
|
import com.vincent.rsf.openApi.entity.params.ExMsgCallbackParams;
|
import com.vincent.rsf.openApi.entity.params.LocSiteParams;
|
import com.vincent.rsf.openApi.entity.params.LocationAllocateParams;
|
import com.vincent.rsf.openApi.entity.params.RcsPubTaskParams;
|
import com.vincent.rsf.openApi.entity.params.SyncRcsLocsParam;
|
import com.vincent.rsf.openApi.entity.params.TaskReportParams;
|
import com.vincent.rsf.openApi.mapper.LocMapper;
|
import com.vincent.rsf.openApi.service.WmsRcsService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.http.HttpEntity;
|
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpMethod;
|
import org.springframework.http.ResponseEntity;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.web.client.RestTemplate;
|
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
|
|
@Slf4j
|
@Service("wmsRcsService")
|
public class WmsRcsServiceImpl extends ServiceImpl<LocMapper, Loc> implements WmsRcsService {
|
|
@Autowired
|
private PlatformProperties rcsApi;
|
@Autowired
|
private PlatformProperties.WmsApi wmsApi;
|
@Autowired
|
private RestTemplate restTemplate;
|
|
|
|
/**
|
* @author Ryan
|
* @date 2025/8/27
|
* @description: 任务下发
|
* @version 1.0
|
*/
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public CommonResponse pubTasks(RcsPubTaskParams params) {
|
/**RCS基础配置链接*/
|
String rcsUrl = rcsApi.getHost() + ":" + rcsApi.getPort() + RcsConstant.pubTask;
|
log.info("========== 开始下发任务到RCS ==========");
|
log.info("RCS请求地址:{}", rcsUrl);
|
if (params != null) {
|
log.info("批次编号:{}", params.getBatchNo());
|
if (params.getTasks() != null) {
|
log.info("任务数量:{}", params.getTasks().size());
|
}
|
}
|
log.info("请求参数:{}", JSONObject.toJSONString(params));
|
HttpHeaders headers = new HttpHeaders();
|
headers.add("Content-Type", "application/json");
|
headers.add("api-version", "v2.0");
|
HttpEntity httpEntity = new HttpEntity(params, headers);
|
long startTime = System.currentTimeMillis();
|
ResponseEntity<String> exchange = restTemplate.exchange(rcsUrl, HttpMethod.POST, httpEntity, String.class);
|
long endTime = System.currentTimeMillis();
|
log.info("RCS响应耗时:{}ms", (endTime - startTime));
|
log.info("RCS响应状态码:{}", exchange.getStatusCode());
|
log.info("RCS响应头:{}", exchange.getHeaders());
|
log.info("RCS响应体:{}", exchange.getBody());
|
if (Objects.isNull(exchange.getBody())) {
|
log.error("========== RCS任务下发失败 ==========");
|
log.error("RCS响应体为空,无法解析响应结果");
|
log.error("请求地址:{}", rcsUrl);
|
log.error("请求参数:{}", JSONObject.toJSONString(params));
|
throw new CoolException("任务下发失败,RCS响应体为空!!");
|
} else {
|
ObjectMapper objectMapper = new ObjectMapper();
|
objectMapper.coercionConfigDefaults()
|
.setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
|
try {
|
CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
|
log.info("RCS响应解析结果 - code:{},msg:{},data:{}",
|
result.getCode(), result.getMsg(), result.getData());
|
if (result.getCode() == 200) {
|
log.info("========== RCS任务下发成功 ==========");
|
return result;
|
} else {
|
log.error("========== RCS任务下发失败 ==========");
|
log.error("RCS返回错误 - code:{},msg:{},data:{}",
|
result.getCode(), result.getMsg(), result.getData());
|
return result;
|
}
|
} catch (JsonProcessingException e) {
|
log.error("========== RCS任务下发异常 ==========");
|
log.error("解析RCS响应失败,响应体:{}", exchange.getBody(), e);
|
throw new CoolException("解析RCS响应失败:" + e.getMessage());
|
} catch (Exception e) {
|
log.error("========== RCS任务下发异常 ==========");
|
log.error("任务下发过程中发生异常", e);
|
throw e;
|
}
|
}
|
}
|
|
/**
|
* @author Ryan
|
* @date 2025/8/27
|
* @description: 取消任务
|
* @version 1.0
|
*/
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public CommonResponse cancelTasks(Map<String, Object> params) {
|
/**RCS基础配置链接*/
|
String rcsUrl = rcsApi.getHost() + ":" + rcsApi.getPort() + RcsConstant.cancelTask;
|
log.info("========== 开始取消RCS任务(open-rcs接口) ==========");
|
log.info("RCS取消任务请求地址:{}", rcsUrl);
|
log.info("RCS取消任务请求参数:{}", JSONObject.toJSONString(params));
|
|
// 打印详细的请求参数信息
|
if (params != null) {
|
Object batchNo = params.get("batchNo");
|
Object tasks = params.get("tasks");
|
if (batchNo != null) {
|
log.info("批次编号:{}", batchNo);
|
}
|
if (tasks != null) {
|
if (tasks instanceof List) {
|
log.info("任务数量:{}", ((List<?>) tasks).size());
|
log.info("任务编号列表:{}", tasks);
|
} else {
|
log.info("任务参数:{}", tasks);
|
}
|
}
|
}
|
|
HttpHeaders headers = new HttpHeaders();
|
headers.add("Content-Type", "application/json");
|
headers.add("api-version", "v2.0");
|
HttpEntity httpEntity = new HttpEntity(params, headers);
|
|
long startTime = System.currentTimeMillis();
|
ResponseEntity<String> exchange = restTemplate.exchange(rcsUrl, HttpMethod.POST, httpEntity, String.class);
|
long endTime = System.currentTimeMillis();
|
|
log.info("RCS取消任务响应耗时:{}ms", (endTime - startTime));
|
log.info("RCS取消任务响应状态码:{}", exchange.getStatusCode());
|
log.info("RCS取消任务响应头:{}", exchange.getHeaders());
|
log.info("RCS取消任务响应体:{}", exchange.getBody());
|
if (Objects.isNull(exchange.getBody())) {
|
throw new CoolException("取消任务失败!!");
|
} else {
|
ObjectMapper objectMapper = new ObjectMapper();
|
objectMapper.coercionConfigDefaults()
|
.setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
|
try {
|
CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
|
if (result.getCode() == 200) {
|
log.info("========== RCS任务取消成功(open-rcs接口) ==========");
|
log.info("成功取消的任务编号:{}", params.get("tasks"));
|
return result;
|
} else {
|
log.error("========== RCS任务取消失败(open-rcs接口) ==========");
|
log.error("RCS返回错误码:{},错误信息:{}", result.getCode(), result.getMsg());
|
throw new CoolException("取消任务失败!!" + (result.getMsg() != null ? ":" + result.getMsg() : ""));
|
}
|
} catch (JsonProcessingException e) {
|
log.error("RCS取消任务响应解析失败:{}", e.getMessage(), e);
|
throw new CoolException("RCS取消任务响应解析失败:" + e.getMessage());
|
}
|
}
|
}
|
|
/**
|
* @author Ryan
|
* @date 2025/8/27
|
* @description: RCS状态回写
|
* @version 1.0
|
*/
|
@Override
|
public CommonResponse callBackEvent(ExMsgCallbackParams params) {
|
// 参数校验
|
if (Objects.isNull(params)) {
|
log.error("RCS回调事件参数为空!");
|
throw new CoolException("参数不能为空!!");
|
}
|
|
// 详细记录接收到的参数
|
log.info("RCS回调事件接收参数 - seqNum: {}, eventType: {}, robotCode: {}, zpallet: {}",
|
params.getSeqNum(), params.getEventType(), params.getRobotCode(), params.getZpallet());
|
|
// 检查关键字段是否为空
|
if (Objects.isNull(params.getSeqNum()) || params.getSeqNum().isEmpty()) {
|
log.warn("RCS回调事件参数seqNum为空!完整参数:{}", JSONObject.toJSONString(params));
|
}
|
if (Objects.isNull(params.getEventType()) || params.getEventType().isEmpty()) {
|
log.warn("RCS回调事件参数eventType为空!完整参数:{}", JSONObject.toJSONString(params));
|
}
|
|
String callUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.callBack;
|
/**WMS基础配置链接*/
|
log.info("任务执行状态上报,请求地址: {}, 请求参数: {}", callUrl , JSONObject.toJSONString(params));
|
HttpHeaders headers = new HttpHeaders();
|
headers.add("Content-Type", "application/json");
|
headers.add("api-version", "v2.0");
|
HttpEntity httpEntity = new HttpEntity(params, headers);
|
ResponseEntity<String> exchange = restTemplate.exchange(callUrl, HttpMethod.POST, httpEntity, String.class);
|
log.info("任务执行状态上报,响应结果: {}", exchange);
|
if (Objects.isNull(exchange.getBody())) {
|
return new CommonResponse();
|
} else {
|
ObjectMapper objectMapper = new ObjectMapper();
|
objectMapper.coercionConfigDefaults()
|
.setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
|
try {
|
CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
|
if (result.getCode() == 200) {
|
return result;
|
} else {
|
return result;
|
// throw new CoolException("任务执行状态上报失败!!");
|
}
|
} catch (JsonProcessingException e) {
|
throw new CoolException(e.getMessage());
|
}
|
}
|
}
|
|
/**
|
* @author Ryan
|
* @date 2025/8/27
|
* @description: 库位信息同步
|
* @version 1.0
|
*/
|
@Override
|
public List<SyncLocsDto> syncLocs(SyncRcsLocsParam params) {
|
return syncRcsLocs(params);
|
}
|
|
|
/**
|
* @author Ryan
|
* @date 2025/11/10
|
* @description: 修改库位或站点状态
|
* @version 1.0
|
*/
|
@Override
|
public R modifyLocOrSite(LocSiteParams params) {
|
/**RCS基础配置链接*/
|
String rcsUrl = rcsApi.getHost() + ":" + rcsApi.getPort() + RcsConstant.modifystatus;
|
log.info("库位或站点状态修改,请求地址: {}, 请求参数: {}", rcsUrl , JSONObject.toJSONString(params));
|
HttpHeaders headers = new HttpHeaders();
|
headers.add("Content-Type", "application/json");
|
headers.add("api-version", "v2.0");
|
HttpEntity httpEntity = new HttpEntity(params, headers);
|
ResponseEntity<String> exchange = restTemplate.exchange(rcsUrl, HttpMethod.POST, httpEntity, String.class);
|
log.info("库位或站点状态修改,响应结果: {}", exchange);
|
if (Objects.isNull(exchange.getBody())) {
|
throw new CoolException("状态修改失败!!");
|
} else {
|
ObjectMapper objectMapper = new ObjectMapper();
|
objectMapper.coercionConfigDefaults()
|
.setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
|
try {
|
CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
|
if (result.getCode() == 200) {
|
return R.ok();
|
} else {
|
throw new CoolException("状态修改失败!!");
|
}
|
} catch (JsonProcessingException e) {
|
throw new CoolException(e.getMessage());
|
}
|
}
|
}
|
|
/**
|
* @author Ryan
|
* @date 2025/8/28
|
* @description: 拉取RCS库位,同步至本地
|
* @version 1.0
|
*/
|
@Transactional(rollbackFor = Exception.class)
|
public List<SyncLocsDto> syncRcsLocs(SyncRcsLocsParam params) {
|
/**RCS基础配置链接*/
|
String rcsUrl = rcsApi.getHost() + ":" + rcsApi.getPort() + RcsConstant.syncLocs;
|
log.info("任务下发,请求地址2: {}, 请求参数: {}", rcsUrl , JSONObject.toJSONString(params));
|
HttpHeaders headers = new HttpHeaders();
|
headers.add("Content-Type", "application/json");
|
headers.add("api-version", "v2.0");
|
HttpEntity httpEntity = new HttpEntity(params, headers);
|
ResponseEntity<String> exchange = restTemplate.exchange(rcsUrl, HttpMethod.POST, httpEntity, String.class);
|
log.info("任务下发后,响应结果: {}", exchange);
|
if (Objects.isNull(exchange.getBody())) {
|
throw new CoolException("任务下发失败!!");
|
} else {
|
ObjectMapper objectMapper = new ObjectMapper();
|
objectMapper.coercionConfigDefaults()
|
.setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
|
try {
|
CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
|
if (result.getCode() == 200) {
|
JSONObject jsonObject = JSONObject.parseObject(exchange.getBody()).getJSONObject("data");
|
List<SyncLocsDto> array = JSONArray.parseArray(jsonObject.getJSONArray("records").toJSONString(), SyncLocsDto.class);
|
log.info("records结果: {}", array);
|
return array;
|
} else {
|
throw new CoolException("任务下发失败!!");
|
}
|
} catch (JsonProcessingException e) {
|
throw new CoolException(e.getMessage());
|
}
|
}
|
}
|
|
/**
|
* @author Ryan
|
* @date 2026/2/3
|
* @description: 任务执行通知上报(RCS回调接口)
|
* @version 1.0
|
*/
|
@Override
|
public CommonResponse reportTask(TaskReportParams params) {
|
log.info("RCS回调,请求参数: {}", JSONObject.toJSONString(params));
|
|
// 参数校验
|
if (Objects.isNull(params)) {
|
throw new CoolException("参数不能为空!!");
|
}
|
if (Objects.isNull(params.getBatchNo()) || params.getBatchNo().isEmpty()) {
|
throw new CoolException("任务批次不能为空!!");
|
}
|
if (Objects.isNull(params.getTaskNo()) || params.getTaskNo().isEmpty()) {
|
throw new CoolException("任务编号不能为空!!");
|
}
|
if (Objects.isNull(params.getTimestamp()) || params.getTimestamp().isEmpty()) {
|
throw new CoolException("时间戳不能为空!!");
|
}
|
|
// 将TaskReportParams转换为ExMsgParams格式(taskNo -> seqNum)
|
// 根据RCS新接口规范,taskNo对应旧接口的seqNum
|
JSONObject exMsgParams = new JSONObject();
|
exMsgParams.put("seqNum", params.getTaskNo()); // taskNo映射到seqNum
|
// eventType设置为END,表示任务完成(根据业务需求可能需要调整)
|
exMsgParams.put("eventType", "END");
|
exMsgParams.put("robotCode", null);
|
exMsgParams.put("zpallet", null);
|
|
// 将任务上报回调转发到WMS系统
|
String callUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.callBack;
|
log.info("RCS回调-WMS-SERVER任务上报-,请求地址: {}, 转换后参数: {}", callUrl, exMsgParams.toJSONString());
|
HttpHeaders headers = new HttpHeaders();
|
headers.add("Content-Type", "application/json");
|
headers.add("api-version", "v2.0");
|
HttpEntity httpEntity = new HttpEntity(exMsgParams, headers);
|
ResponseEntity<String> exchange = restTemplate.exchange(callUrl, HttpMethod.POST, httpEntity, String.class);
|
log.info("RCS回调-WMS-SERVER任务上报-,响应结果: {}", exchange);
|
|
if (Objects.isNull(exchange.getBody())) {
|
// 回调失败,抛出异常
|
log.error("========== RCS回调-WMS-SERVER任务上报-失败 ==========");
|
log.error("RCS回调-WMS-SERVER任务上报-响应体为空,无法解析响应结果");
|
log.error("RCS回调-WMS-SERVER任务上报-请求地址:{}", callUrl);
|
log.error("RCS回调-WMS-SERVER任务上报-请求参数:{}", exMsgParams.toJSONString());
|
log.error("RCS回调-WMS-SERVER任务上报-失败的任务编号:{},批次:{}", params.getTaskNo(), params.getBatchNo());
|
throw new CoolException("RCS回调-WMS-SERVER任务上报-失败,WMS响应体为空!任务编号:" + params.getTaskNo() + ",批次:" + params.getBatchNo());
|
} else {
|
ObjectMapper objectMapper = new ObjectMapper();
|
objectMapper.coercionConfigDefaults()
|
.setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
|
try {
|
CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
|
if (result.getCode() == 200) {
|
log.info("RCS回调-WMS-SERVER任务上报-成功,任务编号:{},批次:{}", params.getTaskNo(), params.getBatchNo());
|
return result;
|
} else {
|
log.warn("RCS回调-WMS-SERVER任务上报-返回非200状态,任务编号:{},批次:{},响应:{}", params.getTaskNo(), params.getBatchNo(), exchange.getBody());
|
return result;
|
}
|
} catch (JsonProcessingException e) {
|
log.error("RCS回调-WMS-SERVER任务上报-响应解析失败,任务编号:{},批次:{},错误:{}", params.getTaskNo(), params.getBatchNo(), e.getMessage());
|
// 解析失败时返回成功响应,避免RCS重复回调
|
CommonResponse response = new CommonResponse();
|
response.setCode(200);
|
response.setMsg("接收成功");
|
return response;
|
}
|
}
|
}
|
|
/**
|
* @author Ryan
|
* @date 2026/2/6
|
* @description: 申请入库任务,分配库位
|
* @version 1.0
|
*/
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public R allocateLocation(LocationAllocateParams params) {
|
log.info("========== 开始申请入库任务,分配库位 ==========");
|
log.info("料箱码:{},入库站点:{},入库类型:{}", params.getBarcode(), params.getStaNo(), params.getType());
|
|
// 调用WMS server内部接口进行库位分配
|
String wmsUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + "/rsf-server/wcs/allocate/location";
|
log.info("WMS请求地址:{}", wmsUrl);
|
|
// 构建请求参数
|
JSONObject requestParams = new JSONObject();
|
requestParams.put("barcode", params.getBarcode());
|
requestParams.put("staNo", params.getStaNo());
|
requestParams.put("type", params.getType());
|
log.info("请求参数:{}", requestParams.toJSONString());
|
|
HttpHeaders headers = new HttpHeaders();
|
headers.add("Content-Type", "application/json");
|
HttpEntity httpEntity = new HttpEntity(requestParams, headers);
|
|
long startTime = System.currentTimeMillis();
|
ResponseEntity<String> exchange = restTemplate.exchange(wmsUrl, HttpMethod.POST, httpEntity, String.class);
|
long endTime = System.currentTimeMillis();
|
log.info("WMS响应耗时:{}ms", (endTime - startTime));
|
log.info("WMS响应状态码:{}", exchange.getStatusCode());
|
log.info("WMS响应体:{}", exchange.getBody());
|
|
if (Objects.isNull(exchange.getBody())) {
|
log.error("========== 申请入库任务失败 ==========");
|
log.error("WMS响应体为空,无法解析响应结果");
|
return R.error("申请入库任务失败,WMS响应体为空!!");
|
} else {
|
ObjectMapper objectMapper = new ObjectMapper();
|
objectMapper.coercionConfigDefaults()
|
.setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
|
try {
|
JSONObject responseJson = JSONObject.parseObject(exchange.getBody());
|
Integer code = responseJson.getInteger("code");
|
String msg = responseJson.getString("msg");
|
|
if (code != null && code == 200) {
|
JSONObject data = responseJson.getJSONObject("data");
|
if (data != null) {
|
String locNo = data.getString("locNo");
|
log.info("========== 申请入库任务成功 ==========");
|
log.info("分配库位号:{}", locNo);
|
|
LocationAllocateResponse response = new LocationAllocateResponse();
|
response.setLocNo(locNo);
|
return R.ok(response);
|
} else {
|
log.error("========== 申请入库任务失败 ==========");
|
log.error("响应数据为空");
|
return R.error("申请入库任务失败,响应数据为空!!");
|
}
|
} else {
|
log.error("========== 申请入库任务失败 ==========");
|
log.error("WMS返回错误 - code:{},msg:{}", code, msg);
|
return R.error(msg != null ? msg : "申请入库任务失败!!");
|
}
|
} catch (Exception e) {
|
log.error("========== 申请入库任务异常 ==========");
|
log.error("解析WMS响应失败,响应体:{}", exchange.getBody(), e);
|
return R.error("解析WMS响应失败:" + e.getMessage());
|
}
|
}
|
}
|
}
|