Merge remote-tracking branch 'origin/main'
This commit is contained in:
		
						commit
						a4549be60b
					
				|  | @ -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; | ||||
|  | @ -14,6 +15,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 +61,7 @@ public class APIOnhandQueryIpml implements IAPIOnhandQuery { | |||
|     public OnhandVO[] queryOnhandVOByDimsNoTrans(List<Map<String, Object>> paramMapList) throws BusinessException { | ||||
| 
 | ||||
| 
 | ||||
|         //±<EFBFBD><EFBFBD>ה<EFBFBD>מ¼ל²י | ||||
|         // 必输项检查 | ||||
|         try { | ||||
|             List<OnhandDimVO> onhandDimVOS = new ArrayList<>(); | ||||
|             for (Map<String, Object> paramMap : paramMapList) { | ||||
|  | @ -79,6 +81,7 @@ public class APIOnhandQueryIpml implements IAPIOnhandQuery { | |||
|             return null; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public OnhandVO[] queryOnhandVOByDims(List<Map<String, Object>> paramMapList) throws Exception { | ||||
|         // ±ØÊäÏî¼ì²é | ||||
|  | @ -120,6 +123,52 @@ public class APIOnhandQueryIpml implements IAPIOnhandQuery { | |||
|         return onhandVOs; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public OnhandVO[] onhandQueryBatch(Map<String, Object> paramMap) throws Exception { | ||||
|         try { | ||||
|             List<OnhandDimVO> onhandDimVOS = new ArrayList<>(); | ||||
|             String pk_org = paramMap.get("pk_org").toString(); | ||||
|             if (paramMap.get("cmaterialoid") != null && paramMap.get("cmaterialoid") instanceof List) { | ||||
|                 List<String> cmaterialoids = (List<String>) paramMap.get("cmaterialoid"); | ||||
|                 for (String cmaterialoid : cmaterialoids) { | ||||
|                     Map<String, Object> 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(); | ||||
|                     try { | ||||
|                         onhandDimVO = dataSupplement.process(selMap); | ||||
|                     } catch (Exception e) { | ||||
|                         Logger.error(e); | ||||
|                     } | ||||
|                     // 跳过查不出数据的物料 | ||||
|                     if (onhandDimVO == null || onhandDimVO.getCmaterialoid() == null) { | ||||
|                         continue; | ||||
|                     } | ||||
|                     onhandDimVOS.add(onhandDimVO); | ||||
|                 } | ||||
| 
 | ||||
|             } else { | ||||
|                 Map<String, Object> 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<String, Object> paramMap) { | ||||
|  |  | |||
|  | @ -46,4 +46,13 @@ public interface IAPIOnhandQuery { | |||
|      * @throws Exception 当查询操作失败时抛出的异常 | ||||
|      */ | ||||
|     OnhandVO[] queryOnhandVOByCondition(Map<String, Object> paramMap) throws Exception; | ||||
| 
 | ||||
|     /** | ||||
|      * 根据查询条件查询多个物料的现存量信息 | ||||
|      * | ||||
|      * @param paramMap 参数映射列表,每个映射包含一组查询条件 | ||||
|      * @return OnhandVO[] 查询到的现存量信息数组 | ||||
|      * @throws Exception 当查询操作失败时抛出的异常 | ||||
|      */ | ||||
|     OnhandVO[] onhandQueryBatch(Map<String, Object> paramMap) throws Exception; | ||||
| } | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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<AggPickmVO> processer) { | ||||
|  |  | |||
|  | @ -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()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -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<AggPickmVO> { | ||||
| 
 | ||||
|     // 日志配置(固定) | ||||
|     private static final String LOG_INFO_NAME = "gyimslog"; | ||||
|     private static final Log logger = Log.getInstance(LOG_INFO_NAME); | ||||
|     // 配置参数(同步目标组织等) | ||||
|     private Map<String, String> configParams; | ||||
| 
 | ||||
|     // -------------------------- 线程安全的日期格式化工具(解决SimpleDateFormat线程安全问题) -------------------------- | ||||
|     private static final ThreadLocal<SimpleDateFormat> DATETIME_FORMATTER = ThreadLocal.withInitial( | ||||
|             () -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") | ||||
|     ); | ||||
|     private static final ThreadLocal<SimpleDateFormat> 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<Map<String, Object>> mainDataList = new ArrayList<>(); // 主表数据 | ||||
|             List<Map<String, Object>> 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<Map<String, Object>> mainDataList, List<Map<String, Object>> 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<Map<String, Object>> 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<Map<String, Object>> detailMapList = JsonUtil.jsonObjectToListMap(detailJson); | ||||
|                     if (!detailMapList.isEmpty()) { | ||||
|                         detailDataList.add(detailMapList.get(0)); | ||||
|                     } | ||||
|                 } | ||||
|             } else { | ||||
|                 logger.info("备料计划" + headVO.getVbillcode() + "无表体数据,仅同步主表"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     private void pushIms(List<Map<String, Object>> mainDataList, List<Map<String, Object>> 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<String, Object> existMain = (Map<String, Object>) 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<Map<String, Object>> 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<String, Object> 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<Map<String, Object>> 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<String, Object> 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<Map<String, Object>> 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<String, Object> 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<Map<String, Object>> 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<String, Object> 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<String, String> 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<Map<String, Object>>(单个JSON对象) | ||||
|          */ | ||||
|         public static List<Map<String, Object>> jsonObjectToListMap(JSONObject jsonObject) { | ||||
|             List<Map<String, Object>> resultList = new ArrayList<>(); | ||||
|             if (jsonObject == null || jsonObject.isEmpty()) { | ||||
|                 return resultList; | ||||
|             } | ||||
|             // 指定初始容量,优化性能 | ||||
|             Map<String, Object> dataMap = new HashMap<>(jsonObject.size()); | ||||
|             for (Map.Entry<String, Object> 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(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -129,7 +129,7 @@ public class AfterApproveSyncPLMRule implements IRule<PMOAggVO> { | |||
|                         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); | ||||
|  |  | |||
|  | @ -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<String, Object> goodsMap = MyHelper.transferFields(MaterialVO.getDefaultTableName(), selectFields, MaterialVO.PK_MATERIAL, cmaterialid); | ||||
|         // 项目 | ||||
|         // String cprojectid = pmoItem.getCprojectid(); | ||||
|         // selectFields = ProjectHeadVO.PROJECT_CODE + "," + ProjectHeadVO.PROJECT_NAME; | ||||
|         // Map<String, Object> projectMap = MyHelper.transferFields(ProjectHeadVO.getDefaultTableName(), selectFields, ProjectHeadVO.PK_PROJECT, cprojectid); | ||||
|         String cprojectid = pmoItem.getCprojectid(); | ||||
|         selectFields = ProjectHeadVO.PROJECT_CODE + "," + ProjectHeadVO.PROJECT_NAME; | ||||
|         Map<String, Object> 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) { | ||||
|  |  | |||
|  | @ -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<Map<String, Object>> mainList = (List<Map<String, Object>>) getImsDao().executeQuery(selSql, new MapListProcessor()); | ||||
|             Set<String> pkWrSet = new HashSet<>(); | ||||
|             for (Map<String, Object> mainMap : mainList) { | ||||
|                 String pkWr = mainMap.get("pk_wr").toString(); | ||||
|                 String pkWrSql = "select * from BIPReportDetailTab where pk_wr = '" + pkWr + "'"; | ||||
|                 List<Map<String, Object>> detailList = (List<Map<String, Object>>) getImsDao().executeQuery(pkWrSql, new MapListProcessor()); | ||||
|                 Map<String, Map<String, Object>> detailIdMap = new HashMap<>(); | ||||
|                 for (Map<String, Object> 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<String, Object> 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
		Loading…
	
		Reference in New Issue