From f3f739e8e281fd59d4d5df3ab367533dd01eda5b Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 11 Mar 2025 13:31:04 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DBug45555=EF=BC=8C=E9=9B=B6?= =?UTF-8?q?=E4=BB=B6=E5=8F=91=E8=BF=90=E7=BB=84,=E6=89=AB=E6=8F=8F?= =?UTF-8?q?=E7=A1=AE=E8=AE=A4=E9=9B=B6=E4=BB=B6=E6=96=B9=E5=BC=8F=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E2=80=9C=E6=89=AB=E6=8F=8F=E7=9B=AE=E8=A7=86=E5=8D=95?= =?UTF-8?q?=E2=80=9D=E6=9E=9A=E4=B8=BE=EF=BC=8C=E5=AE=9E=E7=8E=B0=E6=89=AB?= =?UTF-8?q?=E6=8F=8F=E7=9B=AE=E8=A7=86=E5=8D=95=E5=8F=91=E8=BF=90=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../busi/MesSortShippingCheckService.java | 18 +- .../mesShippingScanOrderStrategyServiceImpl.java | 282 +++++++++++++++++++++ 2 files changed, 298 insertions(+), 2 deletions(-) create mode 100644 modules/i3plus-ext-mes-pcn-apiservice/src/main/java/cn/estsh/i3plus/ext/mes/pcn/apiservice/serviceimpl/busi/shippingscan/strategy/mesShippingScanOrderStrategyServiceImpl.java diff --git a/modules/i3plus-ext-mes-pcn-apiservice/src/main/java/cn/estsh/i3plus/ext/mes/pcn/apiservice/serviceimpl/busi/MesSortShippingCheckService.java b/modules/i3plus-ext-mes-pcn-apiservice/src/main/java/cn/estsh/i3plus/ext/mes/pcn/apiservice/serviceimpl/busi/MesSortShippingCheckService.java index e009f62..6282b35 100644 --- a/modules/i3plus-ext-mes-pcn-apiservice/src/main/java/cn/estsh/i3plus/ext/mes/pcn/apiservice/serviceimpl/busi/MesSortShippingCheckService.java +++ b/modules/i3plus-ext-mes-pcn-apiservice/src/main/java/cn/estsh/i3plus/ext/mes/pcn/apiservice/serviceimpl/busi/MesSortShippingCheckService.java @@ -560,6 +560,7 @@ public class MesSortShippingCheckService implements IMesSortShippingCheckService //查询条码信息 Map> produceSnByCustSnMap = getProduceSnByCustSnMap(orderManagement.getIsEnableMemory(), organizeCode, detailList.stream().map(MesShippingOrderManagementDetail::getBarcode).filter(barCode -> !StringUtil.isEmptyAndNull(barCode)).collect(Collectors.toList())); + final String confirmPartType = getConfirmPartType(orderManagement); List produceSnList = new ArrayList<>(); List workOrderNoList = new ArrayList<>(); List mesShippingSnUniqueList = new ArrayList<>(); @@ -590,8 +591,10 @@ public class MesSortShippingCheckService implements IMesSortShippingCheckService mesEmergencyLocationService.doShippingStockOutOnline(organizeCode, detail.getVisualOrderNo(), userInfo, true); // 保存到发运队列,后续发运单的条码会拼接,而保存到发运队列中的为拼接前的数据,因此要在拼接前调用。 saveShippingQueue(orderManagement, detail, userInfo); - //条码格式(扫描目视单,扫描条码) - detail.setBarcode(new StringJoiner(MesPcnExtConstWords.COMMA).add(detail.getVisualOrderNo()).add(detail.getBarcode()).toString()); + if (!Objects.equals(confirmPartType, String.valueOf(MesExtEnumUtil.SHIPPING_GROUP_CONFIRM_PART_TYPE.SHIPPING_GROUP_CONFIRM_PART_TYPE_40.getValue()))) { + //条码格式(扫描目视单,扫描条码) + detail.setBarcode(new StringJoiner(MesPcnExtConstWords.COMMA).add(detail.getVisualOrderNo()).add(detail.getBarcode()).toString()); + } } } //客供品移库 @@ -808,4 +811,15 @@ public class MesSortShippingCheckService implements IMesSortShippingCheckService ConvertBean.serviceModelInitialize(mesShippingQueue, userInfo); shippingQueueRDao.insert(mesShippingQueue); } + + private String getConfirmPartType(MesShippingOrderManagement orderManagement) { + if (StringUtils.isEmpty(orderManagement.getShippingGroupCode())) { + return ""; + } + MesPartShippingGroup shippingGroup = mesPartShippingGroupService.getMesPartShippingGroup(orderManagement.getOrganizeCode(), orderManagement.getShippingGroupCode()); + if (shippingGroup == null) { + return ""; + } + return shippingGroup.getConfirmPartType(); + } } diff --git a/modules/i3plus-ext-mes-pcn-apiservice/src/main/java/cn/estsh/i3plus/ext/mes/pcn/apiservice/serviceimpl/busi/shippingscan/strategy/mesShippingScanOrderStrategyServiceImpl.java b/modules/i3plus-ext-mes-pcn-apiservice/src/main/java/cn/estsh/i3plus/ext/mes/pcn/apiservice/serviceimpl/busi/shippingscan/strategy/mesShippingScanOrderStrategyServiceImpl.java new file mode 100644 index 0000000..d1d12de --- /dev/null +++ b/modules/i3plus-ext-mes-pcn-apiservice/src/main/java/cn/estsh/i3plus/ext/mes/pcn/apiservice/serviceimpl/busi/shippingscan/strategy/mesShippingScanOrderStrategyServiceImpl.java @@ -0,0 +1,282 @@ +package cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.busi.shippingscan.strategy; + +import cn.estsh.i3plus.ext.mes.pcn.api.busi.*; +import cn.estsh.i3plus.ext.mes.pcn.apiservice.aspect.MonitorLog; +import cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.busi.shippingscan.IMesShippingScanStrategyService; +import cn.estsh.i3plus.ext.mes.pcn.apiservice.util.MesPcnException; +import cn.estsh.i3plus.ext.mes.pcn.pojo.constant.MesCommonConstant; +import cn.estsh.i3plus.ext.mes.pcn.pojo.model.MesSortShippingCheckModel; +import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords; +import cn.estsh.i3plus.platform.common.convert.ConvertBean; +import cn.estsh.i3plus.platform.common.tool.TimeTool; +import cn.estsh.i3plus.pojo.base.bean.DdlPackBean; +import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil; +import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack; +import cn.estsh.i3plus.pojo.base.util.StringUtil; +import cn.estsh.i3plus.pojo.mes.bean.*; +import cn.estsh.i3plus.pojo.mes.bean.shipping.MesShippingOrderManagement; +import cn.estsh.i3plus.pojo.mes.bean.shipping.MesShippingOrderManagementDetail; +import cn.estsh.i3plus.pojo.mes.repository.MesCustomerPartRepository; +import cn.estsh.i3plus.pojo.mes.repository.MesProduceSnRepository; +import cn.estsh.i3plus.pojo.mes.repository.MesShippingOrderManagementDetailRepository; +import cn.estsh.i3plus.pojo.mes.repository.MesShippingOrderManagementRepository; +import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil; +import cn.estsh.impp.framework.boot.exception.ImppBusiException; +import cn.estsh.impp.framework.boot.util.SpringContextsUtil; +import groovy.util.logging.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * @Description : 扫描目视单校验策略 + * @Reference : + * @Author : jason.niu + * @CreateDate 2025/3/11 10:54 + * @Modify: + **/ +@Service +@Slf4j +public class mesShippingScanOrderStrategyServiceImpl implements IMesShippingScanStrategyService { + @Autowired + private MesShippingOrderManagementRepository shippingOrderManagementRepository; + @Autowired + private MesShippingOrderManagementDetailRepository shippingOrderManagementDetailRepository; + @Autowired + private MesProduceSnRepository produceSnRepository; + + @Autowired + private IMesProduceSnExtService produceSnExtService; + + @Autowired + private MesCustomerPartRepository mesCustomerPartRepository; + + @Autowired + private IMesConfigService mesConfigService; + + @Autowired + private IMesPartShippingGroupService mesPartShippingGroupService; + + @Autowired + private IMesShippingSnUniqueService mesShippingSnUniqueService; + + @Autowired + private IMesWorkOrderService mesWorkOrderService; + + @Override + public MesSortShippingCheckModel doScan(MesSortShippingCheckModel model, MesShippingOrderManagement orderManagement, MesPartShippingGroup shippingGroup) { + //校验条码 + MesProduceSn produceSn = checkSn(model); + MesWorkOrder workOrder = mesWorkOrderService.getWorkOrderNoByCustSn(model.getOrganizeCode(), model.getSn()); + boolean bMatchWorkOrder = false; + for (MesShippingOrderManagementDetail detail : model.getDetailList()) { + if (workOrder != null && Objects.equals(workOrder.getCustPartNo(), detail.getCustPartNo())) { + bMatchWorkOrder = true; + break; + } + } + if (!bMatchWorkOrder) { + throw new ImppBusiException(String.format("发运单明细对应的客户零件号与此客户条码【%s】工单中的客户零件号不匹配,请检查数据!", model.getSn())); + } + boolean scanFlg = false; + for (MesShippingOrderManagementDetail detail : model.getDetailList()) { + if (detail.getPartNo().equals(produceSn.getPartNo()) && StringUtils.isEmpty(detail.getBarcode()) && !Objects.equals(detail.getIsScanFlg(), MesCommonConstant.TRUE_INTEGER)) { + //校验发运明细 + checkShippingDetails(model, orderManagement, shippingGroup, produceSn, detail); + scanFlg = true; + //明细更新 + updateOrderManagementDetails(produceSn, orderManagement, detail, workOrder, model.getUserInfo()); + break; + } + } + if (!scanFlg) { + throw new ImppBusiException(String.format("【%s】此条码对应的【%s】物料号与发运单中物料号不匹配,请检查数据!", model.getSn(), produceSn.getPartNo())); + } + model.setMsg(String.format("条码【%s】扫描完成,请扫描下一个条码", model.getSn())); + return model; + } + + private void checkShippingDetails(MesSortShippingCheckModel model, MesShippingOrderManagement orderManagement, MesPartShippingGroup shippingGroup, MesProduceSn produceSn, MesShippingOrderManagementDetail detail) { + + + //校验发运单明细顺序 + if (!Objects.isNull(shippingGroup) && !StringUtils.isEmpty(shippingGroup.getIsEnableShippingFailSafe()) && CommonEnumUtil.VALID == shippingGroup.getIsEnableShippingFailSafe()) { + //45550 PDA-MES-PDA发运扫描排序方式修改 + List shippingBusiSoftCfgList = mesConfigService.getConfigList(orderManagement.getOrganizeCode(), + MesCommonConstant.SHIPPING_BUSI_SOFT_CFG, shippingGroup.getShippingGroupCode(), null); + if (CollectionUtils.isEmpty(shippingBusiSoftCfgList)) { + Optional first = model.getDetailList().stream().filter(k -> k.getCustInfoSeq().compareTo(detail.getCustInfoSeq()) < 0 && !Objects.equals(k.getIsScanFlg(), MesCommonConstant.TRUE_INTEGER)).findFirst(); + if (first.isPresent()) { + throw new ImppBusiException(String.format("发运单【%s】启用明细顺序防错,序号【%s】前还有未扫描的发运单明细,请检查数据!", orderManagement.getShippingCode(), detail.getCustInfoSeq())); + } + }else { + MesConfig mesConfig = shippingBusiSoftCfgList.get(0); + if (!Objects.isNull(mesConfig) && + !StringUtils.isEmpty(mesConfig.getCfgValue()) && + "logic_seq".equals(mesConfig.getCfgValue())) { + Optional first = model.getDetailList().stream().filter(k -> k.getLogicSeq().compareTo(detail.getLogicSeq()) < 0 && !Objects.equals(k.getIsScanFlg(), MesCommonConstant.TRUE_INTEGER)).findFirst(); + if (first.isPresent()) { + throw new ImppBusiException(String.format("发运单【%s】启用明细顺序防错,序号【%s】前还有未扫描的发运单明细,请检查数据!", orderManagement.getShippingCode(), detail.getLogicSeq())); + } + }else { + Optional first = model.getDetailList().stream().filter(k -> k.getCustInfoSeq().compareTo(detail.getCustInfoSeq()) < 0 && !Objects.equals(k.getIsScanFlg(), MesCommonConstant.TRUE_INTEGER)).findFirst(); + if (first.isPresent()) { + throw new ImppBusiException(String.format("发运单【%s】启用明细顺序防错,序号【%s】前还有未扫描的发运单明细,请检查数据!", orderManagement.getShippingCode(), detail.getCustInfoSeq())); + } + } + } + } + //判断是否需要排序校验 默认排序则需要校验 + if (!StringUtils.isEmpty(orderManagement.getScanSeqWay()) && !Objects.isNull(MesExtEnumUtil.SHIPPING_GROUP_SCAN_CONFIRM_SEQ_MODE.valueOfDescription(orderManagement.getScanSeqWay()))) { + //按照页面显示顺序校验 + Optional nextShippingDetail = model.getDetailList().stream().filter(k -> StringUtils.isEmpty(k.getBarcode()) && !Objects.equals(k.getIsScanFlg(), MesCommonConstant.TRUE_INTEGER)).findFirst(); + if (nextShippingDetail.isPresent() && !StringUtils.isEmpty(nextShippingDetail.get().getPartTypeCode()) && !nextShippingDetail.get().getPartNo().equals(produceSn.getPartNo())) { + throw new ImppBusiException(String.format("【%s】此条码扫描顺序错误,请检查数据!", model.getSn())); + } + } + + //校验客户零件信息是否存在 (默认需要验证, 值可能是[空/0/20]) + if (StringUtils.isEmpty(shippingGroup.getScanMethodJudgment()) || !shippingGroup.getScanMethodJudgment().equals(MesExtEnumUtil.SHIPPING_GROUP_SCAN_METHOD_JUDGMENT.PART_NO.getValueStr())) { + DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode()); + DdlPreparedPack.getStringEqualPack(detail.getPartNo(), "erpPartNo", packBean); + DdlPreparedPack.getStringEqualPack(detail.getCustPartNo(), "custPartNo", packBean); + if (!mesCustomerPartRepository.isExitByHql(packBean)) { + throw new ImppBusiException(String.format("零件号【%s】客户零件号【%s】关系不存在,请检查数据!", detail.getPartNo(), detail.getCustPartNo())); + } + } + + } + + private MesProduceSn checkSn(MesSortShippingCheckModel model) { + //校验条码是否重复扫描 (不区分大小写) + Optional optional = model.getDetailList().stream().filter(k -> !StringUtils.isEmpty(k.getBarcode()) && k.getBarcode().equalsIgnoreCase(model.getSn())).findFirst(); + if (optional.isPresent()) { + throw new ImppBusiException(String.format("【%s】此条码已经扫描过,请检查数据!", model.getSn())); + } + DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode()); + DdlPreparedPack.getStringEqualPack(model.getSn(), "custSn", packBean); + DdlPreparedPack.getOrderByPack(new Object[]{CommonEnumUtil.ASC_OR_DESC.DESC.getValue()}, new String[]{"createDatetime"}, packBean); + MesProduceSn produceSn = produceSnRepository.getByProperty(packBean); + if (!StringUtils.isEmpty(produceSn)) { + //校验状态 + checkStatus(model, produceSn); + } +// else { +// //外部条码解析 +// MesShippingOrderManagementDetail mesShippingOrderManagementDetail = getMesShippingOrderManagementDetail(model); +// //封装信息 +// produceSn = new MesProduceSn(); +// produceSn.setSerialNumber(model.getSn()); +// produceSn.setProductSn(model.getSn()); +// produceSn.setPartNo(mesShippingOrderManagementDetail.getPartNo()); +// produceSn.setOrganizeCode(model.getOrganizeCode()); +// } + return produceSn; + } + + private void checkStatus(MesSortShippingCheckModel model, MesProduceSn produceSn) { + //校验产品条码状态 必须是状态为已下线条码 + if (produceSn.getSnStatus() != MesExtEnumUtil.PRODUCE_SN_STATUS.OFFLINE.getValue() && produceSn.getSnStatus() != MesExtEnumUtil.PRODUCE_SN_STATUS.CREATE.getValue()) { + throw new ImppBusiException(String.format("【%s】此条码状态为【%s】,请选择状态为【%s】或【%s】状态的条码,请检查数据!", model.getSn(), MesExtEnumUtil.PRODUCE_SN_STATUS.valueOfDescription(produceSn.getSnStatus()), + MesExtEnumUtil.PRODUCE_SN_STATUS.OFFLINE.getDescription(), MesExtEnumUtil.PRODUCE_SN_STATUS.CREATE.getDescription())); + } + //校验产品质量状态 必须是状态为合格条码 + List statusList = Stream.of(MesExtEnumUtil.PRODUCE_QC_STATUS.QUALIFIED.getValue(), MesExtEnumUtil.PRODUCE_QC_STATUS.SUSPICIOUS_TO_QUALIFIED.getValue()).collect(Collectors.toList()); + if (!statusList.contains(produceSn.getQcStatus())){ + throw new ImppBusiException(String.format("【%s】此条码质量状态为【%s】,请选择【%s】状态的条码,请检查数据!", model.getSn(), MesExtEnumUtil.PRODUCE_QC_STATUS.valueOfDescription(produceSn.getQcStatus()), + MesExtEnumUtil.PRODUCE_QC_STATUS.QUALIFIED.getDescription())); + } + } + + private MesShippingOrderManagementDetail getMesShippingOrderManagementDetail(MesSortShippingCheckModel model) { + //外部解析条码长度卡控 + String cfgValue = mesConfigService.getCfgValue(model.getOrganizeCode(), MesPcnExtConstWords.MAX_SHIPPING_BARCODE_LENGTH); + if (Integer.parseInt(cfgValue) < model.getSn().length()) { + MesPcnException.throwMesBusiException("【%s】此条码长度超过【%s】位,请检查数据!", model.getSn(), cfgValue); + } + //唯一性校验 + if (mesShippingSnUniqueService.checkMesShippingSnUnique(model.getOrganizeCode(),model.getSn())) { + throw new ImppBusiException(String.format("【%s】条码唯一性校验数据已存在,请检查数据!", model.getSn())); + } + //发运组代码不存在 + if (Objects.isNull(model.getMesPartShippingGroup())) { + MesPcnException.throwMesBusiException("发运组信息不存在,请检查数据!"); + } + List detailList = model.getDetailList().stream().filter(k -> !StringUtils.isEmpty(k.getCustPartNo()) && StringUtils.isEmpty(k.getBarcode()) && !Objects.equals(k.getIsScanFlg(), MesCommonConstant.TRUE_INTEGER)).collect(Collectors.toList()); + MesShippingOrderManagementDetail mesShippingOrderManagementDetail = null; + for (MesShippingOrderManagementDetail managementDetail : detailList) { + DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode()); + DdlPreparedPack.getStringEqualPack(managementDetail.getPartNo(), "erpPartNo", packBean); + DdlPreparedPack.getStringEqualPack(managementDetail.getCustPartNo(), "custPartNo", packBean); + if (checkMesPartShippingGroupDetailRule(model, managementDetail) && mesCustomerPartRepository.isExitByHql(packBean)) { + mesShippingOrderManagementDetail = managementDetail; + break; + } + } + if (Objects.isNull(mesShippingOrderManagementDetail)) { + throw new ImppBusiException(String.format("【%s】此条码未匹配到数据,请检查数据!", model.getSn())); + } + return mesShippingOrderManagementDetail; + } + + private void updateOrderManagementDetails(MesProduceSn produceSn, MesShippingOrderManagement orderManagement, MesShippingOrderManagementDetail detail, MesWorkOrder workOrder, String userInfo) { + if (StringUtils.isEmpty(orderManagement.getCheckSeqCode())) { + detail.setBarcode(produceSn.getCustSn()); + detail.setVisualOrderNo(workOrder.getWorkOrderNo()); + detail.setIsScanFlg(MesCommonConstant.TRUE_INTEGER); + detail.setStatus(MesExtEnumUtil.SHIPPING_ORDER_DETAIL_SHIPPING_STATUS.SHIPPINGED.getValue()); + detail.setRemark("扫描完成"); + //根据是否启动记忆判断 若启用记忆,则根据保存数据库 + if (!StringUtils.isEmpty(orderManagement.getIsEnableMemory()) && Objects.equals(orderManagement.getIsEnableMemory(), MesCommonConstant.TRUE_INTEGER)) { + + //若发运单状态为创建或发布 则写入开始扫描时间 + if (!StringUtils.isEmpty(orderManagement.getStatus()) && (orderManagement.getStatus() == MesExtEnumUtil.SHIPPING_ORDER_STATUS.CREATE.getValue() || + orderManagement.getStatus() == MesExtEnumUtil.SHIPPING_ORDER_STATUS.PUBLISHED.getValue())) { + orderManagement.setStartScanTime(TimeTool.getNowTime(true)); + } + + orderManagement.setStatus(MesExtEnumUtil.SHIPPING_ORDER_STATUS.SHIPPING.getValue()); + orderManagement.setSystemSyncStatus(CommonEnumUtil.FALSE); + ConvertBean.serviceModelUpdate(orderManagement, userInfo); + update(orderManagement); + + detail.setActualQty(1); + detail.setSystemSyncStatus(CommonEnumUtil.FALSE); + ConvertBean.serviceModelUpdate(detail, userInfo); + updateDetail(detail); + //内部条码更新条码状态 + if (!Objects.isNull(produceSn.getId())) { + produceSn.setSnStatus(MesExtEnumUtil.PRODUCE_SN_STATUS.SHIPPED.getValue()); + produceSn.setSystemSyncStatus(CommonEnumUtil.FALSE); + ConvertBean.serviceModelUpdate(produceSn, userInfo); + produceSnExtService.update(produceSn); + }else{ + //记录唯一性校验表 + mesShippingSnUniqueService.insertMesShippingSnUnique(orderManagement.getOrganizeCode(),detail.getBarcode(),orderManagement.getShippingCode(),userInfo); + } + } + } + } + + @MonitorLog + public void update(MesShippingOrderManagement item) { + shippingOrderManagementRepository.update(item); + } + + @MonitorLog + public void updateDetail(MesShippingOrderManagementDetail item) { + shippingOrderManagementDetailRepository.update(item); + } + + private Boolean checkMesPartShippingGroupDetailRule(MesSortShippingCheckModel model, MesShippingOrderManagementDetail managementDetail) { + MesPartShippingGroupDetail mesPartShippingGroupDetail = mesPartShippingGroupService.getMesPartShippingGroupDetail(model.getOrganizeCode(), model.getMesPartShippingGroup().getShippingGroupCode(), managementDetail.getPartNo(), managementDetail.getCustPartNo()); + return !Objects.isNull(mesPartShippingGroupDetail) && !StringUtil.isEmpty(mesPartShippingGroupDetail.getSnRule()) && ((Boolean) ((IMesNumberRuleMatchDispatchService) SpringContextsUtil.getBean(MesExtEnumUtil.ASSEMBLY_MATCH_TYPE.MATCH_TYPE_20.getStrategyClass())).matchNumberRule(model.getOrganizeCode(), model.getSn(), mesPartShippingGroupDetail.getSnRule(), mesPartShippingGroupDetail.getSnRule()).get(MesPcnExtConstWords.RESULT)); + } +}