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 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 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 res = wmsServerFeignClient.queryOrderAndDetls(params); CommonResponse result = mapToCommonResponse(res); if (result.getCode() == 200 && result.getData() instanceof Map) { @SuppressWarnings("unchecked") Map dataModel = (Map) 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 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 mapParams = toServerOrderMap(params); List> maps = Collections.singletonList(mapParams); log.info("新增/修改单据,请求参数: {}", JSONArray.toJSONString(maps)); Map 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 toServerOrderMap(ErpOpParams params) { Map 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> 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 toServerOrderItemMap(WmsOrderItemParam item) { Map 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 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 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 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 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 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 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 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 params) { Map 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 params) { Map 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 params) { Map 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 dataModel = (Map) 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(); 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 httpEntity = new HttpEntity<>(body, headers); ResponseEntity 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()); } } }