| | |
| | | package com.vincent.rsf.openApi.service.phyz.impl; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONArray; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | 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.app.OpenApiOrder; |
| | | import com.vincent.rsf.openApi.entity.app.OpenApiOrderItem; |
| | | import com.vincent.rsf.openApi.entity.app.OpenApiOrderItemMap; |
| | | import com.vincent.rsf.openApi.entity.app.OpenApiOrderReportEvent; |
| | | import com.vincent.rsf.openApi.entity.constant.WmsConstant; |
| | | import com.vincent.rsf.openApi.entity.dto.CommonResponse; |
| | | import com.vincent.rsf.openApi.entity.phyz.ErpReportParams; |
| | | import com.vincent.rsf.openApi.entity.phyz.*; |
| | | import com.vincent.rsf.openApi.entity.params.ReportDataParam; |
| | | import com.vincent.rsf.openApi.entity.params.ReportParams; |
| | | import com.vincent.rsf.openApi.mapper.OpenApiOrderItemMapMapper; |
| | | import com.vincent.rsf.openApi.mapper.OpenApiOrderItemMapper; |
| | | import com.vincent.rsf.openApi.mapper.OpenApiOrderMapper; |
| | | import com.vincent.rsf.openApi.mapper.OpenApiOrderReportEventMapper; |
| | | import com.vincent.rsf.openApi.service.WmsErpService; |
| | | import com.vincent.rsf.openApi.service.phyz.ErpReportService; |
| | | import com.vincent.rsf.openApi.utils.ParamsMapUtils; |
| | | import com.vincent.rsf.openApi.utils.SslUtils; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.apache.http.client.methods.HttpPost; |
| | | import org.apache.http.entity.StringEntity; |
| | | import org.apache.http.impl.client.CloseableHttpClient; |
| | | import org.apache.http.impl.client.HttpClients; |
| | | import org.apache.http.util.EntityUtils; |
| | | import org.apache.http.conn.ssl.SSLConnectionSocketFactory; |
| | | import org.apache.http.client.config.RequestConfig; |
| | | import org.springframework.http.HttpEntity; |
| | | import org.springframework.http.HttpHeaders; |
| | | import org.springframework.http.HttpMethod; |
| | | import org.springframework.http.ResponseEntity; |
| | | import org.springframework.http.client.ClientHttpResponse; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.web.client.RestTemplate; |
| | | |
| | | import javax.annotation.PostConstruct; |
| | | import javax.annotation.Resource; |
| | | import jakarta.annotation.PostConstruct; |
| | | import jakarta.annotation.Resource; |
| | | import javax.net.ssl.SSLContext; |
| | | import javax.net.ssl.TrustManager; |
| | | import javax.net.ssl.X509TrustManager; |
| | | import java.lang.reflect.Field; |
| | | import java.security.cert.X509Certificate; |
| | | import java.io.IOException; |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.security.MessageDigest; |
| | | import java.security.NoSuchAlgorithmException; |
| | | import java.util.Arrays; |
| | | import java.util.Objects; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @Slf4j |
| | | @Service |
| | |
| | | |
| | | private static String ERP_REPORT_URL; |
| | | |
| | | private CloseableHttpClient httpClient; |
| | | |
| | | @Resource |
| | | private PlatformProperties.ErpApi erpApi; |
| | | @Resource |
| | | private PlatformProperties.WmsApi wmsApi; |
| | | @Resource |
| | | private WmsErpService wmsErpService; |
| | | @Resource |
| | | private RestTemplate restTemplate; |
| | | @Resource |
| | | private OpenApiOrderMapper openApiOrderMapper; |
| | | @Resource |
| | | private OpenApiOrderItemMapper openApiOrderItemMapper; |
| | | @Resource |
| | | private OpenApiOrderItemMapMapper openApiOrderItemMapMapper; |
| | | @Resource |
| | | private OpenApiOrderReportEventMapper openApiOrderReportEventMapper; |
| | | |
| | | private static final BigDecimal ZERO = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP); |
| | | |
| | | |
| | | @PostConstruct |
| | |
| | | ERP_REPORT_URL = erpApi.getErpUrl(); |
| | | } |
| | | |
| | | @Override |
| | | public String syncMaterial(List<Material> materialList){ |
| | | if (materialList.isEmpty()) { |
| | | throw new CoolException("参数不能为空!!"); |
| | | } |
| | | /**WMS基础配置链接*/ |
| | | String wmsUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.SYNC_MATNRS; |
| | | HttpHeaders headers = new HttpHeaders(); |
| | | headers.add("Content-Type", "application/json"); |
| | | headers.add("api-version", "v2.0"); |
| | | // Material -> BaseMatParms 字段一一对应后再下发 |
| | | List<Map<String, Object>> baseMatParamsList = materialToBaseMatParams(materialList); |
| | | HttpEntity httpEntity2 = new HttpEntity<>(baseMatParamsList, headers);//cs |
| | | // sync/warehouse |
| | | ResponseEntity<String> exchange = restTemplate.exchange(wmsUrl, HttpMethod.POST, httpEntity2, String.class);//cs |
| | | 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 "200"; |
| | | } else { |
| | | return result.getMsg(); |
| | | // throw new CoolException("查询失败!!"); |
| | | } |
| | | } catch (JsonProcessingException e) { |
| | | return e.getMessage(); |
| | | // throw new CoolException(e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Material 字段映射为 server 端 BaseMatParms 字段 |
| | | */ |
| | | private List<Map<String, Object>> materialToBaseMatParams(List<Material> materialList) { |
| | | List<Map<String, Object>> mappedList = new ArrayList<>(); |
| | | for (Material material : materialList) { |
| | | if (Objects.isNull(material)) { |
| | | continue; |
| | | } |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("maktx", material.getMakTx()); |
| | | map.put("matnr", material.getMatNr()); |
| | | map.put("groupName", material.getGroupName()); |
| | | map.put("model", material.getModel()); |
| | | map.put("weight", material.getWeight() == null ? null : material.getWeight().toString()); |
| | | map.put("color", material.getColor()); |
| | | map.put("size", material.getSize()); |
| | | map.put("spec", material.getSpec()); |
| | | map.put("describle", material.getDescribe()); |
| | | map.put("unit", material.getUnit()); |
| | | map.put("operateType", material.getOperateType()); |
| | | mappedList.add(map); |
| | | } |
| | | return mappedList; |
| | | } |
| | | |
| | | @Override |
| | | public String syncWareHouse(List<Warehouse> warehouseList){ |
| | | if (warehouseList.isEmpty()) { |
| | | throw new CoolException("参数不能为空!!"); |
| | | } |
| | | /**WMS基础配置链接*/ |
| | | String wmsUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.SYNC_WAREHOUSE; |
| | | HttpHeaders headers = new HttpHeaders(); |
| | | headers.add("Content-Type", "application/json"); |
| | | headers.add("api-version", "v2.0"); |
| | | // Warehouse -> WarehouseParams 字段一一对应后再下发 |
| | | List<Map<String, Object>> warehouseParamsList = warehouseToWarehouseParams(warehouseList); |
| | | HttpEntity httpEntity2 = new HttpEntity<>(warehouseParamsList, headers);//cs |
| | | // sync/warehouse |
| | | ResponseEntity<String> exchange = restTemplate.exchange(wmsUrl, HttpMethod.POST, httpEntity2, String.class);//cs |
| | | 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 "200"; |
| | | } else { |
| | | return result.getMsg(); |
| | | // throw new CoolException("查询失败!!"); |
| | | } |
| | | } catch (JsonProcessingException e) { |
| | | return e.getMessage(); |
| | | // throw new CoolException(e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | @Override |
| | | public String syncCustomer(List<Customer> customerList){ |
| | | if (customerList.isEmpty()) { |
| | | throw new CoolException("参数不能为空!!"); |
| | | } |
| | | /**WMS基础配置链接*/ |
| | | String wmsUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.SYNC_COMPANIES; |
| | | HttpHeaders headers = new HttpHeaders(); |
| | | headers.add("Content-Type", "application/json"); |
| | | headers.add("api-version", "v2.0"); |
| | | // Customer -> CompaniesParam 字段一一对应后再下发 |
| | | List<Map<String, Object>> companiesParamsList = customerToCompaniesParams(customerList); |
| | | HttpEntity httpEntity2 = new HttpEntity<>(companiesParamsList, headers);//cs |
| | | ResponseEntity<String> exchange = restTemplate.exchange(wmsUrl, HttpMethod.POST, httpEntity2, String.class);//cs |
| | | 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 "200"; |
| | | } else { |
| | | return result.getMsg(); |
| | | } |
| | | } catch (JsonProcessingException e) { |
| | | return e.getMessage(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public String syncSupplier(List<Supplier> supplierList){ |
| | | if (supplierList.isEmpty()) { |
| | | throw new CoolException("参数不能为空!!"); |
| | | } |
| | | /**WMS基础配置链接*/ |
| | | String wmsUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.SYNC_COMPANIES; |
| | | HttpHeaders headers = new HttpHeaders(); |
| | | headers.add("Content-Type", "application/json"); |
| | | headers.add("api-version", "v2.0"); |
| | | // Supplier -> supplierParams 字段一一对应后再下发 |
| | | List<Map<String, Object>> supplierParamsList = customerToSupplierParams(supplierList); |
| | | HttpEntity httpEntity2 = new HttpEntity<>(supplierParamsList, headers);//cs |
| | | ResponseEntity<String> exchange = restTemplate.exchange(wmsUrl, HttpMethod.POST, httpEntity2, String.class);//cs |
| | | 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 "200"; |
| | | } else { |
| | | return result.getMsg(); |
| | | } |
| | | } catch (JsonProcessingException e) { |
| | | return e.getMessage(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Warehouse 字段映射为 server 端 WarehouseParams 字段 |
| | | */ |
| | | private List<Map<String, Object>> warehouseToWarehouseParams(List<Warehouse> warehouseList) { |
| | | List<Map<String, Object>> mappedList = new ArrayList<>(); |
| | | for (Warehouse warehouse : warehouseList) { |
| | | if (Objects.isNull(warehouse)) { |
| | | continue; |
| | | } |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("name", warehouse.getWareHouseName()); |
| | | map.put("code", warehouse.getWareHouseId()); |
| | | map.put("factory", warehouse.getUseOrgName()); |
| | | map.put("factoryId", warehouse.getUseOrgId()); |
| | | map.put("address", warehouse.getAddress()); |
| | | map.put("type", null); |
| | | map.put("longitude", null); |
| | | map.put("latitude", null); |
| | | map.put("operateType", warehouse.getOperateType()); |
| | | mappedList.add(map); |
| | | } |
| | | return mappedList; |
| | | } |
| | | |
| | | /** |
| | | * Customer 字段映射为 server 端 CompaniesParam 字段 |
| | | */ |
| | | private List<Map<String, Object>> customerToCompaniesParams(List<Customer> customerList) { |
| | | List<Map<String, Object>> mappedList = new ArrayList<>(); |
| | | int rowNum = 0; |
| | | for (Customer customer : customerList) { |
| | | rowNum++; |
| | | if (Objects.isNull(customer)) { |
| | | continue; |
| | | } |
| | | if (StringUtils.isBlank(customer.getCustomerId())) { |
| | | throw new CoolException("客户同步失败:第" + rowNum + "行客户编码为空"); |
| | | } |
| | | if (StringUtils.isBlank(customer.getCustomerName())) { |
| | | throw new CoolException("客户同步失败:第" + rowNum + "行客户名称为空"); |
| | | } |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("name", customer.getCustomerName()); |
| | | map.put("nameEn", null); |
| | | map.put("breifCode", customer.getCustomerNickName()); |
| | | // server 端类型转换使用中文描述 |
| | | map.put("type", "客户"); |
| | | map.put("contact", customer.getContact()); |
| | | map.put("tel", customer.getTelephone()); |
| | | map.put("email", customer.getEmail()); |
| | | map.put("pcode", null); |
| | | map.put("city", customer.getCustomerGroup()); |
| | | map.put("province", null); |
| | | map.put("address", customer.getAddress()); |
| | | map.put("code", customer.getCustomerId()); |
| | | map.put("operateType", customer.getOperateType()); |
| | | mappedList.add(map); |
| | | } |
| | | return mappedList; |
| | | } |
| | | |
| | | /** |
| | | * Customer 字段映射为 server 端 CompaniesParam 字段 |
| | | */ |
| | | private List<Map<String, Object>> customerToSupplierParams(List<Supplier> supplierList) { |
| | | List<Map<String, Object>> mappedList = new ArrayList<>(); |
| | | for (Supplier supplier : supplierList) { |
| | | if (Objects.isNull(supplier)) { |
| | | continue; |
| | | } |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("name", supplier.getSupplierName()); |
| | | map.put("nameEn", null); |
| | | map.put("breifCode", supplier.getSupplierName()); |
| | | // server 端类型转换使用中文描述 |
| | | map.put("type", supplier.getType()); |
| | | map.put("contact", supplier.getContact()); |
| | | map.put("tel", supplier.getTelephone()); |
| | | map.put("email", supplier.getEmail()); |
| | | map.put("pcode", null); |
| | | map.put("city", supplier.getSupplierGroup()); |
| | | map.put("province", null); |
| | | map.put("address", supplier.getAddress()); |
| | | map.put("code", supplier.getSupplierId()); |
| | | map.put("operateType", supplier.getOperateType()); |
| | | mappedList.add(map); |
| | | } |
| | | return mappedList; |
| | | } |
| | | |
| | | @Override |
| | | public String addOrderToServer(Order order) { |
| | | if (Objects.isNull(order.getOrderNo()) || order.getOrderNo().isEmpty()) { |
| | | throw new CoolException("订单号不能为空!!"); |
| | | } |
| | | /**WMS基础配置链接*/ |
| | | String wmsUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.MODIFY_ORDER_DETLS; |
| | | 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", 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); |
| | | |
| | | JSONObject params = JSONObject.parseObject(JSON.toJSONString(order)); |
| | | JSONObject mappedData = ParamsMapUtils.apiMaps("erp", "orderId", params); |
| | | mappedData.put("updateBy", "erp"); |
| | | mapParams = objectToMap(mappedData); |
| | | maps.add(mapParams); |
| | | log.info("修改订单信息及状态: {}, 请求参数: {}", wmsUrl, JSONArray.toJSONString(maps)); |
| | | HttpEntity<List<Map<String, Object>>> httpEntity = new HttpEntity<>(maps, headers); |
| | | ArrayList<Order> orders = new ArrayList<>(); |
| | | orders.add(order); |
| | | HttpEntity httpEntity2 = new HttpEntity<>(orders, headers);//cs |
| | | // asnOrder/items/save |
| | | ResponseEntity<String> exchange = restTemplate.exchange(wmsUrl, HttpMethod.POST, httpEntity2, String.class);//cs |
| | | 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 "200"; |
| | | } else { |
| | | return result.getMsg(); |
| | | // throw new CoolException("查询失败!!"); |
| | | } |
| | | } catch (JsonProcessingException e) { |
| | | return e.getMessage(); |
| | | // throw new CoolException(e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | |
| | | // 登录参数依次为账套ID、用户名、应用ID、时间戳、签名信息、语言ID |
| | | public void loginBySign() throws UnsupportedEncodingException, NoSuchAlgorithmException { |
| | | String url = ERP_REPORT_URL + "/Kingdee.BOS.WebApi.ServicesStub.AuthService.LoginBySign.common.kdsvc"; |
| | | JSONObject params = new JSONObject(); |
| | | params.put("parameters", loginParams()); |
| | | JSONObject result = postRequest(url, params, false); |
| | | // ErpOpParams erpOpParams = new ErpOpParams(); |
| | | // erpOpParams.set |
| | | // |
| | | // wmsErpService.updateOrderDetl(ErpOpParams params); |
| | | |
| | | // CommonResponse updateOrderDetl() |
| | | // |
| | | // asnOrderService.saveOrderAndItems(params, getLoginUserId()); |
| | | } |
| | | |
| | | @Override |
| | | public String addOrderToServerNew(Order order) { |
| | | if (Objects.isNull(order) || StringUtils.isBlank(order.getOrderNo())) { |
| | | throw new CoolException("订单号不能为空!!"); |
| | | } |
| | | if (Objects.isNull(order.getOrderItems()) || order.getOrderItems().isEmpty()) { |
| | | throw new CoolException("订单明细不能为空!!"); |
| | | } |
| | | |
| | | OpenApiOrder persistedOrder = saveOpenApiOrder(order); |
| | | List<OpenApiOrderItem> persistedItems = saveOpenApiOrderItems(persistedOrder, order.getOrderItems()); |
| | | saveOpenApiOrderItemMappings(persistedOrder, persistedItems); |
| | | |
| | | Order mergedOrder = buildMergedOrder(order); |
| | | String dispatchResult = addOrderToServer(mergedOrder); |
| | | if (!"200".equals(dispatchResult)) { |
| | | return dispatchResult; |
| | | } |
| | | return "200"; |
| | | } |
| | | |
| | | @Override |
| | | public CommonResponse reportOrderNew(Object params) { |
| | | if (Objects.isNull(params)) { |
| | | throw new CoolException("参数不能为空!!"); |
| | | } |
| | | JSONObject root = JSONObject.parseObject(JSON.toJSONString(params)); |
| | | |
| | | String eventId = pickString(root, "eventId", "EventId"); |
| | | String taskNo = pickString(root, "taskNo", "TaskNo"); |
| | | String reportNo = pickString(root, "reportNo", "ReportNo"); |
| | | if (StringUtils.isBlank(eventId) && StringUtils.isBlank(taskNo) && StringUtils.isBlank(reportNo)) { |
| | | throw new CoolException("幂等键不能为空(eventId/taskNo/reportNo)"); |
| | | } |
| | | |
| | | if (existsReportEvent(eventId, taskNo, reportNo)) { |
| | | return CommonResponse.ok("重复回传已忽略"); |
| | | } |
| | | OpenApiOrderReportEvent reportEvent = saveReportEvent(eventId, taskNo, reportNo, pickString(root, "orderNo", "WMSNO"), root.toJSONString()); |
| | | |
| | | JSONArray dataArray = pickArray(root, "Data", "data"); |
| | | if (Objects.isNull(dataArray) || dataArray.isEmpty()) { |
| | | return CommonResponse.error("回传明细为空"); |
| | | } |
| | | |
| | | int allocateCount = 0; |
| | | int erpReportCount = 0; |
| | | List<String> errors = new ArrayList<>(); |
| | | |
| | | for (int i = 0; i < dataArray.size(); i++) { |
| | | JSONObject row = dataArray.getJSONObject(i); |
| | | String orderNo = pickString(row, "WMSNO", "wmsNo", "orderNo", "OrderNo"); |
| | | String matnrCode = pickString(row, "ItemCode", "itemCode", "matNr", "MatNr"); |
| | | String batch = pickString(row, "Batch", "batch", "GoodsNO", "goodsNo"); |
| | | BigDecimal doneQty = pickDecimal(row, "qty", "doneQty", "InQty", "OutQty"); |
| | | if (StringUtils.isBlank(orderNo) || StringUtils.isBlank(matnrCode) || doneQty.compareTo(ZERO) <= 0) { |
| | | errors.add("第" + (i + 1) + "行缺少必要字段(WMSNO/ItemCode/数量)"); |
| | | continue; |
| | | } |
| | | doneQty = doneQty.setScale(2, RoundingMode.HALF_UP); |
| | | |
| | | try { |
| | | int singleAllocated = allocateMergedDoneQty(orderNo, matnrCode, batch, doneQty); |
| | | allocateCount += singleAllocated; |
| | | erpReportCount += reportReadyLinesToErp(orderNo); |
| | | refreshOrderFinishStatus(orderNo); |
| | | } catch (Exception e) { |
| | | log.error("处理回传失败,orderNo={}, matnr={}, batch={}", orderNo, matnrCode, batch, e); |
| | | errors.add("第" + (i + 1) + "行处理失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | if (!errors.isEmpty()) { |
| | | reportEvent.setStatus(2); |
| | | openApiOrderReportEventMapper.updateById(reportEvent); |
| | | return CommonResponse.error("处理完成,但存在异常:" + String.join(" | ", errors)); |
| | | } |
| | | reportEvent.setStatus(1); |
| | | openApiOrderReportEventMapper.updateById(reportEvent); |
| | | |
| | | Map<String, Object> result = new HashMap<>(); |
| | | result.put("allocatedCount", allocateCount); |
| | | result.put("erpReportCount", erpReportCount); |
| | | return CommonResponse.ok(result); |
| | | } |
| | | |
| | | private OpenApiOrder saveOpenApiOrder(Order order) { |
| | | OpenApiOrder existing = openApiOrderMapper.selectOne(new LambdaQueryWrapper<OpenApiOrder>() |
| | | .eq(OpenApiOrder::getCode, order.getOrderNo()) |
| | | .last("limit 1")); |
| | | |
| | | BigDecimal totalQty = sumOrderItemQty(order.getOrderItems()); |
| | | Date businessTime = toDate(order.getBusinessTime()); |
| | | OpenApiOrder target = Objects.isNull(existing) ? new OpenApiOrder() : existing; |
| | | target.setCode(order.getOrderNo()) |
| | | .setType(order.getType()) |
| | | .setWkType(order.getWkType()) |
| | | .setAnfme(totalQty) |
| | | .setQty(ZERO) |
| | | .setWorkQty(ZERO) |
| | | .setExceStatus(0) |
| | | .setStatus(1) |
| | | .setBusinessTime(businessTime) |
| | | .setOrderInternalCode(order.getOrderInternalCode()) |
| | | .setStationId(order.getStationId()) |
| | | .setStockDirect(order.getStockDirect()) |
| | | .setCustomerId(order.getCustomerId()) |
| | | .setCustomerName(order.getCustomerName()) |
| | | .setSupplierId(order.getSupplierId()) |
| | | .setSupplierName(order.getSupplierName()) |
| | | .setStockOrgId(order.getStockOrgId()) |
| | | .setStockOrgName(order.getStockOrgName()) |
| | | .setPurchaseOrgId(order.getPurchaseOrgId()) |
| | | .setPurchaseOrgName(order.getPurchaseOrgName()) |
| | | .setPurchaseUserId(order.getPurchaseUserId()) |
| | | .setPurchaseUserName(order.getPurchaseUserName()) |
| | | .setPrdOrgId(order.getPrdOrgId()) |
| | | .setPrdOrgName(order.getPrdOrgName()) |
| | | .setSaleOrgId(order.getSaleOrgId()) |
| | | .setSaleOrgName(order.getSaleOrgName()) |
| | | .setSaleUserId(order.getSaleUserId()) |
| | | .setSaleUserName(order.getSaleUserName()); |
| | | |
| | | if (Objects.isNull(existing)) { |
| | | openApiOrderMapper.insert(target); |
| | | } else { |
| | | openApiOrderMapper.updateById(target); |
| | | openApiOrderItemMapper.delete(new LambdaQueryWrapper<OpenApiOrderItem>().eq(OpenApiOrderItem::getOrderId, target.getId())); |
| | | openApiOrderItemMapMapper.delete(new LambdaQueryWrapper<OpenApiOrderItemMap>().eq(OpenApiOrderItemMap::getOrderId, target.getId())); |
| | | } |
| | | return target; |
| | | } |
| | | |
| | | private List<OpenApiOrderItem> saveOpenApiOrderItems(OpenApiOrder order, List<OrderItem> orderItems) { |
| | | List<OpenApiOrderItem> saved = new ArrayList<>(); |
| | | for (OrderItem src : orderItems) { |
| | | OpenApiOrderItem target = new OpenApiOrderItem() |
| | | .setOrderId(order.getId()) |
| | | .setOrderCode(order.getCode()) |
| | | .setPlatItemId(src.getLineId()) |
| | | .setPlatWorkCode(src.getPlanNo()) |
| | | .setMatnrCode(src.getMatNr()) |
| | | .setMaktx(src.getMakTx()) |
| | | .setModel(src.getModel()) |
| | | .setSpec(src.getSpec()) |
| | | .setAnfme(toDecimal(src.getAnfme())) |
| | | .setStockUnit(src.getUnit()) |
| | | .setWorkQty(ZERO) |
| | | .setQty(ZERO) |
| | | .setBatch(src.getBatch()) |
| | | .setMemo(src.getMemo()) |
| | | .setTargetWarehouseId(src.getTargetWarehouseId()) |
| | | .setSourceWarehouseId(src.getSourceWarehouseId()) |
| | | .setOwnerId(src.getOwnerId()) |
| | | .setBaseUnit(src.getBaseUnit()) |
| | | .setUseOrgId(src.getUseOrgId()) |
| | | .setUseOrgName(src.getUseOrgName()) |
| | | .setErpClsId(src.getErpClsId()) |
| | | .setPriceUnitId(src.getPriceUnitId()) |
| | | .setInStockType(src.getInStockType()) |
| | | .setOwnerTypeId(src.getOwnerTypeId()) |
| | | .setOwnerName(src.getOwnerName()) |
| | | .setKeeperTypeId(src.getKeeperTypeId()) |
| | | .setKeeperId(src.getKeeperId()) |
| | | .setKeeperName(src.getKeeperName()) |
| | | .setStatus(1) |
| | | .setDeleted(0); |
| | | openApiOrderItemMapper.insert(target); |
| | | saved.add(target); |
| | | } |
| | | return saved; |
| | | } |
| | | |
| | | private void saveOpenApiOrderItemMappings(OpenApiOrder order, List<OpenApiOrderItem> items) { |
| | | Map<String, List<OpenApiOrderItem>> grouped = items.stream().collect(Collectors.groupingBy(i -> mergeKey(i.getMatnrCode(), i.getBatch()))); |
| | | for (List<OpenApiOrderItem> sameGroupItems : grouped.values()) { |
| | | sameGroupItems.sort(Comparator.comparing(OpenApiOrderItem::getId)); |
| | | for (int i = 0; i < sameGroupItems.size(); i++) { |
| | | OpenApiOrderItem item = sameGroupItems.get(i); |
| | | OpenApiOrderItemMap map = new OpenApiOrderItemMap() |
| | | .setOrderId(order.getId()) |
| | | .setOrderCode(order.getCode()) |
| | | .setSourceItemId(item.getId()) |
| | | .setSourceLineId(item.getPlatItemId()) |
| | | .setMergeMatnrCode(defaultString(item.getMatnrCode())) |
| | | .setMergeBatch(defaultString(item.getBatch())) |
| | | .setSeqNo(i + 1) |
| | | .setSourceQty(defaultQty(item.getAnfme())) |
| | | .setAllocatedQty(ZERO) |
| | | .setReportedQty(ZERO) |
| | | .setStatus(1) |
| | | .setDeleted(0); |
| | | openApiOrderItemMapMapper.insert(map); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private Order buildMergedOrder(Order source) { |
| | | Order merged = new Order() |
| | | .setOrderNo(source.getOrderNo()) |
| | | .setOrderInternalCode(source.getOrderInternalCode()) |
| | | .setWkType(source.getWkType()) |
| | | .setCreateTime(source.getCreateTime()) |
| | | .setBusinessTime(source.getBusinessTime()) |
| | | .setStockDirect(source.getStockDirect()) |
| | | .setStationId(source.getStationId()) |
| | | .setCustomerId(source.getCustomerId()) |
| | | .setCustomerName(source.getCustomerName()) |
| | | .setSupplierId(source.getSupplierId()) |
| | | .setSupplierName(source.getSupplierName()) |
| | | .setStockOrgId(source.getStockOrgId()) |
| | | .setStockOrgName(source.getStockOrgName()) |
| | | .setPurchaseOrgId(source.getPurchaseOrgId()) |
| | | .setPurchaseOrgName(source.getPurchaseOrgName()) |
| | | .setPurchaseUserId(source.getPurchaseUserId()) |
| | | .setPurchaseUserName(source.getPurchaseUserName()) |
| | | .setPrdOrgId(source.getPrdOrgId()) |
| | | .setPrdOrgName(source.getPrdOrgName()) |
| | | .setSaleOrgId(source.getSaleOrgId()) |
| | | .setSaleOrgName(source.getSaleOrgName()) |
| | | .setSaleUserId(source.getSaleUserId()) |
| | | .setSaleUserName(source.getSaleUserName()); |
| | | merged.setType(source.getType()); |
| | | Map<String, List<OrderItem>> grouped = source.getOrderItems().stream().collect(Collectors.groupingBy(i -> mergeKey(i.getMatNr(), i.getBatch()))); |
| | | List<OrderItem> mergedItems = new ArrayList<>(); |
| | | int idx = 1; |
| | | for (List<OrderItem> groupItems : grouped.values()) { |
| | | OrderItem first = groupItems.get(0); |
| | | BigDecimal qty = groupItems.stream() |
| | | .map(i -> toDecimal(i.getAnfme())) |
| | | .reduce(ZERO, BigDecimal::add) |
| | | .setScale(2, RoundingMode.HALF_UP); |
| | | OrderItem mergedItem = new OrderItem() |
| | | .setLineId("M" + idx++) |
| | | .setPlanNo(first.getPlanNo()) |
| | | .setMatNr(first.getMatNr()) |
| | | .setMakTx(first.getMakTx()) |
| | | .setModel(first.getModel()) |
| | | .setAnfme(qty.doubleValue()) |
| | | .setBatch(first.getBatch()) |
| | | .setUnit(first.getUnit()) |
| | | .setBaseUnit(first.getBaseUnit()) |
| | | .setPriceUnitId(first.getPriceUnitId()) |
| | | .setPalletId(first.getPalletId()) |
| | | .setTargetWarehouseId(first.getTargetWarehouseId()) |
| | | .setSourceWarehouseId(first.getSourceWarehouseId()) |
| | | .setInStockType(first.getInStockType()) |
| | | .setOwnerTypeId(first.getOwnerTypeId()) |
| | | .setOwnerId(first.getOwnerId()) |
| | | .setOwnerName(first.getOwnerName()) |
| | | .setKeeperTypeId(first.getKeeperTypeId()) |
| | | .setKeeperId(first.getKeeperId()) |
| | | .setKeeperName(first.getKeeperName()) |
| | | .setMemo(first.getMemo()) |
| | | .setUseOrgId(first.getUseOrgId()) |
| | | .setUseOrgName(first.getUseOrgName()) |
| | | .setErpClsId(first.getErpClsId()); |
| | | mergedItem.setSpec(first.getSpec()); |
| | | mergedItems.add(mergedItem); |
| | | } |
| | | merged.setOrderItems(mergedItems); |
| | | return merged; |
| | | } |
| | | |
| | | private boolean existsReportEvent(String eventId, String taskNo, String reportNo) { |
| | | return openApiOrderReportEventMapper.selectCount(new LambdaQueryWrapper<OpenApiOrderReportEvent>() |
| | | .eq(OpenApiOrderReportEvent::getEventId, defaultString(eventId)) |
| | | .eq(OpenApiOrderReportEvent::getTaskNo, defaultString(taskNo)) |
| | | .eq(OpenApiOrderReportEvent::getReportNo, defaultString(reportNo)) |
| | | .eq(OpenApiOrderReportEvent::getStatus, 1)) > 0; |
| | | } |
| | | |
| | | private OpenApiOrderReportEvent saveReportEvent(String eventId, String taskNo, String reportNo, String orderCode, String payload) { |
| | | OpenApiOrderReportEvent event = new OpenApiOrderReportEvent() |
| | | .setEventId(defaultString(eventId)) |
| | | .setTaskNo(defaultString(taskNo)) |
| | | .setReportNo(defaultString(reportNo)) |
| | | .setOrderCode(orderCode) |
| | | .setPayload(payload) |
| | | .setStatus(0); |
| | | openApiOrderReportEventMapper.insert(event); |
| | | return event; |
| | | } |
| | | |
| | | private int allocateMergedDoneQty(String orderNo, String matnrCode, String batch, BigDecimal mergedDoneQty) { |
| | | OpenApiOrder order = openApiOrderMapper.selectOne(new LambdaQueryWrapper<OpenApiOrder>() |
| | | .eq(OpenApiOrder::getCode, orderNo) |
| | | .last("limit 1")); |
| | | if (Objects.isNull(order)) { |
| | | throw new CoolException("未找到订单:" + orderNo); |
| | | } |
| | | |
| | | LambdaQueryWrapper<OpenApiOrderItemMap> queryWrapper = new LambdaQueryWrapper<OpenApiOrderItemMap>() |
| | | .eq(OpenApiOrderItemMap::getOrderId, order.getId()) |
| | | .eq(OpenApiOrderItemMap::getMergeMatnrCode, defaultString(matnrCode)) |
| | | .orderByAsc(OpenApiOrderItemMap::getSeqNo) |
| | | .orderByAsc(OpenApiOrderItemMap::getId); |
| | | if (StringUtils.isNotBlank(batch)) { |
| | | queryWrapper.eq(OpenApiOrderItemMap::getMergeBatch, batch); |
| | | } |
| | | List<OpenApiOrderItemMap> mappingRows = openApiOrderItemMapMapper.selectList(queryWrapper); |
| | | if (mappingRows.isEmpty()) { |
| | | throw new CoolException("未找到映射关系,订单:" + orderNo + ",物料:" + matnrCode); |
| | | } |
| | | |
| | | BigDecimal remaining = mergedDoneQty; |
| | | int allocateRows = 0; |
| | | for (OpenApiOrderItemMap row : mappingRows) { |
| | | if (remaining.compareTo(ZERO) <= 0) { |
| | | break; |
| | | } |
| | | BigDecimal sourceQty = defaultQty(row.getSourceQty()); |
| | | BigDecimal allocatedQty = defaultQty(row.getAllocatedQty()); |
| | | BigDecimal canAllocate = sourceQty.subtract(allocatedQty); |
| | | if (canAllocate.compareTo(ZERO) <= 0) { |
| | | continue; |
| | | } |
| | | BigDecimal toAllocate = remaining.min(canAllocate).setScale(2, RoundingMode.HALF_UP); |
| | | if (toAllocate.compareTo(ZERO) <= 0) { |
| | | continue; |
| | | } |
| | | |
| | | row.setAllocatedQty(allocatedQty.add(toAllocate).setScale(2, RoundingMode.HALF_UP)); |
| | | openApiOrderItemMapMapper.updateById(row); |
| | | openApiOrderItemMapper.update(null, new LambdaUpdateWrapper<OpenApiOrderItem>() |
| | | .eq(OpenApiOrderItem::getId, row.getSourceItemId()) |
| | | .setSql("qty = IFNULL(qty,0) + " + toAllocate)); |
| | | remaining = remaining.subtract(toAllocate).setScale(2, RoundingMode.HALF_UP); |
| | | allocateRows++; |
| | | } |
| | | if (remaining.compareTo(ZERO) > 0) { |
| | | log.warn("回传数量超过未分配数量,orderNo={}, matnr={}, batch={}, overflow={}", orderNo, matnrCode, batch, remaining); |
| | | } |
| | | return allocateRows; |
| | | } |
| | | |
| | | private int reportReadyLinesToErp(String orderNo) { |
| | | OpenApiOrder order = openApiOrderMapper.selectOne(new LambdaQueryWrapper<OpenApiOrder>() |
| | | .eq(OpenApiOrder::getCode, orderNo) |
| | | .last("limit 1")); |
| | | if (Objects.isNull(order)) { |
| | | return 0; |
| | | } |
| | | |
| | | List<OpenApiOrderItemMap> mappings = openApiOrderItemMapMapper.selectList(new LambdaQueryWrapper<OpenApiOrderItemMap>() |
| | | .eq(OpenApiOrderItemMap::getOrderId, order.getId()) |
| | | .orderByAsc(OpenApiOrderItemMap::getSeqNo) |
| | | .orderByAsc(OpenApiOrderItemMap::getId)); |
| | | int successCount = 0; |
| | | |
| | | for (OpenApiOrderItemMap mapping : mappings) { |
| | | BigDecimal allocatedQty = defaultQty(mapping.getAllocatedQty()); |
| | | BigDecimal reportedQty = defaultQty(mapping.getReportedQty()); |
| | | BigDecimal delta = allocatedQty.subtract(reportedQty).setScale(2, RoundingMode.HALF_UP); |
| | | if (delta.compareTo(ZERO) <= 0) { |
| | | continue; |
| | | } |
| | | |
| | | OpenApiOrderItem item = openApiOrderItemMapper.selectById(mapping.getSourceItemId()); |
| | | if (Objects.isNull(item)) { |
| | | continue; |
| | | } |
| | | |
| | | ReportParams params = buildLineReportParams(order, item, delta); |
| | | CommonResponse erpResp = wmsErpService.reportOrders(params); |
| | | if (Objects.nonNull(erpResp) && Objects.equals(erpResp.getCode(), 200)) { |
| | | mapping.setReportedQty(reportedQty.add(delta).setScale(2, RoundingMode.HALF_UP)); |
| | | openApiOrderItemMapMapper.updateById(mapping); |
| | | successCount++; |
| | | } else { |
| | | String msg = Objects.isNull(erpResp) ? "ERP响应为空" : erpResp.getMsg(); |
| | | log.warn("ERP行上报失败,orderNo={}, itemId={}, msg={}", orderNo, item.getId(), msg); |
| | | } |
| | | } |
| | | return successCount; |
| | | } |
| | | |
| | | private ReportParams buildLineReportParams(OpenApiOrder order, OpenApiOrderItem item, BigDecimal deltaQty) { |
| | | ReportDataParam dataParam = new ReportDataParam() |
| | | .setWMSNO(order.getCode()) |
| | | .setPONO(order.getPoCode()) |
| | | .setOrderNO(item.getPlatWorkCode()) |
| | | .setGoodsNO(item.getBatch()) |
| | | .setItemCode(item.getMatnrCode()) |
| | | .setEditUser("open-api") |
| | | .setEditDate(new Date()) |
| | | .setMemoDtl("lineId=" + defaultString(item.getPlatItemId())); |
| | | |
| | | if ("in".equalsIgnoreCase(order.getType())) { |
| | | dataParam.setInQty(deltaQty.doubleValue()); |
| | | } else { |
| | | dataParam.setOutQty(deltaQty.doubleValue()); |
| | | } |
| | | |
| | | return new ReportParams().setOrderType(order.getType()).setAction("Update").setData(Collections.singletonList(dataParam)); |
| | | } |
| | | |
| | | private void refreshOrderFinishStatus(String orderNo) { |
| | | OpenApiOrder order = openApiOrderMapper.selectOne(new LambdaQueryWrapper<OpenApiOrder>() |
| | | .eq(OpenApiOrder::getCode, orderNo) |
| | | .last("limit 1")); |
| | | if (Objects.isNull(order)) { |
| | | return; |
| | | } |
| | | List<OpenApiOrderItem> items = openApiOrderItemMapper.selectList(new LambdaQueryWrapper<OpenApiOrderItem>() |
| | | .eq(OpenApiOrderItem::getOrderId, order.getId())); |
| | | BigDecimal totalPlan = items.stream().map(i -> defaultQty(i.getAnfme())).reduce(ZERO, BigDecimal::add); |
| | | BigDecimal totalDone = items.stream().map(i -> defaultQty(i.getQty())).reduce(ZERO, BigDecimal::add); |
| | | |
| | | int exceStatus = 0; |
| | | if (totalDone.compareTo(ZERO) > 0 && totalDone.compareTo(totalPlan) < 0) { |
| | | exceStatus = 1; |
| | | } else if (totalDone.compareTo(totalPlan) >= 0 && totalPlan.compareTo(ZERO) > 0) { |
| | | exceStatus = 2; |
| | | } |
| | | |
| | | order.setQty(totalDone.setScale(2, RoundingMode.HALF_UP)) |
| | | .setWorkQty(totalDone.setScale(2, RoundingMode.HALF_UP)) |
| | | .setExceStatus(exceStatus); |
| | | openApiOrderMapper.updateById(order); |
| | | } |
| | | |
| | | private BigDecimal sumOrderItemQty(List<OrderItem> orderItems) { |
| | | return orderItems.stream() |
| | | .filter(Objects::nonNull) |
| | | .map(i -> toDecimal(i.getAnfme())) |
| | | .reduce(ZERO, BigDecimal::add) |
| | | .setScale(2, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | private BigDecimal toDecimal(Double value) { |
| | | if (Objects.isNull(value)) { |
| | | return ZERO; |
| | | } |
| | | return BigDecimal.valueOf(value).setScale(2, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | private BigDecimal defaultQty(BigDecimal value) { |
| | | return Objects.isNull(value) ? ZERO : value.setScale(2, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | private Date toDate(Long timestampSeconds) { |
| | | if (Objects.isNull(timestampSeconds) || timestampSeconds <= 0L) { |
| | | return null; |
| | | } |
| | | return new Date(timestampSeconds * 1000); |
| | | } |
| | | |
| | | private String mergeKey(String matnr, String batch) { |
| | | return defaultString(matnr) + "@@" + defaultString(batch); |
| | | } |
| | | |
| | | private String defaultString(String value) { |
| | | return StringUtils.trimToEmpty(value); |
| | | } |
| | | |
| | | private String pickString(JSONObject object, String... candidates) { |
| | | if (Objects.isNull(object) || Objects.isNull(candidates)) { |
| | | return ""; |
| | | } |
| | | for (String key : candidates) { |
| | | Object value = object.get(key); |
| | | if (Objects.nonNull(value) && StringUtils.isNotBlank(String.valueOf(value))) { |
| | | return String.valueOf(value).trim(); |
| | | } |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | | private JSONArray pickArray(JSONObject object, String... candidates) { |
| | | if (Objects.isNull(object) || Objects.isNull(candidates)) { |
| | | return new JSONArray(); |
| | | } |
| | | for (String key : candidates) { |
| | | Object value = object.get(key); |
| | | if (value instanceof JSONArray) { |
| | | return (JSONArray) value; |
| | | } |
| | | if (value instanceof List) { |
| | | return JSONArray.parseArray(JSON.toJSONString(value)); |
| | | } |
| | | if (value instanceof String && ((String) value).trim().startsWith("[")) { |
| | | return JSONArray.parseArray((String) value); |
| | | } |
| | | } |
| | | return new JSONArray(); |
| | | } |
| | | |
| | | private BigDecimal pickDecimal(JSONObject object, String... candidates) { |
| | | if (Objects.isNull(object) || Objects.isNull(candidates)) { |
| | | return ZERO; |
| | | } |
| | | for (String key : candidates) { |
| | | Object value = object.get(key); |
| | | if (Objects.isNull(value)) { |
| | | continue; |
| | | } |
| | | try { |
| | | return new BigDecimal(String.valueOf(value)).abs().setScale(2, RoundingMode.HALF_UP); |
| | | } catch (Exception ignore) { |
| | | // ignore invalid value |
| | | } |
| | | } |
| | | return ZERO; |
| | | } |
| | | |
| | | public static Map<String, Object> objectToMap(Object obj) { |
| | | Map<String, Object> map = new HashMap<>(); |
| | | Field[] fields = obj.getClass().getDeclaredFields(); |
| | | for (Field field : fields) { |
| | | field.setAccessible(true); // 设置私有字段也可以访问 |
| | | try { |
| | | map.put(field.getName(), field.get(obj)); |
| | | } catch (IllegalAccessException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | |
| | | // 入/出库任务完成上报 |
| | | |
| | | /** |
| | | * 入/出库任务完成上报 |
| | | * |
| | | * @param params |
| | | * @return |
| | | */ |
| | | public CommonResponse reportInOrOutBound(Object params) { |
| | | if (Objects.isNull(params)) { |
| | | throw new CoolException("入/出库任务信息参数不能为空!!"); |
| | |
| | | |
| | | // TODO:参数转换 |
| | | ErpReportParams erpReportParams = new ErpReportParams(); |
| | | erpReportParams = (ErpReportParams) params; |
| | | |
| | | String erpUrl = ERP_REPORT_URL + "/Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Save.common.kdsvc"; |
| | | log.info("Erp入/出库任务完成上报: {}, 请求参数: {}", erpUrl, JSONObject.toJSONString(erpReportParams)); |
| | | try { |
| | | JSONObject jsonObject = postRequest(erpUrl, erpReportParams, true); |
| | | boolean sendSuccess = jsonObject.getJSONObject("Result").getJSONObject("ResponseStatus").getBoolean("IsSuccess"); |
| | | |
| | | // TODO:转换后返回 |
| | | if (sendSuccess) { |
| | | return CommonResponse.ok(); |
| | | } else { |
| | | JSONArray errors = jsonObject.getJSONObject("Result").getJSONObject("ResponseStatus").getJSONArray("Errors"); |
| | | String errorMsg = ""; |
| | | for (int i = 0; i < errors.size(); i++) { |
| | | errorMsg += errors.getJSONObject(i).getString("Message") + " "; |
| | | if (params instanceof ErpReportParams) { |
| | | erpReportParams = (ErpReportParams) params; |
| | | } else if (params instanceof java.util.Map) { |
| | | java.util.Map<String, Object> paramMap = (java.util.Map<String, Object>) params; |
| | | |
| | | // 设置基本属性 |
| | | erpReportParams.setFDate((String) paramMap.get("FDate")); |
| | | erpReportParams.setF_OHDL_BillnoType((String) paramMap.get("F_OHDL_BillnoType")); |
| | | erpReportParams.setFStockOrgId(paramMap.get("FStockOrgId")); |
| | | erpReportParams.setFPrdOrgId(paramMap.get("FPrdOrgId")); |
| | | erpReportParams.setF_OHDL_ProPlan((String) paramMap.get("F_OHDL_ProPlan")); |
| | | |
| | | // 处理FEntity列表 |
| | | Object fEntityObj = paramMap.get("FEntity"); |
| | | if (fEntityObj instanceof java.util.List) { |
| | | java.util.List<?> fEntityList = (java.util.List<?>) fEntityObj; |
| | | java.util.List<ErpReportParams.FEntityItem> entityItems = new java.util.ArrayList<>(); |
| | | |
| | | for (Object item : fEntityList) { |
| | | if (item instanceof java.util.Map) { |
| | | java.util.Map<String, Object> itemMap = (java.util.Map<String, Object>) item; |
| | | ErpReportParams.FEntityItem entityItem = new ErpReportParams.FEntityItem(); |
| | | |
| | | // 使用反射设置属性值 |
| | | try { |
| | | // 使用反射直接访问字段并设置值 |
| | | java.lang.reflect.Field field; |
| | | |
| | | field = entityItem.getClass().getDeclaredField("FMaterialId"); |
| | | field.setAccessible(true); |
| | | field.set(entityItem, itemMap.get("FMaterialId")); |
| | | |
| | | field = entityItem.getClass().getDeclaredField("FUnitID"); |
| | | field.setAccessible(true); |
| | | field.set(entityItem, itemMap.get("FUnitID")); |
| | | |
| | | // 处理数值类型 |
| | | Object fAppQty = itemMap.get("FAppQty"); |
| | | if (fAppQty instanceof Number) { |
| | | field = entityItem.getClass().getDeclaredField("FAppQty"); |
| | | field.setAccessible(true); |
| | | field.set(entityItem, ((Number) fAppQty).doubleValue()); |
| | | } else if (fAppQty != null) { |
| | | field = entityItem.getClass().getDeclaredField("FAppQty"); |
| | | field.setAccessible(true); |
| | | field.set(entityItem, Double.parseDouble(fAppQty.toString())); |
| | | } |
| | | |
| | | Object fActualQty = itemMap.get("FActualQty"); |
| | | if (fActualQty instanceof Number) { |
| | | field = entityItem.getClass().getDeclaredField("FActualQty"); |
| | | field.setAccessible(true); |
| | | field.set(entityItem, ((Number) fActualQty).doubleValue()); |
| | | } else if (fActualQty != null) { |
| | | field = entityItem.getClass().getDeclaredField("FActualQty"); |
| | | field.setAccessible(true); |
| | | field.set(entityItem, Double.parseDouble(fActualQty.toString())); |
| | | } |
| | | |
| | | field = entityItem.getClass().getDeclaredField("FStockId"); |
| | | field.setAccessible(true); |
| | | field.set(entityItem, itemMap.get("FStockId")); |
| | | |
| | | field = entityItem.getClass().getDeclaredField("F_OHDL_BworkShop"); |
| | | field.setAccessible(true); |
| | | field.set(entityItem, itemMap.get("F_OHDL_BworkShop")); |
| | | |
| | | field = entityItem.getClass().getDeclaredField("F_OHDL_Pallet"); |
| | | field.setAccessible(true); |
| | | field.set(entityItem, (String) itemMap.get("F_OHDL_Pallet")); |
| | | |
| | | field = entityItem.getClass().getDeclaredField("F_OHDL_ConPoint"); |
| | | field.setAccessible(true); |
| | | field.set(entityItem, (String) itemMap.get("F_OHDL_ConPoint")); |
| | | |
| | | field = entityItem.getClass().getDeclaredField("F_OHDL_PlanNo"); |
| | | field.setAccessible(true); |
| | | field.set(entityItem, (String) itemMap.get("F_OHDL_PlanNo")); |
| | | |
| | | field = entityItem.getClass().getDeclaredField("F_OHDL_MONo"); |
| | | field.setAccessible(true); |
| | | field.set(entityItem, (String) itemMap.get("F_OHDL_MONo")); |
| | | |
| | | field = entityItem.getClass().getDeclaredField("F_OHDL_MOId"); |
| | | field.setAccessible(true); |
| | | field.set(entityItem, (String) itemMap.get("F_OHDL_MOId")); |
| | | |
| | | field = entityItem.getClass().getDeclaredField("F_OHDL_MOLine"); |
| | | field.setAccessible(true); |
| | | field.set(entityItem, (String) itemMap.get("F_OHDL_MOLine")); |
| | | |
| | | field = entityItem.getClass().getDeclaredField("F_OHDL_MOLineId"); |
| | | field.setAccessible(true); |
| | | field.set(entityItem, (String) itemMap.get("F_OHDL_MOLineId")); |
| | | } catch (Exception e) { |
| | | log.error("设置FEntityItem属性时发生错误: " + e.getMessage()); |
| | | throw new CoolException("设置FEntityItem属性失败: " + e.getMessage()); |
| | | } |
| | | |
| | | entityItems.add(entityItem); |
| | | } else if (item instanceof ErpReportParams.FEntityItem) { |
| | | entityItems.add((ErpReportParams.FEntityItem) item); |
| | | } |
| | | } |
| | | return CommonResponse.error(errorMsg); |
| | | erpReportParams.setFEntity(entityItems); |
| | | } |
| | | } else { |
| | | throw new CoolException("无法处理的参数类型: " + params.getClass().getName()); |
| | | } |
| | | |
| | | JSONObject model = new JSONObject(); |
| | | model.put("Model", erpReportParams); |
| | | JSONObject data = new JSONObject(); |
| | | data.put("data", model); |
| | | data.put("formid", "ke3d5adc0bbe64eceafd5891400adf40e"); |
| | | |
| | | try { |
| | | JSONObject loginResult = loginBySign(); |
| | | if (loginResult.getInteger("LoginResultType") == 1) { |
| | | String erpUrl = ERP_REPORT_URL + "/Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Save.common.kdsvc"; |
| | | log.info("Erp入/出库任务完成上报: {}, 请求参数: {}", erpUrl, JSONObject.toJSONString(data)); |
| | | |
| | | String result2 = httpPostExample(erpUrl, data.toJSONString()); |
| | | JSONObject jsonObject = JSONObject.parseObject(result2); |
| | | log.info("Erp入/出库任务完成上报返回" + jsonObject.toJSONString()); |
| | | boolean sendSuccess = jsonObject.getJSONObject("Result").getJSONObject("ResponseStatus").getBoolean("IsSuccess"); |
| | | |
| | | // TODO:转换后返回 |
| | | if (sendSuccess) { |
| | | return CommonResponse.ok(); |
| | | } else { |
| | | JSONArray errors = jsonObject.getJSONObject("Result").getJSONObject("ResponseStatus").getJSONArray("Errors"); |
| | | String errorMsg = ""; |
| | | for (int i = 0; i < errors.size(); i++) { |
| | | errorMsg += errors.getJSONObject(i).getString("Message") + " "; |
| | | } |
| | | return CommonResponse.error(errorMsg); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("Erp入/出库任务上报响应失败", e); |
| | | throw new CoolException("Erp解析响应失败:" + e.getMessage()); |
| | | log.error("loginBySign", e); |
| | | } |
| | | |
| | | |
| | | // try { |
| | | // JSONObject jsonObject = postRequest(erpUrl, data, true); |
| | | // log.info(jsonObject.toJSONString()); |
| | | // boolean sendSuccess = jsonObject.getJSONObject("Result").getJSONObject("ResponseStatus").getBoolean("IsSuccess"); |
| | | // |
| | | // // TODO:转换后返回 |
| | | // if (sendSuccess) { |
| | | // return CommonResponse.ok(); |
| | | // } else { |
| | | // JSONArray errors = jsonObject.getJSONObject("Result").getJSONObject("ResponseStatus").getJSONArray("Errors"); |
| | | // String errorMsg = ""; |
| | | // for (int i = 0; i < errors.size(); i++) { |
| | | // errorMsg += errors.getJSONObject(i).getString("Message") + " "; |
| | | // } |
| | | // return CommonResponse.error(errorMsg); |
| | | // } |
| | | // } catch (Exception e) { |
| | | // log.error("Erp入/出库任务上报响应失败", e); |
| | | // throw new CoolException("Erp解析响应失败:" + e.getMessage()); |
| | | // } |
| | | |
| | | return null; |
| | | } |
| | | |
| | | |
| | |
| | | // 盘点结果上报 |
| | | |
| | | |
| | | // region 登录 |
| | | /** |
| | | * 登录,登录参数依次为账套ID、用户名、应用ID、时间戳、签名信息、语言ID |
| | | * |
| | | * @throws UnsupportedEncodingException |
| | | * @throws NoSuchAlgorithmException |
| | | */ |
| | | public JSONObject loginBySign() throws UnsupportedEncodingException, NoSuchAlgorithmException { |
| | | String url = ERP_REPORT_URL + "/Kingdee.BOS.WebApi.ServicesStub.AuthService.LoginBySign.common.kdsvc"; |
| | | JSONObject params = new JSONObject(); |
| | | params.put("parameters", loginParams()); |
| | | String result = httpPostExample(url, params.toJSONString()); |
| | | return JSONObject.parseObject(result); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 登录参数整理 |
| | | * |
| | | * @return |
| | | * @throws UnsupportedEncodingException |
| | | * @throws NoSuchAlgorithmException |
| | | */ |
| | | private Object[] loginParams() throws UnsupportedEncodingException, NoSuchAlgorithmException { |
| | | //时间戳 |
| | | long timestamp = System.currentTimeMillis() / 1000; |
| | |
| | | } |
| | | return hashString.toString(); |
| | | } |
| | | // endregion |
| | | |
| | | /** |
| | | * 通用HTTP POST请求方法 |
| | | * |
| | | * @param url 请求URL |
| | | * @param params 请求参数 |
| | | * @param needToken 是否需要token认证 |
| | | * @return 响应结果 |
| | | */ |
| | | public JSONObject postRequest(String url, Object params, boolean needToken) { |
| | | public JSONObject postRequest(String url, Object params) { |
| | | if (StringUtils.isBlank(url)) { |
| | | throw new CoolException("请求URL不能为空!!"); |
| | | } |
| | |
| | | HttpHeaders headers = new HttpHeaders(); |
| | | headers.add("Content-Type", "application/json;charset=utf-8"); |
| | | |
| | | if (needToken) { |
| | | // String token = getToken(); |
| | | // headers.add("Authorization", "Bearer " + token); |
| | | } |
| | | |
| | | HttpEntity<Object> httpEntity = new HttpEntity<>(params, headers); |
| | | ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class); |
| | | |
| | | // 创建支持忽略SSL证书验证的RestTemplate |
| | | RestTemplate sslRestTemplate = SslUtils.createIgnoreSSLRestTemplate(); |
| | | |
| | | // 设置错误处理器,不抛出异常,而是返回响应体 |
| | | sslRestTemplate.setErrorHandler(new org.springframework.web.client.DefaultResponseErrorHandler() { |
| | | @Override |
| | | public boolean hasError(ClientHttpResponse response) throws IOException { |
| | | // 不管状态码如何,都不视为错误 |
| | | return false; |
| | | } |
| | | }); |
| | | |
| | | ResponseEntity<String> exchange = sslRestTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class); |
| | | log.info("Erp POST请求响应结果: {}", exchange); |
| | | |
| | | if (Objects.isNull(exchange.getBody())) { |
| | |
| | | throw new CoolException("Erp解析响应失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * HTTP POST请求示例 - 支持HTTPS |
| | | * |
| | | * @param url 请求URL |
| | | * @param params 请求参数 |
| | | * @return 响应结果 |
| | | */ |
| | | public String httpPostExample(String url, String params) { |
| | | if (httpClient == null) { |
| | | httpClient = createHttpsClient(); |
| | | } |
| | | HttpPost httpPost = new HttpPost(url); |
| | | try { |
| | | StringEntity entity = new StringEntity(params, "UTF-8"); |
| | | httpPost.setEntity(entity); |
| | | httpPost.setHeader("Content-type", "application/json;charset=utf-8"); |
| | | httpPost.setHeader("Accept", "application/json"); |
| | | return EntityUtils.toString(httpClient.execute(httpPost).getEntity()); |
| | | } catch (Exception e) { |
| | | log.error("HTTP POST请求失败: {}", e.getMessage(), e); |
| | | throw new CoolException("HTTP POST请求失败: " + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 使用RestTemplate的HTTPS POST请求示例 |
| | | * |
| | | * @param url 请求URL |
| | | * @param params 请求参数 |
| | | * @return 响应结果 |
| | | */ |
| | | public String httpsPostWithRestTemplate(String url, String params) { |
| | | try { |
| | | log.info("HTTPS POST请求: {}, 请求参数: {}", url, params); |
| | | |
| | | HttpHeaders headers = new HttpHeaders(); |
| | | headers.add("Content-Type", "application/json;charset=utf-8"); |
| | | headers.add("Accept", "application/json"); |
| | | |
| | | HttpEntity<String> httpEntity = new HttpEntity<>(params, headers); |
| | | |
| | | // 使用项目中已有的SSL工具类创建忽略SSL证书验证的RestTemplate |
| | | RestTemplate sslRestTemplate = SslUtils.createIgnoreSSLRestTemplate(); |
| | | |
| | | // 设置错误处理器,不抛出异常,而是返回响应体 |
| | | sslRestTemplate.setErrorHandler(new org.springframework.web.client.DefaultResponseErrorHandler() { |
| | | @Override |
| | | public boolean hasError(ClientHttpResponse response) throws IOException { |
| | | // 不管状态码如何,都不视为错误 |
| | | return false; |
| | | } |
| | | }); |
| | | |
| | | ResponseEntity<String> exchange = sslRestTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class); |
| | | log.info("HTTPS POST请求响应结果: {}", exchange); |
| | | |
| | | if (Objects.isNull(exchange.getBody())) { |
| | | throw new CoolException("请求失败!!"); |
| | | } |
| | | |
| | | return exchange.getBody(); |
| | | } catch (Exception e) { |
| | | log.error("HTTPS POST请求失败: {}", e.getMessage(), e); |
| | | throw new CoolException("HTTPS POST请求失败: " + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 创建支持HTTPS的HttpClient |
| | | * |
| | | * @return CloseableHttpClient实例 |
| | | */ |
| | | private CloseableHttpClient createHttpsClient() { |
| | | try { |
| | | // 创建信任所有证书的TrustManager |
| | | TrustManager[] trustAllCerts = new TrustManager[] { |
| | | new X509TrustManager() { |
| | | public X509Certificate[] getAcceptedIssuers() { return null; } |
| | | public void checkClientTrusted(X509Certificate[] certs, String authType) { } |
| | | public void checkServerTrusted(X509Certificate[] certs, String authType) { } |
| | | } |
| | | }; |
| | | |
| | | // 初始化SSLContext |
| | | SSLContext sslContext = SSLContext.getInstance("TLS"); |
| | | sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); |
| | | |
| | | // 创建SSL连接管理器 |
| | | SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( |
| | | sslContext, |
| | | (hostname, session) -> true // 允许所有主机名 |
| | | ); |
| | | |
| | | // 创建HttpClientBuilder并设置SSL配置 |
| | | RequestConfig config = RequestConfig.custom() |
| | | .setConnectTimeout(30000) // 连接超时时间 |
| | | .setSocketTimeout(60000) // 读取超时时间 |
| | | .build(); |
| | | |
| | | return HttpClients.custom() |
| | | .setSSLSocketFactory(sslsf) |
| | | .setDefaultRequestConfig(config) |
| | | .build(); |
| | | } catch (Exception e) { |
| | | log.error("创建HTTPS客户端失败: {}", e.getMessage(), e); |
| | | return HttpClients.createDefault(); // 回退到默认客户端 |
| | | } |
| | | } |
| | | |
| | | // /** |
| | | // * 示例:如何使用HTTPS POST方法 |
| | | // * |
| | | // * @param url 目标URL |
| | | // * @param jsonData JSON数据 |
| | | // * @return 响应结果 |
| | | // */ |
| | | // public String exampleUsage(String url, String jsonData) { |
| | | // log.info("开始调用HTTPS POST请求示例"); |
| | | // |
| | | // try { |
| | | // // 方法1: 使用Apache HttpClient |
| | | // String result1 = httpPostExample(url, jsonData); |
| | | // log.info("使用HttpClient的POST请求结果: {}", result1); |
| | | // |
| | | // // 方法2: 使用RestTemplate |
| | | // String result2 = httpsPostWithRestTemplate(url, jsonData); |
| | | // log.info("使用RestTemplate的POST请求结果: {}", result2); |
| | | // |
| | | // // 根据实际需要选择返回结果 |
| | | // return result1; |
| | | // } catch (Exception e) { |
| | | // log.error("HTTPS POST请求示例执行失败: {}", e.getMessage(), e); |
| | | // throw e; |
| | | // } |
| | | // } |
| | | |
| | | } |