KdYdOrderServiceImpl.java 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954
  1. package com.malk.huagao.service.impl;
  2. import cn.hutool.http.HttpRequest;
  3. import cn.hutool.http.HttpResponse;
  4. import cn.hutool.http.HttpUtil;
  5. import com.alibaba.fastjson.JSON;
  6. import com.alibaba.fastjson.JSONArray;
  7. import com.alibaba.fastjson.JSONObject;
  8. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  9. import com.malk.huagao.entity.*;
  10. import com.malk.huagao.mapper.KdYdOrderDetailMapper;
  11. import com.malk.huagao.mapper.KdYdOrderMapper;
  12. import com.malk.huagao.mapper.KdYdOrderPaymentMapper;
  13. import com.malk.huagao.service.IKdYdOrderService;
  14. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  15. import com.malk.server.aliwork.YDConf;
  16. import com.malk.server.aliwork.YDParam;
  17. import com.malk.server.aliwork.YDSearch;
  18. import com.malk.server.common.McException;
  19. import com.malk.server.common.McR;
  20. import com.malk.server.dingtalk.DDR_New;
  21. import com.malk.service.aliwork.YDClient;
  22. import com.malk.utils.UtilHttp;
  23. import com.malk.utils.UtilMap;
  24. import lombok.extern.slf4j.Slf4j;
  25. import org.apache.commons.lang3.StringUtils;
  26. import org.slf4j.MDC;
  27. import org.springframework.beans.factory.annotation.Autowired;
  28. import org.springframework.beans.factory.annotation.Value;
  29. import org.springframework.stereotype.Service;
  30. import java.math.BigDecimal;
  31. import java.math.RoundingMode;
  32. import java.text.SimpleDateFormat;
  33. import java.time.Instant;
  34. import java.time.LocalDateTime;
  35. import java.time.ZoneId;
  36. import java.util.*;
  37. /**
  38. * <p>
  39. * 服务实现类
  40. * </p>
  41. *
  42. * @author LQY
  43. * @since 2025-10-15
  44. */
  45. @Service
  46. @Slf4j
  47. public class KdYdOrderServiceImpl extends ServiceImpl<KdYdOrderMapper, KdYdOrder> implements IKdYdOrderService {
  48. @Autowired
  49. private YDClient ydClient;
  50. @Autowired
  51. private KdYdOrderMapper kdYdOrderMapper;
  52. @Autowired
  53. private KdYdOrderDetailMapper kdYdOrderDetailMapper;
  54. @Autowired
  55. private KdYdOrderPaymentMapper kdYdOrderPaymentMapper;
  56. @Value(value = "${kd.host}")
  57. private String kdHost;
  58. @Override
  59. public Map<String, Object> insertkdYdOrder(Map map) {
  60. Map<String, Object> result = new HashMap<>();
  61. try {
  62. MDC.put("MDC_KEY_PID", "1003");
  63. String formInstId = UtilMap.getString(map, "formInstId");
  64. String type = UtilMap.getString(map, "type");
  65. // 处理特殊操作类型
  66. if ("del".equals(type)) {
  67. String bm = UtilMap.getString(map, "bm");
  68. Map<String, String> headers = new HashMap<>();
  69. headers.put("Content-Type", "application/x-www-form-urlencoded");
  70. Map<String, Object> formParams = new HashMap<>();
  71. Map<String, Object> djbh = new HashMap<>();
  72. djbh.put("djbh", bm);
  73. result.put("data", djbh);
  74. String jsonStr = JSON.toJSONString(result);
  75. formParams.put("jsons", jsonStr);
  76. System.out.println("====" + formParams);
  77. HttpResponse response = HttpRequest.post(kdHost+"/xk/dyzn/WsBasedyzn.asmx/hgdjydtbdeletexsdd")
  78. .headerMap(headers, true)
  79. .form(formParams)
  80. .timeout(30000) // 30秒超时
  81. .execute();
  82. String responseBody = response.body();
  83. // 返回删除操作的格式
  84. result.put("table", "KD_YD_ORDER");
  85. result.put("action", "del");
  86. result.put("data", new HashMap<String, Object>() {{
  87. put("bm", bm); // 删除的主键或标识
  88. put("msg", "删除成功");
  89. }});
  90. return result;
  91. }
  92. if ("cancel".equals(type)) {
  93. String bm = UtilMap.getString(map, "bm");
  94. Map<String, String> headers = new HashMap<>();
  95. headers.put("Content-Type", "application/x-www-form-urlencoded");
  96. Map<String, Object> formParams = new HashMap<>();
  97. Map<String, Object> djbh = new HashMap<>();
  98. djbh.put("djbh", bm);
  99. result.put("data", djbh);
  100. String jsonStr = JSON.toJSONString(result);
  101. System.out.println("==" + jsonStr);
  102. formParams.put("jsons", jsonStr);
  103. HttpResponse response = HttpRequest.post(kdHost+"/xk/dyzn/WsBasedyzn.asmx/hgdjydtbExcuteOperationxsdd")
  104. .headerMap(headers, true)
  105. .form(formParams)
  106. .timeout(30000) // 30秒超时
  107. .execute();
  108. String responseBody = response.body();
  109. String msg = JSON.parseArray(responseBody)
  110. .getJSONObject(0)
  111. .getString("msg");
  112. String code = JSON.parseArray(responseBody)
  113. .getJSONObject(0)
  114. .getString("code");
  115. ydClient.operateData(
  116. YDParam.builder()
  117. .formInstanceId(formInstId)
  118. .updateFormDataJson(JSONObject.toJSONString(UtilMap.map("textField_ml08nk3y, textareaField_mkxqgrvq", code, msg)))
  119. .useLatestVersion(true).build(),
  120. YDConf.FORM_OPERATION.update);
  121. // 返回作废操作的格式
  122. result.put("table", "KD_YD_ORDER");
  123. result.put("action", "cancel"); // 作废通常是修改状态
  124. result.put("data", new HashMap<String, Object>() {{
  125. put("bm", bm); // 作废状态
  126. put("msg", "作废成功");
  127. // 其他作废需要的数据
  128. }});
  129. return result;
  130. }
  131. // 查询表单数据
  132. DDR_New ddrNew = retryQueryData(YDParam.builder()
  133. .formInstId(formInstId)
  134. .build(), YDConf.FORM_QUERY.retrieve_id);
  135. Map formData = ddrNew.getFormData();
  136. // 提取主表字段
  137. String djlx = UtilMap.getString(formData, "selectField_mejowmna");
  138. String khmc = UtilMap.getString(formData, "textField_mejnamf2");
  139. // String khmc = "五岳";
  140. // String djbh = UtilMap.getString(formData, "textField_mjs6fuwo");
  141. // 判断操作类型对应的action
  142. String actionType;
  143. String djbh = null;
  144. if ("edit".equals(type)) {
  145. // djbh = UtilMap.getString(formData, "textField_mjs6fuwo");
  146. // djbh = UtilMap.getString(formData, "textField_miwvnkep");
  147. djbh = StringUtils.isNotBlank(UtilMap.getString(formData, "textField_mjs6fuwo"))
  148. ? UtilMap.getString(formData, "textField_mjs6fuwo")
  149. : UtilMap.getString(formData, "textField_miwvnkep");
  150. actionType = "edit";
  151. } else {
  152. actionType = "add";
  153. djbh = "";
  154. }
  155. // 提取其他字段...
  156. LocalDateTime rq = parseTimestamp(UtilMap.getString(formData, "dateField_mejowmnb"));
  157. String khxypj = UtilMap.getString(formData, "selectField_mewirdx4");
  158. String ywlx = UtilMap.getString(formData, "textField_mfxv2vfz");
  159. String xsy = UtilMap.getString(formData, "employeeField_mejowmng").replace("[\"", "").replace("\"]", "").trim();
  160. String xslx = UtilMap.getString(formData, "selectField_mejowmnc");
  161. String bzq = UtilMap.getString(formData, "selectField_mf6gyfkq");
  162. String xsbm = UtilMap.getString(formData, "departmentSelectField_mfxv2vfu").replace("[\"", "").replace("\"]", "").trim();
  163. String bz = UtilMap.getString(formData, "textareaField_mejnamfb");
  164. String jsbb = UtilMap.getString(formData, "selectField_mejowmnk");
  165. String sktj = UtilMap.getString(formData, "selectField_mgisux07");
  166. String zdzkestr = UtilMap.getString(formData, "numberField_mejowmni");
  167. BigDecimal zdzke = toBigDecimal(zdzkestr);
  168. String sestr = UtilMap.getString(formData, "numberField_mfxv2vgh");
  169. BigDecimal se = toBigDecimal(sestr);
  170. String jestr = UtilMap.getString(formData, "numberField_mfxv2vgj");
  171. BigDecimal je = toBigDecimal(jestr);
  172. String jshjstr = UtilMap.getString(formData, "numberField_mewfgzkv");
  173. BigDecimal jshj = toBigDecimal(jshjstr);
  174. String sfhs = UtilMap.getString(formData, "radioField_mfxv2vg4");
  175. String ckddh = UtilMap.getString(formData, "textField_mqg2b2g5");
  176. String jws = UtilMap.getString(formData, "radioField_mfxv2vgm");
  177. List<Map> tableField = (List<Map>) formData.get("tableField_mfbx1pqi");
  178. List<Map> tableFieldPayment = (List<Map>) formData.get("tableField_mhiui6v5");
  179. // 处理订单明细
  180. List<Map<String, Object>> orderList = new ArrayList<>();
  181. if (tableField != null) {
  182. for (int i = 0; i < tableField.size(); i++) {
  183. Map item = tableField.get(i);
  184. Map<String, Object> table1Map = new HashMap<>();
  185. int detailId = parseInt(safeGetString(item, "numberField_mjzfodew"), 1);
  186. String wlbm = safeGetString(item, "textField_mfbx1pqt");
  187. // String wlbm = "010101010003";
  188. String wlmc = safeGetString(item, "textField_mfbx1pqs");
  189. // String kzfh = safeGetString1(item, "radioField_mqyje8pg");
  190. String sku = safeGetString(item, "textField_mqg2b2g6");
  191. String tcfpfs = safeGetString(item, "textField_mpqmsz2q");
  192. String yjfpfs = safeGetString(item, "textField_mpqmsz2r");
  193. String fpxsy = safeGetString(item, "textField_mpqmsz2s");
  194. String ggxh = safeGetString(item, "textField_mfbx1pqr");
  195. String xsdw = safeGetString(item, "textField_mfbx1pqq");
  196. int xssl = parseInt(safeGetString(item, "numberField_mfbx1pr4"), 0);
  197. String ssxl = safeGetString(item, "selectField_mfbx1pr1");
  198. BigDecimal dj = toBigDecimal(safeGetString(item, "numberField_mfbx1prf"));
  199. BigDecimal cxzkje = toBigDecimal(safeGetString(item, "numberField_mk56soin"));
  200. BigDecimal hsdj = toBigDecimal(safeGetString(item, "numberField_mfbx1prg"));
  201. String sfzp = safeGetString(item, "radioField_mfbx1prc");
  202. String bz1 = safeGetString(item, "textareaField_mjryuaok");
  203. int sl = parseInt(safeGetString(item, "numberField_mfbx1prb"), 0);
  204. BigDecimal zse = toBigDecimal(safeGetString(item, "numberField_mfbx1prh"));
  205. BigDecimal bbh = toBigDecimal1(safeGetString(item, "numberField_mowq936x"));
  206. BigDecimal zje = toBigDecimal(safeGetString(item, "numberField_mfbx1pri"));
  207. BigDecimal zjshj = toBigDecimal(safeGetString(item, "numberField_mfbx1prj"));
  208. BigDecimal jj = toBigDecimal(safeGetString(item, "numberField_mfbx1prk"));
  209. BigDecimal zkl = toBigDecimal(safeGetString(item, "numberField_mfbx1pru"));
  210. BigDecimal zke = toBigDecimal(safeGetString(item, "numberField_mfbx1prt"));
  211. LocalDateTime yhrq = parseTimestamp(UtilMap.getString(item, "dateField_mfbx1prs"));
  212. BigDecimal xsjzj = toBigDecimal(safeGetString(item, "numberField_mfbx1pr0"));
  213. String zmzs = safeGetString(item, "textField_mfxv2vgv");
  214. // 设置明细字段
  215. table1Map.put("detailId", detailId);
  216. table1Map.put("wlbm", wlbm);
  217. table1Map.put("sku", sku);
  218. // table1Map.put("kzfh", kzfh);
  219. table1Map.put("wlmc", wlmc);
  220. table1Map.put("ggxh", ggxh);
  221. table1Map.put("xsdw", xsdw);
  222. table1Map.put("xssl", xssl);
  223. table1Map.put("ssxl", ssxl);
  224. table1Map.put("dj", dj);
  225. table1Map.put("cxzkje", cxzkje);
  226. table1Map.put("hsdj", hsdj);
  227. table1Map.put("sfzp", sfzp);
  228. table1Map.put("bz", bz1);
  229. table1Map.put("sl", sl);
  230. table1Map.put("tcfpfs", tcfpfs);
  231. table1Map.put("yjfpfs", yjfpfs);
  232. table1Map.put("fpxsy", fpxsy);
  233. table1Map.put("se1", zse);
  234. table1Map.put("bbh", bbh);
  235. table1Map.put("je1", zje);
  236. table1Map.put("jshj1", zjshj);
  237. table1Map.put("jj", jj);
  238. table1Map.put("zkl", zkl);
  239. table1Map.put("zke", zke);
  240. table1Map.put("xsjzj", xsjzj);
  241. table1Map.put("zmzs", zmzs);
  242. table1Map.put("yhrq", yhrq);
  243. orderList.add(table1Map);
  244. }
  245. }
  246. // 处理付款明细
  247. List<Map<String, Object>> OrderPayList = new ArrayList<>();
  248. if (tableFieldPayment != null) {
  249. for (int i = 0; i < tableFieldPayment.size(); i++) {
  250. Map row = tableFieldPayment.get(i);
  251. Map<String, Object> table2Map = new HashMap<>();
  252. int detailId = i + 1;
  253. String sfys = safeGetString(row, "radioField_mhiui6v7");
  254. // String sjyskzfh = safeGetString(row, "radioField_ml7hg2oi");
  255. String gldh = safeGetString(row, "textField_mhiui6va");
  256. BigDecimal ysbl = toBigDecimal(UtilMap.getString(row, "numberField_mhiui6v6"));
  257. BigDecimal ysje = toBigDecimal(UtilMap.getString(row, "numberField_mhiui6v8"));
  258. BigDecimal ssje = toBigDecimal(UtilMap.getString(row, "numberField_mhiui6vb"));
  259. LocalDateTime endTime = parseTimestamp(UtilMap.getString(row, "dateField_mhiui6v9"));
  260. table2Map.put("detailId", detailId);
  261. table2Map.put("sfys", sfys);
  262. // table2Map.put("sjyskzfh", sjyskzfh);
  263. table2Map.put("gldh", gldh);
  264. table2Map.put("ysbl", ysbl);
  265. table2Map.put("ysje", ysje);
  266. table2Map.put("ssje", ssje);
  267. table2Map.put("endTime", endTime);
  268. OrderPayList.add(table2Map);
  269. }
  270. }
  271. // 构建主表数据,映射到数据库表字段
  272. Map<String, Object> orderData = new HashMap<>();
  273. // 注意:这里需要将字段名映射到数据库表字段名
  274. // 示例映射,实际需要根据数据库表结构调整
  275. orderData.put("djlx", djlx); // 单据类型
  276. orderData.put("djbh", djbh); // 单据编号
  277. orderData.put("ckddh", ckddh); // 单据编号
  278. orderData.put("khmc", khmc); // 客户名称
  279. orderData.put("rq", rq); // 日期
  280. orderData.put("khxypj", khxypj); // 客户信用评级
  281. orderData.put("ywlx", ywlx); // 业务类型
  282. orderData.put("xslx", xslx); // 销售类型
  283. orderData.put("bzq", bzq); // 保质期
  284. orderData.put("xsy", xsy); // 销售员
  285. orderData.put("xsbm", xsbm); // 销售部门
  286. orderData.put("bz", bz); // 备注
  287. orderData.put("jsbb", jsbb); // 结算币别
  288. orderData.put("sktj", sktj); // 收款条件
  289. orderData.put("zdzke", zdzke); // 整单折扣额
  290. orderData.put("se", se); // 税额
  291. orderData.put("je", je); // 金额
  292. orderData.put("jshj", jshj); // 价税合计
  293. orderData.put("sfhs", sfhs); // 是否含税
  294. orderData.put("jws", jws); // 价位税
  295. // 明细数据(需要根据实际数据库设计确定存储方式)
  296. // 如果明细是单独的表,可能需要单独处理
  297. orderData.put("OrderDetailList", orderList); // 订单明细列表
  298. orderData.put("PaymentDetailList", OrderPayList); // 付款明细列表
  299. Map<String, String> headers = new HashMap<>();
  300. headers.put("Content-Type", "application/x-www-form-urlencoded");
  301. result.put("data", orderData);
  302. // 将result转换为JSON字符串
  303. String jsonStr = JSON.toJSONString(result);
  304. // 构建form参数
  305. Map<String, Object> formParams = new HashMap<>();
  306. formParams.put("jsons", jsonStr);
  307. log.info("订单请求参数:" + formParams);
  308. // 发送请求
  309. HttpResponse response = null;
  310. if ("add".equals(actionType)) {
  311. response = HttpRequest.post(kdHost+"/xk/dyzn/WsBasedyzn.asmx/hgdjydtbxsdd")
  312. .headerMap(headers, true)
  313. .form(formParams)
  314. .timeout(30000) // 30秒超时
  315. .execute();
  316. } else {
  317. response = HttpRequest.post(kdHost+"/xk/dyzn/WsBasedyzn.asmx/hgdjydtbupdatexsdd")
  318. .headerMap(headers, true)
  319. .form(formParams)
  320. .timeout(30000) // 30秒超时
  321. .execute();
  322. }
  323. String responseBody = response.body();
  324. log.info("返回结果responseBody: " + responseBody);
  325. try {
  326. // 一行代码提取
  327. String jdbh = JSON.parseArray(responseBody)
  328. .getJSONObject(0)
  329. .getJSONObject("data")
  330. .getString("djbh");
  331. String msg = JSON.parseArray(responseBody)
  332. .getJSONObject(0)
  333. .getString("msg");
  334. String code = JSON.parseArray(responseBody)
  335. .getJSONObject(0)
  336. .getString("code");
  337. retryOperateData(
  338. YDParam.builder()
  339. .formInstanceId(formInstId)
  340. .updateFormDataJson(JSONObject.toJSONString(UtilMap.map("textField_ml08nk3y, textareaField_mkxqgrvq, textField_mjs6fuwo", code, msg, jdbh)))
  341. .useLatestVersion(true).build(),
  342. YDConf.FORM_OPERATION.update);
  343. } catch (Exception e) {
  344. System.out.println("解析JSON失败: " + e.getMessage());
  345. }
  346. } catch (Exception e) {
  347. // 异常处理
  348. result.put("table", "KD_YD_SALE_ORDER");
  349. result.put("action", "error");
  350. result.put("data", new HashMap<String, Object>() {{
  351. put("errorMsg", "操作失败:" + e.getMessage());
  352. }});
  353. // 可以添加日志记录
  354. // log.error("insertkdYdOrder error", e);
  355. }
  356. return result;
  357. }
  358. @Override
  359. public void SckdYdOrder(Map map) {
  360. MDC.put("MDC_KEY_PID", "1003");
  361. try {
  362. String formInstId = UtilMap.getString(map, "formInstId");
  363. String khbm = UtilMap.getString(map, "khbm");
  364. // 参数校验
  365. if (StringUtils.isBlank(formInstId)) {
  366. throw new RuntimeException("订单ID不能为空");
  367. }
  368. if (StringUtils.isBlank(khbm)) {
  369. throw new RuntimeException("客户编号不能为空");
  370. }
  371. // 1. 查询订单详情
  372. DDR_New ddrNew = retryQueryData(YDParam.builder()
  373. .formInstId(formInstId)
  374. .build(), YDConf.FORM_QUERY.retrieve_id);
  375. if (ddrNew == null || ddrNew.getFormData() == null) {
  376. throw new RuntimeException("未找到订单信息,订单ID:" + formInstId);
  377. }
  378. Map formData1 = ddrNew.getFormData();
  379. String ddje = UtilMap.getString(formData1, "numberField_mfxv2vgj");
  380. Long zhcjrq = UtilMap.getLong(formData1, "dateField_mejowmnb");
  381. // 订单金额校验
  382. if (ddje == null || ddje.trim().isEmpty()) {
  383. throw new RuntimeException("订单金额不能为空,订单ID:" + formInstId);
  384. }
  385. // 2. 计算订单金额
  386. Double orderAmount = null;
  387. try {
  388. orderAmount = Double.parseDouble(ddje);
  389. orderAmount = Math.round(orderAmount * 100.0) / 100.0;
  390. // 订单金额合理性校验
  391. if (orderAmount < 0) {
  392. throw new RuntimeException("订单金额不能为负数: " + orderAmount);
  393. }
  394. } catch (NumberFormatException e) {
  395. throw new RuntimeException("订单金额格式错误: " + ddje, e);
  396. }
  397. System.out.println("订单信息:订单ID=" + formInstId +
  398. ", 订单金额=" + orderAmount +
  399. ", 客户编号=" + khbm);
  400. // 3. 查询客户历史信息
  401. Object result = retryQueryData(YDParam.builder()
  402. .formUuid("FORM-F79B680547674A6BBD11C0D511E3C14B28FY")
  403. .searchFieldJson(JSONObject.toJSONString(Arrays.asList(
  404. new YDSearch("textField_mjm9k35n",
  405. khbm,
  406. "客户编号",
  407. YDSearch.Type.TEXT_FIELD,
  408. YDSearch.Operator.EQ)
  409. )))
  410. .build(), YDConf.FORM_QUERY.retrieve_list_all).getData();
  411. List<Map> list = (List<Map>) result;
  412. if (list == null || list.isEmpty()) {
  413. throw new RuntimeException("未找到客户信息,客户编号:" + khbm);
  414. }
  415. // 4. 获取客户现有信息并进行数据完整性校验
  416. Map customerData = (Map) list.get(0).get("formData");
  417. Double historicalAmount = UtilMap.getDouble(customerData, "numberField_mjm9k35k");
  418. Long dddateTimestampStr = UtilMap.getLong(customerData, "dateField_mjqkkcsg");
  419. Long sfdateTimestampStr = UtilMap.getLong(customerData, "dateField_mjm9k35l");
  420. String originalSelectFieldValue = UtilMap.getString(customerData, "selectField_l3nrjuq0");
  421. String originalKhsx = UtilMap.getString(customerData, "selectField_mjsco9d4");
  422. // 关键字段完整性校验
  423. if (dddateTimestampStr == null) {
  424. throw new RuntimeException("最后成交日期不能为空,客户编号:" + khbm);
  425. }
  426. if (historicalAmount == null) {
  427. // 历史金额为null时,记录错误日志并抛出异常,避免错误清零
  428. System.err.println("严重错误:未能获取到客户历史金额,客户编号:" + khbm +
  429. ",返回数据:" + JSONObject.toJSONString(customerData));
  430. throw new RuntimeException("无法获取客户历史金额,客户编号:" + khbm + ",请检查数据完整性");
  431. }
  432. // 记录更新前的数据快照,便于问题追踪
  433. System.out.println("更新前数据快照:客户编号=" + khbm +
  434. ", 历史金额=" + historicalAmount +
  435. ", 最后成交日期=" + timestampToDateString(dddateTimestampStr) +
  436. ", 公海池日期=" + (sfdateTimestampStr != null ? timestampToDateString(sfdateTimestampStr) : "空") +
  437. ", 销售属性=" + originalKhsx +
  438. ", 选择字段=" + originalSelectFieldValue);
  439. // 5. 金额计算和校验
  440. historicalAmount = Math.round(historicalAmount * 100.0) / 100.0;
  441. Double totalAmount = orderAmount + historicalAmount;
  442. totalAmount = Math.round(totalAmount * 100.0) / 100.0;
  443. // 金额变化监控:检测异常的大幅减少
  444. if (totalAmount < historicalAmount && totalAmount < historicalAmount * 0.5) {
  445. String errorMsg = String.format(
  446. "警告:金额异常减少!客户编号=%s, 订单金额=%.2f, 原历史金额=%.2f, 新总金额=%.2f, 减少比例=%.2f%%",
  447. khbm, orderAmount, historicalAmount, totalAmount,
  448. (historicalAmount - totalAmount) / historicalAmount * 100
  449. );
  450. System.err.println(errorMsg);
  451. // 根据业务需求决定是否抛出异常
  452. // throw new RuntimeException(errorMsg);
  453. }
  454. // 订单金额为0时的特殊处理:保持原金额不变
  455. if (orderAmount == 0 && historicalAmount > 0) {
  456. System.out.println("订单金额为0,保持原累计金额不变:" + historicalAmount);
  457. totalAmount = historicalAmount;
  458. }
  459. System.out.println("金额计算:订单金额=" + orderAmount +
  460. ", 历史金额=" + historicalAmount +
  461. ", 总金额=" + totalAmount);
  462. // 6. 时间计算
  463. long currentTimestamp = System.currentTimeMillis();
  464. long currentToDdDays = (currentTimestamp - dddateTimestampStr) / (1000 * 60 * 60 * 24);
  465. long sfToDdDays = (sfdateTimestampStr != null && sfdateTimestampStr > 0) ?
  466. (sfdateTimestampStr - dddateTimestampStr) / (1000 * 60 * 60 * 24) : 0;
  467. System.out.println("时间计算:当前时间=" + timestampToDateString(String.valueOf(currentTimestamp)) +
  468. ", 成交日期=" + timestampToDateString(String.valueOf(dddateTimestampStr)) +
  469. ", 当前-成交相差=" + currentToDdDays + "天" +
  470. ", 公海-成交相差=" + sfToDdDays + "天");
  471. // 7. 业务规则计算
  472. String ghcDateTimestamp = null;
  473. String selectFieldValue = originalSelectFieldValue;
  474. String khsx = originalKhsx;
  475. // 设置客户属性
  476. if (totalAmount >= 75000 && sfToDdDays <= 180) {
  477. khsx = "自行开发";
  478. }
  479. // 业务规则判断
  480. if (currentToDdDays < 90 && totalAmount > 0 && Math.abs(sfToDdDays - 180) <= 1) {
  481. // 条件1:在成交日期上加90天
  482. ghcDateTimestamp = String.valueOf(calculateTimestamp(sfdateTimestampStr, 90));
  483. selectFieldValue = "半年金额不足";
  484. System.out.println("条件1触发:公海池时间设为成交日期+90天=" +
  485. timestampToDateString(ghcDateTimestamp));
  486. } else if (totalAmount >= 75000 && sfToDdDays <= 180) {
  487. // 条件2:在成交日期上加180天
  488. ghcDateTimestamp = String.valueOf(calculateTimestamp(sfdateTimestampStr, 180));
  489. selectFieldValue = "半年金额不足";
  490. System.out.println("条件2触发:公海池时间设为成交日期+180天=" +
  491. timestampToDateString(ghcDateTimestamp));
  492. } else if (totalAmount < 150000 && sfToDdDays > 180) {
  493. // 条件3:设置一年金额不足,但不设置公海池日期
  494. selectFieldValue = "一年金额不足";
  495. System.out.println("条件3触发:金额<15万且公海日期>180天,设置一年金额不足");
  496. } else if (totalAmount > 150000) {
  497. // 【新增】总金额大于15万:释放公海池日期设为成交日期的下一年第一天
  498. ghcDateTimestamp = getNextYearFirstDay(dddateTimestampStr);
  499. selectFieldValue = "金额充足";
  500. System.out.println("条件4触发:总金额>15万,公海池时间设为成交日期下一年第一天=" +
  501. timestampToDateString(ghcDateTimestamp));
  502. } else {
  503. // 其他情况
  504. if (totalAmount > 0) {
  505. ghcDateTimestamp = String.valueOf(calculateTimestamp(sfdateTimestampStr, 90));
  506. selectFieldValue = "半年金额不足";
  507. System.out.println("基础情况:金额大于0,公海池时间+90天=" +
  508. timestampToDateString(ghcDateTimestamp));
  509. } else if (totalAmount < 75000) {
  510. selectFieldValue = "半年金额不足";
  511. System.out.println("金额<7.5万,但未设置公海池时间");
  512. } else if (totalAmount < 150000) {
  513. selectFieldValue = "一年金额不足";
  514. System.out.println("金额7.5-15万,但未设置公海池时间");
  515. }
  516. }
  517. // 8. 构建更新数据(只更新需要变更的字段)
  518. Map<String, Object> formData = new HashMap<>();
  519. // 必须更新的字段
  520. formData.put("dateField_mjm9k35j", zhcjrq); // 最后成交日期
  521. formData.put("numberField_mjm9k35k", totalAmount); // 累计金额
  522. formData.put("selectField_mjsco9d4", khsx); // 销售属性
  523. // 条件更新:只在有值时才更新 selectField
  524. if (selectFieldValue != null && !selectFieldValue.isEmpty()) {
  525. if (!selectFieldValue.equals(originalSelectFieldValue)) {
  526. formData.put("selectField_l3nrjuq0", selectFieldValue);
  527. System.out.println("更新选择字段:" + originalSelectFieldValue + " -> " + selectFieldValue);
  528. }
  529. }
  530. // 条件更新:只在明确需要变更公海池日期时才更新
  531. if (ghcDateTimestamp != null) {
  532. // 只有当新值与旧值不同时才更新
  533. String newDateStr = timestampToDateString(ghcDateTimestamp);
  534. String oldDateStr = sfdateTimestampStr != null ? timestampToDateString(String.valueOf(sfdateTimestampStr)) : "空";
  535. if (!newDateStr.equals(oldDateStr)) {
  536. formData.put("dateField_mjm9k35l", ghcDateTimestamp);
  537. System.out.println("更新公海池日期:" + oldDateStr + " -> " + newDateStr);
  538. } else {
  539. System.out.println("公海池日期未变化,跳过更新:" + newDateStr);
  540. }
  541. } else {
  542. // 不设置该字段,upsert操作会保持原值不变
  543. System.out.println("公海池日期无需变更,保持原值:" +
  544. (sfdateTimestampStr != null ? timestampToDateString(String.valueOf(sfdateTimestampStr)) : "空"));
  545. }
  546. // 9. 数据变更前最终校验
  547. if (totalAmount == 0 && historicalAmount > 0) {
  548. System.err.println("警告:即将把客户金额从 " + historicalAmount + " 更新为 0,请确认业务逻辑!");
  549. // 可选:根据业务需求决定是否继续执行
  550. // throw new RuntimeException("金额异常清零,操作已阻止");
  551. }
  552. System.out.println("最终更新数据:" + JSONObject.toJSONString(formData));
  553. // 10. 执行更新操作(retryOperateData已内置重试功能)
  554. retryOperateData(YDParam.builder()
  555. .formUuid("FORM-F79B680547674A6BBD11C0D511E3C14B28FY")
  556. .appType("APP_VQDMMWS6OR1VHL8VMFD3")
  557. .systemToken("XE766X81JHKXK4Z27SYOI86CPCLQ3J1LV7ODMH2")
  558. .noExecuteExpression(false)
  559. .searchFieldJson(JSONObject.toJSONString(Arrays.asList(
  560. new YDSearch("textField_mjm9k35n",
  561. khbm,
  562. "客户编号",
  563. YDSearch.Type.TEXT_FIELD,
  564. YDSearch.Operator.EQ)
  565. )))
  566. .formDataJson(JSONObject.toJSONString(formData))
  567. .build(), YDConf.FORM_OPERATION.upsert);
  568. System.out.println("客户信息更新成功,客户编号:" + khbm);
  569. } catch (Exception e) {
  570. System.err.println("处理订单失败: " + e.getMessage());
  571. e.printStackTrace();
  572. throw new RuntimeException("处理订单失败: " + e.getMessage(), e);
  573. } finally {
  574. MDC.remove("MDC_KEY_PID");
  575. }
  576. }
  577. /**
  578. * 获取指定时间戳的下一年第一天零点的时间戳
  579. * @param timestamp 时间戳(毫秒)
  580. * @return 下一年第一天零点的时间戳
  581. */
  582. private String getNextYearFirstDay(Long timestamp) {
  583. if (timestamp == null || timestamp <= 0) {
  584. // 如果时间戳无效,返回当前时间下一年第一天
  585. timestamp = System.currentTimeMillis();
  586. }
  587. Calendar calendar = Calendar.getInstance();
  588. calendar.setTimeInMillis(timestamp);
  589. // 设置为下一年第一天
  590. calendar.add(Calendar.YEAR, 1);
  591. calendar.set(Calendar.MONTH, Calendar.JANUARY);
  592. calendar.set(Calendar.DAY_OF_MONTH, 1);
  593. calendar.set(Calendar.HOUR_OF_DAY, 0);
  594. calendar.set(Calendar.MINUTE, 0);
  595. calendar.set(Calendar.SECOND, 0);
  596. calendar.set(Calendar.MILLISECOND, 0);
  597. return String.valueOf(calendar.getTimeInMillis());
  598. }
  599. /**
  600. * 计算指定日期加上天数后的时间戳
  601. */
  602. private long calculateTimestamp(Long baseTimestamp, int daysToAdd) {
  603. if (baseTimestamp == null || baseTimestamp <= 0) {
  604. baseTimestamp = System.currentTimeMillis();
  605. }
  606. return baseTimestamp + (daysToAdd * 24L * 60 * 60 * 1000);
  607. }
  608. /**
  609. * 时间戳转日期字符串(用于日志)
  610. */
  611. private String timestampToDateString(Object timestamp) {
  612. if (timestamp == null) {
  613. return "空";
  614. }
  615. try {
  616. long ts;
  617. if (timestamp instanceof String) {
  618. ts = Long.parseLong((String) timestamp);
  619. } else if (timestamp instanceof Long) {
  620. ts = (Long) timestamp;
  621. } else {
  622. return timestamp.toString();
  623. }
  624. if (ts <= 0) {
  625. return "无效时间戳";
  626. }
  627. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  628. return sdf.format(new Date(ts));
  629. } catch (Exception e) {
  630. return timestamp.toString();
  631. }
  632. }
  633. /**
  634. * 计算时间戳:在基础时间戳上添加天数
  635. *
  636. * @param baseTimestamp 基础时间戳(毫秒)
  637. * @param days 要添加的天数
  638. * @return 计算后的时间戳(毫秒)
  639. */
  640. private long calculateTimestamp(long baseTimestamp, int days) {
  641. try {
  642. long oneDayMillis = 24L * 60L * 60L * 1000L;
  643. long daysMillis = (long) days * oneDayMillis;
  644. return baseTimestamp + daysMillis;
  645. } catch (Exception e) {
  646. System.err.println("时间戳计算失败:" + baseTimestamp + ", 天数:" + days);
  647. return baseTimestamp + (days * 24L * 60L * 60L * 1000L);
  648. }
  649. }
  650. /**
  651. * 辅助方法:将时间戳转换为可读日期(仅用于调试)
  652. */
  653. private String timestampToDateString(String timestamp) {
  654. try {
  655. long ts = Long.parseLong(timestamp.trim());
  656. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  657. return sdf.format(new Date(ts));
  658. } catch (Exception e) {
  659. return "无效时间戳:" + timestamp;
  660. }
  661. }
  662. /**
  663. * 重载方法:直接接收long类型时间戳
  664. */
  665. private String timestampToDateString(long timestamp) {
  666. try {
  667. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  668. return sdf.format(new Date(timestamp));
  669. } catch (Exception e) {
  670. return "无效时间戳:" + timestamp;
  671. }
  672. }
  673. private static LocalDateTime parseTimestamp(String timestampStr) {
  674. if (timestampStr == null || timestampStr.trim().isEmpty()) return null;
  675. try {
  676. long timestamp = Long.parseLong(timestampStr.trim());
  677. return LocalDateTime.ofInstant(
  678. Instant.ofEpochMilli(timestamp),
  679. ZoneId.systemDefault()
  680. );
  681. } catch (NumberFormatException e) {
  682. return null;
  683. }
  684. }
  685. private static int parseInt(String str, int defaultValue) {
  686. if (str == null || str.trim().isEmpty()) {
  687. return defaultValue;
  688. }
  689. try {
  690. return Integer.parseInt(str.trim());
  691. } catch (NumberFormatException e) {
  692. return defaultValue;
  693. }
  694. }
  695. private String safeGetString(Map formData, String key) {
  696. Object val = formData.get(key);
  697. return val == null ? "" : String.valueOf(val);
  698. }
  699. private String safeGetString1(Map formData, String key) {
  700. Object val = formData.get(key);
  701. return val == null ? "否" : String.valueOf(val);
  702. }
  703. public static BigDecimal toBigDecimal(String str) {
  704. if (str == null || str.trim().isEmpty()) {
  705. return BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP);
  706. }
  707. try {
  708. return new BigDecimal(str.trim())
  709. .setScale(6, RoundingMode.HALF_UP);
  710. } catch (NumberFormatException e) {
  711. // 返回默认值而不是抛出异常,避免程序中断
  712. return BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP);
  713. }
  714. }
  715. public static BigDecimal toBigDecimal1(String str) {
  716. if (str == null || str.trim().isEmpty()) {
  717. return BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP);
  718. }
  719. try {
  720. return new BigDecimal(str.trim())
  721. .setScale(6, RoundingMode.HALF_UP);
  722. } catch (NumberFormatException e) {
  723. // 返回默认值而不是抛出异常,避免程序中断
  724. return BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP);
  725. }
  726. }
  727. /**
  728. * 重载方法,支持Number类型输入
  729. */
  730. // public static BigDecimal toBigDecimal(Number number) {
  731. // if (number == null) {
  732. // return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
  733. // }
  734. // return new BigDecimal(number.toString())
  735. // .setScale(2, RoundingMode.HALF_UP);
  736. // }
  737. private Object retryOperateData(YDParam param, YDConf.FORM_OPERATION formOperation) {
  738. int maxAttempts = 3; // 尝试的最大次数
  739. int attempt = 0;
  740. long baseWaitTime = 3000; // 基础等待时间3秒
  741. while (attempt < maxAttempts) {
  742. try {
  743. Object result = ydClient.operateData(param, formOperation);
  744. // 成功调用后,如果有之前失败的重试日志,记录成功
  745. if (attempt > 0) {
  746. log.info("第{}次重试成功", attempt + 1);
  747. }
  748. return result;
  749. } catch (McException e) {
  750. String errorMsg = e.getMessage();
  751. log.warn("第{}次调用失败,错误信息:{}", attempt + 1, errorMsg);
  752. // 判断是否是可重试的异常
  753. if (isRetryableError(errorMsg)) {
  754. attempt++;
  755. // 如果已达到最大尝试次数,不再重试,直接抛出异常
  756. if (attempt >= maxAttempts) {
  757. log.error("已达最大重试次数{}次,放弃重试", maxAttempts);
  758. throw new RuntimeException("超出最大重试次数, param:" + JSONObject.toJSONString(param) + ", FORM_OPERATION:" + formOperation, e);
  759. }
  760. // 线程睡眠,使用指数退避策略
  761. try {
  762. long waitTime = baseWaitTime * (long) Math.pow(2, attempt - 1);
  763. log.info("等待{}ms后重试第{}次, param:{}, FORM_OPERATION:{}",
  764. waitTime, attempt + 1, JSONObject.toJSONString(param), formOperation);
  765. Thread.sleep(waitTime);
  766. } catch (InterruptedException ie) {
  767. Thread.currentThread().interrupt(); // 重新设置中断状态
  768. log.error("重试睡眠被中断", ie);
  769. throw new RuntimeException("重试过程被中断", ie);
  770. }
  771. } else {
  772. // 不可重试的异常,直接抛出
  773. log.error("发生不可重试的异常,直接失败: {}", errorMsg);
  774. throw new RuntimeException("宜搭操作失败: " + errorMsg, e);
  775. }
  776. } catch (Exception e) {
  777. // 非McException异常,直接抛出,不重试
  778. log.error("操作失败,param:{},FORM_OPERATION:{},异常信息:{}",
  779. JSONObject.toJSONString(param), formOperation, e.getMessage());
  780. throw new RuntimeException(e);
  781. }
  782. }
  783. // 理论上不会执行到这里,但为了安全保留
  784. throw new RuntimeException("超出最大重试次数, param:" + JSONObject.toJSONString(param) + ", FORM_OPERATION:" + formOperation);
  785. }
  786. //自带重试的queryData方法
  787. private DDR_New retryQueryData(YDParam param, YDConf.FORM_QUERY formQuery) {
  788. int maxAttempts = 3; // 尝试的最大次数
  789. int attempt = 0;
  790. long baseWaitTime = 3000; // 基础等待时间3秒
  791. while (attempt < maxAttempts) {
  792. try {
  793. DDR_New result = ydClient.queryData(param, formQuery);
  794. // 成功调用后,如果有之前失败的重试日志,记录成功
  795. if (attempt > 0) {
  796. log.info("第{}次重试查询成功", attempt + 1);
  797. }
  798. return result;
  799. } catch (McException e) {
  800. String errorMsg = e.getMessage();
  801. log.warn("第{}次查询失败,错误信息:{}", attempt + 1, errorMsg);
  802. // 判断是否是可重试的异常
  803. if (isRetryableError(errorMsg)) {
  804. attempt++;
  805. // 如果已达到最大尝试次数,不再重试,直接抛出异常
  806. if (attempt >= maxAttempts) {
  807. log.error("已达最大重试次数{}次,放弃重试查询", maxAttempts);
  808. throw new RuntimeException("超出最大重试次数, param:" + JSONObject.toJSONString(param) + ", FORM_QUERY:" + formQuery, e);
  809. }
  810. // 线程睡眠,使用指数退避策略
  811. try {
  812. long waitTime = baseWaitTime * (long) Math.pow(2, attempt - 1);
  813. log.info("等待{}ms后重试第{}次查询, param:{}, FORM_QUERY:{}",
  814. waitTime, attempt + 1, JSONObject.toJSONString(param), formQuery);
  815. Thread.sleep(waitTime);
  816. } catch (InterruptedException ie) {
  817. Thread.currentThread().interrupt(); // 重新设置中断状态
  818. log.error("重试查询睡眠被中断", ie);
  819. throw new RuntimeException("重试查询过程被中断", ie);
  820. }
  821. } else {
  822. // 不可重试的异常,直接抛出
  823. log.error("发生不可重试的异常,查询直接失败: {}", errorMsg);
  824. throw new RuntimeException("宜搭查询失败: " + errorMsg, e);
  825. }
  826. } catch (Exception e) {
  827. // 非McException异常,直接抛出,不重试
  828. log.error("查询操作失败,param:{},FORM_QUERY:{},异常信息:{}",
  829. JSONObject.toJSONString(param), formQuery, e.getMessage());
  830. throw new RuntimeException(e);
  831. }
  832. }
  833. // 理论上不会执行到这里,但为了安全保留
  834. throw new RuntimeException("超出最大重试次数, param:" + JSONObject.toJSONString(param) + ", FORM_QUERY:" + formQuery);
  835. }
  836. /**
  837. * 判断是否是可重试的错误
  838. */
  839. private boolean isRetryableError(String errorMsg) {
  840. if (errorMsg == null) return false;
  841. // 可重试的错误关键字列表(扩展了匹配范围)
  842. String[] retryableKeywords = {
  843. "temporary failure",
  844. "未知异常",
  845. "timeout",
  846. "Timeout",
  847. "Connection refused",
  848. "Internal Server",
  849. "服务不可用",
  850. "Service Unavailable",
  851. "Gateway Timeout",
  852. "Bad Gateway"
  853. };
  854. for (String keyword : retryableKeywords) {
  855. if (errorMsg.contains(keyword)) {
  856. return true;
  857. }
  858. }
  859. return false;
  860. }
  861. }