package com.xisc.pm.app.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.xisc.boot.common.feign.pojo.MtUserInfo;
import com.xisc.boot.common.sys.UserClient;
import com.xisc.pm.api.dto.PmCompositeBoardDTO;
import com.xisc.pm.api.dto.PmCompositeSlabCalcDTO;
import com.xisc.pm.api.dto.PmPdMidSplitDTO;
import com.xisc.pm.api.dto.PmPdMidSplitRequestDTO;
import com.xisc.pm.api.dto.PmPdPlateDTO;
import com.xisc.pm.api.dto.PmPdRecDTO;
import com.xisc.pm.api.dto.PmPdSlabDTO;
import com.xisc.pm.api.dto.PmPdSlabOrderDTO;
import com.xisc.pm.api.dto.PmPdSlabSplitDTO;
import com.xisc.pm.api.dto.PmPdSlabSplitRequestDTO;
import com.xisc.pm.api.dto.PmProContFilterRequestDTO;
import com.xisc.pm.api.dto.PmProContFilterResposeDTO;
import com.xisc.pm.api.dto.PmProContYieldDTO;
import com.xisc.pm.api.dto.PmProContYieldRequestDTO;
import com.xisc.pm.api.dto.PmProContYieldResposeDTO;
import com.xisc.pm.api.dto.PmTwoRollInterimRequestDTO;
import com.xisc.pm.api.dto.RuleParamDTO;
import com.xisc.pm.api.dto.ctevent.ProContConsumeDTO;
import com.xisc.pm.app.service.PmCmdSlabService;
import com.xisc.pm.app.service.PmPdRecService;
import com.xisc.pm.app.service.PmPdSlabService;
import com.xisc.pm.app.service.PmProContService;
import com.xisc.pm.app.service.PmRuleCodeService;
import com.xisc.pm.app.service.strategy.FormPlateModeStrategyFactory;
import com.xisc.pm.app.service.strategy.PdMatTypeStrategyFactory;
import com.xisc.pm.app.service.strategy.RuleExecStrategyFactory;
import com.xisc.pm.app.service.strategy.SecondaryDesignHelper;
import com.xisc.pm.app.service.strategy.SecondaryDesignStrategyFactory;
import com.xisc.pm.app.service.strategy.formplatemode.FormPlateModeStrategy;
import com.xisc.pm.app.service.strategy.pdmattype.PdMatTypeStrategy;
import com.xisc.pm.app.service.strategy.pdrule.RuleExecStrategy;
import com.xisc.pm.app.service.strategy.secondarydesign.SecondaryDesignStrategy;
import com.xisc.pm.domain.entity.MmSlab;
import com.xisc.pm.domain.entity.PmCmdCont;
import com.xisc.pm.domain.entity.PmCmdContTra;
import com.xisc.pm.domain.entity.PmCmdLargePlt;
import com.xisc.pm.domain.entity.PmCmdLargePltTra;
import com.xisc.pm.domain.entity.PmCmdSlab;
import com.xisc.pm.domain.entity.PmCmdSlabTra;
import com.xisc.pm.domain.entity.PmCmdSmallPlt;
import com.xisc.pm.domain.entity.PmCmdSmallPltTra;
import com.xisc.pm.domain.entity.PmContMscTech;
import com.xisc.pm.domain.entity.PmPdBlockPos;
import com.xisc.pm.domain.entity.PmPdBlockPosTra;
import com.xisc.pm.domain.entity.PmPdCcSlab;
import com.xisc.pm.domain.entity.PmPdConstBt;
import com.xisc.pm.domain.entity.PmPdContSum;
import com.xisc.pm.domain.entity.PmPdContSumTra;
import com.xisc.pm.domain.entity.PmPdPlate;
import com.xisc.pm.domain.entity.PmPdPlateInfo;
import com.xisc.pm.domain.entity.PmPdSlab;
import com.xisc.pm.domain.entity.PmPdSlabInfo;
import com.xisc.pm.domain.entity.PmPdSlabInfoTra;
import com.xisc.pm.domain.entity.PmPdSlabTra;
import com.xisc.pm.domain.entity.PmProCont;
import com.xisc.pm.domain.entity.PmProContProdTtr;
import com.xisc.pm.domain.entity.PmSlabSpecBt;
import com.xisc.pm.domain.entity.PmSmallPltPos;
import com.xisc.pm.domain.entity.PmSmallPltPosTra;
import com.xisc.pm.domain.repository.MmSlabRepository;
import com.xisc.pm.domain.repository.PmCmdContRepository;
import com.xisc.pm.domain.repository.PmCmdContTraRepository;
import com.xisc.pm.domain.repository.PmCmdLargePltRepository;
import com.xisc.pm.domain.repository.PmCmdLargePltTraRepository;
import com.xisc.pm.domain.repository.PmCmdSlabRepository;
import com.xisc.pm.domain.repository.PmCmdSlabTraRepository;
import com.xisc.pm.domain.repository.PmCmdSmallPltRepository;
import com.xisc.pm.domain.repository.PmCmdSmallPltTraRepository;
import com.xisc.pm.domain.repository.PmContMscTechRepository;
import com.xisc.pm.domain.repository.PmPdBlockPosRepository;
import com.xisc.pm.domain.repository.PmPdBlockPosTraRepository;
import com.xisc.pm.domain.repository.PmPdCcSlabRepository;
import com.xisc.pm.domain.repository.PmPdConstBtRepository;
import com.xisc.pm.domain.repository.PmPdContSumRepository;
import com.xisc.pm.domain.repository.PmPdContSumTraRepository;
import com.xisc.pm.domain.repository.PmPdPlateCutRepository;
import com.xisc.pm.domain.repository.PmPdPlateInfoRepository;
import com.xisc.pm.domain.repository.PmPdPlateRepository;
import com.xisc.pm.domain.repository.PmPdSlabInfoRepository;
import com.xisc.pm.domain.repository.PmPdSlabInfoTraRepository;
import com.xisc.pm.domain.repository.PmPdSlabRepository;
import com.xisc.pm.domain.repository.PmPdSlabTraRepository;
import com.xisc.pm.domain.repository.PmProContProdTtrRepository;
import com.xisc.pm.domain.repository.PmProContRepository;
import com.xisc.pm.domain.repository.PmSlabScrapLenBtRepository;
import com.xisc.pm.domain.repository.PmSlabSpecBtRepository;
import com.xisc.pm.domain.repository.PmSmallPltPosRepository;
import com.xisc.pm.domain.repository.PmSmallPltPosTraRepository;
import com.xisc.pm.domain.vo.MatStatusModifyVO;
import com.xisc.pm.infra.client.EventClient;
import com.xisc.pm.infra.client.MmEventClient;
import com.xisc.pm.infra.constant.Constants;
import com.xisc.pm.infra.constant.Constants.AutoManualFlag;
import com.xisc.pm.infra.constant.Constants.CcType;
import com.xisc.pm.infra.constant.Constants.PdProgram;
import com.xisc.pm.infra.constant.Constants.PdStatusHp;
import com.xisc.pm.infra.constant.Constants.RollDirectCode;
import com.xisc.pm.infra.constant.Constants.StatusCode;
import com.xisc.pm.infra.constant.CtEventConstants;
import com.xisc.pm.infra.constant.PmPlateConstants;
import com.xisc.pm.infra.constant.RuleSetConstants;
import com.xisc.pm.infra.enums.FormPlateMode;
import com.xisc.pm.infra.enums.PdEventType;
import com.xisc.pm.infra.enums.PdMatType;
import com.xisc.pm.infra.enums.PdProdFlag;
import com.xisc.pm.infra.enums.PdRuleItemType;
import com.xisc.pm.infra.enums.PdRuleSetType;
import com.xisc.pm.infra.util.BeanUtils;
import com.xisc.pm.infra.util.DateUtils;
import com.xisc.pm.infra.util.PageUtils;
import com.xisc.pm.infra.util.Utils;
import io.choerodon.core.domain.Page;
import io.choerodon.core.exception.CommonException;
import io.choerodon.core.oauth.CustomUserDetails;
import io.choerodon.core.oauth.DetailsHelper;
import io.choerodon.mybatis.pagehelper.PageHelper;
import io.choerodon.mybatis.pagehelper.domain.PageRequest;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.hzero.boot.platform.code.builder.CodeRuleBuilder;
import org.hzero.boot.platform.code.constant.CodeConstants;
import org.hzero.boot.platform.lov.adapter.LovAdapter;
import org.hzero.boot.platform.lov.dto.LovValueDTO;
import org.hzero.core.base.AopProxy;
import org.hzero.core.base.BaseConstants;
import org.hzero.core.message.Message;
import org.hzero.core.message.MessageAccessor;
import org.hzero.core.redis.RedisHelper;
import org.hzero.mybatis.domian.Condition;
import org.hzero.mybatis.util.Sqls;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 组板板坯表(PmPdSlab)应用服务
 *
 * @author 纪文桃 wentao.ji01@hand-china.com
 * @since 2024-07-31 16:30:31
 */
@Service
public class PmPdSlabServiceImpl implements PmPdSlabService, AopProxy<PmPdSlabService> {
    
    @Autowired
    private PmPdConstBtRepository pmPdConstBtRepository;

    @Autowired
    private PmPdSlabInfoRepository pmPdSlabInfoRepository;
    
    @Autowired
    private CodeRuleBuilder codeRuleBuilder;
    
    @Autowired
    private PmRuleCodeService pmRuleCodeService;
    
    @Autowired
    private PmPdRecService pmPdRecService;
    
    @Autowired
    private RedisHelper redisHelper;
    
    @Autowired
    private PmPdContSumRepository pmPdContSumRepository;
    
    @Autowired
    private PmPdPlateCutRepository pmPdPlateCutRepository;

    @Autowired
    private PmSmallPltPosRepository pmSmallPltPosRepository;
    
    @Autowired
    private PmPdBlockPosRepository pmPdBlockPosRepository;
    
    @Autowired
    private PmSlabSpecBtRepository pmSlabSpecBtRepository ;
    
    @Autowired
    private PmCmdSlabService pmCmdSlabService;

    @Autowired
    private PmPdSlabRepository pmPdSlabRepository;

    @Autowired
    private PmProContRepository pmProContRepository;
    
    @Autowired
    private PmProContProdTtrRepository pmProContProdTtrRepository;

    @Autowired
    private PmContMscTechRepository pmContMscTechRepository;

    @Autowired
    private PmPdPlateRepository pmPdPlateRepository;

    @Autowired
    private PmPdPlateInfoRepository pmPdPlateInfoRepository;
    
    @Autowired
    private PmPdCcSlabRepository pmPdCcSlabRepository;
    
    @Autowired
    private PmCmdSlabRepository pmCmdSlabRepository;

    @Autowired
    private UserClient userClient;
    
    @Autowired
    private EventClient eventClient;
    
    @Autowired
    private PmProContService pmProContService;
    
    @Autowired
    private PmCmdLargePltRepository pmCmdLargePltRepository;
    
    @Autowired
    private MmSlabRepository mmSlabRepository;
    @Autowired
    private MmEventClient mmEventClient;

    @Autowired
    private LovAdapter lovAdapter;

    @Autowired
    private PmCmdContRepository pmCmdContRepository;

    @Autowired
    private PmCmdSmallPltRepository pmCmdSmallPltRepository;

    @Autowired
    private PmPdSlabTraRepository pmPdSlabTraRepository;

    @Autowired
    private PmPdSlabInfoTraRepository pmPdSlabInfoTraRepository;

    @Autowired
    private PmPdBlockPosTraRepository pmPdBlockPosTraRepository;

    @Autowired
    private PmPdContSumTraRepository pmPdContSumTraRepository;

    @Autowired
    private PmSmallPltPosTraRepository pmSmallPltPosTraRepository;

    @Autowired
    private PmCmdSlabTraRepository pmCmdSlabTraRepository;

    @Autowired
    private PmCmdLargePltTraRepository pmCmdLargePltTraRepository;

    @Autowired
    private PmCmdContTraRepository pmCmdContTraRepository;

    @Autowired
    private PmCmdSmallPltTraRepository pmCmdSmallPltTraRepository;

    @Autowired
    protected PmSlabScrapLenBtRepository pmSlabScrapLenBtRepository;

    @Override
    public Page<PmPdSlab> selectList(PageRequest pageRequest, PmPdSlab pmPdSlab) {
        return PageHelper.doPageAndSort(pageRequest, () -> pmPdSlabRepository.selectList(pmPdSlab));
    }

    @Override
    public void saveData(List<PmPdSlab> pmPdSlabs) {
        List<PmPdSlab> insertList = pmPdSlabs.stream().filter(line -> line.getPmPdSlabId() == null)
                .collect(Collectors.toList());
        List<PmPdSlab> updateList = pmPdSlabs.stream().filter(line -> line.getPmPdSlabId() != null)
                .collect(Collectors.toList());
        pmPdSlabRepository.batchInsertSelective(insertList);
        pmPdSlabRepository.batchUpdateByPrimaryKeySelective(updateList);
    }

    /**
     * 填充计算值
     * @param pmPdSlabSplitDTO
     * @param pmPdSlabs
     * @param pmPdSlabInfo
     * @param organizationId
     */
    private void buildPmPdSlabSplitDTO(PmPdSlabSplitDTO pmPdSlabSplitDTO, List<PmPdSlab> pmPdSlabs,
            PmPdSlabInfo pmPdSlabInfo, Long organizationId) {
        long slabDivNo = 0L;
        BigDecimal pdSlabWt = BigDecimal.ZERO;
        BigDecimal tempRemainSlabLen = pmPdSlabSplitDTO.getSlabActLen() == null ? BigDecimal.ZERO
                : pmPdSlabSplitDTO.getSlabActLen();
        
        for (PmPdSlab pmPdSlab : pmPdSlabs) {
            if(StringUtils.isBlank(pmPdSlabSplitDTO.getMscLineNo())) {
                pmPdSlabSplitDTO.setMscLineNo(pmPdSlab.getMscLineNo());
            }
            BigDecimal preCleanSlabLen = pmPdSlab.getPreCleanSlabLen() == null ? BigDecimal.ZERO : pmPdSlab.getPreCleanSlabLen();
            if (pmPdSlab.getSlabDivNo() != null) {
                if (pmPdSlab.getSlabDivNo().intValue() > slabDivNo) {
                    slabDivNo = pmPdSlab.getSlabDivNo().intValue();
                }
                if (pmPdSlab.getSlabDivNo().longValue() == 1L) {
                    pmPdSlabSplitDTO.setSlabDivLen1(preCleanSlabLen);
                } else if (pmPdSlab.getSlabDivNo().longValue() == 2L) {
                    pmPdSlabSplitDTO.setSlabDivLen2(preCleanSlabLen);
                } else if (pmPdSlab.getSlabDivNo().longValue() == 3L) {
                    pmPdSlabSplitDTO.setSlabDivLen3(preCleanSlabLen);
                }
            }
            tempRemainSlabLen = tempRemainSlabLen.subtract(preCleanSlabLen);
            pdSlabWt = pdSlabWt.add(pmPdSlab.getPreCleanSlabWt() == null ? BigDecimal.ZERO : pmPdSlab.getPreCleanSlabWt());
        }
        pmPdSlabSplitDTO.setPdSlabWt(pdSlabWt);
        if (slabDivNo == 0) {
            pmPdSlabSplitDTO.setRemainSlabLen(pmPdSlabSplitDTO.getSlabActLen());
        } else {
            if (pmPdSlabInfo == null) {
                // 如果slabDivNo 不为零，一定有分割信息，对应板坯信息表必须要值
                throw new CommonException("pm.pm_pd_slab_info_001", pmPdSlabSplitDTO.getSlabNo());
            }
            BigDecimal slabCutGap = BigDecimal.valueOf(slabDivNo - 1).multiply(getSlabCutGap(organizationId, pmPdSlabInfo.getMscLineNo()));
            tempRemainSlabLen = tempRemainSlabLen.subtract(slabCutGap);
            pmPdSlabSplitDTO.setRemainSlabLen(tempRemainSlabLen);
        }
    }
    
    private BigDecimal getSlabCutGap(Long organizationId , String mscLineNo) {
        PmPdConstBt pmPdConstBt = new PmPdConstBt();
        pmPdConstBt.setTenantId(organizationId);
        pmPdConstBt.setRollLineNo(Utils.mscLineNoToRoolLineNo(mscLineNo));
        pmPdConstBt = pmPdConstBtRepository.selectOne(pmPdConstBt);
        if (pmPdConstBt == null || pmPdConstBt.getSlabCutGap() == null) {
            // 未查询到组板常数基准表，或者长板坯充当短板坯之间切缝宽度未配置，产线号【{0}】
            throw new CommonException("pm.pm_pd_const_bt_001", mscLineNo);
        }
        return pmPdConstBt.getSlabCutGap() == null ? BigDecimal.ZERO : pmPdConstBt.getSlabCutGap();
    }

    @Override
    public PmPdSlabSplitDTO selectBySlabNo(Long slabId, String slabNo, Long organizationId) {
        if(slabId == null || StringUtils.isBlank(slabNo)) {
            throw new CommonException("pm.pm_pd_slab_info_029");
        }
        // 查询MM_SLAB 信息获取板坯信息
        PmPdSlabSplitDTO pmPdSlabSplitDTO = pmPdSlabRepository.selectMmSlabBySlabId(slabId, organizationId);
        pmPdSlabSplitDTO.setMscLineNo(null);
        // 查询分割信息
        List<PmPdSlab> pmPdSlabs = pmPdSlabRepository.selectListBySlabNo(slabNo, organizationId);
        pmPdSlabSplitDTO.setPmPdSlabs(pmPdSlabs);
        // 查询板坯信息表。第一次查询可能无值
        PmPdSlabInfo pmPdSlabInfo = pmPdSlabInfoRepository.selectBySlabNo(slabNo, organizationId);
        // 填充其他信息
        buildPmPdSlabSplitDTO(pmPdSlabSplitDTO, pmPdSlabs, pmPdSlabInfo, organizationId);
        return pmPdSlabSplitDTO;
    }
    
