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

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
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.PmBoardMatInfoDTO;
import com.xisc.pm.api.dto.PmCompositeSlabCalcDTO;
import com.xisc.pm.api.dto.PmCutPlaceDTO;
import com.xisc.pm.api.dto.PmDeleteFailureDTO;
import com.xisc.pm.api.dto.PmOrderOverDTO;
import com.xisc.pm.api.dto.PmPdRecDTO;
import com.xisc.pm.api.dto.PmPlateConfigDTO;
import com.xisc.pm.api.dto.PmProContCanclePoolReqDTO;
import com.xisc.pm.api.dto.PmProContFilterRequestDTO;
import com.xisc.pm.api.dto.PmProContFilterResposeDTO;
import com.xisc.pm.api.dto.PmProContPoolRequestDTO;
import com.xisc.pm.api.dto.PmProContPoolResposeDTO;
import com.xisc.pm.api.dto.PmProContRequestDTO;
import com.xisc.pm.api.dto.PmProContResposeDTO;
import com.xisc.pm.api.dto.PmProContSelectionDTO;
import com.xisc.pm.api.dto.PmProContSelectionRequestDTO;
import com.xisc.pm.api.dto.PmProContSimpleDTO;
import com.xisc.pm.api.dto.PmProContYieldCopyRequestDTO;
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.RuleParamDTO;
import com.xisc.pm.api.dto.ctevent.ProContPoolDTO;
import com.xisc.pm.app.service.PmPdCcSlabService;
import com.xisc.pm.app.service.PmPdRecService;
import com.xisc.pm.app.service.PmPdRuleSetService;
import com.xisc.pm.app.service.PmProContService;
import com.xisc.pm.app.service.strategy.PdMatTypeStrategyFactory;
import com.xisc.pm.app.service.strategy.pdmattype.PdMatTypeStrategy;
import com.xisc.pm.domain.entity.PmContMscTech;
import com.xisc.pm.domain.entity.PmMinThickTolBt;
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.PmProCont;
import com.xisc.pm.domain.entity.PmProContProdTtr;
import com.xisc.pm.domain.entity.PmSampleReserveBt;
import com.xisc.pm.domain.entity.PmSlabSpecBt;
import com.xisc.pm.domain.repository.PmContMscTechRepository;
import com.xisc.pm.domain.repository.PmCtMainRepository;
import com.xisc.pm.domain.repository.PmCutPlaceBtRepository;
import com.xisc.pm.domain.repository.PmMinThickTolBtRepository;
import com.xisc.pm.domain.repository.PmPdBlockPosRepository;
import com.xisc.pm.domain.repository.PmPdConstBtRepository;
import com.xisc.pm.domain.repository.PmPdContSumRepository;
import com.xisc.pm.domain.repository.PmPdSlabRepository;
import com.xisc.pm.domain.repository.PmPlateSpecBtRepository;
import com.xisc.pm.domain.repository.PmProContProdTtrRepository;
import com.xisc.pm.domain.repository.PmProContRepository;
import com.xisc.pm.domain.repository.PmQdToPoOrderRepository;
import com.xisc.pm.domain.repository.PmSampleReserveBtRepository;
import com.xisc.pm.domain.repository.PmSlabSpecBtRepository;
import com.xisc.pm.domain.vo.CtMainVO;
import com.xisc.pm.domain.vo.QdOrderTechVO;
import com.xisc.pm.domain.vo.QdOrderVO;
import com.xisc.pm.domain.vo.QdToLineupResultSteelVO;
import com.xisc.pm.domain.vo.QeTjWitnessProOrderVO;
import com.xisc.pm.infra.client.EventClient;
import com.xisc.pm.infra.client.QdOrderClient;
import com.xisc.pm.infra.constant.Constants;
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.PdMatStatus;
import com.xisc.pm.infra.enums.PdMatType;
import com.xisc.pm.infra.util.BeanUtils;
import com.xisc.pm.infra.util.DateUtils;
import com.xisc.pm.infra.util.Utils;
import io.choerodon.core.domain.Page;
import io.choerodon.core.domain.PageInfo;
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 lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
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.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.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
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.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 生产合同主表应用服务默认实现
 *
 * @author 曾俊 jun.zeng@hand-china.com 2024-07-29 14:28:16
 */
@Slf4j
@Service
public class PmProContServiceImpl implements PmProContService, AopProxy<PmProContService> {

    private final PmProContRepository pmProContRepository;

    @Autowired
    private PmProContProdTtrRepository pmProContProdTtrRepository;

    @Autowired
    private PmContMscTechRepository pmContMscTechRepository;

    @Autowired
    private PmPdContSumRepository pmPdContSumRepository;

    @Autowired
    private PmPdRuleSetService pmPdRuleSetService;

    @Autowired
    private UserClient userClient;

    @Autowired
    private PmSlabSpecBtRepository pmSlabSpecBtRepository;

    @Autowired
    private PmMinThickTolBtRepository pmMinThickTolBtRepository;

    @Autowired
    private CodeRuleBuilder codeRuleBuilder;
    
    @Autowired
    private PmPdConstBtRepository pmPdConstBtRepository ;
    
    @Autowired
    private PmPlateSpecBtRepository pmPlateSpecBtRepository;
    
    @Autowired
    private PmPdCcSlabService pmPdCcSlabService;
    
    @Autowired
    private PmCutPlaceBtRepository pmCutPlaceBtRepository;
    
    @Autowired
    private RedisHelper redisHelper;
    
    @Autowired
    private PmQdToPoOrderRepository pmQdToPoOrderRepository;

    @Autowired
    private PmCtMainRepository pmCtMainRepository;
    
    @Autowired
    private PmPdRecService pmPdRecService;
    
    @Autowired
    private EventClient eventClient;
    
    @Autowired
    private QdOrderClient qdOrderClient;
    
    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private PmPdBlockPosRepository pmPdBlockPosRepository;

    @Autowired
    private PmPdSlabRepository pmPdSlabRepository;

    @Autowired
    private PmSampleReserveBtRepository pmSampleReserveBtRepository;
    
    @Autowired
    private LovAdapter lovAdapter;

    @Autowired
    public PmProContServiceImpl(PmProContRepository pmProContRepository) {
        this.pmProContRepository = pmProContRepository;
    }

