ludc
2023-04-15 716ded9c48898ff8fb9e4a1872ccfe676c7f2f99
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/CodeRuleServiceImpl.java
@@ -1,685 +1,432 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package com.vci.ubcs.code.service.impl;
import com.vci.ubcs.code.constant.MdmBtmTypeConstant;
import com.vci.ubcs.code.dao.CodeBasicSecDaoI;
import com.vci.ubcs.code.dao.CodeRuleDaoI;
import com.vci.ubcs.code.lifecycle.CodeRuleLC;
import com.vci.ubcs.code.model.CodeAllCodeDO;
import com.vci.ubcs.code.model.CodeBasicSecDO;
import com.vci.ubcs.code.model.CodeClassifyDO;
import com.vci.ubcs.code.model.CodeRuleDO;
import com.vci.ubcs.code.service.CodeBasicSecServiceI;
import com.vci.ubcs.code.service.CodeClassifyServiceI;
import com.vci.ubcs.code.service.CodeRuleServiceI;
import com.vci.corba.common.VCIError;
import com.vci.starter.revision.service.RevisionModelUtil;
import com.vci.starter.web.exception.VciBaseException;
import com.vci.starter.web.pagemodel.BaseResult;
import com.vci.starter.web.pagemodel.DataGrid;
import com.vci.starter.web.pagemodel.KeyValue;
import com.vci.starter.web.pagemodel.PageHelper;
import com.vci.starter.web.util.BeanUtilForVCI;
import com.vci.starter.web.util.VciBaseUtil;
import com.vci.starter.web.wrapper.VciQueryWrapperForDO;
import com.vci.web.pageModel.BatchCBO;
import com.vci.web.service.WebBoServiceI;
import com.vci.web.util.WebUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vci.ubcs.code.dto.CodeBasicSecDTO;
import com.vci.ubcs.code.dto.CodeRuleDTO;
import com.vci.ubcs.code.vo.pagemodel.CodeBasicSecVO;
import com.vci.ubcs.code.entity.*;
import com.vci.ubcs.code.lifecycle.CodeRuleLC;
import com.vci.ubcs.code.mapper.CodeRuleMapper;
import com.vci.ubcs.code.mapper.CodeSerialValueMapper;
import com.vci.ubcs.code.mapper.CommonsMapper;
import com.vci.ubcs.code.service.ICodeAllCodeService;
import com.vci.ubcs.code.service.ICodeBasicSecService;
import com.vci.ubcs.code.service.ICodeClassifyService;
import com.vci.ubcs.code.service.ICodeRuleService;
import com.vci.ubcs.code.vo.pagemodel.CodeClassifyVO;
import com.vci.ubcs.code.vo.pagemodel.CodeRuleVO;
import org.springframework.beans.factory.annotation.Autowired;
import com.vci.ubcs.code.wrapper.CodeClassifyWrapper;
import com.vci.ubcs.code.wrapper.CodeRuleWrapper;
import com.vci.ubcs.com.vci.starter.exception.VciBaseException;
import com.vci.ubcs.com.vci.starter.revision.service.RevisionModelUtil;
import com.vci.ubcs.com.vci.starter.web.pagemodel.KeyValue;
import com.vci.ubcs.com.vci.starter.web.util.BeanUtilForVCI;
import com.vci.ubcs.com.vci.starter.web.util.VciBaseUtil;
import com.vci.ubcs.com.vci.starter.web.util.WebUtil;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.BeanUtil;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import plm.bs.bom.clientobject.ClientBusinessObject;
import plm.bs.bom.clientobject.ClientBusinessObjectOperation;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
import static com.vci.frameworkcore.constant.FrameWorkBusLangCodeConstant.*;
import static com.vci.ubcs.code.constant.FrameWorkDefaultValueConstant.FRAMEWORK_RELEASE_EDITING;
import static com.vci.ubcs.code.constant.FrameWorkLangCodeConstant.DATA_OID_NOT_EXIST;
import static com.vci.ubcs.code.constant.MdmLifeCycleConstant.CODE_RULE_LC;
/**
 * 主数据编码规则服务
 * 编码规则 服务实现类
 *
 * @author weidy
 * @date 2022-01-24
 * @author ludc
 * @since 2023-04-03
 */
