package com.malk.huagao.service.impl; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpResponse; 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.malk.huagao.entity.*; import com.malk.huagao.mapper.KdYdDeliveryDetailMapper; import com.malk.huagao.mapper.KdYdDeliveryMapper; import com.malk.huagao.mapper.KdYdOrderDetailMapper; import com.malk.huagao.mapper.KdYdOrderMapper; import com.malk.huagao.service.IKdYdDeliveryService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.malk.server.aliwork.YDConf; import com.malk.server.aliwork.YDParam; import com.malk.server.common.McException; import com.malk.server.dingtalk.DDR_New; import com.malk.service.aliwork.YDClient; import com.malk.utils.UtilMap; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringEscapeUtils; import org.slf4j.MDC; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.*; /** *

* 服务实现类 *

* * @author LQY * @since 2025-10-15 */ @Service @Slf4j public class KdYdDeliveryServiceImpl extends ServiceImpl implements IKdYdDeliveryService { @Autowired private YDClient ydClient; @Autowired private KdYdDeliveryMapper kdYdDeliveryMapper; @Autowired private KdYdDeliveryDetailMapper kdYdDeliveryDetailMapper; @Value(value = "${kd.host}") private String kdHost; @Override public Map insertDelivery(Map map) { Map result = new HashMap<>(); try { MDC.put("MDC_KEY_PID", "1003"); String formInstId = UtilMap.getString(map, "formInstId"); String action = UtilMap.getString(map, "type"); // 处理特殊操作类型 // 处理特殊操作类型 if ("del".equals(action)) { String bm = UtilMap.getString(map, "bm"); int maxRetries = 3; boolean success = false; String lastResponse = ""; for (int i = 0; i < maxRetries; i++) { Map headers = new HashMap<>(); headers.put("Content-Type", "application/x-www-form-urlencoded"); Map formParams = new HashMap<>(); Map requestBody = new HashMap<>(); Map djbh = new HashMap<>(); djbh.put("djbh", bm); requestBody.put("data", djbh); String jsonStr = JSON.toJSONString(requestBody); formParams.put("jsons", jsonStr); HttpResponse response = HttpRequest.post(kdHost + "/xk/dyzn/WsBasedyzn.asmx/hgdjydtbdeletefhtzd") .headerMap(headers, true) .form(formParams) .timeout(30000) .execute(); lastResponse = response.body(); log.info("第{}次删除返回值: {}", i + 1, lastResponse); if (lastResponse != null && lastResponse.contains("\"code\":200")) { success = true; break; } if (i < maxRetries - 1) { try { long delay = 2000 + (i * 1000); log.info("等待 {} 秒后重试", delay / 1000); Thread.sleep(delay); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } result.put("table", "KD_YD_DELIVERY"); result.put("action", "del"); Map dataMap = new HashMap<>(); dataMap.put("bm", bm); dataMap.put("msg", success ? "删除成功" : "删除失败,已重试" + maxRetries + "次"); if (!success) { dataMap.put("error", lastResponse); } result.put("data", dataMap); return result; } // 查询表单数据 DDR_New ddrNew = ydClient.queryData(YDParam.builder() .formInstId(formInstId) .build(), YDConf.FORM_QUERY.retrieve_id); Map formData = ddrNew.getFormData(); // 提取主表字段 String djlx = UtilMap.getString(formData, "selectField_mg3fuqvg"); String orderId = UtilMap.getString(formData, "textField_mf6a0h6f"); LocalDateTime rq = parseTimestamp(UtilMap.getString(formData, "dateField_krbgloam")); String kh = UtilMap.getString(formData, "textField_mejnamf2"); String jsbb = UtilMap.getString(formData, "selectField_mg3fuqvn"); String djbh = UtilMap.getString(formData, "serialNumberField_mheazm7w"); String xsbm = UtilMap.getString(formData, "textField_krnn5bmr"); String lllx = UtilMap.getString(formData, "selectField_mejowmnc"); String jjr = UtilMap.getString(formData, "textField_mf6a0h5f"); String jjrdh = UtilMap.getString(formData, "textField_mf6a0h5g"); String jjdz = UtilMap.getString(formData, "textareaField_mf6a0h5h"); String xslx = UtilMap.getString(formData, "selectField_mgrn6p2d"); String bzfs = UtilMap.getString(formData, "selectField_mf6a0h5y"); String hqdmb = UtilMap.getString(formData, "selectField_mg4hjsig"); String bz = UtilMap.getString(formData, "textareaField_mejnamfb"); String ckddh = UtilMap.getString(formData, "textField_mqg2b2g5"); // LocalDateTime hhsj = parseTimestamp(UtilMap.getString(formData, "dateField_mf6a0h67")); LocalDateTime hhsj = Optional.ofNullable( parseTimestamp(UtilMap.getString(formData, "dateField_mf6a0h67")) ) .orElseGet(() -> LocalDateTime.now() .withHour(17) .withMinute(0) .withSecond(0) .withNano(0)); String ysfs = UtilMap.getString(formData, "selectField_mf6a0h5z"); String hdfs = UtilMap.getString(formData, "selectField_mf6a0h60"); String kdgs = UtilMap.getString(formData, "selectField_mf6a0h61"); String fkfs = UtilMap.getString(formData, "selectField_mf6a0h66"); // 处理明细数据 List> deliveryList = new ArrayList<>(); List tableField = (List) formData.get("tableField_mejnamfd"); if (tableField != null && !tableField.isEmpty()) { // int detailId = 1; for (Map item : tableField) { Map table1Map = new HashMap<>(); int detailId = parseInt(safeGetString(item, "numberField_mjzg06br"), 1); String wlbm = safeGetString(item, "textField_mejnamff"); String wlmc = safeGetString(item, "textField_mejnamfg"); String ggxh = safeGetString(item, "textField_mejnamfh"); String xsdw = safeGetString(item, "textField_mejnamfk"); int jjsl = parseInt(safeGetString(item, "numberField_mf6a0h6r"), 0); // int count = parseInt(safeGetString(item, "numberField_mjzg06br"), 0); String ssxl = safeGetString(item, "textField_mejnamfx"); String sfzp = safeGetString(item, "radioField_mf6a0h6h"); String ckck = safeGetString(item, "textField_mf6a0h6l"); String ckcw = safeGetString(item, "textField_mf6a0h6k"); String sjr = safeGetString(item, "textField_mejnamf6"); String sjdh = safeGetString(item, "textField_mejnamf7"); String sjdz = safeGetString(item, "textareaField_mf6a0h5e"); String bz1 = safeGetString(item, "textareaField_mf6a0h6q"); String zbq = safeGetString(item, "numberField_mf6a0h6v"); String kddh = safeGetString(item, "textField_mf6a0h6w"); String mdh = safeGetString(item, "textField_mf6a0h6y"); String sku = safeGetString(item, "textField_mqg2b2g6"); String skuh = safeGetString(item, "textField_mqg2p1zi"); LocalDateTime yhrq = parseTimestamp(safeGetString(item, "dateField_mejnamfo")); table1Map.put("wlbm", wlbm); table1Map.put("detailId", detailId); table1Map.put("wlmc", wlmc); table1Map.put("sku", sku); table1Map.put("skuh", skuh); table1Map.put("ggxh", ggxh); table1Map.put("xsdw", xsdw); table1Map.put("jjsl", jjsl); // table1Map.put("count", count); table1Map.put("bz1", bz1); table1Map.put("ssxl", ssxl); table1Map.put("yhrq", yhrq); table1Map.put("sfzp", sfzp); table1Map.put("ckck", ckck); table1Map.put("ckcw", ckcw); table1Map.put("sjr", sjr); table1Map.put("sjdh", sjdh); table1Map.put("sjdz", sjdz); table1Map.put("zbq", zbq); table1Map.put("kddh", kddh); table1Map.put("mdh", mdh); deliveryList.add(table1Map); // detailId++; } } // 构建返回数据 Map deliveryData = new HashMap<>(); deliveryData.put("djlx", djlx); deliveryData.put("orderId", orderId); deliveryData.put("rq", rq); deliveryData.put("ckddh", ckddh); deliveryData.put("kh", kh); deliveryData.put("jsbb", jsbb); deliveryData.put("djbh", djbh); deliveryData.put("xsbm", xsbm); deliveryData.put("lllx", lllx); deliveryData.put("jjr", jjr); deliveryData.put("jjrdh", jjrdh); deliveryData.put("jjdz", jjdz); deliveryData.put("hqdmb", hqdmb); deliveryData.put("xslx", xslx); deliveryData.put("bzfs", bzfs); deliveryData.put("bz", bz); deliveryData.put("hhsj", hhsj); deliveryData.put("ysfs", ysfs); deliveryData.put("hdfs", hdfs); deliveryData.put("kdgs", kdgs); deliveryData.put("fkfs", fkfs); deliveryData.put("DeliveryList", deliveryList); Map headers = new HashMap<>(); headers.put("Content-Type", "application/x-www-form-urlencoded"); result.put("data", deliveryData); // 将result转换为JSON字符串 String jsonStr = JSON.toJSONString(result); // 构建form参数 Map formParams = new HashMap<>(); formParams.put("jsons", jsonStr); log.info("请求参数:" + formParams); // 发送请求(带重试功能) String responseBody = null; int maxRetries = 3; boolean requestSuccess = false; for (int retryCount = 0; retryCount < maxRetries; retryCount++) { try { if (retryCount > 0) { log.info("第{}次重试新增请求...", retryCount); Thread.sleep(1500 * retryCount); } HttpResponse response = null; if ("add".equals(action)) { response = HttpRequest.post(kdHost + "/xk/dyzn/WsBasedyzn.asmx/hgdjydtbcreatefhtzd") .headerMap(headers, true) .form(formParams) .timeout(30000) .execute(); } else { response = HttpRequest.post(kdHost + "/xk/dyzn/WsBasedyzn.asmx/") .headerMap(headers, true) .form(formParams) .timeout(30000) .execute(); } responseBody = response.body(); log.info("第{}次请求返回结果:{}", retryCount + 1, responseBody); if (responseBody != null && !responseBody.isEmpty()) { try { JSONArray jsonArray = JSONArray.parseArray(responseBody); if (jsonArray != null && !jsonArray.isEmpty()) { JSONObject jsonObject = jsonArray.getJSONObject(0); Integer code = jsonObject.getInteger("code"); if (code != null && code == 200) { requestSuccess = true; log.info("新增发货通知单成功"); break; } else { log.warn("请求返回错误码:{},第{}次尝试失败,将进行重试", code, retryCount + 1); } } } catch (Exception parseException) { log.error("解析返回结果异常:{}", parseException.getMessage()); if (retryCount == maxRetries - 1) { throw new RuntimeException("解析返回结果失败", parseException); } } } else { log.warn("返回响应为空,第{}次尝试失败", retryCount + 1); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.error("重试被中断", e); break; } catch (Exception e) { log.error("请求异常,第{}次尝试失败:{}", retryCount + 1, e.getMessage()); if (retryCount == maxRetries - 1) { throw new RuntimeException("新增请求失败,已重试" + maxRetries + "次", e); } } } try { String msg = JSON.parseArray(responseBody) .getJSONObject(0) .getString("msg"); String code = JSON.parseArray(responseBody) .getJSONObject(0) .getString("code"); ydClient.operateData( YDParam.builder() .formInstanceId(formInstId) .updateFormDataJson(JSONObject.toJSONString(UtilMap.map("textField_ml08nk3y, textareaField_mkz9u4p9", code, msg))) .useLatestVersion(true).build(), YDConf.FORM_OPERATION.update); } catch (Exception e) { System.out.println("解析JSON失败: " + e.getMessage()); } } catch (Exception e) { log.error("发货通知单同步异常", e); result.put("table", "KD_YD_DELIVERY"); result.put("action", "error"); result.put("data", new HashMap() {{ put("errorMsg", "操作失败:" + e.getMessage()); }}); } return result; } @Override public void CfkdYdDelivery(Map map) { MDC.put("MDC_KEY_PID", "1003"); String formInstId = UtilMap.getString(map, "formInstId"); // 查询原表单数据 DDR_New ddrNew = retryQueryData( YDParam.builder().formInstId(formInstId).build(), YDConf.FORM_QUERY.retrieve_id ); Map formData1 = ddrNew.getFormData(); // 提取需要特殊处理的主表字段 String glbdjson = String.valueOf(formData1.get("associationFormField_mejmml36_id")); String sqr = String.valueOf(formData1.get("employeeField_krbgloal_id")); String xsy = String.valueOf(formData1.get("employeeField_mejnamf3_id")); String xszg = String.valueOf(formData1.get("employeeField_mmsna3tn_id")); String zssj = String.valueOf(formData1.get("employeeField_mmsna3tm_id")); String fhtzd = String.valueOf(formData1.get("serialNumberField_mheazm7w")); // 解析关联字段 JSON List sealjsonlist = parseJsonList(glbdjson); // 获取原表单的子表数据 List tableField = UtilMap.getList(formData1, "tableField_mejnamfd"); if (tableField == null || tableField.isEmpty()) { return; } // 按 dz 分组 Map> groupedByDz = new LinkedHashMap<>(); for (Map item : tableField) { String dz = UtilMap.getString(item, "textareaField_mf6a0h5e"); if (dz == null) dz = ""; groupedByDz.computeIfAbsent(dz, k -> new ArrayList<>()).add(item); } // 对每个 dz 分组,创建一条新表单 for (Map.Entry> entry : groupedByDz.entrySet()) { String dz = entry.getKey(); List subTableRows = entry.getValue(); // 构建新子表数据 List newSubTable = new ArrayList<>(); for (Map row : subTableRows) { newSubTable.add(new HashMap<>(row)); } // 构建新表单的formData HashMap updateMap = new HashMap<>(); // 1. 首先复制原表单的所有主表数据 for (Object obj : formData1.entrySet()) { Map.Entry formEntry = (Map.Entry) obj; String key = formEntry.getKey(); Object value = formEntry.getValue(); // 跳过不需要特殊处理的子表字段 if ("tableField_mejnamfd".equals(key)) { continue; } // 跳过需要特殊处理的主表关联字段 if (key.equals("associationFormField_mejmml36_id") || key.equals("associationFormField_mfavc4ve_id") || key.equals("associationFormField_mk0gzflu_id") || key.equals("employeeField_krbgloal_id") || key.equals("employeeField_mejnamf3_id") || key.equals("employeeField_mmsna3tn_id") || key.equals("employeeField_mmsna3tm_id") || key.equals("serialNumberField_mheazm7w")) { continue; } // 复制其他字段 updateMap.put(key, value); } // 2. 添加需要特殊处理的主表字段 updateMap.put("associationFormField_mejmml36", sealjsonlist); // updateMap.put("associationFormField_mfavc4ve", khjsonlist); updateMap.put("associationFormField_mk0gzflu", Arrays.asList(getfhdAss(fhtzd, formInstId))); updateMap.put("employeeField_krbgloal", sqr); updateMap.put("employeeField_mejnamf3", xsy); updateMap.put("employeeField_mmsna3tn", xszg); updateMap.put("employeeField_mmsna3tm", zssj); updateMap.put("textField_mjzk47so", fhtzd); // 3. 添加处理后的子表数据 updateMap.put("tableField_mejnamfd", newSubTable); String sqrid = sqr.substring(2, sqr.length() - 2); String xszgid = xszg.substring(2, xszg.length() - 2); String finalId = (sqrid == null || sqrid.trim().isEmpty()) ? xszgid : sqrid; System.out.println("sqrid==" + sqrid); // 创建新表单实例 try { retryOperateData( YDParam.builder() .formUuid("FORM-FAE2575E112644ED914CAB4FEC9309F32AVR") .formDataJson(JSON.toJSONString(updateMap)) .userId(finalId) .build(), YDConf.FORM_OPERATION.create ); } catch (Exception e) { log.error("创建新单据失败,dz=" + dz, e); } try { Thread.sleep(3000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.error("线程被中断", e); } } } // 工具方法:安全解析 JSON 列表(处理宜搭返回的带引号字符串) private List parseJsonList(String jsonStr) { if (jsonStr == null || "null".equals(jsonStr) || jsonStr.isEmpty()) { return Collections.emptyList(); } try { // 宜搭有时返回的是 "\"[{...}]\"",需先 unescape String clean = StringEscapeUtils.unescapeJava(jsonStr); // 如果首尾是双引号,去掉 if (clean.startsWith("\"") && clean.endsWith("\"")) { clean = clean.substring(1, clean.length() - 1); } return (List) JSONArray.parse(clean); } catch (Exception e) { return Collections.emptyList(); } } private Object getfhdAss(String title, String id) { return UtilMap.map("appType, formUuid, formType, instanceId, title, subTitle", "APP_VQDMMWS6OR1VHL8VMFD3", "FORM-A7F03ACEE01D4F609550C86BF7FE87D35M6I", "receipt", id, title, ""); } private static LocalDateTime parseTimestamp(String timestampStr) { if (timestampStr == null || timestampStr.trim().isEmpty()) return null; try { long timestamp = Long.parseLong(timestampStr.trim()); return LocalDateTime.ofInstant( Instant.ofEpochMilli(timestamp), ZoneId.systemDefault() ); } catch (NumberFormatException e) { return null; } } private static int parseInt(String str, int defaultValue) { if (str == null || str.trim().isEmpty()) { return defaultValue; } try { return Integer.parseInt(str.trim()); } catch (NumberFormatException e) { return defaultValue; } } private String safeGetString(Map formData, String key) { Object val = formData.get(key); return val == null ? "" : String.valueOf(val); } public static BigDecimal toBigDecimal(String str) { if (str == null || str.trim().isEmpty()) { return BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP); } try { return new BigDecimal(str.trim()) .setScale(6, RoundingMode.HALF_UP); } catch (NumberFormatException e) { // 返回默认值而不是抛出异常,避免程序中断 return BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP); } } /** * 重载方法,支持Number类型输入 */ // public static BigDecimal toBigDecimal(Number number) { // if (number == null) { // return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP); // } // return new BigDecimal(number.toString()) // .setScale(2, RoundingMode.HALF_UP); // } //自带重试的operateData方法 private Object retryOperateData(YDParam param, YDConf.FORM_OPERATION formOperation) { int maxAttempts = 3; // 尝试的最大次数 int attempt = 0; long baseWaitTime = 3000; // 基础等待时间3秒 while (attempt < maxAttempts) { try { Object result = ydClient.operateData(param, formOperation); // 成功调用后,如果有之前失败的重试日志,记录成功 if (attempt > 0) { log.info("第{}次重试成功", attempt + 1); } return result; } catch (McException e) { String errorMsg = e.getMessage(); log.warn("第{}次调用失败,错误信息:{}", attempt + 1, errorMsg); // 判断是否是可重试的异常 if (isRetryableError(errorMsg)) { attempt++; // 如果已达到最大尝试次数,不再重试,直接抛出异常 if (attempt >= maxAttempts) { log.error("已达最大重试次数{}次,放弃重试", maxAttempts); throw new RuntimeException("超出最大重试次数, param:" + JSONObject.toJSONString(param) + ", FORM_OPERATION:" + formOperation, e); } // 线程睡眠,使用指数退避策略 try { long waitTime = baseWaitTime * (long) Math.pow(2, attempt - 1); log.info("等待{}ms后重试第{}次, param:{}, FORM_OPERATION:{}", waitTime, attempt + 1, JSONObject.toJSONString(param), formOperation); Thread.sleep(waitTime); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); // 重新设置中断状态 log.error("重试睡眠被中断", ie); throw new RuntimeException("重试过程被中断", ie); } } else { // 不可重试的异常,直接抛出 log.error("发生不可重试的异常,直接失败: {}", errorMsg); throw new RuntimeException("宜搭操作失败: " + errorMsg, e); } } catch (Exception e) { // 非McException异常,直接抛出,不重试 log.error("操作失败,param:{},FORM_OPERATION:{},异常信息:{}", JSONObject.toJSONString(param), formOperation, e.getMessage()); throw new RuntimeException(e); } } // 理论上不会执行到这里,但为了安全保留 throw new RuntimeException("超出最大重试次数, param:" + JSONObject.toJSONString(param) + ", FORM_OPERATION:" + formOperation); } //自带重试的queryData方法 private DDR_New retryQueryData(YDParam param, YDConf.FORM_QUERY formQuery) { int maxAttempts = 3; // 尝试的最大次数 int attempt = 0; long baseWaitTime = 3000; // 基础等待时间3秒 while (attempt < maxAttempts) { try { DDR_New result = ydClient.queryData(param, formQuery); // 成功调用后,如果有之前失败的重试日志,记录成功 if (attempt > 0) { log.info("第{}次重试查询成功", attempt + 1); } return result; } catch (McException e) { String errorMsg = e.getMessage(); log.warn("第{}次查询失败,错误信息:{}", attempt + 1, errorMsg); // 判断是否是可重试的异常 if (isRetryableError(errorMsg)) { attempt++; // 如果已达到最大尝试次数,不再重试,直接抛出异常 if (attempt >= maxAttempts) { log.error("已达最大重试次数{}次,放弃重试查询", maxAttempts); throw new RuntimeException("超出最大重试次数, param:" + JSONObject.toJSONString(param) + ", FORM_QUERY:" + formQuery, e); } // 线程睡眠,使用指数退避策略 try { long waitTime = baseWaitTime * (long) Math.pow(2, attempt - 1); log.info("等待{}ms后重试第{}次查询, param:{}, FORM_QUERY:{}", waitTime, attempt + 1, JSONObject.toJSONString(param), formQuery); Thread.sleep(waitTime); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); // 重新设置中断状态 log.error("重试查询睡眠被中断", ie); throw new RuntimeException("重试查询过程被中断", ie); } } else { // 不可重试的异常,直接抛出 log.error("发生不可重试的异常,查询直接失败: {}", errorMsg); throw new RuntimeException("宜搭查询失败: " + errorMsg, e); } } catch (Exception e) { // 非McException异常,直接抛出,不重试 log.error("查询操作失败,param:{},FORM_QUERY:{},异常信息:{}", JSONObject.toJSONString(param), formQuery, e.getMessage()); throw new RuntimeException(e); } } // 理论上不会执行到这里,但为了安全保留 throw new RuntimeException("超出最大重试次数, param:" + JSONObject.toJSONString(param) + ", FORM_QUERY:" + formQuery); } /** * 判断是否是可重试的错误 */ private boolean isRetryableError(String errorMsg) { if (errorMsg == null) return false; // 可重试的错误关键字列表(扩展了匹配范围) String[] retryableKeywords = { "temporary failure", "未知异常", "timeout", "Timeout", "Connection refused", "Internal Server", "服务不可用", "Service Unavailable", "Gateway Timeout", "Bad Gateway" }; for (String keyword : retryableKeywords) { if (errorMsg.contains(keyword)) { return true; } } return false; } }