    /**
     * 按订单编号执行生产合同收池，生成生产合同表，生产合同属性表，合同产线工艺参数表数据，并调用合同跟踪修改合同状态38为40
     * 
     * @param pmProContPoolRequest 查询收池合同接口请求参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pool(PmProContPoolRequestDTO pmProContPoolRequestDTO) {
        if (pmProContPoolRequestDTO == null || pmProContPoolRequestDTO.getOrderNoList() == null
                || pmProContPoolRequestDTO.getOrderNoList().isEmpty()) {
            // 参数订单编号为空!
            throw new CommonException("pm.pm_pro_cont_001");
        }
        List<PmPdRecDTO> pmPdRecs = new ArrayList<>();
        long allCount = pmProContPoolRequestDTO.getOrderNoList().size();
        long limit = (allCount + PmPlateConstants.BATCH_MAX_SIZE - 1) / PmPlateConstants.BATCH_MAX_SIZE;
        List<ProContPoolDTO> proContPoolDTOs = new ArrayList<>();
        Stream.iterate(0, n -> n + 1).limit(limit).forEach(i -> {
            // 分拆多个子sheet
            List<String> orderNoList =  pmProContPoolRequestDTO.getOrderNoList().stream().skip(i * PmPlateConstants.BATCH_MAX_SIZE)
                    .limit(PmPlateConstants.BATCH_MAX_SIZE)
                    .collect(Collectors.toList());
            List<CtMainVO> ctMainVOs = pmCtMainRepository.selectCtMainByOrderList(orderNoList, pmProContPoolRequestDTO.getTenantId());
            // 查询合同信息
            List<QdOrderVO> qdOrderVOs = qdOrderClient.selectQdOrderByOrderNoList(pmProContPoolRequestDTO.getTenantId(), orderNoList);
            
            List<QdOrderTechVO> qdOrderTechVOs = qdOrderClient.selectQdOrderTechByOrderNoList(pmProContPoolRequestDTO.getTenantId(), orderNoList);
            if(qdOrderVOs == null || qdOrderTechVOs == null) {
                throw new CommonException("pm.pm_pro_cont_prod_ttr_001", String.join(",", pmProContPoolRequestDTO.getOrderNoList()));   
            }
            Map<String , QdOrderVO> poOrderMap = Maps.uniqueIndex(qdOrderVOs, QdOrderVO::getOrderNo);

            List<String> stNoList = qdOrderTechVOs.stream().map(QdOrderTechVO::getStNo).distinct().collect(Collectors.toList());
            Map<String, String> qdOrderTechMap = new HashMap<>();
            for (QdOrderTechVO qdOrderTechVO : qdOrderTechVOs) {
                qdOrderTechMap.put(qdOrderTechVO.getOrderNo(), qdOrderTechVO.getStNo());
            }
            stNoList.add("*");
            List<PmSampleReserveBt> pmSampleReserveBtList = pmSampleReserveBtRepository.selectByStNoList(stNoList, pmProContPoolRequestDTO.getTenantId());
            Map<String, PmSampleReserveBt> pmSampleReserveBtMap = pmSampleReserveBtList.stream().collect(Collectors.toMap(PmSampleReserveBt::getStNo, Function.identity()));
            for (CtMainVO ctMainVO : ctMainVOs) {
                if (!poOrderMap.containsKey(ctMainVO.getOrderNo())) {
                    throw new CommonException("pm.pro_cont_002", ctMainVO.getOrderNo());
                }
                // 校验合同跟踪订货件数和质量订货件数
                if (Utils.getBigDecimalValue(ctMainVO.getOrderNum()).compareTo(poOrderMap.get(ctMainVO.getOrderNo()).getOrderQty()) != 0) {
                    throw new CommonException("pm.pro_cont_003", ctMainVO.getOrderNo(), ctMainVO.getOrderNum(), poOrderMap.get(ctMainVO.getOrderNo()).getOrderQty());
                }
            }
            
            // 查询存在试样记录的列表
            Set<String> diOrderSet = pmQdToPoOrderRepository.qdToLineupResultSampleOrderList(orderNoList, pmProContPoolRequestDTO.getTenantId());

            // 创建生产合同数据
            long start = System.currentTimeMillis();
            List<PmProCont> pmProConts = pmProContRepository.createProContList(ctMainVOs , pmProContPoolRequestDTO , orderNoList);
            log.debug("插入合同表：" + (System.currentTimeMillis()-start));
            long start1 = System.currentTimeMillis();
            // 生产生产合同属性信息
            pmProContProdTtrRepository.createProContProdTtr(pmProConts , poOrderMap , diOrderSet, pmSampleReserveBtMap, qdOrderTechMap);
            log.debug("生产生产合同属性信息：" + (System.currentTimeMillis()-start1));
            //生产工艺相关表关系与取值
            long start2 = System.currentTimeMillis();
            // 获取板坯位置代码
            List<String> mscLineNoList = qdOrderTechVOs.stream().map(QdOrderTechVO::getMscLineNo).distinct().collect(Collectors.toList());
            List<QdToLineupResultSteelVO> qdToLineupResultSteelVOList = pmProContRepository.selectSlabPlaceCode(orderNoList , mscLineNoList , pmProContPoolRequestDTO.getTenantId());
            Map<String, String> qdToLineupResultSteelMap = new HashMap<>(qdToLineupResultSteelVOList.size());
            if (CollectionUtils.isNotEmpty(qdToLineupResultSteelVOList)) {
                qdToLineupResultSteelMap = qdToLineupResultSteelVOList.stream().collect(Collectors
                        .toMap(item -> Strings.concat(item.getOrderNo(), item.getMscLineNo()), QdToLineupResultSteelVO::getSlabPlaceCode, (k,v)->k));
            }
            pmContMscTechRepository.createPmContMscTech(pmProConts , qdOrderTechVOs , pmProContPoolRequestDTO.getTenantId(), qdToLineupResultSteelMap);
            log.debug("生产工艺相关表关系与取值: " + (System.currentTimeMillis()-start2));
            for (PmProCont pmProCont : pmProConts) {
                proContPoolDTOs.add(new ProContPoolDTO(pmProCont.getOrderNo(), pmProCont.getPdLackQty(), pmProCont.getPdLackWt()));
            }

            Map<String, String> mechMap = qdOrderTechVOs.stream().collect(Collectors.groupingBy(QdOrderTechVO::getOrderNo, Collectors.mapping(QdOrderTechVO::getMscLineNo, Collectors.joining(", "))));
            pmProConts.forEach(pmProCont -> {
                PmPdRecDTO pmPdRecDTO = new PmPdRecDTO();
                pmPdRecDTO.setOrderNo(pmProCont.getOrderNo());
                pmPdRecDTO.setMscLineNo(mechMap.get(pmProCont.getOrderNo()));
                pmPdRecDTO.setWt(pmProCont.getPdLackWt());
                pmPdRecDTO.setQty(pmProCont.getPdLackQty());
                pmPdRecs.add(pmPdRecDTO);
            });
        });
        // 抛组板履历
        pmPdRecService.createEvent(pmProContPoolRequestDTO.getTenantId(), pmPdRecs , PdEventType.HP01 ,Constants.SYSTEM_CODE , Constants.PdProgram.ORDER_POOL_ADD_PROGRAM);

        // 抛合同
        eventClient.sendEvent(pmProContPoolRequestDTO.getTenantId(), CtEventConstants.EVENT_PM_CONTRACT_BOARD_REC , proContPoolDTOs , String.class);
    }

    /**
     * 
     * 通过调用合同跟踪模块，与质量管理模块获取合同状态为38的合同数据。
     * 
     * @param pageRequest          分页参数
     * @param pmProContPoolRequest 查询收池合同接口请求参数
     */
    @Override
    public Page<PmProContPoolResposeDTO> poolList(PmProContPoolRequestDTO pmProContPoolRequest, PageRequest pageRequest) {
        SimpleDateFormat sdf = new SimpleDateFormat(DateUtils.YMD);
        if (pmProContPoolRequest.getDelivyDateTo() != null) {
            pmProContPoolRequest.setDelivyDateToStr(sdf.format(pmProContPoolRequest.getDelivyDateTo()));
            pmProContPoolRequest.setDelivyDateTo(null);
        }
        if (pmProContPoolRequest.getDelivyDateFrom() != null) {
            pmProContPoolRequest.setDelivyDateFromStr(sdf.format(pmProContPoolRequest.getDelivyDateFrom()));
            pmProContPoolRequest.setDelivyDateFrom(null);
        }
        //1. 调取合同跟踪模块“合同跟踪合同查询”接口，获取合同状态ORDER_STATUS为‘38’状态的合同号ORDER_NO
        pmProContPoolRequest.setPageFlag(BaseConstants.Flag.YES);
        Page<PmProContPoolResposeDTO> pageResult = PageHelper.doPage(pageRequest, ()->pmQdToPoOrderRepository.selectByOrderNoList(pmProContPoolRequest)) ;
        pmProContPoolRequest.setPageFlag(BaseConstants.Flag.NO);
        List<String> orderNoList = new ArrayList<>();
        for (PmProContPoolResposeDTO pmProContPoolResposeDTO : pageResult) {
            orderNoList.add(pmProContPoolResposeDTO.getOrderNo());
        }
//        pmProContPoolRequest.setOrderNoList(orderNoList);
        if(orderNoList == null || orderNoList.isEmpty()) {
            return new Page<>();
        }
        List<PmProContPoolResposeDTO> context = new ArrayList<>(orderNoList.size());
        // 2. 用1获取到的合同号+参数，调用质量管理模块“质量管理合同查询”接口，获取画面数据项展示所需信息
        
        long allCount = orderNoList.size();
        long limit = (allCount + PmPlateConstants.BATCH_MAX_SIZE - 1) / PmPlateConstants.BATCH_MAX_SIZE;
        List<ProContPoolDTO> proContPoolDTOs = new ArrayList<>();
        Stream.iterate(0, n -> n + 1).limit(limit).forEach(i -> {
            // 分拆多个子sheet
            List<String> splitOrderNoList =  orderNoList.stream().skip(i * PmPlateConstants.BATCH_MAX_SIZE)
                    .limit(PmPlateConstants.BATCH_MAX_SIZE)
                    .collect(Collectors.toList());
            pmProContPoolRequest.setOrderNoList(splitOrderNoList);
            List<PmProContPoolResposeDTO> contPoolResposeDTOs = pmQdToPoOrderRepository.selectByOrderNoList(pmProContPoolRequest);
            // 产线号聚合
            Map<String , PmProContPoolResposeDTO> result = new HashMap<>(contPoolResposeDTOs.size());
            Map<String , Set<String>> st = new HashMap<>(contPoolResposeDTOs.size());
            Map<String , Set<String>> mscLine = new HashMap<>(contPoolResposeDTOs.size());
            
//            List<LovValueDTO> mscLineNoList = lovAdapter.queryLovValue("PM.MSC_LINE_NO", pmProContPoolRequest.getTenantId());
//            Map<String , LovValueDTO> lovMap = Maps.uniqueIndex(mscLineNoList, LovValueDTO::getValue);
            
            for (PmProContPoolResposeDTO pmProContPoolResposeDTO : contPoolResposeDTOs) {
                if(!result.containsKey(pmProContPoolResposeDTO.getOrderNo())) {
                    result.put(pmProContPoolResposeDTO.getOrderNo(), pmProContPoolResposeDTO);
                    mscLine.put(pmProContPoolResposeDTO.getOrderNo(), new TreeSet<>());
                    st.put(pmProContPoolResposeDTO.getOrderNo(), new HashSet<>());
                } 
                if(StringUtils.isNotBlank(pmProContPoolResposeDTO.getStNo())) {
                    st.get(pmProContPoolResposeDTO.getOrderNo()).add(pmProContPoolResposeDTO.getStNo());
                }
                if(StringUtils.isNotBlank(pmProContPoolResposeDTO.getMscLineNo())) {
//                    mscLine.get(pmProContPoolResposeDTO.getOrderNo()).add(lovMap.containsKey(pmProContPoolResposeDTO.getMscLineNo()) ? 
//                            lovMap.get(pmProContPoolResposeDTO.getMscLineNo()).getMeaning():pmProContPoolResposeDTO.getMscLineNo());
                    mscLine.get(pmProContPoolResposeDTO.getOrderNo()).add(pmProContPoolResposeDTO.getMscLineNo());
                }
            }
            for (PmProContPoolResposeDTO pmProContPoolResposeDTO : result.values()) {
                if(st.containsKey(pmProContPoolResposeDTO.getOrderNo())) {
                    pmProContPoolResposeDTO.setStNo(String.join(",",st.get(pmProContPoolResposeDTO.getOrderNo())));
                }
                if(mscLine.containsKey(pmProContPoolResposeDTO.getOrderNo())) {
                    pmProContPoolResposeDTO.setMscLineNo(String.join(",",mscLine.get(pmProContPoolResposeDTO.getOrderNo())));
                }
                context.add(pmProContPoolResposeDTO);
            }
        });
        return new Page<>(context, new PageInfo(pageRequest.getPage(), pageRequest.getSize()), pageResult.getTotalElements());
    }
    
    @Override
    public List<PmProContSimpleDTO> selectProContSimpleList(Long organizationId, String orderNo, String stNo) {
        if(StringUtils.isBlank(stNo) && StringUtils.isBlank(orderNo)) {
            throw new CommonException("pm.pm_pro_cont_052");
        }
        return pmProContRepository.selectProContSimpleList(organizationId, orderNo, stNo);
    }
    
    @Override
    public List<PmBoardMatInfoDTO> boardMatList(Long organizationId, String orderNo, String matDesignKind) {
        PdMatTypeStrategy pdMatTypeStrategy = PdMatTypeStrategyFactory.matchStrategy(matDesignKind);
        return pdMatTypeStrategy.selectBoardMatByOrderNo(orderNo , organizationId);
    }