@Service
public class CodeRuleServiceImpl implements CodeRuleServiceI {
public class CodeRuleServiceImpl extends ServiceImpl<CodeRuleMapper, CodeRule> implements ICodeRuleService {
    /**
     * 日志
     */
    private Logger logger = LoggerFactory.getLogger(getClass());
   /**
    * 数据操作层
    */
   @Resource
   private CodeRuleMapper codeRuleMapper;
   @Resource
   private CommonsMapper commonsMapper;
   @Resource
   private CodeSerialValueMapper codeSerialValueMapper;
    /**
     * 数据操作层
     */
    @Resource
    private CodeRuleDaoI codeRuleMapper;
   /**
    * 其他服务层
    */
   @Resource
   @Lazy
   private ICodeClassifyService codeClassifyServcie;
   @Resource
   private ICodeAllCodeService codeAllcodeService;
   @Resource
   private ICodeBasicSecService codeBasicSecService;
    /**
     * 业务类型操作的服务
     */
    @Autowired
    @Lazy
   private WebBoServiceI boService;
   /**
    * 对象的操作
    */
   @Resource
   private RevisionModelUtil revisionModelUtil;
    /**
     * 对象的操作
     */
    @Autowired
    private RevisionModelUtil revisionModelUtil;
   @Override
   public IPage<CodeRuleVO> gridCodeRule(IPage<CodeRuleVO> page, CodeRuleVO codeRule) {
      //对生命周期的枚举进行转换
      if(!StringUtils.isEmpty(codeRule.getLcStatusText())){
         codeRule.setLcStatus(CodeRuleLC.getValueByText(codeRule.getLcStatusText()));
      }
      List<CodeRule> codeRulePage = codeRuleMapper.selectCodeRulePage(page, codeRule);
      //do转vo同时setLcStatusText生命周期值,并包装成分页对象返回
      return page.setRecords(CodeRuleWrapper.build().listVO(codeRulePage));
   }
    /**
     * 主题库分类数据操作层
     */
    @Autowired
    private CodeClassifyServiceI codeClassifyService;
   /**
    * 增加主数据编码规则
    *
    * @param codeRuleDTO 主数据编码规则数据传输对象
    * @return 执行结果
    * @throws VciBaseException 参数为空,唯一项,必输项不通过时会抛出异常
    */
   @Override
   public boolean addSave(CodeRuleDTO codeRuleDTO) throws VciBaseException{
      VciBaseUtil.alertNotNull(codeRuleDTO, "需要添加的数据对象");
      //将DTO转换为DO
      CodeRule codeRule = Objects.requireNonNull(BeanUtil.copy(codeRuleDTO, CodeRule.class));
      String userId = AuthUtil.getUserId().toString();
      codeRule.setOid(VciBaseUtil.getPk());
      codeRule.setRevisionOid(VciBaseUtil.getPk());
      codeRule.setNameOid(VciBaseUtil.getPk());
      codeRule.setBtmname("coderule");
      codeRule.setLastR("1");
      codeRule.setLastV("1");
      codeRule.setFirstR("1");
      codeRule.setFirstV("1");
      codeRule.setCreator(userId);
      codeRule.setCreateTime(new Date());
      codeRule.setLastModifier("1");
      codeRule.setLastModifyTime(new Date());
      codeRule.setVersionRule("0");
      codeRule.setVersionSeq(1);
      codeRule.setLctid(CODE_RULE_LC);
      codeRule.setLcStatus(FRAMEWORK_RELEASE_EDITING);
      codeRule.setOwner("1");
      codeRule.setCreator(userId);
      codeRule.setLastModifier(userId);
      return codeRuleMapper.insert(codeRule)>0;
   }
    /**
     * 码段基础信息服务
     */
    @Autowired
    private CodeBasicSecServiceI codeBasicSecService;
   /**
    * 校验编码规则的状态是否可以编辑或删除
    *
    * @param lcStatus 编码规则
    * @return true表示可以编辑或删除,false表示不可以
    */
   @Override
   public boolean checkEditDelStatus(String lcStatus) {
      if (CodeRuleLC.RELEASED.getValue().equals(lcStatus) || CodeRuleLC.DISABLED.getValue().equals(lcStatus)) {
         return false;
      }
      return true;
   }
    /**
     * 码段基础信息数据操作层
     */
    @Resource
    private CodeBasicSecDaoI codeBasicSecMapper;
   /**
    * 修改主数据编码规则
    *
    * @param codeRuleDTO 主数据编码规则数据传输对象
    * @return 执行结果
    * @throws VciBaseException 参数为空,唯一项,必输项不通过时会抛出异常
    */
   @Override
   public boolean editSave(CodeRuleDTO codeRuleDTO) throws VciBaseException{
      VciBaseUtil.alertNotNull(codeRuleDTO, "数据对象", codeRuleDTO.getOid(), "主数据编码规则主键");
      if (!checkEditDelStatus(codeRuleDTO.getLcStatus())) {
         throw new VciBaseException("编码规则已发布,不允许编辑或删除");
      }
      //将DTO转换为DO
      CodeRule codeRule = selectByOid(codeRuleDTO.getOid());
      revisionModelUtil.copyFromDTOIgnore(codeRuleDTO, codeRule);
      return codeRuleMapper.updateById(codeRule)>0;
   }
   /**
    * 删除主数据编码规则
    *
    * @param codeRuleDTO 主数据编码规则数据传输对象,oid和ts需要传输
    * @return 删除结果反馈::success:成功,fail:失败
    * @throws VciBaseException 参数为空,被引用时抛出异常
    */
   @Override
   @Transactional(rollbackFor = Exception.class)
   public R deleteCodeRule(CodeRuleDTO codeRuleDTO) throws VciBaseException {
      VciBaseUtil.alertNotNull(codeRuleDTO, "主数据编码规则数据对象", codeRuleDTO.getOid(), "主数据编码规则的主键");
      CodeRule codeRule = selectByOid(codeRuleDTO.getOid());
      if (!checkEditDelStatus(codeRule.getLcStatus())) {
         return R.fail("编码规则已发布,不允许编辑或删除");
      } else {
         if (isAlreadyInUse(codeRule.getOid())) {
            return R.fail("编码规则已被引用,不允许编辑或删除!");
         }
      }
      List<CodeAllCode> codeDOList = codeAllcodeService.selectByWrapper(Wrappers.<CodeAllCode>query().lambda().eq(CodeAllCode::getCodeRuleOid, codeRuleDTO.getOid()));
      if (!CollectionUtils.isEmpty(codeDOList)) {
         return R.fail("编码规则已生成编码,不允许删除");
      }
      //执行删除操作
      //WebUtil.setPersistence(false);
      boolean resBoolean = codeBasicSecService.batchDeleteSecByCodeRuleOid(codeRule.getOid());
      boolean resBoolean1 = codeRuleMapper.deleteById(codeRule.getOid()) > 0;
      //WebUtil.setPersistence(true);
      return R.status(resBoolean&&resBoolean1);
   }
   /**
    * 编码规则清空所有已生成的编码
    *
    * @param oid 编码规则主键
    * @return 执行结果
    */
   @Override
   public R clearAllCode(String oid) {
      WebUtil.alertNotNull(oid, "编码规则主键");
      List<CodeAllCode> codeDOList = codeAllcodeService.selectByWrapper(Wrappers.<CodeAllCode>query().lambda().eq(CodeAllCode::getCodeRuleOid, oid));
      if (CollectionUtils.isEmpty(codeDOList)) {
         return R.fail("当前编码规则没有生成编码,无需清空");
      }
      //是否需要进行btm不统一的判断?
      String btmType = codeDOList.get(0).getCreateCodeBtm();
      //多种类型下的查询
      Set<String> btmTypeSet = codeDOList.stream().filter(s -> {
         return !btmType.equalsIgnoreCase(s.getCreateCodeBtm());
      }).map(s -> s.getCreateCodeBtm()).collect(Collectors.toSet());
      List<Map<String,String>> businessDataList = new ArrayList<>();
      if (btmTypeSet.size() > 1) {
         for (String btm : btmTypeSet) {
            Map<String,String> businessData = commonsMapper.selectByCount("PL_CODE_"+btm,oid,btm);
            businessDataList.add(businessData);
         }
      }else {
         Map<String,String> businessData = commonsMapper.selectByCount("PL_CODE_"+btmType,oid,btmType);
         businessDataList.add(businessData);
      }
      if (CollectionUtils.isEmpty(businessDataList) || StringUtils.isBlank(businessDataList.get(0).get("count"))) {
         //无效查询
         return R.fail("查询失败");
      } else if (!"0".equalsIgnoreCase(businessDataList.get(0).get("count"))) {
         return R.fail("编码规则生成的编码已在业务数据中应用,不允许清空");
      }
      //没有数据,可以安全删除
      WebUtil.setPersistence(false);
      //删除码值表中的数据,但不够,如果有流水的码段,需要重新计算流水
      List<CodeSerialValue> serialValueList = codeSerialValueMapper.selectByCodeRoleId(oid);
      /*BatchCBO batchCBO = boService.batchDelete(codeDOList);
      batchCBO.getDeleteCbos().addAll(serialValueList);
      WebUtil.setPersistence(true);
      boService.persistenceBatch(batchCBO);*/
      return R.success("清空码值成功!");
   }
   /**
    * 主键查询数据对象
    *
    * @param oid 主键
    * @return 数据对象
    * @throws VciBaseException 参数为空,并且数据不存在的时候会抛出异常
    */
   private CodeRule selectByOid(String oid) throws VciBaseException {
      VciBaseUtil.alertNotNull(oid, "主键");
      CodeRule codeRuleDO = codeRuleMapper.selectById(oid.trim());
      if (codeRuleDO == null || StringUtils.isBlank(codeRuleDO.getOid())) {
         throw new VciBaseException(DATA_OID_NOT_EXIST);
      }
      return codeRuleDO;
   }
   /**
    * 检验编码规则是否已经被使用
    *
    * @param oid 编码规则主键
    * @return true表示已经使用,false表示未被使用
    */
   @Override
   public boolean isAlreadyInUse(String oid) {
      Collection<CodeClassifyVO> codeClassifyVOS = listUseRangeInCodeClassify(oid);
      if (codeClassifyVOS.size() > 0) {
         return true;
      } else {
         return false;
      }
   }
   /**
    * 查看主数据编码规则的使用范围
    *
    * @param oid 编码规则主键
    * @return 主题库分类使用到该编码规则的所有集合
    */
   @Override
   public Collection<CodeClassifyVO> listUseRangeInCodeClassify(String oid) {
      List<CodeClassify> codeClassifies = codeClassifyServcie.selectByWrapper(Wrappers.<CodeClassify>query().eq("codeRuleOid", oid));
      return CodeClassifyWrapper.build().listVO(codeClassifies);
   }
   /**
    * 主键获取主数据编码规则
    *
    * @param oid 主键
    * @return 主数据编码规则显示对象
    * @throws VciBaseException 参数为空,数据不存在时会抛出异常
    */
   @Override
   public CodeRuleVO getObjectByOid(String oid) throws VciBaseException {
      CodeRule codeRule = selectByOid(oid);
      return CodeRuleWrapper.build().entityVO(codeRule);
   }
   /**
    * 主键批量获取主数据编码规则
    *
    * @param oidCollections 主键集合,但是受性能影响,建议一次查询不超过10000个
    * @return 主数据编码规则显示对象
    * @throws VciBaseException 查询出现异常时会抛出
    */
   @Override
   public Collection<CodeRuleVO> listCodeRuleByOids(Collection<String> oidCollections) throws VciBaseException {
      VciBaseUtil.alertNotNull(oidCollections, "数据对象主键集合");
      List<CodeRule> codeRuleDOList = listCodeRuleDOByOidCollections(oidCollections);
      return CodeRuleWrapper.build().listVO(codeRuleDOList);
   }
   /**
    * 使用主键集合查询数据对象
    *
    * @param oidCollections 主键的集合
    * @return 数据对象列表
    */
   private List<CodeRule> listCodeRuleDOByOidCollections(Collection<String> oidCollections) {
      List<CodeRule> codeRuleDOList = new ArrayList<CodeRule>();
      if (!CollectionUtils.isEmpty(oidCollections)) {
         Collection<Collection<String>> oidCollectionsList = VciBaseUtil.switchCollectionForOracleIn(oidCollections);
         for (Collection<String> oids : oidCollectionsList) {
            List<CodeRule> tempDOList = codeRuleMapper.selectBatchIds(oids);
            if (!CollectionUtils.isEmpty(tempDOList)) {
               codeRuleDOList.addAll(tempDOList);
            }
         }
      }
      return codeRuleDOList;
   }
   /**
    * 参照主数据编码规则列表
    *
    * @param codeRule 查询条件
    * @param page   分页和排序
    * @return 主数据编码规则显示对象列表,生效的内容
    * @throws VciBaseException 查询条件和分页出错的时候会抛出异常
    */
   @Override
   public IPage<CodeRuleVO> refDataGridCodeRule(IPage<CodeRuleVO> page, CodeRuleVO codeRule) throws VciBaseException {
      return gridCodeRule(page, codeRule);
   }
   /**
    * 停用与启用编码规则
    *
    * @param oid    编码规则主键
    * @param update enable:启用 disable:停用 release:发布
    * @return 执行结果
    */
   @Override
   public R updateStatus(String oid, String update) {
      int count = 0;
      //先查询对象
      CodeRule codeRuleDO = selectByOid(oid);
      //创建修改对象的的wrapper条件
      LambdaUpdateWrapper<CodeRule> wrapper = Wrappers.<CodeRule>update()
         .lambda()
         .eq(CodeRule::getOid, oid);
      if ("enable".equalsIgnoreCase(update)) {
         if (!CodeRuleLC.DISABLED.getValue().equals(codeRuleDO.getLcStatus())) {
            return R.fail("非停用状态的编码规则无需点击启用");
         }
         count = codeRuleMapper.update(null,wrapper.set(CodeRule::getLcStatus, CodeRuleLC.RELEASED.getValue()));
      } else if ("disable".equalsIgnoreCase(update)) {
         if (!CodeRuleLC.RELEASED.getValue().equals(codeRuleDO.getLcStatus())) {
            return R.fail("非发布状态的编码规则无法停用");
         }
         count = codeRuleMapper.update(null,wrapper.set(CodeRule::getLcStatus, CodeRuleLC.DISABLED.getValue()));
      } else if ("release".equalsIgnoreCase(update)) {
         if (!CodeRuleLC.EDITING.getValue().equals(codeRuleDO.getLcStatus())) {
            return R.fail("非编辑状态的编码规则无法发布");
         }
         count = codeRuleMapper.update(null,wrapper.set(CodeRule::getLcStatus, CodeRuleLC.RELEASED.getValue()));
      } else {
         return R.fail("暂不支持的操作类型");
      }
      if (count > 0) {
         return R.success("更新状态成功");
      } else {
         return R.fail("更新状态失败");
      }
   }
   /**
    * 克隆编码规则
    *
    * @param codeRuleDTO 主数据编码规则数据传输对象,oid和ts需要传输
    * @return 主数据编码规则显示对象
    */
   @Override
   @Transactional(rollbackFor = Exception.class)
   public R cloneCodeRule(CodeRuleDTO codeRuleDTO) {
      VciBaseUtil.alertNotNull(codeRuleDTO, "需要添加的数据对象");
      CodeRule codeRuleDO = new CodeRule();
      BeanUtilForVCI.copyPropertiesIgnoreCase(codeRuleDTO, codeRuleDO);
      boolean exFlag = codeRuleMapper.insert(codeRuleDO)>0;
      List<CodeBasicSecDTO> secList = codeRuleDTO.getElements();
      List<CodeBasicSec> codeBasicSecs = new ArrayList<>();
      secList.forEach(codeBasicSecDTO -> {
         codeBasicSecDTO.setPkCodeRule(codeRuleDO.getOid());
         KeyValue attrKv = codeBasicSecService.checkAttrNullableBySecType(codeBasicSecDTO);
         if (!"success".equals(attrKv.getKey())) {
            throw new VciBaseException(attrKv.getValue() + "不能为空");
         }
         CodeBasicSec codeBasicSecDO = new CodeBasicSec();
         BeanUtilForVCI.copyPropertiesIgnoreCase(codeBasicSecDTO, codeBasicSecDO);
         codeBasicSecDO.setOid("");
         codeBasicSecDO.setRevisionOid("");
         codeBasicSecDO.setNameOid("");
         codeBasicSecs.add(codeBasicSecDO);
      });
      boolean exFlag1 = this.codeBasicSecService.saveBatch(codeBasicSecs);
      return R.data(exFlag&&exFlag1);
   }
    /**
     * 查询所有的主数据编码规则
     *
     * @param conditionMap 查询条件
     * @param pageHelper   分页和排序
     * @return 执行结果
     * @throws VciBaseException 查询条件和分页出错的时候会抛出异常
     */
    @Override
    public DataGrid<CodeRuleVO> gridCodeRule(Map<String, String> conditionMap, PageHelper pageHelper) throws VciBaseException {
        if (pageHelper == null) {
            pageHelper = new PageHelper(-1);
        }
        pageHelper.addDefaultDesc("createTime");
        List<CodeRuleDO> doList = codeRuleMapper.selectByCondition(conditionMap, pageHelper);
        DataGrid<CodeRuleVO> dataGrid = new DataGrid<CodeRuleVO>();
        if (!CollectionUtils.isEmpty(doList)) {
            dataGrid.setData(codeRuleDO2VOs(doList));
            dataGrid.setTotal(VciBaseUtil.getInt(String.valueOf(codeRuleMapper.countByCondition(conditionMap))));
        }
        return dataGrid;
    }
    /**
     * 批量数据对象转换为显示对象
     *
     * @param codeRuleDOs 数据对象列表
     * @return 显示对象
     * @throws VciBaseException 参数为空或者不存在的时候会抛出异常
     */
    @Override
    public List<CodeRuleVO> codeRuleDO2VOs(Collection<CodeRuleDO> codeRuleDOs) throws VciBaseException {
        return codeRuleDO2VOs(codeRuleDOs, false);
    }
    /**
     * 批量数据对象转换为显示对象
     *
     * @param codeRuleDOs 数据对象列表
     * @param hasSec      是否包含码段
     * @return 显示对象
     * @throws VciBaseException 参数为空或者不存在的时候会抛出异常
     */
    @Override
    public List<CodeRuleVO> codeRuleDO2VOs(Collection<CodeRuleDO> codeRuleDOs, boolean hasSec) throws VciBaseException {
        List<CodeRuleVO> voList = new ArrayList<CodeRuleVO>();
        if (!CollectionUtils.isEmpty(codeRuleDOs)) {
            for (CodeRuleDO s : codeRuleDOs) {
                CodeRuleVO vo = codeRuleDO2VO(s);
                if (vo != null) {
                    voList.add(vo);
                }
            }
            if (hasSec) {
                List<CodeBasicSecVO> secVOList = codeBasicSecService.listCodeBasicSecByRuleOids(voList.stream().map(CodeRuleVO::getOid).collect(Collectors.toList()));
                if (!CollectionUtils.isEmpty(secVOList)) {
                    Map<String, List<CodeBasicSecVO>> secVOMap = secVOList.stream().collect(Collectors.groupingBy(CodeBasicSecVO::getPkCodeRule));
                    voList.stream().forEach(vo -> {
                        vo.setSecVOList(secVOMap.getOrDefault(vo.getOid(), new ArrayList<>()));
                    });
                }
            }
        }
        return voList;
    }
    /**
     * 数据对象转换为显示对象
     *
     * @param codeRuleDO 数据对象
     * @return 显示对象
     * @throws VciBaseException 拷贝属性出错的时候会抛出异常
     */
    @Override
    public CodeRuleVO codeRuleDO2VO(CodeRuleDO codeRuleDO) throws VciBaseException {
        CodeRuleVO vo = new CodeRuleVO();
        if (codeRuleDO != null) {
            BeanUtilForVCI.copyPropertiesIgnoreCase(codeRuleDO, vo);
            //如果有lcstatus的类的话
            vo.setLcStatusText(CodeRuleLC.getTextByValue(vo.getLcStatus()));
        }
        return vo;
    }
    /**
     * 数据对象转换为显示对象
     *
     * @param codeRuleDO 规则的数据对象
     * @param hasSec     是否查询码段
     * @return 显示对象
     * @throws VciBaseException 拷贝属性出错的时候会抛出异常
     */
    public CodeRuleVO codeRuleDO2VO(CodeRuleDO codeRuleDO, boolean hasSec) throws VciBaseException {
        CodeRuleVO vo = new CodeRuleVO();
        if (codeRuleDO != null) {
            BeanUtilForVCI.copyPropertiesIgnoreCase(codeRuleDO, vo);
            //如果有lcstatus的类的话
            vo.setLcStatusText(CodeRuleLC.getTextByValue(vo.getLcStatus()));
            if (hasSec) {
                //查询码段
                vo.setSecVOList(codeBasicSecService.listCodeBasicSecByRuleOid(vo.getOid()));
            }
        }
        return vo;
    }
    /**
     * 增加主数据编码规则
     *
     * @param codeRuleDTO 主数据编码规则数据传输对象
     * @return 执行结果
     * @throws VciBaseException 参数为空,唯一项,必输项不通过时会抛出异常
     */
    @Override
    public CodeRuleVO addSave(CodeRuleDTO codeRuleDTO) throws VciBaseException {
        VciBaseUtil.alertNotNull(codeRuleDTO, "需要添加的数据对象");
        //将DTO转换为DO
        CodeRuleDO codeRuleDO = new CodeRuleDO();
        BeanUtilForVCI.copyPropertiesIgnoreCase(codeRuleDTO, codeRuleDO);
        codeRuleMapper.insert(codeRuleDO);
        return codeRuleDO2VO(codeRuleDO);
    }
    /**
     * 修改主数据编码规则
     *
     * @param codeRuleDTO 主数据编码规则数据传输对象
     * @return 执行结果
     * @throws VciBaseException 参数为空,唯一项,必输项不通过时会抛出异常
     */
    @Override
    public CodeRuleVO editSave(CodeRuleDTO codeRuleDTO) throws VciBaseException {
        VciBaseUtil.alertNotNull(codeRuleDTO, "数据对象", codeRuleDTO.getOid(), "主数据编码规则主键");
        if (!checkEditDelStatus(codeRuleDTO.getLcStatus())) {
            throw new VciBaseException("编码规则已发布,不允许编辑或删除");
        }
        //将DTO转换为DO
        CodeRuleDO codeRuleDO = selectByOid(codeRuleDTO.getOid());
        revisionModelUtil.copyFromDTOIgnore(codeRuleDTO, codeRuleDO);
        codeRuleMapper.updateByPrimaryKey(codeRuleDO);
        return codeRuleDO2VO(codeRuleDO);
    }
    /**
     * 校验是否可以删除,如果存在下级,并且下级有数据引用则不能删除
     *
     * @param codeRuleDTO 数据传输对象
     * @param codeRuleDO  数据库中的数据对象
     * @return success为true为可以删除,false表示有数据引用,obj为true表示有下级
     */
    private BaseResult checkIsCanDeleteForDO(CodeRuleDTO codeRuleDTO, CodeRuleDO codeRuleDO) {
        boService.checkTs(codeRuleDTO);
        if (!checkIsLinked(codeRuleDO.getOid())) {
            return BaseResult.success();
        } else {
            return BaseResult.fail(DATA_LINKED_NOT_DELETE, new String[]{""});
        }
    }
    /**
     * 校验是否被引用
     *
     * @param oid 主键
     * @throws VciBaseException 被引用的时候会抛出异常
     */
    private boolean checkIsLinked(String oid) throws VciBaseException {
        //TODO 添加需要校验引用的地方
        return false;
    }
    /**
     * 删除主数据编码规则
     *
     * @param codeRuleDTO 主数据编码规则数据传输对象,oid和ts需要传输
     * @return 删除结果反馈::success:成功,fail:失败
     * @throws VciBaseException 参数为空,被引用时抛出异常
     */
    @Override
    public BaseResult deleteCodeRule(CodeRuleDTO codeRuleDTO) throws VciBaseException {
        VciBaseUtil.alertNotNull(codeRuleDTO, "主数据编码规则数据对象", codeRuleDTO.getOid(), "主数据编码规则的主键");
        CodeRuleDO codeRuleDO = selectByOid(codeRuleDTO.getOid());
        //BaseResult baseResult = checkIsCanDeleteForDO(codeRuleDTO,codeRuleDO);
        // if(baseResult.isSuccess()) {
        //             }else{
        //     return baseResult;
        // }
        if (!checkEditDelStatus(codeRuleDO.getLcStatus())) {
            return BaseResult.fail("编码规则已发布,不允许编辑或删除");
        } else {
            if (isAlreadyInUse(codeRuleDO.getOid())) {
                return BaseResult.fail("编码规则已被引用,不允许编辑或删除!");
            }
        }
        Map<String, String> conditionMap = new HashMap<>();
        conditionMap.put("codeRuleOid", codeRuleDTO.getOid());
        List<CodeAllCodeDO> codeDOList = boService.queryObject(CodeAllCodeDO.class, conditionMap);
        if (!CollectionUtils.isEmpty(codeDOList)) {
            return BaseResult.fail("编码规则已生成编码,不允许删除");
        }
        //执行删除操作
        WebUtil.setPersistence(false);
        BatchCBO batchCBO = codeBasicSecService.batchDeleteSecByCodeRuleOid(codeRuleDO.getOid());
        BatchCBO mainCBO = codeRuleMapper.deleteByPrimaryKey(codeRuleDO.getOid());
        WebUtil.setPersistence(true);
        Set<ClientBusinessObject> deleteSet = new HashSet<>();
        deleteSet.addAll(batchCBO.getDeleteCbos());
        deleteSet.addAll(mainCBO.getDeleteCbos());
        batchCBO.setDeleteCbos(deleteSet);
        boService.persistenceBatch(batchCBO);
        return (batchCBO != null && batchCBO.getDeleteCbos() != null && batchCBO.getDeleteCbos().size() > 0) ? BaseResult.successMsg(DELETE_SUCCESS) : BaseResult.fail(DELETE_FAIL);
    }
    /**
     * 校验编码规则的状态是否可以编辑或删除
     *
     * @param lcStatus 编码规则
     * @return true表示可以编辑或删除,false表示不可以
     */
    @Override
    public boolean checkEditDelStatus(String lcStatus) {
        if (CodeRuleLC.RELEASED.getValue().equals(lcStatus) || CodeRuleLC.DISABLED.getValue().equals(lcStatus)) {
            return false;
        }
        return true;
    }
    /**
     * 主键获取主数据编码规则
     *
     * @param oid 主键
     * @return 主数据编码规则显示对象
     * @throws VciBaseException 参数为空,数据不存在时会抛出异常
     */
    @Override
    public CodeRuleVO getObjectByOid(String oid) throws VciBaseException {
        return codeRuleDO2VO(selectByOid(oid));
    }
    /**
     * 主键查询数据对象
     *
     * @param oid 主键
     * @return 数据对象
     * @throws VciBaseException 参数为空,并且数据不存在的时候会抛出异常
     */
    private CodeRuleDO selectByOid(String oid) throws VciBaseException {
        VciBaseUtil.alertNotNull(oid, "主键");
        CodeRuleDO codeRuleDO = codeRuleMapper.selectByPrimaryKey(oid.trim());
        if (codeRuleDO == null || StringUtils.isBlank(codeRuleDO.getOid())) {
            throw new VciBaseException(DATA_OID_NOT_EXIST);
        }
        return codeRuleDO;
    }
    /**
     * 主键批量获取主数据编码规则
     *
     * @param oidCollections 主键集合,但是受性能影响,建议一次查询不超过10000个
     * @return 主数据编码规则显示对象
     * @throws VciBaseException 查询出现异常时会抛出
     */
    @Override
    public Collection<CodeRuleVO> listCodeRuleByOids(Collection<String> oidCollections) throws VciBaseException {
        VciBaseUtil.alertNotNull(oidCollections, "数据对象主键集合");
        List<CodeRuleDO> codeRuleDOList = listCodeRuleDOByOidCollections(oidCollections);
        return codeRuleDO2VOs(codeRuleDOList);
    }
    /**
     * 主键批量获取主数据编码规则
     *
     * @param oidCollections 主键集合,但是受性能影响,建议一次查询不超过10000个
     * @param hasSec         是否包含码段
     * @return 主数据编码规则显示对象
     * @throws VciBaseException 查询出现异常时会抛出
     */
    @Override
    public Collection<CodeRuleVO> listCodeRuleByOids(Collection<String> oidCollections, boolean hasSec) throws VciBaseException {
        VciBaseUtil.alertNotNull(oidCollections, "数据对象主键集合");
        List<CodeRuleDO> codeRuleDOList = listCodeRuleDOByOidCollections(oidCollections);
        return codeRuleDO2VOs(codeRuleDOList, true);
    }
    /**
     * 使用编号的集合获取规则的内容
     *
     * @param idCollection 编号的集合
     * @return 规则的内容
     */
    @Override
    public List<CodeRuleVO> listCodeRuleByIds(Collection<String> idCollection) {
        return codeRuleDO2VOs(listCodeRuleDOByIdCollections(idCollection));
    }
    /**
     * 使用主键集合查询数据对象
     *
     * @param oidCollections 主键的集合
     * @return 数据对象列表
     */
    private List<CodeRuleDO> listCodeRuleDOByOidCollections(Collection<String> oidCollections) {
        List<CodeRuleDO> codeRuleDOList = new ArrayList<CodeRuleDO>();
        if (!CollectionUtils.isEmpty(oidCollections)) {
            Collection<Collection<String>> oidCollectionsList = VciBaseUtil.switchCollectionForOracleIn(oidCollections);
            for (Collection<String> oids : oidCollectionsList) {
                List<CodeRuleDO> tempDOList = codeRuleMapper.selectByPrimaryKeyCollection(oids);
                if (!CollectionUtils.isEmpty(tempDOList)) {
                    codeRuleDOList.addAll(tempDOList);
                }
            }
        }
        return codeRuleDOList;
    }
    /**
     * 使用编号集合查询数据对象
     *
     * @param idCollections 编号的集合
     * @return 数据对象列表
     */
    private List<CodeRuleDO> listCodeRuleDOByIdCollections(Collection<String> idCollections) {
        List<CodeRuleDO> codeRuleDOList = new ArrayList<CodeRuleDO>();
        if (!CollectionUtils.isEmpty(idCollections)) {
            Collection<Collection<String>> idCollectionsList = VciBaseUtil.switchCollectionForOracleIn(idCollections);
            for (Collection<String> ids : idCollectionsList) {
                List<CodeRuleDO> tempDOList = codeRuleMapper.selectByIdCollection(ids);
                if (!CollectionUtils.isEmpty(tempDOList)) {
                    codeRuleDOList.addAll(tempDOList);
                }
            }
        }
        return codeRuleDOList;
    }
    /**
     * 参照主数据编码规则列表
     *
     * @param conditionMap 查询条件
     * @param pageHelper   分页和排序
     * @return 主数据编码规则显示对象列表,生效的内容
     * @throws VciBaseException 查询条件和分页出错的时候会抛出异常
     */
    @Override
    public DataGrid<CodeRuleVO> refDataGridCodeRule(Map<String, String> conditionMap, PageHelper pageHelper) throws VciBaseException {
        if (conditionMap == null) {
            conditionMap = new HashMap<String, String>();
        }
        return gridCodeRule(conditionMap, pageHelper);
    }
    /**
     * 查看主数据编码规则的使用范围
     *
     * @param oid 编码规则主键
     * @return 主题库分类使用到该编码规则的所有集合
     */
    @Override
    public Collection<CodeClassifyVO> listUseRangeInCodeClassify(String oid) {
        Map<String, String> conditionMap = new HashMap<>();
        conditionMap.put("codeRuleOid", oid);
        VciQueryWrapperForDO queryWrapper = new VciQueryWrapperForDO(conditionMap, CodeClassifyDO.class);
        List<CodeClassifyDO> dos = codeClassifyService.selectByWrapper(queryWrapper);
        return codeClassifyService.codeClassifyDO2VOs(dos);
    }
    /**
     * 检验编码规则是否已经被使用
     *
     * @param oid 编码规则主键
     * @return true表示已经使用,false表示未被使用
     */
    @Override
    public boolean isAlreadyInUse(String oid) {
        Collection<CodeClassifyVO> codeClassifyVOS = listUseRangeInCodeClassify(oid);
        if (codeClassifyVOS.size() > 0) {
            return true;
        } else {
            return false;
        }
    }
    /**
     * 停用与启用编码规则
     *
     * @param oid    编码规则主键
     * @param update enable:启用 disable:停用 release:发布
     * @return 执行结果
     */
    @Override
    public BaseResult updateStatus(String oid, String update) {
        int count = 0;
        CodeRuleDO codeRuleDO = selectByOid(oid);
        if ("enable".equalsIgnoreCase(update)) {
            if (!CodeRuleLC.DISABLED.getValue().equals(codeRuleDO.getLcStatus())) {
                return BaseResult.fail("非停用状态的编码规则无需点击启用");
            }
            count = codeRuleMapper.updateLcStatus(oid, CodeRuleLC.RELEASED.getValue());
        } else if ("disable".equalsIgnoreCase(update)) {
            if (!CodeRuleLC.RELEASED.getValue().equals(codeRuleDO.getLcStatus())) {
                return BaseResult.fail("非发布状态的编码规则无法停用");
            }
            count = codeRuleMapper.updateLcStatus(oid, CodeRuleLC.DISABLED.getValue());
        } else if ("release".equalsIgnoreCase(update)) {
            if (!CodeRuleLC.EDITING.getValue().equals(codeRuleDO.getLcStatus())) {
                return BaseResult.fail("非编辑状态的编码规则无法发布");
            }
            count = codeRuleMapper.updateLcStatus(oid, CodeRuleLC.RELEASED.getValue());
        } else {
            return BaseResult.fail("暂不支持的操作类型");
        }
        if (count > 0) {
            return BaseResult.success();
        } else {
            return BaseResult.fail("更新状态失败");
        }
    }
    /**
     * 克隆编码规则
     *
     * @param codeRuleDTO 主数据编码规则数据传输对象,oid和ts需要传输
     * @return 主数据编码规则显示对象
     */
    public BaseResult cloneCodeRule_v1(CodeRuleDTO codeRuleDTO) {
        VciBaseUtil.alertNotNull(codeRuleDTO.getOid(), "编码规则主键");
        ClientBusinessObjectOperation operation = new ClientBusinessObjectOperation();
        Map<String, String> conditionMap = new HashMap<>();
        conditionMap.put("pkCodeRule", codeRuleDTO.getOid());
        List<CodeBasicSecDO> basicSecDOS = boService.queryObject(CodeBasicSecDO.class, conditionMap);
        List<String> secOidList = new ArrayList<>();
        for (CodeBasicSecDO secDO : basicSecDOS) {
            secOidList.add(secDO.getOid());
        }
        List<ClientBusinessObject> cboList = new ArrayList<>();
        try {
            ClientBusinessObject templateCbo = operation.readBusinessObjectById(codeRuleDTO.getOid(), MdmBtmTypeConstant.CODE_RULE);
            ClientBusinessObject codeRuleCbo = operation.initBusinessObject(templateCbo.getBtmName());
            String curOid = codeRuleCbo.getOid();
            String curRevisionId = codeRuleCbo.getRevisionid();
            String curNameOid = codeRuleCbo.getNameoid();
            BeanUtilForVCI.copyPropertiesIgnoreCase(templateCbo, codeRuleCbo);
            codeRuleCbo.setOid(curOid);
            codeRuleCbo.setRevisionid(curRevisionId);
            codeRuleCbo.setNameoid(curNameOid);
            codeRuleCbo.setId(templateCbo.getId() + "_copy");
            codeRuleCbo.setName(templateCbo.getName() + "_copy");
            if (!CollectionUtils.isEmpty(secOidList)) {
                ClientBusinessObject[] secCboArr = operation.readBusinessObjectById(secOidList.toArray(new String[0]), MdmBtmTypeConstant.CODE_BASIC_SEC);
                for (ClientBusinessObject cbo : secCboArr) {
                    ClientBusinessObject newSecCbo = operation.initBusinessObject(cbo.getBtmName());
                    String newSecCboOid = newSecCbo.getOid();
                    String newSecCboRevisionId = newSecCbo.getRevisionid();
                    String newSecCboNameOid = newSecCbo.getNameoid();
                    BeanUtilForVCI.copyPropertiesIgnoreCase(cbo, newSecCbo);
                    newSecCbo.setOid(newSecCboOid);
                    newSecCbo.setRevisionid(newSecCboRevisionId);
                    newSecCbo.setNameoid(newSecCboNameOid);
                    newSecCbo.setId(newSecCbo.getId() + "_copy");
                    newSecCbo.setName(newSecCbo.getName() + "_copy");
                    newSecCbo.setAttributeValue("pkCodeRule", codeRuleCbo.getOid());
                    cboList.add(newSecCbo);
                }
            }
            cboList.add(codeRuleCbo);
            ClientBusinessObject[] saveList = operation.batchSaveCreateBuinessObject(cboList.toArray(new ClientBusinessObject[0]));
            if (saveList.length == 0) {
                return BaseResult.fail("克隆出错了……");
            }
        } catch (VCIError vciError) {
            vciError.printStackTrace();
        }
        return BaseResult.success();
    }
    /**
     * 克隆编码规则
     *
     * @param codeRuleDTO 主数据编码规则数据传输对象,oid和ts需要传输
     * @return 主数据编码规则显示对象
     */
    @Override
    public BaseResult cloneCodeRule(CodeRuleDTO codeRuleDTO) {
        VciBaseUtil.alertNotNull(codeRuleDTO, "需要添加的数据对象");
        CodeRuleDO codeRuleDO = new CodeRuleDO();
        BeanUtilForVCI.copyPropertiesIgnoreCase(codeRuleDTO, codeRuleDO);
        WebUtil.setPersistence(false);
        BatchCBO batchInsertCBO = codeRuleMapper.insert(codeRuleDO);
        List<CodeBasicSecDTO> secList = codeRuleDTO.getElements();
        secList.forEach(codeBasicSecDTO -> {
            codeBasicSecDTO.setPkCodeRule(codeRuleDO.getOid());
            KeyValue attrKv = codeBasicSecService.checkAttrNullableBySecType(codeBasicSecDTO);
            if (!"success".equals(attrKv.getKey())) {
                throw new VciBaseException(attrKv.getValue() + "不能为空");
            }
            CodeBasicSecDO codeBasicSecDO = new CodeBasicSecDO();
            BeanUtilForVCI.copyPropertiesIgnoreCase(codeBasicSecDTO, codeBasicSecDO);
            codeBasicSecDO.setOid("");
            codeBasicSecDO.setRevisionOid("");
            codeBasicSecDO.setNameOid("");
            BatchCBO cbo = codeBasicSecMapper.insert(codeBasicSecDO);
            batchInsertCBO.addCreateCbo(cbo.getCreateCboArray()[0]);
        });
        boService.persistenceBatch(batchInsertCBO);
        return BaseResult.success();
    }
    /**
     * 使用主键获取编码规则的内容
     *
     * @param oid 主键
     * @return 规则的显示对象
     */
    @Override
    public CodeRuleVO getObjectHasSecByOid(String oid) {
        CodeRuleDO ruleDO = selectByOid(oid);
        return codeRuleDO2VO(ruleDO, true);
    }
    /**
     * 编码规则清空所有已生成的编码
     *
     * @param oid 编码规则主键
     * @return 执行结果
     */
    @Override
    public BaseResult clearAllCode(String oid) {
        WebUtil.alertNotNull(oid, "编码规则主键");
        Map<String, String> conditionMap = new HashMap<>();
        conditionMap.put("codeRuleOid", oid);
        List<CodeAllCodeDO> codeDOList = boService.queryObject(CodeAllCodeDO.class, conditionMap);
        if (CollectionUtils.isEmpty(codeDOList)) {
            return BaseResult.fail("当前编码规则没有生成编码,无需清空");
        }
        //是否需要进行btm不统一的判断?
        String btmType = codeDOList.get(0).getCreateCodeBtm();
        /*boolean flag = codeDOList.stream().anyMatch(s -> !StringUtils.equalsIgnoreCase(btmType, s.getCreateCodeBtm()));
        if (flag) {
            return BaseResult.fail("当前编码规则生成编码在不同类型下使用过");
        }*/
        //多种类型下的查询
        Set<String> btmTypeSet = codeDOList.stream().filter(s -> {
            return !StringUtils.equalsIgnoreCase(btmType, s.getCreateCodeBtm());
        }).map(s -> s.getCreateCodeBtm()).collect(Collectors.toSet());
        List<ClientBusinessObject> businessDataList = new ArrayList<>();
        if (btmTypeSet.size() > 1) {
            for (String btm : btmTypeSet) {
                String sql = "select COUNT(w.OID) from PLATFORMBTM_" + btm + "  w\n" +
                        "join PLATFORMBTM_" + MdmBtmTypeConstant.CODE_ALL_CODE + " c on w.OID = c.CREATECODEOID\n" +
                        "where c.CREATECODEBTM = '" + btm + "' and c.CODERULEOID = '" + oid + "'" +
                        "and w.ISLASTR = '1' and w.ISLASTV = '1'";
                List<ClientBusinessObject> businessData = boService.queryByOnlySql(sql);
                businessDataList.addAll(businessData);
            }
        }else {
            String sql = "select COUNT(w.OID) from PLATFORMBTM_" + btmType + "  w\n" +
                    "join PLATFORMBTM_" + MdmBtmTypeConstant.CODE_ALL_CODE + " c on w.OID = c.CREATECODEOID\n" +
                    "where c.CREATECODEBTM = '" + btmType + "' and c.CODERULEOID = '" + oid + "'" +
                    "and w.ISLASTR = '1' and w.ISLASTV = '1'";
            List<ClientBusinessObject> businessData = boService.queryByOnlySql(sql);
            businessDataList.addAll(businessData);
        }
        if (CollectionUtils.isEmpty(businessDataList) || StringUtils.isBlank(businessDataList.get(0).getAttributeValue("COUNT(w.OID)"))) {
            //无效查询
            return BaseResult.fail("查询失败");
        } else if (!StringUtils.equalsIgnoreCase("0", businessDataList.get(0).getAttributeValue("COUNT(w.OID)"))) {
            return BaseResult.fail("编码规则生成的编码已在业务数据中应用,不允许清空");
        }
        //没有数据,可以安全删除
        WebUtil.setPersistence(false);
        //删除码值表中的数据,但不够,如果有流水的码段,需要重新计算流水
        conditionMap.clear();
        conditionMap.put("codeRuleOid", oid);
        List<ClientBusinessObject> serialValueList = boService.queryCBO("codeserialvalue", conditionMap);
        BatchCBO batchCBO = boService.batchDelete(codeDOList);
        batchCBO.getDeleteCbos().addAll(serialValueList);
        WebUtil.setPersistence(true);
        boService.persistenceBatch(batchCBO);
        return BaseResult.success();
    }
}