    private void callMatStatusModify(PmPdSlabInfo pmPdSlabInfo) {
        MatStatusModifyVO matStatusModifyVO = new MatStatusModifyVO();
        matStatusModifyVO.setMatNo(pmPdSlabInfo.getSlabNo());
        matStatusModifyVO.setPpFlag(Constants.PpFlag.SM);
        Map<String, Object> informationMap = new HashMap<>(16);
        informationMap.put("holdCauseCode", Constants.HoldCauseCode.PM01);
        informationMap.put("holdCauseCodeMeaning", "余材板坯组板收池");
        informationMap.put("holdTime", new Date());
        informationMap.put("holdMaker", DetailsHelper.getUserDetails().getUserId());
        informationMap.put("plateLockRegion", "Q77");
        matStatusModifyVO.setMatInformationString(JSONObject.toJSONString(informationMap));
        mmEventClient.matStatusModify(pmPdSlabInfo.getTenantId(), Constants.EventCode.MM_PM_PROD_MANAGEMENT_BLOCKED_IN_PROCESS_MATERIAL,matStatusModifyVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PmPdSlabSplitDTO addSplitInfoBySlabNo(PmPdSlabSplitRequestDTO splitInfoRequest) {
        String key = String.format(PmPlateConstants.SPLIT_PM_PD_SLAB_KEY, splitInfoRequest.getTenantId().toString() , splitInfoRequest.getSlabNo());
        if(redisHelper.hasKey(key)) {
            throw new CommonException("pm.pm_pd_slab_info_018", splitInfoRequest.getSlabNo());
        }
        try {
            redisHelper.strSet(key, "1", 2L, TimeUnit.MINUTES);
            // 查询MM_SLAB 信息获取板坯信息 
            PmPdSlabSplitDTO pmPdSlabSplitDTO = pmPdSlabRepository.selectMmSlabBySlabId(splitInfoRequest.getSlabId(),
                    splitInfoRequest.getTenantId());
            if(pmPdSlabSplitDTO == null) {
                throw new CommonException("pm.pm_pd_slab_info_030" , splitInfoRequest.getSlabNo() == null ? splitInfoRequest.getSlabId().toString() : splitInfoRequest.getSlabNo());
            }
    
            // 查询板坯信息表。第一次查询可能无值
            PmPdSlabInfo pmPdSlabInfo = pmPdSlabInfoRepository.selectBySlabNo(splitInfoRequest.getSlabNo(),
                    splitInfoRequest.getTenantId());
    
            if (pmPdSlabInfo == null) {
                check(pmPdSlabSplitDTO);
                pmPdSlabInfo = buildPmPdSlabInfo(pmPdSlabSplitDTO , splitInfoRequest.getSlabNo() , splitInfoRequest.getMscLineNo() , splitInfoRequest.getTenantId());
                pmPdSlabInfoRepository.insertSelective(pmPdSlabInfo);
                // 轧钢模块“在制品材料管理封锁事件接口"
                callMatStatusModify(pmPdSlabInfo);
 
            } else {
                if (!pmPdSlabInfo.getMscLineNo().equals(splitInfoRequest.getMscLineNo())) {
                    throw new CommonException("pm.pm_pd_slab_info_002", pmPdSlabInfo.getMscLineNo());
                }
            }
            if(Constants.PdStatusHp.PD_STATUS_HP_11.compareTo(pmPdSlabInfo.getPdStatusHp()) < 0) {
                // 板坯【slab_no】组板已确认，不能新增分割
                throw new CommonException("pm.pm_pd_slab_info_015", pmPdSlabInfo.getMscLineNo());
            }
            if(StringUtils.isBlank(pmPdSlabInfo.getPono())) {
                //  (7) 若其PONO为空，返回消息：材料【slab_no】制造命令号为空，不能组板；
                throw new CommonException("pm.pm_pd_slab_info_009", pmPdSlabSplitDTO.getSlabNo());
            }
            String loginName = DetailsHelper.getUserDetails() == null ? "": DetailsHelper.getUserDetails().getUserId().toString();
            if(StringUtils.isNotBlank(pmPdSlabInfo.getPdResp()) && !loginName.equals(pmPdSlabInfo.getPdResp())) {
                // 板坯【slab_no】的组板者为【PD_RESP】，【系统操作员id】不能操作！
                Map<Long, MtUserInfo> mtUserInfoMap = userClient.userInfoBatchGet(splitInfoRequest.getTenantId(),
                        Arrays.asList(Long.parseLong( pmPdSlabInfo.getPdResp()), Long.parseLong(loginName)));
                String loginNameResp = mtUserInfoMap.containsKey(Long.parseLong(pmPdSlabInfo.getPdResp())) ?
                        mtUserInfoMap.get(Long.parseLong(pmPdSlabInfo.getPdResp())).getLoginName(): pmPdSlabInfo.getPdResp();
                String loginNameUser = mtUserInfoMap.containsKey(Long.parseLong(loginName)) ?
                        mtUserInfoMap.get(Long.parseLong(loginName)).getLoginName(): loginName;
                throw new CommonException("pm.pm_pd_slab_info_016", pmPdSlabInfo.getSlabNo() , loginNameResp, loginNameUser);
            }
            // 查询分割信息
            List<PmPdSlab> pmPdSlabs = pmPdSlabRepository.selectListBySlabNo(splitInfoRequest.getSlabNo(),
                    splitInfoRequest.getTenantId());
            for (PmPdSlab pmPdSlab : pmPdSlabs) {
                if(Constants.PdStatusHp.PD_STATUS_HP_11.equals(pmPdSlab.getPdStatusHp())) {
                    // 板坯【slab_no】有尚在组板的分割坯，不能新增分割；
                    throw new CommonException("pm.pm_pd_slab_info_017", pmPdSlabInfo.getSlabNo());
                }
            }

            String virtualSlabNo = pmRuleCodeService.generateCode(splitInfoRequest.getTenantId(),
                    Constants.CodeRule.SPLIT_VIRTUAL_SLAB_NO, pmPdSlabInfo.getPono() + "S", 4);
            
            PmPdSlab pmPdSlab = new PmPdSlab();
            pmPdSlab.setPono(pmPdSlabInfo.getPono());
            pmPdSlab.setSlabDivNo(BigDecimal.valueOf(Long.valueOf(pmPdSlabs.size() + 1L)));
            pmPdSlab.setVirtualSlabNo(virtualSlabNo);
            pmPdSlab.setPdStatusHp(Constants.PdStatusHp.PD_STATUS_HP_11);
            pmPdSlab.setSlabNo(pmPdSlabInfo.getSlabNo());
            pmPdSlab.setTwoRollInterimFlag(pmPdSlabInfo.getTwoRollInterimFlag());
            pmPdSlab.setIngotType(pmPdSlabInfo.getIngotType());
            pmPdSlab.setMscLineNo(splitInfoRequest.getMscLineNo());
            pmPdSlab.setTenantId(splitInfoRequest.getTenantId());
            pmPdSlabRepository.insertSelective(pmPdSlab);
            
            PmPdSlabInfo record = new PmPdSlabInfo();
            record.setPmPdSlabInfoId(pmPdSlabInfo.getPmPdSlabInfoId());
            record.setPdProgram(PdProgram.SLAB_INFO_PD_PROGRAM);
            record.setPdResp(loginName);  
            record.setPdStatusHp(Constants.PdStatusHp.PD_STATUS_HP_11);
            record.setAutoManualFlag(AutoManualFlag.AUTO_MANUA_FLAG_M);
            record.setObjectVersionNumber(pmPdSlabInfo.getObjectVersionNumber());
            record.setPdBeginTime(new Date());
            pmPdSlabInfoRepository.updateByPrimaryKeySelective(record);
            
            pmPdSlabs.add(pmPdSlab);
            pmPdSlabSplitDTO.setPmPdSlabs(pmPdSlabs);
            // 填充其他信息
            buildPmPdSlabSplitDTO(pmPdSlabSplitDTO, pmPdSlabs, pmPdSlabInfo, splitInfoRequest.getTenantId());
            return pmPdSlabSplitDTO;
        } finally {
            redisHelper.delKey(key);
        }
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean removeSplitInfoBySlabNo(PmPdSlabSplitRequestDTO splitInfoRequest) {
        String key = String.format(PmPlateConstants.SPLIT_PM_PD_SLAB_KEY, splitInfoRequest.getTenantId().toString() , splitInfoRequest.getSlabNo());
        if(redisHelper.hasKey(key)) {
            throw new CommonException("pm.pm_pd_slab_info_018", splitInfoRequest.getSlabNo());
        }
        try {
            redisHelper.strSet(key, "1", 2L, TimeUnit.MINUTES);
            PmPdSlabInfo pmPdSlabInfo = pmPdSlabInfoRepository.selectBySlabNo(splitInfoRequest.getSlabNo(),
                    splitInfoRequest.getTenantId());
            
            if(Constants.PdStatusHp.PD_STATUS_HP_12.compareTo(pmPdSlabInfo.getPdStatusHp()) < 0){
                // 虚拟板坯【slab_no】临时命令已生成，不能删除分割
                throw new CommonException("pm.pm_pd_slab_info_019", splitInfoRequest.getSlabNo());
            }
            String loginName = DetailsHelper.getUserDetails() == null ? "": DetailsHelper.getUserDetails().getUserId().toString();
            if(StringUtils.isNotBlank(pmPdSlabInfo.getPdResp()) && !loginName.equals(pmPdSlabInfo.getPdResp())) {
                // 板坯【slab_no】的组板者为【PD_RESP】，【系统操作员id】不能操作！
                Map<Long, MtUserInfo> mtUserInfoMap = userClient.userInfoBatchGet(splitInfoRequest.getTenantId(),
                        Arrays.asList(Long.parseLong( pmPdSlabInfo.getPdResp()), Long.parseLong(loginName)));
                String loginNameResp = mtUserInfoMap.containsKey(Long.parseLong(pmPdSlabInfo.getPdResp())) ?
                        mtUserInfoMap.get(Long.parseLong(pmPdSlabInfo.getPdResp())).getLoginName(): pmPdSlabInfo.getPdResp();
                String loginNameUser = mtUserInfoMap.containsKey(Long.parseLong(loginName)) ?
                        mtUserInfoMap.get(Long.parseLong(loginName)).getLoginName(): loginName;
                throw new CommonException("pm.pm_pd_slab_info_016", pmPdSlabInfo.getSlabNo() , loginNameResp, loginNameUser);
            }
            
            List<PmPdSlab> pmPdSlabs = pmPdSlabRepository.selectListBySlabNo(splitInfoRequest.getSlabNo(),
                    splitInfoRequest.getTenantId());
            List<PmPdSlab> removePmPdSlabs = new ArrayList<PmPdSlab>(splitInfoRequest.getRemovePdSlabIdList().size());
            List<PmPdSlab> sortPmPdSlabs = new ArrayList<PmPdSlab>(splitInfoRequest.getRemovePdSlabIdList().size());
            List<String> removePdMatNo = new ArrayList<>(splitInfoRequest.getRemovePdSlabIdList().size());
            for (PmPdSlab pmPdSlab : pmPdSlabs) {
                if(splitInfoRequest.getRemovePdSlabIdList().contains(pmPdSlab.getPmPdSlabId())) {
                    removePmPdSlabs.add(pmPdSlab);
                    removePdMatNo.add(pmPdSlab.getVirtualSlabNo());
                } else {
                    sortPmPdSlabs.add(pmPdSlab);
                }
            }

            List<PmSmallPltPos> pmSmallPltPosList = pmSmallPltPosRepository.selectByCondition(Condition.builder(PmSmallPltPos.class)
                    .andWhere(Sqls.custom().andIn(PmSmallPltPos.FIELD_PD_MAT_NO, removePdMatNo))
                    .andWhere(Sqls.custom().andEqualTo(PmSmallPltPos.FIELD_TENANT_ID, splitInfoRequest.getTenantId()))
                    .build());

            
            // 组板履历事件11
            List<PmPdContSum> pdPmPdContSums = pmPdContSumRepository.selectByPdMatNoList(splitInfoRequest.getTenantId() , removePdMatNo);
            Map<String , List<PmPdContSum>> contSumMap = pdPmPdContSums.stream().collect(Collectors.groupingBy(PmPdContSum::getPdMatNo));
            PdMatTypeStrategy pdMatTypeStrategy = PdMatTypeStrategyFactory.matchStrategy(PdMatType.S);
            for (Entry<String, List<PmPdContSum>> entry : contSumMap.entrySet()) {
                pdMatTypeStrategy.pdDeleteEvent(entry.getValue(), entry.getKey()
                        , pmPdSlabInfo.getMscLineNo(), Constants.PdProgram.SLAB_DELETED_PD_PROGRAM, splitInfoRequest.getTenantId());
            }
            
            pmPdSlabRepository.batchDeleteByPrimaryKey(removePmPdSlabs);
            pmPdContSumRepository.deleteByMatNo(splitInfoRequest.getTenantId() , removePdMatNo);
            pmPdPlateCutRepository.deleteByMatNo(splitInfoRequest.getTenantId() , removePdMatNo);
            pmSmallPltPosRepository.deleteByMatNo(splitInfoRequest.getTenantId() , removePdMatNo);
            pmPdBlockPosRepository.deleteByMatNo(splitInfoRequest.getTenantId() , removePdMatNo);
            
            if(!sortPmPdSlabs.isEmpty()) {
                long i = 1 ;
                for (PmPdSlab pdSlab : sortPmPdSlabs) {
                    pdSlab.setSlabDivNo(BigDecimal.valueOf(i++));
                }
                // 否则，置板坯信息表该板坯号的厚板组板状态为‘11’。
                PmPdSlabInfo record = new PmPdSlabInfo();
                record.setPmPdSlabInfoId(pmPdSlabInfo.getPmPdSlabInfoId());
                record.setPdStatusHp(Constants.PdStatusHp.PD_STATUS_HP_11);
                record.setObjectVersionNumber(pmPdSlabInfo.getObjectVersionNumber());
                pmPdSlabInfoRepository.updateByPrimaryKeySelective(record);
                pmPdSlabRepository.batchUpdateByPrimaryKeySelective(sortPmPdSlabs);
            } else {
                // 则删除板坯信息表PM_PD_SLAB_INFO该板坯号的记录，
                pmPdSlabInfoRepository.deleteByPrimaryKey(pmPdSlabInfo.getPmPdSlabInfoId());

                 // 轧钢模块“在制品余材释放事件”
                MatStatusModifyVO matStatusModifyVO = new MatStatusModifyVO();
                matStatusModifyVO.setMatNo(pmPdSlabInfo.getSlabNo());
                matStatusModifyVO.setPpFlag(Constants.PpFlag.SM);
                Map<String, Object> informationMap = new HashMap<>(16);
                informationMap.put("holdTime", new Date());
                informationMap.put("holdMaker", DetailsHelper.getUserDetails().getUserId());
                matStatusModifyVO.setMatInformationString(JSONObject.toJSONString(informationMap));
                mmEventClient.matStatusModify(splitInfoRequest.getTenantId(), Constants.EventCode.MM_IN_PROCESS_SUR_MATERIAL_RELEASE,matStatusModifyVO);
            }

            // 将事件标识、材料号（虚拟板坯号拼接小板分割号）、是否有效、产品标记（板坯1）抛合同跟踪组板解散事件
            if (CollectionUtils.isNotEmpty(pmSmallPltPosList)) {
                Map<String ,List<PmSmallPltPos>> pmSmallPltPosListMap = pmSmallPltPosList.stream().collect(Collectors.groupingBy(PmSmallPltPos::getPdMatNo));

                    for (Entry<String, List<PmSmallPltPos>> entry : pmSmallPltPosListMap.entrySet()) {
                        List<ProContConsumeDTO> proContConsumeDTOs = new ArrayList<>();
                        proContConsumeDTOs.add(new ProContConsumeDTO(entry.getKey(), PdProdFlag.VIRTUAL_SLAB.getCode(), BaseConstants.Flag.NO.longValue()));
                        proContConsumeDTOs.add(new ProContConsumeDTO(entry.getKey(), PdProdFlag.VIRTUAL_COMPOSITE_SLAB.getCode(), BaseConstants.Flag.NO.longValue()));
                        for (PmSmallPltPos pmSmallPltPos : entry.getValue()) {
                            proContConsumeDTOs.add(new ProContConsumeDTO(pmSmallPltPos.getPdMatNo() + pmSmallPltPos.getSmallPlateDivNo(), PdProdFlag.SMALL_POS_VIRTUAL_SLAB.getCode(), BaseConstants.Flag.NO.longValue()));
                        }
                        eventClient.addEvent(CtEventConstants.EVENT_PM_CONTRACT_RESIDUE_BOARD_CONSUME, proContConsumeDTOs);
                    }
                    eventClient.sendEvent(splitInfoRequest.getTenantId());
            }
            return true;
        } finally {
            eventClient.remove();
            redisHelper.delKey(key);
        }
    }
    
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @Transactional(rollbackFor = Exception.class)
    public Boolean confirmSplitInfoBySlabNo(PmPdSlabSplitRequestDTO splitInfoRequest) {
        String key = String.format(PmPlateConstants.SPLIT_PM_PD_SLAB_KEY, splitInfoRequest.getTenantId().toString() , splitInfoRequest.getSlabNo());
        if(redisHelper.hasKey(key)) {
            throw new CommonException("pm.pm_pd_slab_info_018", splitInfoRequest.getSlabNo());
        }
        try {
            redisHelper.strSet(key, "1", 2L, TimeUnit.MINUTES);
            PmPdSlabInfo pmPdSlabInfo = pmPdSlabInfoRepository.selectBySlabNo(splitInfoRequest.getSlabNo(),
                    splitInfoRequest.getTenantId());
            String loginName = DetailsHelper.getUserDetails() == null ? "": DetailsHelper.getUserDetails().getUserId().toString();
            if(StringUtils.isNotBlank(pmPdSlabInfo.getPdResp()) && !loginName.equals(pmPdSlabInfo.getPdResp())) {
                // 板坯【slab_no】的组板者为【PD_RESP】，【系统操作员id】不能操作！
                Map<Long, MtUserInfo> mtUserInfoMap = userClient.userInfoBatchGet(splitInfoRequest.getTenantId(),
                        Arrays.asList(Long.parseLong( pmPdSlabInfo.getPdResp()), Long.parseLong(loginName)));
                String loginNameResp = mtUserInfoMap.containsKey(Long.parseLong(pmPdSlabInfo.getPdResp())) ?
                        mtUserInfoMap.get(Long.parseLong(pmPdSlabInfo.getPdResp())).getLoginName(): pmPdSlabInfo.getPdResp();
                String loginNameUser = mtUserInfoMap.containsKey(Long.parseLong(loginName)) ?
                        mtUserInfoMap.get(Long.parseLong(loginName)).getLoginName(): loginName;
                throw new CommonException("pm.pm_pd_slab_info_016", pmPdSlabInfo.getSlabNo() , loginNameResp, loginNameUser);
            }
            if(!Constants.PdStatusHp.PD_STATUS_HP_11.equals(pmPdSlabInfo.getPdStatusHp())){
                // 余材板坯【slab_no】不是组板中状态，不能分割确认！；
                throw new CommonException("pm.pm_pd_slab_info_020", splitInfoRequest.getSlabNo());
            }
            List<PmPdSlab> pmPdSlabs = pmPdSlabRepository.selectListBySlabNo(splitInfoRequest.getSlabNo(),
                    splitInfoRequest.getTenantId());
            if(pmPdSlabs == null || pmPdSlabs.isEmpty()) {
                throw new CommonException("pm.pm_pd_slab_info_021", splitInfoRequest.getSlabNo());
            }
            BigDecimal tmpLen = BigDecimal.ZERO;
            for (PmPdSlab pmPdSlab : pmPdSlabs) {
                if(!Constants.PdStatusHp.PD_STATUS_HP_12.equals(pmPdSlab.getPdStatusHp())){
                    // 余材板坯【slab_no】的分割坯不在组板完成状态，不能分割确认！
                    throw new CommonException("pm.pm_pd_slab_info_021", splitInfoRequest.getSlabNo());
                }
                tmpLen = tmpLen.add(pmPdSlab.getPreCleanSlabLen());
            }
            
            BigDecimal slabCutGap = getSlabCutGap(splitInfoRequest.getTenantId(), pmPdSlabInfo.getMscLineNo()) ;
            BigDecimal allSlabCutGap = BigDecimal.valueOf(pmPdSlabs.size() - 1L).multiply(slabCutGap);
            BigDecimal residueLen = pmPdSlabInfo.getMatActLen().subtract(tmpLen).subtract(allSlabCutGap);
            if(BigDecimal.ZERO.compareTo(residueLen) > 0) {
                // 组板总长度大于实际板坯长度，不能分割确认。组坯长【清理前板坯长度和】，实际长【余坯实际长度】，切缝【SLAB_CUT_GAP】，剩余长【余坯当前的剩余板坯长度】；
                throw new CommonException("pm.pm_pd_slab_info_022", tmpLen.toPlainString() , pmPdSlabInfo.getMatActLen().toPlainString()
                        , slabCutGap.toPlainString() , residueLen.toPlainString());
            }
            PmSlabSpecBt pmSlabSpecBt = pmSlabSpecBtRepository.selectMinSlabLenByPmPdSlabInfo(pmPdSlabInfo);
            if(pmSlabSpecBt == null) {
                // 查询连铸板坯生产规格基准表时无记录，板坯厚度【余坯实际厚度】，板坯宽度【余坯实际宽度】
                throw new CommonException("pm.pm_pd_slab_info_023", pmPdSlabInfo.getMatActThick().toPlainString()
                        , pmPdSlabInfo.getMatActWidth().toPlainString());
            }
            BigDecimal tempLen = residueLen.subtract(slabCutGap).subtract(pmSlabSpecBt.getSlabMinLen());
            // 标记最后一块板
            PmPdSlab lastPmPdSlab = pmPdSlabs.get(pmPdSlabs.size() - 1);
            if(BigDecimal.ZERO.compareTo(tempLen) <= 0) {
                // 新增余材,并标记为最后一块板
                PmPdSlab pmPdSlab = buildPmPdSlab(pmPdSlabInfo  , pmPdSlabs.size() + 1L ,slabCutGap,residueLen,  loginName);
                pmPdSlab.setOrderNoAxis(lastPmPdSlab.getOrderNoAxis());
                pmPdSlabs.add(pmPdSlab);
                pmPdSlabRepository.insertSelective(pmPdSlab);
            } else {
                lastPmPdSlab.setLastSlabFlag(BaseConstants.Flag.YES.longValue());
            }
            PmPdSlabInfo record = new PmPdSlabInfo();
            record.setPmPdSlabInfoId(pmPdSlabInfo.getPmPdSlabInfoId());
            record.setPdEndTime(new Date());
            record.setPdStatusHp(Constants.PdStatusHp.PD_STATUS_HP_12);
            pmPdSlabInfo.setPdStatusHp(Constants.PdStatusHp.PD_STATUS_HP_12);
            record.setObjectVersionNumber(pmPdSlabInfo.getObjectVersionNumber());
            // 生成命令板坯
            if (Constants.PdStatusHp.PD_STATUS_HP_18.equals(pmPdSlabInfo.getPdStatusHp())) {
                throw new CommonException("pm.pm_cmd_slab_001", pmPdSlabInfo.getSlabNo());
            }
            if (!Constants.PdStatusHp.PD_STATUS_HP_12.equals(pmPdSlabInfo.getPdStatusHp())) {
                throw new CommonException("pm.pm_cmd_slab_002", pmPdSlabInfo.getSlabNo());
            }
            for (PmPdSlab pmPdSlab : pmPdSlabs) {
                if (!Constants.PdStatusHp.PD_STATUS_HP_12.equals(pmPdSlab.getPdStatusHp())) {
                    // 材料【虚拟板坯号】不是组板完成状态12，不能生成命令信息；
                    throw new CommonException("pm.pm_cmd_slab_003", pmPdSlab.getVirtualSlabNo());
                }
            }
            pmCmdSlabService.createPmCmdSlab(pmPdSlabInfo , pmPdSlabs, pmPdSlabInfo.getMscLineNo());
            for (PmPdSlab pmPdSlab : pmPdSlabs) {
                    pmPdSlab.setPdStatusHp(Constants.PdStatusHp.PD_STATUS_HP_18);
            }
            this.pmPdSlabRepository.batchUpdateByPrimaryKeySelective(pmPdSlabs);
            // 更新状态为17
            record.setPdStatusHp(Constants.PdStatusHp.PD_STATUS_HP_18);
            this.pmPdSlabInfoRepository.updateByPrimaryKeySelective(record);
            return true;
        } finally {
            redisHelper.delKey(key);
        }
    }
    
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @Transactional(rollbackFor = Exception.class)
    public Boolean singleSlabConfirm(PmPdSlabSplitRequestDTO splitInfoRequest) {
        List<PmPdSlab> pmPdSlabs = pmPdSlabRepository.selectListBySlabNo(splitInfoRequest.getSlabNo(),
                splitInfoRequest.getTenantId());
        if(pmPdSlabs == null || pmPdSlabs.isEmpty()) {
            throw new CommonException("pm.pm_pd_slab_info_021", splitInfoRequest.getSlabNo());
        }
        List<String> virtualSlabNo = new ArrayList<>();
        for (PmPdSlab pmPdSlab : pmPdSlabs) {
            virtualSlabNo.add(pmPdSlab.getVirtualSlabNo());
            // 校验是否分割确认
            if (!Constants.PdStatusHp.PD_STATUS_HP_18.equals(pmPdSlab.getPdStatusHp())) {
                throw new CommonException("pm.pd_slab_004");
            }
        }
        List<PmCmdLargePlt> pmCmdLargePlts = pmCmdLargePltRepository.selectByCondition(Condition.builder(PmCmdLargePlt.class).andWhere(Sqls.custom().andEqualTo(PmCmdLargePlt.FIELD_TENANT_ID,
                splitInfoRequest.getTenantId()).andIn(PmCmdLargePlt.FIELD_TMP_SLAB_NO, virtualSlabNo)).build());
        SecondaryDesignStrategy secondaryDesignStrategy = SecondaryDesignStrategyFactory.matchStrategy(PdMatType.S);
        secondaryDesignStrategy.sampleAddition(splitInfoRequest.getTenantId(), pmCmdLargePlts);
        secondaryDesignStrategy.secondaryDesign(splitInfoRequest.getTenantId(), pmCmdLargePlts);
        secondaryDesignStrategy.commandCreate(splitInfoRequest.getTenantId(), pmCmdLargePlts);
        return true;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void yiledCalcBeforeCheck(PmProContYieldRequestDTO pmProContYield, boolean isExec) {
        PmPdSlab pdSlab = null ;
        if(StringUtils.isNotBlank(pmProContYield.getVirtualSlabNo())) {
            pdSlab = this.pmPdSlabRepository.selectByVirtualSlabNo(pmProContYield.getVirtualSlabNo(), pmProContYield.getTenantId());
            if(pmProContYield.getPmContFilterRequest().getFixSlabLenFlag() != null && pmProContYield.getPmContFilterRequest().getFixSlabLenFlag().longValue() > 0L) {
                if(pmProContYield.getPmContFilterRequest().getFixSlabLen() != null && pmProContYield.getPmContFilterRequest().getRemainSlabLen() != null
                        && pmProContYield.getPmContFilterRequest().getFixSlabLen().compareTo(pmProContYield.getPmContFilterRequest().getRemainSlabLen()) > 0) {
                    // 指定长【{0}】不能大于剩余板坯长【{1}】。
                    throw new CommonException("pm.pm_pd_slab_info_031", pmProContYield.getPmContFilterRequest().getFixSlabLen().toPlainString()
                            ,pmProContYield.getPmContFilterRequest().getRemainSlabLen().toPlainString());
                }
            }
        } else {
            pdSlab = pmProContYield.getPmPdSlab() ;
           
            PmPdSlabInfo pmPdSlabInfo = pmPdSlabInfoRepository.selectBySlabNo(pdSlab.getSlabNo(),
                    pmProContYield.getTenantId());
            if(pmPdSlabInfo == null) {
                MmSlab mmSlab = mmSlabRepository.selectBySlabNo(pdSlab.getSlabNo(), pmProContYield.getTenantId());
                pmProContYield.setSlabAutoAddSplitFlag(true);
                pmProContYield.getPmContFilterRequest().setFixSlabLen(mmSlab.getSlabActLen());
                pmProContYield.getPmContFilterRequest().setFixSlabLenFlag(BaseConstants.Flag.YES.longValue());
            } else {
                throw new CommonException("pm.pm_pro_cont_039");
            }
        }
        if(pdSlab == null) {
            throw new CommonException("pm.pm_pd_slab_info_025");
        }
        if(isExec) {
            if(StringUtils.isBlank(pmProContYield.getVirtualSlabNo())) {
                PmPdSlabInfo pmPdSlabInfo = pmPdSlabInfoRepository.selectBySlabNo(pdSlab.getSlabNo(),
                        pmProContYield.getTenantId());
                if(pmPdSlabInfo == null) {
                    MmSlab mmSlab = mmSlabRepository.selectBySlabNo(pdSlab.getSlabNo(), pmProContYield.getTenantId());
                    PmPdSlabSplitRequestDTO splitInfoRequest = new PmPdSlabSplitRequestDTO();
                    splitInfoRequest.setTenantId(pmProContYield.getTenantId());
                    splitInfoRequest.setSlabId(mmSlab.getSlabId());
                    splitInfoRequest.setSlabNo(pdSlab.getSlabNo());
                    splitInfoRequest.setMscLineNo(pmProContYield.getPmContFilterRequest().getMscLineNo());
                    PmPdSlabSplitDTO pmPdSlabSplitDTO = this.addSplitInfoBySlabNo(splitInfoRequest);
                    pdSlab = pmPdSlabSplitDTO.getPmPdSlabs().get(0);
                    pmProContYield.setVirtualSlabNo(pdSlab.getVirtualSlabNo());
                    pmProContYield.setSlabAutoAddSplitFlag(true);
                    pmProContYield.getPmContFilterRequest().setFixSlabLen(mmSlab.getSlabActLen());
                    pmProContYield.getPmContFilterRequest().setFixSlabLenFlag(BaseConstants.Flag.YES.longValue());
                } else {
                    if (StringUtils.isBlank(pmProContYield.getVirtualSlabNo())) {
                        throw new CommonException("pm.pm_pro_cont_039");
                    }
                }
            }
            if(pdSlab == null || !Constants.PdStatusHp.PD_STATUS_HP_11.equals(pdSlab.getPdStatusHp())) {
                throw new CommonException("pm.pm_pd_slab_info_024", pmProContYield.getVirtualSlabNo());
            }
            String loginName = DetailsHelper.getUserDetails() == null ? "": DetailsHelper.getUserDetails().getUserId().toString();
            if(StringUtils.isNotBlank(pdSlab.getPdResp()) && !loginName.equals(pdSlab.getPdResp())) {
                // 板坯【slab_no】的组板者为【PD_RESP】，【系统操作员id】不能操作！
                Map<Long, MtUserInfo> mtUserInfoMap = userClient.userInfoBatchGet(pmProContYield.getTenantId(),
                        Arrays.asList(Long.parseLong(pdSlab.getPdResp()), Long.parseLong(loginName)));
                String loginNameResp = mtUserInfoMap.containsKey(Long.parseLong(pdSlab.getPdResp())) ?
                        mtUserInfoMap.get(Long.parseLong(pdSlab.getPdResp())).getLoginName(): pdSlab.getPdResp();
                String loginNameUser = mtUserInfoMap.containsKey(Long.parseLong(loginName)) ?
                        mtUserInfoMap.get(Long.parseLong(loginName)).getLoginName(): loginName;
                throw new CommonException("pm.pm_pd_slab_info_016", pdSlab.getSlabNo(), loginNameResp, loginNameUser);
            }
        } else {
            pmProContYield.setVirtualSlabNo(pdSlab.getSlabNo());
        }
        pmProContYield.setPmPdSlab(pdSlab);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PmPdSlab updatePmPdSlab(PmProContYieldRequestDTO pmProContYield, PmContMscTech axisPmContMscTech,
            PmProContProdTtr axisPmProContProdTtr, Map<String, PmProContFilterResposeDTO> filterOrderMap,
            PmProContYieldResposeDTO pmProContYieldRespose, PmCompositeSlabCalcDTO pmCompositeSlabCalc) {
        PmPdSlab pmPdSlab = this.pmPdSlabRepository.selectByVirtualSlabNo(pmProContYield.getVirtualSlabNo() , pmProContYield.getTenantId());
        PmPdSlabInfo pdSlabInfo = pmPdSlabInfoRepository.selectBySlabNo(pmPdSlab.getSlabNo() , pmProContYield.getTenantId());
        // 组装基础对象
        PmPdSlab updatePmpdSlab = buildPmPdSlab(pmProContYield, axisPmContMscTech, axisPmProContProdTtr, filterOrderMap);
        // 填充计算结构
        buildPmPdSlab(updatePmpdSlab, pmProContYield, pmProContYieldRespose, pmCompositeSlabCalc);
        updatePmpdSlab.setSlabPlaceCode(pmPdSlab.getSlabPlaceCode());
        
        updatePmpdSlab.setPmPdSlabId(pmPdSlab.getPmPdSlabId());
        updatePmpdSlab.setObjectVersionNumber(pmPdSlab.getObjectVersionNumber());
        this.pmPdSlabRepository.updateByPrimaryKeySelective(updatePmpdSlab);
        return updatePmpdSlab;
    }
    
    /**
     * 组板校验
     * @param pmPdSlabSplitDTO
     */
    private void check(PmPdSlabSplitDTO pmPdSlabSplitDTO) {
        if(pmPdSlabSplitDTO.getSubBacklogCode() != null && pmPdSlabSplitDTO.getSubBacklogCode().length() > 3
                && !"B2".equals(pmPdSlabSplitDTO.getSubBacklogCode().substring(1, 3)) &&
                !"B3".equals(pmPdSlabSplitDTO.getSubBacklogCode().substring(1, 3))) {
            // 即MM_SLAB的后全程工序代码NEXT_WHOLE_BACKLOG_CODE第二位为‘B’，返回消息：不能收后面有火切小工序的材料【{0}】;
            throw new CommonException("pm.pm_pd_slab_info_003", pmPdSlabSplitDTO.getSlabNo());
        }
        if(!StatusCode.STATUS_CODE_29.equals(pmPdSlabSplitDTO.getSlabStatus())) {
            // (2) 若其SLAB_STATUS不为‘29’，返回消息：材料【{0}】不是在制余材，不能组板；
            throw new CommonException("pm.pm_pd_slab_info_004", pmPdSlabSplitDTO.getSlabNo());
        }
        if("4".equals(pmPdSlabSplitDTO.getComplexDecideCode())) {
            // (3) 若其综判代码COMPLEX_DECIDE_CODE为‘4’，返回消息：材料【slab_no】是废品，不能组板；
            throw new CommonException("pm.pm_pd_slab_info_005", pmPdSlabSplitDTO.getSlabNo());
        }
        if(pmPdSlabSplitDTO.getSlabNo().charAt(0) == 'F' || pmPdSlabSplitDTO.getSlabNo().charAt(0) == 'E' || pmPdSlabSplitDTO.getSlabNo().charAt(0) == 'K') {
            // (4) 若其SLAB_NO首位为‘F’或‘E’，返回消息：材料【slab_no】是复合/叠轧坯，不能组板；
            throw new CommonException("pm.pm_pd_slab_info_006", pmPdSlabSplitDTO.getSlabNo());
        }
        if(StringUtils.isBlank(pmPdSlabSplitDTO.getPono())) {
            //  (7) 若其PONO为空，返回消息：材料【slab_no】制造命令号为空，不能组板；
            throw new CommonException("pm.pm_pd_slab_info_009", pmPdSlabSplitDTO.getSlabNo());
            
        }
        if(StringUtils.isBlank(pmPdSlabSplitDTO.getStNo())) {
            // (8) 若其ST_NO为空，返回消息：材料【slab_no】内部钢种为空，不能组板；
            throw new CommonException("pm.pm_pd_slab_info_010", pmPdSlabSplitDTO.getSlabNo());
        }
        if(pmPdSlabSplitDTO.getSlabActThk() == null || PmPlateConstants.ACCURACY.compareTo(pmPdSlabSplitDTO.getSlabActThk()) >= 0) {
            // (9) 若其SLAB_ACT_THK小于等于0.001，返回消息：材料【slab_no】的厚度为0，不能组板；
            throw new CommonException("pm.pm_pd_slab_info_011", pmPdSlabSplitDTO.getSlabNo());
        }
        if(pmPdSlabSplitDTO.getSlabActWid() == null || PmPlateConstants.ACCURACY.compareTo(pmPdSlabSplitDTO.getSlabActWid()) >= 0) {
            //(10)若其SLAB_ACT_WID小于等于0.001，返回消息：材料【slab_no】的宽度为0，不能组板；
            throw new CommonException("pm.pm_pd_slab_info_012", pmPdSlabSplitDTO.getSlabNo());
        }
        if(pmPdSlabSplitDTO.getSlabActLen() == null || PmPlateConstants.ACCURACY.compareTo(pmPdSlabSplitDTO.getSlabActLen()) >= 0) {
            // (11)若其SLAB_TARG_LEN小于等于0.001，返回消息：材料【slab_no】的长度为0，不能组板；
            throw new CommonException("pm.pm_pd_slab_info_013", pmPdSlabSplitDTO.getSlabNo());
        }
        if(pmPdSlabSplitDTO.getSlabActWgt() == null || PmPlateConstants.ACCURACY.compareTo(pmPdSlabSplitDTO.getSlabActWgt()) >= 0) {
            // (12)若其SLAB_ACT_WGT小于等于0.001且SLAB_GROSS_WGT小于等于0.001，返回消息：材料【slab_no】的重量为0，不能组板；
            throw new CommonException("pm.pm_pd_slab_info_014", pmPdSlabSplitDTO.getSlabNo());
        }
    }

    /**
     * 组装板坯信息表数据
     * @param pmPdSlabSplitDTO
     * @param
     * @return
     */
    private PmPdSlabInfo buildPmPdSlabInfo(PmPdSlabSplitDTO pmPdSlabSplitDTO , String slabNo , String mscLineNo , Long tenantId) {
        PmPdSlabInfo pmPdSlabInfo = BeanUtils.copy(pmPdSlabSplitDTO, PmPdSlabInfo.class);
        pmPdSlabInfo.setOuBacklogCode("3");
        pmPdSlabInfo.setOuBacklogSeq(13L);
        pmPdSlabInfo.setMatStatus(pmPdSlabSplitDTO.getSlabStatus());
//        pmPdSlabInfo.setSlabFlag(pmPdSlabSplitDTO.getSlabFlag());
        pmPdSlabInfo.setSlabFlag("S");
        pmPdSlabInfo.setPdStatusHp(PdStatusHp.PD_STATUS_HP_11);
        pmPdSlabInfo.setAutoManualFlag(Constants.AutoManualFlag.AUTO_MANUA_FLAG_M);
        pmPdSlabInfo.setPrecStNo(pmPdSlabSplitDTO.getPreStNo());
//        pmPdSlabInfo.setFinStNo(finStNo);
        pmPdSlabInfo.setAutoManualFlag(AutoManualFlag.AUTO_MANUA_FLAG_M);
        pmPdSlabInfo.setCanAssignFlag(BaseConstants.Flag.YES.toString());
        pmPdSlabInfo.setMatActThick(pmPdSlabSplitDTO.getSlabActThk());
        pmPdSlabInfo.setMatActLen(pmPdSlabSplitDTO.getSlabActLen());
        pmPdSlabInfo.setMatActWidth(pmPdSlabSplitDTO.getSlabActWid());
        pmPdSlabInfo.setMatActWt(pmPdSlabSplitDTO.getSlabActWgt());
        pmPdSlabInfo.setIngotType(pmPdSlabSplitDTO.getSlabType());
        pmPdSlabInfo.setOldMscLine(pmPdSlabSplitDTO.getMscLineNo());
        pmPdSlabInfo.setSlabNo(slabNo);
        pmPdSlabInfo.setTwoRollInterimFlag(BaseConstants.Flag.NO.longValue());
        pmPdSlabInfo.setTenantId(tenantId);
        // 若MAT_NO首位为‘G’或第三位为‘5’，则为‘A’，否则为‘1’
        String matNo = pmPdSlabSplitDTO.getSlabNo();
        if(matNo.charAt(0) == 'G' || matNo.charAt(2) == '5') {
            pmPdSlabInfo.setCcType("A");
        } else {
            pmPdSlabInfo.setCcType(CcType.TYPE_1);
        }
        pmPdSlabInfo.setMscLineNo(mscLineNo);
        pmPdSlabInfo.setPono(pmPdSlabSplitDTO.getPono());
        pmPdSlabInfo.setPsc(pmPdSlabSplitDTO.getPsc());
        pmPdSlabInfo.setSgSign(pmPdSlabSplitDTO.getSgSign());
        pmPdSlabInfo.setStNo(pmPdSlabSplitDTO.getStNo());
        pmPdSlabInfo.setApn(pmPdSlabSplitDTO.getApn());
        pmPdSlabInfo.setMsc(pmPdSlabSplitDTO.getMsc());
        return pmPdSlabInfo;
    }
    
    /**
     * 基于计算结果填充板坯表信息
     *
     * @param pmProContYieldRespose
     * @param pmCompositeSlabCalc
     */
    @Override
    public void buildPmPdSlab(PmPdSlab pmPdSlab, PmProContYieldRequestDTO pmProContYield,
            PmProContYieldResposeDTO pmProContYieldRespose, PmCompositeSlabCalcDTO pmCompositeSlabCalc) {
        pmPdSlab.setVirtualSlabNo(pmProContYieldRespose.getVirtualSlabNo());
        pmPdSlab.setTenantId(pmProContYield.getTenantId());
        // 清理器板坯宽厚 = 进加热炉板坯宽厚 = 结晶器宽厚
        pmPdSlab.setPreCleanSlabThick(pmProContYield.getPmContFilterRequest().getMoldThick());
        pmPdSlab.setPreCleanSlabWidth(pmProContYield.getPmContFilterRequest().getMoldWidth());
        pmPdSlab.setInfurSlabThick(pmProContYield.getPmContFilterRequest().getMoldThick());
        pmPdSlab.setInfurSlabWid(pmProContYield.getPmContFilterRequest().getMoldWidth());

        pmPdSlab.setPreCleanSlabLen(pmProContYieldRespose.getPreCleanSlabLen());
        pmPdSlab.setPreCleanSlabWt(pmProContYieldRespose.getPreCleanSlabWt());
        pmPdSlab.setInfurSlabLen(pmProContYieldRespose.getInfurSlabLen());
        pmPdSlab.setInfurSlabWt(pmProContYieldRespose.getInfurSlabWt());
        pmPdSlab.setPreCleanSlabMaxLen(pmProContYieldRespose.getPreCleanSlabMaxLen());
        pmPdSlab.setPreCleanSlabMinLen(pmProContYieldRespose.getPreCleanSlabMinLen());
        pmPdSlab.setPreCleanSlabMaxWt(pmProContYieldRespose.getPreCleanSlabMaxWt());
        pmPdSlab.setPreCleanSlabMinWt(pmProContYieldRespose.getPreCleanSlabMinWt());
        pmPdSlab.setInfurSlabMaxLen(pmProContYieldRespose.getInfurSlabMaxLen());
        pmPdSlab.setInfurSlabMinLen(pmProContYieldRespose.getInfurSlabMinLen());
        pmPdSlab.setInfurSlabMaxWt(pmProContYieldRespose.getInfurSlabMaxWt());
        pmPdSlab.setInfurSlabMinWt(pmProContYieldRespose.getInfurSlabMinWt());
        pmPdSlab.setNeedSlabLen(pmProContYieldRespose.getNeedSlabLen());
        pmPdSlab.setNeedSlabWt(pmProContYieldRespose.getNeedSlabWt());
        pmPdSlab.setCommandYield(pmProContYieldRespose.getCommandYield());
        pmPdSlab.setRollYield(pmProContYieldRespose.getRollYield());

        pmPdSlab.setNormYield(pmProContYieldRespose.getNormYield());

        pmPdSlab.setRollWtHp(pmProContYieldRespose.getRollWtHp());

        pmPdSlab.setCombinePlateLen(pmProContYieldRespose.getCombinePlateLen());
        pmPdSlab.setCombinePlateWidth(pmProContYieldRespose.getCombinePlateWidth());
        pmPdSlab.setSampleLenHead(pmCompositeSlabCalc.getSampleLenHead());
        pmPdSlab.setSampleLenMid(pmCompositeSlabCalc.getSampleLenMid());
        pmPdSlab.setSampleLenTail(pmCompositeSlabCalc.getSampleLenTail());

        pmPdSlab.setRollThickTolMax(pmProContYieldRespose.getRollThickTolMax());
        pmPdSlab.setRollThickTolMin(pmProContYieldRespose.getRollThickTolMin());
        pmPdSlab.setHeadCut(pmProContYieldRespose.getHeadCut());
        pmPdSlab.setTailCut(pmProContYieldRespose.getTailCut());
        pmPdSlab.setRollAimLen(pmProContYieldRespose.getLaim());
        pmPdSlab.setRollAimThick(pmProContYieldRespose.getTaim());
        pmPdSlab.setRollAimWidth(pmProContYieldRespose.getWaim());
        pmPdSlab.setBroadMasUseFlag(pmProContYieldRespose.getBroadMasUseFlag());
        pmPdSlab.setEdgerUseFlag(pmProContYieldRespose.getEdgerUseFlag());
        pmPdSlab.setFormMasUseFlag(pmProContYieldRespose.getFormMasUseFlag());
        pmPdSlab.setBroadFlag(pmCompositeSlabCalc.getBroadFlag());
        pmPdSlab.setRsCode(pmCompositeSlabCalc.getRsCode().toString());
        pmPdSlab.setAddSlabFlag(pmProContYieldRespose.getAddSlabFlag() == null ? null : pmProContYieldRespose.getAddSlabFlag().toString());
    }
    
    /**
     * 组装基本信息
     * 
     * @param pmProContYield
     * @param axisPmContMscTech
     * @param axisPmProContProdTtr
     * @param filterOrderMap
     * @return
     */
    @Override
    public PmPdSlab buildPmPdSlab(PmProContYieldRequestDTO pmProContYield, PmContMscTech axisPmContMscTech,
            PmProContProdTtr axisPmProContProdTtr, Map<String, PmProContFilterResposeDTO> filterOrderMap) {
        PmPdSlab pmPdSlab = new PmPdSlab();
        pmPdSlab.setMatDesignKind(pmProContYield.getPmContFilterRequest().getMatDesignKind());
        pmPdSlab.setPdStatusHp(PdStatusHp.PD_STATUS_HP_12);
        pmPdSlab.setPdResp(DetailsHelper.getUserDetails().getUserId().toString());
        pmPdSlab.setFurType(pmProContYield.getPmContFilterRequest().getFurType());
        pmPdSlab.setAutoManualFlag(AutoManualFlag.AUTO_MANUA_FLAG_M);
        if (pmProContYield.getPmContFilterRequest().getFixSlabLenFlag() != null) {
            pmPdSlab.setFixSlabLenFlag(pmProContYield.getPmContFilterRequest().getFixSlabLenFlag());
            if (pmProContYield.getPmContFilterRequest().getFixSlabLenFlag().intValue() == 1) {
                // 指定长
                pmPdSlab.setFixSlabLen(pmProContYield.getPmContFilterRequest().getFixSlabLen());
            } else if(pmProContYield.getPmContFilterRequest().getFixSlabLenFlag().intValue() == 2){
                // 奉送样
                pmPdSlab.setFixSlabLen(pmProContYield.getPmContFilterRequest().getSampleLenGice());
            } else {
                // 不指定长
                pmPdSlab.setFixSlabLen(BigDecimal.ZERO);
            }
        }
        pmPdSlab.setSlabFinishCode(axisPmContMscTech.getSlabFinishCode());
        pmPdSlab.setSlabCleanWtLossRateSt(BigDecimal.ZERO);
        pmPdSlab.setSlabCleanWtLossRateFr(BigDecimal.ZERO);
        
        pmPdSlab.setOrderRemainDiv(BaseConstants.Flag.YES.toString());
        pmPdSlab.setCanDelFlag(BaseConstants.Flag.YES.toString());
        pmPdSlab.setMscLineNo(pmProContYield.getPmContFilterRequest().getMscLineNo());
        pmPdSlab.setHpFlameCleanDiv(axisPmContMscTech.getFlameCleanDiv());
        pmPdSlab.setSlabFinishCode(axisPmContMscTech.getSlabFinishCode());
        
        pmPdSlab.setSgSign(axisPmProContProdTtr.getSgSign());
        Date steelPlanDate = null;
        Date steelLatestDate = null;
        Set<String> ultCode = new TreeSet<>();
        for (PmProContYieldDTO order : pmProContYield.getPmProContYieldList()) {
            PmProContFilterResposeDTO resposeDTO = filterOrderMap.get(order.getOrderNo());
            if (StringUtils.isBlank(pmPdSlab.getUrgOrderFlag()) && resposeDTO.getUrgOrderFlag() != null) {
                pmPdSlab.setUrgOrderFlag(resposeDTO.getUrgOrderFlag().toString());
            }
            if (steelPlanDate == null || (resposeDTO.getSteelPlanDate() != null && steelPlanDate.after(resposeDTO.getSteelPlanDate()))) {
                steelPlanDate = resposeDTO.getSteelPlanDate();
            }
            if (steelLatestDate == null || (resposeDTO.getSteelLatestDate() != null && steelLatestDate.after(resposeDTO.getSteelLatestDate()))) {
                steelLatestDate = resposeDTO.getSteelLatestDate();
            }
            if (StringUtils.isNotBlank(resposeDTO.getErpUtSpec1())) {
                ultCode.add(resposeDTO.getErpUtSpec1());
            }
            if (StringUtils.isNotBlank(resposeDTO.getErpUtSpec2())) {
                 ultCode.add(resposeDTO.getErpUtSpec2());
            }
            if (StringUtils.isNotBlank(resposeDTO.getErpUtSpec3())) {
                 ultCode.add(resposeDTO.getErpUtSpec3());
            }
            if (StringUtils.isBlank(pmPdSlab.getCoolCode()) && StringUtils.isNotBlank(resposeDTO.getCoolCode())) {
                pmPdSlab.setCoolCode(resposeDTO.getCoolCode());
            }
            if (StringUtils.isBlank(pmPdSlab.getUltDetectMethodCode())
                    && StringUtils.isNotBlank(resposeDTO.getUltDetectMethodCode())) {
                pmPdSlab.setUltDetectMethodCode(resposeDTO.getUltDetectMethodCode());
            }
        }
        if(ultCode != null && !ultCode.isEmpty()) {
            pmPdSlab.setUltCode(String.join("@", ultCode));
        }
//        pmPdSlab.setSgDecideTime(null);
//        pmPdSlab.setSlabPlaceCode("");
//        pmPdSlab.setIgMatDesignKind(PdMatType.S.getCode());
//        pmPdSlab.setShpCode(""); 

        pmPdSlab.setAdTypeCode(axisPmContMscTech.getAdTypeCode());
        pmPdSlab.setAdModeCode(axisPmContMscTech.getAdModeCode());
        pmPdSlab.setCtrlRollCode(axisPmContMscTech.getCtrlRollCode());
        pmPdSlab.setWithSideFlag(axisPmProContProdTtr.getProdSideMark());
        pmPdSlab.setCutModeCode(axisPmContMscTech.getCutModeCode());
        pmPdSlab.setOrderThickAxis(axisPmProContProdTtr.getOrderThick());
        pmPdSlab.setOrderNoAxis(axisPmProContProdTtr.getOrderNo());
        pmPdSlab.setFormPlateMode(pmProContYield.getPmContFilterRequest().getFormPlateMode());

        pmPdSlab.setRollDirectCode(axisPmContMscTech.getRollDirectCode());

        pmPdSlab.setStNo(pmProContYield.getPmContFilterRequest().getStNo());
        pmPdSlab.setOutSgNo(pmProContYield.getPmContFilterRequest().getStNo());
        pmPdSlab.setLastSlabFlag(BaseConstants.Flag.NO.longValue());
        return pmPdSlab;
    }
    
    /**
     * 新增余材
     * @param pmPdSlabInfo
     * @param residueLen 
     * @return
     */
    private PmPdSlab buildPmPdSlab(PmPdSlabInfo pmPdSlabInfo , Long slabDivNo , BigDecimal slabCutGap , BigDecimal residueLen, String loginName) {
        Map<String, String> paramsMap = new HashMap<String, String>();
        paramsMap.put("poNo", pmPdSlabInfo.getPono());
        String virtualSlabNo = pmRuleCodeService.generateCode(pmPdSlabInfo.getTenantId(),
                Constants.CodeRule.SPLIT_VIRTUAL_SLAB_NO, pmPdSlabInfo.getPono() + "S", 4);
        
        PmPdSlab pmPdSlab = new PmPdSlab();
        pmPdSlab.setTenantId(pmPdSlabInfo.getTenantId());
        pmPdSlab.setPono(pmPdSlabInfo.getPono());
        pmPdSlab.setTwoRollInterimFlag(pmPdSlabInfo.getTwoRollInterimFlag());
        pmPdSlab.setMscLineNo(pmPdSlabInfo.getMscLineNo());
        pmPdSlab.setVirtualSlabNo(virtualSlabNo);
        pmPdSlab.setPdStatusHp(Constants.PdStatusHp.PD_STATUS_HP_12);
        pmPdSlab.setSlabNo(pmPdSlabInfo.getSlabNo());
        pmPdSlab.setMatDesignKind(PdMatType.S.getCode());
        pmPdSlab.setPdResp(loginName);
        pmPdSlab.setAutoManualFlag(AutoManualFlag.AUTO_MANUA_FLAG_M);
        pmPdSlab.setOrderRemainDiv(BaseConstants.Flag.NO.toString());
        pmPdSlab.setCanDelFlag(BaseConstants.Flag.YES.toString());
        pmPdSlab.setStNo(pmPdSlabInfo.getStNo());
        pmPdSlab.setPreCleanSlabThick(pmPdSlabInfo.getMatActThick());
        pmPdSlab.setPreCleanSlabWidth(pmPdSlabInfo.getMatActWidth());
        pmPdSlab.setPreCleanSlabLen(residueLen.subtract(slabCutGap));
        pmPdSlab.setPreCleanSlabMaxLen(pmPdSlab.getPreCleanSlabLen());
        pmPdSlab.setPreCleanSlabMinLen(pmPdSlab.getPreCleanSlabLen());
//        pmPdSlab.setIgMatDesignKind(PdMatType.S.getCode());
        pmPdSlab.setIngotType(pmPdSlabInfo.getIngotType());
        // 体积
        BigDecimal volume = pmPdSlab.getPreCleanSlabLen().multiply(pmPdSlabInfo.getMatActThick()).multiply(pmPdSlabInfo.getMatActWidth());
        // 立方毫米转化为立方厘米
        volume = volume.divide(PmPlateConstants.CM3_TO_MM3).setScale(PmPlateConstants.TEM_SCALE, RoundingMode.HALF_UP);
        // 体积*密度 再转化为吨；
        BigDecimal wt = volume.multiply(PmPlateConstants.DEFAULT_PROD_DENCITY).divide(PmPlateConstants.GRAM_TO_TON).setScale(PmPlateConstants.WT_SCALE, RoundingMode.HALF_UP);
        pmPdSlab.setPreCleanSlabWt(wt);
        pmPdSlab.setPreCleanSlabMaxWt(wt);
        pmPdSlab.setPreCleanSlabMinWt(wt);
        
        pmPdSlab.setInfurSlabWid(pmPdSlabInfo.getMatActWidth());
        pmPdSlab.setInfurSlabThick(pmPdSlabInfo.getMatActThick());
        pmPdSlab.setInfurSlabLen(pmPdSlab.getPreCleanSlabLen());
        pmPdSlab.setInfurSlabMaxLen(pmPdSlab.getPreCleanSlabLen());
        pmPdSlab.setInfurSlabMinLen(pmPdSlab.getPreCleanSlabLen());
        pmPdSlab.setInfurSlabWt(wt);
        pmPdSlab.setInfurSlabMaxWt(wt);
        pmPdSlab.setInfurSlabMinWt(wt);
        pmPdSlab.setNeedSlabLen(pmPdSlab.getPreCleanSlabLen());
        pmPdSlab.setNeedSlabWt(wt);
        pmPdSlab.setLastSlabFlag(BaseConstants.Flag.YES.longValue());
        pmPdSlab.setFixSlabLenFlag(BaseConstants.Flag.NO.longValue());
        return pmPdSlab;
    }

    @Override
    public PmPdSlabDTO detailQueryList(String virtualSlabNo, Long tenantId) {
        // 根据前端输入的虚拟板坯号，查询组板板坯表（PM_PD_SLAB）中符合条件的数据信息
        List<PmPdSlab> pmPdSlabList = pmPdSlabRepository.selectByCondition(Condition.builder(PmPdSlab.class)
                .andWhere(Sqls.custom().andEqualTo(PmPdSlab.FIELD_VIRTUAL_SLAB_NO, virtualSlabNo))
                .andWhere(Sqls.custom().andEqualTo(PmPdSlab.FIELD_TENANT_ID, tenantId))
                .build());
        if (CollectionUtils.isEmpty(pmPdSlabList)) {
            return null;
        }
        // Ⅱ根据组板板坯表（PM_PD_SLAB）中的板坯号SLAB_NO，查询板坯信息表（PM_PD_SLAB_INFO）中的板坯实际厚度、板坯实际宽度、板坯实际长度、
        // 板坯实际重量；
        PmPdSlab pmPdSlab = pmPdSlabList.get(0);
        List<PmPdSlabInfo> pmPdSlabInfoList = pmPdSlabInfoRepository.selectByCondition(Condition.builder(PmPdSlabInfo.class)
                .andWhere(Sqls.custom().andEqualTo(PmPdSlabInfo.FIELD_SLAB_NO, pmPdSlab.getSlabNo()))
                .andWhere(Sqls.custom().andEqualTo(PmPdSlabInfo.FIELD_TENANT_ID, tenantId))
                .build());
        if (CollectionUtils.isEmpty(pmPdSlabInfoList)) {
            throw new CommonException("pm.pd_slab_001","板坯号", pmPdSlab.getSlabNo(), "板坯信息表");
        }
        PmPdSlabInfo pmPdSlabInfo = pmPdSlabInfoList.get(0);

        // 切缝的取值，是用“产线号”（组板钢板表中已读取）的后两位去匹配“轧制产线号”，读取组板常数基准表(PM_PD_CONST_BT)中的SLAB_CUT_GAP所得。
        if (pmPdSlabInfo.getMscLineNo().length() < 4) {
            throw new CommonException("pm.pd_slab_002",pmPdSlabInfo.getSlabNo());
        }
        List<PmPdConstBt> pmPdConstBtList = pmPdConstBtRepository.selectByCondition(Condition.builder(PmPdConstBt.class)
                .andWhere(Sqls.custom().andEqualTo(PmPdConstBt.FIELD_ROLL_LINE_NO, pmPdSlabInfo.getMscLineNo().substring(2, 4)))
                .andWhere(Sqls.custom().andEqualTo(PmPdConstBt.FIELD_TENANT_ID, tenantId))
                .build());
        if (CollectionUtils.isEmpty(pmPdConstBtList)) {
            throw new CommonException("pm.pd_slab_001","产线号", pmPdSlabInfo.getMscLineNo().substring(2, 4), "组板常数基准表");
        }
        PmPdConstBt pmPdConstBt = pmPdConstBtList.get(0);

        // 计算剩余板坯长度：剩余板坯长度 = 实际板坯长度 - 累计分割坯清理前长度 - (分割坯个数-1)*切缝
        BigDecimal remainSlabLen = pmPdSlabInfo.getMatActLen() == null ? BigDecimal.ZERO : pmPdSlabInfo.getMatActLen();
        BigDecimal slabDivNo = new BigDecimal(0);
        Optional<PmPdSlab> slabDivNoOptional = pmPdSlabList.stream().filter(item->item.getSlabDivNo() != null).max(Comparator.comparing(PmPdSlab::getSlabDivNo));
        if (slabDivNoOptional.isPresent()) {
            slabDivNo = slabDivNoOptional.get().getSlabDivNo();
        }

        PmPdSlabDTO result = new PmPdSlabDTO();
        result.setSlabNo(pmPdSlab.getSlabNo());
        result.setStNo(pmPdSlab.getStNo());
        if (StringUtils.isNotEmpty(pmPdSlab.getPdResp()) && pmPdSlab.getPdResp().matches("\\d+")) {
            MtUserInfo userInfo = userClient.userInfoGet(tenantId, Long.parseLong(pmPdSlab.getPdResp()));
            result.setPdResp(userInfo.getLoginName() + userInfo.getRealName());
        }
        result.setFormPlateMode(pmPdSlab.getFormPlateMode());
        result.setPdStatusHp(pmPdSlab.getPdStatusHp());
        result.setFurType(pmPdSlab.getFurType());
        result.setMatActThick(pmPdSlabInfo.getMatActThick());
        result.setMatActWidth(pmPdSlabInfo.getMatActWidth());
        result.setMatActLen(pmPdSlabInfo.getMatActLen());
        result.setMatActWt(pmPdSlabInfo.getMatActWt());
        result.setNeedSlabLen(pmPdSlab.getNeedSlabLen());
        result.setInfurSlabLen(pmPdSlab.getInfurSlabLen());
        result.setPreCleanSlabLen(pmPdSlab.getPreCleanSlabLen());
        result.setRollDirectCode(pmPdSlab.getRollDirectCode());
        result.setRemainSlabLen(remainSlabLen);
        result.setCombinePlateWidth(pmPdSlab.getCombinePlateWidth());
        result.setCombinePlateLen(pmPdSlab.getCombinePlateLen());
        result.setFixSlabLen(pmPdSlab.getFixSlabLen());
        result.setRollAimThick(pmPdSlab.getRollAimThick());
        result.setRollAimWidth(pmPdSlab.getRollAimWidth());
        result.setRollAimLen(pmPdSlab.getRollAimLen());
        result.setFixSlabLenFlag(pmPdSlab.getFixSlabLenFlag());
        result.setNormYield(pmPdSlab.getNormYield());
        result.setRollYield(pmPdSlab.getRollYield());
        result.setCommandYield(pmPdSlab.getCommandYield());
        result.setSlabCleanWtLossRateFr(pmPdSlab.getSlabCleanWtLossRateFr());
        result.setOrderNoAxis(pmPdSlab.getOrderNoAxis());
        result.setMscLineNo(pmPdSlab.getMscLineNo());


        // 2)	获取输入材料的组板合同信息
        List<PmPdSlabOrderDTO> pmPdSlabOrderDTOList = assembleOrderList(virtualSlabNo, tenantId, pmPdSlab.getMscLineNo());
        result.setPmPdSlabOrderDTOList(pmPdSlabOrderDTOList);

        // 3)	获取输入材料上各组合子板的位置信息
        // 根据前端输入的临时命令板坯号，查询组合子板位置表（PM_PD_BLOCK_POS）
        List<PmPdBlockPos> pmPdBlockPosList = pmPdBlockPosRepository.selectByCondition(Condition.builder(PmPdBlockPos.class)
                .andWhere(Sqls.custom().andEqualTo(PmPdBlockPos.FIELD_PD_MAT_NO, virtualSlabNo))
                .andWhere(Sqls.custom().andEqualTo(PmPdBlockPos.FIELD_TENANT_ID, tenantId))
                .build());
        result.setPmPdBlockPosList(pmPdBlockPosList);
        return result;
    }


    @Override
    public PmPdPlateDTO plateDetailQueryList(String tmpSlabNo, Long tenantId) {
        // 根据临时命令板坯号查询钢板表
        List<PmPdPlate> pmPdPlateList = pmPdPlateRepository.selectByCondition(Condition.builder(PmPdPlate.class)
                .andWhere(Sqls.custom().andEqualTo(PmPdPlate.FIELD_TMP_SLAB_NO, tmpSlabNo))
                .andWhere(Sqls.custom().andEqualTo(PmPdPlate.FIELD_TENANT_ID, tenantId))
                .build());
        // 为空，则返回
        if (CollectionUtils.isEmpty(pmPdPlateList)) {
            return null;
        }
        // 根据板坯号查询钢板信息表
        PmPdPlate pmPdPlate = pmPdPlateList.get(0);
        List<PmPdPlateInfo> pmPdPlateInfoList = pmPdPlateInfoRepository.selectByCondition(Condition.builder(PmPdPlateInfo.class)
                .andWhere(Sqls.custom().andEqualTo(PmPdPlateInfo.FIELD_PLATE_NO, pmPdPlate.getPlateNo()))
                .andWhere(Sqls.custom().andEqualTo(PmPdPlateInfo.FIELD_TENANT_ID, tenantId))
                .build());
        if (CollectionUtils.isEmpty(pmPdPlateInfoList)) {
            throw new CommonException("pm.pd_slab_001","钢板号",  pmPdPlate.getPlateNo(), "钢板信息表");
        }
        PmPdPlateInfo pmPdPlateInfo = pmPdPlateInfoList.get(0);

        // 赋值
        PmPdPlateDTO result = new PmPdPlateDTO();
        result.setPlateNo(pmPdPlate.getPlateNo());
        result.setFormPlateMode(pmPdPlate.getFormPlateMode());
        result.setMatActThick(pmPdPlateInfo.getMatActThick());
        result.setMatActWidth(pmPdPlateInfo.getMatActWidth());
        result.setMatActLen(pmPdPlateInfo.getMatActLen());
        result.setOuBacklogCode(pmPdPlateInfo.getOuBacklogCode());
        if (StringUtils.isNotEmpty(pmPdPlateInfo.getPdResp()) && pmPdPlateInfo.getPdResp().matches("\\d+")) {
            MtUserInfo userInfo = userClient.userInfoGet(tenantId, Long.parseLong(pmPdPlateInfo.getPdResp()));
            result.setPdResp(userInfo.getLoginName() + userInfo.getRealName());
        }
        result.setPdStatusHp(pmPdPlateInfo.getPdStatusHp());
        result.setStNo(pmPdPlate.getStNo());
        result.setSgSign(pmPdPlate.getSgSign());
        result.setCommandYield(pmPdPlate.getCommandYield());
        result.setMscLineNo(pmPdPlateInfo.getMscLineNo());

        // 2)	获取输入材料的组板合同信息
        List<PmPdSlabOrderDTO> pmPdSlabOrderDTOList = assembleOrderList(tmpSlabNo, tenantId, pmPdPlateInfo.getMscLineNo());
        // 获取轴合同号
        if (CollectionUtils.isNotEmpty(pmPdSlabOrderDTOList)) {
            List<PmPdSlabOrderDTO> axisOrderList = pmPdSlabOrderDTOList.stream()
                    .filter(item -> 1 == item.getAxisFlag()).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(axisOrderList)) {
                if (axisOrderList.size() > 1) {
                    throw new CommonException("pm.pd_plate_001",tmpSlabNo);
                } else {
                    result.setOrderNoAxis(axisOrderList.get(0).getOrderNo());
                }
            } else {
                throw new CommonException("pm.pd_plate_002",tmpSlabNo);
            }
        }
        result.setPmPdSlabOrderDTOList(pmPdSlabOrderDTOList);

        // 3)	获取输入材料上各组合子板的位置信息
        // 根据前端输入的临时命令板坯号，查询组合子板位置表（PM_PD_BLOCK_POS）
        List<PmPdBlockPos> pmPdBlockPosList = pmPdBlockPosRepository.selectByCondition(Condition.builder(PmPdBlockPos.class)
                .andWhere(Sqls.custom().andEqualTo(PmPdBlockPos.FIELD_PD_MAT_NO, tmpSlabNo))
                .andWhere(Sqls.custom().andEqualTo(PmPdBlockPos.FIELD_TENANT_ID, tenantId))
                .build());
        result.setPmPdBlockPosList(pmPdBlockPosList);
        return result;
    }

    private List<PmPdSlabOrderDTO> assembleOrderList(String virtualSlabNo, Long tenantId, String mscLineNo) {
        // 根据前端输入的虚拟板坯号，查询组板合同总量表（PM_PD_CONT_SUM）中当前组板材料
        List<PmPdContSum> pdContSumList = pmPdContSumRepository.selectByCondition(Condition.builder(PmPdContSum.class)
                .andWhere(Sqls.custom().andEqualTo(PmPdContSum.FIELD_PD_MAT_NO, virtualSlabNo))
                .andWhere(Sqls.custom().andEqualTo(PmPdContSum.FIELD_TENANT_ID, tenantId))
                .build());
        // 判空
        if (CollectionUtils.isEmpty(pdContSumList)) {
            return Collections.emptyList();
        }

        List<String> orderNoList = pdContSumList.stream().map(PmPdContSum::getOrderNo).distinct().collect(Collectors.toList());
        // 根据当前合同号，读取生产合同主表（PM_PRO_CONT）,获取当前合同的组板工序欠件
        List<PmProCont> pmProContList = pmProContRepository.selectByCondition(Condition.builder(PmProCont.class)
                .andWhere(Sqls.custom().andIn(PmProCont.FIELD_ORDER_NO, orderNoList))
                .andWhere(Sqls.custom().andEqualTo(PmProCont.FIELD_TENANT_ID, tenantId))
                .build());
        Map<String, BigDecimal>  pmProContMap = new HashMap<>(pmProContList.size());
        if (CollectionUtils.isNotEmpty(pmProContList)) {
            pmProContMap = pmProContList.stream().collect(Collectors.toMap(PmProCont::getOrderNo, PmProCont::getPdLackQty));
        }

        // 当前合同的合同号与产线号，读取生产合同产品属性表（PM_PRO_CONT_PROD_ATTR）的订货厚度、订货宽度、订货长度、订货长度下限、订货长度上限、内部钢种。
        List<PmProContProdTtr> pmProContProdTtrList = pmProContProdTtrRepository.selectByCondition(Condition.builder(PmProContProdTtr.class)
                .andWhere(Sqls.custom().andIn(PmProContProdTtr.FIELD_ORDER_NO, orderNoList))
                .andWhere(Sqls.custom().andEqualTo(PmProContProdTtr.FIELD_TENANT_ID, tenantId))
                .build());
        Map<String, PmProContProdTtr>  pmProContProdTtrMap = new HashMap<>(pmProContProdTtrList.size());
        if (CollectionUtils.isNotEmpty(pmProContProdTtrList)) {
            pmProContProdTtrMap = pmProContProdTtrList.stream()
                    .collect(Collectors.toMap(PmProContProdTtr::getOrderNo, Function.identity()));
        }

        // 查询合同产线工艺表获取stNo
        List<PmContMscTech> pmContMscTecheList = pmContMscTechRepository.selectByCondition(Condition.builder(PmContMscTech.class)
                .andWhere(Sqls.custom().andEqualTo(PmContMscTech.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andIn(PmContMscTech.FIELD_ORDER_NO, orderNoList))
                .andWhere(Sqls.custom().andEqualTo(PmContMscTech.FIELD_MSC_LINE_NO, mscLineNo))
                .build());
        Map<String, String> pmContMscTecheMap = new HashMap<>(pmContMscTecheList.size());
        if (CollectionUtils.isNotEmpty(pmContMscTecheList)) {
            pmContMscTecheMap = pmContMscTecheList.stream()
                    .collect(Collectors.toMap(item -> Strings.concat(item.getOrderNo(), item.getMscLineNo()),PmContMscTech::getStNo));
        }

        // 组装合同数据
        List<PmPdSlabOrderDTO> pmPdSlabOrderDTOList = new ArrayList<>();
        for (PmPdContSum pmPdContSum : pdContSumList) {
            PmPdSlabOrderDTO pmPdSlabOrderDTO = new PmPdSlabOrderDTO();
            pmPdSlabOrderDTO.setOrderNo(pmPdContSum.getOrderNo());
            pmPdSlabOrderDTO.setAxisFlag(pmPdContSum.getAxisFlag());
            if (!pmProContMap.isEmpty()) {
                pmPdSlabOrderDTO.setPdLackQty(pmProContMap.getOrDefault(pmPdContSum.getOrderNo(), null));
            }
            pmPdSlabOrderDTO.setSmallPlateThick(pmPdContSum.getSmallPlateThick());
            pmPdSlabOrderDTO.setSmallPlateWidth(pmPdContSum.getSmallPlateWidth());
            pmPdSlabOrderDTO.setSmallPlateLen(pmPdContSum.getSmallPlateLen());
            if (!pmProContProdTtrMap.isEmpty() && pmProContProdTtrMap.containsKey(pmPdContSum.getOrderNo())) {
                PmProContProdTtr pmProContProdTtr = pmProContProdTtrMap.get(pmPdContSum.getOrderNo());
                pmPdSlabOrderDTO.setOrderThick(pmProContProdTtr.getOrderThick());
                pmPdSlabOrderDTO.setOrderWidth(pmProContProdTtr.getOrderWidth());
                pmPdSlabOrderDTO.setOrderLen(pmProContProdTtr.getOrderLen());
                pmPdSlabOrderDTO.setOrderLenMin(pmProContProdTtr.getOrderMinLen());
                pmPdSlabOrderDTO.setOrderLenMax(pmProContProdTtr.getOrderMaxLen());
            }
            if (!pmContMscTecheMap.isEmpty()) {
                pmPdSlabOrderDTO.setStNo(pmContMscTecheMap.getOrDefault(Strings.concat(pmPdContSum.getOrderNo(), mscLineNo), null));
            }
            pmPdSlabOrderDTOList.add(pmPdSlabOrderDTO);
        }
        return pmPdSlabOrderDTOList;
    }

    @Override
    public String addMidSplit(PmPdMidSplitRequestDTO splitInfoRequest) {
        if(StringUtils.isBlank(splitInfoRequest.getMscLineNo())) {
            throw new CommonException("pm.pm_pd_slab_38");
        }
        String virtualSlabNo = splitInfoRequest.getVirtualSlabNo();
        // 如果中间坯的虚拟板坯号为空，新增一个
        if(StringUtils.isBlank(splitInfoRequest.getVirtualSlabNo())) {
            // 钢锭
            if ("A".equals(splitInfoRequest.getIgMatDesignKind())) {
                // 如果中间坯的虚拟板坯号为空，新增一个
                Map<String, String> paramsMap = new HashMap<>(1);
                paramsMap.put("month", DateUtils.getCurrentMonthOneChar());
                virtualSlabNo = codeRuleBuilder.generateCode(splitInfoRequest.getTenantId(), Constants.CodeRule.IG_VIRTUAL_SLAB_NO,
                        CodeConstants.CodeRuleLevelCode.GLOBAL, Constants.CodeRule.GLOBAL_LEVEL_VALUE, paramsMap);
            } else {
                // 二次开坯
                Map<String, String> paramsMap = new HashMap<>(1);
                paramsMap.put("month", DateUtils.getCurrentMonthOneChar());
                virtualSlabNo = codeRuleBuilder.generateCode(splitInfoRequest.getTenantId(), Constants.CodeRule.MID_VIRTUAL_SLAB_NO,
                        CodeConstants.CodeRuleLevelCode.GLOBAL, Constants.CodeRule.GLOBAL_LEVEL_VALUE, paramsMap);
            }
        }
        String key = String.format(PmPlateConstants.MID_SPLIT_PM_PD_SLAB_KEY, splitInfoRequest.getTenantId().toString() , virtualSlabNo);
        if(redisHelper.hasKey(key)) {
            throw new CommonException("pm.pm_pd_slab_33", virtualSlabNo);
        }
        try {
            CustomUserDetails userDetails = DetailsHelper.getUserDetails();
            redisHelper.strSet(key, "1", 2L, TimeUnit.MINUTES);
            PmPdCcSlab pmPdCcSlab = null;
            List<PmPdSlab> pmPdSlabs = null ;

            if (StringUtils.isNotEmpty(splitInfoRequest.getVirtualSlabNo())) {
                // 如果中间坯号不为空，但是查询不到记录，说明该中间坯已经被删除了，此时认为是第一次新增分割
                pmPdCcSlab = pmPdCcSlabRepository.selectByPdMatNo(splitInfoRequest.getTenantId(), splitInfoRequest.getVirtualSlabNo());
            }
            if(StringUtils.isBlank(splitInfoRequest.getVirtualSlabNo()) || pmPdCcSlab == null) {
                PdMatType pdMatType = PdMatType.getByCode(splitInfoRequest.getMatDesignKind());
                int count = pmPdCcSlabRepository.selectCountByCondition(Condition.builder(PmPdCcSlab.class).andWhere(Sqls.custom()
                        .andEqualTo(PmPdCcSlab.FIELD_PD_RESP, userDetails == null ? "" : userDetails.getUserId().toString())
                        .andEqualTo(PmPdCcSlab.FIELD_TWO_ROLL_INTERIM_FLAG, BaseConstants.Flag.YES)
                        .andEqualTo(PmPdCcSlab.FIELD_PD_STATUS_HP, Constants.PdStatusHp.PD_STATUS_HP_11)
                        .andEqualTo(PmPdCcSlab.FIELD_MAT_DESIGN_KIND, PdMatType.C.getCode())
                        .andEqualTo(PmPdCcSlab.FIELD_IG_MAT_DESIGN_KIND, pdMatType.getActualPdMatType())
                        .andEqualTo(PmPdCcSlab.FIELD_TENANT_ID, splitInfoRequest.getTenantId())).build());
                if(count > 0) {
                    // 用户【userid】有尚在组板的中间坯，不能新增中间坯与分割
                    throw new CommonException("pm.pm_pd_slab_30", userDetails == null ? "" : userDetails.getUserId().toString());
                } 
                pmPdCcSlab = new PmPdCcSlab(); 
                pmPdCcSlab.setPdResp(userDetails == null ? "" : userDetails.getUserId().toString());
                pmPdCcSlab.setPdStatusHp(Constants.PdStatusHp.PD_STATUS_HP_11);
                pmPdCcSlab.setAutoManualFlag(Constants.AutoManualFlag.AUTO_MANUA_FLAG_M);
                pmPdCcSlab.setVirtualSlabNo(virtualSlabNo);
                pmPdCcSlab.setTwoRollInterimFlag(BaseConstants.Flag.YES.longValue());
                pmPdCcSlab.setMatDesignKind(PdMatType.C.getCode());
                pmPdCcSlab.setIgMatDesignKind(pdMatType.getActualPdMatType());
                pmPdCcSlab.setFormPlateMode(FormPlateMode.A1.getCode());
                pmPdCcSlab.setPickModeLenDir(BaseConstants.Flag.YES.longValue());
                pmPdCcSlab.setPickModeWidDir(BaseConstants.Flag.YES.longValue());
                pmPdCcSlab.setHeadCut(BigDecimal.ZERO);
                pmPdCcSlab.setTailCut(BigDecimal.ZERO);
//                pmPdCcSlab.setHeadCut(BigDecimal.valueOf(30L));
//                pmPdCcSlab.setTailCut(BigDecimal.valueOf(30L));
                pmPdCcSlab.setRollDirectCode(Constants.RollDirectCode.L);
                pmPdCcSlab.setFurType(PmPlateConstants.FUR_TYPR_C);
                pmPdCcSlab.setSlabCleanWtLossRateSt(BigDecimal.ZERO);
                pmPdCcSlab.setSlabCleanWtLossRateFr(BigDecimal.ZERO);
                pmPdCcSlab.setFixSlabLen(BigDecimal.ZERO);
                pmPdCcSlab.setFixSlabLenFlag(BaseConstants.Flag.NO.longValue());
                pmPdCcSlab.setCcType(Constants.CcType.TYPE_1);
                pmPdCcSlab.setCanDelFlag(BaseConstants.Flag.YES.toString());
                pmPdCcSlab.setOrderRemainDiv(BaseConstants.Flag.YES.toString());
                pmPdCcSlab.setMscLineNo(splitInfoRequest.getMscLineNo()); 
                pmPdCcSlab.setTenantId(splitInfoRequest.getTenantId());
                pmPdCcSlabRepository.insertSelective(pmPdCcSlab);
                splitInfoRequest.setVirtualSlabNo(virtualSlabNo);
            } else {
//                pmPdCcSlab = pmPdCcSlabRepository.selectByPdMatNo(splitInfoRequest.getTenantId(), splitInfoRequest.getVirtualSlabNo());
                if(Constants.PdStatusHp.PD_STATUS_HP_11.compareTo(pmPdCcSlab.getPdStatusHp()) < 0) {
                    // 中间坯【mid_virtual_slab_no】组板已确认，不能新增分割
                    throw new CommonException("pm.pm_pd_slab_31", splitInfoRequest.getVirtualSlabNo());
                }
                pmPdSlabs = pmPdSlabRepository.selectListBySlabNo(splitInfoRequest.getVirtualSlabNo() ,splitInfoRequest.getTenantId());
                if(pmPdSlabs != null && !pmPdSlabs.isEmpty() && Constants.PdStatusHp.PD_STATUS_HP_31.equals(pmPdSlabs.get(pmPdSlabs.size() - 1).getPdStatusHp())) {
                    // 板坯【mid_virtual_slab_no】有尚在组板的分割坯，不能新增分割；
                    throw new CommonException("pm.pm_pd_slab_32", splitInfoRequest.getVirtualSlabNo());
                }
            }
            Long divNo = pmPdSlabs == null ? 1L : pmPdSlabs.size() + 1L;
            String midSplitVirtualSlabNoPrefix = virtualSlabNo.substring(0, 7) + "C";
            String splitVirtualSlabNo = pmRuleCodeService.generateCode(splitInfoRequest.getTenantId(), Constants.CodeRule.MID_SPLIT_VIRTUAL_SLAB_NO , midSplitVirtualSlabNoPrefix , 4);
            PmPdSlab pmPdSlab = new PmPdSlab();
            pmPdSlab.setVirtualSlabNo(splitVirtualSlabNo);
            pmPdSlab.setSlabNo(virtualSlabNo);
            pmPdSlab.setPdResp(userDetails == null ? "" : userDetails.getUserId().toString());
            pmPdSlab.setPdStatusHp(Constants.PdStatusHp.PD_STATUS_HP_31);
            pmPdSlab.setIngotType(" ");
            pmPdSlab.setStNo(splitInfoRequest.getStNo());
            pmPdSlab.setInfurSlabThick(splitInfoRequest.getMoldThick());
            pmPdSlab.setInfurSlabWid(splitInfoRequest.getMoldWidth());
            pmPdSlab.setMscLineNo(splitInfoRequest.getMscLineNo());
            pmPdSlab.setTwoRollInterimFlag(BaseConstants.Flag.YES.longValue());
            pmPdSlab.setTenantId(splitInfoRequest.getTenantId());
            pmPdSlabRepository.insertSelective(pmPdSlab);
            return virtualSlabNo;
        } finally {
            redisHelper.delKey(key);
        }
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean midSplitConfirm(PmPdMidSplitRequestDTO splitInfoRequest) {
        if(splitInfoRequest.getMoldThick() == null || splitInfoRequest.getMoldWidth() == null) {
            throw new CommonException("pm.pm_pd_slab_39");
        }
        String key = String.format(PmPlateConstants.SPLIT_PM_PD_SLAB_KEY, splitInfoRequest.getTenantId().toString() , splitInfoRequest.getVirtualSlabNo());
        if(redisHelper.hasKey(key)) {
            throw new CommonException("pm.pm_pd_slab_33", splitInfoRequest.getVirtualSlabNo());
        }
        try {
            redisHelper.strSet(key, "1", 2L, TimeUnit.MINUTES);
            PmPdCcSlab pmPdCcSlab = pmPdCcSlabRepository.selectByPdMatNo(splitInfoRequest.getTenantId(), splitInfoRequest.getVirtualSlabNo());
            String loginName = DetailsHelper.getUserDetails() == null ? "": DetailsHelper.getUserDetails().getUserId().toString();
            if(StringUtils.isNotBlank(pmPdCcSlab.getPdResp()) && !loginName.equals(pmPdCcSlab.getPdResp())) {
                // 中间坯【mid_virtual_slab_no】的组板责任者为【PD_RESP】，与当前操作人员不符；
                Map<Long, MtUserInfo> mtUserInfoMap = userClient.userInfoBatchGet(splitInfoRequest.getTenantId(),
                        Arrays.asList(Long.parseLong(pmPdCcSlab.getPdResp()), Long.parseLong(loginName)));
                String loginNameResp = mtUserInfoMap.containsKey(Long.parseLong(pmPdCcSlab.getPdResp())) ?
                        mtUserInfoMap.get(Long.parseLong(pmPdCcSlab.getPdResp())).getLoginName(): pmPdCcSlab.getPdResp();
                String loginNameUser = mtUserInfoMap.containsKey(Long.parseLong(loginName)) ? mtUserInfoMap.get(Long.parseLong(loginName)).getLoginName(): loginName;
                throw new CommonException("pm.pm_pd_slab_35", splitInfoRequest.getVirtualSlabNo() , loginNameResp, loginNameUser);
            }
            if(!Constants.PdStatusHp.PD_STATUS_HP_11.equals(pmPdCcSlab.getPdStatusHp())) {
                // 中间坯【mid_virtual_slab_no】不是组板中状态，不能分割确认！
                throw new CommonException("pm.pm_pd_slab_36", splitInfoRequest.getVirtualSlabNo());
            }
            // 生产连铸板坯信息
            PmPdCcSlab pmPdCcSlabUpdate = buildPmPdCcSlab(splitInfoRequest, pmPdCcSlab, loginName);
            // 校验
            if ("A".equals(splitInfoRequest.getIgMatDesignKind())) {
                // 查询锭坯型对应值
                List<LovValueDTO> lovValueDTOList = lovAdapter.queryLovValue(Constants.LovCode.INGOT_TYPE, splitInfoRequest.getTenantId())
                        .stream().filter(item -> splitInfoRequest.getIngotType().equals(item.getValue())).collect(Collectors.toList());
                BigDecimal result = new BigDecimal(lovValueDTOList.get(0).getMeaning());
                if ( pmPdCcSlabUpdate.getInfurSlabWt().compareTo(result) > 0) {
                    throw new CommonException("pm.pd_cc_slab_009",pmPdCcSlabUpdate.getInfurSlabWt(),splitInfoRequest.getIngotType(), result);
                }
            } else {
                if(pmPdCcSlabUpdate.getPreCleanSlabLen().compareTo(BigDecimal.valueOf(2200)) < 0) {
                    throw new CommonException("pm.pd_cc_slab_010",pmPdCcSlabUpdate.getPreCleanSlabLen().toPlainString());
                }
                midConfirmCheckRuleSet(pmPdCcSlab,pmPdCcSlabUpdate, splitInfoRequest);
            }
            pmPdCcSlabRepository.updateByPrimaryKeySelective(pmPdCcSlabUpdate);
            
            return Boolean.TRUE;
        } finally {
            redisHelper.delKey(key);
        }
    }
    
    private PmPdContSum buildMidPmPdContSum(Long tenantId , PmSmallPltPos pmSmallPltPosFirst , String pdMatNo , Long orderSeqNo , Long axisFlag) {
        PmPdContSum pmPdContSum = new PmPdContSum();
        pmPdContSum.setTenantId(pmSmallPltPosFirst.getTenantId());
        pmPdContSum.setOrderNo(pmSmallPltPosFirst.getOrderNo());
        pmPdContSum.setPdMatNo(pdMatNo);
        pmPdContSum.setPdMatType(PdMatType.C.getActualPdMatType());
        pmPdContSum.setProContId(pmSmallPltPosFirst.getProContId());
        pmPdContSum.setAxisFlag(axisFlag);
        pmPdContSum.setPdStatus(Constants.PdStatusHp.PD_STATUS_HP_12);
        pmPdContSum.setOrderThick(pmSmallPltPosFirst.getOrderThick());
        pmPdContSum.setOrderWidth(pmSmallPltPosFirst.getOrderWidth());
        pmPdContSum.setOrderLen(pmSmallPltPosFirst.getOrderLen());
        pmPdContSum.setOrderLenMax(pmSmallPltPosFirst.getOrderLenMax());
        pmPdContSum.setOrderLenMin(pmSmallPltPosFirst.getOrderLenMin());
        pmPdContSum.setSmallPlateLen(pmSmallPltPosFirst.getSmallPlateLen());
        pmPdContSum.setSmallPlateThick(pmSmallPltPosFirst.getSmallPlateThick());
        pmPdContSum.setSmallPlateWidth(pmSmallPltPosFirst.getSmallPlateWidth());
        return pmPdContSum;
    }
    
    private void createPlatePosAndContInfo(PmPdCcSlab pmPdCcSlabUpdate, List<PmSmallPltPos> pmSmallPltPos , String pdMatNo) {
        // 如果不在标记中，则需要添加到组板子板位置表 和合同总量表中
        PmSmallPltPos pmSmallPltPosFirst = pmSmallPltPos.get(0);
        for (PmSmallPltPos pmSmallPltPos2 : pmSmallPltPos) {
            if(pmSmallPltPos2.getOrderNo().equals(pmPdCcSlabUpdate.getOrderNoAxis())) {
                pmSmallPltPosFirst = pmSmallPltPos2;
            }
        }
        PmPdBlockPos pmPdBlockPos = new PmPdBlockPos();
        pmPdBlockPos.setPdMatNo(pdMatNo);
        pmPdBlockPos.setOrderBlockNo(1L);
        pmPdBlockPos.setOrderNo(pmSmallPltPosFirst.getOrderNo());
        pmPdBlockPos.setOrderSeqNo(1L);
        pmPdBlockPos.setBlockPlateNum(BigDecimal.valueOf(pmSmallPltPos.size()));
        pmPdBlockPos.setProContId(pmSmallPltPosFirst.getProContId());
        pmPdBlockPos.setTenantId(pmSmallPltPosFirst.getTenantId());

        List<PmPdContSum> pmPdContSums = new ArrayList<>();

        List<PmSmallPltPos> pmSmallPltPosInserts = new ArrayList<>();
        long orderSeqNo = 1L;
        Map<String , PmPdContSum> pmPdContSumMaps = Maps.newHashMap();
        long i = 1 ;
        Set<String> orderSet = new HashSet<>();
        for (PmSmallPltPos pmSmallPltPosDb : pmSmallPltPos) {
            PmSmallPltPos pmSmallPltPosInsert = BeanUtils.copy(pmSmallPltPosDb, PmSmallPltPos.class);
            pmSmallPltPosInsert.setTenantId(pmSmallPltPosFirst.getTenantId());
            pmSmallPltPosInsert.setPdMatNo(pdMatNo);
            pmSmallPltPosInsert.setProContId(pmSmallPltPosDb.getProContId());
            pmSmallPltPosInsert.setPickModeLenDir(i++);
            pmSmallPltPosInsert.setPickModeWidDir(1L);
            pmSmallPltPosInsert.setSmallPlateDivNo(pmSmallPltPosDb.getSmallPlateDivNo());
            pmSmallPltPosInsert.setPsppId(null);
            pmSmallPltPosInsert.setSlabNo(pdMatNo);
            pmSmallPltPosInserts.add(pmSmallPltPosInsert);
            orderSet.add(pmSmallPltPosDb.getOrderNo());
            if(pmPdContSumMaps.containsKey(pmSmallPltPosDb.getOrderNo())) {
                PmPdContSum pmPdContSum = pmPdContSumMaps.get(pmSmallPltPosDb.getOrderNo());
            } else {
                Long axisFlag = 0L;
                if(pmSmallPltPosDb.getOrderNo().equals(pmPdCcSlabUpdate.getOrderNoAxis())) {
                    axisFlag = 1L;
                }
                PmPdContSum pmPdContSum = buildMidPmPdContSum(pmSmallPltPosDb.getTenantId(), pmSmallPltPosDb, pdMatNo, orderSeqNo, axisFlag);
                pmPdContSumMaps.put(pmSmallPltPosDb.getOrderNo(), pmPdContSum);
                pmPdContSums.add(pmPdContSum);
            }
        }
        pmPdCcSlabUpdate.setOrderNumInPlate(orderSet.size() + 0L);
        
        pmPdContSumRepository.batchInsertSelective(pmPdContSums);
        pmSmallPltPosRepository.batchInsertSelective(pmSmallPltPosInserts);
        pmPdBlockPosRepository.insertSelective(pmPdBlockPos);
    }
    
    private void midConfirmCheckRuleSet(PmPdCcSlab pmPdCcSlab,PmPdCcSlab updatePmPdCcSlab,  PmPdMidSplitRequestDTO splitInfoRequest ) {
        RuleParamDTO ruleParam = new RuleParamDTO(PdRuleSetType.C05);
        ruleParam.setTenantId(pmPdCcSlab.getTenantId());
        Map<String, Object> bizData = new HashMap<>(8);
        BigDecimal moldWidth = splitInfoRequest.getMoldWidth();
        BigDecimal infurSlabLen = updatePmPdCcSlab.getInfurSlabLen();
        BigDecimal laim = updatePmPdCcSlab.getRollAimLen();
        bizData.put(RuleSetConstants.ROLL_LINE_NO, Utils.mscLineNoToRoolLineNo(pmPdCcSlab.getMscLineNo()));
        bizData.put(RuleSetConstants.TENANT_ID, pmPdCcSlab.getTenantId());
        bizData.put(RuleSetConstants.LAIM, laim);
        bizData.put(RuleSetConstants.ORDER_NO, pmPdCcSlab.getOrderNoAxis());
        ruleParam.setBizData(bizData);
        RuleExecStrategy ruleExecStrategy47 = RuleExecStrategyFactory.matchPdEventStrategy(PdRuleItemType.LAIM_LIMIT);
        ruleExecStrategy47.execRule(ruleParam);
        String rollDirectCode = "3".equals(updatePmPdCcSlab.getRsCode()) ? RollDirectCode.L : RollDirectCode.C;
        
        List<PmSlabSpecBt> specBts = pmSlabSpecBtRepository.selectByCondition(Condition.builder(PmSlabSpecBt.class)
                .andWhere(Sqls.custom().andEqualTo(PmSlabSpecBt.FIELD_TENANT_ID, pmPdCcSlab.getTenantId())
                        .andEqualTo(PmSlabSpecBt.FIELD_ROLL_LINE_NO, Utils.mscLineNoToRoolLineNo(pmPdCcSlab.getMscLineNo()))
                        .andEqualTo(PmSlabSpecBt.FIELD_ROLL_DIRECT_CODE, rollDirectCode)
                        .andGreaterThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_THICK_TO, splitInfoRequest.getMoldThick())
                        .andLessThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_THICK_FROM, splitInfoRequest.getMoldThick())
                        .andGreaterThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_WIDTH_TO, moldWidth)
                        .andLessThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_WIDTH_FROM, moldWidth)
                        .andGreaterThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_MAX_LEN, infurSlabLen)
                        .andLessThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_MIN_LEN, infurSlabLen)
                        .andEqualTo(PmSlabSpecBt.FIELD_CC_TYPE, CcType.TYPE_1))
                .build());
        if (specBts == null || specBts.isEmpty()) {
            // 增加一次转置校验
            List<PmSlabSpecBt> specBts2 = pmSlabSpecBtRepository.selectByCondition(Condition.builder(PmSlabSpecBt.class)
                    .andWhere(Sqls.custom().andEqualTo(PmSlabSpecBt.FIELD_TENANT_ID, pmPdCcSlab.getTenantId())
                            .andEqualTo(PmSlabSpecBt.FIELD_ROLL_LINE_NO, Utils.mscLineNoToRoolLineNo(pmPdCcSlab.getMscLineNo()))
                            .andEqualTo(PmSlabSpecBt.FIELD_ROLL_DIRECT_CODE, rollDirectCode)
                            .andGreaterThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_THICK_TO, splitInfoRequest.getMoldThick())
                            .andLessThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_THICK_FROM, splitInfoRequest.getMoldThick())
                            .andGreaterThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_WIDTH_TO, infurSlabLen)
                            .andLessThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_WIDTH_FROM, infurSlabLen)
                            .andGreaterThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_MAX_LEN, moldWidth)
                            .andLessThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_MIN_LEN, moldWidth)
                            .andEqualTo(PmSlabSpecBt.FIELD_CC_TYPE, CcType.TYPE_1))
                    .build());
            if (specBts2 == null || specBts2.isEmpty()) {
                // 获取连铸板坯生产规格基准表失败,轧制产线号【{0}】，轧制方向【{1}】，板坯厚度【{2}】，板坯宽度【{3}】，连铸机类型【{4}】，进加热炉板坯长【{5}】，必要板坯长度【{6}】
                throw new CommonException("pm.pm_pd_rule_set_019", Utils.mscLineNoToRoolLineNo(pmPdCcSlab.getMscLineNo()), rollDirectCode, splitInfoRequest.getMoldThick().toPlainString(),
                        moldWidth.toPlainString(), CcType.TYPE_1, infurSlabLen.toPlainString() ,updatePmPdCcSlab.getNeedSlabLen().toPlainString());
            }
        } 
    }
    
    /**
     * 生产连铸板坯信息
     * @param splitInfoRequest
     * @param pmPdCcSlab
     * @param loginName
     * @return
     */
    private PmPdCcSlab buildPmPdCcSlab(PmPdMidSplitRequestDTO splitInfoRequest , PmPdCcSlab pmPdCcSlab , String loginName) {
        List<PmPdSlab> pmPdSlabs = pmPdSlabRepository.selectListBySlabNo(splitInfoRequest.getVirtualSlabNo(), splitInfoRequest.getTenantId());
        BigDecimal rollAimLen = BigDecimal.ZERO;
        BigDecimal slabCutGap = getSlabCutGap(splitInfoRequest.getTenantId(), splitInfoRequest.getMscLineNo());
        List<String> pdMatNo = new ArrayList<>();
        if(splitInfoRequest.getTmpYield() == null) {
            splitInfoRequest.setTmpYield(BigDecimal.ONE);
        }
        List<String> virtualSlabNo = new ArrayList<>();
        for (PmPdSlab pmPdSlab : pmPdSlabs) {
            virtualSlabNo.add(pmPdSlab.getVirtualSlabNo());
            if(!Constants.PdStatusHp.PD_STATUS_HP_32.equals(pmPdSlab.getPdStatusHp())) {
                // 中间坯【mid_virtual_slab_no】的分割坯不在中间坯组板完成状态，不能分割确认！
                throw new CommonException("pm.pm_pd_slab_37", splitInfoRequest.getVirtualSlabNo());
            }
            rollAimLen = rollAimLen.add(pmPdSlab.getNeedSlabLen());
            pdMatNo.add(pmPdSlab.getVirtualSlabNo());
            
        }
        rollAimLen = rollAimLen.add(slabCutGap.multiply(BigDecimal.valueOf(pmPdSlabs.size() - 1L)));
        rollAimLen = rollAimLen.divide(splitInfoRequest.getTmpYield(), PmPlateConstants.LEN_SCALE, RoundingMode.HALF_UP);
        BigDecimal moldWidth = Utils.maxValue(splitInfoRequest.getMoldWidth() ,pmPdCcSlab.getRollAimWidth());
        BigDecimal rollWtHp = rollAimLen.multiply(moldWidth).multiply(pmPdCcSlab.getRollAimThick());
        
        // 必要板坯长度need_slab_len = 轧制目标长度 * 轧制目标宽度 * 轧制目标厚度 / (结晶器宽 * 结晶器厚)
        BigDecimal mold = splitInfoRequest.getMoldThick().multiply(splitInfoRequest.getMoldWidth());

        BigDecimal neddSlabLen = rollWtHp.divide(mold.multiply(PmPlateConstants.IRON_OXIDE_EFFECT_RATE) , PmPlateConstants.LEN_SCALE , RoundingMode.HALF_UP);
        BigDecimal needSlabWt = neddSlabLen.multiply(mold);
        
        BigDecimal len = neddSlabLen;
        BigDecimal wt = needSlabWt.multiply(PmPlateConstants.DEFAULT_PROD_DENCITY).divide(BigDecimal.valueOf(1000L * 1000L * 1000L), PmPlateConstants.WT_SCALE, RoundingMode.HALF_UP);
        if(splitInfoRequest.getFixSlabLenFlag() != null && splitInfoRequest.getFixSlabLenFlag().intValue() == 1 && splitInfoRequest.getFixSlabLen() != null) {
            if(neddSlabLen.compareTo(splitInfoRequest.getFixSlabLen()) > 0) {
                // 必要板坯长度【{0}】大于指定长【{1}】，不能组板。
                throw new CommonException("pm.pm_pd_slab_42", neddSlabLen.toPlainString() , splitInfoRequest.getFixSlabLen().toPlainString());
            }
            len = splitInfoRequest.getFixSlabLen();
            wt = len.multiply(PmPlateConstants.DEFAULT_PROD_DENCITY).multiply(mold).divide(BigDecimal.valueOf(1000L * 1000L * 1000L), PmPlateConstants.WT_SCALE, RoundingMode.HALF_UP);
        }

        // 从合同产线表取精炼路径代码
        PmContMscTech pmContMscTech = pmContMscTechRepository.selectByOrderNoAndMscLineNo(pmPdSlabs.get(0).getOrderNoAxis(), pmPdSlabs.get(0).getMscLineNo());

        List<PmProContProdTtr> pmProContProdTtrList = pmProContProdTtrRepository.selectByOrderNoList(Arrays.asList(pmPdSlabs.get(0).getOrderNoAxis()), splitInfoRequest.getTenantId());

        String hotSendFlag = "H";
        PmPdCcSlab pmPdCcSlabUpdate = new PmPdCcSlab();
        if(pdMatNo != null && !pdMatNo.isEmpty()) {
            List<PmPdContSum> pdPmPdContSums = pmPdContSumRepository.selectByPdMatNoList(splitInfoRequest.getTenantId() , pdMatNo);
            List<String> orderNoList = new ArrayList<>();
            for (PmPdContSum contSum : pdPmPdContSums) {
                orderNoList.add(contSum.getOrderNo());
            }
            if(orderNoList != null) {
                Date steelPlanDate = null ;
                Date steelLatestDate = null;
                String urgOrderFlag = "0";
                Long MacroSmpFlag = 1L;
                Map<String, PmProContFilterResposeDTO> filterOrderMap = pmProContRepository.orderFilterMap(orderNoList, splitInfoRequest.getTenantId(), pmPdCcSlab.getMscLineNo());
                for (Entry<String, PmProContFilterResposeDTO> entry : filterOrderMap.entrySet()) {
                    if (entry.getValue().getSteelPlanDate() != null) {
                        if (steelPlanDate == null || steelPlanDate.after(entry.getValue().getSteelPlanDate())) {
                            steelPlanDate = entry.getValue().getSteelPlanDate();
                        }
                    }
                    if (entry.getValue().getSteelLatestDate() != null) {
                        if (steelLatestDate == null || steelLatestDate.after(entry.getValue().getSteelLatestDate())) {
                            steelLatestDate = entry.getValue().getSteelLatestDate();
                        }
                    }
                    if(entry.getValue().getUrgOrderFlag() != null && entry.getValue().getUrgOrderFlag() == 1L) {
                        urgOrderFlag = "1";
                    }

                    //  存在一个合同macro_smp_flag != 0 或者合同热送区分为C,则落C;否则H
                    if (MacroSmpFlag.equals(entry.getValue().getMacroSmpFlag()) || "C".equals(entry.getValue().getHotSendDiv())) {
                        hotSendFlag = "C";
                    }
                }
                pmPdCcSlabUpdate.setSteelLatestDate(steelLatestDate);
                pmPdCcSlabUpdate.setUrgOrderFlag(urgOrderFlag);
                if (steelPlanDate == null) {
                    // 获取当前时间往前推15天
//                    LocalDate now = LocalDate.now().minusDays(-15);
//                    steelPlanDate = Date.from(now.atStartOfDay(ZoneId.systemDefault()).toInstant());
                    steelPlanDate = new Date();
                }
                pmPdCcSlabUpdate.setSteelPlanDate(steelPlanDate);
            }
        }

        pmPdCcSlabUpdate.setAxisOrderThick(CollectionUtils.isNotEmpty(pmProContProdTtrList) ? pmProContProdTtrList.get(0).getOrderThick() : null);
        pmPdCcSlabUpdate.setAxisOrderWidth(CollectionUtils.isNotEmpty(pmProContProdTtrList) ? pmProContProdTtrList.get(0).getOrderWidth() : null);
        pmPdCcSlabUpdate.setRollAimLen(rollAimLen);
        pmPdCcSlabUpdate.setRollAimWidth(moldWidth);
        pmPdCcSlabUpdate.setRollWtHp(rollWtHp.multiply(PmPlateConstants.DEFAULT_PROD_DENCITY).divide(BigDecimal.valueOf(1000L * 1000L * 1000L), PmPlateConstants.WT_SCALE, RoundingMode.HALF_UP));
        pmPdCcSlabUpdate.setNeedSlabWt(needSlabWt.multiply(PmPlateConstants.DEFAULT_PROD_DENCITY).divide(BigDecimal.valueOf(1000L * 1000L * 1000L), PmPlateConstants.WT_SCALE, RoundingMode.HALF_UP));
        pmPdCcSlabUpdate.setNeedSlabLen(neddSlabLen);
        pmPdCcSlabUpdate.setVirtualSlabId(pmPdCcSlab.getVirtualSlabId());
        pmPdCcSlabUpdate.setObjectVersionNumber(pmPdCcSlab.getObjectVersionNumber());
        pmPdCcSlabUpdate.setPdStatusHp(Constants.PdStatusHp.PD_STATUS_HP_12);
        pmPdCcSlabUpdate.setPdResp(loginName);
        pmPdCcSlabUpdate.setMoldThick(splitInfoRequest.getMoldThick());
        pmPdCcSlabUpdate.setMoldWid(splitInfoRequest.getMoldWidth());
        pmPdCcSlabUpdate.setPreCleanSlabThick(splitInfoRequest.getMoldThick());
        pmPdCcSlabUpdate.setPreCleanSlabWidth(splitInfoRequest.getMoldWidth());
        pmPdCcSlabUpdate.setPreCleanSlabLen(len);
        pmPdCcSlabUpdate.setPreCleanSlabWt(wt);
        pmPdCcSlabUpdate.setPreCleanSlabMinLen(len);
        pmPdCcSlabUpdate.setPreCleanSlabMinWt(wt);
        pmPdCcSlabUpdate.setPreCleanSlabMaxLen(len);
        pmPdCcSlabUpdate.setPreCleanSlabMaxWt(wt);
        
        pmPdCcSlabUpdate.setInfurSlabThick(splitInfoRequest.getMoldThick());
        pmPdCcSlabUpdate.setInfurSlabWid(splitInfoRequest.getMoldWidth());
        pmPdCcSlabUpdate.setInfurSlabLen(len);
        pmPdCcSlabUpdate.setInfurSlabWt(wt);
        pmPdCcSlabUpdate.setInfurSlabMinLen(len);
        pmPdCcSlabUpdate.setInfurSlabMinWt(wt);
        pmPdCcSlabUpdate.setInfurSlabMaxLen(len);
        pmPdCcSlabUpdate.setInfurSlabMaxWt(wt);
        pmPdCcSlabUpdate.setCombinePlateLen(rollAimLen);
        pmPdCcSlabUpdate.setCombinePlateWidth(pmPdCcSlab.getRollAimWidth());
        pmPdCcSlabUpdate.setStNo(pmPdSlabs.get(0).getStNo());
        pmPdCcSlabUpdate.setSgSign(pmPdSlabs.get(0).getSgSign());
        pmPdCcSlabUpdate.setTotSmallPlateNum(1L);
        pmPdCcSlabUpdate.setNormYield(splitInfoRequest.getTmpYield().multiply(PmPlateConstants.IRON_OXIDE_EFFECT_RATE).multiply(pmPdCcSlab.getRollAimWidth()).divide(moldWidth , PmPlateConstants.YIELD_SCALE, RoundingMode.HALF_UP));
        pmPdCcSlabUpdate.setOrderNoAxis(pmPdSlabs.get(0).getOrderNoAxis());
        pmPdCcSlabUpdate.setRfPath(pmContMscTech != null ? pmContMscTech.getRfPath() : null);
        pmPdCcSlabUpdate.setHotChargeFlag(pmContMscTech != null ? pmContMscTech.getHotChargeFlag() : null);
        pmPdCcSlabUpdate.setHotSendFlag(hotSendFlag);
        pmPdCcSlabUpdate.setIngotType(splitInfoRequest.getIngotType());
        pmPdCcSlabUpdate.setFixSlabLen(splitInfoRequest.getFixSlabLen());
        pmPdCcSlabUpdate.setFixSlabLenFlag(splitInfoRequest.getFixSlabLenFlag());
        pmPdCcSlabUpdate.setCommandYield(splitInfoRequest.getTmpYield());
        
        // 若组合板宽 + 切边量 <= 结晶器宽，rs_code = 3 , 这里没有切边量
        if(pmPdCcSlab.getRollAimWidth().compareTo(splitInfoRequest.getMoldWidth()) <= 0) {
            pmPdCcSlabUpdate.setRsCode("3");
            pmPdCcSlabUpdate.setBroadFlag(BaseConstants.Flag.NO.toString());
        } else {
            pmPdCcSlabUpdate.setRsCode("0");
            pmPdCcSlabUpdate.setBroadFlag(BaseConstants.Flag.YES.toString());
        }
        
        List<PmSmallPltPos> pmSmallPltPos = pmSmallPltPosRepository.selectByPdMatNoList(virtualSlabNo, splitInfoRequest.getTenantId());
        createPlatePosAndContInfo(pmPdCcSlabUpdate, pmSmallPltPos, pmPdCcSlab.getVirtualSlabNo());
        return pmPdCcSlabUpdate;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean removeMidSplit(PmPdMidSplitRequestDTO splitInfoRequest) {
        String key = String.format(PmPlateConstants.SPLIT_PM_PD_SLAB_KEY, splitInfoRequest.getTenantId().toString() , splitInfoRequest.getVirtualSlabNo());
        if(redisHelper.hasKey(key)) {
            throw new CommonException("pm.pm_pd_slab_33", splitInfoRequest.getVirtualSlabNo());
        }
        try {
            redisHelper.strSet(key, "1", 2L, TimeUnit.MINUTES);
            PmPdCcSlab pmPdCcSlab = pmPdCcSlabRepository.selectByPdMatNo(splitInfoRequest.getTenantId() ,splitInfoRequest.getVirtualSlabNo());
            
            if(Constants.PdStatusHp.PD_STATUS_HP_12.compareTo(pmPdCcSlab.getPdStatusHp()) < 0){
                // 虚拟板坯【slab_no】临时命令已生成，不能删除分割
                throw new CommonException("pm.pm_pd_slab_info_019", splitInfoRequest.getVirtualSlabNo());
            }
            String loginName = DetailsHelper.getUserDetails() == null ? "": DetailsHelper.getUserDetails().getUserId().toString();
            if(StringUtils.isNotBlank(pmPdCcSlab.getPdResp()) && !loginName.equals(pmPdCcSlab.getPdResp())) {
                // 板坯【slab_no】的组板者为【PD_RESP】，【系统操作员id】不能操作！
                Map<Long, MtUserInfo> mtUserInfoMap = userClient.userInfoBatchGet(splitInfoRequest.getTenantId(),
                        Arrays.asList(Long.parseLong(pmPdCcSlab.getPdResp()), Long.parseLong(loginName)));
                String loginNameResp = mtUserInfoMap.containsKey(Long.parseLong(pmPdCcSlab.getPdResp())) ?
                        mtUserInfoMap.get(Long.parseLong(pmPdCcSlab.getPdResp())).getLoginName(): pmPdCcSlab.getPdResp();
                String loginNameUser = mtUserInfoMap.containsKey(Long.parseLong(loginName)) ? mtUserInfoMap.get(Long.parseLong(loginName)).getLoginName(): loginName;
                throw new CommonException("pm.pm_pd_slab_35", splitInfoRequest.getVirtualSlabNo(), loginNameResp, loginNameUser);
            }
            
            List<PmPdSlab> pmPdSlabs = pmPdSlabRepository.selectListBySlabNo(splitInfoRequest.getVirtualSlabNo(),
                    splitInfoRequest.getTenantId());
            // 是否删除全部标记
            if (splitInfoRequest.isRomoveAll()) {
                if (CollectionUtils.isEmpty(splitInfoRequest.getRemovePdSlabIdList())) {
                    splitInfoRequest.setRemovePdSlabIdList( new HashSet<>(pmPdSlabs.size()));
                }
                for (PmPdSlab pmPdSlab : pmPdSlabs) {
                    splitInfoRequest.getRemovePdSlabIdList().add(pmPdSlab.getPmPdSlabId());
                }
            }
            List<PmPdSlab> removePmPdSlabs = new ArrayList<PmPdSlab>(splitInfoRequest.getRemovePdSlabIdList().size());
            List<PmPdSlab> sortPmPdSlabs = new ArrayList<PmPdSlab>(splitInfoRequest.getRemovePdSlabIdList().size());
            List<PmPdSlab> needCallCtPmPdSlabs = new ArrayList<PmPdSlab>(splitInfoRequest.getRemovePdSlabIdList().size());
            List<String> removePdMatNo = new ArrayList<>(splitInfoRequest.getRemovePdSlabIdList().size());
            List<String> matNoList = new ArrayList<String>();

            for (PmPdSlab pmPdSlab : pmPdSlabs) {
                if(splitInfoRequest.getRemovePdSlabIdList().contains(pmPdSlab.getPmPdSlabId())) {
                    removePmPdSlabs.add(pmPdSlab);
                    removePdMatNo.add(pmPdSlab.getVirtualSlabNo());
                    if(Constants.PdStatusHp.PD_STATUS_HP_32.equals(pmPdSlab.getPdStatusHp())) {
                        needCallCtPmPdSlabs.add(pmPdSlab);
                        matNoList.add(pmPdSlab.getSlabNo());
                    }
                } else {
                    sortPmPdSlabs.add(pmPdSlab);
                }
            }

            // 抛组板履历
            List<PmPdContSum> pdPmPdContSums = pmPdContSumRepository.selectByPdMatNoList(splitInfoRequest.getTenantId() , removePdMatNo);
            Map<String , List<PmPdContSum>> contSumMap = pdPmPdContSums.stream().collect(Collectors.groupingBy(PmPdContSum::getPdMatNo));
            PdMatTypeStrategy pdMatTypeStrategy = PdMatTypeStrategyFactory.matchStrategy(PdMatType.MID_SPLIT);
            for (Entry<String, List<PmPdContSum>> entry : contSumMap.entrySet()) {
                pdMatTypeStrategy.pdDeleteEvent(entry.getValue(), entry.getKey()
                        , splitInfoRequest.getMscLineNo(), Constants.PdProgram.MID_DELETE_SLAB_PROGRAM, splitInfoRequest.getTenantId());
            }
            List<PmSmallPltPos> pmSmallPltPosList = null;
            if(!removePdMatNo.isEmpty()) {
                pmSmallPltPosList = pmSmallPltPosRepository.selectByCondition(Condition.builder(PmSmallPltPos.class)
                        .andWhere(Sqls.custom().andIn(PmSmallPltPos.FIELD_PD_MAT_NO, removePdMatNo ))
                        .andWhere(Sqls.custom().andEqualTo(PmSmallPltPos.FIELD_TENANT_ID, splitInfoRequest.getTenantId()))
                        .build());
            }
            if(!sortPmPdSlabs.isEmpty()) {
                removePdMatNo.add(splitInfoRequest.getVirtualSlabNo());
            }
            removePdMatNo.add(pmPdCcSlab.getVirtualSlabNo());
            pmPdSlabRepository.batchDeleteByPrimaryKey(removePmPdSlabs);
            pmPdContSumRepository.deleteByMatNo(splitInfoRequest.getTenantId() , removePdMatNo);
            pmPdPlateCutRepository.deleteByMatNo(splitInfoRequest.getTenantId() , removePdMatNo);
            pmSmallPltPosRepository.deleteByMatNo(splitInfoRequest.getTenantId() , removePdMatNo);
            pmPdBlockPosRepository.deleteByMatNo(splitInfoRequest.getTenantId() , removePdMatNo);
            
            if(!sortPmPdSlabs.isEmpty()) {
                BigDecimal slabCutGap = getSlabCutGap(splitInfoRequest.getTenantId(), pmPdCcSlab.getMscLineNo());
                BigDecimal rollAimLen = BigDecimal.ZERO;
                long i = 1 ;
                for (PmPdSlab pdSlab : sortPmPdSlabs) {
                    if(pdSlab.getRollAimLen() != null) {
                        rollAimLen = rollAimLen.add(pdSlab.getRollAimLen());
                    }
                    if(i != 1) {
                        rollAimLen = rollAimLen.add(slabCutGap);
                    }
                }
                // 否则，置板坯信息表该板坯号的厚板组板状态为‘11’。
                PmPdCcSlab updatePmPdCcSlab = new PmPdCcSlab();
                updatePmPdCcSlab.setRollAimLen(rollAimLen);
                updatePmPdCcSlab.setVirtualSlabId(pmPdCcSlab.getVirtualSlabId());
                updatePmPdCcSlab.setPdStatusHp(Constants.PdStatusHp.PD_STATUS_HP_11);
                updatePmPdCcSlab.setObjectVersionNumber(pmPdCcSlab.getObjectVersionNumber());
                BigDecimal rollWtHp = pmPdCcSlab.getRollAimLen().multiply(pmPdCcSlab.getRollAimWidth()).multiply(pmPdCcSlab.getRollAimThick().multiply(PmPlateConstants.DEFAULT_PROD_DENCITY));
                rollWtHp = rollWtHp.divide(BigDecimal.valueOf(1000L * 1000L * 1000L), PmPlateConstants.WT_SCALE, RoundingMode.HALF_UP);
                updatePmPdCcSlab.setRollWtHp(rollWtHp);
                pmPdCcSlabRepository.updateByPrimaryKeySelective(updatePmPdCcSlab);
                pmPdSlabRepository.batchUpdateByPrimaryKeySelective(sortPmPdSlabs);
            } else {
                // 则删除板坯信息表PM_PD_SLAB_INFO该板坯号的记录，
                pmPdCcSlabRepository.deleteByPrimaryKey(pmPdCcSlab.getVirtualSlabId());
            }
            
            if (CollectionUtils.isNotEmpty(pmSmallPltPosList)) {
                Map<String ,List<PmSmallPltPos>> pmSmallPltPosListMap = pmSmallPltPosList.stream().collect(Collectors.groupingBy(PmSmallPltPos::getPdMatNo));
                for (Entry<String, List<PmSmallPltPos>> entry : pmSmallPltPosListMap.entrySet()) {
                    List<ProContConsumeDTO> proContConsumeDTOs = new ArrayList<>();
                    if(sortPmPdSlabs.isEmpty()) {
                        // 如果删除全部分割坯则删除虚拟板坯和大板
                        proContConsumeDTOs.add(new ProContConsumeDTO(splitInfoRequest.getVirtualSlabNo(), PdProdFlag.VIRTUAL_SLAB.getCode(), BaseConstants.Flag.NO.longValue()));
                        proContConsumeDTOs.add(new ProContConsumeDTO(splitInfoRequest.getVirtualSlabNo(), PdProdFlag.VIRTUAL_COMPOSITE_SLAB.getCode(), BaseConstants.Flag.NO.longValue()));
                    }
                    for (PmSmallPltPos pmSmallPltPos : entry.getValue()) {
                        proContConsumeDTOs.add(new ProContConsumeDTO(splitInfoRequest.getVirtualSlabNo() + pmSmallPltPos.getSmallPlateDivNo(), PdProdFlag.VIRTUAL_SUB_SLAB.getCode(), BaseConstants.Flag.NO.longValue()));
                    }
                    eventClient.addEvent(CtEventConstants.EVENT_PM_CONTRACT_BOARD_CONSUME, proContConsumeDTOs);
                }
                eventClient.sendEvent(splitInfoRequest.getTenantId());
            }
            return true;
        } finally {
            redisHelper.delKey(key);
            eventClient.remove();
        }
    }
    
    @Override
    public BigDecimal selectMidSplitTmpSlabLen(String virtualSlabNo, BigDecimal moldThick, BigDecimal moldWid,
            BigDecimal infuSlabWt, Long organizationId) {
        List<PmPdSlab> pmPdSlabs = pmPdSlabRepository.selectListBySlabNo(virtualSlabNo, organizationId);
        BigDecimal wt = BigDecimal.ZERO;
        for (PmPdSlab pmPdSlab : pmPdSlabs) {
            if(pmPdSlab.getInfurSlabWt() != null) {
                wt = wt.add(pmPdSlab.getInfurSlabWt());
            }
        }
        if(infuSlabWt != null) {
            wt = wt.add(infuSlabWt);
        }
        wt = wt.multiply(PmPlateConstants.GRAM_TO_TON).multiply(PmPlateConstants.CM3_TO_MM3);
        if(moldWid != null && moldThick != null) {
            BigDecimal value = moldWid.multiply(moldThick).multiply(PmPlateConstants.DEFAULT_PROD_DENCITY);
            return wt.divide(value , PmPlateConstants.LEN_SCALE, RoundingMode.HALF_UP);
        }
        return BigDecimal.ZERO;
    }
    
    @Override
    public Map<String, Object> selectMidSplitTmpYield(String virtualSlabNo, BigDecimal moldThick, BigDecimal moldWid,
            BigDecimal infuSlabLen, Long organizationId) {
        List<PmPdSlab> pmPdSlabs = pmPdSlabRepository.selectListBySlabNo(virtualSlabNo, organizationId);
        BigDecimal len = BigDecimal.ZERO;
        for (PmPdSlab pmPdSlab : pmPdSlabs) {
            if(pmPdSlab.getInfurSlabWt() != null) {
                len = len.add(pmPdSlab.getInfurSlabLen());
            }
        }
        List<PmSlabSpecBt> pmSlabSpecBts = pmSlabSpecBtRepository.selectBy(organizationId,
                Utils.mscLineNoToRoolLineNo(pmPdSlabs.get(0).getMscLineNo()), CcType.TYPE_1, PmPlateConstants.FUR_TYPR_C, moldThick, moldWid);
        // Ymax = (（max+ a+b ）/（a+b+c）)* 0.99      
        // Ymin = (（min + a + b）/ (a+b+c)* 0.99        
        Map<String , Object> result = new HashMap<>();
        String maxValue = "maxValue";
        String rangeYield = "rangeYield";
        StringBuffer sb = new StringBuffer();
        for (PmSlabSpecBt pmSlabSpecBt : pmSlabSpecBts) {
            BigDecimal min = pmSlabSpecBt.getSlabMinLen().add(len.subtract(infuSlabLen))
                    .multiply(PmPlateConstants.IRON_OXIDE_EFFECT_RATE).divide(len , PmPlateConstants.LEN_SCALE, RoundingMode.HALF_UP);
            BigDecimal max = pmSlabSpecBt.getSlabMaxLen().add(len.subtract(infuSlabLen))
                    .multiply(PmPlateConstants.IRON_OXIDE_EFFECT_RATE).divide(len , PmPlateConstants.LEN_SCALE, RoundingMode.HALF_UP);
            if(!result.containsKey(maxValue) || ((BigDecimal)result.get(maxValue)).compareTo(max) < 0) {
                result.put(maxValue, max);
            }
            sb.append(min.toPlainString()).append("~").append(max.toPlainString()).append(";");
        }
        result.put(rangeYield, sb.toString());
        return result;
    }
    
    @Override
    public PmPdMidSplitDTO selectMidSplit(String virtualSlabNo, Long organizationId) {
        List<PmPdSlab> pmPdSlabs = pmPdSlabRepository.selectListBySlabNo(virtualSlabNo, organizationId);
        PmPdCcSlab pmPdCcSlab = pmPdCcSlabRepository.selectByPdMatNo(organizationId, virtualSlabNo);
        PmPdMidSplitDTO pmPdMidSplitDTO = new PmPdMidSplitDTO();
        pmPdMidSplitDTO.setVirtualSlabNo(virtualSlabNo);
        if(pmPdSlabs == null || pmPdSlabs.isEmpty()) {
            return pmPdMidSplitDTO;
        }
        // 有序排列
        
        pmPdMidSplitDTO.setMidSlabLen(BigDecimal.ZERO);
        pmPdMidSplitDTO.setRollAimLen(BigDecimal.ZERO);
        pmPdMidSplitDTO.setRollAimWidth(BigDecimal.ZERO);
        pmPdMidSplitDTO.setRollAimWidth(BigDecimal.ZERO);
        pmPdMidSplitDTO.setRollWtHp(BigDecimal.ZERO);
        pmPdMidSplitDTO.setPdStatusHp(pmPdCcSlab.getPdStatusHp());
        pmPdMidSplitDTO.setPmPdSlabs(Lists.newArrayList());
        
        for (PmPdSlab pmPdSlab : pmPdSlabs) {
            
            if(StringUtils.isBlank(pmPdMidSplitDTO.getMscLineNo())) {
                pmPdMidSplitDTO.setMscLineNo(pmPdSlab.getMscLineNo());
            }
            if(pmPdSlab.getNeedSlabLen() != null) {
                pmPdMidSplitDTO.setMidSlabLen(pmPdMidSplitDTO.getMidSlabLen().add(pmPdSlab.getNeedSlabLen()));
                pmPdMidSplitDTO.setRollAimLen(pmPdMidSplitDTO.getRollAimLen().add(pmPdSlab.getNeedSlabLen()));
            }
            
            if(pmPdCcSlab != null) {
                pmPdMidSplitDTO.setNeedSlabLen(pmPdCcSlab.getNeedSlabLen());
                pmPdMidSplitDTO.setRollWtHp(pmPdCcSlab.getNeedSlabWt());
                pmPdMidSplitDTO.setRollAimWidth(pmPdCcSlab.getRollAimWidth());
                pmPdMidSplitDTO.setRollAimThick(pmPdCcSlab.getRollAimThick());
            }
            
        }
        pmPdMidSplitDTO.setTmpSlabLen(pmPdMidSplitDTO.getRollAimLen());
        pmPdMidSplitDTO.setPmPdSlabs(pmPdSlabs);
        return pmPdMidSplitDTO;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createTwoRollInterim(PmTwoRollInterimRequestDTO request , PdMatType pdMatType) {
        String midSlabNo = null ;
        try {
            PmCmdSlab pmCmdSlab = pmCmdSlabRepository.selectByPonoSlabNo(request.getPonoSlabNo(), request.getTenantId());
            
            if(pmCmdSlab == null || StringUtils.isBlank(pmCmdSlab.getVirtualSlabNo())) {
                throw new CommonException("pm.pm_pd_slab_40" , request.getPonoSlabNo());
            }
            midSlabNo = pmCmdSlab.getVirtualSlabNo();
            List<PmPdSlab> pmSlabs = pmPdSlabRepository.selectListBySlabNo(pmCmdSlab.getVirtualSlabNo(), request.getTenantId());
            if(pmSlabs == null || pmSlabs.isEmpty()) {
                throw new CommonException("pm.pm_pd_slab_41" , pmCmdSlab.getVirtualSlabNo());
            }
            if(request.getMmSlab() == null) {
                throw new CommonException("pm.pm_pd_slab_info_030" , request.getSlabNo());
            }
            PmPdSlabSplitDTO pmPdSlabSplitDTO = request.getMmSlab();
            // 板坯主数据校验
            check(pmPdSlabSplitDTO);
            
            PmPdSlabInfo pmPdSlabInfo = buildPmPdSlabInfo(pmPdSlabSplitDTO , request.getSlabNo() , pmSlabs.get(0).getMscLineNo() , request.getTenantId());
            
            // 新增组板板坯表、大板粗切位置表、组合子板位置表、组板合同总量表、组板小板位置表的记录：
            List<String> codeList = pmRuleCodeService.generateCode(pmSlabs.size() , request.getTenantId(), Constants.CodeRule.SPLIT_VIRTUAL_SLAB_NO
                    , pmPdSlabInfo.getPono() + "S", 4);
            Iterator<String> iterator = codeList.iterator();
            List<PmPdSlab> newPmPdSlabs = new ArrayList<>(pmSlabs.size());
            List<String> pdMatNo = new ArrayList<>(pmSlabs.size());
            List<String> axisOrderNo = new ArrayList<>(pmSlabs.size());
            for (PmPdSlab pmPdSlab : pmSlabs) {
                pdMatNo.add(pmPdSlab.getVirtualSlabNo());
                axisOrderNo.add(pmPdSlab.getOrderNoAxis());
            }
            List<PmProContYieldRequestDTO> pmProContYieldRequestList = new ArrayList<>(pmSlabs.size());
            List<PmPdContSum> pdPmPdContSums = pmPdContSumRepository.selectByPdMatNoList(request.getTenantId() , pdMatNo);
            Map<String , List<PmPdContSum>> contSumMap = pdPmPdContSums.stream().collect(Collectors.groupingBy(PmPdContSum::getPdMatNo));
            List<PmProContProdTtr> pmProContProdTtrs = pmProContProdTtrRepository.selectByOrderNoList(axisOrderNo, request.getTenantId());
            Map<String , PmProContProdTtr> contProdTtrMap = Maps.uniqueIndex(pmProContProdTtrs, PmProContProdTtr::getOrderNo);
            List<PmSmallPltPos> pmSmallPltPosList = pmSmallPltPosRepository.selectByCondition(Condition.builder(PmSmallPltPos.class)
                        .andWhere(Sqls.custom().andIn(PmSmallPltPos.FIELD_PD_MAT_NO, pdMatNo ))
                        .andWhere(Sqls.custom().andEqualTo(PmSmallPltPos.FIELD_TENANT_ID, request.getTenantId()))
                        .build());
            Map<String ,List<PmSmallPltPos>> pmSmallPltPosListMap = pmSmallPltPosList.stream().collect(Collectors.groupingBy(PmSmallPltPos::getPdMatNo));
            int i = 0; 
            for (PmPdSlab pmPdSlab : pmSlabs) {
                i++;
                PmPdSlab newPmPdSlab = new PmPdSlab();
                newPmPdSlab.setPono(pmPdSlabInfo.getPono());
                newPmPdSlab.setSlabDivNo(pmPdSlab.getSlabDivNo());
                newPmPdSlab.setVirtualSlabNo(iterator.next());
                newPmPdSlab.setPdStatusHp(Constants.PdStatusHp.PD_STATUS_HP_11);
                newPmPdSlab.setSlabNo(pmPdSlabInfo.getSlabNo());
                newPmPdSlab.setTwoRollInterimFlag(pmPdSlabInfo.getTwoRollInterimFlag());
                newPmPdSlab.setIngotType(pmPdSlabInfo.getIngotType());
                newPmPdSlab.setMscLineNo(pmPdSlab.getMscLineNo());
                newPmPdSlab.setTenantId(pmPdSlab.getTenantId());
                newPmPdSlab.setFormPlateMode(pmPdSlab.getFormPlateMode());
                newPmPdSlab.setOrderNoAxis(pmPdSlab.getOrderNoAxis());
                newPmPdSlab.setStNo(pmPdSlab.getStNo());
                newPmPdSlab.setSgSign(pmPdSlab.getSgSign());
                newPmPdSlab.setFixSlabLenFlag(pmPdSlab.getFixSlabLenFlag());
                newPmPdSlab.setFixSlabLen(pmPdSlab.getFixSlabLen());
                newPmPdSlab.setRollDirectCode(pmPdSlab.getRollDirectCode());
                newPmPdSlabs.add(newPmPdSlab);
                if(i == pmSlabs.size()) {
                    // 如果是最后一块坯
                    String rollDirectCode = "3".equals(pmPdSlab.getRsCode()) ? RollDirectCode.L : RollDirectCode.C;
                    BigDecimal infurSlabLen = pmPdSlab.getNeedSlabLen().add(BigDecimal.valueOf(50));
                    List<PmSlabSpecBt> specBts = pmSlabSpecBtRepository.selectByCondition(Condition.builder(PmSlabSpecBt.class)
                            .andWhere(Sqls.custom().andEqualTo(PmSlabSpecBt.FIELD_TENANT_ID, pmPdSlab.getTenantId())
                                    .andEqualTo(PmSlabSpecBt.FIELD_ROLL_LINE_NO, Utils.mscLineNoToRoolLineNo(pmPdSlab.getMscLineNo()))
                                    .andEqualTo(PmSlabSpecBt.FIELD_ROLL_DIRECT_CODE, rollDirectCode)
                                    .andGreaterThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_THICK_TO, request.getMoldThick())
                                    .andLessThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_THICK_FROM, request.getMoldThick())
                                    .andGreaterThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_WIDTH_TO, request.getMoldWidth())
                                    .andLessThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_WIDTH_FROM, request.getMoldWidth())
                                    .andGreaterThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_MAX_LEN, infurSlabLen)
                                    .andLessThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_MIN_LEN, infurSlabLen)
                                    .andEqualTo(PmSlabSpecBt.FIELD_CC_TYPE, CcType.TYPE_1))
                            .build());
                    if(specBts == null || specBts.isEmpty()) {
                        // 转置匹配一次基表
                        specBts = pmSlabSpecBtRepository.selectByCondition(Condition.builder(PmSlabSpecBt.class)
                                .andWhere(Sqls.custom().andEqualTo(PmSlabSpecBt.FIELD_TENANT_ID, pmPdSlab.getTenantId())
                                        .andEqualTo(PmSlabSpecBt.FIELD_ROLL_LINE_NO, Utils.mscLineNoToRoolLineNo(pmPdSlab.getMscLineNo()))
                                        .andEqualTo(PmSlabSpecBt.FIELD_ROLL_DIRECT_CODE, rollDirectCode)
                                        .andGreaterThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_THICK_TO, request.getMoldThick())
                                        .andLessThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_THICK_FROM, request.getMoldThick())
                                        .andGreaterThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_WIDTH_TO, infurSlabLen)
                                        .andLessThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_WIDTH_FROM, infurSlabLen)
                                        .andGreaterThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_MAX_LEN, request.getMoldWidth())
                                        .andLessThanOrEqualTo(PmSlabSpecBt.FIELD_SLAB_MIN_LEN, request.getMoldWidth())
                                        .andEqualTo(PmSlabSpecBt.FIELD_CC_TYPE, CcType.TYPE_1))
                                .build());
                    }
                    if(specBts != null && !specBts.isEmpty()) {
                        PmSlabSpecBt pmSlabSpecBt = specBts.get(0);
                        BigDecimal fixSlabLen = Utils.minValue(pmSlabSpecBt.getSlabMaxLen() , infurSlabLen);
                        newPmPdSlab.setFixSlabLenFlag(BaseConstants.Flag.YES.longValue());
                        newPmPdSlab.setFixSlabLen(fixSlabLen);
                    } else {
                        newPmPdSlab.setFixSlabLenFlag(BaseConstants.Flag.YES.longValue());
                        newPmPdSlab.setFixSlabLen(BigDecimal.ZERO);
                    }
                }
                // 构造余坯计算参数
                PmProContYieldRequestDTO pmProContYieldRequestDTO = getSlabCalcRequest(newPmPdSlab, pmPdSlabInfo ,pdMatType, contProdTtrMap.get(pmPdSlab.getOrderNoAxis())
                        , pmSmallPltPosListMap.get(pmPdSlab.getVirtualSlabNo()), contSumMap.get(pmPdSlab.getVirtualSlabNo()) ,request);
                pmProContYieldRequestList.add(pmProContYieldRequestDTO);
            }
            pmPdSlabRepository.batchInsertSelective(newPmPdSlabs);
            pmPdSlabInfoRepository.insertSelective(pmPdSlabInfo);
            callMatStatusModify(pmPdSlabInfo);
            // 余坯组板计算
            try {
                // 出钢材脱合同事件-轧钢已经做了拖合同，生产不处理
    //            for (Entry<String, List<PmSmallPltPos>> entry : pmSmallPltPosListMap.entrySet()) {
    //                List<ProContConsumeDTO> proContConsumeDTOs = new ArrayList<>();
    //                proContConsumeDTOs.add(new ProContConsumeDTO(pmCmdSlab.getVirtualSlabNo(), PdProdFlag.VIRTUAL_SLAB.getCode(), BaseConstants.Flag.NO.longValue()));
    //                proContConsumeDTOs.add(new ProContConsumeDTO(pmCmdSlab.getVirtualSlabNo(), PdProdFlag.VIRTUAL_COMPOSITE_SLAB.getCode(), BaseConstants.Flag.NO.longValue()));
    //                for (PmSmallPltPos pmSmallPltPos : entry.getValue()) {
    //                    proContConsumeDTOs.add(new ProContConsumeDTO(pmCmdSlab.getVirtualSlabNo() + pmSmallPltPos.getSmallPlateDivNo(), PdProdFlag.VIRTUAL_SUB_SLAB.getCode(), BaseConstants.Flag.NO.longValue()));
    //                }
    //                eventClient.addEvent(CtEventConstants.EVENT_PM_CONTRACT_BOARD_CONSUME, proContConsumeDTOs);
    //            }
                SecondaryDesignHelper.setTwoRollFlag(true);
                PdMatTypeStrategy pdMatTypeStrategy = PdMatTypeStrategyFactory.matchStrategy(PdMatType.C);
                for (Entry<String, List<PmPdContSum>> entry : contSumMap.entrySet()) {
                    pdMatTypeStrategy.pdDeleteEvent(entry.getValue(), entry.getKey()
                            , pmPdSlabInfo.getMscLineNo(), Constants.PdProgram.CC_SLAB_DETAIL_DELETE_PROGRAM, request.getTenantId());
                }
                
                Iterator<PmProContYieldRequestDTO> calcIterator = pmProContYieldRequestList.iterator();
                BigDecimal remainSlabLen = request.getSlabLen();
                while(calcIterator.hasNext()) {
                    PmProContYieldRequestDTO pmProContYieldRequest = calcIterator.next();
                    pmProContYieldRequest.getPmContFilterRequest().setRemainSlabLen(remainSlabLen);
                    // 二次开坯重新计算余坯与二次设计逻辑一致
                    pmProContYieldRequest.setSecondaryDesignFlag(true);
                    PmProContYieldResposeDTO pmProContYieldRespose = pmProContService.contYieldExec(pmProContYieldRequest);
                    remainSlabLen = remainSlabLen.subtract(pmProContYieldRespose.getNeedSlabLen());
                }
                // 余坯分割确认
                PmPdSlabSplitRequestDTO splitInfoRequest = new PmPdSlabSplitRequestDTO();
                splitInfoRequest.setSlabId(pmPdSlabInfo.getPmPdSlabInfoId());
                splitInfoRequest.setSlabNo(pmPdSlabInfo.getSlabNo());
                splitInfoRequest.setMscLineNo(pmPdSlabInfo.getMscLineNo());
                splitInfoRequest.setTenantId(request.getTenantId());
                confirmSplitInfoBySlabNo(splitInfoRequest);
                
                // 最后发送所有事件
                eventClient.sendEvent(splitInfoRequest.getTenantId());
                List<String> slabNoList = new ArrayList<>();
                slabNoList.add(splitInfoRequest.getSlabNo());
                List<PmCmdLargePlt> pmCmdLargePltList = pmCmdLargePltRepository.selectBySlabNoList(slabNoList, request.getTenantId());
                SecondaryDesignStrategy secondaryDesignStrategy = SecondaryDesignStrategyFactory.matchStrategy(pdMatType);
                secondaryDesignStrategy.sampleAddition(request.getTenantId(), pmCmdLargePltList);
                secondaryDesignStrategy.secondaryDesign(request.getTenantId(), pmCmdLargePltList);
                secondaryDesignStrategy.commandCreate(request.getTenantId(), pmCmdLargePltList);
            } finally {
                SecondaryDesignHelper.remove();
                eventClient.remove();
            }
        } catch (Exception e) {
            this.self().twoRollInterimLog(request, e, midSlabNo);
            throw e ;
        }
        
    }
    
    @Override
    @GlobalTransactional(rollbackFor = Exception.class , propagation = io.seata.tm.api.transaction.Propagation.REQUIRES_NEW)
    @Transactional(rollbackFor = Exception.class , propagation = Propagation.REQUIRES_NEW)
    public void twoRollInterimLog(PmTwoRollInterimRequestDTO request, Exception e , String midSlabNo) {
        String msg = e.getMessage();
        if(e instanceof CommonException) {
            CommonException commonException = (CommonException) e ;
            Message message = MessageAccessor.getMessage(commonException.getCode(), commonException.getParameters());
            msg = message.getDesc();
        }
        PmPdRecDTO pmPdRec = new PmPdRecDTO();
        pmPdRec.setApiCode(PdEventType.HP49.getDesc());
        pmPdRec.setEventCode(PdEventType.HP49.getCode());
        pmPdRec.setSystemCode(Constants.SYSTEM_PD_CODE);
        pmPdRec.setKeyvalue1(request.getSlabNo());
        pmPdRec.setKeyvalue1Desc("板坯号");
        pmPdRec.setKeyvalue2(midSlabNo);
        pmPdRec.setKeyvalue2Desc("中间坯号");
        pmPdRec.setKeyvalue3(request.getPonoSlabNo());
        pmPdRec.setKeyvalue3Desc("命令板坯号");
        String eventMaker = DetailsHelper.getUserDetails() == null ? "-1" : DetailsHelper.getUserDetails().getUserId().toString();
        pmPdRec.setEventMaker(eventMaker);
        if(StringUtils.isNotBlank(msg)) {
            if(msg.length() > 500) {
                pmPdRec.setReturnErrorMsg(msg.substring(0, 500));
            } else {
                pmPdRec.setReturnErrorMsg(msg);
            }
        }
        pmPdRecService.createEvent(request.getTenantId(), pmPdRec);
    } 
    
    /**
     * 构造余坯组板-执行请求参数
     * @param pmPdSlab
     * @param pmPdSlabInfo
     * @param pmSmallPltPoss
     * @param pmPdContSums
     * @return
     */
    private PmProContYieldRequestDTO getSlabCalcRequest(PmPdSlab pmPdSlab, PmPdSlabInfo pmPdSlabInfo , PdMatType pdMatType
            ,PmProContProdTtr axisPmProContProdTtr,List<PmSmallPltPos> pmSmallPltPoss, List<PmPdContSum> pmPdContSums , PmTwoRollInterimRequestDTO request) {
        PmProContYieldRequestDTO pmProContYieldRequestDTO = new PmProContYieldRequestDTO();
        pmProContYieldRequestDTO.setSendCtEvent(false);
        pmProContYieldRequestDTO.setAxisOrderNo(pmPdSlab.getOrderNoAxis());
        pmProContYieldRequestDTO.setPmPdSlab(pmPdSlab);
        pmProContYieldRequestDTO.setVirtualSlabNo(pmPdSlab.getVirtualSlabNo());
        pmProContYieldRequestDTO.setTenantId(pmPdSlab.getTenantId());
        FormPlateModeStrategy formPlateModeStrategy = FormPlateModeStrategyFactory.matchStrategy(pmPdSlab.getFormPlateMode());
        // 组板位置参数
        PmCompositeBoardDTO pmCompositeBoardDTO = formPlateModeStrategy.buildPmCompositeBoard(FormPlateMode.getByCode(pmPdSlab.getFormPlateMode()) ,pmSmallPltPoss, axisPmProContProdTtr, pmPdSlab.getMscLineNo(), pmPdSlab.getTenantId());
        pmProContYieldRequestDTO.setCompositeBoard(pmCompositeBoardDTO);
        
        List<PmProContYieldDTO> pmProContYieldList = new ArrayList<>();
        
        for (PmPdContSum pmPdContSum : pmPdContSums) {
            PmProContYieldDTO pmProContYieldDTO = new PmProContYieldDTO();
            pmProContYieldDTO.setAxisFlag(pmPdContSum.getAxisFlag() == 1L);
            pmProContYieldDTO.setOrderNo(pmPdContSum.getOrderNo());
            pmProContYieldDTO.setSmallPlateLen(pmPdContSum.getSmallPlateLen());
            pmProContYieldList.add(pmProContYieldDTO);
        }
        pmProContYieldRequestDTO.setPmProContYieldList(pmProContYieldList);
        PmProContFilterRequestDTO pmContFilterRequest = new PmProContFilterRequestDTO();
        pmContFilterRequest.setMoldThick(request.getMoldThick());
        pmContFilterRequest.setMoldWidth(request.getMoldWidth());
        pmContFilterRequest.setStNo(pmPdSlab.getStNo());
        pmContFilterRequest.setSgSign(pmPdSlab.getSgSign());
        
        pmContFilterRequest.setFurType(PmPlateConstants.FUR_TYPR_C);
        pmContFilterRequest.setCcType(Constants.CcType.TYPE_1);
        pmContFilterRequest.setMatDesignKind(pdMatType.getCode());
        pmContFilterRequest.setFixSlabLenFlag(pmPdSlab.getFixSlabLenFlag() == null ? 0L : pmPdSlab.getFixSlabLenFlag());
        pmContFilterRequest.setFixSlabLen(pmPdSlab.getFixSlabLen() == null ? BigDecimal.ZERO : pmPdSlab.getFixSlabLen());
        
        pmContFilterRequest.setMscLineNo(pmPdSlab.getMscLineNo());
        pmContFilterRequest.setFormPlateMode(pmPdSlab.getFormPlateMode());
        pmContFilterRequest.setRollDirectCode(pmPdSlab.getRollDirectCode());
        pmProContYieldRequestDTO.setPmContFilterRequest(pmContFilterRequest) ;
        return pmProContYieldRequestDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void disband(Long tenantId, List<String> virtualSlabNoList) {
        List<PmPdSlab> pdSlabList = pmPdSlabRepository.selectByVirtualSlabNoList(virtualSlabNoList, tenantId);
        if (CollectionUtils.isEmpty(pdSlabList)) {
           throw new CommonException("pm.pd_cc_slab_001", virtualSlabNoList, "组板板坯表");
        }
        // 获取同一个板坯号的其他板坯表数据
        List<String> slabNoList = pdSlabList.stream().map(PmPdSlab::getSlabNo).distinct().collect(Collectors.toList());
        List<PmPdSlab> pmPdSlabList = pmPdSlabRepository.selectListBySlabNoList(slabNoList, tenantId);
        List<String> allVirtualSlabNoList = pmPdSlabList.stream().map(PmPdSlab::getVirtualSlabNo).collect(Collectors.toList());

        final Map<String , String> mscLineNoMap = new HashMap<>();
        // 校验材料状态是否是18
        for (PmPdSlab pmPdSlab : pmPdSlabList) {
            if (!PdStatusHp.PD_STATUS_HP_18.equals(pmPdSlab.getPdStatusHp())) {
                throw new CommonException("pm.pd_slab_003", pmPdSlab.getVirtualSlabNo());
            }
            mscLineNoMap.put(pmPdSlab.getVirtualSlabNo(), pmPdSlab.getMscLineNo());
        }

        // 查询相关表并删除
        List<PmPdSlabInfo> pmPdSlabInfoList = pmPdSlabInfoRepository.selectBySlabNoList(slabNoList, tenantId);
        List<PmSmallPltPos> pmSmallPltPosList = pmSmallPltPosRepository.selectByPdMatNoList(allVirtualSlabNoList, tenantId);
        if (CollectionUtils.isEmpty(pmSmallPltPosList)) {
            throw new CommonException("pm.pd_cc_slab_001", allVirtualSlabNoList, "组板小板位置表");
        }

        List<PmPdBlockPos> pmPdBlockPosList = pmPdBlockPosRepository.selectByPdMatNoList(allVirtualSlabNoList, tenantId);
        if (CollectionUtils.isEmpty(pmPdBlockPosList)) {
            throw new CommonException("pm.pd_cc_slab_001", allVirtualSlabNoList, "组合子板位置表");
        }
        List<PmCmdSlab> pmCmdSlabList = pmCmdSlabRepository.selectByPonoSlabList(allVirtualSlabNoList, tenantId);
        if (CollectionUtils.isEmpty(pmCmdSlabList)) {
            throw new CommonException("pm.cd_plate_029", "命令板坯表", allVirtualSlabNoList);
        }
        List<PmCmdLargePlt> pmCmdLargePltList = pmCmdLargePltRepository.selectByPonoSlabList(allVirtualSlabNoList, tenantId);
        if (CollectionUtils.isEmpty(pmCmdSlabList)) {
            throw new CommonException("pm.cd_plate_029", "命令大板表", allVirtualSlabNoList);
        }
        List<PmCmdCont> pmCmdContList = pmCmdContRepository.selectByPonoSlabList(allVirtualSlabNoList, tenantId);
        if (CollectionUtils.isEmpty(pmCmdSlabList)) {
            throw new CommonException("pm.cd_plate_029", "命令参数表", allVirtualSlabNoList);
        }
        List<PmCmdSmallPlt> pmCmdSmallPltList = pmCmdSmallPltRepository.selectByPonoSlabList(allVirtualSlabNoList, tenantId);
        if (CollectionUtils.isEmpty(pmCmdSmallPltList)) {
            throw new CommonException("pm.cd_plate_029", "命令小板表", allVirtualSlabNoList);
        }

        // 根据虚拟板坯号，从组板合同总量表调用组板履历函数，抛组板履历事件
        List<PmPdContSum> pdContSumList = pmPdContSumRepository.selectByPdMatNoList(tenantId, allVirtualSlabNoList);
        if (CollectionUtils.isEmpty(pdContSumList)) {
            throw new CommonException("pm.pd_cc_slab_001", allVirtualSlabNoList, "组板合同总量表");
        }
        Map<String , List<PmPdContSum>> contSumMap = pdContSumList.stream().collect(Collectors.groupingBy(PmPdContSum::getPdMatNo));
        PdMatTypeStrategy pdMatTypeStrategy = PdMatTypeStrategyFactory.matchStrategy(PdMatType.S);
        for (Entry<String, List<PmPdContSum>> entry : contSumMap.entrySet()) {
            pdMatTypeStrategy.pdDeleteEvent(entry.getValue(), entry.getKey()
                    , mscLineNoMap.get(entry.getKey()), Constants.PdProgram.PD_SLAB_DETAIL_DELETE_PROGRAM, tenantId);
        }
        // 记履历表
        // 获取当前时间和用户账号
        Date now = new Date();
        String username = DetailsHelper.getUserDetails().getUsername();
        List<PmPdSlabTra> insertPmPdSlabTraList = pmPdSlabTraRepository.buildPmPdSlabTraList(pdSlabList, "D", now, username);
        List<PmPdSlabInfoTra> insertPmPdSlabInfoTraList = pmPdSlabInfoTraRepository.buildPmPdSlabInfoTraList(pmPdSlabInfoList, "D", now, username);
        List<PmPdBlockPosTra> insertPmPdBlockPosTraList =  pmPdBlockPosTraRepository.buildPmPdBlockPosTraList(pmPdBlockPosList, "D", now, username);
        List<PmPdContSumTra> insertPmPdContSumTraList = pmPdContSumTraRepository.buildPmPdContSumTraList(pdContSumList, "D", now, username);
        List<PmSmallPltPosTra> insertPmSmallPltPosTraList =  pmSmallPltPosTraRepository.buildPmSmallPltPosTraList(pmSmallPltPosList, "D", now, username);
        List<PmCmdSlabTra> insertPmCmdSlabTraList = pmCmdSlabTraRepository.buildPmCmdSlabTraList(pmCmdSlabList, "D", now, username);
        List<PmCmdLargePltTra> insertPmCmdLargePltTraList =  pmCmdLargePltTraRepository.buildPmCmdLargePltTraList(pmCmdLargePltList, "D", now, username);
        List<PmCmdContTra> insertPmCmdContTraList =  pmCmdContTraRepository.buildPmCmdContTraList(pmCmdContList, "D", now, username);
        List<PmCmdSmallPltTra> insertPmCmdSmallPltTraList =  pmCmdSmallPltTraRepository.buildPmCmdSmallPltTraList(pmCmdSmallPltList, "D", now, username);
        // 删除相关表和记录相关履历表
        pmPdSlabRepository.batchDeleteByPrimaryKey(pmPdSlabList);
        pmPdSlabTraRepository.batchInsertSelective(insertPmPdSlabTraList);
        pmPdSlabInfoRepository.batchDeleteByPrimaryKey(pmPdSlabInfoList);
        pmPdSlabInfoTraRepository.batchInsertSelective(insertPmPdSlabInfoTraList);
        pmPdBlockPosRepository.batchDeleteByPrimaryKey(pmPdBlockPosList);
        pmPdBlockPosTraRepository.batchInsertSelective(insertPmPdBlockPosTraList);
        pmPdContSumRepository.batchDeleteByPrimaryKey(pdContSumList);
        pmPdContSumTraRepository.batchInsertSelective(insertPmPdContSumTraList);
        pmSmallPltPosRepository.batchDeleteByPrimaryKey(pmSmallPltPosList);
        pmSmallPltPosTraRepository.batchInsertSelective(insertPmSmallPltPosTraList);
        pmCmdSlabRepository.batchDeleteByPrimaryKey(pmCmdSlabList);
        pmCmdSlabTraRepository.batchInsertSelective(insertPmCmdSlabTraList);
        pmCmdLargePltRepository.batchDeleteByPrimaryKey(pmCmdLargePltList);
        pmCmdLargePltTraRepository.batchInsertSelective(insertPmCmdLargePltTraList);
        pmCmdContRepository.batchDeleteByPrimaryKey(pmCmdContList);
        pmCmdContTraRepository.batchInsertSelective(insertPmCmdContTraList);
        pmCmdSmallPltRepository.batchDeleteByPrimaryKey(pmCmdSmallPltList);
        pmCmdSmallPltTraRepository.batchInsertSelective(insertPmCmdSmallPltTraList);

        // 根据虚拟板坯号从PM_SMALL_PLT_POS获取厚板组板材料号等于虚拟板坯号的所有记录的小板分割号SMALL_PLATE_DIV_NO，将把虚拟板坯信息、大板信息、小板信息抛合同跟踪合同组板解散事件，
        Map<String ,List<PmSmallPltPos>> pmSmallPltPosListMap = pmSmallPltPosList.stream().collect(Collectors.groupingBy(PmSmallPltPos::getPdMatNo));
        try {
            for (Entry<String, List<PmSmallPltPos>> entry : pmSmallPltPosListMap.entrySet()) {
                List<ProContConsumeDTO> proContConsumeDTOs = new ArrayList<>();
                proContConsumeDTOs.add(new ProContConsumeDTO(entry.getKey(), PdProdFlag.VIRTUAL_SLAB.getCode(), BaseConstants.Flag.NO.longValue()));
                proContConsumeDTOs.add(new ProContConsumeDTO(entry.getKey(), PdProdFlag.VIRTUAL_COMPOSITE_SLAB.getCode(), BaseConstants.Flag.NO.longValue()));
                for (PmSmallPltPos pmSmallPltPos : entry.getValue()) {
                    proContConsumeDTOs.add(new ProContConsumeDTO(pmSmallPltPos.getPdMatNo() + pmSmallPltPos.getSmallPlateDivNo(), PdProdFlag.SMALL_POS_VIRTUAL_SLAB.getCode(), BaseConstants.Flag.NO.longValue()));
                }
                eventClient.addEvent(CtEventConstants.EVENT_PM_CONTRACT_RESIDUE_BOARD_CONSUME, proContConsumeDTOs);
            }
            eventClient.sendEvent(tenantId);
        } finally {
            eventClient.remove();
        }

        // 调用轧钢在制品余材释放事件
        List<MatStatusModifyVO> matStatusModifyList = new ArrayList<>();
        slabNoList.forEach(slabNo->{
            MatStatusModifyVO matStatusModifyVO = new MatStatusModifyVO();
            matStatusModifyVO.setMatNo(slabNo);
            matStatusModifyVO.setPpFlag(Constants.PpFlag.SM);
            Map<String, Object> informationMap = new HashMap<>(16);
            informationMap.put("holdTime", new Date());
            informationMap.put("holdMaker", DetailsHelper.getUserDetails().getUserId());
            matStatusModifyVO.setMatInformationString(JSONObject.toJSONString(informationMap));
            matStatusModifyList.add(matStatusModifyVO);
        });
        mmEventClient.batchMatStatusModify(tenantId, Constants.EventCode.MM_IN_PROCESS_SUR_MATERIAL_RELEASE,matStatusModifyList);
    }

    @Override
    public Page<PmPdSlabDTO> slabList(PageRequest pageRequest, String slabNo, Long tenantId) {
        // 改成根据板坯号查询
        List<PmPdSlab> pmPdSlabList = pmPdSlabRepository.selectByCondition(Condition.builder(PmPdSlab.class)
                .andWhere(Sqls.custom().andLike(PmPdSlab.FIELD_SLAB_NO, slabNo, true))
                .andWhere(Sqls.custom().andEqualTo(PmPdSlab.FIELD_TENANT_ID, tenantId))
                .build());
        if (CollectionUtils.isEmpty(pmPdSlabList)) {
            return new Page<>();
        }
        List<String> slabNoList = pmPdSlabList.stream().map(PmPdSlab::getSlabNo).distinct().collect(Collectors.toList());
        List<String> rollLineNoList = pmPdSlabList.stream().map(item -> item.getMscLineNo().substring(2, 4)).distinct().collect(Collectors.toList());
        List<PmPdSlabInfo> pmPdSlabInfoList = pmPdSlabInfoRepository.selectBySlabNoList(slabNoList, tenantId);
        if (CollectionUtils.isEmpty(pmPdSlabInfoList)) {
//            throw new CommonException("pm.pd_slab_001","板坯号", slabNoList, "板坯信息表");
            return new Page<>();
        }
        Map<String, PmPdSlabInfo> pmPdSlabInfoMap = pmPdSlabInfoList.stream().collect(Collectors.toMap(PmPdSlabInfo::getSlabNo, item -> item));
        Map<String, List<PmPdSlab>> pmPdSlabMap = pmPdSlabList.stream().collect(Collectors.groupingBy(PmPdSlab::getSlabNo));

        // 查询到组板常数基准表
        List<PmPdConstBt> pmPdConstBtList =  pmPdConstBtRepository.selectByRollLineNoList(rollLineNoList, tenantId);
        if (CollectionUtils.isEmpty(pmPdConstBtList)) {
            throw new CommonException("pm.pm_pd_const_bt_001", rollLineNoList);
        }
        Map<String, BigDecimal> pmPdConstBtMap = pmPdConstBtList.stream().collect(Collectors.toMap(PmPdConstBt::getRollLineNo, PmPdConstBt::getSlabCutGap));

        List<PmPdSlabDTO> resultList = new ArrayList<>();
        for (PmPdSlab pmPdSlab : pmPdSlabList) {
            PmPdSlabDTO result = new PmPdSlabDTO();
            if (!pmPdSlabInfoMap.containsKey(pmPdSlab.getSlabNo())) {
//                throw new CommonException("pm.pd_slab_001","板坯号", pmPdSlab.getSlabNo(), "板坯信息表");
                continue;
            }
            PmPdSlabInfo pmPdSlabInfo = pmPdSlabInfoMap.get(pmPdSlab.getSlabNo());
            // 组装数据
            buildPmPdSlabDTO(result, pmPdSlab, pmPdSlabInfo);

            // 计算剩余板坯长度：剩余板坯长度 = 实际板坯长度 - 累计分割坯清理前长度 - (分割坯个数-1)*切缝
            BigDecimal remainSlabLen = pmPdSlabInfo.getMatActLen() == null ? BigDecimal.ZERO : pmPdSlabInfo.getMatActLen();
            BigDecimal preCleanSlabLenTotal = pmPdSlabMap.get(pmPdSlab.getSlabNo()).stream().filter(item -> item.getPreCleanSlabLen() != null).map(PmPdSlab::getPreCleanSlabLen).reduce(BigDecimal.ZERO, BigDecimal::add);
            Long slabDivNo = 0L;
            Optional<PmPdSlab> slabDivNoOptional = pmPdSlabMap.get(pmPdSlab.getSlabNo()).stream().filter(item->item.getSlabDivNo() != null).max(Comparator.comparing(PmPdSlab::getSlabDivNo));
            if (slabDivNoOptional.isPresent()) {
            }
            if (!pmPdConstBtMap.containsKey(pmPdSlab.getMscLineNo().substring(2, 4))) {
                throw new CommonException("pm.pm_pd_const_bt_001", pmPdSlab.getMscLineNo().substring(2, 4));
            }
            BigDecimal slabCutGap = BigDecimal.valueOf(slabDivNo - 1).multiply(pmPdConstBtMap.get(pmPdSlab.getMscLineNo().substring(2, 4)));
            remainSlabLen = remainSlabLen.subtract(slabCutGap).subtract(preCleanSlabLenTotal);
            result.setRemainSlabLen(remainSlabLen);

            // 复制操作人
            if (StringUtils.isNotEmpty(pmPdSlab.getPdResp()) && pmPdSlab.getPdResp().matches("\\d+")) {
                MtUserInfo userInfo = userClient.userInfoGet(tenantId, Long.parseLong(pmPdSlab.getPdResp()));
                if (userInfo != null) {
                    result.setPdResp(userInfo.getLoginName() + userInfo.getRealName());
                }
            }
            resultList.add(result);
        }
        // 分页返回
        return PageUtils.convertListToPage(resultList, pageRequest);
    }

    @Override
    public List<PmPdSlabDTO> slabRecordCheckUi(List<String> virtualSlabNoList, Long tenantId) {
        List<PmPdSlabDTO> resList = new ArrayList<>();
        // 根据前端输入的虚拟板坯号，查询组板板坯表（PM_PD_SLAB）中符合条件的数据信息
        List<PmPdSlab> pmPdSlabList = pmPdSlabRepository.selectByCondition(Condition.builder(PmPdSlab.class)
                .andWhere(Sqls.custom().andIn(PmPdSlab.FIELD_VIRTUAL_SLAB_NO, virtualSlabNoList))
                .andWhere(Sqls.custom().andEqualTo(PmPdSlab.FIELD_TENANT_ID, tenantId))
                .build());
        if (CollectionUtils.isEmpty(pmPdSlabList)) {
            return resList;
        }
        // Ⅱ根据组板板坯表（PM_PD_SLAB）中的板坯号SLAB_NO，查询板坯信息表（PM_PD_SLAB_INFO）中的板坯实际厚度、板坯实际宽度、板坯实际长度、板坯实际重量；
        List<String> slabNoList = pmPdSlabList.stream().map(PmPdSlab::getSlabNo).distinct().collect(Collectors.toList());
        List<String> mscLineNoList = pmPdSlabList.stream().map(PmPdSlab::getMscLineNo).distinct().collect(Collectors.toList());

        List<PmPdSlabInfo> pmPdSlabInfoList = pmPdSlabInfoRepository.selectBySlabNoList(slabNoList, tenantId);
        if (CollectionUtils.isEmpty(pmPdSlabInfoList)) {
            throw new CommonException("pm.pd_slab_001","板坯号", slabNoList, "板坯信息表");
        }
        Map<String, PmPdSlabInfo> pmPdSlabInfoMap = pmPdSlabInfoList.stream().collect(Collectors.toMap(PmPdSlabInfo::getSlabNo, item -> item));
        List<String> rollLineNoList = pmPdSlabList.stream().map(item -> item.getMscLineNo().substring(2, 4)).distinct().collect(Collectors.toList());

        // 查询到组板常数基准表
        List<PmPdConstBt> pmPdConstBtList =  pmPdConstBtRepository.selectByRollLineNoList(rollLineNoList, tenantId);
        if (CollectionUtils.isEmpty(pmPdConstBtList)) {
            throw new CommonException("pm.pm_pd_const_bt_001", rollLineNoList);
        }
        Map<String, BigDecimal> pmPdConstBtMap = pmPdConstBtList.stream().collect(Collectors.toMap(PmPdConstBt::getRollLineNo, PmPdConstBt::getSlabCutGap));

        // 根据前端输入的虚拟板坯号，查询组板合同总量表（PM_PD_CONT_SUM）中当前组板材料
        List<PmPdContSum> pdContSumList = pmPdContSumRepository.selectByPdMatNoList(tenantId, virtualSlabNoList);
        if (CollectionUtils.isEmpty(pdContSumList)) {
            throw new CommonException("pm.pd_slab_001","虚拟板坯号", slabNoList, "组板合同总量表");
        }
        Map<String, List<PmPdContSum>> pdContSumMap = pdContSumList.stream().collect(Collectors.groupingBy(PmPdContSum::getPdMatNo));


        // 根据前端输入的临时命令板坯号，查询组合子板位置表（PM_PD_BLOCK_POS）
        List<PmPdBlockPos> pmPdBlockPosList = pmPdBlockPosRepository.selectByPdMatNoList(virtualSlabNoList, tenantId);
        Map<String, List<PmPdBlockPos>> pmPdBlockPosMap = pmPdBlockPosList.stream().collect(Collectors.groupingBy(PmPdBlockPos::getPdMatNo));

        // 根据当前合同号，读取生产合同主表（PM_PRO_CONT）,获取当前合同的组板工序欠件
        List<String> orderNoList = pdContSumList.stream().map(PmPdContSum::getOrderNo).distinct().collect(Collectors.toList());
        List<PmProCont> pmProContList = pmProContRepository.selectByOrderList(orderNoList, tenantId);
        Map<String, BigDecimal> pmProContMap = pmProContList.stream().collect(Collectors.toMap(PmProCont::getOrderNo, PmProCont::getPdLackQty));


        // 当前合同的合同号与产线号，读取生产合同产品属性表（PM_PRO_CONT_PROD_ATTR）的订货厚度、订货宽度、订货长度、订货长度下限、订货长度上限、内部钢种。
        List<PmProContProdTtr> pmProContProdTtrList = pmProContProdTtrRepository.selectByOrderNoList(orderNoList, tenantId);
        Map<String, PmProContProdTtr> pmProContProdTtrMap = pmProContProdTtrList.stream().collect(Collectors.toMap(PmProContProdTtr::getOrderNo, Function.identity()));

        // 查询合同产线工艺表获取stNo
        List<PmContMscTech> pmContMscTechList = pmContMscTechRepository.selectByOrderNoAndMscLineNo(orderNoList, mscLineNoList, tenantId);
        Map<String, String> pmContMscTecheMap =  pmContMscTechList.stream()
                .collect(Collectors.toMap(item -> Strings.concat(item.getOrderNo(), item.getMscLineNo()),PmContMscTech::getStNo));


        for (PmPdSlab pmPdSlab : pmPdSlabList) {
            PmPdSlabDTO result = new PmPdSlabDTO();
            if (!pmPdSlabInfoMap.containsKey(pmPdSlab.getSlabNo())) {
                throw new CommonException("pm.pd_slab_001","板坯号", pmPdSlab.getSlabNo(), "板坯信息表");
            }
            PmPdSlabInfo pmPdSlabInfo = pmPdSlabInfoMap.get(pmPdSlab.getSlabNo());
            // 组装数据
            buildPmPdSlabDTO(result, pmPdSlab, pmPdSlabInfo);

            // 计算剩余板坯长度：剩余板坯长度 = 实际板坯长度 - 累计分割坯清理前长度 - (分割坯个数-1)*切缝
            BigDecimal remainSlabLen = pmPdSlabInfo.getMatActLen() == null ? BigDecimal.ZERO : pmPdSlabInfo.getMatActLen();
            Long slabDivNo = 0L;
            Optional<PmPdSlab> slabDivNoOptional = pmPdSlabList.stream().filter(item->item.getSlabDivNo() != null).max(Comparator.comparing(PmPdSlab::getSlabDivNo));
            if (slabDivNoOptional.isPresent()) {

            }
            if (!pmPdConstBtMap.containsKey(pmPdSlab.getMscLineNo().substring(2, 4))) {
                throw new CommonException("pm.pm_pd_const_bt_001", pmPdSlab.getMscLineNo().substring(2, 4));
            }
            BigDecimal slabCutGap = BigDecimal.valueOf(slabDivNo - 1).multiply(pmPdConstBtMap.get(pmPdSlab.getMscLineNo().substring(2, 4)));
            remainSlabLen = remainSlabLen.subtract(slabCutGap);
            result.setRemainSlabLen(remainSlabLen);

            // 复制操作人
            if (StringUtils.isNotEmpty(pmPdSlab.getPdResp()) && pmPdSlab.getPdResp().matches("\\d+")) {
                MtUserInfo userInfo = userClient.userInfoGet(tenantId, Long.parseLong(pmPdSlab.getPdResp()));
                result.setPdResp(userInfo.getLoginName() + userInfo.getRealName());
            }

            // 组装合同数据
            List<PmPdSlabOrderDTO> pmPdSlabOrderDTOList = new ArrayList<>();
            if (pdContSumMap.containsKey(pmPdSlab.getVirtualSlabNo())) {
                for (PmPdContSum pmPdContSum : pdContSumMap.get(pmPdSlab.getVirtualSlabNo())) {
                    PmPdSlabOrderDTO pmPdSlabOrderDTO = new PmPdSlabOrderDTO();
                    pmPdSlabOrderDTO.setOrderNo(pmPdContSum.getOrderNo());
                    pmPdSlabOrderDTO.setAxisFlag(pmPdContSum.getAxisFlag());

                    if (!pmProContMap.isEmpty()) {
                        pmPdSlabOrderDTO.setPdLackQty(pmProContMap.getOrDefault(pmPdContSum.getOrderNo(), null));
                    }
                    pmPdSlabOrderDTO.setSmallPlateThick(pmPdContSum.getSmallPlateThick());
                    pmPdSlabOrderDTO.setSmallPlateWidth(pmPdContSum.getSmallPlateWidth());
                    pmPdSlabOrderDTO.setSmallPlateLen(pmPdContSum.getSmallPlateLen());
                    if (!pmProContProdTtrMap.isEmpty() && pmProContProdTtrMap.containsKey(pmPdContSum.getOrderNo())) {
                        PmProContProdTtr pmProContProdTtr = pmProContProdTtrMap.get(pmPdContSum.getOrderNo());
                        pmPdSlabOrderDTO.setOrderThick(pmProContProdTtr.getOrderThick());
                        pmPdSlabOrderDTO.setOrderWidth(pmProContProdTtr.getOrderWidth());
                        pmPdSlabOrderDTO.setOrderLen(pmProContProdTtr.getOrderLen());
                        pmPdSlabOrderDTO.setOrderLenMin(pmProContProdTtr.getOrderMinLen());
                        pmPdSlabOrderDTO.setOrderLenMax(pmProContProdTtr.getOrderMaxLen());
                    }
                    if (!pmContMscTecheMap.isEmpty()) {
                        pmPdSlabOrderDTO.setStNo(pmContMscTecheMap.getOrDefault(Strings.concat(pmPdContSum.getOrderNo(), pmPdSlab.getMscLineNo()), null));
                    }
                    pmPdSlabOrderDTOList.add(pmPdSlabOrderDTO);
                }
            }
            result.setPmPdSlabOrderDTOList(pmPdSlabOrderDTOList);

            // 组合子板位置信息
            result.setPmPdBlockPosList(pmPdBlockPosMap.get(pmPdSlab.getVirtualSlabNo()));
            resList.add(result);
        }
        return resList;
    }

    @Override
    public Page<PmPdPlateDTO> plateList(PageRequest pageRequest, String plateNo, Long tenantId) {
        // 根据钢板号
        List<PmPdPlate> pmPdPlateList = pmPdPlateRepository.selectByCondition(Condition.builder(PmPdPlate.class)
                .andWhere(Sqls.custom().andEqualTo(PmPdPlate.FIELD_PLATE_NO, plateNo, true))
                .andWhere(Sqls.custom().andEqualTo(PmPdPlate.FIELD_TENANT_ID, tenantId))
                .build());
        if (CollectionUtils.isEmpty(pmPdPlateList)) {
            return new Page<>();
        }

        // 根据板坯号查询钢板信息表
        List<String> plateNoList = pmPdPlateList.stream().map(PmPdPlate::getPlateNo).collect(Collectors.toList());
        List<PmPdPlateInfo> pmPdPlateInfoList = pmPdPlateInfoRepository.selectByPlateNoList(tenantId, plateNoList);
        if (CollectionUtils.isEmpty(pmPdPlateInfoList)) {
            throw new CommonException("pm.pd_slab_001","钢板号",  plateNoList, "钢板信息表");
        }
        Map<String, PmPdPlateInfo> pmPdPlateInfoMap = pmPdPlateInfoList.stream().collect(Collectors.toMap(PmPdPlateInfo::getPlateNo, Function.identity()));

        // 赋值
        List<PmPdPlateDTO> resList = new ArrayList<>();
        for (PmPdPlate pmPdPlate : pmPdPlateList) {
            PmPdPlateDTO result = new PmPdPlateDTO();
            result.setPlateNo(pmPdPlate.getPlateNo());
            result.setFormPlateMode(pmPdPlate.getFormPlateMode());
            result.setTmpSlabNo(pmPdPlate.getTmpSlabNo());
            if (!pmPdPlateInfoMap.containsKey(pmPdPlate.getPlateNo())) {
//                throw new CommonException("pm.pd_slab_001","钢板号",  pmPdPlate.getPlateNo(), "钢板信息表");
                continue;
            }
            PmPdPlateInfo pmPdPlateInfo = pmPdPlateInfoMap.get(pmPdPlate.getPlateNo());
            result.setMatActThick(pmPdPlateInfo.getMatActThick());
            result.setMatActWidth(pmPdPlateInfo.getMatActWidth());
            result.setMatActLen(pmPdPlateInfo.getMatActLen());
            result.setOuBacklogCode(pmPdPlateInfo.getOuBacklogCode());
            result.setPdResp(pmPdPlateInfo.getPdResp());
            if (StringUtils.isNotEmpty(pmPdPlateInfo.getPdResp()) && pmPdPlateInfo.getPdResp().matches("\\d+")) {
                MtUserInfo userInfo = userClient.userInfoGet(tenantId, Long.parseLong(pmPdPlateInfo.getPdResp()));
                if (userInfo != null) {
                    result.setPdResp(userInfo.getLoginName() + userInfo.getRealName());
                }
            }
            result.setPdStatusHp(pmPdPlateInfo.getPdStatusHp());
            result.setStNo(pmPdPlate.getStNo());
            result.setSgSign(pmPdPlate.getSgSign());
            result.setCommandYield(pmPdPlate.getCommandYield());
            result.setMscLineNo(pmPdPlateInfo.getMscLineNo());
            resList.add(result);
        }
        return PageUtils.convertListToPage(resList, pageRequest);
    }

    @Override
    public List<PmPdPlateDTO> plateRecordCheckUi(List<String> plateNoList, Long tenantId) {
        // 根据临时命令板坯号查询钢板表
        List<PmPdPlate> pmPdPlateList = pmPdPlateRepository.selectByCondition(Condition.builder(PmPdPlate.class)
                .andWhere(Sqls.custom().andIn(PmPdPlate.FIELD_PLATE_NO, plateNoList, true))
                .andWhere(Sqls.custom().andEqualTo(PmPdPlate.FIELD_TENANT_ID, tenantId))
                .build());
        if (CollectionUtils.isEmpty(pmPdPlateList)) {
            return new Page<>();
        }
//        List<String> plateNoList = pmPdPlateList.stream().map(PmPdPlate::getPlateNo).collect(Collectors.toList());
        // 根据板坯号查询钢板信息表
        List<PmPdPlateInfo> pmPdPlateInfoList = pmPdPlateInfoRepository.selectByCondition(Condition.builder(PmPdPlateInfo.class)
                .andWhere(Sqls.custom().andIn(PmPdPlateInfo.FIELD_PLATE_NO, plateNoList))
                .andWhere(Sqls.custom().andEqualTo(PmPdPlateInfo.FIELD_TENANT_ID, tenantId))
                .build());
        if (CollectionUtils.isEmpty(pmPdPlateInfoList)) {
            throw new CommonException("pm.pd_slab_001","钢板号",  plateNoList, "钢板信息表");
        }
        List<String> mscLineNoList = pmPdPlateInfoList.stream().map(PmPdPlateInfo::getMscLineNo).distinct().collect(Collectors.toList());
        Map<String, PmPdPlateInfo> pmPdPlateInfoMap = pmPdPlateInfoList.stream().collect(Collectors.toMap(PmPdPlateInfo::getPlateNo, Function.identity()));

        // 根据前端输入的虚拟板坯号，查询组板合同总量表（PM_PD_CONT_SUM）中当前组板材料
        List<PmPdContSum> pdContSumList = pmPdContSumRepository.selectByPdMatNoList(tenantId, plateNoList);
        if (CollectionUtils.isEmpty(pdContSumList)) {
            throw new CommonException("pm.pd_slab_001","钢板号", plateNoList, "组板合同总量表");
        }
        Map<String, List<PmPdContSum>> pdContSumMap = pdContSumList.stream().collect(Collectors.groupingBy(PmPdContSum::getPdMatNo));


        // 根据前端输入的临时命令板坯号，查询组合子板位置表（PM_PD_BLOCK_POS）
        List<PmPdBlockPos> pmPdBlockPosList = pmPdBlockPosRepository.selectByPdMatNoList(plateNoList, tenantId);
        Map<String, List<PmPdBlockPos>> pmPdBlockPosMap = pmPdBlockPosList.stream().collect(Collectors.groupingBy(PmPdBlockPos::getPdMatNo));

        // 根据当前合同号，读取生产合同主表（PM_PRO_CONT）,获取当前合同的组板工序欠件
        List<String> orderNoList = pdContSumList.stream().map(PmPdContSum::getOrderNo).distinct().collect(Collectors.toList());
        List<PmProCont> pmProContList = pmProContRepository.selectByOrderList(orderNoList, tenantId);
        Map<String, BigDecimal> pmProContMap = pmProContList.stream().collect(Collectors.toMap(PmProCont::getOrderNo, PmProCont::getPdLackQty));

        // 当前合同的合同号与产线号，读取生产合同产品属性表（PM_PRO_CONT_PROD_ATTR）的订货厚度、订货宽度、订货长度、订货长度下限、订货长度上限、内部钢种。
        List<PmProContProdTtr> pmProContProdTtrList = pmProContProdTtrRepository.selectByOrderNoList(orderNoList, tenantId);
        Map<String, PmProContProdTtr> pmProContProdTtrMap = pmProContProdTtrList.stream().collect(Collectors.toMap(PmProContProdTtr::getOrderNo, Function.identity()));

        // 查询合同产线工艺表获取stNo
        List<PmContMscTech> pmContMscTechList = pmContMscTechRepository.selectByOrderNoAndMscLineNo(orderNoList, mscLineNoList, tenantId);
        Map<String, String> pmContMscTecheMap =  pmContMscTechList.stream()
                .collect(Collectors.toMap(item -> Strings.concat(item.getOrderNo(), item.getMscLineNo()),PmContMscTech::getStNo));

        // 赋值
        List<PmPdPlateDTO> resList = new ArrayList<>();
        for (PmPdPlate pmPdPlate : pmPdPlateList) {
            PmPdPlateDTO result = new PmPdPlateDTO();
            result.setPlateNo(pmPdPlate.getPlateNo());
            result.setTmpSlabNo(pmPdPlate.getTmpSlabNo());
            result.setFormPlateMode(pmPdPlate.getFormPlateMode());
            if (!pmPdPlateInfoMap.containsKey(pmPdPlate.getPlateNo())) {
                throw new CommonException("pm.pd_slab_001","钢板号",  pmPdPlate.getPlateNo(), "钢板信息表");
            }
            PmPdPlateInfo pmPdPlateInfo = pmPdPlateInfoMap.get(pmPdPlate.getPlateNo());
            result.setMatActThick(pmPdPlateInfo.getMatActThick());
            result.setMatActWidth(pmPdPlateInfo.getMatActWidth());
            result.setMatActLen(pmPdPlateInfo.getMatActLen());
            result.setOuBacklogCode(pmPdPlateInfo.getOuBacklogCode());
            if (StringUtils.isNotEmpty(pmPdPlateInfo.getPdResp()) && pmPdPlateInfo.getPdResp().matches("\\d+")) {
                MtUserInfo userInfo = userClient.userInfoGet(tenantId, Long.parseLong(pmPdPlateInfo.getPdResp()));
                result.setPdResp(userInfo.getLoginName() + userInfo.getRealName());
            }
            result.setPdStatusHp(pmPdPlateInfo.getPdStatusHp());
            result.setStNo(pmPdPlate.getStNo());
            result.setSgSign(pmPdPlate.getSgSign());
            result.setCommandYield(pmPdPlate.getCommandYield());
            result.setMscLineNo(pmPdPlateInfo.getMscLineNo());

            // 组装合同数据
            List<PmPdSlabOrderDTO> pmPdSlabOrderDTOList = new ArrayList<>();
            if (pdContSumMap.containsKey(pmPdPlate.getPlateNo())) {
                for (PmPdContSum pmPdContSum : pdContSumMap.get(pmPdPlate.getPlateNo())) {
                    PmPdSlabOrderDTO pmPdSlabOrderDTO = new PmPdSlabOrderDTO();
                    pmPdSlabOrderDTO.setOrderNo(pmPdContSum.getOrderNo());
                    pmPdSlabOrderDTO.setAxisFlag(pmPdContSum.getAxisFlag());

                    if (!pmProContMap.isEmpty()) {
                        pmPdSlabOrderDTO.setPdLackQty(pmProContMap.getOrDefault(pmPdContSum.getOrderNo(), null));
                    }
                    pmPdSlabOrderDTO.setSmallPlateThick(pmPdContSum.getSmallPlateThick());
                    pmPdSlabOrderDTO.setSmallPlateWidth(pmPdContSum.getSmallPlateWidth());
                    pmPdSlabOrderDTO.setSmallPlateLen(pmPdContSum.getSmallPlateLen());
                    if (!pmProContProdTtrMap.isEmpty() && pmProContProdTtrMap.containsKey(pmPdContSum.getOrderNo())) {
                        PmProContProdTtr pmProContProdTtr = pmProContProdTtrMap.get(pmPdContSum.getOrderNo());
                        pmPdSlabOrderDTO.setOrderThick(pmProContProdTtr.getOrderThick());
                        pmPdSlabOrderDTO.setOrderWidth(pmProContProdTtr.getOrderWidth());
                        pmPdSlabOrderDTO.setOrderLen(pmProContProdTtr.getOrderLen());
                        pmPdSlabOrderDTO.setOrderLenMin(pmProContProdTtr.getOrderMinLen());
                        pmPdSlabOrderDTO.setOrderLenMax(pmProContProdTtr.getOrderMaxLen());
                    }
                    if (!pmContMscTecheMap.isEmpty()) {
                        pmPdSlabOrderDTO.setStNo(pmContMscTecheMap.getOrDefault(Strings.concat(pmPdContSum.getOrderNo(), pmPdPlateInfo.getMsc()), null));
                    }
                    pmPdSlabOrderDTOList.add(pmPdSlabOrderDTO);
                }
            }

            if (CollectionUtils.isNotEmpty(pmPdSlabOrderDTOList)) {
                List<PmPdSlabOrderDTO> axisOrderList = pmPdSlabOrderDTOList.stream()
                        .filter(item -> 1 == item.getAxisFlag()).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(axisOrderList)) {
                    if (axisOrderList.size() > 1) {
                        throw new CommonException("pm.pd_plate_001",pmPdPlate.getPlateNo());
                    } else {
                        result.setOrderNoAxis(axisOrderList.get(0).getOrderNo());
                    }
                } else {
                    throw new CommonException("pm.pd_plate_002",pmPdPlate.getPlateNo());
                }
            }
            result.setPmPdSlabOrderDTOList(pmPdSlabOrderDTOList);

            // 获取输入材料上各组合子板的位置信息
            result.setPmPdBlockPosList(pmPdBlockPosMap.get(pmPdPlate.getPlateNo()));
            resList.add(result);
        }
        return resList;
    }

    private void buildPmPdSlabDTO(PmPdSlabDTO result, PmPdSlab pmPdSlab, PmPdSlabInfo pmPdSlabInfo) {
        result.setVirtualSlabNo(pmPdSlab.getVirtualSlabNo());
        result.setSlabNo(pmPdSlab.getSlabNo());
        result.setStNo(pmPdSlab.getStNo());
        result.setFormPlateMode(pmPdSlab.getFormPlateMode());
        result.setPdStatusHp(pmPdSlab.getPdStatusHp());
        result.setFurType(pmPdSlab.getFurType());
        result.setMatActThick(pmPdSlabInfo.getMatActThick());
        result.setMatActWidth(pmPdSlabInfo.getMatActWidth());
        result.setMatActLen(pmPdSlabInfo.getMatActLen());
        result.setMatActWt(pmPdSlabInfo.getMatActWt());
        result.setNeedSlabLen(pmPdSlab.getNeedSlabLen());
        result.setInfurSlabLen(pmPdSlab.getInfurSlabLen());
        result.setPreCleanSlabLen(pmPdSlab.getPreCleanSlabLen());
        result.setRollDirectCode(pmPdSlab.getRollDirectCode());
        result.setCombinePlateWidth(pmPdSlab.getCombinePlateWidth());
        result.setCombinePlateLen(pmPdSlab.getCombinePlateLen());
        result.setFixSlabLen(pmPdSlab.getFixSlabLen());
        result.setRollAimThick(pmPdSlab.getRollAimThick());
        result.setRollAimWidth(pmPdSlab.getRollAimWidth());
        result.setRollAimLen(pmPdSlab.getRollAimLen());
        result.setFixSlabLenFlag(pmPdSlab.getFixSlabLenFlag());
        result.setNormYield(pmPdSlab.getNormYield());
        result.setRollYield(pmPdSlab.getRollYield());
        result.setCommandYield(pmPdSlab.getCommandYield());
        result.setSlabCleanWtLossRateFr(pmPdSlab.getSlabCleanWtLossRateFr());
        result.setOrderNoAxis(pmPdSlab.getOrderNoAxis());
        result.setMscLineNo(pmPdSlab.getMscLineNo());
    }
}
