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

import com.alibaba.fastjson.JSON;
import com.xisc.pm.api.dto.ObtainWitnessPointDTO;
import com.xisc.pm.api.dto.PmSlabEstaPlanDissoDTO;
import com.xisc.pm.api.dto.PmSteelCastHeatReqParamDTO;
import com.xisc.pm.api.dto.ctevent.PmSlabPreCastingDTO;
import com.xisc.pm.app.service.PmSlabEstaPlanService;
import com.xisc.pm.app.service.PmSteelCastHeatService;
import com.xisc.pm.common.dto.ProductionPlanningApiDTO;
import com.xisc.pm.domain.entity.PmCmdCont;
import com.xisc.pm.domain.entity.PmCmdLargePlt;
import com.xisc.pm.domain.entity.PmCmdSlab;
import com.xisc.pm.domain.entity.PmContMscTech;
import com.xisc.pm.domain.entity.PmHotConfig;
import com.xisc.pm.domain.entity.PmHotDest;
import com.xisc.pm.domain.entity.PmHotDestTra;
import com.xisc.pm.domain.entity.PmPdCcSlab;
import com.xisc.pm.domain.entity.PmPdContSum;
import com.xisc.pm.domain.entity.PmSlabEstaPlan;
import com.xisc.pm.domain.entity.PmSlabMerge;
import com.xisc.pm.domain.entity.PmSlabPoolIn;
import com.xisc.pm.domain.entity.PmSmallPltPos;
import com.xisc.pm.domain.entity.PmSteelCastFlow;
import com.xisc.pm.domain.entity.PmSteelCastHeat;
import com.xisc.pm.domain.entity.PmSteelCastLot;
import com.xisc.pm.domain.entity.PmSteelCastSlab;
import com.xisc.pm.domain.repository.PmCmdContRepository;
import com.xisc.pm.domain.repository.PmCmdLargePltRepository;
import com.xisc.pm.domain.repository.PmCmdSlabRepository;
import com.xisc.pm.domain.repository.PmContMscTechRepository;
import com.xisc.pm.domain.repository.PmHotConfigRepository;
import com.xisc.pm.domain.repository.PmHotDestRepository;
import com.xisc.pm.domain.repository.PmHotDestTraRepository;
import com.xisc.pm.domain.repository.PmPdCcSlabRepository;
import com.xisc.pm.domain.repository.PmPdContSumRepository;
import com.xisc.pm.domain.repository.PmQdToPoOrderRepository;
import com.xisc.pm.domain.repository.PmSlabEstaPlanRepository;
import com.xisc.pm.domain.repository.PmSlabMergeRepository;
import com.xisc.pm.domain.repository.PmSlabPoolInRepository;
import com.xisc.pm.domain.repository.PmSmallPltPosRepository;
import com.xisc.pm.domain.repository.PmSteelCastFlowRepository;
import com.xisc.pm.domain.repository.PmSteelCastHeatRepository;
import com.xisc.pm.domain.repository.PmSteelCastLotRepository;
import com.xisc.pm.domain.repository.PmSteelCastSlabRepository;
import com.xisc.pm.domain.vo.PmHotConfigVO;
import com.xisc.pm.infra.client.EventClient;
import com.xisc.pm.infra.client.SmApiClient;
import com.xisc.pm.infra.constant.Constants;
import com.xisc.pm.infra.constant.CtEventConstants;
import com.xisc.pm.infra.mapper.PmSteelCastHeatMapper;
import com.xisc.pm.infra.util.Utils;
import io.choerodon.core.exception.CommonException;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.logging.log4j.util.Strings;
import org.hzero.core.base.BaseConstants;
import org.hzero.mybatis.domian.Condition;
import org.hzero.mybatis.util.Sqls;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 炼钢连铸制造命令炉次表 (PmSteelCastHeat)应用服务
 *
 * @author 纪文桃 wentao.ji01@hand-china.com
 * @since 2024-08-15 08:20:13
 */
@Slf4j
@Service
public class PmSteelCastHeatServiceImpl implements PmSteelCastHeatService {

    private static final Logger LOGGER = LoggerFactory.getLogger(PmSteelCastHeatServiceImpl.class);

    @Autowired
    private PmSteelCastHeatRepository pmSteelCastHeatRepository;
    @Autowired
    private PmSteelCastHeatMapper pmSteelCastHeatMapper;
    @Autowired
    private PmSteelCastSlabRepository pmSteelCastSlabRepository;
    @Autowired
    private PmCmdContRepository pmCmdContRepository;
    @Autowired
    private PmContMscTechRepository pmContMscTechRepository;
    @Autowired
    private PmHotConfigRepository pmHotConfigRepository;
    @Autowired
    private PmHotDestRepository pmHotDestRepository;
    @Autowired
    private PmHotDestTraRepository pmHotDestTraRepository;
    @Autowired
    private PmSteelCastFlowRepository pmSteelCastFlowRepository;
    @Autowired
    private PmSteelCastLotRepository pmSteelCastLotRepository;
    @Autowired
    private PmSlabEstaPlanService pmSlabEstaPlanService;
    @Autowired
    private PmSlabEstaPlanRepository pmSlabEstaPlanRepository;
    @Autowired
    private PmPdCcSlabRepository pmPdCcSlabRepository;
    @Autowired
    private  SmApiClient smApiClient;
    @Autowired
    private  PmSlabMergeRepository pmSlabMergeRepository;
    @Autowired
    private PmPdContSumRepository pmPdContSumRepository;
    @Autowired
    private PmCmdSlabRepository pmCmdSlabRepository;
    @Autowired
    private PmCmdLargePltRepository pmCmdLargePltRepository;
    @Autowired
    private PmSmallPltPosRepository pmSmallPltPosRepository;
    @Autowired
    private PmSlabPoolInRepository pmSlabPoolInRepository;
    @Autowired
    private EventClient eventClient;

