diff --git a/modules/i3plus-ext-mes-pcn-apiservice/src/main/java/cn/estsh/i3plus/ext/mes/pcn/apiservice/serviceimpl/step/MesProdCraftRouteCheckNosortStepService.java b/modules/i3plus-ext-mes-pcn-apiservice/src/main/java/cn/estsh/i3plus/ext/mes/pcn/apiservice/serviceimpl/step/MesProdCraftRouteCheckNosortStepService.java index c1f6ee9..9bcbeb9 100644 --- a/modules/i3plus-ext-mes-pcn-apiservice/src/main/java/cn/estsh/i3plus/ext/mes/pcn/apiservice/serviceimpl/step/MesProdCraftRouteCheckNosortStepService.java +++ b/modules/i3plus-ext-mes-pcn-apiservice/src/main/java/cn/estsh/i3plus/ext/mes/pcn/apiservice/serviceimpl/step/MesProdCraftRouteCheckNosortStepService.java @@ -179,9 +179,11 @@ public class MesProdCraftRouteCheckNosortStepService extends MesProdCraftRouteCh return stepResult.isCompleted(false).msg(String.format("%s%s[%s]产品工艺路线[%s]相同工艺对应工序最多经过1个,上道工艺[%s]当前工位工艺[%s]", message, suffix, productionPsInContext.getProductSn(), craftRouteDetailList.get(0).getCraftRouteCode(), productionPsInContext.getCraftCode(), productionProcessContext.getCraftCode())).isCompleted(); + //判断条码是否在当前已完成的工序工位上重做 + Boolean isPsProcessRepeat = null != optionalPs && optionalPs.isPresent() && reqBean.getProcessCode().equals(productionPsInContext.getProcessCode()); List productionRecordList = null; //验证已完成工序最大重复次数: 如果当前工位的工序与主条码的当前工序一致的情况下, 根据条码+物料+工序+工艺查询加工记录, 判断加工记录条数 - if (null != optionalPs && optionalPs.isPresent() && reqBean.getProcessCode().equals(productionPsInContext.getProcessCode())) { + if (isPsProcessRepeat) { //根据零件条码查询加工记录信息 productionRecordList = productionRecordService.findProductionRecordList(reqBean.getOrganizeCode(), productionPsInContext.getProductSn()); //条码+物料+工序+工艺搜集加工记录 @@ -207,10 +209,9 @@ public class MesProdCraftRouteCheckNosortStepService extends MesProdCraftRouteCh beforeCellCraftList = beforeCellCraftList.stream().filter(o -> null != o).sorted(Comparator.comparing(MesCraftRouteDetail::getSeq)).collect(Collectors.toList()); //判断上面是否已经查询过数据 - if (!(null != optionalPs && optionalPs.isPresent() && optionalPs.get().getRepeatTimes().compareTo(MesPcnExtConstWords.ONE) > 0 && reqBean.getProcessCode().equals(productionPsInContext.getProcessCode()))) - productionRecordList = productionRecordService.findProductionRecordList(reqBean.getOrganizeCode(), productionPsInContext.getProductSn()); + if (!isPsProcessRepeat) productionRecordList = productionRecordService.findProductionRecordList(reqBean.getOrganizeCode(), productionPsInContext.getProductSn()); - Map> prMapByCraft = CollectionUtils.isEmpty(productionRecordList) ? null : productionRecordList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesProductionRecord::getCraftCode)); + Map> prMapByCraft = productionRecordMap2Craft(productionRecordList); //遍历前道工艺, 根据工艺查询加工记录是否存在, 并验证是否存在捆绑工艺 for (int i = 0; i < beforeCellCraftList.size(); i ++) { @@ -224,10 +225,26 @@ public class MesProdCraftRouteCheckNosortStepService extends MesProdCraftRouteCh message, suffix, productionPsInContext.getProductSn(), beforeCellCraftList.get(i).getCraftRouteCode(), beforeCellCraftList.get(i - 1).getCraftCode())).isCompleted(); } + //当主条码存在已做工序 且 与当前工位的工序不一致时, 判断当前工位的工序是否已经存在加工记录 + if (!CollectionUtils.isEmpty(productionRecordList) + && !StringUtils.isEmpty(productionPsInContext.getProcessCode()) + && !reqBean.getProcessCode().equals(productionPsInContext.getProcessCode()) + && isExistProductionRecord(productionRecordMap2Process(productionRecordList), reqBean.getProcessCode())) { + return stepResult.isCompleted(false).msg(String.format("%s%s[%s]已经过当前工序[%s]", message, suffix, productionPsInContext.getProductSn(), reqBean.getProcessCode())).isCompleted(); + } + return true; } + private Map> productionRecordMap2Craft(List productionRecordList) { + return CollectionUtils.isEmpty(productionRecordList) ? null : productionRecordList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesProductionRecord::getCraftCode)); + } + + private Map> productionRecordMap2Process(List productionRecordList) { + return CollectionUtils.isEmpty(productionRecordList) ? null : productionRecordList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesProductionRecord::getProcessCode)); + } + private Boolean isExistProductionRecord(Map> prMapByCraft, String craftCode) { return (CollectionUtils.isEmpty(prMapByCraft) || !prMapByCraft.containsKey(craftCode)) ? false : true; } diff --git a/modules/i3plus-ext-mes-pcn-apiservice/src/main/java/cn/estsh/i3plus/ext/mes/pcn/apiservice/serviceimpl/step/MesProdCraftRouteCheckNosortStepServiceBak.java b/modules/i3plus-ext-mes-pcn-apiservice/src/main/java/cn/estsh/i3plus/ext/mes/pcn/apiservice/serviceimpl/step/MesProdCraftRouteCheckNosortStepServiceBak.java new file mode 100644 index 0000000..91da467 --- /dev/null +++ b/modules/i3plus-ext-mes-pcn-apiservice/src/main/java/cn/estsh/i3plus/ext/mes/pcn/apiservice/serviceimpl/step/MesProdCraftRouteCheckNosortStepServiceBak.java @@ -0,0 +1,235 @@ +package cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.step; + +import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProductionProcessContext; +import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProductionPsInContext; +import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords; +import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil; +import cn.estsh.i3plus.pojo.base.enumutil.MesPcnEnumUtil; +import cn.estsh.i3plus.pojo.mes.bean.MesCraftRouteDetail; +import cn.estsh.i3plus.pojo.mes.bean.MesProdRouteOptParam; +import cn.estsh.i3plus.pojo.mes.bean.MesProductionRecord; +import cn.estsh.i3plus.pojo.mes.bean.MesWorkCenter; +import cn.estsh.i3plus.pojo.mes.model.StationRequestBean; +import cn.estsh.i3plus.pojo.mes.model.StationResultBean; +import cn.estsh.i3plus.pojo.mes.model.StepResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @Description : 前道工艺防错工步 【非排序】 + * @Author : wangjie + **/ +@Slf4j +@Service("mesProdCraftRouteCheckNosortStepServiceBak") +public class MesProdCraftRouteCheckNosortStepServiceBak extends MesProdCraftRouteCheckStepService { + + @Override + public StepResult execute(StationRequestBean reqBean) { + + StationResultBean resultBean = new StationResultBean(); + + StepResult stepResult = StepResult.getSuccessComplete(); + + //获取上下文信息 + MesProductionProcessContext productionProcessContext = productionProcessContextStepService.dispatchCurCellEquipment(reqBean); + + //获取生产过程上下文对象有异常信息 抛出异常 + if (!productionProcessContext.getSuccess()) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), productionProcessContext.getMessage()); + + //存储生产过程上下文对象 + productionProcessContextStepService.dispatchProductionProcessContext(reqBean, productionProcessContext); + + //获取进料主条码数据信息 + List productionPsInContextList = productionDispatchContextStepService.getProductionPsInContext(reqBean); + + if (CollectionUtils.isEmpty(productionPsInContextList)) return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, "当前无主条码信息,无需进行前道工艺防错验证!"); + + //非排序需要验证主条码是否是自制件[工步参数] + Optional> stepParamMap = getStepParams(reqBean); + Boolean needCheckIsPs = (null != stepParamMap && stepParamMap.isPresent() && stepParamMap.get().containsKey(MesPcnExtConstWords.NEED_CHECK_IS_PS)) ? true : false; + + //验证是否存在零件为空的主条码 + if (needCheckIsPs && isExistProductSnNoPart(productionPsInContextList)) { + productionDispatchContextStepService.dispatchProductionPsInContext(reqBean, productionPsInContextList); + return stepNonCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, "当前存在主条码为外协件,前道工艺防错验证失败,主条码必须为自制件!"); + } + + //验证是否存在自制件 + if (!isExistProductSn(productionPsInContextList)) + return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, "当前主条码信息均为外协件,无需进行前道工艺防错验证!"); + + //验证工位是否设置需要前道防错 + if (!isNeedCheckCraft(productionPsInContextList)) + return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, String.format("生产线[%s]工位[%s]未设置前道工艺防错,无需进行前道工艺防错验证!", reqBean.getWorkCenterCode(), reqBean.getWorkCellCode())); + + //验证是否存在工艺强过码, 存在则保存 并返回强过的主条码 + List productSnList2Jump = doHandleCraftJumpCode(reqBean, productionPsInContextList); + if (!CollectionUtils.isEmpty(productSnList2Jump)) + return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog().scanInfo(productSnList2Jump.toString()), stepResult, String.format("主条码%s跳过前道工艺防错验证成功!", productSnList2Jump.toString())); + + Boolean isPart = checkIsPart(productionPsInContextList); + List partNoList = (productionPsInContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getPartNo()) && + o.getCheckCraftResult().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) != 0)).map(o -> isPart ? o.getPartNo() : o.getCutCode()).collect(Collectors.toList())).stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList()); + if (CollectionUtils.isEmpty(partNoList)) return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean, stepResult, "主条码均已通过前道工艺防错验证!"); + + //从上下文中取出生产线对象 + MesWorkCenter workCenter = productionProcessContext.getWorkCenter(); + + //查询工艺路线数据 + Map> craftRouteDataMap = new HashMap<>(); + partNoList.forEach(o -> handleProdCraftData(reqBean, workCenter, o, craftRouteDataMap, isPart)); + + if (CollectionUtils.isEmpty(craftRouteDataMap) || craftRouteDataMap.size() != partNoList.size()) { + //剔除未验证的进料主条码后保存数据 + productionDispatchContextStepService.dispatchProductionPsInContext(reqBean, productionPsInContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getForeignKey()))).collect(Collectors.toList())); + return stepNonCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, String.format("零件编码%s未匹配到产品工艺路线!", + CollectionUtils.isEmpty(craftRouteDataMap) ? partNoList.toString() : partNoList.stream().filter(o -> (!StringUtils.isEmpty(o) && !craftRouteDataMap.containsKey(o))).collect(Collectors.toList()).toString())); + } + + //前道工艺防错验证处理 + doHandleProdCraftRouteCheck(reqBean, resultBean, stepResult, productionProcessContext, productionPsInContextList, craftRouteDataMap, isPart); + + return stepResult; + + } + + //验证是否存在零件为空的主条码 + private Boolean isExistProductSnNoPart(List productionPsInContextList) { + + Boolean result = false; + + for (MesProductionPsInContext productionPsInContext : productionPsInContextList) { + + if (null == productionPsInContext || !StringUtils.isEmpty(productionPsInContext.getPartNo()) || productionPsInContext.getIsFinishCode().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) == 0) continue; + + productionPsInContext.checkCraftResult(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()); + + result = true; + } + + return result; + } + + //验证是否存在自制件 + private Boolean isExistProductSn(List productionPsInContextList) { + Optional optional = productionPsInContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getPartNo()))).findFirst(); + return (null == optional || !optional.isPresent()) ? false : true; + } + + private Boolean checkIsPart(List productionPsInContextList) { + Optional optional = CollectionUtils.isEmpty(productionPsInContextList) ? null : productionPsInContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getCutCode()))).findFirst(); + return (null != optional && optional.isPresent()) ? false : true; + } + + //前道工艺防错验证处理 + private void doHandleProdCraftRouteCheck(StationRequestBean reqBean, StationResultBean resultBean, StepResult stepResult, MesProductionProcessContext productionProcessContext, + List productionPsInContextList, Map> craftRouteDataMap, Boolean isPart) { + + String suffix = isPart ? "主条码" : "裁片工单"; + + List productSnList = new ArrayList<>(); + + for (MesProductionPsInContext productionPsInContext : productionPsInContextList) { + + if (null == productionPsInContext) continue; + if (StringUtils.isEmpty(productionPsInContext.getPartNo())) continue; + if (productionPsInContext.getCheckCraftResult().compareTo(MesPcnExtConstWords.ZERO) != 0) continue; + + //前道工艺防错验证 + Boolean result = doProdCraftRouteCheckNosort(reqBean, stepResult, productionProcessContext, productionPsInContext, craftRouteDataMap.get(productionPsInContext.getPartNo()), suffix); + + productionPsInContext.checkCraftResult(!result ? CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue() : CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()); + + productSnList.add(productionPsInContext.getProductSn()); + + //裁片工单只需要验证一次即可 + if (!isPart) break; + + } + + //裁片工单存在多腔时, 上面只验证了第一腔, 需要同时标记其他腔的验证状态 + if (!isPart && productionPsInContextList.size() > 1) productionPsInContextList.stream().forEach(o -> o.checkCraftResult(stepResult.isCompleted() ? CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue() : CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue())); + + //保存进料主条码数据 + productionDispatchContextStepService.dispatchProductionPsInContext(reqBean, productionPsInContextList); + + if (stepResult.isCompleted()) this.sendMessage(reqBean, resultBean.writeDbLog().scanInfo(productSnList.toString()), String.format("%s%s前道工艺防错验证成功!", suffix, productSnList), MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.TEXT); + else this.sendMessage(reqBean, resultBean.writeDbLog().scanInfo(productSnList.toString()), stepResult.getMsg(), MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT); + + } + + //前道工艺防错验证 【非排序】 + private Boolean doProdCraftRouteCheckNosort(StationRequestBean reqBean, StepResult stepResult, MesProductionProcessContext productionProcessContext, MesProductionPsInContext productionPsInContext, List craftRouteDetailList, String suffix) { + + String message = StringUtils.isEmpty(stepResult.getMsg()) ? MesPcnExtConstWords.EMPTY : stepResult.getMsg() + MesPcnExtConstWords.SEMICOLON; + + //判断主条码的当前工艺是否包含在产品工艺路线中 + Optional optionalPs = StringUtils.isEmpty(productionPsInContext.getCraftCode()) ? null : craftRouteDetailList.stream().filter(o -> (null != o && o.getCraftCode().equals(productionPsInContext.getCraftCode()))).findFirst(); + if (!StringUtils.isEmpty(productionPsInContext.getCraftCode()) && (null == optionalPs || !optionalPs.isPresent())) + return stepResult.isCompleted(false).msg(String.format("%s%s[%s]对应的工艺代码[%s]不匹配零件[%s]对应的产品工艺路线[%s]", + message, suffix, productionPsInContext.getProductSn(), productionPsInContext.getCraftCode(), productionPsInContext.getPartNo(), craftRouteDetailList.get(0).getCraftRouteCode())).isCompleted(); + + //验证工艺对应工序最多经过1个: 当前主条码的工艺字段有值, 对应的工艺路线明细信息设置了【true】, 当前工位的工艺与主条码的当前工艺相同, 当前工位的工序与主条码的当前工序不相同 + if (null != optionalPs && optionalPs.isPresent() && optionalPs.get().getAtMostProcess().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) == 0 && productionProcessContext.getCraftCode().equals(productionPsInContext.getCraftCode()) && !reqBean.getProcessCode().equals(productionPsInContext.getProcessCode())) + return stepResult.isCompleted(false).msg(String.format("%s%s[%s]产品工艺路线[%s]相同工艺对应工序最多经过1个,上道工艺[%s]当前工位工艺[%s]", + message, suffix, productionPsInContext.getProductSn(), craftRouteDetailList.get(0).getCraftRouteCode(), productionPsInContext.getCraftCode(), productionProcessContext.getCraftCode())).isCompleted(); + + List productionRecordList = null; + //验证已完成工序最大重复次数: 如果当前工位的工序与主条码的当前工序一致的情况下, 根据条码+物料+工序+工艺查询加工记录, 判断加工记录条数 + if (null != optionalPs && optionalPs.isPresent() && reqBean.getProcessCode().equals(productionPsInContext.getProcessCode())) { + //根据零件条码查询加工记录信息 + productionRecordList = productionRecordService.findProductionRecordList(reqBean.getOrganizeCode(), productionPsInContext.getProductSn()); + //条码+物料+工序+工艺搜集加工记录 + List filterList = CollectionUtils.isEmpty(productionRecordList) ? null : + productionRecordList.stream().filter(o -> (null != o && o.getPartNo().equals(productionPsInContext.getPartNo()) && o.getProcessCode().equals(reqBean.getProcessCode()) && o.getCraftCode().equals(productionProcessContext.getCraftCode()))).collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(filterList) && filterList.size() >= + ((!StringUtils.isEmpty(optionalPs.get().getRepeatTimes()) && optionalPs.get().getRepeatTimes().compareTo(MesPcnExtConstWords.ZERO) > 0) ? optionalPs.get().getRepeatTimes() : MesPcnExtConstWords.ONE)) + return stepResult.isCompleted(false).msg(String.format("%s%s[%s]当前工序[%s]产品工艺路线[%s]已完成工序最大重复次数[%s]", + message, suffix, productionPsInContext.getProductSn(), reqBean.getProcessCode(), craftRouteDetailList.get(0).getCraftRouteCode(), optionalPs.get().getRepeatTimes())).isCompleted(); + } + + //判断当前工位的工序对应的工艺是否包含在产品工艺路线中 + Optional optionalCell = craftRouteDetailList.stream().filter(o -> (null != o && o.getCraftCode().equals(productionProcessContext.getCraftCode()))).findFirst(); + //根据当前工位对应的工艺 获取 所有前道工艺, 如果当前工位的工序对应工艺不在工艺路线明细内, 则默认所有明细均为所有前道工艺, 否则搜集当前工位工序对应工艺前面的所有前道工艺 + List beforeCellCraftList; + if (null == optionalCell || !optionalCell.isPresent()) beforeCellCraftList = craftRouteDetailList; + else beforeCellCraftList = craftRouteDetailList.stream().filter(o -> (null != o && o.getSeq().compareTo(optionalCell.get().getSeq()) < 0)).collect(Collectors.toList()); + + //前道工艺不存在即当前为首道工艺 + if (CollectionUtils.isEmpty(beforeCellCraftList)) return true; + + //前道工艺正序 + beforeCellCraftList = beforeCellCraftList.stream().filter(o -> null != o).sorted(Comparator.comparing(MesCraftRouteDetail::getSeq)).collect(Collectors.toList()); + + //判断上面是否已经查询过数据 + if (!(null != optionalPs && optionalPs.isPresent() && optionalPs.get().getRepeatTimes().compareTo(MesPcnExtConstWords.ONE) > 0 && reqBean.getProcessCode().equals(productionPsInContext.getProcessCode()))) + productionRecordList = productionRecordService.findProductionRecordList(reqBean.getOrganizeCode(), productionPsInContext.getProductSn()); + + Map> prMapByCraft = CollectionUtils.isEmpty(productionRecordList) ? null : productionRecordList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesProductionRecord::getCraftCode)); + + //遍历前道工艺, 根据工艺查询加工记录是否存在, 并验证是否存在捆绑工艺 + for (int i = 0; i < beforeCellCraftList.size(); i ++) { + if (null == beforeCellCraftList.get(i)) continue; + Boolean isExist = isExistProductionRecord(prMapByCraft, beforeCellCraftList.get(i).getCraftCode()); + if (beforeCellCraftList.get(i).getIsChoose().compareTo(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()) == 0 && !isExist) + return stepResult.isCompleted(false).msg(String.format("%s%s[%s]未经过必过工艺[%s]", message, suffix, productionPsInContext.getProductSn(), beforeCellCraftList.get(i).getCraftCode())).isCompleted(); + + if (i != 0 && beforeCellCraftList.get(i - 1).getIsBindNextCraft().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) == 0 && isExistProductionRecord(prMapByCraft, beforeCellCraftList.get(i - 1).getCraftCode()) && !isExist) + return stepResult.isCompleted(false).msg(String.format("%s%s[%s]产品工艺路线[%s]工艺[%s]捆绑后道工艺", + message, suffix, productionPsInContext.getProductSn(), beforeCellCraftList.get(i).getCraftRouteCode(), beforeCellCraftList.get(i - 1).getCraftCode())).isCompleted(); + } + + return true; + + } + + private Boolean isExistProductionRecord(Map> prMapByCraft, String craftCode) { + return (CollectionUtils.isEmpty(prMapByCraft) || !prMapByCraft.containsKey(craftCode)) ? false : true; + } + +}