chen.lin
2 天以前 9140aee230de0ef41de9682a9353fbd372e2bcaa
rsf-open-api/src/main/java/com/vincent/rsf/openApi/service/impl/WmsErpServiceImpl.java
@@ -1,5 +1,6 @@
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;
@@ -9,8 +10,14 @@
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;
@@ -22,6 +29,7 @@
import org.springframework.web.client.RestTemplate;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Service("WmsErpService")
@@ -31,7 +39,51 @@
    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;
    }
    /**
     * 获取订单明细
@@ -44,122 +96,300 @@
        if (Objects.isNull(params.getOrderNo()) || params.getOrderNo().isEmpty()) {
            throw new CoolException("订单号不能为空!!");
        }
        /**WMS基础配置链接*/
        String rcsUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.QUERY_ORDER_AND_DETLS;
        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) {
                    JSONObject object = JSONObject.parseObject(JSONObject.toJSONString(result.getData()));
                    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"));
                    result.setData(dto);
                    return result;
                } else {
                    throw new CoolException("查询失败!!");
                }
            } catch (JsonProcessingException e) {
                throw new CoolException(e.getMessage());
        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 updateOrderDetl(ErpOpParams params) {
        if (Objects.isNull(params.getOrderNo()) || params.getOrderNo().isEmpty()) {
            throw new CoolException("订单号不能为空!!");
    public CommonResponse syncMatnrs(ErpMatnrParms params) {
        if (Objects.isNull(params.getMatnr())) {
            throw new CoolException("物料编码不能为空!!");
        }
        /**WMS基础配置链接*/
        String wmsUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.MODIFY_ORDER_DETLS;
        log.info("修改订单信息及状态: {}, 请求参数: {}", wmsUrl, JSONObject.toJSONString(params));
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json");
        headers.add("api-version", "v2.0");
        List<Map<String, Object>> maps = new ArrayList<>();
        Map<String, Object> mapParams = new HashMap<>();
        mapParams.put("orderNo", Arrays.asList(params.getOrderNo()));
        mapParams.put("anfme", params.getAnfme());
        mapParams.put("type", params.getType());
        mapParams.put("wkType", params.getWkType());
        mapParams.put("exceStatus", params.getExceStatus());
        mapParams.put("orderItems", params.getOrderItems());
        maps.add(mapParams);
        HttpEntity httpEntity = new HttpEntity(maps, headers);
        ResponseEntity<String> exchange = restTemplate.exchange(wmsUrl, 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 object = JSONObject.parseObject(JSONObject.toJSONString(result.getData()));
                    return result;
                } else {
                    throw new CoolException("查询失败!!");
                }
            } catch (JsonProcessingException e) {
                throw new CoolException(e.getMessage());
            }
        if (Objects.isNull(params.getMaktx())) {
            throw new CoolException("物料名称不能为空!!");
        }
        log.info("物料修改,请求参数: {}", JSONObject.toJSONString(params));
        Map<String, Object> res = wmsServerFeignClient.syncMatnrs(params);
        return mapToCommonResponse(res);
    }
    /**
     * 删除单据
     * @param params
     * @return
     * @author Ryan
     * @date 2025/10/27
     * @description: 上报单据状态
     * @version 1.0
     */
    @Override
    public CommonResponse orderDel(ErpOpParams params) {
        if (Objects.isNull(params.getOrderNo()) || params.getOrderNo().isEmpty()) {
            throw new CoolException("订单号不能为空!!");
    public CommonResponse reportOrders(ReportParams params) {
        if (Objects.isNull(params)) {
            throw new CoolException("参数不能为空!!");
        }
        /**WMS基础配置链接*/
        String rcsUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.ORDER_DEL;
        log.info("查询订单信息及状态: {}, 请求参数: {}", rcsUrl, JSONObject.toJSONString(params));
        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);
        log.info("已完成订单上传,请求结果: {}", exchange.getBody());
        if (Objects.isNull(exchange.getBody())) {
            throw new CoolException("查询失败!!");
            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 result;
                } else {
                    throw new CoolException("查询失败!!");
                }
            } catch (JsonProcessingException e) {
                throw new CoolException(e.getMessage());
            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());
        }
    }
}