    @Autowired
    private PmQdToPoOrderRepository pmQdToPoOrderRepository;

    
    @Override
    public List<PmSteelCastHeat> list(PmSteelCastHeat pmSteelCastHeat, Long tenantId) {
        // 条件搜索查询
        List<PmSteelCastHeat> steelCastHeatList = pmSteelCastHeatMapper.queryList(pmSteelCastHeat, tenantId);
        // 为空则返回
        if (CollectionUtils.isEmpty(steelCastHeatList)) {
            return steelCastHeatList;
        }
        List<PmSteelCastHeat> pmSteelCastHeatList = new ArrayList<>();
        pmSteelCastHeatList.addAll(steelCastHeatList.stream().filter(item -> !Constants.PonoStatus.STATUS_15.equals(item.getPonoStatus())).collect(Collectors.toList()));
        // 计划下达状态查询轧钢为挂起的状态
        List<PmSteelCastHeat> postatusHeatList = steelCastHeatList.stream().filter(item -> Constants.PonoStatus.STATUS_15.equals(item.getPonoStatus())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(postatusHeatList)) {
            List<String> ponoStausList = postatusHeatList.stream().map(PmSteelCastHeat::getPono).collect(Collectors.toList());
            List<String> newPonoList = pmSteelCastHeatMapper.queryPonoIsAdjust(ponoStausList, tenantId);
            if (CollectionUtils.isNotEmpty(newPonoList)) {
                pmSteelCastHeatList.addAll(steelCastHeatList.stream().filter(item -> newPonoList.contains(item.getPono())).collect(Collectors.toList()));
            }
        }

        if (CollectionUtils.isEmpty(pmSteelCastHeatList)) {
            return pmSteelCastHeatList;
        }
        List<String> ponoList = pmSteelCastHeatList.stream().map(PmSteelCastHeat::getPono).collect(Collectors.toList());
        List<String> castLotNoList = pmSteelCastHeatList.stream().map(PmSteelCastHeat::getCastLotNo).collect(Collectors.toList());
        Map<String, PmSteelCastLot> pmSteelCastLotMap = pmSteelCastLotRepository.selectByCastLotNoList(castLotNoList, tenantId).stream().collect(Collectors.toMap(PmSteelCastLot::getCastLotNo, Function.identity()));
        Map<String, PmSteelCastFlow> pmSteelCastFlowMap = pmSteelCastFlowRepository.selectByPonoList(ponoList, tenantId).stream().collect(Collectors.toMap(PmSteelCastFlow::getPono, Function.identity()));
        // 获取命令板坯号和板坯位置代码

        List<PmSteelCastSlab> pmSteelCastSlabList = pmSteelCastSlabRepository.selectByCondition(Condition.builder(PmSteelCastSlab.class)
                .andWhere(Sqls.custom().andIn(PmSteelCastSlab.FIELD_PONO, ponoList))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastSlab.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastSlab.FIELD_SLAB_SEQ_HEAT, 1L))
                .build());
        if (CollectionUtils.isNotEmpty(pmSteelCastSlabList)) {
            // 转map,方便取值
            Map<String, PmSteelCastSlab> castSlabMap = pmSteelCastSlabList.stream().collect(Collectors.toMap(PmSteelCastSlab::getPono, Function.identity()));
            // 赋值
            pmSteelCastHeatList.forEach(item -> {
                if (castSlabMap.containsKey(item.getPono())) {
                    PmSteelCastSlab slab = castSlabMap.get(item.getPono());
                    item.setSlabNo(slab.getSlabNo());
                    item.setSlabPlaceCode(slab.getSlabPlaceCode());
                }
                if (pmSteelCastLotMap.containsKey(item.getCastLotNo())) {
                    PmSteelCastLot pmSteelCastLot = pmSteelCastLotMap.get(item.getCastLotNo());
                    item.setSlabThick(pmSteelCastLot.getSlabThick());
                    item.setBilletType(pmSteelCastLot.getBilletType());

                }
                if (pmSteelCastFlowMap.containsKey(item.getPono())) {
                    item.setSlabWidth(pmSteelCastFlowMap.get(item.getPono()).getSlabWidth());
                }
            });
        }

        // 非外卖坯和备坯的热处理模式
        Map<String, PmContMscTech> contMscTecheMap = new HashMap<>(pmSteelCastHeatList.size());
        List<PmCmdCont> pmCmdContList = new ArrayList<>(pmSteelCastHeatList.size());
        List<String> orderPonoList = pmSteelCastHeatList.stream().filter(item -> Constants.CcType.TYPE_1.equals(item.getCcType()) || Constants.CcType.TYPE_5.equals(item.getCcType()))
                .map(PmSteelCastHeat::getPono).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(orderPonoList)) {
            Condition.Builder builder = Condition.builder(PmCmdCont.class)
                    .andWhere(Sqls.custom().andEqualTo(PmCmdCont.FIELD_TENANT_ID, tenantId));
            Sqls sqls = Sqls.custom();
            orderPonoList.forEach(pono -> sqls.orLikeRight(PmCmdCont.FIELD_PONO_SLAB_NO, pono));
            pmCmdContList = pmCmdContRepository.selectByCondition(builder.andWhere(sqls).build());
            if (CollectionUtils.isEmpty(pmCmdContList)) {
                throw new CommonException("pm.steel_cast_heat_007", ponoList, "命令参数表");
            }
            List<String> orderNoList = pmCmdContList.stream().map(PmCmdCont::getOrderNo).distinct().collect(Collectors.toList());
            List<String> mscLineList = pmCmdContList.stream().map(PmCmdCont::getMscLineNo).distinct().collect(Collectors.toList());
            // 3.	根据产线号以及合同号到【合同产线工艺参数表(PM_CONT_MSC_TECH)】中查询热处理模式（HEAT_TREAT_MODE）
            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().andIn(PmContMscTech.FIELD_MSC_LINE_NO, mscLineList))
                    .build());
            if (CollectionUtils.isNotEmpty(pmContMscTecheList)) {
                contMscTecheMap = pmContMscTecheList.stream()
                        .collect(Collectors.toMap(item -> Strings.concat(item.getOrderNo(), item.getMscLineNo()), Function.identity()));
                for (PmSteelCastHeat steelCastHeat : pmSteelCastHeatList) {
                    // 制造命令号对应的命令参数表数据
                    if (Constants.CcType.TYPE_1.equals(steelCastHeat.getCcType()) || Constants.CcType.TYPE_5.equals(steelCastHeat.getCcType())) {
                        List<PmCmdCont> contList = pmCmdContList.stream()
                                .filter(cont -> cont.getPonoSlabNo().startsWith(steelCastHeat.getPono())).collect(Collectors.toList());
                        if (CollectionUtils.isEmpty(contList)) {
                            throw new CommonException("pm.steel_cast_heat_007", steelCastHeat.getPono(), "命令参数表");
                        }
                        for (PmCmdCont pmCmdCont : contList) {
                            // 根据合同+产线->热处理模式
                            PmContMscTech orDefault = contMscTecheMap.getOrDefault(Strings.concat(pmCmdCont.getOrderNo(), pmCmdCont.getMscLineNo()), new PmContMscTech());
                            // 有热处理模式
                            if (StringUtils.isNotEmpty(orDefault.getWholeHeatTreatmentType())) {
                                steelCastHeat.setIsHavingHreat(BaseConstants.FlagChar.YES);
                            }
                        }
                    }
                }
            }
        }

        // 2.	将上述查询到的字段信息以及铸机类型返回前台显示，优先按照浇次号（CAST_LOT_NO），其次按照浇次分割号（CAST_LOT_DIV_NO）升序排列
       return  pmSteelCastHeatList.stream().sorted(Comparator.comparing(PmSteelCastHeat::getCastLotNo,Comparator.nullsLast(Comparator.naturalOrder()))
                .thenComparing(PmSteelCastHeat::getCastLotDivNo, Comparator.nullsLast(Comparator.naturalOrder()))).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void planReceive(Long tenantId, PmSteelCastHeatReqParamDTO dto) {
        // 赋值
        // 获取计划时间的最大序号
        long seq = 0L;
        List<PmSteelCastHeat> steelCastHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PLAN_DATE, dto.getPlanDate()))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_MAIN_BACKLOG_CODE, dto.getMainBacklogCode()))
                .build());
        if (CollectionUtils.isNotEmpty(steelCastHeatList)) {
            seq = steelCastHeatList.stream().mapToLong(PmSteelCastHeat::getCcSeq).max().getAsLong();
        }
        List<String> castLotNoList = dto.getPmSteelCastHeatList().stream().map(PmSteelCastHeat::getCastLotNo).collect(Collectors.toList());
        List<PmSteelCastHeat> castHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andIn(PmSteelCastHeat.FIELD_CAST_LOT_NO, castLotNoList))
                .build());
        Map<String, List<PmSteelCastHeat>> castHeatMap = castHeatList.stream().collect(Collectors.groupingBy(PmSteelCastHeat::getCastLotNo));

        for (PmSteelCastHeat pmSteelCastHeat : dto.getPmSteelCastHeatList()) {
            // c)	根据浇次分割号（CAST_LOT_DIV_NO）判断当前炉在浇次中的位置，若为头炉，则令计划浇次头/尾炉标记(RESTRAND_FLG)“T”，若为尾炉，则令RESTRAND_FLG=“W”
            if (pmSteelCastHeat.getCastLotDivNo().equals(1L) ) {
                pmSteelCastHeat.setRestrandFlg("T");
            } else {
                Optional<PmSteelCastHeat> max = castHeatMap.get(pmSteelCastHeat.getCastLotNo()).stream().max(Comparator.comparingLong(PmSteelCastHeat::getCastLotDivNo));
                if (max.isPresent() && pmSteelCastHeat.getCastLotDivNo().equals(max.get().getCastLotDivNo())) {
                    pmSteelCastHeat.setRestrandFlg("W");
                }
            }

            // d)	计算浇铸时间（POUR_TIME） 炉中是否为自产钢锭，制造命令号（PONO）第三位为字符为“5”表示自产钢锭
            if ("5".equals(pmSteelCastHeat.getPono().substring(2, 3))) {
                pmSteelCastHeat.setPourTime(36L);
            } else {
                // 浇铸时间 = 计划出钢重量 / （7.85 * (板坯宽度 / 1000.0) * (板坯厚度/1000.0)），计算结果向上取整；
                if (pmSteelCastHeat.getSlabWidth() == null) {
                    throw new CommonException("pm.steel_cast_heat_014", pmSteelCastHeat.getPono());
                }
                if (pmSteelCastHeat.getSlabThick() == null) {
                    throw new CommonException("pm.steel_cast_heat_015", pmSteelCastHeat.getPono());
                }
                if (pmSteelCastHeat.getSlabWidth().compareTo(BigDecimal.valueOf(0)) == 0 ||
                        pmSteelCastHeat.getSlabThick().compareTo(BigDecimal.valueOf(0)) == 0) {
                    throw new CommonException("pm.steel_cast_heat_001", pmSteelCastHeat.getSlabWidth(),
                            pmSteelCastHeat.getSlabThick());
                } else {
                    BigDecimal divide = BigDecimal.valueOf(7.85).multiply(pmSteelCastHeat.getSlabWidth().divide(BigDecimal.valueOf(1000.0), 4, BigDecimal.ROUND_HALF_UP))
                            .multiply(pmSteelCastHeat.getSlabThick().divide(BigDecimal.valueOf(1000.0), 4, BigDecimal.ROUND_HALF_UP));
                    BigDecimal pourTime = pmSteelCastHeat.getPlanTapWt().divide(divide, 4, BigDecimal.ROUND_HALF_UP).setScale(0, RoundingMode.CEILING);
                    pmSteelCastHeat.setPourTime(pourTime.longValue());
                }
            }
            pmSteelCastHeat.setPonoStatus(Constants.PonoStatus.STATUS_13);
            pmSteelCastHeat.setCcSeq(++seq);
            pmSteelCastHeat.setPlanDate(dto.getPlanDate());
            pmSteelCastHeat.setCcMachNo(dto.getCcMachNo());
        }
        // 批量更新
        pmSteelCastHeatRepository.batchUpdateByPrimaryKey(dto.getPmSteelCastHeatList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void planMove(Long tenantId, PmSteelCastHeatReqParamDTO dto) {
        // 若操作LOT等于基准LOT，则前端提示（右下角）：PM.CASTING.MACHINE.PRE.PLAN.008，程序结束
        if (dto.getOperationLot().equals(dto.getBasicLot())) {
            throw new CommonException("pm.casting_machine_pre_plan_008", dto.getOperationLot(), dto.getBasicLot());
        }
        // a)	获取校验操作LOT号：
        List<PmSteelCastHeat> operationDateCastHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_CAST_LOT_NO, dto.getOperationLot()))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_MAIN_BACKLOG_CODE, dto.getMainBacklogCode()))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PLAN_DATE, dto.getPlanDate()))
                .build());
        if (CollectionUtils.isEmpty(operationDateCastHeatList)) {
            throw new CommonException("pm.casting_machine_pre_plan_009", dto.getOperationLot());
        }
        // 校验状态 值为“13”，表示计划接收状态
        List<PmSteelCastHeat> operationCastHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_CAST_LOT_NO, dto.getOperationLot()))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_MAIN_BACKLOG_CODE, dto.getMainBacklogCode()))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PONO_STATUS, Constants.PonoStatus.STATUS_13))
                .build());
        if (CollectionUtils.isEmpty(operationCastHeatList)) {
            throw new CommonException("pm.casting_machine_pre_plan_010", dto.getOperationLot());
        }
        // vi.	操作最LOT（这一浇次）的最小顺序号
        long minOperationSeq = 0L;
        Optional<Long> seqOptional = operationCastHeatList.stream().map(PmSteelCastHeat::getCcSeq).min(Comparator.comparing(Long::longValue));
        if (seqOptional.isPresent()) {
            minOperationSeq = seqOptional.get();
        }
        // vi.	操作最LOT（这一浇次）的最大顺序号
        long maxOperationSeq = 0L;
        Optional<Long> seqMaxOptional = operationCastHeatList.stream().map(PmSteelCastHeat::getCcSeq).max(Comparator.comparing(Long::longValue));
        if (seqMaxOptional.isPresent()) {
            maxOperationSeq = seqMaxOptional.get();
        }

        // 获取当日计划已确定或者下达最大顺序号
        long sexMoveMax = 0L;
        List<PmSteelCastHeat> steelCastHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PLAN_DATE, dto.getPlanDate()))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_MAIN_BACKLOG_CODE, dto.getMainBacklogCode()))
                .andWhere(Sqls.custom().andGreaterThan(PmSteelCastHeat.FIELD_PONO_STATUS, Constants.PonoStatus.STATUS_13))
                .build());
        if (CollectionUtils.isNotEmpty(steelCastHeatList)) {
            // 已经计划确定的最大连铸计划顺序号（CC_SEQ），
            Optional<Long> ccSeqOptional = steelCastHeatList.stream().map(PmSteelCastHeat::getCcSeq).max(Comparator.comparing(Long::longValue));
            if (ccSeqOptional.isPresent()) {
                sexMoveMax = ccSeqOptional.get();
            }
        }

        List<PmSteelCastHeat> updateList = new ArrayList<>();
        // i.	若输入的基准LOT号为0，则将操作LOT移动到计划日期最前
        if ("0".equals(dto.getBasicLot())) {
            // ，则将操作LOT移动到该最大顺序号后
            long seq = sexMoveMax + 1;
            List<PmSteelCastHeat> sortOperationCastHeatList = operationCastHeatList.stream().sorted(Comparator.comparing(PmSteelCastHeat::getCcSeq)).collect(Collectors.toList());
            for (PmSteelCastHeat pmSteelCastHeat : sortOperationCastHeatList) {
                pmSteelCastHeat.setCcSeq(seq++);
                updateList.add(pmSteelCastHeat);
            }
            // 同时非操作lot的都要挪动
            List<PmSteelCastHeat> otherLotHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_MAIN_BACKLOG_CODE, dto.getMainBacklogCode()))
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PLAN_DATE, dto.getPlanDate()))
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PONO_STATUS, Constants.PonoStatus.STATUS_13))
                    .andWhere(Sqls.custom().andGreaterThan(PmSteelCastHeat.FIELD_CC_SEQ, sexMoveMax))
                    .andWhere(Sqls.custom().andLessThan(PmSteelCastHeat.FIELD_CC_SEQ, minOperationSeq))
                    .build());
            if (CollectionUtils.isNotEmpty(otherLotHeatList)) {
                List<PmSteelCastHeat> sortOtherLotHeatList = otherLotHeatList.stream().sorted(Comparator.comparing(PmSteelCastHeat::getCcSeq)).collect(Collectors.toList());
                for (PmSteelCastHeat pmSteelCastHeat : sortOtherLotHeatList) {
                    pmSteelCastHeat.setCcSeq(seq++);
                    updateList.add(pmSteelCastHeat);
                }  
            }

        } else if ("1".equals(dto.getBasicLot())) {
            // 计划接收状态的最大连铸计划顺序号（CC_SEQ），
            long planRceiveSeqMax = 0L;
            List<PmSteelCastHeat> castHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PLAN_DATE, dto.getPlanDate()))
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_MAIN_BACKLOG_CODE, dto.getMainBacklogCode()))
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PONO_STATUS, Constants.PonoStatus.STATUS_13))
                    .build());
            if (CollectionUtils.isNotEmpty(castHeatList)) {
                Optional<Long> ccSeqOptional = castHeatList.stream().map(PmSteelCastHeat::getCcSeq).max(Comparator.comparing(Long::longValue));
                if (ccSeqOptional.isPresent()) {
                    planRceiveSeqMax = ccSeqOptional.get();
                }
                // 同时非操作lot的都要挪动
                // 将大于操作LOT的最大顺序号，小于计划接收状态的最大连铸计划顺序号（CC_SEQ），在此区间的都往前移动
                List<PmSteelCastHeat> otherLotHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                        .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                        .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_MAIN_BACKLOG_CODE, dto.getMainBacklogCode()))
                        .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PLAN_DATE, dto.getPlanDate()))
                        .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PONO_STATUS, Constants.PonoStatus.STATUS_13))
                        .andWhere(Sqls.custom().andGreaterThan(PmSteelCastHeat.FIELD_CC_SEQ, maxOperationSeq))
                        .andWhere(Sqls.custom().andLessThanOrEqualTo(PmSteelCastHeat.FIELD_CC_SEQ, planRceiveSeqMax))
                        .build());
                long seq = minOperationSeq;
                if (CollectionUtils.isNotEmpty(otherLotHeatList)) {
                    List<PmSteelCastHeat> sortOtherLotHeatList = otherLotHeatList.stream().sorted(Comparator.comparing(PmSteelCastHeat::getCcSeq)).collect(Collectors.toList());
                    for (PmSteelCastHeat pmSteelCastHeat : sortOtherLotHeatList) {
                        pmSteelCastHeat.setCcSeq(seq++);
                        updateList.add(pmSteelCastHeat);
                    }
                }
                // 操作Lot往后移
                List<PmSteelCastHeat> sortOperationCastHeatList = operationCastHeatList.stream().sorted(Comparator.comparing(PmSteelCastHeat::getCcSeq)).collect(Collectors.toList());
                for (PmSteelCastHeat pmSteelCastHeat : sortOperationCastHeatList) {
                    pmSteelCastHeat.setCcSeq(seq++);
                    updateList.add(pmSteelCastHeat);
                }
            }
        } else {
            // iii.	否则根据基准LOT号、主工序代码（MAIN_BACKLOG_CODE）、计划日期（PLAN_DATE）查询【炼钢连铸制造命令炉次表（PM_STEEL_CAST_HEAT）】信息，
            // 其中基准LOT号关联浇次号（CAST_LOT_NO），若获取的记录数为0，则报错（右下角）：PM.CASTING.MACHINE.PRE.PLAN.011，程序结束；
            List<PmSteelCastHeat> castHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_CAST_LOT_NO, dto.getBasicLot()))
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_MAIN_BACKLOG_CODE, dto.getMainBacklogCode()))
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PLAN_DATE, dto.getPlanDate()))
                    .build());
            if (CollectionUtils.isEmpty(castHeatList)) {
                throw new CommonException("pm.casting_machine_pre_plan_011",dto.getBasicLot());
            }

            // vi.	基准LOT的最大顺序号（SEQ_MOVE_TO）
            long basicSexMoveTo = 0L;
            List<PmSteelCastHeat> basicLotHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_CAST_LOT_NO, dto.getBasicLot()))
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_MAIN_BACKLOG_CODE, dto.getMainBacklogCode()))
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PLAN_DATE, dto.getPlanDate()))
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PONO_STATUS, Constants.PonoStatus.STATUS_13))
                    .build());
            if (CollectionUtils.isEmpty(basicLotHeatList)) {
                throw new CommonException("pm_steel_cast_heat_001", dto.getBasicLot());
            }
            Optional<PmSteelCastHeat> maxCcSeqHeat = basicLotHeatList.stream().max(Comparator.comparing(PmSteelCastHeat::getCcSeq));
            String pono = "";
            if (maxCcSeqHeat.isPresent()) {
                basicSexMoveTo = maxCcSeqHeat.get().getCcSeq();
                pono = maxCcSeqHeat.get().getPono();
            }

            // iv.	验证基准LOT内是否有已经计划确定或下达的炉次， 说明基准lot不在计划确定里
            // 即当日最大顺序号（SEQ_MOVE_MAX）大于基准LOT的最大顺序号（说明基准LOT排前面）,说名基准LOT内是否有已经计划确定或下达的炉次，则报错
            if (sexMoveMax > basicSexMoveTo) {
                throw new CommonException("pm.casting_machine_pre_plan_012", pono);
            }

            // 3.	若上述校验通过，则将操作LOT号内的炉次移动到基准LOT之后，
            // 3.1 炉次的连铸计划顺序号（CC_SEQ）的值等于基准LOT的最大顺序号（SEQ_MOVE_TO）加1
            if (minOperationSeq == (basicSexMoveTo + 1)) {
                throw new CommonException("pm.casting_machine_pre_plan_013", dto.getOperationLot(), dto.getBasicLot());
            } else if (minOperationSeq > (basicSexMoveTo + 1)) {
                // 操作lot在基准lot的后面后面 操作lot往前移动
                long seq = basicSexMoveTo + 1;
                List<PmSteelCastHeat> sortOperationCastHeatList = operationCastHeatList.stream().sorted(Comparator.comparing(PmSteelCastHeat::getCcSeq)).collect(Collectors.toList());
                for (PmSteelCastHeat pmSteelCastHeat : sortOperationCastHeatList) {
                    pmSteelCastHeat.setCcSeq(seq++);
                    updateList.add(pmSteelCastHeat);
                }
                // 在此区间的都往后移动
                List<PmSteelCastHeat> otherLotHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                        .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                        .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_MAIN_BACKLOG_CODE, dto.getMainBacklogCode()))
                        .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PLAN_DATE, dto.getPlanDate()))
                        .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PONO_STATUS, Constants.PonoStatus.STATUS_13))
                        .andWhere(Sqls.custom().andGreaterThan(PmSteelCastHeat.FIELD_CC_SEQ, basicSexMoveTo))
                        .andWhere(Sqls.custom().andLessThan(PmSteelCastHeat.FIELD_CC_SEQ, minOperationSeq))
                        .build());
                if (CollectionUtils.isNotEmpty(otherLotHeatList)) {
                    List<PmSteelCastHeat> sortOtherLotHeatList = otherLotHeatList.stream().sorted(Comparator.comparing(PmSteelCastHeat::getCcSeq)).collect(Collectors.toList());
                    for (PmSteelCastHeat pmSteelCastHeat : sortOtherLotHeatList) {
                        pmSteelCastHeat.setCcSeq(seq++);
                        updateList.add(pmSteelCastHeat);
                    }
                }
            } else {
                // 操作lot在基准lot的前面 操作lot往后移动
                // 在此区间的都往前移动
                List<PmSteelCastHeat> otherLotHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                        .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                        .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_MAIN_BACKLOG_CODE, dto.getMainBacklogCode()))
                        .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PLAN_DATE, dto.getPlanDate()))
                        .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PONO_STATUS, Constants.PonoStatus.STATUS_13))
                        .andWhere(Sqls.custom().andGreaterThan(PmSteelCastHeat.FIELD_CC_SEQ, maxOperationSeq))
                        .andWhere(Sqls.custom().andLessThanOrEqualTo(PmSteelCastHeat.FIELD_CC_SEQ, basicSexMoveTo))
                        .build());
                long seq = minOperationSeq;
                if (CollectionUtils.isNotEmpty(otherLotHeatList)) {
                    List<PmSteelCastHeat> sortOtherLotHeatList = otherLotHeatList.stream().sorted(Comparator.comparing(PmSteelCastHeat::getCcSeq)).collect(Collectors.toList());
                    for (PmSteelCastHeat pmSteelCastHeat : sortOtherLotHeatList) {
                        pmSteelCastHeat.setCcSeq(seq++);
                        updateList.add(pmSteelCastHeat);
                    }
                }

                // 然后是操作Lot
                List<PmSteelCastHeat> sortOperationCastHeatList = operationCastHeatList.stream().sorted(Comparator.comparing(PmSteelCastHeat::getCcSeq)).collect(Collectors.toList());
                for (PmSteelCastHeat pmSteelCastHeat : sortOperationCastHeatList) {
                    pmSteelCastHeat.setCcSeq(seq++);
                    updateList.add(pmSteelCastHeat);
                }
            }
        }
        pmSteelCastHeatRepository.batchUpdateByPrimaryKey(updateList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void reIntroduce(Long tenantId, List<PmSteelCastHeat> pmSteelCastHeatList) {
        // 2.	若当前炉在浇次中的位置不为头炉，则令计划浇次头/尾炉标记(RESTRAND_FLG)等于T
        List<PmSteelCastHeat> filterList = pmSteelCastHeatList.stream().filter(item -> !item.getCastLotDivNo().equals(1L)).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(filterList)) {
            throw new CommonException("pm.steel_cast_heat", filterList.get(0).getPono(), filterList.get(0).getCastLotNo());
        }
        pmSteelCastHeatList.forEach(item->item.setRestrandFlg( Constants.RestrandFlg.FLAG_T));
        // 值更新【炼钢连铸制造命令炉次表（PM_STEEL_CAST_HEAT）】
        pmSteelCastHeatRepository.batchUpdateByPrimaryKey(pmSteelCastHeatList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void heatTreatmentMatch(Long tenantId, List<PmSteelCastHeat> pmSteelCastHeatList) {
        // 校验是否有热处理匹配要求
        for (PmSteelCastHeat steelCastHeat : pmSteelCastHeatList) {
            if (!BaseConstants.FlagChar.YES.equals(steelCastHeat.getIsHavingHreat())) {
                throw new CommonException("pm.casting_machine_pre_plan_020", steelCastHeat.getPono());
            }
        }

        // 校验是否已经命令接收
        List<PmSteelCastHeat> isNotAcceptList = pmSteelCastHeatList.stream().filter(item ->
                !Constants.PonoStatus.STATUS_13.equals(item.getPonoStatus())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(isNotAcceptList)) {
            throw new CommonException("pm.steel_cast_heat_008",isNotAcceptList.get(0).getPono());
        }
        
        // 校验是否是外卖坯或者备坯
        List<PmSteelCastHeat> isStandbyList = pmSteelCastHeatList.stream().filter(item ->
                Constants.CcType.TYPE_2.equals(item.getCcType())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(isStandbyList)) {
            throw new CommonException("pm.steel_cast_heat_011");
        }
        List<PmSteelCastHeat> isDeliveryList = pmSteelCastHeatList.stream().filter(item ->
                Constants.CcType.TYPE_4.equals(item.getCcType())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(isDeliveryList)) {
            throw new CommonException("pm.steel_cast_heat_013");
        }

        List<String> ponoList = pmSteelCastHeatList.stream().map(PmSteelCastHeat::getPono).distinct().collect(Collectors.toList());
        List<PmHotDest> pmHotDestList = pmHotDestRepository.selectByPonoList(tenantId, ponoList);

        // 校验是否做过热处理匹配
        if (CollectionUtils.isNotEmpty(pmHotDestList)) {
            throw new CommonException("pm.hot_dest_004", ponoList);
        }

        // 1.	根据制造命令号更新【炼钢连铸制造命令炉次表（PM_STEEL_CAST_HEAT）】中板坯要求（SLAB_REQ）的值，令其等于1
        pmSteelCastHeatList.forEach(pmSteelCastHeat -> pmSteelCastHeat.setSlabReq("1"));
        // 值更新【炼钢连铸制造命令炉次表（PM_STEEL_CAST_HEAT）】
        pmSteelCastHeatRepository.batchUpdateByPrimaryKey(pmSteelCastHeatList);


        // 利用制造命令号右匹配匹配查询【命令参数表（PM_CMD_CONT）】中的信息
        Condition.Builder builder = Condition.builder(PmCmdCont.class)
                .andWhere(Sqls.custom().andEqualTo(PmCmdCont.FIELD_TENANT_ID, tenantId));
        Sqls sqls = Sqls.custom();
        ponoList.forEach(pono -> sqls.orLikeRight(PmCmdCont.FIELD_PONO_SLAB_NO, pono));
        List<PmCmdCont> pmCmdContList = pmCmdContRepository.selectByCondition(builder.andWhere(sqls).build());
        if (CollectionUtils.isEmpty(pmCmdContList)) {
            throw new CommonException("pm.steel_cast_heat_007", ponoList, "命令参数表");
        }

        List<String> orderNoList = pmCmdContList.stream().map(PmCmdCont::getOrderNo).distinct().collect(Collectors.toList());
        List<String> mscLineList = pmCmdContList.stream().map(PmCmdCont::getMscLineNo).distinct().collect(Collectors.toList());

        // 3.	根据产线号以及合同号到【合同产线工艺参数表(PM_CONT_MSC_TECH)】中查询热处理模式（HEAT_TREAT_MODE）
        List<PmContMscTech> pmContMscTecheList =  pmContMscTechRepository.selectByOrderNoAndMscLineNo(orderNoList, mscLineList, tenantId);
        if (CollectionUtils.isEmpty(pmContMscTecheList)) {
            throw new CommonException("pm.steel_cast_heat_006", mscLineList, orderNoList);
        }
        Map<String, PmContMscTech> contMscTecheMap = pmContMscTecheList.stream()
                .collect(Collectors.toMap(item -> Strings.concat(item.getOrderNo(), item.getMscLineNo()), Function.identity()));

        List<PmHotDest> insertTpssmHotList = new ArrayList<>();
        List<PmHotDest> deleteHotList = new ArrayList<>();
        for (PmSteelCastHeat pmSteelCastHeat : pmSteelCastHeatList) {
            // 制造命令号对应的命令参数表数据
            List<PmCmdCont> contList = pmCmdContList.stream()
                    .filter(cont -> cont.getPonoSlabNo().startsWith(pmSteelCastHeat.getPono())).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(contList)) {
                throw new CommonException("pm.steel_cast_heat_007", pmSteelCastHeat.getPono(), "命令参数表");
            }

            Condition.Builder build = Condition.builder(PmHotConfig.class);
            boolean isFirst = true;
            boolean isExistHeatMode = false;
            Map<String, PmHotConfigVO> heatLineMap = new HashMap<>(contList.size());
            for (PmCmdCont pmCmdCont : contList) {
                // 根据合同+产线->热处理模式
                PmContMscTech orDefault = contMscTecheMap.getOrDefault(Strings.concat(pmCmdCont.getOrderNo(), pmCmdCont.getMscLineNo()), new PmContMscTech());
                if (StringUtils.isEmpty(orDefault.getWholeHeatTreatmentType())) {
                    continue;
                }
                for (int i = 0; i < orDefault.getWholeHeatTreatmentType().length(); i++) {
                    if (isFirst) {
                        // 4.	接着根据产线号、热处理模式、订货厚度、订货宽度、订货长度到【组炉默认热处理去向配置表（PM_HOT_CONFIG）】中查询默认热处理炉号（DEFAULT_DEST）
                        build.where(Sqls.custom().andEqualTo(PmHotConfig.FIELD_TENANT_ID, tenantId)
                                .andEqualTo(PmHotConfig.FIELD_MSC_LINE_NO, pmCmdCont.getMscLineNo())
                                .andEqualTo(PmHotConfig.FIELD_HEAT_TREAT_MODE, String.valueOf(orDefault.getWholeHeatTreatmentType().charAt(i)))
                                .andLessThanOrEqualTo(PmHotConfig.FIELD_PLATE_THICK_FROM, pmCmdCont.getOrderThick())
                                .andGreaterThanOrEqualTo(PmHotConfig.FIELD_PLATE_THICK_TO, pmCmdCont.getOrderThick())
                                .andLessThanOrEqualTo(PmHotConfig.FIELD_PLATE_WID_FROM, pmCmdCont.getOrderWidth())
                                .andGreaterThanOrEqualTo(PmHotConfig.FIELD_PLATE_WID_TO, pmCmdCont.getOrderWidth())
                                .andLessThanOrEqualTo(PmHotConfig.FIELD_PLATE_LEN_FROM, pmCmdCont.getOrderLen())
                                .andGreaterThanOrEqualTo(PmHotConfig.FIELD_PLATE_LEN_TO, pmCmdCont.getOrderLen()));
                        isFirst = false;
                    } else {
                        build.orWhere(Sqls.custom().andEqualTo(PmHotConfig.FIELD_TENANT_ID, tenantId)
                                .andEqualTo(PmHotConfig.FIELD_MSC_LINE_NO, pmCmdCont.getMscLineNo())
                                .andEqualTo(PmHotConfig.FIELD_HEAT_TREAT_MODE, String.valueOf(orDefault.getWholeHeatTreatmentType().charAt(i)))
                                .andLessThanOrEqualTo(PmHotConfig.FIELD_PLATE_THICK_FROM, pmCmdCont.getOrderThick())
                                .andGreaterThanOrEqualTo(PmHotConfig.FIELD_PLATE_THICK_TO, pmCmdCont.getOrderThick())
                                .andLessThanOrEqualTo(PmHotConfig.FIELD_PLATE_WID_FROM, pmCmdCont.getOrderWidth())
                                .andGreaterThanOrEqualTo(PmHotConfig.FIELD_PLATE_WID_TO, pmCmdCont.getOrderWidth())
                                .andLessThanOrEqualTo(PmHotConfig.FIELD_PLATE_LEN_FROM, pmCmdCont.getOrderLen())
                                .andGreaterThanOrEqualTo(PmHotConfig.FIELD_PLATE_LEN_TO, pmCmdCont.getOrderLen()));
                    }

                    // 暂存每一个热处理模式对应的信息，便于抛错
                    isExistHeatMode = true;
                    if (!heatLineMap.containsKey(String.valueOf(orDefault.getWholeHeatTreatmentType().charAt(i)))) {
                        PmHotConfigVO pmHotConfigVO = new PmHotConfigVO();
                        pmHotConfigVO.setPonoSlabNo(pmCmdCont.getPonoSlabNo());
                        pmHotConfigVO.setOrderNo(pmCmdCont.getOrderNo());
                        pmHotConfigVO.setMscLineNo(pmCmdCont.getMscLineNo());
                        pmHotConfigVO.setHeatTreatMode(String.valueOf(orDefault.getWholeHeatTreatmentType().charAt(i)));
                        heatLineMap.put(String.valueOf(orDefault.getWholeHeatTreatmentType().charAt(i)), pmHotConfigVO);
                    }
                }
            }
            List<PmHotConfig> pmHotConfigList = pmHotConfigRepository.selectByCondition(build.build());

           // 没有热处理要求，提示错误
            if (!isExistHeatMode) {
                throw new CommonException("pm.casting_machine_pre_plan_020", pmSteelCastHeat.getPono());
            }
            // a)	如果默认热处理去向为“ ”，表示该合同、产线有热处理要求，但配置表中没有配置，前台提示（右下角）：PM.CASTING.MACHINE.PRE.PLAN.004，程序结束
            if (CollectionUtils.isEmpty(pmHotConfigList) && isExistHeatMode) {
                heatLineMap.forEach((key, value)->{
                    throw new CommonException("pm.casting_machine_pre_plan_004", pmSteelCastHeat.getPono(),
                            value.getPonoSlabNo(),   value.getOrderNo(),key);
                });
            }

            // 热处理模式和配置表条数不一致
            if (pmHotConfigList.size() < heatLineMap.size()) {
                heatLineMap.forEach((key, value)->{
                    Optional<PmHotConfig> first = pmHotConfigList.stream().filter(item -> key.equals(item.getHeatTreatMode()) && value.getMscLineNo().equals(item.getMscLineNo())).findFirst();
                    if (!first.isPresent()) {
                        throw new CommonException("pm.casting_machine_pre_plan_004", pmSteelCastHeat.getPono(),
                                value.getPonoSlabNo(), value.getOrderNo(), key);
                    }
                });
            }

            // b)	否则根据制造命令号（PONO）查询【炼钢炉次计划热处理去向表（TPSSM_HOT）】
            if (CollectionUtils.isNotEmpty(pmHotConfigList)) {
                for (PmHotConfig pmHotConfig : pmHotConfigList) {
                    // 插入炼钢炉次计划热处理去向表（TPSSM_HOT）
                    PmHotDest pmHotDest = new PmHotDest();
                    pmHotDest.setPono(pmSteelCastHeat.getPono());
                    pmHotDest.setHotMode(pmHotConfig.getHeatTreatMode());
                    pmHotDest.setDefaultDest(pmHotConfig.getDefaultDest());
                    pmHotDest.setStatus("W");
                    pmHotDest.setTenantId(tenantId);
                    insertTpssmHotList.add(pmHotDest);
                }
            }
        }

        if (CollectionUtils.isNotEmpty(insertTpssmHotList)) {
            // 根据唯一性如果表里已经存在，则删除，再插入
            List<String> hotPonoList = insertTpssmHotList.stream().map(PmHotDest::getPono).distinct().collect(Collectors.toList());
            List<String> hotModeList = insertTpssmHotList.stream().map(PmHotDest::getHotMode).distinct().collect(Collectors.toList());
            List<String> defaultDestList = insertTpssmHotList.stream().map(PmHotDest::getDefaultDest).distinct().collect(Collectors.toList());
            List<PmHotDest> pmTpssmHotList = pmHotDestRepository.selectByCondition(Condition.builder(PmHotDest.class)
                    .andWhere(Sqls.custom().andEqualTo(PmHotDest.FIELD_TENANT_ID, tenantId))
                    .andWhere(Sqls.custom().andIn(PmHotDest.FIELD_PONO, hotPonoList))
                    .andWhere(Sqls.custom().andIn(PmHotDest.FIELD_HOT_MODE, hotModeList))
                    .andWhere(Sqls.custom().andIn(PmHotDest.FIELD_DEFAULT_DEST, defaultDestList))
                    .build());
            if (CollectionUtils.isNotEmpty(pmTpssmHotList)) {
                // 校验是否已存在
                Map<String, PmHotDest> pmTpssHotMap = pmTpssmHotList.stream()
                        .collect(Collectors.toMap(item -> item.getPono() + item.getHotMode() + item.getDefaultDest(), Function.identity()));
                for (PmHotDest pmTpssmHot : insertTpssmHotList) {
                    if (pmTpssHotMap.containsKey(pmTpssmHot.getPono()+pmTpssmHot.getHotMode()+pmTpssmHot.getDefaultDest())) {
                        deleteHotList.add(pmTpssHotMap.get(pmTpssmHot.getPono()+pmTpssmHot.getHotMode()+pmTpssmHot.getDefaultDest()));
                    }
                }
            }
        }
        // 先删除已存在的
        pmHotDestRepository.batchDeleteByPrimaryKey(deleteHotList);
        // 批量插入【炼钢炉次计划热处理去向表（TPSSM_HOT）】
        pmHotDestRepository.batchInsertSelective(insertTpssmHotList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void heatTreatmentRelease(Long tenantId, List<PmSteelCastHeat> pmSteelCastHeatList) {
        // 校验是否有热处理匹配要求
        for (PmSteelCastHeat steelCastHeat : pmSteelCastHeatList) {
            if (!BaseConstants.FlagChar.YES.equals(steelCastHeat.getIsHavingHreat())) {
                throw new CommonException("pm.casting_machine_pre_plan_020", steelCastHeat.getPono());
            }
        }

        // 1.	根据前端所选炉次的制造命令号（PONO）查询【炼钢炉次计划热处理去向表（PM_HOT_DEST）】信息，获
        List<String> ponoList = pmSteelCastHeatList.stream().map(PmSteelCastHeat::getPono).collect(Collectors.toList());
        List<PmHotDest> tpssmHotList = pmHotDestRepository.selectByCondition(Condition.builder(PmHotDest.class)
                .andWhere(Sqls.custom().andEqualTo(PmHotDest.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andIn(PmHotDest.FIELD_PONO, ponoList))
                .build());
        if (CollectionUtils.isEmpty(tpssmHotList)) {
            throw new CommonException("pm.hot_dest_001", ponoList);
        }
        List<PmHotDestTra> pmTpssmHotLogList = new ArrayList<>();
        List<PmHotDest> updateList = new ArrayList<>();
        Map<String, List<PmHotDest>> tpssmHotMap = tpssmHotList.stream().collect(Collectors.groupingBy(PmHotDest::getPono));
        for (String pono : ponoList) {
            if (!tpssmHotMap.containsKey(pono)) {
                throw new CommonException("pm.hot_dest_001", pono);
            }
            tpssmHotMap.get(pono).forEach(item->{
                if ("N".equals(item.getStatus())) {
                    throw new CommonException("pm.hot_dest_002",pono);
                }
            });

            // 2.将制造命令号依次插入到【修改炼钢炉次计划热处理去向履历表（TPSSM_HOT_LOG）】中；
            PmHotDestTra pmTpssmHotLog = new PmHotDestTra();
            pmTpssmHotLog.setPono(pono);
            pmTpssmHotLogList.add(pmTpssmHotLog);

            // 3.根据热处理去向状态将【炼钢炉次计划热处理去向表（TPSSM_HOT）】中的热处理去向状态由“W”修改为“N”
            tpssmHotMap.get(pono).forEach(item->{
                item.setStatus("N");
                updateList.add(item);
            });
        }
        // 批量插入
        pmHotDestTraRepository.batchInsertSelective(pmTpssmHotLogList);
        // 批量更新
        pmHotDestRepository.batchUpdateByPrimaryKey(updateList);
    }

    @Override
    public List<PmHotDest> getHotDestList(Long tenantId, List<PmSteelCastHeat> pmSteelCastHeatList) {
        List<String> ponoList = new ArrayList<>();
        // 校验是否有热处理匹配要求
        for (PmSteelCastHeat steelCastHeat : pmSteelCastHeatList) {
            if (!BaseConstants.FlagChar.YES.equals(steelCastHeat.getIsHavingHreat())) {
                throw new CommonException("pm.casting_machine_pre_plan_020", steelCastHeat.getPono());
            }
            ponoList.add(steelCastHeat.getPono());
        }
        List<PmHotDest> pmHotDestList = pmHotDestRepository.selectByPonoList(tenantId, ponoList);

        // 校验是否做过热处理匹配
        if (CollectionUtils.isEmpty(pmHotDestList)) {
            throw new CommonException("pm.hot_dest_001", ponoList);
        }
        Map<String, List<PmHotDest>> pmHotDestMap = pmHotDestList.stream().collect(Collectors.groupingBy(PmHotDest::getPono));
        for (String pono : ponoList) {
            if (!pmHotDestMap.containsKey(pono)) {
                throw new CommonException("pm.hot_dest_001", pono);
            }
        }
        return pmHotDestList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void heatTreatmentModify(Long tenantId, List<PmHotDest> pmHotDestList) {
        for (PmHotDest pmHotDest : pmHotDestList) {
            pmHotDest.setStatus("W");
        }
        pmHotDestRepository.batchUpdateByPrimaryKey(pmHotDestList);
        // 校验是否有热处理匹配要求
//        for (PmSteelCastHeat steelCastHeat : pmSteelCastHeatList) {
//            if (!BaseConstants.FlagChar.YES.equals(steelCastHeat.getIsHavingHreat())) {
//                throw new CommonException("pm.casting_machine_pre_plan_020", steelCastHeat.getPono());
//            }
//        }

        // 1.	根据前端所选炉次的制造命令号（PONO）更新【炼钢炉次计划热处理去向表（TPSSM_HOT）】中热处理去向状态（STATUS）的值为未下达状态，
        // 即令热处理去向状态（STATUS）等于“W”；
//        List<String> ponoList = pmSteelCastHeatList.stream().map(PmSteelCastHeat::getPono).collect(Collectors.toList());
//        List<PmHotDest> hotDestList =  pmHotDestRepository.selectByPonoList(tenantId, ponoList);
//        if (CollectionUtils.isEmpty(hotDestList)) {
//            throw new CommonException("pm.hot_dest_001", ponoList);
//        }
//        List<PmHotDest> updateList = new ArrayList<>();
//        Map<String, List<PmHotDest>> tpssmHotMap = hotDestList.stream().collect(Collectors.groupingBy(PmHotDest::getPono));
//        for (String pono : ponoList) {
//            if (!tpssmHotMap.containsKey(pono)) {
//                throw new CommonException("pm.hot_dest_001", pono);
//            }
//            List<PmHotDest> pmHotDestList = tpssmHotMap.get(pono);
//            // 根据制造命令号将【炼钢炉次计划热处理去向表（PM_HOT_DEST）】中的热处理去向状态由“N”修改为“W
//            for (PmHotDest pmHotDest : pmHotDestList) {
//                if ("W".equals(pmHotDest.getStatus())) {
//                    throw new CommonException("pm.hot_dest_003",pono);
//                }
//                pmHotDest.setStatus("W");
//                updateList.add(pmHotDest);
//            }
//        }
//        pmHotDestRepository.batchUpdateByPrimaryKey(updateList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public void dissolution(Long tenantId, PmSteelCastHeatReqParamDTO dto) {
        // 3.	如果制造命令状态（PONO_STATUS）的值大于等于13，说明当前炉次已被计划接收
        dto.getPmSteelCastHeatList().forEach(item -> {
            if (item.getPonoStatus().compareTo(Constants.PonoStatus.STATUS_13) >= 0) {
                throw new CommonException("pm.casting_machine_pre_plan_017", item.getPono());
            }
        });

        // 4.	否则根据主工序代码（MAIN_BACKLOG_CODE）以及制造命令号（PONO）删除【炼钢连铸制造命令炉次表（PM_STEEL_CAST_HEAT）】、
        List<String> castLotNoList = dto.getPmSteelCastHeatList().stream().map(PmSteelCastHeat::getCastLotNo).collect(Collectors.toList());
        List<String> ponoList = dto.getPmSteelCastHeatList().stream().map(PmSteelCastHeat::getPono).collect(Collectors.toList());
        List<String> mainBacklogCodeList = dto.getPmSteelCastHeatList().stream().map(PmSteelCastHeat::getMainBacklogCode).distinct()
                .collect(Collectors.toList());
        pmSteelCastHeatRepository.batchDeleteByPrimaryKey(dto.getPmSteelCastHeatList());

        // 删除【炼钢连铸制造命令板坯表（PM_STEEL_CAST_SLAB）】
        List<PmSteelCastSlab> pmSteelCastSlabList = pmSteelCastSlabRepository.selectByCondition(Condition.builder(PmSteelCastSlab.class)
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastSlab.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andIn(PmSteelCastSlab.FIELD_PONO, ponoList))
                .andWhere(Sqls.custom().andIn(PmSteelCastSlab.FIELD_MAIN_BACKLOG_CODE, mainBacklogCodeList))
                .build());
        pmSteelCastSlabRepository.batchDeleteByPrimaryKey(pmSteelCastSlabList);

        // 删除【炼钢连铸制造命令铸机流表（PM_STEEL_CAST_FLOW）】
        List<PmSteelCastFlow> pmSteelCastFlowList = pmSteelCastFlowRepository.selectByCondition(Condition.builder(PmSteelCastFlow.class)
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastFlow.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andIn(PmSteelCastFlow.FIELD_PONO, ponoList))
                .andWhere(Sqls.custom().andIn(PmSteelCastFlow.FIELD_MAIN_BACKLOG_CODE, mainBacklogCodeList))
                .build());
        pmSteelCastFlowRepository.batchDeleteByPrimaryKey(pmSteelCastFlowList);

        // 根据浇次号（CAST_LOT_NO）、主工序代码（MAIN_BACKLOG_CODE）查询【炼钢连铸制造命令炉次表（PM_STEEL_CAST_HEAT）】
        List<PmSteelCastHeat> steelCastHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andIn(PmSteelCastHeat.FIELD_CAST_LOT_NO, castLotNoList))
                .andWhere(Sqls.custom().andIn(PmSteelCastHeat.FIELD_MAIN_BACKLOG_CODE, mainBacklogCodeList))
                .build());
        Map<String, List<PmSteelCastHeat>> castLotNoMap = new HashMap<>(steelCastHeatList.size());
        if (CollectionUtils.isNotEmpty(steelCastHeatList)) {
            castLotNoMap = steelCastHeatList.stream().collect(Collectors.groupingBy(PmSteelCastHeat::getCastLotNo));
        }
        // 炼钢连铸制造命令LOT表待删除的浇次号
        List<String> deleteCastLotNoList = new ArrayList<>();
        List<PmSteelCastHeat> updateSteelCastHeatList = new ArrayList<>();
        for (String castLotNo : castLotNoList) {
            // a)	若获取到的记录数为0
            if (!castLotNoMap.containsKey(castLotNo)) {
                // 删除【炼钢连铸制造命令LOT表（PM_STEEL_CAST_LOT）】对应记录的信息；
                deleteCastLotNoList.add(castLotNo);
            } else {
                // 更新【炼钢连铸制造命令炉次表（PM_STEEL_CAST_HEAT）】的浇次分割号（CAST_LOT_DIV_NO），使浇次分割号（CAST_LOT_DIV_NO）保持连续
                List<PmSteelCastHeat> castHeatList = castLotNoMap.get(castLotNo).stream()
                        .sorted(Comparator.comparing(PmSteelCastHeat::getCastLotDivNo)).collect(Collectors.toList());
                long divNo = 1L;
                for (PmSteelCastHeat item : castHeatList) {
                    item.setCastLotDivNo(divNo++);
                    item.setCastLotSum((long)castHeatList.size());
                    updateSteelCastHeatList.add(item);
                }
            }
        }
        // 删除【炼钢连铸制造命令LOT表（PM_STEEL_CAST_LOT）】对应记录的信息；
        if (CollectionUtils.isNotEmpty(deleteCastLotNoList)) {
            List<PmSteelCastLot> pmSteelCastLotList = pmSteelCastLotRepository.selectByCondition(Condition.builder(PmSteelCastLot.class)
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastLot.FIELD_TENANT_ID, tenantId))
                    .andWhere(Sqls.custom().andIn(PmSteelCastLot.FIELD_CAST_LOT_NO, deleteCastLotNoList))
                    .build());
            pmSteelCastLotRepository.batchDeleteByPrimaryKey(pmSteelCastLotList);
        }

        // 更新【炼钢连铸制造命令炉次表（PM_STEEL_CAST_HEAT）】的浇次分割号,浇次炉数
        if (CollectionUtils.isNotEmpty(updateSteelCastHeatList)) {
            pmSteelCastHeatRepository.batchUpdateByPrimaryKey(updateSteelCastHeatList);

            // 更新【炼钢连铸制造命令LOT表(PM STEEL_CAST LOT)】表中板坯块数(SLAB NUM)的值为浇次内实际板坏块数的值:
            List<String> updateCastLotNoList = updateSteelCastHeatList.stream().map(PmSteelCastHeat::getCastLotNo).distinct().collect(Collectors.toList());
            List<PmSteelCastLot> steelCastLotList = pmSteelCastLotRepository.selectByCondition(Condition.builder(PmSteelCastLot.class)
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastLot.FIELD_TENANT_ID, tenantId))
                    .andWhere(Sqls.custom().andIn(PmSteelCastLot.FIELD_CAST_LOT_NO, updateCastLotNoList))
                    .build());
            // 查询浇次号的板坯数
            List<PmSteelCastSlab> steelCastSlabList = pmSteelCastSlabRepository.selectByCondition(Condition.builder(PmSteelCastSlab.class)
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastSlab.FIELD_TENANT_ID, tenantId))
                    .andWhere(Sqls.custom().andIn(PmSteelCastSlab.FIELD_CAST_LOT_NO, updateCastLotNoList))
                    .andWhere(Sqls.custom().andIn(PmSteelCastSlab.FIELD_MAIN_BACKLOG_CODE, mainBacklogCodeList))
                    .build());
            if (CollectionUtils.isEmpty(steelCastSlabList)) {
                throw new CommonException("pm.steel_cast_heat_012", Strings.join(updateCastLotNoList,','));
            }
            Map<String, Long> slabNumMap = steelCastSlabList.stream().collect(Collectors.groupingBy(PmSteelCastSlab::getCastLotNo, Collectors.counting()));
            steelCastLotList.forEach(item -> item.setSlabNum(slabNumMap.get(item.getCastLotNo())));
            pmSteelCastLotRepository.batchUpdateByPrimaryKey(steelCastLotList);
        }

        // 解散到组板、解散到组矩
        // 6.	根据浇次号（CAST_LOT_NO）以及制造命令号（PONO）查询【组炉编制表（PM_SLAB_ESTA_PLAN）】
        List<PmSlabEstaPlan> slabEstaPlanList = pmSlabEstaPlanRepository.selectByCondition(Condition.builder(PmSlabEstaPlan.class)
                .andWhere(Sqls.custom().andIn(PmSlabEstaPlan.FIELD_CAST_LOT_NO, castLotNoList))
                .andWhere(Sqls.custom().andIn(PmSlabEstaPlan.FIELD_PONO, ponoList))
                .andWhere(Sqls.custom().andEqualTo(PmSlabEstaPlan.FIELD_TENANT_ID, tenantId))
                .build());
        if (CollectionUtils.isEmpty(slabEstaPlanList)) {
            throw new CommonException("pm.steel_cast_heat_002", castLotNoList, ponoList);
        }
        // 调用解散到组板、解散到组矩方法
        List<String> preCastLotList = slabEstaPlanList.stream().map(PmSlabEstaPlan::getPrecCastLotNo).collect(Collectors.toList());
        List<String> precPonoList = slabEstaPlanList.stream().map(PmSlabEstaPlan::getPrecPono).collect(Collectors.toList());
        PmSlabEstaPlanDissoDTO param = new PmSlabEstaPlanDissoDTO();
        param.setPrecCastLotNoList(preCastLotList);
        param.setPrePonoList(precPonoList);
        param.setIsBoard(dto.getIsBoard());
        pmSlabEstaPlanService.dissolution(param, tenantId, false);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<PmSteelCastHeat> planAssignGetMark(Long tenantId, PmSteelCastHeatReqParamDTO dto) {
        List<PmSteelCastHeat> resultList = new ArrayList<>();
        List<PmSteelCastHeat> steelCastHeatList = dto.getPmSteelCastHeatList();
        if (CollectionUtils.isEmpty(steelCastHeatList)) {
            throw new CommonException("pm.steel_cast_heat_017");
        }

        List<String> matchPonoList = new ArrayList<>();
        List<String> releasePonoList = new ArrayList<>();
        List<PmSteelCastHeat> heatTreatList = steelCastHeatList.stream().filter(item ->
                BaseConstants.FlagChar.YES.equals(item.getIsHavingHreat())).collect(Collectors.toList());
        // 如果有需要做热处理匹配和热处理下达，先进行热处理匹配和下达
        if (CollectionUtils.isNotEmpty(heatTreatList)) {
            List<String> heatPonoList = heatTreatList.stream().map(PmSteelCastHeat::getPono).distinct().collect(Collectors.toList());
            List<PmHotDest> tpssmHotList = pmHotDestRepository.selectByPonoList(tenantId, heatPonoList);
            if (CollectionUtils.isEmpty(tpssmHotList)) {
                matchPonoList.addAll(heatPonoList);
            } else {
                // 未做过做过热处理匹配和下达
                List<String> tpssmHotPonoList =  tpssmHotList.stream().map(PmHotDest::getPono).distinct().collect(Collectors.toList());
                for (String pono : heatPonoList) {
                    if (!tpssmHotPonoList.contains(pono)) {
                        matchPonoList.add(pono);
                    }
                }
                // 状态为W,做过热处理匹配,需要做热处理下达
                releasePonoList.addAll(tpssmHotList.stream().filter(item -> heatPonoList.contains(item.getPono()) &&
                        "W".equals(item.getStatus())).map(PmHotDest::getPono).collect(Collectors.toList()));
            }
        }

        // 热处理匹配
        List<PmSteelCastHeat> matchCastHeatList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(matchPonoList)) {
            matchCastHeatList.addAll(steelCastHeatList.stream().filter(item -> matchPonoList.contains(item.getPono())).collect(Collectors.toList()));
            heatTreatmentMatch(tenantId, matchCastHeatList);
        }
        // 热处理下达
        if (CollectionUtils.isNotEmpty(releasePonoList) || CollectionUtils.isNotEmpty(matchPonoList)) {
            if (CollectionUtils.isNotEmpty(releasePonoList)) {
                matchCastHeatList.addAll(steelCastHeatList.stream().filter(item -> releasePonoList.contains(item.getPono())).collect(Collectors.toList()));
            }
            heatTreatmentRelease(tenantId, matchCastHeatList);
        }

        // 获取更新后的炉次数据
        List<String> steelPonoList = steelCastHeatList.stream().map(PmSteelCastHeat::getPono).collect(Collectors.toList());
        List<PmSteelCastHeat> pmSteelCastHeatList = pmSteelCastHeatRepository.selectByPonoList(steelPonoList, tenantId);

        pmSteelCastHeatList.forEach(item->{
            if (!Constants.PonoStatus.STATUS_13.equals(item.getPonoStatus())) {
                throw new CommonException("pm.steel_cast_heat_018", item.getPono());
            }
        });

        // 如果CC_TYPE等于1或者5（连铸板坯或钢锭） 查询是否有热处理匹配要求
        List<String> ponoList = pmSteelCastHeatList.stream().filter(item->Constants.CcType.TYPE_1.equals(item.getCcType()) ||
                        Constants.CcType.TYPE_5.equals(item.getCcType())).map(PmSteelCastHeat::getPono)
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(ponoList)) {
            resultList.addAll(pmSteelCastHeatList);
            return resultList;
        }
        Condition.Builder builder = Condition.builder(PmCmdCont.class)
                .andWhere(Sqls.custom().andEqualTo(PmCmdCont.FIELD_TENANT_ID, tenantId));
        Sqls sqls = Sqls.custom();
        ponoList.forEach(pono -> sqls.orLikeRight(PmCmdCont.FIELD_PONO_SLAB_NO, pono));
        List<PmCmdCont> pmCmdContList = pmCmdContRepository.selectByCondition(builder.andWhere(sqls).build());
        if (CollectionUtils.isEmpty(pmCmdContList)) {
            throw new CommonException("pm.steel_cast_heat_007", ponoList, "命令参数表");
        }

        List<String> orderNoList = pmCmdContList.stream().map(PmCmdCont::getOrderNo).distinct().collect(Collectors.toList());
        List<String> mscLineList = pmCmdContList.stream().map(PmCmdCont::getMscLineNo).distinct().collect(Collectors.toList());
        // 3.	根据产线号以及合同号到【合同产线工艺参数表(PM_CONT_MSC_TECH)】中查询热处理模式（HEAT_TREAT_MODE）
        List<PmContMscTech> pmContMscTecheList = pmContMscTechRepository.selectByOrderNoAndMscLineNo(orderNoList, mscLineList, tenantId);
        if (CollectionUtils.isEmpty(pmContMscTecheList)) {
            throw new CommonException("pm.steel_cast_heat_006", mscLineList, orderNoList);
        }
        Map<String, PmContMscTech> contMscTecheMap = pmContMscTecheList.stream()
                .collect(Collectors.toMap(item -> Strings.concat(item.getOrderNo(), item.getMscLineNo()), Function.identity()));

        for (PmSteelCastHeat steelCastHeat : pmSteelCastHeatList) {
            if (!Constants.CcType.TYPE_1.equals(steelCastHeat.getCcType()) && !Constants.CcType.TYPE_5.equals(steelCastHeat.getCcType())) {
                continue;
            }
            // 制造命令号对应的命令参数表数据
            List<PmCmdCont> contList = pmCmdContList.stream()
                    .filter(cont -> cont.getPonoSlabNo().startsWith(steelCastHeat.getPono())).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(contList)) {
                throw new CommonException("pm.steel_cast_heat_007", steelCastHeat.getPono(), "命令参数表");
            }
            for (PmCmdCont pmCmdCont : contList) {
                // 根据合同+产线->热处理模式
                PmContMscTech orDefault = contMscTecheMap.getOrDefault(Strings.concat(pmCmdCont.getOrderNo(), pmCmdCont.getMscLineNo()), new PmContMscTech());
                // 有热处理模式
                if (StringUtils.isNotEmpty(orDefault.getWholeHeatTreatmentType())) {
                    // 3.	过滤外卖坯和备坯，验证热处理去向是否匹配与下达，如果板坯要求（SLAB_REQ）的值不为1，则表示未匹配热处理去向，前台提示（右下角）
                    if (!"1".equals(steelCastHeat.getSlabReq())) {
                        throw new CommonException("pm.casting_machine_pre_plan_005", steelCastHeat.getPono());
                    }
                }
            }
        }


        // c)	根据制造命令号（PONO）以及处理去向状态STATUS=“W”查询【炼钢炉次计划热处理去向表（TPSSM_HOT）】信息，如果查询到的记录大于0，
        // 表示存在热处理去向未下达的记录，前台提示：PM.CASTING.MACHINE.PRE.PLAN.006，程序结束；
        List<PmHotDest> tpssmHotList = pmHotDestRepository.selectByCondition(Condition.builder(PmHotDest.class)
                .andWhere(Sqls.custom().andIn(PmHotDest.FIELD_PONO, ponoList))
                .andWhere(Sqls.custom().andEqualTo(PmHotDest.FIELD_STATUS, "W"))
                .andWhere(Sqls.custom().andEqualTo(PmHotDest.FIELD_TENANT_ID, tenantId))
                .build());
        if (CollectionUtils.isNotEmpty(tpssmHotList)) {
            throw new CommonException("pm.casting_machine_pre_plan_006", tpssmHotList.get(0).getPono());
        }

        // a)	根据制造命令号（PONO）、连铸预计划状态（CS_PREC_PLAN_STATUS）=“09”查询【组炉编制表（PM_SLAB_ESTA_PLAN）】
        List<PmSlabEstaPlan> slabEstaPlanList = pmSlabEstaPlanRepository.selectByCondition(Condition.builder(PmSlabEstaPlan.class)
                .andWhere(Sqls.custom().andIn(PmSlabEstaPlan.FIELD_PONO, ponoList))
                .andWhere(Sqls.custom().andEqualTo(PmSlabEstaPlan.FIELD_CS_PREC_PLAN_STATUS, "09"))
                .andWhere(Sqls.custom().andEqualTo(PmSlabEstaPlan.FIELD_TENANT_ID, tenantId))
                .build());
        if (CollectionUtils.isEmpty(slabEstaPlanList)) {
            throw new CommonException("pm.steel_cast_heat_004", ponoList);
        }
        // 制造命令号和对应虚拟板坯号关系
        Map<String, List<String>> slabEstaPlanMap = slabEstaPlanList.stream().collect(Collectors
                .groupingBy(PmSlabEstaPlan::getPono,  Collectors.mapping(PmSlabEstaPlan::getVirtualSlabNo, Collectors.toList())));

        List<String> virtualSlabNoList = slabEstaPlanList.stream().filter(item -> !Utils.isMergeSlab(item.getVirtualSlabNo()))
                .map(PmSlabEstaPlan::getVirtualSlabNo).collect(Collectors.toList());
        // 判断是否有合并板坯表
        List<String> mergeVirtualSlabNoList = slabEstaPlanList.stream().filter(item -> Utils.isMergeSlab(item.getVirtualSlabNo()))
                .map(PmSlabEstaPlan::getVirtualSlabNo).collect(Collectors.toList());
        // 根据虚拟板坯号查询组炉板坯合并表
        List<PmSlabMerge> pmSlabMergeList = new ArrayList<>(16);
        if (CollectionUtils.isNotEmpty(mergeVirtualSlabNoList)) {
            pmSlabMergeList =pmSlabMergeRepository.selectByMergeSlabNoList(mergeVirtualSlabNoList, tenantId);
            virtualSlabNoList.addAll(pmSlabMergeList.stream().map(PmSlabMerge::getVirtualSlabNo).collect(Collectors.toList()));
        }

        // b)	根据虚拟板坯号（VIRTUAL_SLAB_NO）查询【组板连铸板坯表（PM_PD_CC_SLAB）】获取见证点状态（WITNESS_POINT_STATUS）；
        List<PmPdCcSlab> slabList = pmPdCcSlabRepository.selectByVirtualSlabList(virtualSlabNoList, tenantId);
        if (CollectionUtils.isEmpty(slabList)) {
            throw new CommonException("pm.pd_cc_slab_001",virtualSlabNoList,"组板连铸板坯表");
        }
        List<String> orderNoAxisList = slabList.stream().map(PmPdCcSlab::getOrderNoAxis).distinct().collect(Collectors.toList());
        List<ObtainWitnessPointDTO> witnessPointList = pmQdToPoOrderRepository.selectWitnessOrderPass(orderNoAxisList, Arrays.asList(Constants.WITNESS_POINT), tenantId);
        Map<String, String> witnessPointMap = new HashMap<>(witnessPointList.size());
        for (ObtainWitnessPointDTO pointDTO : witnessPointList) {
            witnessPointMap.put(pointDTO.getOrderNo(), pointDTO.getWitnessPointStatus());
        }
        // 遍历计划下达的每一炉
        for (PmSteelCastHeat steelCastHeat : pmSteelCastHeatList) {
            steelCastHeat.setIsWitnessPoint("N");
            resultList.add(steelCastHeat);

            // 不是板坯和钢锭
            if (!Constants.CcType.TYPE_1.equals(steelCastHeat.getCcType()) && !Constants.CcType.TYPE_5.equals(steelCastHeat.getCcType())) {
                continue;
            }

            if (!slabEstaPlanMap.containsKey(steelCastHeat.getPono())) {
                throw new CommonException("pm.steel_cast_heat_009", steelCastHeat.getPono());
            }
            List<String> virtualList = slabEstaPlanMap.get(steelCastHeat.getPono());
            // 如果存在合并板坯，获取合并板坯的虚拟板坯号
            List<String> mergeVirtualList = virtualList.stream().filter(item -> Utils.isMergeSlab(item)).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(mergeVirtualList)) {
                virtualList.addAll(pmSlabMergeList.stream().filter(item -> mergeVirtualList.contains(item.getMergeSlabNo()))
                        .map(PmSlabMerge::getVirtualSlabNo).collect(Collectors.toList()));
            }

            // c)	若这一炉中存在见证点状态（WITNESS_POINT_STATUS）的值等于“Y”，则前端弹框提醒用户手动输入下发时间（SEND_TIME）,为"N"则提示