    @Override
    public Page<PmProContResposeDTO> list(PmProContRequestDTO pmProContRequest , PageRequest pageRequest) {
        PmProContFilterRequestDTO pmProContFilterRequest = new PmProContFilterRequestDTO();
        pmProContFilterRequest.setTenantId(pmProContRequest.getTenantId());
        // 调取合同跟踪模块“合同跟踪合同查询”接口，获取合同状态ORDER_STATUS大于等于‘40’小于‘67’的所有合同号ORDER_NO
        List<String> orderNoList = new ArrayList<>();
                // pmCtMainRepository.selectCanPdByCtMain(pmProContFilterRequest);
        
        Page<PmProCont> pmProConts = PageHelper.doPage(pageRequest, () -> this.pmProContRepository.queryByOrderNoList(orderNoList,pmProContRequest)) ;
        if (pmProConts == null || pmProConts.isEmpty()) {
            return new Page<>();
        }
        for (PmProCont pmProCont : pmProConts) {
            orderNoList.add(pmProCont.getOrderNo());
        }
        Map<String, PmProContProdTtr> pmProContProdTtrMap = new HashMap<>(pmProConts.size());
        // 查询合同产线工艺参数表PM_CONT_MSC_TECH的相关内容的第一条记录（因为一个合同可能对应多个产线）；
        Map<String, PmContMscTech> contMscTechMap = new HashMap<>(pmProConts.size());
        Map<String , Set<String>> mscLineNo = new HashMap<>();
        Map<String , CtMainVO> cmCtMainMap = new HashMap<>();
        long allCount = orderNoList.size();
        long limit = (allCount + PmPlateConstants.BATCH_MAX_SIZE - 1) / PmPlateConstants.BATCH_MAX_SIZE;
        Stream.iterate(0, n -> n + 1).limit(limit).forEach(i -> {
            // 分拆多个子sheet
            List<String> splitOrderNoList =  orderNoList.stream().skip(i * PmPlateConstants.BATCH_MAX_SIZE)
                    .limit(PmPlateConstants.BATCH_MAX_SIZE)
                    .collect(Collectors.toList());
            
            List<PmProContProdTtr> pmProContProdTtrs = this.pmProContProdTtrRepository.selectByOrderNoList(splitOrderNoList,
                    pmProContRequest.getTenantId());
            List<PmContMscTech> contMscTechs = this.pmContMscTechRepository.selectByOrderNoList(splitOrderNoList,
                    pmProContRequest.getTenantId());
            
            // 调用合同跟踪模块“合同跟踪合同查询”接口 获取状态和合同跟踪欠件
            pmProContFilterRequest.setOrderNoList(splitOrderNoList);
            List<CtMainVO> cmCtMainVOs = pmCtMainRepository.selectCanPdByOrderStatus(pmProContFilterRequest);
           
            for (CtMainVO ctMainVO : cmCtMainVOs) {
                cmCtMainMap.put(ctMainVO.getOrderNo(), ctMainVO);
            }
            
            
            if (pmProContProdTtrs != null && !pmProContProdTtrs.isEmpty()) {
                for (PmProContProdTtr pmProContProdTtr : pmProContProdTtrs) {
                    pmProContProdTtrMap.put(pmProContProdTtr.getOrderNo(), pmProContProdTtr);
                }
            }
            if (contMscTechs != null && !contMscTechs.isEmpty()) {
                for (PmContMscTech pmContMscTech : contMscTechs) {
                    if (contMscTechMap.containsKey(pmContMscTech.getOrderNo())) {
                        mscLineNo.get(pmContMscTech.getOrderNo()).add(pmContMscTech.getMscLineNo());
                        continue;
                    }
                    mscLineNo.put(pmContMscTech.getOrderNo(), new TreeSet<>());
                    mscLineNo.get(pmContMscTech.getOrderNo()).add(pmContMscTech.getMscLineNo());
                    contMscTechMap.put(pmContMscTech.getOrderNo(), pmContMscTech);
                }
            }
        });

        List<Long> userId = new ArrayList<>();
        for (PmProCont pmProCont : pmProConts) {
            if (pmProCont.getCreatedBy() != null) {
                userId.add(pmProCont.getCreatedBy());
            }
        }
        // 获取合约欠量
        List<CtMainVO> ctMainVOList = pmProContRepository.queryOrderRemNumByOrderNoList(orderNoList, pmProContRequest.getTenantId());
        Map<String, BigDecimal> contractNuMap = new HashMap<>(ctMainVOList.size());
        if (CollectionUtils.isNotEmpty(ctMainVOList)) {
            contractNuMap = ctMainVOList.stream().collect(Collectors.toMap(CtMainVO::getContractOrder, CtMainVO::getContractNum));
        }

        List<PmProContResposeDTO> content = new ArrayList<>();
        Map<Long, MtUserInfo> userMap = userClient.userInfoBatchGet(pmProContRequest.getTenantId(), userId);
        
        Map<String , String> lovMeaning = Utils.getLovMeaning(lovAdapter, pmProContRequest.getTenantId()
                , "PM.YES_NO" , "IIOT.YES_NO" , "XISC.TP_CONTRACT_TYPE" , "XISC.WHETHER_FLAG_01" 
                , "QD.TO_NEED_LECQUERING" ,"PM.AD_TYPE_CODE");
        
        for (PmProCont pmProCont : pmProConts) {
            CtMainVO ctMainVO = cmCtMainMap.get(pmProCont.getOrderNo());
            PmProContResposeDTO contResposeDTO = new PmProContResposeDTO();
            BeanCopier.create(PmProCont.class, PmProContResposeDTO.class, false).copy(pmProCont, contResposeDTO, null);
            contResposeDTO.setRecCreateTime(pmProCont.getCreationDate());
            contResposeDTO.setPdOverDevoQty(pmProCont.getPdOverDevoQty());
            if (userMap != null && userMap.containsKey(pmProCont.getCreatedBy())) {
                MtUserInfo mtUserInfo = userMap.get(pmProCont.getCreatedBy());
                if (mtUserInfo != null) {
                    contResposeDTO.setRecCreator(mtUserInfo.getLoginName() + mtUserInfo.getRealName());
                }
            }
            PmProContProdTtr pmProContProdTtr = pmProContProdTtrMap.get(pmProCont.getOrderNo());
            if (null != pmProContProdTtr) {
                BeanCopier.create(PmProContProdTtr.class, PmProContResposeDTO.class, false).copy(pmProContProdTtr,
                        contResposeDTO, null);
                contResposeDTO.setUnitWtAim(pmProContProdTtr.getOrderUnitAimWt());
                contResposeDTO.setLenAim(pmProContProdTtr.getOrderLen());
            }
            PmContMscTech pmContMscTech = contMscTechMap.get(pmProCont.getOrderNo());
            if (null != pmContMscTech) {
                BeanCopier.create(PmContMscTech.class, PmProContResposeDTO.class, false).copy(pmContMscTech,
                        contResposeDTO, null);
//                if(pmContMscTech.getCompressMin() != null && pmProContProdTtr != null && pmProContProdTtr.getOrderThick() != null) {
//                    contResposeDTO.setMinThick(pmProContProdTtr.getOrderThick().multiply(pmContMscTech.getCompressMin()));
//                }
                contResposeDTO.setMinThick(pmContMscTech.getSlabThkMin());
                contResposeDTO.setMscLineNo(String.join(",", mscLineNo.get(pmContMscTech.getOrderNo())));
                contResposeDTO.setWholeHeatTreatmentType(pmContMscTech.getWholeHeatTreatmentType());
            }
            if(ctMainVO != null) {
                contResposeDTO.setOrdRemNum(ctMainVO.getOrdRemNum());
                contResposeDTO.setStockNum(ctMainVO.getStockNum());
                contResposeDTO.setUserdBoardNum(ctMainVO.getUserdBoardNum());
            }
            contResposeDTO.setCotractNum(contractNuMap.getOrDefault(pmProCont.getOrderNo().substring(0, 8), null));
            
            Utils.setMeaning(lovMeaning , "PM.AD_TYPE_CODE", contResposeDTO, contResposeDTO::setAdTypeCodeName, PmProContResposeDTO::getAdTypeCode);
            Utils.setMeaning(lovMeaning , "QD.TO_NEED_LECQUERING", contResposeDTO, contResposeDTO::setNeedLecqueringName, PmProContResposeDTO::getNeedLecquering);
            Utils.setMeaning(lovMeaning , "XISC.WHETHER_FLAG_01", contResposeDTO, contResposeDTO::setSectionManageName, PmProContResposeDTO::getSectionManage);
            Utils.setMeaning(lovMeaning , "XISC.TP_CONTRACT_TYPE", contResposeDTO, contResposeDTO::setOrderTypeCodeName, PmProContResposeDTO::getOrderTypeCode);
            Utils.setMeaning(lovMeaning , "IIOT.YES_NO", contResposeDTO, contResposeDTO::setDiFlagName, PmProContResposeDTO::getDiFlag);
            Utils.setMeaning(lovMeaning , "PM.YES_NO", contResposeDTO, contResposeDTO::setPdHoldFlagName, PmProContResposeDTO::getPdHoldFlag);
            content.add(contResposeDTO);
        }
        return new Page<>(content, new PageInfo(pageRequest.getPage(), pageRequest.getSize()), pmProConts.getTotalElements());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<PmDeleteFailureDTO> delete(PmProContPoolRequestDTO pmProContPoolRequest) {
        List<PmDeleteFailureDTO> deleteFailureList = new ArrayList<>();
        if (null == pmProContPoolRequest || pmProContPoolRequest.getOrderNoList() == null
                || pmProContPoolRequest.getOrderNoList().isEmpty()) {
            // 参数订单编号为空!
            throw new CommonException("pm.pm_pro_cont_001");
        }
        List<ProContPoolDTO> proContPoolDTOs = new ArrayList<>();
        long allCount = pmProContPoolRequest.getOrderNoList().size();
        long limit = (allCount + PmPlateConstants.BATCH_MAX_SIZE - 1) / PmPlateConstants.BATCH_MAX_SIZE;
        Stream.iterate(0, n -> n + 1).limit(limit).forEach(i -> {
            // 分拆多个子sheet
            List<String> splitOrderNoList =  pmProContPoolRequest.getOrderNoList().stream().skip(i * PmPlateConstants.BATCH_MAX_SIZE)
                    .limit(PmPlateConstants.BATCH_MAX_SIZE)
                    .collect(Collectors.toList());
            Set<String> commandOrderSet = new HashSet<String>(16);
            // 通过合同编码查询生产合同数据
            List<PmProCont> pmProConts = this.pmProContRepository.queryByOrderNoList(splitOrderNoList,
                    pmProContPoolRequest.getTenantId());
            if (null == pmProConts || pmProConts.isEmpty()) {
                // 订单编号不存在
                throw new CommonException("pm.pm_pro_cont_002");
            }
            List<PmPdContSum> pmPdContSums = pmPdContSumRepository
                    .selectByOrderNoList(splitOrderNoList, pmProContPoolRequest.getTenantId());
    
            for (PmPdContSum pmPdContSum : pmPdContSums) {
                if (PdMatType.C.getCode().equals(pmPdContSum.getPdMatType()) && pmPdContSum.getPdStatus() != null
                        && pmPdContSum.getPdStatus()
                                .compareTo(PdMatStatus.MATERIAL_PRODUCED.getCode()) < 0) {
                    commandOrderSet.add(pmPdContSum.getOrderNo());
                }
                if (PdMatType.S.getCode().equals(pmPdContSum.getPdMatType())
                        || PdMatType.P.getCode().equals(pmPdContSum.getPdMatType())) {
                    if (pmPdContSum.getPdStatus() != null
                            && pmPdContSum.getPdStatus().compareTo(PdMatStatus.COMMAND_CREATED.getCode()) < 0) {
                        commandOrderSet.add(pmPdContSum.getOrderNo());
                    }
                }
            }
//            if (!commandOrderSet.isEmpty()) {
//                // 合同【{0}】还有材料未到四大命令下发状态，不能退池!
//                throw new CommonException("pm.pm_pro_cont_008", String.join(",", checkFailSet));
//            }
            List<PmPdRecDTO> pmPdRecs = new ArrayList<>();
            
            List<PmProCont> deletePmProConts = new ArrayList<>();
            List<String> deleteOrderNoList = new ArrayList<>();
            
            for (PmProCont pmProCont : pmProConts) {
                if(commandOrderSet.contains(pmProCont.getOrderNo())) {
                    PmDeleteFailureDTO pmDeleteFailure = new PmDeleteFailureDTO();
                    pmDeleteFailure.setOrderNo(pmProCont.getOrderNo());
                    pmDeleteFailure.setErrorMsg("还有材料未到四大命令下发状态，不能退池!");
                    deleteFailureList.add(pmDeleteFailure);
                    continue;
                }
                if (pmProCont.getPdLackQty() != null && pmProCont.getPdLackQty().compareTo(BigDecimal.ZERO) <= 0) {
                    PmDeleteFailureDTO pmDeleteFailure = new PmDeleteFailureDTO();
                    pmDeleteFailure.setOrderNo(pmProCont.getOrderNo());
                    pmDeleteFailure.setErrorMsg("合同欠件数或欠量为0，不能退池!");
                    deleteFailureList.add(pmDeleteFailure);
                    continue;
                }
                if (pmProCont.getPdLackWt() != null && pmProCont.getPdLackWt().compareTo(BigDecimal.ZERO) <= 0) {
                    PmDeleteFailureDTO pmDeleteFailure = new PmDeleteFailureDTO();
                    pmDeleteFailure.setOrderNo(pmProCont.getOrderNo());
                    pmDeleteFailure.setErrorMsg("合同欠件数或欠量为0，不能退池!");
                    deleteFailureList.add(pmDeleteFailure);
                    continue;
                }
                PmPdRecDTO pmPdRecDTO = new PmPdRecDTO();
                pmPdRecDTO.setOrderNo(pmProCont.getOrderNo());
                pmPdRecDTO.setQty(pmProCont.getPdLackQty());
                pmPdRecDTO.setWt(pmProCont.getPdLackWt());
                pmPdRecs.add(pmPdRecDTO);
                proContPoolDTOs.add(new ProContPoolDTO(pmProCont.getOrderNo(), pmProCont.getPdLackQty(), pmProCont.getPdLackWt()));
                deletePmProConts.add(pmProCont);
                deleteOrderNoList.add(pmProCont.getOrderNo());
            }
//            if (!checkFailSet.isEmpty()) {
//                // 合同号【{0}】的合同欠件数或欠量为0，不能退池
//                throw new CommonException("pm.pm_pro_cont_007", String.join(",", checkFailSet));
//            }
        
            // 4、 调用组板履历函数，抛组板履历事件
            if(!deletePmProConts.isEmpty()) {
                pmPdRecService.createEvent(pmProContPoolRequest.getTenantId(), pmPdRecs , PdEventType.HP02, Constants.SYSTEM_CODE, Constants.PdProgram.ORDER_POOL_DEL_PROGRAM);
                // 删除 生产合同主表PM_PRO_CONT
                this.pmProContRepository.batchDeleteByPrimaryKey(deletePmProConts);
                // 生产合同产品属性表PM_PRO_CONT_PROD_ATTR
                this.pmProContProdTtrRepository.deleteByOrderNoList(deleteOrderNoList,
                        pmProContPoolRequest.getTenantId());
                // 合同产线工艺参数表PM_CONT_MSC_TECH的相关记录
                this.pmContMscTechRepository.deleteByOrderNoList(deleteOrderNoList,
                        pmProContPoolRequest.getTenantId());
            }
        });
        // 调用合同跟踪api，抛“生产合同退池”事件
        if(!proContPoolDTOs.isEmpty()) {
            eventClient.sendEvent(pmProContPoolRequest.getTenantId(), CtEventConstants.EVENT_PM_CONTRACT_BOARD_REC_CANCEL, proContPoolDTOs, String.class);
        }
        return deleteFailureList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void hold(PmProContPoolRequestDTO pmProContPoolRequest) {
        if (null == pmProContPoolRequest || StringUtils.isBlank(pmProContPoolRequest.getOrderNo())) {
            // 参数订单编号为空!
            throw new CommonException("pm.pm_pro_cont_001");
        }
        PmProCont pmProCont = this.pmProContRepository.queryByOrderNo(pmProContPoolRequest.getOrderNo(),
                pmProContPoolRequest.getTenantId());
        if (null == pmProCont) {
            // 订单编号不存在
            throw new CommonException("pm.pm_pro_cont_002");
        }
        if (pmProCont.getOnPdFlag() != null
                && BaseConstants.Flag.YES.intValue() == pmProCont.getOnPdFlag().intValue()) {
            // 合同组板中，不能合同封锁！
            throw new CommonException("pm.pm_pro_cont_004");
        }
        if (pmProCont.getPdHoldFlag() != null
                && BaseConstants.Flag.YES.intValue() == pmProCont.getPdHoldFlag().intValue()) {
            // 合同已封锁，不必再人工封锁！
            throw new CommonException("pm.pm_pro_cont_006");
        }
        PmProCont record = new PmProCont();
        record.setProContId(pmProCont.getProContId());
        record.setPdHoldFlag(BaseConstants.Flag.YES.longValue());
        record.setHoldMaker(DetailsHelper.getUserDetails().getUserId().toString());
        record.setHoldTime(new Date());
        record.setObjectVersionNumber(pmProCont.getObjectVersionNumber());
        this.pmProContRepository.updateByPrimaryKeySelective(record);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rel(PmProContPoolRequestDTO pmProContPoolRequest) {
        if (null == pmProContPoolRequest || StringUtils.isBlank(pmProContPoolRequest.getOrderNo())) {
            // 参数订单编号为空!
            throw new CommonException("pm.pm_pro_cont_001");
        }
        PmProCont pmProCont = this.pmProContRepository.queryByOrderNo(pmProContPoolRequest.getOrderNo(),
                pmProContPoolRequest.getTenantId());
        if (null == pmProCont) {
            // 订单编号不存在
            throw new CommonException("pm.pm_pro_cont_002");
        }
        if (pmProCont.getOnPdFlag() != null
                && BaseConstants.Flag.YES.intValue() == pmProCont.getOnPdFlag().intValue()) {
            // 合同组板中，不能合同封锁！
            throw new CommonException("pm.pm_pro_cont_004");
        }
        if (pmProCont.getPdHoldFlag() != null
                && BaseConstants.Flag.NO.intValue() == pmProCont.getPdHoldFlag().intValue()) {
            // 合同未封锁，不必释放!
            throw new CommonException("pm.pm_pro_cont_005");
        }
        PmProCont record = new PmProCont();
        record.setProContId(pmProCont.getProContId());
        record.setPdHoldFlag(BaseConstants.Flag.NO.longValue());
        record.setRelMaker(DetailsHelper.getUserDetails().getUserId().toString());
        record.setRelTime(new Date());
        record.setObjectVersionNumber(pmProCont.getObjectVersionNumber());
        this.pmProContRepository.updateByPrimaryKeySelective(record);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pdUnlock(PmProContPoolRequestDTO pmProContPoolRequest) {
        if (null == pmProContPoolRequest || StringUtils.isBlank(pmProContPoolRequest.getOrderNo())) {
            // 参数订单编号为空!
            throw new CommonException("pm.pm_pro_cont_001");
        }
        PmProCont pmProCont = this.pmProContRepository.queryByOrderNo(pmProContPoolRequest.getOrderNo(),
                pmProContPoolRequest.getTenantId());
        if (null == pmProCont) {
            // 订单编号不存在
            throw new CommonException("pm.pm_pro_cont_002");
        }
        if (pmProCont.getOnPdFlag() != null && BaseConstants.Flag.NO.intValue() == pmProCont.getOnPdFlag().intValue()) {
            // 合同不在组板中，不用组板释放！
            throw new CommonException("pm.pm_pro_cont_003");
        }

        PmProCont record = new PmProCont();
        record.setProContId(pmProCont.getProContId());
        record.setOnPdFlag(BaseConstants.Flag.YES.longValue());
        record.setObjectVersionNumber(pmProCont.getObjectVersionNumber());
        // 更新为组板中
        this.pmProContRepository.updateByPrimaryKeySelective(record);
        
        List<PmPdRecDTO> pmPdRecs = new ArrayList<>();
        CustomUserDetails userDetails = DetailsHelper.getUserDetails();
        PmPdRecDTO pmPdRecDTO = new PmPdRecDTO();
        pmPdRecDTO.setOrderNo(pmProCont.getOrderNo());
        pmPdRecDTO.setEventMaker(userDetails == null ? "": userDetails.getUserId().toString());
        pmPdRecDTO.setQty(pmProCont.getPdLackQty());
        pmPdRecs.add(pmPdRecDTO);
        pmPdRecService.createEvent(pmProContPoolRequest.getTenantId(), pmPdRecs 
                , PdEventType.HP05, Constants.SYSTEM_PD_CODE, Constants.PdProgram.ORDER_POOL_UNLOCK_PROGRAM);
    }

    @Override
    public Map<String, List<PmProContFilterResposeDTO>> contFilterList(PmProContFilterRequestDTO pmProContFilterRequest) {
        // 初始化返回结构Map
        Map<String, List<PmProContFilterResposeDTO>> result = new HashMap<>();
        result.put(PmPlateConstants.SELECTED_FLAG, new ArrayList<>());
        result.put(PmPlateConstants.UN_SELECTED_FLAG, new ArrayList<>());
        PdMatTypeStrategy pdMatTypeStrategy = PdMatTypeStrategyFactory.matchStrategy(pmProContFilterRequest.getMatDesignKind());
        pdMatTypeStrategy.contFilterInitParam(pmProContFilterRequest);
        pmProContFilterRequest.setJoinCtMainFlag(BaseConstants.Flag.YES.longValue());
        
        List<PmProContFilterResposeDTO> filterList = pmProContRepository.orderFilterList(pmProContFilterRequest);
        pmProContFilterRequest.setOrderNoList(new ArrayList<>());
        List<String> orderNoList = new ArrayList<>();
        for (PmProContFilterResposeDTO pmProContFilterResposeDTO : filterList) {
            pmProContFilterRequest.getOrderNoList().add(pmProContFilterResposeDTO.getOrderNo());
            orderNoList.add(pmProContFilterResposeDTO.getOrderNo());
        }

        // 获取合约欠量
        List<CtMainVO> ctMainVOList = pmProContRepository.queryOrderRemNumByOrderNoList(orderNoList, pmProContFilterRequest.getTenantId());
        Map<String, CtMainVO> contractNuMap = new HashMap<>(ctMainVOList.size());
        if (CollectionUtils.isNotEmpty(ctMainVOList)) {
            contractNuMap = ctMainVOList.stream().collect(Collectors.toMap(CtMainVO::getContractOrder, Function.identity()));
        }

        // 调用合同跟踪模块“合同跟踪合同查询”接口 获取状态和合同跟踪欠件
        Map<String , CtMainVO> cmCtMainMap = new HashMap<>();
        long allCount = pmProContFilterRequest.getOrderNoList().size();
        long limit = (allCount + PmPlateConstants.BATCH_MAX_SIZE - 1) / PmPlateConstants.BATCH_MAX_SIZE;
        Stream.iterate(0, n -> n + 1).limit(limit).forEach(i -> {
            // 分拆多个子sheet
            List<String> splitOrderNoList =  pmProContFilterRequest.getOrderNoList().stream().skip(i * PmPlateConstants.BATCH_MAX_SIZE)
                    .limit(PmPlateConstants.BATCH_MAX_SIZE)
                    .collect(Collectors.toList());
            PmProContFilterRequestDTO pmProContFilterRequestQurey = BeanUtils.copy(pmProContFilterRequest, PmProContFilterRequestDTO.class);
            pmProContFilterRequestQurey.setOrderNoList(splitOrderNoList);
            List<CtMainVO> cmCtMainVOs = pmCtMainRepository.selectCanPdByOrderStatus(pmProContFilterRequestQurey);
            for (CtMainVO ctMainVO : cmCtMainVOs) {
                cmCtMainMap.put(ctMainVO.getOrderNo(), ctMainVO);
            }
        });
        
        if(pmProContFilterRequest.getOrderNoList().isEmpty()) {
            return result;
        }

        // 获取连铸板坯生产规格基准表数据
        String rollLineNo = pmProContFilterRequest.getMscLineNo()
                .substring(pmProContFilterRequest.getMscLineNo().length() - 2);

        // 连铸板坯生产规格基准表
        List<PmSlabSpecBt> pmSlabSpecBts = pmSlabSpecBtRepository.selectByLineNoAndCcType(
                pmProContFilterRequest.getTenantId(), rollLineNo, pmProContFilterRequest.getCcType(),
                PmSlabSpecBt.FIELD_SLAB_THICK_TO);

        for (PmProContFilterResposeDTO pmProContFilterResposeDTO : filterList) {
            CtMainVO ctMainVO = cmCtMainMap.get(pmProContFilterResposeDTO.getOrderNo());
            pmProContFilterResposeDTO.setOrdRemNum(ctMainVO == null ? pmProContFilterResposeDTO.getPdLackQty() : ctMainVO.getOrdRemNum());
            pmProContFilterResposeDTO.setStockNum(ctMainVO == null ? BigDecimal.ZERO : ctMainVO.getStockNum());
            pmProContFilterResposeDTO.setUserdBoardNum(ctMainVO == null ? BigDecimal.ZERO :ctMainVO.getUserdBoardNum());
            // 合约欠量和合约尾量
            if (contractNuMap.containsKey(pmProContFilterResposeDTO.getOrderNo().substring(0, 8))) {
                CtMainVO ctMainContract = contractNuMap.get(pmProContFilterResposeDTO.getOrderNo().substring(0, 8));
                pmProContFilterResposeDTO.setCotractNum(ctMainContract.getContractNum());
                pmProContFilterResposeDTO.setContWl(ctMainContract.getContractNum().subtract(ctMainContract.getShipEndNum()));
            }
            if(!pdMatTypeStrategy.contPublicConditionsCheck(pmProContFilterResposeDTO, pmProContFilterRequest.getTenantId())) {
                // 如果没有通过公共条件函数检查，添加到未选中列表中！
                result.get(PmPlateConstants.UN_SELECTED_FLAG).add(pmProContFilterResposeDTO);
                continue;
            }

            // 调用规则集，筛选合同
            if(!pdMatTypeStrategy.contFilterRuleSetCheck(pmProContFilterRequest, pmProContFilterResposeDTO, pmSlabSpecBts, cmCtMainMap)) {
                // 未通过规则集校验，添加到未选中列表中！
                result.get(PmPlateConstants.UN_SELECTED_FLAG).add(pmProContFilterResposeDTO);
                continue;
            }
            result.get(PmPlateConstants.SELECTED_FLAG).add(pmProContFilterResposeDTO);
        }
        // 排序
        if (CollectionUtils.isNotEmpty(result.get(PmPlateConstants.SELECTED_FLAG))) {
            result.put(PmPlateConstants.SELECTED_FLAG, result.get(PmPlateConstants.SELECTED_FLAG).stream()
                    .sorted(Comparator.comparing(PmProContFilterResposeDTO::getOrderThick)
                            .thenComparing(PmProContFilterResposeDTO::getOrderWidth)
                            .thenComparing(PmProContFilterResposeDTO::getLenAim))
                    .collect(Collectors.toList()));
        }
        if (CollectionUtils.isNotEmpty(result.get(PmPlateConstants.UN_SELECTED_FLAG))) {
            result.put(PmPlateConstants.UN_SELECTED_FLAG, result.get(PmPlateConstants.UN_SELECTED_FLAG).stream()
                    .sorted(Comparator.comparing(PmProContFilterResposeDTO::getOrderThick)
                            .thenComparing(PmProContFilterResposeDTO::getOrderWidth)
                            .thenComparing(PmProContFilterResposeDTO::getLenAim))
                    .collect(Collectors.toList()));
        }
        return result;
    }

    @Override
    public List<PmProContSelectionDTO> contSelection(PmProContSelectionRequestDTO pmProContSelection) {
        if (pmProContSelection == null || pmProContSelection.getPmContFilterRequest() == null) {
            throw new CommonException("pm.pm_pro_cont_009");
        }
        pmProContSelection.check();
        
        PdMatTypeStrategy pdMatTypeStrategy = PdMatTypeStrategyFactory.matchStrategy(pmProContSelection.getPmContFilterRequest().getMatDesignKind());
        
        List<String> orderNoList = new ArrayList<>();
        List<String> allOrderNoList = new ArrayList<>();
        // 是否需要进行C03校验标记
        for (PmProContSelectionDTO pmProContSelectionDTO : pmProContSelection.getContSelectionList()) {
            if (pmProContSelectionDTO.getAxisFlag()
                    && !pmProContSelection.getAxisOrderNo().equals(pmProContSelectionDTO.getOrderNo())) {
                throw new CommonException("pm.pm_pro_cont_014", pmProContSelectionDTO.getAxisFlag().toString(),
                        pmProContSelection.getAxisOrderNo());
            }
            if (pmProContSelectionDTO.getSelectFlag() || pmProContSelectionDTO.getAxisFlag()) {
                pmProContSelectionDTO.setSelectFlag(true);
                orderNoList.add(pmProContSelectionDTO.getOrderNo());
            }
            allOrderNoList.add(pmProContSelectionDTO.getOrderNo());
        }
        
//        List<QdToLineupResultHeattreatVO> heattreatVOs = pmQdToLineupResultHeattreatRepository.selectByOrderListAndMscLineNo(allOrderNoList, pmProContSelection.getPmContFilterRequest().getMscLineNo());
//        Map<String , QdToLineupResultHeattreatVO> heattreatVOMaps = Maps.uniqueIndex(heattreatVOs, QdToLineupResultHeattreatVO::getOrderNo);

        if (pmProContSelection.getAxisOrderNo().equals(pmProContSelection.getCurrentOrderNo())) {
            // 获取合同号对应的见证点项目
            Map<String, String> orderWithnessProNoMap = queryQdWitnessProNo(allOrderNoList, pmProContSelection.getTenantId());
            // 查询选中的合同信息
            Map<String, PmProContFilterResposeDTO> filterOrderMap = pmProContRepository.orderFilterMap(allOrderNoList,
                    pmProContSelection.getTenantId(), pmProContSelection.getPmContFilterRequest().getMscLineNo());
            // 如果勾选的是轴合同，进行C03校验-默认C03
            RuleParamDTO ruleParamDTO = pdMatTypeStrategy.contSelectionRuleSet();
            if(ruleParamDTO == null) {
                return pmProContSelection.getContSelectionList();
            }
            ruleParamDTO.buildExcludeRuleNo(pmProContSelection.getPmContFilterRequest());
            Map<String, Object> bizData = new HashMap<>();
            ruleParamDTO.setBizData(bizData);
            ruleParamDTO.setTenantId(pmProContSelection.getTenantId());
            for (PmProContSelectionDTO pmProContSelectionDTO : pmProContSelection.getContSelectionList()) {
                if (pmProContSelectionDTO.getAxisFlag()) {
                    // 如果是轴合同，不需要进行校验
                    pmProContSelectionDTO.setCheckFlag(true);
                    continue;
                }
                bizData.put(RuleSetConstants.WITNESS_PRO_NO, orderWithnessProNoMap.getOrDefault(pmProContSelectionDTO.getOrderNo(), null));
                bizData.put(RuleSetConstants.WITNESS_PRO_NO_AXIS, orderWithnessProNoMap.getOrDefault(pmProContSelection.getAxisOrderNo(), null));
                bizData.put(RuleSetConstants.FORM_PLATE_MODE, pmProContSelection.getPmContFilterRequest().getFormPlateMode());
                bizData.put(RuleSetConstants.ORDER_NO, pmProContSelectionDTO.getOrderNo());
                bizData.put(RuleSetConstants.TENANT_ID, pmProContSelection.getTenantId());
                bizData.put(RuleSetConstants.MSC_LINE_NO, pmProContSelection.getPmContFilterRequest().getMscLineNo());
                bizData.put(RuleSetConstants.PM_PRO_CONT_PROD_ATTR,
                        BeanUtils.copy(filterOrderMap.get(pmProContSelectionDTO.getOrderNo()), new PmProContProdTtr()));
                bizData.put(RuleSetConstants.AXIS_PM_PRO_CONT_PROD_ATTR,
                        BeanUtils.copy(filterOrderMap.get(pmProContSelection.getAxisOrderNo()), new PmProContProdTtr()));
                bizData.put(RuleSetConstants.PM_CONT_MSC_TECH,
                        BeanUtils.copy(filterOrderMap.get(pmProContSelectionDTO.getOrderNo()), new PmContMscTech()));
                bizData.put(RuleSetConstants.AXIS_PM_CONT_MSC_TECH,
                        BeanUtils.copy(filterOrderMap.get(pmProContSelection.getAxisOrderNo()), new PmContMscTech()));
//                bizData.put(RuleSetConstants.HEAT_TREATMENT, heattreatVOMaps.get(pmProContSelectionDTO.getOrderNo()));
//                bizData.put(RuleSetConstants.AXIS_HEAT_TREATMENT, heattreatVOMaps.get(pmProContSelection.getAxisOrderNo()));
                try {
                    pmPdRuleSetService.runRuleSet(ruleParamDTO);
                    pmProContSelectionDTO.setCheckFlag(true);
                } catch (CommonException e) {
                    pmProContSelectionDTO.setCheckFlag(false);
                    Message message = MessageAccessor.getMessage(e.getCode(), e.getParameters());
                    pmProContSelectionDTO.setCheckMsg(message.getDesc());
                }
            }
        } else {
            // 查询选中的合同信息
            Map<String, PmProContFilterResposeDTO> filterOrderMap = pmProContRepository.orderFilterMap(orderNoList,
                    pmProContSelection.getTenantId(), pmProContSelection.getPmContFilterRequest().getMscLineNo());
            PmProContProdTtr axisPmProContProdTtr = BeanUtils.copy(filterOrderMap.get(pmProContSelection.getAxisOrderNo()),
                    new PmProContProdTtr());

            String rollLineNo = Utils.mscLineNoToRoolLineNo(pmProContSelection.getPmContFilterRequest().getMscLineNo());
            PmMinThickTolBt pmMinThickTolBt = pmMinThickTolBtRepository.selectByRollLineNoAndAxisOrderThick(
                    pmProContSelection.getTenantId(), rollLineNo, axisPmProContProdTtr.getOrderThick());
            // 否则进行C04校验
            RuleParamDTO ruleParamDTO = pdMatTypeStrategy.contSelectionCheckRuleSet();
            if(ruleParamDTO == null) {
                return pmProContSelection.getContSelectionList();
            }
            ruleParamDTO.buildExcludeRuleNo(pmProContSelection.getPmContFilterRequest());
            ruleParamDTO.setTenantId(pmProContSelection.getTenantId());
            Map<String, Object> bizData = new HashMap<>();
            ruleParamDTO.setBizData(bizData);
            bizData.put(RuleSetConstants.ORDER_NO, pmProContSelection.getCurrentOrderNo());
            bizData.put(RuleSetConstants.FORM_PLATE_MODE, pmProContSelection.getPmContFilterRequest().getFormPlateMode());
            bizData.put(RuleSetConstants.TENANT_ID, pmProContSelection.getTenantId());
            bizData.put(RuleSetConstants.PM_MIN_THICK_TOL_BT, pmMinThickTolBt);
            bizData.put(RuleSetConstants.AXIS_PM_PRO_CONT_PROD_ATTR, axisPmProContProdTtr);
            bizData.put(RuleSetConstants.MSC_LINE_NO, pmProContSelection.getPmContFilterRequest().getMscLineNo());
            // 非轴合同列表
            List<PmProContProdTtr> pmProContProdTtrs = new ArrayList<>();
            bizData.put(RuleSetConstants.PM_PRO_CONT_PROD_ATTR_LIST, pmProContProdTtrs);
            for (String orderNo : orderNoList) {
                PmProContProdTtr pmProContProdTtr = BeanUtils.copy(filterOrderMap.get(orderNo), new PmProContProdTtr());
                pmProContProdTtrs.add(pmProContProdTtr);
            }
            Optional<PmProContProdTtr> first = pmProContProdTtrs.stream().filter(item -> item.getOrderNo().equals(pmProContSelection.getCurrentOrderNo())).findFirst();
            if (first.isPresent()) {
                bizData.put(RuleSetConstants.PM_PRO_CONT_PROD_ATTR, first.get());
            }
            pmPdRuleSetService.runRuleSet(ruleParamDTO);
        }
        return pmProContSelection.getContSelectionList();
    }

    private Map<String, String> queryQdWitnessProNo(List<String> allOrderNoList, Long tenantId) {
        List<QeTjWitnessProOrderVO> qeTjWitnessProOrderVOList = pmCtMainRepository.queryQdWitnessProNo(allOrderNoList, tenantId);
        if (CollectionUtils.isEmpty(qeTjWitnessProOrderVOList)) {
            return new HashMap<>(0);
        }
        Map<String, String> resultMap =  qeTjWitnessProOrderVOList.stream().collect(Collectors
                .toMap(QeTjWitnessProOrderVO::getOrderNo, QeTjWitnessProOrderVO::getWitnessProNo, (v1, v2) -> v1));
        return resultMap;
    }

    @Override
    public PmProContYieldResposeDTO contYieldCalc(PmProContYieldRequestDTO pmProContYield) {
        return this.self().yiledCalcAndExec(pmProContYield, false);
    }

    @Override
    public PmProContYieldResposeDTO contYieldExec(PmProContYieldRequestDTO pmProContYield) {
        String bizId = null;
        if(StringUtils.isNotBlank(pmProContYield.getVirtualSlabNo())) {
            bizId = pmProContYield.getVirtualSlabNo();
        } else if(pmProContYield.getPmContFilterRequest().getPlateId() != null) {
            bizId = pmProContYield.getPmContFilterRequest().getPlateId().toString();
        } else if(pmProContYield.getPmPdSlab() != null) {
            bizId = pmProContYield.getPmPdSlab().getSlabNo();
        } else {
            bizId = UUID.randomUUID().toString();
        }
        String key = String.format(PmPlateConstants.YIELD_EXEC_LOCK_KEY, pmProContYield.getTenantId().toString() , bizId);
        if(redisHelper.hasKey(key)) {
            throw new CommonException("pm.pm_pro_cont_043", pmProContYield.getVirtualSlabNo());
        }
        List<PmPdRecDTO> pmPdRecs = new ArrayList<>();
        CustomUserDetails userDetails = DetailsHelper.getUserDetails();
        for (PmProContYieldDTO contYieldDTO : pmProContYield.getPmProContYieldList()) {
            PmPdRecDTO pmPdRecDTO = new PmPdRecDTO();
            pmPdRecDTO.setOrderNo(contYieldDTO.getOrderNo());
            pmPdRecDTO.setEventMaker(userDetails == null ? "": userDetails.getUserId().toString());
            pmPdRecDTO.setMscLineNo(pmProContYield.getPmContFilterRequest().getMscLineNo());
            pmPdRecDTO.setKeyvalue1Desc(PmPdRecDTO.DESC_VIRTUAL_SLAB_NO);
            pmPdRecDTO.setKeyvalue1(pmProContYield.getVirtualSlabNo());
            pmPdRecDTO.setMatNo(pmProContYield.getVirtualSlabNo());
            pmPdRecDTO.setQty(BigDecimal.ZERO);
            pmPdRecs.add(pmPdRecDTO);
        }
        PdMatTypeStrategy pdMatTypeStrategy = PdMatTypeStrategyFactory.matchStrategy(pmProContYield.getPmContFilterRequest().getMatDesignKind());
        try {
            // 抛合同组板事件
            pmPdRecService.createEvent(pmProContYield.getTenantId(), pmPdRecs 
                    , PdEventType.HP04, Constants.SYSTEM_PD_CODE, pdMatTypeStrategy.pdProgram());
            redisHelper.strSet(key, "1", 30L, TimeUnit.SECONDS);
            return this.self().yiledCalcAndExec(pmProContYield, true);
        } finally {
            // 抛合同组板释放事件
            pmPdRecService.createEvent(pmProContYield.getTenantId(), pmPdRecs 
                    , PdEventType.HP05, Constants.SYSTEM_PD_CODE, pdMatTypeStrategy.pdProgram());
            redisHelper.delKey(key);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<PmPdCcSlab> contYieldCopy(PmProContYieldCopyRequestDTO pmProContYieldCopy) {
        if(StringUtils.isBlank(pmProContYieldCopy.getVirtualSlabNo())) {
            throw new CommonException("pm.pm_pro_cont_039");
        }
        String key = String.format(PmPlateConstants.YIELD_EXEC_LOCK_KEY, pmProContYieldCopy.getTenantId().toString() , pmProContYieldCopy.getVirtualSlabNo());
        if(redisHelper.hasKey(key)) {
            throw new CommonException("pm.pm_pro_cont_043", pmProContYieldCopy.getVirtualSlabNo());
        }
        try {
            redisHelper.strSet(key, "1", 30L, TimeUnit.SECONDS);
            pmPdCcSlabService.copyPmPdCcSlab(pmProContYieldCopy);
        } finally {
            redisHelper.delKey(key);
        }
        return null;
    }
    
    /**
     * 收得率计算与执行
     * @param pmProContYield
     * @param needCreatePmPdCcSlab
     * @return
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @Transactional(rollbackFor = Exception.class)
    public PmProContYieldResposeDTO yiledCalcAndExec(PmProContYieldRequestDTO pmProContYield , Boolean needCreatePmPdCcSlab) {
        pmProContYield.check();
        PdMatTypeStrategy pdMatTypeStrategy = PdMatTypeStrategyFactory.matchStrategy(pmProContYield.getPmContFilterRequest().getMatDesignKind());
        // 执行前检查
        pdMatTypeStrategy.yiledCalcBeforeCheck(pmProContYield , needCreatePmPdCcSlab);
        
        List<String> orderNoList = new ArrayList<>();
        for (PmProContYieldDTO pmProContYieldDTO : pmProContYield.getPmProContYieldList()) {
            orderNoList.add(pmProContYieldDTO.getOrderNo());
        }
        Map<String, PmProContFilterResposeDTO> filterOrderMap = pmProContRepository.orderFilterMap(orderNoList,
                pmProContYield.getTenantId(), pmProContYield.getPmContFilterRequest().getMscLineNo());
        // 查询在库量
        PmProContFilterRequestDTO pmContFilterRequest = new PmProContFilterRequestDTO();
        pmContFilterRequest.setTenantId(pmProContYield.getTenantId());
        pmContFilterRequest.setOrderNoList(orderNoList);
        List<CtMainVO> cmCtMainVOs = pmCtMainRepository.selectCanPdByOrderStatus(pmContFilterRequest);
        if(cmCtMainVOs != null) {
            for (CtMainVO ctMainVO : cmCtMainVOs) {
                PmProContFilterResposeDTO pmProContFilterRespose = filterOrderMap.get(ctMainVO.getOrderNo());
                if(pmProContFilterRespose != null) {
                    pmProContFilterRespose.setStockNum(ctMainVO.getStockNum());
                    pmProContFilterRespose.setUserdBoardNum(ctMainVO.getUserdBoardNum());
                }
            }
        }
        
        PmProContFilterResposeDTO axisContInfo = filterOrderMap.get(pmProContYield.getAxisOrderNo());
        PmProContProdTtr axisPmProContProdTtr = new PmProContProdTtr();
        PmContMscTech axisPmContMscTech = new PmContMscTech();
        if(axisContInfo == null) {
            throw new CommonException("pm.pm_pd_rule_set_001", pmProContYield.getAxisOrderNo(), pmProContYield.getPmContFilterRequest().getMscLineNo());
        }
        BeanCopier.create(PmProContFilterResposeDTO.class, PmProContProdTtr.class, false).copy(axisContInfo,
                axisPmProContProdTtr, null);
        BeanCopier.create(PmProContFilterResposeDTO.class, PmContMscTech.class, false).copy(axisContInfo,
                axisPmContMscTech, null);

        PmProContYieldResposeDTO pmProContYieldRespose = null;
        // 初始化校验与初始化参数
        PmCompositeSlabCalcDTO pmCompositeSlabCalc = pdMatTypeStrategy.checkAndInitParams(filterOrderMap,
                pmProContYield, axisPmProContProdTtr);
        // 记录大板粗切位置
        pdMatTypeStrategy.plateCut(filterOrderMap, pmProContYield, axisPmProContProdTtr, pmCompositeSlabCalc);
        // 计算送样长度
        pdMatTypeStrategy.calcSampleLen(pmProContYield, axisPmProContProdTtr, pmCompositeSlabCalc);
        // 计算RSCODE
        pdMatTypeStrategy.calcRsCodeAndBroadFlag(pmProContYield, axisPmProContProdTtr, pmCompositeSlabCalc);
        // 计算临时板坯长
        pdMatTypeStrategy.calcLpre(pmProContYield, axisPmProContProdTtr, pmCompositeSlabCalc);
        // 计算收得率
        pmProContYieldRespose = pdMatTypeStrategy.calcYield(filterOrderMap, pmProContYield,
                axisPmProContProdTtr, axisPmContMscTech, pmCompositeSlabCalc);
        if (null == pmProContYieldRespose) {
            throw new CommonException("pm.pm_pro_cont_025");
        }
        try {
            log.debug(String.format("计算结果：%s , %s", objectMapper.writeValueAsString(pmCompositeSlabCalc) , objectMapper.writeValueAsString(pmProContYieldRespose)));
        } catch (JsonProcessingException e) {
            log.error(e.getMessage());
        }
        // 规则集05校验
        executeYieldRuleSet(filterOrderMap, pmProContYield, axisContInfo, axisPmProContProdTtr, axisPmContMscTech, pmProContYieldRespose);

        if(needCreatePmPdCcSlab) {
            pmProContYieldRespose.setVirtualSlabNo(pmProContYield.getVirtualSlabNo());
            // 执行收得率计算
            pdMatTypeStrategy.executePd(pmProContYield, filterOrderMap, pmCompositeSlabCalc, pmProContYieldRespose);
        } else {
            if(StringUtils.isBlank(pmProContYield.getVirtualSlabNo())) {
                String slabNo = codeRuleBuilder.generateCode(pmProContYield.getTenantId(), Constants.CodeRule.VIRTUAL_SLAB_NO,
                        CodeConstants.CodeRuleLevelCode.GLOBAL, Constants.CodeRule.GLOBAL_LEVEL_VALUE, new HashMap<>(1));
                pmProContYieldRespose.setVirtualSlabNo(slabNo);
            } else {
                pmProContYieldRespose.setVirtualSlabNo(pmProContYield.getVirtualSlabNo());
            }
        }
        return pmProContYieldRespose;
    }
    
    /**
     * 规则集C05校验
     * @param filterOrderMap 合同集合
     * @param pmProContYield  收得率请求参数
     * @param axisContInfo    轴合同信息
     * @param axisPmProContProdTtr  轴合同生产属性
     * @param axisPmContMscTech    轴合同生产工艺参数
     * @param pmProContYieldRespose   轴合同收得率计算结果
     */
    private void executeYieldRuleSet(Map<String, PmProContFilterResposeDTO> filterOrderMap,
            PmProContYieldRequestDTO pmProContYield, PmProContFilterResposeDTO axisContInfo,
            PmProContProdTtr axisPmProContProdTtr, PmContMscTech axisPmContMscTech,
            PmProContYieldResposeDTO pmProContYieldRespose) {
        PdMatTypeStrategy pdMatTypeStrategy = PdMatTypeStrategyFactory.matchStrategy(pmProContYield.getPmContFilterRequest().getMatDesignKind());
        
        RuleParamDTO ruleParam = pdMatTypeStrategy.pdResultCheckRuleSet();
        if(ruleParam == null) {
            return ;
        }
        ruleParam.buildExcludeRuleNo(pmProContYield.getPmContFilterRequest());
        ruleParam.setTenantId(pmProContYield.getTenantId());
        Map<String, Object> bizData = new HashMap<>(8);
        bizData.put(RuleSetConstants.ORDER_NO, axisContInfo.getOrderNo());
        bizData.put(RuleSetConstants.ORDER_NO_SET, Lists.newArrayList(filterOrderMap.keySet()));
        bizData.put(RuleSetConstants.MSC_LINE_NO, axisContInfo.getMscLineNo());
        bizData.put(RuleSetConstants.FORM_PLATE_MODE, pmProContYield.getPmContFilterRequest().getFormPlateMode());
        String rollLineNo = pmProContYield.getPmContFilterRequest().getMscLineNo()
                .substring(pmProContYield.getPmContFilterRequest().getMscLineNo().length() - 2);
        bizData.put(RuleSetConstants.ROLL_LINE_NO, rollLineNo);
        bizData.put(RuleSetConstants.AXIS_PM_PRO_CONT_PROD_ATTR, axisPmProContProdTtr);
        bizData.put(RuleSetConstants.AXIS_PM_CONT_MSC_TECH, axisPmContMscTech);
        bizData.put(RuleSetConstants.COMBINE_PLATE_LEN, pmProContYieldRespose.getCombinePlateLen());
        bizData.put(RuleSetConstants.COMBINE_PLATE_WIDTH, pmProContYieldRespose.getCombinePlateWidth());
        bizData.put(RuleSetConstants.LAIM, pmProContYieldRespose.getLaim());
        bizData.put(RuleSetConstants.TAIM, pmProContYieldRespose.getTaim());
        bizData.put(RuleSetConstants.WAIM, pmProContYieldRespose.getWaim());
        bizData.put(RuleSetConstants.ROLL_DIRECT_CODE, pmProContYield.getPmContFilterRequest().getRollDirectCode());
        bizData.put(RuleSetConstants.FUR_TYPE, pmProContYield.getPmContFilterRequest().getFurType());
        bizData.put(RuleSetConstants.MOLD_THICK, pmProContYield.getPmContFilterRequest().getMoldThick());
        bizData.put(RuleSetConstants.MOLD_WIDTH, pmProContYield.getPmContFilterRequest().getMoldWidth());
        bizData.put(RuleSetConstants.CC_TYPE, pmProContYield.getPmContFilterRequest().getCcType());
        bizData.put(RuleSetConstants.MAT_DESIGN_KIND, pmProContYield.getPmContFilterRequest().getMatDesignKind());
        bizData.put(RuleSetConstants.INFUR_SLAB_LEN, pmProContYieldRespose.getInfurSlabLen());
        bizData.put(RuleSetConstants.NEED_SLAB_LEN, pmProContYieldRespose.getNeedSlabLen());
        bizData.put(RuleSetConstants.TENANT_ID, pmProContYield.getTenantId());
        bizData.put(RuleSetConstants.RS_CODE, pmProContYieldRespose.getRsCode());
        bizData.put(RuleSetConstants.TRANS_FLAG, pmProContYield.getPmContFilterRequest().getTransFlag());
        bizData.put(RuleSetConstants.SUM_PLATE_WT, pmProContYieldRespose.getSumPlateWt());
        bizData.put(RuleSetConstants.SUM_PLATE_WT, pmProContYieldRespose.getSumPlateWt());
        bizData.put(RuleSetConstants.INGOT_TYPE, pmProContYield.getPmContFilterRequest().getIngotType());
        bizData.put(RuleSetConstants.ST_NO, pmProContYield.getPmContFilterRequest().getStNo());
        bizData.put(RuleSetConstants.CALC_REQUEST, pmProContYield);
        if (BaseConstants.Flag.YES.toString().equals(pmProContYield.getPmContFilterRequest().getTransFlag())) {
            // 板坯宽度
            bizData.put(RuleSetConstants.MOLD_WIDTH, pmProContYieldRespose.getInfurSlabLen());
            // 进加热炉板坯长度
            bizData.put(RuleSetConstants.INFUR_SLAB_LEN, pmProContYield.getPmContFilterRequest().getMoldWidth());
        } 

        List<PmProContProdTtr> pmProContProdTtrs = new ArrayList<>();
        List<PmContMscTech> pmContMscTechs = new ArrayList<>();
        for (Entry<String, PmProContFilterResposeDTO> entry : filterOrderMap.entrySet()) {
            PmProContProdTtr pmProContProdTtr = new PmProContProdTtr();
            PmContMscTech pmContMscTech = new PmContMscTech();
            pmProContProdTtrs.add(BeanUtils.copy(entry.getValue(), pmProContProdTtr));
            pmContMscTechs.add(BeanUtils.copy(entry.getValue(), pmContMscTech));
        }
        bizData.put(RuleSetConstants.PM_PRO_CONT_PROD_ATTR_LIST, pmProContProdTtrs);
        bizData.put(RuleSetConstants.PM_CONT_MSC_TECH_LIST, pmContMscTechs);
        bizData.put(RuleSetConstants.INGOT_GUARANTEE_QUALLITY, pmProContYieldRespose.getGuaranteeQuality());

        ruleParam.setBizData(bizData);
        pmPdRuleSetService.runRuleSet(ruleParam);
    }
    
    @Override
    public PmPlateConfigDTO contCombineLimit(Long organizationId, String axisOrderNo, String mscLineNo , String formPlateMode ) {
        PmPdConstBt record = new PmPdConstBt();
        record.setTenantId(organizationId);
        record.setRollLineNo(Utils.mscLineNoToRoolLineNo(mscLineNo));
        // 轧制目标长度为【laim】，厚板设备限制轧制大板最小长度为【HPM_MIN_P_LEN】、厚板设备限制轧制大板最大长度为【HPM_MAX_P_LEN】。
        record = pmPdConstBtRepository.selectOne(record);
        if(record == null) {
            throw new CommonException("pm.pm_pd_const_bt_002", mscLineNo);
        }
        
        BigDecimal maxCombinePlateLen = pmPlateSpecBtRepository.maxCombinePlateLenMax(organizationId);
        PmPlateConfigDTO pmPlateConfigDTO = new PmPlateConfigDTO();
        pmPlateConfigDTO.setCombinePlateLenMin(BigDecimal.ZERO);
        pmPlateConfigDTO.setCombinePlateLenMax(maxCombinePlateLen);
        pmPlateConfigDTO.setCombinePlateWidthFrom(BigDecimal.ZERO);
        pmPlateConfigDTO.setCombinePlateWidthTo(record.getHpmMaxPWidth());
        if(StringUtils.isNotBlank(axisOrderNo) && StringUtils.isNotBlank(formPlateMode)) {
            FormPlateMode formPlateModeType = FormPlateMode.valueOf(formPlateMode);
            PmProContProdTtr axisPmProContProdTtr = new PmProContProdTtr();
            axisPmProContProdTtr.setTenantId(organizationId);
            axisPmProContProdTtr.setOrderNo(axisOrderNo);
            axisPmProContProdTtr = this.pmProContProdTtrRepository.selectOne(axisPmProContProdTtr);
            PmCutPlaceDTO pmCutPlaceDTO = pmCutPlaceBtRepository.queryCutPlace(formPlateModeType, Utils.mscLineNoToRoolLineNo(mscLineNo), axisPmProContProdTtr, organizationId);
            pmPlateConfigDTO.setCutMax(pmCutPlaceDTO.getCutMax());
            pmPlateConfigDTO.setCutMin(pmCutPlaceDTO.getCutMin());
        } else {
            pmPlateConfigDTO.setCutMax(BigDecimal.ZERO);
            pmPlateConfigDTO.setCutMin(BigDecimal.ZERO);
        }
        return pmPlateConfigDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancleOver(Long tenantId, PmProContCanclePoolReqDTO dto) {
        Map<String, BigDecimal> orderWtMap = pmProContProdTtrRepository.selectByOrderNoList(dto.getOrderNoList(), tenantId).stream()
                .collect(Collectors.toMap(PmProContProdTtr::getOrderNo, PmProContProdTtr::getOrderUnitAimWt));
        List<PmPdRecDTO> pmPdRecs = new ArrayList<>();
        List<PmOrderOverDTO> pmOrderList = new ArrayList<>();
        dto.getOrderNoList().forEach(orderNo -> {
            PmPdRecDTO pmPdRecDTO = new PmPdRecDTO();
            pmPdRecDTO.setOrderNo(orderNo);
            pmPdRecDTO.setEventMaker(DetailsHelper.getUserDetails().getUserId().toString());
            pmPdRecDTO.setMscLineNo( StringUtils.isEmpty(dto.getMscLineNo()) ? " " : dto.getMscLineNo());
            pmPdRecDTO.setQty(dto.getOrderNoQty());
            BigDecimal wt = orderWtMap.get(orderNo).multiply(dto.getOrderNoQty());
            pmPdRecDTO.setWt(wt);
            pmPdRecDTO.setKeyvalue1(dto.getOrderNoQty().toString());
            pmPdRecDTO.setKeyvalue1Desc(PmPdRecDTO.DESC_CALCEL_OVER_QTY);
            pmPdRecs.add(pmPdRecDTO);

            PmOrderOverDTO pmOrderOverDTO = new PmOrderOverDTO();
            pmOrderOverDTO.setOrderNo(orderNo);
            pmOrderOverDTO.setContractNum(orderNo.substring(0, 8));
            pmOrderOverDTO.setWgt(wt);
            pmOrderOverDTO.setNum(dto.getOrderNoQty());
            pmOrderList.add(pmOrderOverDTO);
        });
        // 抛组板履历-合同组板超投取消事件
        pmPdRecService.createEvent(tenantId, pmPdRecs, PdEventType.HP06, Constants.SYSTEM_PD_CODE, PdEventType.HP06.getDesc());
        // 抛合同跟踪
        log.info("<=====取消超投抛合同入参: tenantId：{}, dtoList = {}", tenantId, JSON.toJSONString(pmOrderList));
        eventClient.sendEventWithOutResponse(tenantId,  Constants.EventCode.PM_CONTRACT_BOARD_OVER_CANCEL, pmOrderList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderOver(Long tenantId, PmProContCanclePoolReqDTO dto) {
        Map<String, BigDecimal> orderWtMap = pmProContProdTtrRepository.selectByOrderNoList(dto.getOrderNoList(), tenantId).stream()
                .collect(Collectors.toMap(PmProContProdTtr::getOrderNo, PmProContProdTtr::getOrderUnitAimWt));
        List<PmPdRecDTO> pmPdRecs = new ArrayList<>();
        List<PmOrderOverDTO> pmOrderList = new ArrayList<>();
        dto.getOrderNoList().forEach(orderNo ->{
            PmPdRecDTO pmPdRecDTO = new PmPdRecDTO();
            pmPdRecDTO.setOrderNo(orderNo);
            pmPdRecDTO.setEventMaker(DetailsHelper.getUserDetails().getUserId().toString());
            pmPdRecDTO.setMscLineNo( StringUtils.isEmpty(dto.getMscLineNo()) ? " " : dto.getMscLineNo());
            pmPdRecDTO.setQty(dto.getOrderNoQty());
            BigDecimal wt = orderWtMap.get(orderNo).multiply(dto.getOrderNoQty());
            pmPdRecDTO.setWt(wt);
            pmPdRecDTO.setKeyvalue1(dto.getOrderNoQty().toString());
            pmPdRecDTO.setKeyvalue1Desc(PmPdRecDTO.DESC_OVER_QTY);
            pmPdRecDTO.setKeyvalue2(dto.getOverReason());
            pmPdRecDTO.setKeyvalue2Desc(PmPdRecDTO.DESC_OVER_REASON);
            pmPdRecs.add(pmPdRecDTO);

            PmOrderOverDTO pmOrderOverDTO = new PmOrderOverDTO();
            pmOrderOverDTO.setOrderNo(orderNo);
            pmOrderOverDTO.setContractNum(orderNo.substring(0, 8));
            pmOrderOverDTO.setWgt(wt);
            pmOrderOverDTO.setNum(dto.getOrderNoQty());
            pmOrderOverDTO.setOverFlag(dto.getOverFlag());
            pmOrderList.add(pmOrderOverDTO);
        });
        // 抛组板履历-合同组板超投取消事件
        pmPdRecService.createEvent(tenantId, pmPdRecs, PdEventType.HP03, Constants.SYSTEM_PD_CODE, PdEventType.HP03.getDesc());
        // 抛合同跟踪
        log.info("<=====超投抛合同入参: tenantId：{}, dtoList = {}", tenantId, JSON.toJSONString(pmOrderList));
        eventClient.sendEventWithOutResponse(tenantId,  Constants.EventCode.PM_CONTRACT_BOARD_OVER, pmOrderList);
    }
}
