From 482c656810b7715fced45e80e289885c7a8ae382 Mon Sep 17 00:00:00 2001 From: mzr Date: Fri, 15 Aug 2025 16:02:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(uapbd):=20=E6=B7=BB=E5=8A=A0=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E4=BB=BB=E5=8A=A1=E5=90=8C=E6=AD=A5CLM=E5=90=88?= =?UTF-8?q?=E5=90=8C=E9=94=80=E5=94=AE=E8=AE=A2=E5=8D=95=E5=AD=97=E6=AE=B5?= =?UTF-8?q?-=20=E6=96=B0=E5=A2=9E=20ErpSoToR6Plugin=20=E7=B1=BB=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=20IBackgroundWorkPlugin=20=E6=8E=A5=E5=8F=A3=20-=20?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1=E9=80=BB?= =?UTF-8?q?=E8=BE=91=EF=BC=8C=E5=90=8C=E6=AD=A5=E9=94=80=E5=94=AE=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E4=BF=A1=E6=81=AF=E5=88=B0=20R6=20=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=20-=20=E5=AE=9E=E7=8E=B0=E6=95=B0=E6=8D=AE=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E3=80=81=E5=A4=84=E7=90=86=E5=92=8C=20HTTP=20=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E5=8F=91=E9=80=81=E5=8A=9F=E8=83=BD=20-=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86=E5=92=8C=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../uapbd/bip/workplugin/ErpSoToR6Plugin.java | 421 ++++++++++++++++++ 1 file changed, 421 insertions(+) create mode 100644 uapbd/src/private/nc/bs/uapbd/bip/workplugin/ErpSoToR6Plugin.java diff --git a/uapbd/src/private/nc/bs/uapbd/bip/workplugin/ErpSoToR6Plugin.java b/uapbd/src/private/nc/bs/uapbd/bip/workplugin/ErpSoToR6Plugin.java new file mode 100644 index 0000000..bec1bf8 --- /dev/null +++ b/uapbd/src/private/nc/bs/uapbd/bip/workplugin/ErpSoToR6Plugin.java @@ -0,0 +1,421 @@ +package nc.bs.uapbd.bip.workplugin; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.gson.Gson; +import com.yonyou.cloud.utils.StringUtils; +import nc.bs.dao.BaseDAO; +import nc.bs.dao.DAOException; +import nc.bs.logging.Log; +import nc.bs.pub.pa.PreAlertObject; +import nc.bs.pub.taskcenter.BgWorkingContext; +import nc.bs.pub.taskcenter.IBackgroundWorkPlugin; +import nc.bs.trade.business.HYSuperDMO; +import nc.jdbc.framework.processor.MapListProcessor; +import nc.vo.bd.defdoc.DefdocVO; +import nc.vo.pub.BusinessException; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.*; +import java.util.zip.GZIPInputStream; + +/** + * 定时任务-同步CLM合同销售订单字段 + * + * @author mzr + * @date 2025/8/15 + */ +public class ErpSoToR6Plugin implements IBackgroundWorkPlugin { + private static final Log logger = Log.getInstance("syscron"); + + private HYSuperDMO superDMO = null; + private String baseUrl = ""; + + + public HYSuperDMO getSuperDMO() { + + if (superDMO == null) { + superDMO = new HYSuperDMO(); + } + + return superDMO; + } + + /** + * 检查bip参数是否完整 + * + * @return + */ + private Map checkBipParam() { + + Map map = new HashMap(); + + String strWhere = " pk_defdoclist in (select pk_defdoclist from bd_defdoclist where code='BIP-sq' and dr=0 ) and dr=0"; + + try { + DefdocVO[] defdocVOs = (DefdocVO[]) getSuperDMO().queryByWhereClause(DefdocVO.class, strWhere); + if (defdocVOs != null && defdocVOs.length > 0) { + for (DefdocVO defdocVO : defdocVOs) { + + map.put(defdocVO.getCode().trim(), defdocVO.getName()); + + } + } + } catch (DAOException e) { + e.printStackTrace(); + } + + return map; + + } + + @Override + public PreAlertObject executeTask(BgWorkingContext arg0) throws BusinessException { + Map bipParamMap = checkBipParam(); + if (bipParamMap.isEmpty()) { + return null; + } + baseUrl = bipParamMap.get("baseUrl"); + + String invoiceReceiveUrl = bipParamMap.get("contractSaleOrder");// 合同销售订单回传 + if (StringUtils.isEmpty(invoiceReceiveUrl)) { + logger.error("ErpSoToR6Plugin-未查询到符合条件的销售订单"); + return null; + } + // 查询销售订单的信息 + StringBuilder sql = new StringBuilder(); + sql.append("SELECT "); + sql.append(" a.vdef9, "); + sql.append(" b.vbdef11, "); + sql.append(" c.ntotalinvoicenum billqty, "); + sql.append(" c.ntotalarmny totalaccrued, "); + sql.append(" c.ntotaloutnum totaloutqty, "); + sql.append(" b.fretexchange, "); + sql.append(" b.cexchangesrcretid, "); + sql.append(" c.narrangemonum, "); + sql.append(" c.ntotalreturnnum, "); + sql.append(" c.ntotalrednum "); + sql.append("FROM "); + sql.append(" so_saleorder_b b "); + sql.append(" LEFT JOIN so_saleorder a ON a.csaleorderid = b.csaleorderid "); + sql.append(" LEFT JOIN so_saleorder_exe c ON c.csaleorderbid = b.csaleorderbid "); + sql.append("WHERE "); + sql.append(" b.dr = 0 "); + sql.append(" AND a.dr = 0 "); + sql.append(" AND b.vbdef11 IS NOT NULL "); + sql.append(" AND b.vbdef11 != '~' "); + sql.append(" AND a.vdef9 IS NOT NULL "); + sql.append(" AND a.vdef9 != '~'"); + logger.error("ErpSoToR6Plugin-sql: " + sql); + List> orderList = (List>) new BaseDAO().executeQuery(sql.toString(), new MapListProcessor()); + if (orderList.isEmpty()) { + return null; + } + try { + + // 分批处理,每100个为一组 + int batchSize = 100; + int totalSize = orderList.size(); + logger.error("总共查询到 " + totalSize + " 条销售订单记录,将按每 " + batchSize + " 条一批进行处理"); + + for (int i = 0; i < totalSize; i += batchSize) { + int endIndex = Math.min(i + batchSize, totalSize); + List> batchOrderList = orderList.subList(i, endIndex); + logger.error("开始处理第 " + (i / batchSize + 1) + " 批数据,本批包含 " + batchOrderList.size() + " 条记录"); + + processBatchOrders(batchOrderList, bipParamMap, invoiceReceiveUrl); + + logger.error("完成处理第 " + (i / batchSize + 1) + " 批数据"); + } + + } catch (Exception e) { + logger.error("ErpSoToR6Plugin-exp: " + e.getMessage(), e); + } + return null; + } + + /** + * 批量处理销售订单 + * + * @param batchOrderList 批量订单列表 + * @param bipParamMap BIP参数 + * @param invoiceReceiveUrl 接口URL + */ + private void processBatchOrders(List> batchOrderList, Map bipParamMap, String invoiceReceiveUrl) { + try { + String accessToken = getAccessToken(baseUrl, bipParamMap); + Map tokenParam = new HashMap<>(); + tokenParam.put("access_token", accessToken); + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + String custUpdateUrl = baseUrl + invoiceReceiveUrl; + + JSONObject reqData = new JSONObject(); + JSONArray array = new JSONArray(); + + for (Map soMap : batchOrderList) { + JSONObject oneJson = new JSONObject(); + String hid = soMap.get("vdef9");// BIP合同销售订单 主表id + List> bodyList = new ArrayList<>(); + Map bodyMap = new HashMap<>(); + + bodyMap.put("id", soMap.get("vbdef11"));// BIP合同销售订单 子表id + bodyMap.put("billQty", soMap.getOrDefault("billqty", "0"));// 累计开票数量 + bodyMap.put("totalAccrued", soMap.getOrDefault("totalaccrued", "0"));// 累计确认应收账款 + bodyMap.put("totalOutQty", soMap.getOrDefault("totaloutqty", "0"));// 累计出库数量 + + bodyMap.put("fretexchange", soMap.get("fretexchange")); // 汇率类型 + bodyMap.put("cexchangesrcretid", soMap.get("cexchangesrcretid")); // 对应汇率 + bodyMap.put("narrangemonum", soMap.getOrDefault("narrangemonum", "0")); // 累计安排发货数量 + bodyMap.put("ntotalreturnnum", soMap.getOrDefault("ntotalreturnnum", "0")); // 累计退货数量 + bodyMap.put("ntotalrednum", soMap.getOrDefault("ntotalrednum", "0")); // 累计红冲数量 + + bodyList.add(bodyMap); + oneJson.put("contractOrdersList", bodyList); + oneJson.put("id", hid); + array.add(oneJson); + } + + reqData.put("HTXSDD", array); + String data = reqData.toJSONString(); + logger.error("ErpSoToR6Plugin-param = " + data); + String resultString = doSendHttp(custUpdateUrl, "POST", tokenParam, "", headers, data); + logger.error("ErpSoToR6Plugin-res = " + resultString); + } catch (Exception e) { + logger.error("ErpSoToR6Plugin-exp: " + e.getMessage(), e); + } + } + + public static String doSendHttp(String baseUrl, String method, Map paramMap, String mediaType, Map headers, String json) { + HttpURLConnection urlConnection = null; + InputStream in = null; + OutputStream out = null; + BufferedReader bufferedReader = null; + String result = null; + try { + StringBuffer sb = new StringBuffer(); + sb.append(baseUrl); + if (paramMap != null) { + sb.append("?"); + for (Map.Entry entry : paramMap.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + sb.append(key + "=" + value).append("&"); + baseUrl = sb.toString().substring(0, sb.toString().length() - 1); + } + } +// log.error("uRL:" + baseUrl); +// // 打印请求URL和方法 +// log.error("Request URL: " + baseUrl); +// log.error("Request Method: " + method); + URL urlobj = new URL(baseUrl); + if ("https".equalsIgnoreCase(urlobj.getProtocol())) {// 判定网址是否信任,不信任则调用忽略信任工具类SslUtil + IgnoreSslUtil.ignoreSsl(); + } + urlConnection = (HttpURLConnection) urlobj.openConnection(); + urlConnection.setConnectTimeout(50000); + urlConnection.setRequestMethod(method); + urlConnection.setDoInput(true); + urlConnection.setUseCaches(false); + // 如果设置了自定义头,则打印它们 + if (headers != null && !headers.isEmpty()) { + for (Map.Entry entry : headers.entrySet()) { + urlConnection.addRequestProperty(entry.getKey(), entry.getValue()); +// log.error("Request Header: " + entry.getKey() + ": " + entry.getValue()); + } + } + if (json != null && json.length() > 0) { +// log.error("Request Body: " + json); + urlConnection.setDoInput(true); + urlConnection.setDoOutput(true); + out = urlConnection.getOutputStream(); + out.write(json.getBytes("utf-8")); + out.flush(); + } + int resCode = urlConnection.getResponseCode(); + String ecod = urlConnection.getContentEncoding(); + if (resCode == HttpURLConnection.HTTP_OK || resCode == HttpURLConnection.HTTP_CREATED + || resCode == HttpURLConnection.HTTP_ACCEPTED) { + if (StringUtils.isNotEmpty(ecod) && ecod.equals("gzip")) { + in = new GZIPInputStream(urlConnection.getInputStream()); + } else { + in = urlConnection.getInputStream(); + } + } else { + in = urlConnection.getErrorStream(); + } + bufferedReader = new BufferedReader(new InputStreamReader(in, "utf-8")); + StringBuffer temp = new StringBuffer(); + String line = bufferedReader.readLine(); + while (line != null) { + temp.append(line).append("\r\n"); + line = bufferedReader.readLine(); + } + if (ecod == null || ecod.equals("gzip")) { + ecod = Charset.forName("utf-8").name(); + } + result = new String(temp.toString().getBytes("utf-8"), ecod); + } catch (Exception e) { + JSONObject js = new JSONObject(); + js.put("", -1); + js.put("message", "调用外系统接口失败:" + e.getMessage()); + result = js.toString(); + e.printStackTrace(); + } finally { + if (null != bufferedReader) { + try { + bufferedReader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (null != out) { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (null != in) { + try { + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + urlConnection.disconnect(); + } + return result; + } + + + private String getAccessToken(String baseUrl, Map bipParamMap) throws NoSuchAlgorithmException, InvalidKeyException, IOException { + String tokenUrl = baseUrl + "/iuap-api-auth/open-auth/selfAppAuth/getAccessToken"; +// String appKey = "f10c4bf17b1d4e1fb08eb82bf8540eab"; + String appKey = bipParamMap.get("appKey"); + +// String appSecret = "71dc2a58ca378c1a1143231a62e73e75a60e9236"; + String appSecret = bipParamMap.get("appSecret"); + String accessToken = ""; + Map params = new HashMap<>(); + + + params.put("appKey", appKey); + String timestamp = String.valueOf(System.currentTimeMillis()); + params.put("timestamp", timestamp); + // 计算签名 + Map treeMap; + if (params instanceof TreeMap) { + treeMap = params; + } else { + treeMap = new TreeMap<>(params); + } + StringBuilder stringBuilder = new StringBuilder(); + for (Map.Entry entry : treeMap.entrySet()) { + stringBuilder.append(entry.getKey()).append(entry.getValue()); + } + Mac mac = Mac.getInstance("HmacSHA256"); + + mac.init(new SecretKeySpec(appSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); + byte[] signData = mac.doFinal(stringBuilder.toString().getBytes(StandardCharsets.UTF_8)); + String base64String = Base64.getEncoder().encodeToString(signData); + String signature = URLEncoder.encode(base64String, "UTF-8"); + params.put("signature", signature); + + String responseString = doGet(tokenUrl, params); + + Gson gson = new Gson(); + Map result = gson.fromJson(responseString, Map.class); + if (StringUtils.equals("00000", result.get("code").toString())) { + Map tokenInfo = (Map) result.get("data"); + accessToken = (String) tokenInfo.get("access_token"); + + } + + + return accessToken; + } + + + private static String doGet(String path, Map params) throws IOException { + HttpURLConnection conn = null; + InputStream is = null; + BufferedReader br = null; + StringBuilder result = new StringBuilder(); + try { + if (params != null) { + String paramStr = ""; + for (String key : params.keySet()) { + if (!paramStr.isEmpty()) { + paramStr += '&'; + } + paramStr += key + '=' + params.get(key); + } + + if (path.indexOf('?') > 0) { + path += '&' + paramStr; + } else { + path += '?' + paramStr; + } + } + // 创建远程url连接对象 + URL url = new URL(path); + if ("https".equalsIgnoreCase(url.getProtocol())) {// 判定网址是否信任,不信任则调用忽略信任工具类SslUtil + IgnoreSslUtil.ignoreSsl(); + } + // 通过远程url连接对象打开一个连接,强转成HTTPURLConnection类 + conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + // 设置连接超时时间和读取超时时间 + conn.setConnectTimeout(120000); + conn.setReadTimeout(120000); + conn.setRequestProperty("Accept", "application/json"); + // 发送请求 + conn.connect(); + // 通过conn取得输入流,并使用Reader读取 + if (200 == conn.getResponseCode()) { + is = conn.getInputStream(); + br = new BufferedReader(new InputStreamReader(is, "UTF-8")); + String line; + while ((line = br.readLine()) != null) { + result.append(line); + System.out.println(line); + } + } else { + System.out.println("ResponseCode is an error code:" + conn.getResponseCode()); + } + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } +// finally { +// try { +// if (br != null) { +// br.close(); +// } +// if (is != null) { +// is.close(); +// } +// } catch (IOException ioe) { +// ioe.printStackTrace(); +// } +// conn.disconnect(); +// } + return result.toString(); + } + + +}