//            Optional<PmPdCcSlab> statusOptional = slabList.stream().filter(item -> virtualList.contains(item.getVirtualSlabNo()))
//                    .filter(item -> BaseConstants.FlagChar.NO.equals(item.getWitnessPointStatus())).findAny();
            for (PmPdCcSlab pmPdCcSlab : slabList) {
                if (!virtualList.contains(pmPdCcSlab.getVirtualSlabNo())) {
                    continue;
                }
                String witnessPointStatus = witnessPointMap.get(pmPdCcSlab.getOrderNoAxis());
                if (BaseConstants.FlagChar.YES.equals(witnessPointStatus)) {
                    steelCastHeat.setIsWitnessPoint(BaseConstants.FlagChar.YES);
                    steelCastHeat.setWitnessPointStatus(BaseConstants.FlagChar.YES);
                } else if (BaseConstants.FlagChar.NO.equals(witnessPointStatus)) {
                    throw new CommonException("pm.steel_cast_heat_019", steelCastHeat.getPono());
                }
            }
//            if (statusOptional.isPresent()) {
//                // 这一炉需要见证标记
//                steelCastHeat.setIsWitnessPoint("Y");
//                steelCastHeat.setWitnessPointStatus(BaseConstants.FlagChar.NO);
//            }
        }
        return resultList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<PmSteelCastHeat> planAssign(Long tenantId, PmSteelCastHeatReqParamDTO dto) {
        Date now = new Date();
        long seq = 0L;

        // 获取当日计划已确定或者下达最大顺序号
        long sexMoveMax = 0L;
        List<PmSteelCastHeat> steelCastHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PLAN_DATE, dto.getPlanDate()))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_MAIN_BACKLOG_CODE, dto.getMainBacklogCode()))
                .andWhere(Sqls.custom().andGreaterThan(PmSteelCastHeat.FIELD_PONO_STATUS, Constants.PonoStatus.STATUS_13))
                .build());
        if (CollectionUtils.isNotEmpty(steelCastHeatList)) {
            // 已经计划确定的最大连铸计划顺序号（CC_SEQ），
            Optional<Long> ccSeqOptional = steelCastHeatList.stream().map(PmSteelCastHeat::getCcSeq).max(Comparator.comparing(Long::longValue));
            if (ccSeqOptional.isPresent()) {
                sexMoveMax = ccSeqOptional.get();
            }
        }
        seq = sexMoveMax + 1;
        List<PmSteelCastHeat> sortSteelCastHeatList = dto.getPmSteelCastHeatList().stream().sorted(Comparator
                .comparing(PmSteelCastHeat::getCcSeq)).collect(Collectors.toList());
        for (PmSteelCastHeat steelCastHeat : sortSteelCastHeatList) {
            // 将计划下达的数据序号往前移动
            steelCastHeat.setCcSeq(seq++);
            steelCastHeat.setPonoStatus(Constants.PonoStatus.STATUS_15);
            steelCastHeat.setArchiveFlag("S");
            // 获取CC要求时间（CC_REQ_TIME）,若其值为空，则为其赋当前操作系统的时间；
            if (steelCastHeat.getCcReqTime() == null) {
                steelCastHeat.setCcReqTime(now);
            }
        }
        pmSteelCastHeatRepository.batchUpdateByPrimaryKey(sortSteelCastHeatList);

        // 然后将未进行计划下达的数据往后移动
        List<PmSteelCastHeat> castHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PLAN_DATE, dto.getPlanDate()))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_MAIN_BACKLOG_CODE, dto.getMainBacklogCode()))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PONO_STATUS, Constants.PonoStatus.STATUS_13))
                .build());
        if (CollectionUtils.isNotEmpty(castHeatList)) {
            List<PmSteelCastHeat> sortCastHeatList = castHeatList.stream().sorted(Comparator.comparing(PmSteelCastHeat::getCcSeq)).collect(Collectors.toList());
            for (PmSteelCastHeat pmSteelCastHeat : sortCastHeatList) {
                pmSteelCastHeat.setCcSeq(seq++);
            }
            pmSteelCastHeatRepository.batchUpdateByPrimaryKey(castHeatList);
        }

        // 更新组炉编制表状态为10
        List<String> ponoList = dto.getPmSteelCastHeatList().stream().map(PmSteelCastHeat::getPono).collect(Collectors.toList());
        List<PmSlabEstaPlan> pmSlabEstaPlanList = pmSlabEstaPlanRepository.selectByPonoList(ponoList, tenantId);
        pmSlabEstaPlanList.forEach(item -> item.setCsPrecPlanStatus(Constants.CsPrecPlanStatus.STATUS_10));
        pmSlabEstaPlanRepository.batchUpdateByPrimaryKey(pmSlabEstaPlanList);

        // 更新厚板组板状态
        // 1. 获取虚拟板坯号
        List<String> virtualSlabNoList = pmSlabEstaPlanList.stream().map(PmSlabEstaPlan::getVirtualSlabNo).collect(Collectors.toList());
        List<String> mergeVirtualList = pmSlabEstaPlanList.stream().filter(item -> Utils.isMergeSlab(item.getVirtualSlabNo()))
                .map(PmSlabEstaPlan::getVirtualSlabNo).collect(Collectors.toList());
        List<String> tmpSlabNoList = pmSlabEstaPlanList.stream().map(PmSlabEstaPlan::getTmpSlabNo).collect(Collectors.toList());
        Map<String, List<PmSlabMerge>> pmSlabMergeMap = new HashMap<>(mergeVirtualList.size());
        if (CollectionUtils.isNotEmpty(mergeVirtualList)) {
            List<PmSlabMerge> pmSlabMergeList = pmSlabMergeRepository.selectByMergeSlabNoList(mergeVirtualList, tenantId);
            for (PmSlabMerge pmSlabMerge : pmSlabMergeList) {
                virtualSlabNoList.add(pmSlabMerge.getVirtualSlabNo());
                tmpSlabNoList.add(pmSlabMerge.getTmpSlabNo());
                tmpSlabNoList.add(pmSlabMerge.getTmpPonoSlabNo());
                if (!pmSlabMergeMap.containsKey(pmSlabMerge.getMergeSlabNo())) {
                    pmSlabMergeMap.put(pmSlabMerge.getMergeSlabNo(), new ArrayList<>());
                }
                pmSlabMergeMap.get(pmSlabMerge.getMergeSlabNo()).add(pmSlabMerge);
            }
        }

        // 2.更新状态
        // 更新组板合同总量表
        List<PmPdContSum> pdContSumList = pmPdContSumRepository.selectByPdMatNoList(tenantId, virtualSlabNoList);
        pdContSumList.forEach(item -> item.setPdStatus(Constants.PdStatusHp.PD_STATUS_HP_27));
        pmPdContSumRepository.batchUpdateByPrimaryKey(pdContSumList);

        // 连铸板坯表
        List<PmPdCcSlab> pmPdCcSlabList = pmPdCcSlabRepository.selectByVirtualSlabList(virtualSlabNoList, tenantId);
        Map<String, String> pmPdCcSlabMap = new HashMap<>(pmPdCcSlabList.size());
        if (CollectionUtils.isNotEmpty(pmPdCcSlabList)) {
            pmPdCcSlabMap = pmPdCcSlabList.stream().collect(Collectors.toMap(PmPdCcSlab::getVirtualSlabNo, PmPdCcSlab::getCcType));
        }
        pmPdCcSlabList.forEach(item -> item.setPdStatusHp(Constants.PdStatusHp.PD_STATUS_HP_27));
        pmPdCcSlabRepository.batchUpdateByPrimaryKey(pmPdCcSlabList);


        List<PmCmdSlab> pmCmdSlabList = pmCmdSlabRepository.selectByTmpSlabNoList(tmpSlabNoList, tenantId);
        pmCmdSlabList.forEach(item -> item.setPdStatusHp(Constants.PdStatusHp.PD_STATUS_HP_27));
        pmCmdSlabRepository.batchUpdateByPrimaryKey(pmCmdSlabList);

        // 命令大板表
        List<PmCmdLargePlt> pmCmdLargePltList = pmCmdLargePltRepository.selectByTmpSlabNoList(tmpSlabNoList, tenantId);
        pmCmdLargePltList.forEach(item -> item.setPdStatusHp(Constants.PdStatusHp.PD_STATUS_HP_27));
        pmCmdLargePltRepository.batchUpdateByPrimaryKey(pmCmdLargePltList);

        // 获取浇次号信息（CAST_LOT_NO），根据浇次号以及主工序代码更新【炼钢连铸制造命令LOT表（PM_STEEL_CAST_LOT）】中LOT状态（LOT_STATUS）值为3，
        // 表示LOT计划确定；
        List<String> castLotNoList = dto.getPmSteelCastHeatList().stream().map(PmSteelCastHeat::getCastLotNo).distinct()
                .collect(Collectors.toList());
        List<PmSteelCastLot> pmSteelCastLotList = pmSteelCastLotRepository.selectByCastLotNoList(castLotNoList, tenantId);
        if (CollectionUtils.isNotEmpty(pmSteelCastLotList)) {
            pmSteelCastLotList.forEach(item -> item.setLotStatus(3L));
            pmSteelCastLotRepository.batchUpdateByPrimaryKey(pmSteelCastLotList);
        }

        // 将以下字段作为入参，调用合同跟踪模块“连铸预编制事件”接口，向合同跟踪抛帐
        List<PmSmallPltPos> pmSmallPltPosList = pmSmallPltPosRepository.selectByPdMatNoList(virtualSlabNoList, tenantId);
        Map<String, List<PmSmallPltPos>> pmSmallPltPosMap = new HashMap<>(pmSmallPltPosList.size());
        if (CollectionUtils.isNotEmpty(pmSmallPltPosList)) {
            pmSmallPltPosMap = pmSmallPltPosList.stream().collect(Collectors.groupingBy(PmSmallPltPos::getPdMatNo));
        }

        // 虚拟板坯或者备坯的数据从收池表拿
        Map<String, PmSlabPoolIn> poolInMap = new HashMap<>(virtualSlabNoList.size());
        if (CollectionUtils.isNotEmpty(virtualSlabNoList)) {
            List<PmSlabPoolIn> poolInList = pmSlabPoolInRepository.selectByVirtualSlabNoList(virtualSlabNoList, tenantId);
            poolInMap = poolInList.stream().collect(Collectors.toMap(PmSlabPoolIn::getVirtualSlabNo, Function.identity()));
        }
        List<PmSlabPreCastingDTO> resList = pmSlabEstaPlanService.commandAbandonContract(pmSlabEstaPlanList, pmSlabMergeMap, pmPdCcSlabMap, pmSmallPltPosMap, poolInMap,
                "27", "10", "A1A", "A1");
        // 以下字段作为入参，调用合同跟踪模块“连铸预编制事件”接口，向合同跟踪抛帐：
        log.info("<=====计划下达调用连铸预编制事件，入参为{}=====>", JSON.toJSONString(resList));
        eventClient.sendEventWithOutResponse(tenantId, CtEventConstants.EVENT_PM_PRE_CONTINUOUS_CASTING, resList);

        // 5.  将厂别（MAIN_BACKLOG_CODE）和制造命令号（PONO）作为入参，调用炼钢模块“计划下达”接口，根据其返回结果进行如下操作：
        List<ProductionPlanningApiDTO> requestList = new ArrayList<>();
        for (PmSteelCastHeat pmSteelCastHeat : dto.getPmSteelCastHeatList()) {
            ProductionPlanningApiDTO request = buildProductionPlanningApiDTO(pmSteelCastHeat);
            requestList.add(request);
        }
        smApiClient.productionPlanningApi(tenantId, requestList);

        return dto.getPmSteelCastHeatList();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<PmSteelCastHeat> squarePlanAssign(Long tenantId, List<PmSteelCastHeat> pmSteelCastHeatList) {
        Date now = new Date();
        for (PmSteelCastHeat steelCastHeat : pmSteelCastHeatList) {
            steelCastHeat.setPonoStatus(Constants.PonoStatus.STATUS_15);
            steelCastHeat.setArchiveFlag("S");
            // 获取CC要求时间（CC_REQ_TIME）,若其值为空，则为其赋当前操作系统的时间；
            if (steelCastHeat.getCcReqTime() == null) {
                steelCastHeat.setCcReqTime(now);
            }
        }
        pmSteelCastHeatRepository.batchUpdateByPrimaryKey(pmSteelCastHeatList);

        // 5.  将厂别（MAIN_BACKLOG_CODE）和制造命令号（PONO）作为入参，调用炼钢模块“计划下达”接口，根据其返回结果进行如下操作：
        List<ProductionPlanningApiDTO> requestList = new ArrayList<>();
        for (PmSteelCastHeat pmSteelCastHeat : pmSteelCastHeatList) {
            ProductionPlanningApiDTO request  = buildProductionPlanningApiDTO(pmSteelCastHeat);
            requestList.add(request);
        }
        smApiClient.productionPlanningApi(tenantId, requestList);
        return pmSteelCastHeatList;
    }

    private ProductionPlanningApiDTO buildProductionPlanningApiDTO(PmSteelCastHeat pmSteelCastHeat) {
        ProductionPlanningApiDTO request = new ProductionPlanningApiDTO();
        request.setMainBacklogCode(pmSteelCastHeat.getMainBacklogCode());
        request.setPono(pmSteelCastHeat.getPono());
        request.setYearId(pmSteelCastHeat.getYearId());
        request.setCcSeq(pmSteelCastHeat.getCcSeq());
        request.setStNo(pmSteelCastHeat.getStNo());
        request.setSgSign(pmSteelCastHeat.getSgSign());
        request.setPlanCastLotNo(pmSteelCastHeat.getCastLotNo());
        request.setCastLotDivNo(pmSteelCastHeat.getCastLotDivNo());
        request.setCastLotSum(pmSteelCastHeat.getCastLotSum());
        request.setCastLotNo(pmSteelCastHeat.getCastLotNo());
        request.setCcmNo(pmSteelCastHeat.getCcMachNo());
        request.setMoldThick(pmSteelCastHeat.getMoldThick());
        request.setMoldWidth(pmSteelCastHeat.getMoldWidth());
        request.setRestrandFlg(pmSteelCastHeat.getRestrandFlg());
        request.setPlanRefineRouteCode(pmSteelCastHeat.getRefineRouteCode());
        request.setRefineRouteCode(null);
        request.setPlanTapWt(pmSteelCastHeat.getPlanTapWt());
        request.setPlanDate(pmSteelCastHeat.getPlanDate());
        request.setCcReqTime(pmSteelCastHeat.getCcReqTime());
        request.setSteelReturnCode(null);
        request.setHotSendFlag(pmSteelCastHeat.getHotSendFlag());
        request.setHotChargeFlag(pmSteelCastHeat.getHotChargeFlag());
        request.setIsBloom(pmSteelCastHeat.getIsBloom());
        request.setTdChgFlg(pmSteelCastHeat.getTdChgFlg());
        if (pmSteelCastHeat.getSendTime() != null) {
            try {
                request.setSendTime(DateUtils.parseDate(pmSteelCastHeat.getSendTime(), BaseConstants.Pattern.DATETIME));
            } catch (ParseException e) {
                throw new CommonException("pm.pm.pm_pd_rec_001");
            }
        }
        request.setWitnessPointStatus(pmSteelCastHeat.getWitnessPointStatus());
        request.setCcType(pmSteelCastHeat.getCcType());
        request.setScrapSteelType(pmSteelCastHeat.getSlabPlaceCode());
        return request;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void furnaceRecycle(Long tenantId, PmSteelCastHeatReqParamDTO dto) {
        dto.getPmSteelCastHeatList().forEach(item -> {
            // 查询出来的连铸机号与前端传入的连铸机号不相等
            if (!BaseConstants.FlagChar.YES.equals(dto.getIsInterface())) {
                if (!item.getCcMachNo().equals(dto.getCcMachNo())) {
                    throw new CommonException("pm.casting_machine_pre_plan_014", item.getPono(), dto.getCcMachNo());
                }
                // 没有计划下达
                if (item.getPonoStatus().compareTo(Constants.PonoStatus.STATUS_15) < 0) {
                    throw new CommonException("pm.casting_machine_pre_plan_018", item.getPono());
                }

                // 查询出来的制造命令状态（PONO_STATUS）大于15
                if (item.getPonoStatus().compareTo(Constants.PonoStatus.STATUS_15) > 0) {
                    throw new CommonException("pm.casting_machine_pre_plan_015", item.getPono());
                }
            } else {
                // 查询出来的制造命令状态（PONO_STATUS）大于15
                if (item.getPonoStatus().compareTo(Constants.PonoStatus.STATUS_15) > 0) {
                    throw new CommonException("pm.casting_machine_pre_plan_015", item.getPono());
                }
            }
        });
        // 制造命令号
        List<String> ponoList = dto.getPmSteelCastHeatList().stream().map(PmSteelCastHeat::getPono).collect(Collectors.toList());
        // 浇次号
        List<String> castLotNoList = dto.getPmSteelCastHeatList().stream().map(PmSteelCastHeat::getCastLotNo).distinct().collect(Collectors.toList());

        // e)	若待回收炉次的计划浇次头/尾炉标记（RESTRAND_FLG）的值为T，说明该炉为所在浇次的头炉，回收之前需要将头炉标记传给下一炉，
        Map<String, List<PmSteelCastHeat>> steelCastHeatMap = dto.getPmSteelCastHeatList().stream()
                .collect(Collectors.groupingBy(PmSteelCastHeat::getCastLotNo));
        // 查询表里浇次的数据
        List<PmSteelCastHeat> pmSteelCastHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                .andWhere(Sqls.custom().andIn(PmSteelCastHeat.FIELD_CAST_LOT_NO, castLotNoList))
                .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                .build());
        Map<String, List<PmSteelCastHeat>> steelCastMap = new HashMap<>(pmSteelCastHeatList.size());
        if (CollectionUtils.isNotEmpty(pmSteelCastHeatList)) {
            // 过滤掉要回收的炉
            List<PmSteelCastHeat> otherCastHeatList = pmSteelCastHeatList.stream().filter(item -> !ponoList.contains(item.getPono()))
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(otherCastHeatList)) {
                steelCastMap = otherCastHeatList.stream().collect(Collectors.groupingBy(PmSteelCastHeat::getCastLotNo));
            }
        }
        List<PmSteelCastHeat> updateRestrandFlgList = new ArrayList<>();
        for (Map.Entry<String, List<PmSteelCastHeat>> entry : steelCastHeatMap.entrySet()) {
            List<PmSteelCastHeat> steelCastHeatList = entry.getValue();
            // 回收的存在头炉标记
            Optional<PmSteelCastHeat> isExistTOptional = steelCastHeatList.stream().filter(item -> "T".equals(item.getRestrandFlg())).findAny();
            if (isExistTOptional.isPresent() && !steelCastMap.isEmpty() && steelCastMap.containsKey(entry.getKey())) {
                // 序号排序取下一炉
                List<PmSteelCastHeat> sortCastHeatList = steelCastMap.get(entry.getKey()).stream().sorted(Comparator.comparing(PmSteelCastHeat::getCcSeq))
                        .collect(Collectors.toList());
                PmSteelCastHeat pmSteelCastHeat = sortCastHeatList.get(0);
                pmSteelCastHeat.setRestrandFlg("T");
                updateRestrandFlgList.add(pmSteelCastHeat);
            }
        }
        pmSteelCastHeatRepository.batchUpdateByPrimaryKey(updateRestrandFlgList);

        // 如果ccType = 1 或者5，更新炼钢炉次计划热处理去向表热处理去向状态为W
        List<String> slabPonoList = dto.getPmSteelCastHeatList().stream().filter(item->Constants.CcType.TYPE_1.equals(item.getCcType()) ||
                Constants.CcType.TYPE_5.equals(item.getCcType())).filter(item->BaseConstants.FlagChar.YES.equals(item.getIsHavingHreat()))
                .map(PmSteelCastHeat::getPono).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(slabPonoList)) {
            List<PmHotDest> pmHotDestList = pmHotDestRepository.selectByCondition(Condition.builder(PmHotDest.class)
                    .andWhere(Sqls.custom().andIn(PmHotDest.FIELD_PONO, slabPonoList))
                    .andWhere(Sqls.custom().andEqualTo(PmHotDest.FIELD_TENANT_ID, tenantId))
                    .build());
            if (CollectionUtils.isEmpty(pmHotDestList)) {
                throw new CommonException("pm.steel_cast_heat_007", slabPonoList, "炼钢炉次计划热处理去向表");
            }
            pmHotDestList.forEach(item->item.setStatus("W"));
            pmHotDestRepository.batchUpdateByPrimaryKey(pmHotDestList);
        }

        // g)	根据待回收炉次的制造命令号（PONO）、主工序代码（MAIN_BACKLOG_CODE）更新【炼钢连铸制造命令炉次表（PM_STEEL_CAST_HEAT）】信息
        List<PmSteelCastHeat> updateList = new ArrayList<>();
        for (PmSteelCastHeat pmSteelCastHeat : dto.getPmSteelCastHeatList()) {
            pmSteelCastHeat.setPonoStatus(Constants.PonoStatus.STATUS_11);
            pmSteelCastHeat.setCcSeq(0L);
            pmSteelCastHeat.setCcReqTime(null);
            pmSteelCastHeat.setCcReqTimeFlag(null);
            pmSteelCastHeat.setPlanDate(null);
            pmSteelCastHeat.setShiftNo(null);
            pmSteelCastHeat.setShiftGroup(null);
            pmSteelCastHeat.setNewTestNo(null);
            updateList.add(pmSteelCastHeat);
        }
        pmSteelCastHeatRepository.batchUpdateByPrimaryKey(updateList);

        // 更新计划日期下的序号 当天序号重新排序
        if (!BaseConstants.FlagChar.YES.equals(dto.getIsInterface())) {
            List<PmSteelCastHeat> steelCastHeatList = pmSteelCastHeatRepository.selectByCondition(Condition.builder(PmSteelCastHeat.class)
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_TENANT_ID, tenantId))
                    .andWhere(Sqls.custom().andEqualTo(PmSteelCastHeat.FIELD_PLAN_DATE, dto.getPlanDate()))
                    .build());
            if (CollectionUtils.isNotEmpty(steelCastHeatList)) {
                List<PmSteelCastHeat> sortSteelCastHeatList = steelCastHeatList.stream()
                        .sorted(Comparator.comparing(PmSteelCastHeat::getCcSeq)).collect(Collectors.toList());
                long seq = 1L;
                for (PmSteelCastHeat pmSteelCastHeat : sortSteelCastHeatList) {
                    pmSteelCastHeat.setCcSeq(seq++);
                }
                pmSteelCastHeatRepository.batchUpdateByPrimaryKey(sortSteelCastHeatList);
            }

        }

        // 更新组炉编制表状态为09
        List<PmSlabEstaPlan> pmSlabEstaPlanList = pmSlabEstaPlanRepository.selectByPonoList(ponoList, tenantId);
        pmSlabEstaPlanList.forEach(item->item.setCsPrecPlanStatus(Constants.CsPrecPlanStatus.STATUS_09));
        pmSlabEstaPlanRepository.batchUpdateByPrimaryKey(pmSlabEstaPlanList);
        // 将制造命令号（PONO）作为入参，调用炼钢模块“炉次回收”接口，返回“炉次回收失败”，则在前端提示失败原因;若接口返回“炉次回收成功”.
        smApiClient.heatRetracted(tenantId, ponoList);
    }
}

