Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
a4549be60b
|
|
@ -1,6 +1,7 @@
|
||||||
package nccloud.api.impl.ic.onhand;
|
package nccloud.api.impl.ic.onhand;
|
||||||
|
|
||||||
import nc.bs.framework.common.NCLocator;
|
import nc.bs.framework.common.NCLocator;
|
||||||
|
import nc.bs.logging.Logger;
|
||||||
import nc.itf.ic.onhand.OnhandResService;
|
import nc.itf.ic.onhand.OnhandResService;
|
||||||
import nc.vo.ic.onhand.entity.OnhandDimVO;
|
import nc.vo.ic.onhand.entity.OnhandDimVO;
|
||||||
import nc.vo.ic.onhand.entity.OnhandVO;
|
import nc.vo.ic.onhand.entity.OnhandVO;
|
||||||
|
|
@ -14,6 +15,7 @@ import nccloud.openapi.scmpub.pub.TransferCodeToPKTool;
|
||||||
import nccloud.openapi.scmpub.pubitf.IJsonParamMapping;
|
import nccloud.openapi.scmpub.pubitf.IJsonParamMapping;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
@ -59,7 +61,7 @@ public class APIOnhandQueryIpml implements IAPIOnhandQuery {
|
||||||
public OnhandVO[] queryOnhandVOByDimsNoTrans(List<Map<String, Object>> paramMapList) throws BusinessException {
|
public OnhandVO[] queryOnhandVOByDimsNoTrans(List<Map<String, Object>> paramMapList) throws BusinessException {
|
||||||
|
|
||||||
|
|
||||||
//±<EFBFBD><EFBFBD>ה<EFBFBD>מ¼ל²י
|
// 必输项检查
|
||||||
try {
|
try {
|
||||||
List<OnhandDimVO> onhandDimVOS = new ArrayList<>();
|
List<OnhandDimVO> onhandDimVOS = new ArrayList<>();
|
||||||
for (Map<String, Object> paramMap : paramMapList) {
|
for (Map<String, Object> paramMap : paramMapList) {
|
||||||
|
|
@ -79,6 +81,7 @@ public class APIOnhandQueryIpml implements IAPIOnhandQuery {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OnhandVO[] queryOnhandVOByDims(List<Map<String, Object>> paramMapList) throws Exception {
|
public OnhandVO[] queryOnhandVOByDims(List<Map<String, Object>> paramMapList) throws Exception {
|
||||||
// ±ØÊäÏî¼ì²é
|
// ±ØÊäÏî¼ì²é
|
||||||
|
|
@ -120,6 +123,52 @@ public class APIOnhandQueryIpml implements IAPIOnhandQuery {
|
||||||
return onhandVOs;
|
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) {
|
private void requiredFieldCheck(String[] requiredField, Map<String, Object> paramMap) {
|
||||||
|
|
|
||||||
|
|
@ -46,4 +46,13 @@ public interface IAPIOnhandQuery {
|
||||||
* @throws Exception 当查询操作失败时抛出的异常
|
* @throws Exception 当查询操作失败时抛出的异常
|
||||||
*/
|
*/
|
||||||
OnhandVO[] queryOnhandVOByCondition(Map<String, Object> paramMap) 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 {
|
try {
|
||||||
OnhandVO[] onhandVOs = NCLocator.getInstance().lookup(IAPIOnhandQuery.class)
|
OnhandVO[] onhandVOs = NCLocator.getInstance().lookup(IAPIOnhandQuery.class)
|
||||||
.queryOnhandVOByDims(paramMap);
|
.onhandQueryBatch(paramMap);
|
||||||
// 对数据进行整合组装,返回物料+仓库+数量
|
// 对数据进行整合组装,返回物料+仓库+数量
|
||||||
if (null != onhandVOs && onhandVOs.length > 0) {
|
if (null != onhandVOs && onhandVOs.length > 0) {
|
||||||
// 收集所有物料和仓库ID
|
// 收集所有物料和仓库ID
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ public class PmoToPlmAction implements ICommonAction {
|
||||||
request.put("asuser34", projectMap.get("project_name"));
|
request.put("asuser34", projectMap.get("project_name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
request.put("asuser28", itemVO.getVfirstcode());
|
request.put("asuser28", itemVO.getVsalebillcode());
|
||||||
request.put("ab012", itemVO.getNastnum());
|
request.put("ab012", itemVO.getNastnum());
|
||||||
|
|
||||||
request.put("gsdm", GSDM);
|
request.put("gsdm", GSDM);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package nc.bs.mmpac.pickm.bp;
|
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.AfterApproveRuleHighpressureMes;
|
||||||
import nc.bs.mmpac.pickm.bp.rule.AfterApproveRuleSyncRZWMS;
|
import nc.bs.mmpac.pickm.bp.rule.AfterApproveRuleSyncRZWMS;
|
||||||
import nc.bs.mmpac.pickm.plugin.PickmPluginPoint;
|
import nc.bs.mmpac.pickm.plugin.PickmPluginPoint;
|
||||||
|
|
@ -28,6 +29,8 @@ public class PickmApproveBP {
|
||||||
processer.addAfterRule(pickmstatusFilterRule);
|
processer.addAfterRule(pickmstatusFilterRule);
|
||||||
//备料计划审批后推送高压MES
|
//备料计划审批后推送高压MES
|
||||||
processer.addAfterRule(new AfterApproveRuleHighpressureMes());
|
processer.addAfterRule(new AfterApproveRuleHighpressureMes());
|
||||||
|
//备料计划审批后推送高压IMS
|
||||||
|
processer.addAfterRule(new AfterApproveRuleHighpressureIms());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addBeforeRule(CompareAroundProcesser<AggPickmVO> processer) {
|
private void addBeforeRule(CompareAroundProcesser<AggPickmVO> processer) {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package nc.bs.mmpac.pickm.bp;
|
||||||
|
|
||||||
import java.util.Map;
|
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.bp.rule.AfterupdateSyncEpicMesRule;
|
||||||
import nc.bs.mmpac.pickm.plugin.PickmPluginPoint;
|
import nc.bs.mmpac.pickm.plugin.PickmPluginPoint;
|
||||||
import nc.bs.mmpac.pickm.rule.PickmCheckItemMaterialPermissionRule;
|
import nc.bs.mmpac.pickm.rule.PickmCheckItemMaterialPermissionRule;
|
||||||
|
|
@ -226,6 +227,9 @@ public class PickmUpdateForMOBP {
|
||||||
|
|
||||||
|
|
||||||
aroundProcesser.addAfterRule(new AfterupdateSyncEpicMesRule());
|
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("asuser34", projectMap.get("project_name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
request.put("asuser28", itemVO.getVfirstcode());
|
request.put("asuser28", itemVO.getVsalebillcode());
|
||||||
request.put("ab012", itemVO.getNastnum());
|
request.put("ab012", itemVO.getNastnum());
|
||||||
|
|
||||||
request.put("gsdm", GSDM);
|
request.put("gsdm", GSDM);
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import nc.bs.uapbd.util.MyHelper;
|
||||||
import nc.bs.uapbd.util.ThirdPartyPostRequestUtil;
|
import nc.bs.uapbd.util.ThirdPartyPostRequestUtil;
|
||||||
import nc.jdbc.framework.processor.MapListProcessor;
|
import nc.jdbc.framework.processor.MapListProcessor;
|
||||||
import nc.jdbc.framework.processor.MapProcessor;
|
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.bom.bom0202.entity.BomVO;
|
||||||
import nc.vo.bd.material.MaterialVO;
|
import nc.vo.bd.material.MaterialVO;
|
||||||
import nc.vo.mmpac.pmo.pac0002.entity.PMOAggVO;
|
import nc.vo.mmpac.pmo.pac0002.entity.PMOAggVO;
|
||||||
|
|
@ -186,9 +187,9 @@ public class HttpPmoEpicMesUtil {
|
||||||
selectFields = MaterialVO.CODE + "," + MaterialVO.NAME;
|
selectFields = MaterialVO.CODE + "," + MaterialVO.NAME;
|
||||||
Map<String, Object> goodsMap = MyHelper.transferFields(MaterialVO.getDefaultTableName(), selectFields, MaterialVO.PK_MATERIAL, cmaterialid);
|
Map<String, Object> goodsMap = MyHelper.transferFields(MaterialVO.getDefaultTableName(), selectFields, MaterialVO.PK_MATERIAL, cmaterialid);
|
||||||
// 项目
|
// 项目
|
||||||
// String cprojectid = pmoItem.getCprojectid();
|
String cprojectid = pmoItem.getCprojectid();
|
||||||
// selectFields = ProjectHeadVO.PROJECT_CODE + "," + ProjectHeadVO.PROJECT_NAME;
|
selectFields = ProjectHeadVO.PROJECT_CODE + "," + ProjectHeadVO.PROJECT_NAME;
|
||||||
// Map<String, Object> projectMap = MyHelper.transferFields(ProjectHeadVO.getDefaultTableName(), selectFields, ProjectHeadVO.PK_PROJECT, cprojectid);
|
Map<String, Object> projectMap = MyHelper.transferFields(ProjectHeadVO.getDefaultTableName(), selectFields, ProjectHeadVO.PK_PROJECT, cprojectid);
|
||||||
// 生产部门 cdeptid
|
// 生产部门 cdeptid
|
||||||
String cdeptid = pmoItem.getCdeptid();
|
String cdeptid = pmoItem.getCdeptid();
|
||||||
String deptCode = MyHelper.transferField(DeptVO.getDefaultTableName(), DeptVO.CODE, DeptVO.PK_DEPT, cdeptid);
|
String deptCode = MyHelper.transferField(DeptVO.getDefaultTableName(), DeptVO.CODE, DeptVO.PK_DEPT, cdeptid);
|
||||||
|
|
@ -202,10 +203,10 @@ public class HttpPmoEpicMesUtil {
|
||||||
// 根据自定义档案中的映射关系,部门编码转换为MES中的编码
|
// 根据自定义档案中的映射关系,部门编码转换为MES中的编码
|
||||||
orderParam.put("siteCode", deptParams.getOrDefault(deptCode, ""));// 工厂编码
|
orderParam.put("siteCode", deptParams.getOrDefault(deptCode, ""));// 工厂编码
|
||||||
orderParam.put("contractNo", pmoItem.getVfirstcode());// 合同号-取ERP的源头单据号-销售订单号
|
orderParam.put("contractNo", pmoItem.getVfirstcode());// 合同号-取ERP的源头单据号-销售订单号
|
||||||
/*if (projectMap != null) {
|
if (projectMap != null) {
|
||||||
orderParam.put("contractNo", projectMap.get(ProjectHeadVO.PROJECT_CODE));// şĎÍŹşĹ
|
// orderParam.put("contractNo", projectMap.get(ProjectHeadVO.PROJECT_CODE));// şĎÍŹşĹ
|
||||||
orderParam.put("contractName", projectMap.get(ProjectHeadVO.PROJECT_NAME)); // 合同名称
|
orderParam.put("contractName", projectMap.get(ProjectHeadVO.PROJECT_NAME)); // 合同名称
|
||||||
}*/
|
}
|
||||||
orderParam.put("workOrderCode", headVo.getVbillcode());// 工单号
|
orderParam.put("workOrderCode", headVo.getVbillcode());// 工单号
|
||||||
orderParam.put("qty", String.valueOf(pmoItem.getNastnum())); // 计划数量,字符串类型
|
orderParam.put("qty", String.valueOf(pmoItem.getNastnum())); // 计划数量,字符串类型
|
||||||
if (goodsMap != null) {
|
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