From 91ce065bdfa17f8c76d3af784e0eeec0ad3f4931 Mon Sep 17 00:00:00 2001 From: mzr Date: Thu, 3 Jul 2025 10:31:34 +0800 Subject: [PATCH] =?UTF-8?q?=E7=89=A9=E6=96=99=E6=96=B0=E5=A2=9E=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=90=8E=E5=90=8C=E6=AD=A5=E8=89=BE=E6=99=AEMES?= =?UTF-8?q?=E7=9A=84=E7=89=A9=E6=96=99=E3=80=81=E6=B5=81=E7=A8=8B=E7=94=9F?= =?UTF-8?q?=E4=BA=A7=E8=AE=A2=E5=8D=95=E5=AE=A1=E6=89=B9=E5=90=8E=E6=8E=A8?= =?UTF-8?q?=E9=80=81=E8=89=BE=E6=99=AEMES?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bp/rule/AfterApproveSyncEpicMesRule.java | 184 ++++++++++++++++++ .../listener/MaterialToEpicMesListener.java | 110 +++++++++++ 2 files changed, 294 insertions(+) create mode 100644 mmpac/src/private/nc/bs/mmpac/pmo/pac0002/bp/rule/AfterApproveSyncEpicMesRule.java create mode 100644 uapbd/src/private/nccloud/api/uapbd/material/listener/MaterialToEpicMesListener.java diff --git a/mmpac/src/private/nc/bs/mmpac/pmo/pac0002/bp/rule/AfterApproveSyncEpicMesRule.java b/mmpac/src/private/nc/bs/mmpac/pmo/pac0002/bp/rule/AfterApproveSyncEpicMesRule.java new file mode 100644 index 0000000..8ef38fa --- /dev/null +++ b/mmpac/src/private/nc/bs/mmpac/pmo/pac0002/bp/rule/AfterApproveSyncEpicMesRule.java @@ -0,0 +1,184 @@ +package nc.bs.mmpac.pmo.pac0002.bp.rule; + + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import nc.bs.logging.Log; +import nc.bs.logging.Logger; +import nc.bs.uapbd.util.MyHelper; +import nc.bs.uapbd.util.ThirdPartyPostRequestUtil; +import nc.impl.pubapp.pattern.rule.IRule; +import nc.itf.arap.goldentax.SysParaInitQuery; +import nc.vo.mmpac.pmo.pac0002.entity.PMOAggVO; +import nc.vo.mmpac.pmo.pac0002.entity.PMOHeadVO; +import nc.vo.mmpac.pmo.pac0002.entity.PMOItemVO; +import nc.vo.org.FactoryVO; +import nc.vo.pub.BusinessException; +import nc.vo.pubapp.pattern.exception.ExceptionUtils; +import nc.vo.scmpub.util.ArrayUtil; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.List; + +/** + * 流程生产订单审批后推送艾普MES + * + * @author mzr + * @date 2025/7/3 + */ +public class AfterApproveSyncEpicMesRule implements IRule { + + private static final String LOG_INFO_NAME = "OALOG"; + + private static final Log obmlog = Log.getInstance(LOG_INFO_NAME); + + private static final String MES_PMO_SYNC_URL = "/prj-v5-web/ext/api/wrokOrder"; + + @Override + public void process(PMOAggVO[] pmoAggVOS) { + if (ArrayUtil.isEmpty(pmoAggVOS)) { + return; + } + try { + List filteredOrders = checkAndFilterBillSrcOrg(pmoAggVOS); + if (filteredOrders.isEmpty()) { + obmlog.debug("没有符合条件的生产订单需要同步到MES系统。"); + return; + } + + obmlog.info("开始同步生产订单到MES系统,符合条件的订单数量: " + filteredOrders.size()); + // 推送到MES系统 + JSONArray dataArr = new JSONArray(); + for (PMOAggVO aggVO : filteredOrders) { + PMOHeadVO head = aggVO.getParentVO(); + PMOItemVO[] bodys = aggVO.getChildrenVO(); + + if (bodys == null || bodys.length == 0) { + obmlog.warn("生产订单 " + head.getVbillcode() + " 没有行信息,跳过同步。"); + continue; + } + JSONObject object = buildSyncData(aggVO); + dataArr.add(object); + } + JSONObject data = new JSONObject(); + data.put("workOrders", dataArr); + pushData(data); + obmlog.info("生产订单同步到MES系统处理完成。"); + + + } catch (Exception e) { + obmlog.error("同步生产订单到MES系统失败: " + e.getMessage(), e); + ExceptionUtils.wrappException(e); + } + } + + /** + * 调用MES接口并处理特定错误 + * + * @param param 请求体 + * @throws BusinessException 如果发生非特定可忽略的错误 + */ + private void pushData(JSONObject param) throws BusinessException { + String responseString = null; + try { + String baseUrl = SysParaInitQuery.getParaString("GLOBLE00000000000000", "EPICMESURL"); + String requestUrl = baseUrl + MES_PMO_SYNC_URL; + responseString = ThirdPartyPostRequestUtil.sendPostRequest(requestUrl, param.toJSONString()); + obmlog.info(" MES系统原始返回: " + responseString); + + JSONObject jsonResponse = JSONObject.parseObject(responseString); + } catch (Exception e) { + obmlog.error(" 调用MES或处理响应时发生错误。原始响应: " + responseString + " 错误: " + e.getMessage(), e); + throw new BusinessException("调用MES或处理响应时发生错误:" + e.getMessage(), e); + } + } + + /** + * 检查并筛选需要同步的单据 + */ + private List checkAndFilterBillSrcOrg(PMOAggVO[] pmoAggVOS) throws BusinessException { + List aggvoList = new ArrayList<>(); + for (PMOAggVO aggVo : pmoAggVOS) { + String pkOrg = aggVo.getParentVO().getPk_org(); + String orgCode = MyHelper.transferField(FactoryVO.getDefaultTableName(), FactoryVO.CODE, FactoryVO.PK_FACTORY, pkOrg); + // 检查当前组织是否为电力电子 + if (MyHelper.checkIfDldzOrg(orgCode)) { + aggvoList.add(aggVo); + } + } + return aggvoList; + } + + /** + * 组装数据 + */ + private JSONObject buildSyncData(PMOAggVO aggVO) { + PMOHeadVO headVo = aggVO.getParentVO(); + PMOItemVO[] pmoItems = aggVO.getChildrenVO(); + JSONObject data = new JSONObject(); + // { + // "workOrders": [ + // { + // "id": null, // 唯一标识(主键) + // "siteCode": "04", // 工厂编码 + // "contractNo": "HDDK0111325", // 合同号 + // "workOrderCode": "DSF01-2501230028",// 工单号 + // "qty": "1.000", // 计划数量(字符串类型) + // "produCode": "103248250005", // 产品编码 + // "produName": "150KV滤抗-特高压宝塔山(试装)-低端", // 产品名称 + // "bomCode": "103248250005", // BOM 编码 + // "planBeginDate": 1751328000000, // 计划开始时间(毫秒级时间戳) + // "planEndDate": 1751328000000, // 计划结束时间(毫秒级时间戳) + // "endDate": 1751328000000, // 试验结束时间(毫秒级时间戳) + // "type": null, // 类型(I:新增 U:修改 D:删除) + // "auditCode": "Y", // 审核码(Y:已审核 N:未审核) + // "contractName": "特高压宝塔山±800 千伏换流站工程", // 合同名称 + // "transferPlanTime": "2025-07-01", // 生产转检计划时间(格式:YYYY-MM-DD) + // "receiptScheduledTime": "2025-07-01", // 完工入库时间(格式:YYYY-MM-DD) + // "companyCode": "DLDZ", // 公司编码 + // "companyName": "泰开电力电子" // 公司名称 + // } + // ], + // "mrls": [ + // { + // "workOrderCode": "DSF01-2501230028",// 工单号 + // "mrlCode": "2305050447", // 物料编码 + // "mrlName": "铝加工件", // 物料名称 + // "qty": 1.000, // 数量(浮点数) + // "unit": "套" // 单位 + // } + // ] + // } + + return data; + } + + /** + * 转换特殊字段 如 1/1 转换为小数 1.0 + */ + + private String transferSpecialField(String field) { + if (field == null || field.trim().isEmpty()) { + return null; + } + String[] split = field.split("/"); + if (split.length == 2) { + String numStr = split[0].trim(); + String denStr = split[1].trim(); + if (denStr.equals("0")) { + return "0.00"; // 分母不能为零 + } + try { + BigDecimal numerator = new BigDecimal(numStr); + BigDecimal denominator = new BigDecimal(denStr); + return numerator.divide(denominator, 2, RoundingMode.HALF_UP).toString(); + } catch (NumberFormatException e) { + return field; // 非法数字,返回原字段 + } + } + return field; + } + +} diff --git a/uapbd/src/private/nccloud/api/uapbd/material/listener/MaterialToEpicMesListener.java b/uapbd/src/private/nccloud/api/uapbd/material/listener/MaterialToEpicMesListener.java new file mode 100644 index 0000000..7fccd1d --- /dev/null +++ b/uapbd/src/private/nccloud/api/uapbd/material/listener/MaterialToEpicMesListener.java @@ -0,0 +1,110 @@ +package nccloud.api.uapbd.material.listener; + +import com.alibaba.fastjson.JSONObject; +import nc.bs.bd.baseservice.ArrayClassConvertUtil; +import nc.bs.businessevent.IBusinessEvent; +import nc.bs.businessevent.IBusinessListener; +import nc.bs.businessevent.bd.BDCommonEvent; +import nc.bs.logging.Logger; +import nc.bs.uapbd.util.MyHelper; +import nc.bs.uapbd.util.ThirdPartyPostRequestUtil; +import nc.itf.arap.goldentax.SysParaInitQuery; +import nc.vo.bd.material.MaterialVO; +import nc.vo.bd.material.marbasclass.MarBasClassVO; +import nc.vo.bd.material.measdoc.MeasdocVO; +import nc.vo.org.FactoryVO; +import nc.vo.pub.BusinessException; + +import java.util.HashMap; +import java.util.Map; + +/** + * 物料新增修改后同步艾普MES的物料 + * + * @author mzr + * @date 2025/06/27 + */ +public class MaterialToEpicMesListener implements IBusinessListener { + + private static final String reqUrl = "/prj-v5-web/ext/api/mrl"; + + @Override + public void doAction(IBusinessEvent event) throws BusinessException { + BDCommonEvent e = (BDCommonEvent) event; + String eventType = event.getEventType(); + Object[] objs = e.getObjs(); + MaterialVO[] useVOs = ArrayClassConvertUtil.convert(objs, MaterialVO.class); + // EventType是事件编码 + if ("1002".equals(eventType)) { + // 新增后 + buildSyncData(useVOs, eventType); + } else if ("1004".equals(eventType)) { + // 修改后 + buildSyncData(useVOs, eventType); + } + } + + /** + * 构建同步数据 + */ + private void buildSyncData(MaterialVO[] useVOs, String eventType) throws BusinessException { + for (MaterialVO vo : useVOs) { + // 判断物料的业务单元是否是电力电子公司,不是则跳过 + String pkOrg = vo.getPk_org(); + String orgCode = MyHelper.transferField(FactoryVO.getDefaultTableName(), FactoryVO.CODE, FactoryVO.PK_FACTORY, pkOrg); + if (!MyHelper.checkIfDldzOrg(orgCode)) { + continue; + } + // 1=未启用;2=已启用;3=已停用; + Integer enablestate = vo.getEnablestate(); + String statusCode = (3 == enablestate) ? "N" : "Y"; + JSONObject singleObj = new JSONObject(); + singleObj.put("id", null);// 唯一标识(主键) + singleObj.put("siteCode", null);// 工厂编码 + singleObj.put("mrlCode", vo.getCode());// 物料编码 + singleObj.put("mrlName", vo.getName());// 物料名称 + String pkMeasdoc = vo.getPk_measdoc(); + String unitName = MyHelper.transferField(MeasdocVO.getDefaultTableName(), MeasdocVO.NAME, MeasdocVO.PK_MEASDOC, pkMeasdoc); + singleObj.put("unit", unitName);// 单位 + singleObj.put("model", vo.getMaterialtype());// 型号 + singleObj.put("specification", vo.getMaterialspec());// 规格 + singleObj.put("type", getType(eventType));// 类型(I:新增 U:修改 D:删除) + singleObj.put("deputyUnit", null);// 副单位 + singleObj.put("auditCode", "1");// 审核码 + singleObj.put("statusCode", statusCode);// 状态码(Y表示启用,N表示停用) + singleObj.put("mrlTypeErp", "1");// 物料类型ERP(1:专用件,3:通用件) + String pk_marbasclass = vo.getPk_marbasclass(); + String mrlTypeCOde = MyHelper.transferField(MarBasClassVO.getDefaultTableName(), MarBasClassVO.CODE, MarBasClassVO.PK_MARBASCLASS, pk_marbasclass); + singleObj.put("mrlType", mrlTypeCOde);// 物料分类编码 + singleObj.put("convertRate", "1");// 单位换算率 + singleObj.put("isCheck", "1");// 是否选中(1:是,0:否) + pushData(singleObj); + } + } + + /** + * 推送同步数据 + */ + private void pushData(JSONObject param) throws BusinessException { + String baseUrl = SysParaInitQuery.getParaString("GLOBLE00000000000000", "EPICMESURL"); + String requestUrl = baseUrl + reqUrl; + String result = ThirdPartyPostRequestUtil.sendPostRequest(requestUrl, param.toJSONString()); + JSONObject resultObj = JSONObject.parseObject(result); + Logger.error("EpicMes-Material-req = " + result); + + if ("false".equals(resultObj.getString("success"))) { + throw new BusinessException("EpicMes-Material-fail,error:" + resultObj.getString("msg")); + } else { + Logger.error("EpicMes-Material-suc,result[" + resultObj.toJSONString() + "]"); + } + } + + private String getType(String eventType) { + // 类型(I:新增 U:修改 D:删除) + Map map = new HashMap<>(); + map.put("1002", "I"); + map.put("1004", "U"); + return map.getOrDefault(eventType, "I"); + } + +}