From 88b5eec9adc4b69912a7d0494b5b2a6b54f9e19f Mon Sep 17 00:00:00 2001 From: mzr Date: Tue, 30 Sep 2025 18:34:17 +0800 Subject: [PATCH 1/6] =?UTF-8?q?plm=E5=86=85=E9=85=8D=E8=AE=A2=E5=8D=95-asu?= =?UTF-8?q?ser28=E4=BF=AE=E6=94=B9=E8=B5=8B=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/client/nccloud/web/mmpac/pmo/action/PmoToPlmAction.java | 2 +- .../bs/mmpac/pmo/pac0002/bp/rule/AfterApproveSyncPLMRule.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mmpac/src/client/nccloud/web/mmpac/pmo/action/PmoToPlmAction.java b/mmpac/src/client/nccloud/web/mmpac/pmo/action/PmoToPlmAction.java index fd80742b..8d7c8863 100644 --- a/mmpac/src/client/nccloud/web/mmpac/pmo/action/PmoToPlmAction.java +++ b/mmpac/src/client/nccloud/web/mmpac/pmo/action/PmoToPlmAction.java @@ -135,7 +135,7 @@ public class PmoToPlmAction implements ICommonAction { request.put("asuser34", projectMap.get("project_name")); } - request.put("asuser28", itemVO.getVfirstcode()); + request.put("asuser28", itemVO.getVsalebillcode()); request.put("ab012", itemVO.getNastnum()); request.put("gsdm", GSDM); diff --git a/mmpac/src/private/nc/bs/mmpac/pmo/pac0002/bp/rule/AfterApproveSyncPLMRule.java b/mmpac/src/private/nc/bs/mmpac/pmo/pac0002/bp/rule/AfterApproveSyncPLMRule.java index ef6556a4..a8e32e58 100644 --- a/mmpac/src/private/nc/bs/mmpac/pmo/pac0002/bp/rule/AfterApproveSyncPLMRule.java +++ b/mmpac/src/private/nc/bs/mmpac/pmo/pac0002/bp/rule/AfterApproveSyncPLMRule.java @@ -129,7 +129,7 @@ public class AfterApproveSyncPLMRule implements IRule { request.put("asuser34", projectMap.get("project_name")); } - request.put("asuser28", itemVO.getVfirstcode()); + request.put("asuser28", itemVO.getVsalebillcode()); request.put("ab012", itemVO.getNastnum()); request.put("gsdm", GSDM); From 4d6cce825d53cde268333d540c79036db48383a9 Mon Sep 17 00:00:00 2001 From: mzr Date: Tue, 30 Sep 2025 18:35:08 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E7=94=B5=E5=8A=9B=E7=94=B5=E5=AD=90-?= =?UTF-8?q?=E8=89=BE=E6=99=AEMES-=E6=B5=81=E7=A8=8B=E7=94=9F=E4=BA=A7?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E5=A2=9E=E5=8A=A0contractName?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mmpac/pmo/pac0002/util/HttpPmoEpicMesUtil.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mmpac/src/public/nc/vo/mmpac/pmo/pac0002/util/HttpPmoEpicMesUtil.java b/mmpac/src/public/nc/vo/mmpac/pmo/pac0002/util/HttpPmoEpicMesUtil.java index 16232434..57a277f9 100644 --- a/mmpac/src/public/nc/vo/mmpac/pmo/pac0002/util/HttpPmoEpicMesUtil.java +++ b/mmpac/src/public/nc/vo/mmpac/pmo/pac0002/util/HttpPmoEpicMesUtil.java @@ -10,6 +10,7 @@ import nc.bs.uapbd.util.MyHelper; import nc.bs.uapbd.util.ThirdPartyPostRequestUtil; import nc.jdbc.framework.processor.MapListProcessor; import nc.jdbc.framework.processor.MapProcessor; +import nc.vo.bc.pmpub.project.ProjectHeadVO; import nc.vo.bd.bom.bom0202.entity.BomVO; import nc.vo.bd.material.MaterialVO; import nc.vo.mmpac.pmo.pac0002.entity.PMOAggVO; @@ -186,9 +187,9 @@ public class HttpPmoEpicMesUtil { selectFields = MaterialVO.CODE + "," + MaterialVO.NAME; Map goodsMap = MyHelper.transferFields(MaterialVO.getDefaultTableName(), selectFields, MaterialVO.PK_MATERIAL, cmaterialid); // 项目 - // String cprojectid = pmoItem.getCprojectid(); - // selectFields = ProjectHeadVO.PROJECT_CODE + "," + ProjectHeadVO.PROJECT_NAME; - // Map projectMap = MyHelper.transferFields(ProjectHeadVO.getDefaultTableName(), selectFields, ProjectHeadVO.PK_PROJECT, cprojectid); + String cprojectid = pmoItem.getCprojectid(); + selectFields = ProjectHeadVO.PROJECT_CODE + "," + ProjectHeadVO.PROJECT_NAME; + Map projectMap = MyHelper.transferFields(ProjectHeadVO.getDefaultTableName(), selectFields, ProjectHeadVO.PK_PROJECT, cprojectid); // 生产部门 cdeptid String cdeptid = pmoItem.getCdeptid(); String deptCode = MyHelper.transferField(DeptVO.getDefaultTableName(), DeptVO.CODE, DeptVO.PK_DEPT, cdeptid); @@ -202,10 +203,10 @@ public class HttpPmoEpicMesUtil { // 根据自定义档案中的映射关系,部门编码转换为MES中的编码 orderParam.put("siteCode", deptParams.getOrDefault(deptCode, ""));// 工厂编码 orderParam.put("contractNo", pmoItem.getVfirstcode());// 合同号-取ERP的源头单据号-销售订单号 - /*if (projectMap != null) { - orderParam.put("contractNo", projectMap.get(ProjectHeadVO.PROJECT_CODE));// 合同号 + if (projectMap != null) { + // orderParam.put("contractNo", projectMap.get(ProjectHeadVO.PROJECT_CODE));// 合同号 orderParam.put("contractName", projectMap.get(ProjectHeadVO.PROJECT_NAME)); // 合同名称 - }*/ + } orderParam.put("workOrderCode", headVo.getVbillcode());// 工单号 orderParam.put("qty", String.valueOf(pmoItem.getNastnum())); // 计划数量,字符串类型 if (goodsMap != null) { From cd2416ebb6616f5eab082ed1b553a3bd9a6d618d Mon Sep 17 00:00:00 2001 From: hefengkai <958118178@qq.com> Date: Tue, 30 Sep 2025 19:28:19 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E9=AB=98=E5=8E=8B--bip=E5=A4=87=E6=96=99?= =?UTF-8?q?=E8=AE=A1=E5=88=92=E6=8E=A8=E9=80=81ims?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nc/bs/mmpac/pickm/bp/PickmApproveBP.java | 3 + .../bs/mmpac/pickm/bp/PickmUpdateForMOBP.java | 4 + .../rule/AfterApproveRuleHighpressureIms.java | 661 ++++++++++++++++++ 3 files changed, 668 insertions(+) create mode 100644 mmpac/src/private/nc/bs/mmpac/pickm/bp/rule/AfterApproveRuleHighpressureIms.java diff --git a/mmpac/src/private/nc/bs/mmpac/pickm/bp/PickmApproveBP.java b/mmpac/src/private/nc/bs/mmpac/pickm/bp/PickmApproveBP.java index ec3605b5..08d4c2be 100644 --- a/mmpac/src/private/nc/bs/mmpac/pickm/bp/PickmApproveBP.java +++ b/mmpac/src/private/nc/bs/mmpac/pickm/bp/PickmApproveBP.java @@ -1,6 +1,7 @@ package nc.bs.mmpac.pickm.bp; +import nc.bs.mmpac.pickm.bp.rule.AfterApproveRuleHighpressureIms; import nc.bs.mmpac.pickm.bp.rule.AfterApproveRuleHighpressureMes; import nc.bs.mmpac.pickm.bp.rule.AfterApproveRuleSyncRZWMS; import nc.bs.mmpac.pickm.plugin.PickmPluginPoint; @@ -28,6 +29,8 @@ public class PickmApproveBP { processer.addAfterRule(pickmstatusFilterRule); //备料计划审批后推送高压MES processer.addAfterRule(new AfterApproveRuleHighpressureMes()); + //备料计划审批后推送高压IMS + processer.addAfterRule(new AfterApproveRuleHighpressureIms()); } private void addBeforeRule(CompareAroundProcesser processer) { diff --git a/mmpac/src/private/nc/bs/mmpac/pickm/bp/PickmUpdateForMOBP.java b/mmpac/src/private/nc/bs/mmpac/pickm/bp/PickmUpdateForMOBP.java index f51a0cb1..04de9147 100644 --- a/mmpac/src/private/nc/bs/mmpac/pickm/bp/PickmUpdateForMOBP.java +++ b/mmpac/src/private/nc/bs/mmpac/pickm/bp/PickmUpdateForMOBP.java @@ -2,6 +2,7 @@ package nc.bs.mmpac.pickm.bp; import java.util.Map; +import nc.bs.mmpac.pickm.bp.rule.AfterApproveRuleHighpressureIms; import nc.bs.mmpac.pickm.bp.rule.AfterupdateSyncEpicMesRule; import nc.bs.mmpac.pickm.plugin.PickmPluginPoint; import nc.bs.mmpac.pickm.rule.PickmCheckItemMaterialPermissionRule; @@ -226,6 +227,9 @@ public class PickmUpdateForMOBP { aroundProcesser.addAfterRule(new AfterupdateSyncEpicMesRule()); + + //备料计划重算后推送高压IMS + aroundProcesser.addAfterRule(new AfterApproveRuleHighpressureIms()); } } diff --git a/mmpac/src/private/nc/bs/mmpac/pickm/bp/rule/AfterApproveRuleHighpressureIms.java b/mmpac/src/private/nc/bs/mmpac/pickm/bp/rule/AfterApproveRuleHighpressureIms.java new file mode 100644 index 00000000..4bc2bbf9 --- /dev/null +++ b/mmpac/src/private/nc/bs/mmpac/pickm/bp/rule/AfterApproveRuleHighpressureIms.java @@ -0,0 +1,661 @@ +package nc.bs.mmpac.pickm.bp.rule; + +import com.alibaba.fastjson.JSONObject; +import nc.bs.dao.BaseDAO; +import nc.bs.dao.DAOException; +import nc.bs.logging.Log; +import nc.bs.trade.business.HYPubBO; +import nc.bs.uapbd.util.MyHelper; +import nc.impl.pubapp.pattern.rule.IRule; +import nc.jdbc.framework.JdbcSession; +import nc.jdbc.framework.PersistenceManager; +import nc.jdbc.framework.exception.DbException; +import nc.jdbc.framework.processor.MapProcessor; +import nc.uif.pub.exception.UifException; +import nc.vo.bd.material.MaterialVO; +import nc.vo.mmpac.pickm.entity.AggPickmVO; +import nc.vo.mmpac.pickm.entity.PickmHeadVO; +import nc.vo.mmpac.pickm.entity.PickmItemVO; +import nc.vo.org.OrgVO; +import nc.vo.pub.BusinessException; +import nc.vo.pub.lang.UFDate; +import nc.vo.pub.lang.UFDateTime; +import nc.vo.pubapp.pattern.exception.ExceptionUtils; +import nc.vo.scmpub.util.ArrayUtil; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 备料计划审批后同步高压MES系统规则类 + * 功能:主表(BIPPlanMainTab)、子表(BIPPlanDetailTab)的新增/更新同步 + */ +public class AfterApproveRuleHighpressureIms implements IRule { + + // 日志配置(固定) + private static final String LOG_INFO_NAME = "gyimslog"; + private static final Log logger = Log.getInstance(LOG_INFO_NAME); + // 配置参数(同步目标组织等) + private Map configParams; + + // -------------------------- 线程安全的日期格式化工具(解决SimpleDateFormat线程安全问题) -------------------------- + private static final ThreadLocal DATETIME_FORMATTER = ThreadLocal.withInitial( + () -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") + ); + private static final ThreadLocal DATE_FORMATTER = ThreadLocal.withInitial( + () -> new SimpleDateFormat("yyyy-MM-dd") + ); + + + @Override + public void process(AggPickmVO[] aggPickmVOS) { + // 1. 空值快速返回(避免后续NPE) + if (ArrayUtil.isEmpty(aggPickmVOS)) { + logger.info("待同步的备料计划数组为空,直接返回"); + return; + } + + // 2. 加载配置参数(失败直接抛业务异常,阻断流程) + try { + configParams = MyHelper.getConfigParams("gy-config", null); + if (configParams == null || configParams.isEmpty()) { + throw new BusinessException("同步高压MES系统失败:未加载到\"gy-config\"配置参数"); + } + } catch (Exception e) { + logger.error("加载同步配置参数失败", e); + ExceptionUtils.wrappException(new BusinessException("加载配置参数异常:" + e.getMessage(), e)); + return; + } + + // 3. 构建同步数据并执行同步(统一异常捕获) + try { + List> mainDataList = new ArrayList<>(); // 主表数据 + List> detailDataList = new ArrayList<>(); // 子表数据 + buildSyncData(aggPickmVOS, mainDataList, detailDataList); + + // 4. 若有数据则执行同步(取第一个主表的cpickmid作为关键标识,若主表为空则不同步) + String targetCpickmid = mainDataList.isEmpty() ? null : (String) mainDataList.get(0).get("cpickmid"); + pushIms(mainDataList, detailDataList, targetCpickmid); + } catch (BusinessException e) { + // 业务异常:直接包装抛出(NC框架会处理) + logger.error("备料计划同步高压MES业务异常,关键备料单号:" + getCpickmidFromAgg(aggPickmVOS) + ""); + ExceptionUtils.wrappException(e); + } catch (Exception e) { + // 未知异常:转为业务异常,避免上游捕获到RuntimeException + String errorMsg = "备料计划同步高压MES系统未知异常,关键备料单号:" + getCpickmidFromAgg(aggPickmVOS); + logger.error(errorMsg, e); + ExceptionUtils.wrappException(new BusinessException(errorMsg, e)); + } + } + + + /** + * 构建同步数据(主表+子表) + * 修复原问题:数据覆盖 → 改为add元素;增强空值校验;统一JSON转Map逻辑 + */ + private void buildSyncData(AggPickmVO[] aggPickmVOS, List> mainDataList, List> detailDataList) throws BusinessException { + for (AggPickmVO aggVO : aggPickmVOS) { + // 1. 校验AggVO非空及获取表头/表体 + if (aggVO == null) { + logger.warn("跳过空的备料计划AggVO"); + continue; + } + PickmHeadVO headVO = aggVO.getParentVO(); + PickmItemVO[] itemVOs = (PickmItemVO[]) aggVO.getChildrenVO(); + if (headVO == null) { + logger.warn("备料计划AggVO的表头为空,跳过该记录"); + continue; + } + + // 2. 组织过滤(仅同步目标组织,原逻辑保留并优化日志) + String pkOrg = headVO.getPk_org(); + String orgCode = MyHelper.transferField(OrgVO.getDefaultTableName(), OrgVO.CODE, OrgVO.PK_ORG, pkOrg); + if (checkIfSkipOrg(orgCode,configParams)) { + logger.info("备料计划组织编码"+ orgCode +"非目标同步组织,跳过同步,备料单号:"+headVO.getVbillcode()+""); + continue; + } + + // 3. 构建主表数据(JSON → Map,添加到列表) + JSONObject mainJson = buildMainJsonObject(headVO); + List> mainMapList = JsonUtil.jsonObjectToListMap(mainJson); + if (!mainMapList.isEmpty()) { + mainDataList.add(mainMapList.get(0)); // 单个JSON转List后取第一个元素 + } + + // 4. 构建子表数据(循环表体,添加到列表) + if (itemVOs != null && itemVOs.length > 0) { + for (PickmItemVO itemVO : itemVOs) { + if (itemVO == null) { + logger.warn("备料计划" + headVO.getVbillcode() + "存在空表体,跳过该表体"); + continue; + } + JSONObject detailJson = buildDetailJsonObject(itemVO, headVO.getVbillcode()); + List> detailMapList = JsonUtil.jsonObjectToListMap(detailJson); + if (!detailMapList.isEmpty()) { + detailDataList.add(detailMapList.get(0)); + } + } + } else { + logger.info("备料计划" + headVO.getVbillcode() + "无表体数据,仅同步主表"); + } + } + } + + + private void pushIms(List> mainDataList, List> detailDataList, String targetCpickmid) throws BusinessException { + // 1. 关键参数校验 + if (targetCpickmid == null || targetCpickmid.trim().isEmpty()) { + logger.warn("同步目标备料计划主键cpickmid为空,终止同步"); + return; + } + if (mainDataList.isEmpty()) { + logger.warn("备料计划主表数据为空,终止同步,cpickmid:" + targetCpickmid + ""); + return; + } + + // 2. 直接通过静态工厂方法获取 PersistenceManager + PersistenceManager pm = null; + JdbcSession jdbcSession = null; + Connection conn = null; + boolean isSuccess = false; + + try { + // 直接调用 PersistenceManager 的静态方法 getInstance() + pm = PersistenceManager.getInstance("gyims"); + pm.setAddTimeStamp(false); + + // 2.1 获取 JdbcSession 和 Connection + jdbcSession = pm.getJdbcSession(); + jdbcSession.setSQLTranslator(true); // 保持 SQL 转换 + conn = jdbcSession.getConnection(); + conn.setAutoCommit(false); + logger.info("直接获取PersistenceManager,手动事务开启,cpickmid:" + targetCpickmid + ""); + + // 3. 判断新增/更新 (checkMainExists 方法逻辑不变) + boolean isUpdate = checkMainExists(pm, targetCpickmid); + + // 4. 执行主表+子表操作 (传入共享的 pm) + if (isUpdate) { + logger.info("事务内执行更新,cpickmid:" + targetCpickmid + ""); + updatePlanMain(mainDataList, pm, targetCpickmid); + if (!detailDataList.isEmpty()) { + updatePlanDetail(detailDataList, pm, targetCpickmid); + } + } else { + logger.info("事务内执行新增,cpickmid:" + targetCpickmid + ""); + insertPlanMain(mainDataList, pm, targetCpickmid); + if (!detailDataList.isEmpty()) { + insertPlanDetail(detailDataList, pm, targetCpickmid); + } + } + + isSuccess = true; + logger.info("事务内操作全部成功,准备提交,cpickmid:" + targetCpickmid + ""); + + } catch (DbException | SQLException e) { // 捕获 DbException 和 SQLException + logger.error("事务执行失败,触发回滚,cpickmid:" + targetCpickmid + ""); + if (conn != null) { + try { + conn.rollback(); + logger.info("事务回滚完成,cpickmid:" + targetCpickmid + ""); + } catch (SQLException rollbackE) { + logger.error("事务回滚异常,cpickmid:" + targetCpickmid + ""); + } + } + throw new BusinessException("备料计划同步事务失败:" + e.getMessage(), e); + + } finally { + if (conn != null) { + try { + if (isSuccess) { + conn.commit(); + logger.info("事务提交成功,cpickmid:" + targetCpickmid + ""); + } + conn.setAutoCommit(true); + } catch (SQLException commitE) { + logger.error("事务提交异常,cpickmid:" + targetCpickmid + ""); + } + } + // 5. 释放 PersistenceManager (至关重要) + if (pm != null) { + try { + pm.release(); // 必须调用 release() 将连接归还给连接池 + logger.info("PersistenceManager 释放完成,cpickmid:" + targetCpickmid + ""); + } catch (Exception releaseE) { + logger.error("PersistenceManager 释放异常", releaseE); + } + } + } + } + + + /** + * 校验主表是否存在(使用共享的 PersistenceManager) + */ + private boolean checkMainExists(PersistenceManager pm, String cpickmid) throws DAOException, DbException { + String safeCpickmid = cpickmid.replace("'", "''"); + String sql = "SELECT cpickmid FROM BIPPlanMainTab WHERE cpickmid = '" + safeCpickmid + "'"; + // 使用共享 pm 的 JdbcSession 执行查询,避免新建连接 + Map existMain = (Map) pm.getJdbcSession().executeQuery(sql, new MapProcessor()); + return existMain != null && !existMain.isEmpty(); + } + + + // -------------------------- 主表/子表JSON构建(拆分逻辑,增强可读性) -------------------------- + + /** + * 构建备料计划主表JSON + */ + private JSONObject buildMainJsonObject(PickmHeadVO headVO) throws UifException { + JSONObject mainJson = new JSONObject(); + mainJson.put("cpickmid", headVO.getCpickmid());// 主键ID + Object pk_org = new HYPubBO().findColValue("org_factory", "code", "nvl(dr,0) = 0 and pk_factory='" + headVO.getPk_org() + "' "); + mainJson.put("pk_org", pk_org);//组织_业务单元_工厂 + mainJson.put("vbillcode", headVO.getVbillcode());// 备料计划单号 + mainJson.put("fbillstatus", headVO.getFbillstatus());//备料状态 + mainJson.put("vbusitypeid", headVO.getVbusitypeid());//备料类型 + mainJson.put("vbusitype", headVO.getVbusitype());//备料类型编码 + Object cmaterialvid = new HYPubBO().findColValue("bd_material", "code", "nvl(dr,0) = 0 and pk_material='" + headVO.getCmaterialvid() + "' "); + mainJson.put("cmaterialvid", cmaterialvid.toString());//产品编码 + mainJson.put("nastnum", headVO.getNastnum() != null ? headVO.getNastnum().doubleValue() : null);//计划数量; + mainJson.put("cdeptid", headVO.getCdeptid());//用料部门最新版本 + mainJson.put("cdeptvid", headVO.getCdeptid());//用料部门 + mainJson.put("vsalebillcode", headVO.getVsalebillcode());//销售订单号 + mainJson.put("ccustmaterialid", headVO.getCcustmaterialid());//客户物料码 + mainJson.put("cemployeeid", headVO.getCemployeeid());//业务员 + mainJson.put("vfirstmoid", headVO.getVfirstmoid());//源头生产订单 + mainJson.put("vfirstmocode", headVO.getVfirstmocode());//源头生产订单号 + mainJson.put("vfirstmorowid", headVO.getVfirstmorowid());//源头生产订单明细 + mainJson.put("vfirstmorowcode", headVO.getVfirstmorowcode());//源头生产订单行号 + mainJson.put("vsourcemoid", headVO.getVsourcemoid());//来源生产订单 + mainJson.put("vsourcemocode", headVO.getVsourcemocode());//来源生产订单号 + mainJson.put("vsourcemorowid", headVO.getVsourcemorowid());//来源生产订单明细 + mainJson.put("vsourcemorowcode", headVO.getVsourcemorowcode());//来源生产订单行号 + mainJson.put("cfirstbillid", headVO.getCfirstbillid());//源头单据 + mainJson.put("vfirstbillcode", headVO.getVfirstbillcode());//源头单据号 + mainJson.put("vfirstbilltype", headVO.getVfirstbilltype());//源头单据类型 + mainJson.put("vfirsttrantypeid", headVO.getVfirsttrantypeid());//源头交易类型 + mainJson.put("vfirsttrantype", headVO.getVfirsttrantype());//源头交易类型编码 + mainJson.put("cfirstbillrowid", headVO.getCfirstbillrowid());//源头单据明细 + mainJson.put("vfirstbillrowno", headVO.getVfirstbillrowno());//源头单据行号 + mainJson.put("csourcebillid", headVO.getCsourcebillid());//来源单据 + mainJson.put("vsourcebillcode", headVO.getVsourcebillcode());//来源单据号 + mainJson.put("vsourcebilltype", headVO.getVsourcebilltype());//来源单据类型 + mainJson.put("vsrctrantypeid", headVO.getVsrctrantypeid());//来源交易类型 + mainJson.put("vsrctrantype", headVO.getVsrctrantype());//来源交易类型编码 + mainJson.put("csourcebillrowid", headVO.getCsourcebillrowid());//来源单据明细 + mainJson.put("vsourcebillrowno", headVO.getVsourcebillrowno());//来源单据行号 + mainJson.put("vnote", headVO.getVnote());//备注 + mainJson.put("status", headVO.getStatus());//同步状态 + mainJson.put("billmaker", headVO.getBillmaker()); + ;//制单人 + mainJson.put("dmakedate", headVO.getDmakedate()); // UFDate制单时间 + mainJson.put("creator", headVO.getCreator());//创建人 + mainJson.put("creationtime", headVO.getCreationtime()); // UFDateTime创建时间 + return mainJson; + } + + /** + * 构建备料计划子表JSON + */ + private JSONObject buildDetailJsonObject(PickmItemVO itemVO, String mainBillCode) throws UifException { + JSONObject detailJson = new JSONObject(); + detailJson.put("cpickm_bid", itemVO.getCpickm_bid());// 备料计划明细 + detailJson.put("cpickmid", itemVO.getCpickmid());// 备料计划单表头主键 + Object pk_org = new HYPubBO().findColValue("org_factory", "code", "nvl(dr,0) = 0 and pk_factory='" + itemVO.getPk_org() + "' "); + detailJson.put("pk_org", pk_org); // 工厂最新版本 + detailJson.put("vbillcode", mainBillCode); // 备料计划单表 + detailJson.put("vrowno", itemVO.getVrowno());// 行号 + detailJson.put("fitemtype", itemVO.getFitemtype());// 子项类型 + detailJson.put("fitemsource", itemVO.getFitemsource());// 备料来源 + Object cmaterialvid = new HYPubBO().findColValue("bd_material", "code", "nvl(dr,0) = 0 and pk_material='" + itemVO.getCbmaterialvid() + "' "); + detailJson.put("cbmaterialvid", cmaterialvid.toString());// 材料编码 + Object cbunitid = new HYPubBO().findColValue("bd_measdoc", "code", "nvl(dr,0) = 0 and pk_measdoc='" + itemVO.getCbunitid() + "' "); + detailJson.put("cbunitid", cbunitid.toString());// 主单位 + Object cbastunitid = new HYPubBO().findColValue("bd_measdoc", "code", "nvl(dr,0) = 0 and pk_measdoc='" + itemVO.getCbastunitid() + "' "); + detailJson.put("cbastunitid", cbastunitid.toString());// 单位 + detailJson.put("vbchangerate", itemVO.getVbchangerate());// 换算率 + detailJson.put("nquotastnum", itemVO.getNquotastnum() != null ? itemVO.getNquotastnum().doubleValue() : null);// 定额用量 + detailJson.put("nplanoutastnum", itemVO.getNplanoutastnum() != null ? itemVO.getNplanoutastnum().doubleValue() : null); // 计划出库数量 + detailJson.put("nplanoutnum", itemVO.getNplanoutnum() != null ? itemVO.getNplanoutnum().doubleValue() : null);// 计划出库主数量 + detailJson.put("vbdef22", itemVO.getVbdef20()); // 是否备件 + return detailJson; + } + + + // -------------------------- 新增/更新逻辑(提取通用SQL值处理,减少冗余) -------------------------- + + /** + * 主表新增(使用共享的 PersistenceManager) + * + * @param mainDataList 主表数据列表 + * @param pm 共享的 PersistenceManager 实例 + * @param cpickmid 主表业务主键 + */ + private void insertPlanMain(List> mainDataList, PersistenceManager pm, String cpickmid) throws DAOException, DbException, DbException { + // 1. 构建 SQL(逻辑与原代码一致,仅执行方式改变) + String[] mainFields = { + "cpickmid", "pk_org", "vbillcode", "fbillstatus", "vbusitypeid", "vbusitype", + "cmaterialvid", "nastnum", "cdeptid", "cdeptvid", "vsalebillcode", "ccustmaterialid", + "cemployeeid", "vfirstmoid", "vfirstmocode", "vfirstmorowid", "vfirstmorowcode", + "vsourcemoid", "vsourcemocode", "vsourcemorowid", "vsourcemorowcode", "cfirstbillid", + "vfirstbillcode", "vfirstbilltype", "vfirsttrantypeid", "vfirsttrantype", "cfirstbillrowid", + "vfirstbillrowno", "csourcebillid", "vsourcebillcode", "vsourcebilltype", "vsrctrantypeid", + "vsrctrantype", "csourcebillrowid", "vsourcebillrowno", "vnote", "status", + "billmaker", "dmakedate", "creator", "creationtime" + }; + String fieldStr = String.join(", ", mainFields); + StringBuilder valuesSb = new StringBuilder(); + + for (Map data : mainDataList) { + data.put("status", "C"); + valuesSb.append("("); + for (int i = 0; i < mainFields.length; i++) { + Object value = data.get(mainFields[i]); + valuesSb.append(SqlValueUtil.processSqlValue(value)); + if (i < mainFields.length - 1) { + valuesSb.append(", "); + } + } + valuesSb.append("), "); + } + + // 2. 执行 SQL(使用共享 pm 的 JdbcSession,避免新建连接) + if (valuesSb.length() > 0) { + String valuesStr = valuesSb.substring(0, valuesSb.length() - 2); + String insertSql = "INSERT INTO BIPPlanMainTab (" + fieldStr + ") VALUES " + valuesStr; + + // 关键:用共享 pm 的 JdbcSession 执行,而非 BaseDAO 的 executeUpdate + int rows = pm.getJdbcSession().executeUpdate(insertSql); + logger.info("主表新增成功,cpickmid:" + cpickmid + ",影响行数:" + rows + ""); + } + } + + /** + * 子表新增(使用共享的 PersistenceManager) + * + * @param detailDataList 子表数据列表 + * @param pm 共享的 PersistenceManager 实例 + * @param cpickmid 子表业务主键 + */ + private void insertPlanDetail(List> detailDataList, PersistenceManager pm, String cpickmid) throws DAOException, DbException { + String[] detailFields = { + "cpickm_bid", "cpickmid", "pk_org", "vbillcode", "vrowno", "fitemtype", + "fitemsource", "cbmaterialvid", "cbunitid", "cbastunitid", "vbchangerate", "nquotastnum", + "nplanoutastnum", "nplanoutnum", "vbdef22" + }; + String fieldStr = String.join(", ", detailFields); + StringBuilder valuesSb = new StringBuilder(); + + for (Map data : detailDataList) { + valuesSb.append("("); + for (int i = 0; i < detailFields.length; i++) { + Object value = data.get(detailFields[i]); + valuesSb.append(SqlValueUtil.processSqlValue(value)); + if (i < detailFields.length - 1) { + valuesSb.append(", "); + } + } + valuesSb.append("), "); + } + + if (valuesSb.length() > 0) { + String valuesStr = valuesSb.substring(0, valuesSb.length() - 2); + String insertSql = "INSERT INTO BIPPlanDetailTab (" + fieldStr + ") VALUES " + valuesStr; + + // 关键:用共享 pm 的 JdbcSession 执行 + int rows = pm.getJdbcSession().executeUpdate(insertSql); + logger.info("子表新增成功,子表cpickmid:" + cpickmid + ",影响行数:" + rows + ""); + } + } + + /** + * 主表更新(使用共享的 PersistenceManager) + * + * @param mainDataList 主表数据列表 + * @param pm 共享的 PersistenceManager 实例 + * @param cpickmid 主表业务主键 + */ + private void updatePlanMain(List> mainDataList, PersistenceManager pm, String cpickmid) throws DAOException, DbException { + String[] mainFields = { + "pk_org", "vbillcode", "fbillstatus", "vbusitypeid", "vbusitype", + "cmaterialvid", "nastnum", "cdeptid", "cdeptvid", "vsalebillcode", "ccustmaterialid", + "cemployeeid", "vfirstmoid", "vfirstmocode", "vfirstmorowid", "vfirstmorowcode", + "vsourcemoid", "vsourcemocode", "vsourcemorowid", "vsourcemorowcode", "cfirstbillid", + "vfirstbillcode", "vfirstbilltype", "vfirsttrantypeid", "vfirsttrantype", "cfirstbillrowid", + "vfirstbillrowno", "csourcebillid", "vsourcebillcode", "vsourcebilltype", "vsrctrantypeid", + "vsrctrantype", "csourcebillrowid", "vsourcebillrowno", "vnote", "status", + "billmaker", "dmakedate", "creator", "creationtime" + }; + + Map mainData = mainDataList.get(0); + mainData.put("status", "U"); + StringBuilder setSb = new StringBuilder(); + for (String field : mainFields) { + Object value = mainData.get(field); + setSb.append(field).append(" = ").append(SqlValueUtil.processSqlValue(value)).append(", "); + } + + if (setSb.length() > 0) { + String setStr = setSb.substring(0, setSb.length() - 2); + String safeCpickmid = cpickmid.replace("'", "''"); + String updateSql = "UPDATE BIPPlanMainTab SET " + setStr + " WHERE cpickmid = '" + safeCpickmid + "'"; + + // 关键:用共享 pm 的 JdbcSession 执行 + int rows = pm.getJdbcSession().executeUpdate(updateSql); + logger.info("主表更新成功,cpickmid:" + cpickmid + ",影响行数:" + rows + ""); + } + } + + /** + * 子表更新(使用共享的 PersistenceManager) + * + * @param detailDataList 子表数据列表 + * @param pm 共享的 PersistenceManager 实例 + * @param cpickmid 子表业务主键 + */ + private void updatePlanDetail(List> detailDataList, PersistenceManager pm, String cpickmid) throws BusinessException { + if (detailDataList.isEmpty()) { + logger.warn("备料计划" + cpickmid + "子表同步数据为空,跳过更新"); + return; + } + + String[] detailFields = { + "cpickmid", "pk_org", "vbillcode", "vrowno", "fitemtype", + "fitemsource", "cbmaterialvid", "cbunitid", "cbastunitid", "vbchangerate", "nquotastnum", + "nplanoutastnum", "nplanoutnum", "vbdef22" + }; + + // 循环更新每条子表数据 + for (Map detailData : detailDataList) { + String cpickmBid = (String) detailData.get("cpickm_bid"); + if (cpickmBid == null || cpickmBid.trim().isEmpty()) { + logger.warn("备料计划" + cpickmid + "子表主键cpickm_bid为空,跳过该子表更新"); + continue; + } + + // 构建SET语句 + StringBuilder setSb = new StringBuilder(); + for (String field : detailFields) { + Object value = detailData.get(field); + setSb.append(field).append(" = ").append(SqlValueUtil.processSqlValue(value)).append(", "); + } + + // 执行SQL + if (setSb.length() > 0) { + String setStr = setSb.substring(0, setSb.length() - 2); + String safeBid = cpickmBid.replace("'", "''"); + String updateSql = "UPDATE BIPPlanDetailTab SET " + setStr + " WHERE cpickm_bid = '" + safeBid + "'"; + + // 关键:使用共享的 PersistenceManager 执行 SQL + try { + int rows = pm.getJdbcSession().executeUpdate(updateSql); + logger.info("子表更新成功,子表主键:" + cpickmBid + ",影响行数:" + rows + ""); + } catch (DbException e) { + throw new BusinessException("子表更新失败,SQL: " + updateSql, e); + } + } + } + } + + + // -------------------------- 通用工具方法(提取后复用,减少冗余) -------------------------- + + /** + * 执行SQL并处理DAO异常 + * + * @param sql SQL语句 + * @param dao BaseDAO实例 + * @param operType 操作类型(如"主表新增") + * @param bizKey 业务标识(如cpickmid) + */ + private void executeSql(String sql, BaseDAO dao, String operType, String bizKey) throws BusinessException { + try { + logger.debug("执行" + operType + "SQL,业务标识:" + bizKey + ",SQL:" + sql + ""); + int rows = dao.executeUpdate(sql); + logger.info("" + operType + "成功,业务标识:" + bizKey + ",影响行数:" + rows + ""); + } catch (DAOException e) { + String errorMsg = operType + "失败,业务标识:" + bizKey + ",SQL:" + sql; + logger.error(errorMsg, e); + throw new BusinessException(errorMsg, e); + } + } + + /** + * 判断是否跳过该组织 + */ + private boolean checkIfSkipOrg(String code, Map configParams) throws BusinessException{ + String targetCode = configParams.get("imsOrg"); + if (targetCode == null || nc.vo.am.common.util.StringUtils.isEmpty(targetCode)) { + throw new BusinessException("未配置组织参数"); + } + String[] orgItem = targetCode.split(","); + for (String orgCode : orgItem) { + if (!orgCode.isEmpty() && orgCode.equals(code)) { + return false; + } + } + return true; + } + + /** + * 从Agg数组中提取关键备料单号(用于日志) + */ + private String getCpickmidFromAgg(AggPickmVO[] aggPickmVOS) { + if (aggPickmVOS != null && aggPickmVOS[0] != null && aggPickmVOS[0].getParentVO() != null) { + return aggPickmVOS[0].getParentVO().getCpickmid(); + } + return "未知"; + } + + + // -------------------------- 内部工具类(封装通用逻辑,避免污染外部类) -------------------------- + + /** + * JSON处理工具类 + */ + private static class JsonUtil { + /** + * JSONObject转List>(单个JSON对象) + */ + public static List> jsonObjectToListMap(JSONObject jsonObject) { + List> resultList = new ArrayList<>(); + if (jsonObject == null || jsonObject.isEmpty()) { + return resultList; + } + // 指定初始容量,优化性能 + Map dataMap = new HashMap<>(jsonObject.size()); + for (Map.Entry entry : jsonObject.entrySet()) { + dataMap.put(entry.getKey(), entry.getValue()); + } + resultList.add(dataMap); + return resultList; + } + } + + /** + * SQL值处理工具类(封装日期转换、字符串转义等) + */ + private static class SqlValueUtil { + /** + * 处理SQL值(自动识别类型,转义特殊字符,加单引号) + */ + public static String processSqlValue(Object value) { + if (value == null) { + return "NULL"; + } + // 处理UFDateTime类型 + if (value instanceof UFDateTime) { + return formatUFDateTime((UFDateTime) value); + } + // 处理UFDate类型 + if (value instanceof UFDate) { + return formatUFDate((UFDate) value); + } + // 处理标准日期类型 + if (value instanceof Date || value instanceof Timestamp) { + return formatDate((Date) value, true); + } + // 处理字符串类型(转义单引号) + if (value instanceof String) { + String safeStr = ((String) value).replace("'", "''"); + return "'" + safeStr + "'"; + } + // 其他类型(数字、布尔等)直接转字符串 + return String.valueOf(value); + } + + /** + * 格式化UFDateTime(转SQL字符串) + */ + private static String formatUFDateTime(UFDateTime ufDateTime) { + try { + Date date = ufDateTime.getDate().toDate(); + return formatDate(date, true); + } catch (Exception e) { + logger.error("格式化UFDateTime失败,值:" + ufDateTime + ""); + return "NULL"; + } + } + + /** + * 格式化UFDate(转SQL字符串) + */ + private static String formatUFDate(UFDate ufDate) { + try { + Date date = ufDate.toDate(); // 依赖UFDate的toDate()方法返回Date + return formatDate(date, true); + } catch (Exception e) { + logger.error("格式化UFDate失败,值:" + ufDate + ""); + return "NULL"; + } + } + + /** + * 格式化Date为SQL字符串 + * + * @param withTime 是否包含时间(true: yyyy-MM-dd HH:mm:ss; false: yyyy-MM-dd) + */ + private static String formatDate(Date date, boolean withTime) { + if (date == null) { + return "NULL"; + } + SimpleDateFormat sdf = withTime ? DATETIME_FORMATTER.get() : DATE_FORMATTER.get(); + try { + String dateStr = sdf.format(date); + return "'" + dateStr + "'"; + } finally { + // 移除ThreadLocal中的Formatter,避免内存泄漏 + if (withTime) { + DATETIME_FORMATTER.remove(); + } else { + DATE_FORMATTER.remove(); + } + } + } + } +} \ No newline at end of file From 220e5bf1475f655d25be204052bd9f1ada4e875b Mon Sep 17 00:00:00 2001 From: mzr Date: Wed, 1 Oct 2025 10:12:14 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E7=8E=B0=E5=AD=98=E9=87=8F=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/ic/onhand/APIOnhandQueryIpml.java | 43 ++++++++++++++++++- .../api/ic/onhand/IAPIOnhandQuery.java | 9 ++++ .../openapi/ic/onhand/OnhandResource.java | 2 +- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/ic/src/private/nccloud/api/impl/ic/onhand/APIOnhandQueryIpml.java b/ic/src/private/nccloud/api/impl/ic/onhand/APIOnhandQueryIpml.java index 462f2876..48e26bec 100644 --- a/ic/src/private/nccloud/api/impl/ic/onhand/APIOnhandQueryIpml.java +++ b/ic/src/private/nccloud/api/impl/ic/onhand/APIOnhandQueryIpml.java @@ -14,6 +14,7 @@ import nccloud.openapi.scmpub.pub.TransferCodeToPKTool; import nccloud.openapi.scmpub.pubitf.IJsonParamMapping; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -59,7 +60,7 @@ public class APIOnhandQueryIpml implements IAPIOnhandQuery { public OnhandVO[] queryOnhandVOByDimsNoTrans(List> paramMapList) throws BusinessException { - //必输项检查 + // 必输项检查 try { List onhandDimVOS = new ArrayList<>(); for (Map paramMap : paramMapList) { @@ -79,6 +80,7 @@ public class APIOnhandQueryIpml implements IAPIOnhandQuery { return null; } } + @Override public OnhandVO[] queryOnhandVOByDims(List> paramMapList) throws Exception { // 必输项检查 @@ -120,6 +122,45 @@ public class APIOnhandQueryIpml implements IAPIOnhandQuery { return onhandVOs; } + @Override + public OnhandVO[] onhandQueryBatch(Map paramMap) throws Exception { + try { + List onhandDimVOS = new ArrayList<>(); + String pk_org = paramMap.get("pk_org").toString(); + if (paramMap.get("cmaterialoid") != null && paramMap.get("cmaterialoid") instanceof List) { + List cmaterialoids = (List) paramMap.get("cmaterialoid"); + for (String cmaterialoid : cmaterialoids) { + Map selMap = new HashMap<>(); + selMap.put("pk_org", pk_org); + selMap.put("cmaterialoid", cmaterialoid); + // 翻译 + selMap = TransferCodeToPKTool.doTranslateFields(jsonParamMapping, selMap); + OnhandDataSupplement dataSupplement = new OnhandDataSupplement(); + OnhandDimVO onhandDimVO = new OnhandDimVO(); + onhandDimVO = dataSupplement.process(selMap); + onhandDimVOS.add(onhandDimVO); + } + + } else { + Map selMap = new HashMap<>(); + selMap.put("pk_org", pk_org); + // 翻译 + selMap = TransferCodeToPKTool.doTranslateFields(jsonParamMapping, selMap); + OnhandDataSupplement dataSupplement = new OnhandDataSupplement(); + OnhandDimVO onhandDimVO = new OnhandDimVO(); + onhandDimVO = dataSupplement.process(selMap); + onhandDimVOS.add(onhandDimVO); + } + + OnhandVO[] onhandVOs = NCLocator.getInstance().lookup(OnhandResService.class) + .queryOnhandVOByDims(onhandDimVOS.toArray(new OnhandDimVO[0])); + return onhandVOs; + } catch (Exception e) { + ExceptionUtils.marsh(e); + return null; + } + } + // 必输项校验 private void requiredFieldCheck(String[] requiredField, Map paramMap) { diff --git a/ic/src/public/nccloud/api/ic/onhand/IAPIOnhandQuery.java b/ic/src/public/nccloud/api/ic/onhand/IAPIOnhandQuery.java index e94d4a22..03708dc6 100644 --- a/ic/src/public/nccloud/api/ic/onhand/IAPIOnhandQuery.java +++ b/ic/src/public/nccloud/api/ic/onhand/IAPIOnhandQuery.java @@ -46,4 +46,13 @@ public interface IAPIOnhandQuery { * @throws Exception 当查询操作失败时抛出的异常 */ OnhandVO[] queryOnhandVOByCondition(Map paramMap) throws Exception; + + /** + * 根据查询条件查询多个物料的现存量信息 + * + * @param paramMap 参数映射列表,每个映射包含一组查询条件 + * @return OnhandVO[] 查询到的现存量信息数组 + * @throws Exception 当查询操作失败时抛出的异常 + */ + OnhandVO[] onhandQueryBatch(Map paramMap) throws Exception; } diff --git a/ic/src/public/nccloud/openapi/ic/onhand/OnhandResource.java b/ic/src/public/nccloud/openapi/ic/onhand/OnhandResource.java index bf349736..2e367616 100644 --- a/ic/src/public/nccloud/openapi/ic/onhand/OnhandResource.java +++ b/ic/src/public/nccloud/openapi/ic/onhand/OnhandResource.java @@ -773,7 +773,7 @@ public class OnhandResource { } try { OnhandVO[] onhandVOs = NCLocator.getInstance().lookup(IAPIOnhandQuery.class) - .queryOnhandVOByDims(paramMap); + .onhandQueryBatch(paramMap); // 对数据进行整合组装,返回物料+仓库+数量 if (null != onhandVOs && onhandVOs.length > 0) { // 收集所有物料和仓库ID From be49a4f6f45b7bd2219e298c0f206e3639a3fa45 Mon Sep 17 00:00:00 2001 From: mzr Date: Wed, 1 Oct 2025 10:25:13 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E7=8E=B0=E5=AD=98=E9=87=8F=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/impl/ic/onhand/APIOnhandQueryIpml.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ic/src/private/nccloud/api/impl/ic/onhand/APIOnhandQueryIpml.java b/ic/src/private/nccloud/api/impl/ic/onhand/APIOnhandQueryIpml.java index 48e26bec..876d5a4d 100644 --- a/ic/src/private/nccloud/api/impl/ic/onhand/APIOnhandQueryIpml.java +++ b/ic/src/private/nccloud/api/impl/ic/onhand/APIOnhandQueryIpml.java @@ -1,6 +1,7 @@ package nccloud.api.impl.ic.onhand; import nc.bs.framework.common.NCLocator; +import nc.bs.logging.Logger; import nc.itf.ic.onhand.OnhandResService; import nc.vo.ic.onhand.entity.OnhandDimVO; import nc.vo.ic.onhand.entity.OnhandVO; @@ -137,7 +138,15 @@ public class APIOnhandQueryIpml implements IAPIOnhandQuery { selMap = TransferCodeToPKTool.doTranslateFields(jsonParamMapping, selMap); OnhandDataSupplement dataSupplement = new OnhandDataSupplement(); OnhandDimVO onhandDimVO = new OnhandDimVO(); - onhandDimVO = dataSupplement.process(selMap); + try { + onhandDimVO = dataSupplement.process(selMap); + } catch (Exception e) { + Logger.error(e); + } + // 跳过查不出数据的物料 + if (onhandDimVO == null || onhandDimVO.getCmaterialoid() == null) { + continue; + } onhandDimVOS.add(onhandDimVO); } @@ -151,7 +160,6 @@ public class APIOnhandQueryIpml implements IAPIOnhandQuery { onhandDimVO = dataSupplement.process(selMap); onhandDimVOS.add(onhandDimVO); } - OnhandVO[] onhandVOs = NCLocator.getInstance().lookup(OnhandResService.class) .queryOnhandVOByDims(onhandDimVOS.toArray(new OnhandDimVO[0])); return onhandVOs; From 80133551cad0c986911bd8ba8ac2c3ceb0b041f6 Mon Sep 17 00:00:00 2001 From: mzr Date: Wed, 1 Oct 2025 13:05:33 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E5=AE=9A=E6=97=B6=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E9=AB=98=E5=8E=8B=E5=8A=A0=E5=B7=A5=E8=BD=A6=E9=97=B4IMS?= =?UTF-8?q?=E7=9A=84=E7=94=9F=E4=BA=A7=E6=8A=A5=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../uapbd/task/ProductReportGyImsPlugin.java | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 uapbd/src/private/nc/bs/uapbd/task/ProductReportGyImsPlugin.java diff --git a/uapbd/src/private/nc/bs/uapbd/task/ProductReportGyImsPlugin.java b/uapbd/src/private/nc/bs/uapbd/task/ProductReportGyImsPlugin.java new file mode 100644 index 00000000..2cc8eae9 --- /dev/null +++ b/uapbd/src/private/nc/bs/uapbd/task/ProductReportGyImsPlugin.java @@ -0,0 +1,171 @@ +package nc.bs.uapbd.task; + +import nc.bs.dao.BaseDAO; +import nc.bs.framework.common.NCLocator; +import nc.bs.logging.Logger; +import nc.bs.pub.pa.PreAlertObject; +import nc.bs.pub.taskcenter.BgWorkingContext; +import nc.bs.pub.taskcenter.IBackgroundWorkPlugin; +import nc.bs.uapbd.util.MyHelper; +import nc.itf.mmpac.pmo.pac0002.IPMOQueryService; +import nc.itf.mmpac.wr.IWrMaintainService; +import nc.itf.uap.pf.busiflow.PfButtonClickContext; +import nc.jdbc.framework.processor.MapListProcessor; +import nc.util.mmf.busi.service.PFPubService; +import nc.util.mmf.framework.base.MMValueCheck; +import nc.vo.bd.material.MaterialVO; +import nc.vo.fi.pub.SqlUtils; +import nc.vo.mmpac.pmo.pac0002.entity.PMOAggVO; +import nc.vo.mmpac.wr.entity.AggWrVO; +import nc.vo.mmpac.wr.entity.WrItemVO; +import nc.vo.mmpac.wr.entity.WrVO; +import nc.vo.pub.BusinessException; +import nc.vo.pub.lang.UFDate; +import nc.vo.pub.lang.UFDateTime; +import nc.vo.pub.lang.UFDouble; +import nc.vo.scmpub.res.billtype.MMBillType; +import nccloud.baseapp.core.log.NCCForUAPLogger; +import uap.mw.trans.TransactionFactory; + +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * 定时同步高压加工车间IMS的生产报告 + * + * @author mzr + * @date 20250929 + */ +public class ProductReportGyImsPlugin implements IBackgroundWorkPlugin { + private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + private SimpleDateFormat sdf_ts = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + // BIP数据源 + public static final BaseDAO baseDAO = new BaseDAO(); + // IMS数据源 + public BaseDAO imsDao; + + /** + * 获取IMS数据源 + */ + public BaseDAO getImsDao() { + if (imsDao == null) { + imsDao = new BaseDAO("gyims"); + // 禁用时间戳ts + imsDao.setAddTimeStamp(false); + } + return imsDao; + } + + @Override + public PreAlertObject executeTask(BgWorkingContext arg0) { + Logger.error("---start----任务开始运行--"); + try { + IPMOQueryService pmoQueryService = NCLocator.getInstance().lookup(IPMOQueryService.class); + IWrMaintainService wrService = NCLocator.getInstance().lookup(IWrMaintainService.class); + // 手动开启事务 + TransactionFactory.getTMProxy().begin(3, 0); + // IMS:C-创建;U-修改 BIP:2-BIP单据接收完成 + String selSql = "select * from BIPReportMainTab where status != '2'"; + List> mainList = (List>) getImsDao().executeQuery(selSql, new MapListProcessor()); + Set pkWrSet = new HashSet<>(); + for (Map mainMap : mainList) { + String pkWr = mainMap.get("pk_wr").toString(); + String pkWrSql = "select * from BIPReportDetailTab where pk_wr = '" + pkWr + "'"; + List> detailList = (List>) getImsDao().executeQuery(pkWrSql, new MapListProcessor()); + Map> detailIdMap = new HashMap<>(); + for (Map detailMap : detailList) { + detailIdMap.put(detailMap.get("vbdef23").toString(), detailMap); + } + if (detailList.isEmpty()) { + continue; + } + String vbdef22 = detailList.get(0).get("vbdef22") + "";// 流程生产订单主键 + // 查询流程生产订单的VO + PMOAggVO[] pmoAggVOS = pmoQueryService.queryByPks(new String[]{vbdef22}); + // 调用单据转换规则转换出流程生产报告的VO + AggWrVO[] vos = (AggWrVO[]) PFPubService.runChangeData(MMBillType.ProduceOrder.getCode(), MMBillType.ProduceReport.getCode(), + pmoAggVOS, null, PfButtonClickContext.ClassifyByItfdef); + if (MMValueCheck.isEmpty(vos)) { + continue; + } + // 根据IMS字段赋值 + for (AggWrVO vo : vos) { + WrVO hvo = vo.getParentVO(); + WrItemVO[] bvos = vo.getChildrenVO(); + hvo.setVbillcode(mainMap.get("vbillcode") + ""); + hvo.setCreator("BIP"); + hvo.setBillmaker("BIP"); + String dmakedateStr = ""; + if (mainMap.get("dmakedate") != null) { + Timestamp dmakedate1 = (Timestamp) mainMap.get("dmakedate"); + dmakedateStr = sdf.format(dmakedate1); + UFDate dmakedate = new UFDate(dmakedateStr); + hvo.setDmakedate(dmakedate); + } + if (mainMap.get("creationtime") != null) { + Timestamp creationtime1 = (Timestamp) mainMap.get("creationtime"); + String creationtimeStr = sdf_ts.format(creationtime1); + UFDateTime creationtime = new UFDateTime(creationtimeStr); + hvo.setCreationtime(creationtime); + } + for (WrItemVO bvo : bvos) { + bvo.setFbproducttype(1);// 产品类型 1.主产品 + bvo.setTbstarttime(new UFDateTime(dmakedateStr + " 00:00:00"));// 开始时间 + bvo.setTbendtime(new UFDateTime(dmakedateStr + " 23:59:59"));// 结束时间 + String cbmobid = bvo.getCbmobid();// 流程生产订单明细id + Map detailMap = detailIdMap.get(cbmobid); + if (detailMap != null) { + // 物料或数量替换 + bvo.setNbplanwrnum(new UFDouble((BigDecimal) detailMap.get("nbplanwrnum")));// 计划完工主数量 + bvo.setNbplanwrastnum(new UFDouble((BigDecimal) detailMap.get("nbplanwrastnum")));// 计划完工数量 + bvo.setNbwrnum(new UFDouble((BigDecimal) detailMap.get("nbwrnum")));// 完工主数量 + bvo.setNbwrastnum(new UFDouble((BigDecimal) detailMap.get("nbwrastnum")));// 完工数量 + // 如果物料不相等,则BIP物料替换为IMS物料 + String cbmaterialvid = bvo.getCbmaterialvid(); + String goodsCode = detailMap.get("cbmaterialvid") + ""; + String goodsId = MyHelper.getStrValByCondition(MaterialVO.getDefaultTableName(), MaterialVO.PK_MATERIAL, + MaterialVO.CODE + " = '" + goodsCode + "'"); + if (!cbmaterialvid.equals(goodsId)) { + bvo.setCbmaterialvid(goodsId); + } + } + } + } + AggWrVO[] resultvos = null; + try { + resultvos = wrService.insert(vos); + } catch (BusinessException e) { + Logger.error("ProductReportGyImsPlugin Error: ", e); + NCCForUAPLogger.debug("ProductReportGyImsPlugin Error: " + e.getMessage()); + String updateSql = "update BIPReportMainTab set err_msg = '[err_msg]' where pk_wr = '[pkWr]'"; + updateSql = updateSql.replace("[err_msg]", e.getMessage()); + updateSql = updateSql.replace("[pkWr]", pkWr); + NCCForUAPLogger.debug("ProductReportGyImsPlugin-updateSql = " + updateSql); + getImsDao().executeUpdate(updateSql); + } + if (MMValueCheck.isEmpty(resultvos)) { + continue; + } + pkWrSet.add(pkWr); + } + if (!pkWrSet.isEmpty()) { + // 修改状态为 完成 + String inSql = SqlUtils.getInStr("pk_wr", pkWrSet.toArray(new String[0]), Boolean.TRUE); + String updateSql = "update BIPReportMainTab set status = '2' where " + inSql; + getImsDao().executeUpdate(updateSql); + } + // 正常结束 + TransactionFactory.getTMProxy().end(null); + Logger.error("---end----任务结束运行--"); + } catch (Exception e) { + // 异常回滚 + TransactionFactory.getTMProxy().end(e); + Logger.error("ProductReportGyImsPlugin Error: ", e); + NCCForUAPLogger.debug("ProductReportGyImsPlugin Error: " + e.getMessage()); + } + return null; + } + +}