package com.vincent.rsf.openApi.service.impl;
|
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
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.exception.CoolException;
|
import com.vincent.rsf.openApi.config.PlatformProperties;
|
import com.vincent.rsf.openApi.entity.constant.WmsConstant;
|
import com.vincent.rsf.openApi.entity.dto.CommonResponse;
|
import com.vincent.rsf.openApi.entity.dto.ErpCommonResponse;
|
import com.vincent.rsf.openApi.entity.dto.ResultData;
|
import com.vincent.rsf.openApi.entity.dto.OrderDto;
|
import com.vincent.rsf.openApi.entity.params.ErpMatnrParms;
|
import com.vincent.rsf.openApi.entity.params.ErpOpParams;
|
import com.vincent.rsf.openApi.entity.params.ReportParams;
|
import com.vincent.rsf.openApi.entity.params.WmsOrderItemParam;
|
import com.vincent.rsf.openApi.feign.wms.WmsServerFeignClient;
|
import com.vincent.rsf.openApi.service.WmsErpService;
|
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.web.client.RestTemplate;
|
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
@Slf4j
|
@Service("WmsErpService")
|
public class WmsErpServiceImpl implements WmsErpService {
|
|
@Autowired
|
private PlatformProperties.WmsApi wmsApi;
|
|
@Autowired
|
private PlatformProperties.ErpApi erpApi;
|
|
@Autowired
|
private RestTemplate restTemplate;
|
|
@Autowired
|
private WmsServerFeignClient wmsServerFeignClient;
|
|
/**
|
* 可选:改用 OpenFeign 调用 ERP 上报(订单完成回写、盘点差异修改)时启用。
|
* 1)增加 import:com.vincent.rsf.openApi.feign.erp.ErpReportFeignClient;
|
* 2)取消下面两行注释,注入 ErpReportFeignClient;
|
* 3)在 reportOrders、reportCheck 中注释掉本方法内整段 HttpEntity/restTemplate 请求,改为使用下面注释中的 erpReportFeignClient.report(params) 及响应解析逻辑。
|
*/
|
// @Autowired
|
// private ErpReportFeignClient erpReportFeignClient;
|
|
/**
|
* 将 Feign 返回的 Map(或 R)转为 CommonResponse,符合 8.2.3:code、msg、data(含 result)。
|
* 无法解析或非成功(code!=200)时直接 throw CoolException,不返回错误体。
|
*/
|
private CommonResponse mapToCommonResponse(Map<String, Object> map) {
|
if (map == null) {
|
throw new CoolException("请求失败");
|
}
|
Object c = map.get("code");
|
int code = c instanceof Number ? ((Number) c).intValue() : 500;
|
if (code != 200) {
|
String msg = map.get("msg") != null ? map.get("msg").toString() : "请求失败";
|
throw new CoolException(msg);
|
}
|
CommonResponse r = new CommonResponse();
|
r.setCode(200);
|
r.setMsg(map.get("msg") != null ? map.get("msg").toString() : "操作成功");
|
Object rawData = map.get("data");
|
if (rawData == null) {
|
r.setData(ResultData.success());
|
} else {
|
Map<String, Object> dataModel = new LinkedHashMap<>();
|
dataModel.put("result", ResultData.SUCCESS);
|
dataModel.put("data", rawData);
|
r.setData(dataModel);
|
}
|
return r;
|
}
|
|
/**
|
* 获取订单明细
|
*
|
* @param params
|
* @return
|
*/
|
@Override
|
public CommonResponse getOrderInfo(ErpOpParams params) {
|
if (Objects.isNull(params.getOrderNo()) || params.getOrderNo().isEmpty()) {
|
throw new CoolException("订单号不能为空!!");
|
}
|
log.info("查询订单信息及状态,请求参数: {}", JSONObject.toJSONString(params));
|
Map<String, Object> res = wmsServerFeignClient.queryOrderAndDetls(params);
|
CommonResponse result = mapToCommonResponse(res);
|
if (result.getCode() == 200 && result.getData() instanceof Map) {
|
@SuppressWarnings("unchecked")
|
Map<String, Object> dataModel = (Map<String, Object>) result.getData();
|
Object inner = dataModel.get("data");
|
if (inner != null) {
|
JSONObject object = JSONObject.parseObject(JSONObject.toJSONString(inner));
|
OrderDto dto = new OrderDto();
|
dto.setOrderNo(object.getString("code"))
|
.setAnfme(object.getDouble("anfme"))
|
.setType(object.getString("type"))
|
.setWkType(object.getString("wkType"))
|
.setQty(object.getDouble("qty"))
|
.setPoCode(object.getString("poCode"))
|
.setExceStatus(object.getShort("exceStatus"))
|
.setWorkQty(object.getDouble("workQty"));
|
Map<String, Object> wrap = new LinkedHashMap<>();
|
wrap.put("result", ResultData.SUCCESS);
|
wrap.put("data", dto);
|
result.setData(wrap);
|
}
|
}
|
return result;
|
}
|
|
/**
|
* 新增单据(兼容修改、取消):8.3 入/出库通知单下发。operateType=3 时按取消处理。
|
* 以 8.3 文档字段为主,转发立库时映射为服务端 SyncOrderParams 字段。
|
*/
|
@Override
|
public CommonResponse addOrUpdateOrder(ErpOpParams params) {
|
if (Objects.isNull(params.getOrderNo()) || params.getOrderNo().isEmpty()) {
|
throw new CoolException("订单号不能为空!!");
|
}
|
if (Integer.valueOf(3).equals(params.getOperateType())) {
|
log.info("order/add 收到 operateType=3,走统一取消逻辑: {}", params.getOrderNo());
|
return doCancel(params);
|
}
|
Map<String, Object> mapParams = toServerOrderMap(params);
|
List<Map<String, Object>> maps = Collections.singletonList(mapParams);
|
log.info("新增/修改单据,请求参数: {}", JSONArray.toJSONString(maps));
|
Map<String, Object> res = wmsServerFeignClient.updateOrderDetls(maps);
|
CommonResponse r = mapToCommonResponse(res);
|
// 8.3.3:data 仅含 result,不返回业务载荷
|
r.setData(ResultData.success());
|
return r;
|
}
|
|
/** 8.3 参数转为立库 SyncOrderParams 结构(orderNo/type/wkType/anfme/arrTime/orderItems 等) */
|
private Map<String, Object> toServerOrderMap(ErpOpParams params) {
|
Map<String, Object> m = new HashMap<>();
|
m.put("orderNo", params.getOrderNo());
|
m.put("wkType", params.getWkType());
|
m.put("type", params.getOrderType() != null ? String.valueOf(params.getOrderType()) : null);
|
m.put("orderId", params.getOrderId());
|
double anfmeSum = 0;
|
if (params.getOrderItems() != null) {
|
List<Map<String, Object>> items = params.getOrderItems().stream()
|
.map(this::toServerOrderItemMap)
|
.collect(Collectors.toList());
|
m.put("orderItems", items);
|
for (WmsOrderItemParam item : params.getOrderItems()) {
|
anfmeSum += parseAnfme(item.getAnfme());
|
}
|
} else {
|
m.put("orderItems", Collections.emptyList());
|
}
|
m.put("anfme", anfmeSum);
|
if (params.getBusinessTime() != null) {
|
m.put("arrTime", new Date(params.getBusinessTime() * 1000));
|
} else if (params.getCreateTime() != null) {
|
m.put("arrTime", new Date(params.getCreateTime() * 1000));
|
}
|
return m;
|
}
|
|
private Map<String, Object> toServerOrderItemMap(WmsOrderItemParam item) {
|
Map<String, Object> m = new HashMap<>();
|
m.put("matnr", item.getMatNr());
|
m.put("maktx", item.getMakTx());
|
m.put("platItemId", item.getLineId());
|
m.put("anfme", parseAnfme(item.getAnfme()));
|
m.put("spec", item.getSpec());
|
m.put("model", item.getModel());
|
m.put("unit", item.getUnit());
|
m.put("batch", item.getBatch());
|
return m;
|
}
|
|
private static double parseAnfme(String anfme) {
|
if (anfme == null || anfme.trim().isEmpty()) {
|
return 0;
|
}
|
try {
|
return Double.parseDouble(anfme.trim());
|
} catch (NumberFormatException e) {
|
return 0;
|
}
|
}
|
|
/**
|
* 取消订单/取消单据。与 /order/add(operateType=3)共用同一套取消逻辑,转发立库 sync/orders/delete。
|
*/
|
@Override
|
public CommonResponse orderCancel(ErpOpParams params) {
|
if (Objects.isNull(params.getOrderNo()) || params.getOrderNo().isEmpty()) {
|
throw new CoolException("订单号不能为空!!");
|
}
|
return doCancel(params);
|
}
|
|
/** 统一取消逻辑:/order/add(operateType=3) 与 /order/cancel、/order/del 均走此方法;8.3.3 data 仅含 result */
|
private CommonResponse doCancel(ErpOpParams params) {
|
log.info("取消单据,请求参数: {}", JSONObject.toJSONString(params));
|
Map<String, Object> one = new HashMap<>();
|
one.put("orderNo", params.getOrderNo());
|
one.put("orderItems", params.getOrderItems() != null ? params.getOrderItems().stream()
|
.map(this::toServerOrderItemMap)
|
.collect(Collectors.toList()) : Collections.emptyList());
|
Map<String, Object> res = wmsServerFeignClient.orderDel(Collections.singletonList(one));
|
CommonResponse r = mapToCommonResponse(res);
|
r.setData(ResultData.success());
|
return r;
|
}
|
|
/**
|
* 物料信息修改
|
*
|
* @param params
|
* @return
|
*/
|
@Override
|
public CommonResponse syncMatnrs(ErpMatnrParms params) {
|
if (Objects.isNull(params.getMatnr())) {
|
throw new CoolException("物料编码不能为空!!");
|
}
|
if (Objects.isNull(params.getMaktx())) {
|
throw new CoolException("物料名称不能为空!!");
|
}
|
log.info("物料修改,请求参数: {}", JSONObject.toJSONString(params));
|
Map<String, Object> res = wmsServerFeignClient.syncMatnrs(params);
|
return mapToCommonResponse(res);
|
}
|
|
/**
|
* @author Ryan
|
* @date 2025/10/27
|
* @description: 上报单据状态
|
* @version 1.0
|
*/
|
@Override
|
public CommonResponse reportOrders(ReportParams params) {
|
if (Objects.isNull(params)) {
|
throw new CoolException("参数不能为空!!");
|
}
|
/**WMS基础配置链接*/
|
String rcsUrl = erpApi.getHost() + ":" + erpApi.getPort() + WmsConstant.REPORT_ORDER_CALLBACK;
|
HttpHeaders headers = new HttpHeaders();
|
headers.add("Content-Type", "application/json");
|
headers.add("api-version", "v2.0");
|
HttpEntity httpEntity = new HttpEntity(params, headers);
|
log.info("已完成订单上传:{}, 请求参数: {}", rcsUrl, httpEntity.getBody());
|
|
ResponseEntity<String> exchange = restTemplate.exchange(rcsUrl, HttpMethod.POST, httpEntity, String.class);
|
log.info("已完成订单上传,请求结果: {}", exchange.getBody());
|
if (Objects.isNull(exchange.getBody())) {
|
throw new CoolException("上传失败!!");
|
} else {
|
CommonResponse commonResponse = new CommonResponse();
|
ErpCommonResponse result = JSONObject.parseObject(exchange.getBody(), ErpCommonResponse.class);
|
if (!result.getIsError()) {
|
commonResponse.setCode(200).setMsg(result.getMessage()).setData(result.getData());
|
return commonResponse;
|
} else {
|
throw new CoolException("上传失败!!");
|
}
|
}
|
// Map<String, Object> res = erpReportFeignClient.report(params);
|
// if (res == null) throw new CoolException("上传失败!!");
|
// Object c = res.get("code"); int code = c instanceof Number ? ((Number) c).intValue() : 500;
|
// if (code != 200) throw new CoolException("上传失败!!");
|
// CommonResponse commonResponse = new CommonResponse();
|
// commonResponse.setCode(200).setMsg(String.valueOf(res.get("msg"))).setData(res.get("data"));
|
// return commonResponse;
|
}
|
|
/**
|
* @author Ryan
|
* @date 2025/10/27
|
* @description: 盘点差异单修改
|
* @version 1.0
|
*/
|
@Override
|
public CommonResponse reportCheck(ReportParams params) {
|
if (Objects.isNull(params)) {
|
throw new CoolException("参数不能为空!!");
|
}
|
/**WMS基础配置链接*/
|
String rcsUrl = erpApi.getHost() + ":" + erpApi.getPort() + WmsConstant.REPORT_ORDER_CALLBACK;
|
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.getBody());
|
if (Objects.isNull(exchange.getBody())) {
|
throw new CoolException("修改失败!!");
|
} else {
|
CommonResponse commonResponse = new CommonResponse();
|
ErpCommonResponse result = JSONObject.parseObject(exchange.getBody(), ErpCommonResponse.class);
|
if (!result.getIsError()) {
|
commonResponse.setCode(200).setMsg(result.getMessage()).setData(result.getData());
|
return commonResponse;
|
} else {
|
throw new CoolException("修改失败!!");
|
}
|
}
|
// Map<String, Object> res = erpReportFeignClient.report(params);
|
// if (res == null) throw new CoolException("修改失败!!");
|
// Object c = res.get("code"); int code = c instanceof Number ? ((Number) c).intValue() : 500;
|
// if (code != 200) throw new CoolException("修改失败!!");
|
// CommonResponse commonResponse = new CommonResponse();
|
// commonResponse.setCode(200).setMsg(String.valueOf(res.get("msg"))).setData(res.get("data"));
|
// return commonResponse;
|
}
|
|
@Override
|
public CommonResponse queryLocsDetls(Map<String, Object> params) {
|
Map<String, Object> p = params == null ? new HashMap<>() : params;
|
log.info("库位信息查询,请求参数: {}", JSONObject.toJSONString(p));
|
return mapToCommonResponse(wmsServerFeignClient.queryLocsDetls(p));
|
}
|
|
/** 8.4 库存明细查询:返回值 data 为对象数组,不包 result 外层 */
|
@Override
|
public CommonResponse inventoryDetails(Map<String, Object> params) {
|
Map<String, Object> p = params == null ? new HashMap<>() : params;
|
log.info("库存明细查询,请求参数: {}", JSONObject.toJSONString(p));
|
CommonResponse r = mapToCommonResponse(wmsServerFeignClient.inventoryDetails(p));
|
unwrapDataToArray(r);
|
return r;
|
}
|
|
/** 8.5 库存汇总查询:返回值 data 为对象数组,不包 result 外层 */
|
@Override
|
public CommonResponse inventorySummary(Map<String, Object> params) {
|
Map<String, Object> p = params == null ? new HashMap<>() : params;
|
log.info("库存汇总查询,请求参数: {}", JSONObject.toJSONString(p));
|
CommonResponse r = mapToCommonResponse(wmsServerFeignClient.inventorySummary(p));
|
unwrapDataToArray(r);
|
return r;
|
}
|
|
/** 8.4/8.5 规范:data 为对象数组,将 { result, data: array } 改为 data = array */
|
private void unwrapDataToArray(CommonResponse r) {
|
if (r.getData() instanceof Map) {
|
@SuppressWarnings("unchecked")
|
Map<String, Object> dataModel = (Map<String, Object>) r.getData();
|
Object inner = dataModel.get("data");
|
if (inner != null) {
|
r.setData(inner);
|
}
|
}
|
}
|
|
@Override
|
public CommonResponse forwardToWms(String wmsPath, Object body) {
|
String url = wmsApi.getHost() + ":" + wmsApi.getPort() + wmsPath;
|
Object payload = body != null ? body : new HashMap<String, Object>();
|
log.info("转发请求: {}, 请求体长度: {}", url, payload instanceof List ? ((List<?>) payload).size() : 1);
|
return postToWms(url, payload);
|
}
|
|
/** 统一转发并解析为 CommonResponse */
|
private CommonResponse postToWms(String url, Object body) {
|
HttpHeaders headers = new HttpHeaders();
|
headers.add("Content-Type", "application/json");
|
headers.add("api-version", "v2.0");
|
HttpEntity<Object> httpEntity = new HttpEntity<>(body, headers);
|
ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
|
if (Objects.isNull(exchange.getBody())) {
|
throw new CoolException("请求失败!!");
|
}
|
ObjectMapper objectMapper = new ObjectMapper();
|
objectMapper.coercionConfigDefaults().setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
|
try {
|
return objectMapper.readValue(exchange.getBody(), CommonResponse.class);
|
} catch (JsonProcessingException e) {
|
throw new CoolException("解析响应失败:" + e.getMessage());
|
}
|
}
|
|
}
|