package com.rongwei.bscommon.sys.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.rongwei.bscommon.sys.dao.ApsBlankOrderDao;
import com.rongwei.bscommon.sys.fegin.RwApsServer;
import com.rongwei.bscommon.sys.service.*;
import com.rongwei.bsentity.domain.*;
import com.rongwei.bsentity.vo.*;
import com.rongwei.commonservice.service.RedisService;
import com.rongwei.rwadmincommon.system.vo.SysUserVo;
import com.rongwei.rwcommon.base.exception.CustomException;
import com.rongwei.rwcommon.utils.DateUtils;
import com.rongwei.rwcommon.utils.SecurityUtil;
import com.rongwei.rwcommon.utils.StringUtils;
import com.rongwei.safecommon.utils.CXCommonUtils;
import com.rongwei.safecommon.utils.SaveConstans;
import org.apache.commons.math3.stat.descriptive.summary.Product;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.rongwei.safecommon.utils.SaveConstans.LockmarkType.LOCKMARK_Y;

@Service
public class ApsServiceImpl implements ApsService {

    private static final Logger logger = LoggerFactory.getLogger(ApsServiceImpl.class);
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RedisService redisService;
    @Autowired
    private ApsBlankOrderService apsBlankOrderService;
    @Autowired
    private ApsBlankOrderDao apsBlankOrderDao;
    @Autowired
    private RwApsServer rwApsServer;
    @Autowired
    private ApsScheduleConfigService apsScheduleConfigService;
    @Autowired
    private AspCheckItemsService aspCheckItemsService;
    @Autowired
    private ApsProcessOperationService apsProcessOperationService;
    @Autowired
    private ApsProcessOperationProcessEquServiceImpl processOperationProcessEquService;
    @Autowired
    private ApsEquipmentCalendarService apsEquipmentCalendarService;
    @Autowired
    private ApsProcessOperationOutMaterService apsProcessOperationOutMaterService;
    @Autowired
    private ApsFurnaceInstallationService apsFurnaceInstallationService;
    @Autowired
    private ApsMergeFurnaceService apsMergeFurnaceService;
    @Autowired
    private ApsProductionOrderService apsProductionOrderService;
    @Autowired
    private ApsAnnealingDifferenceService apsAnnealingDifferenceService;
    @Autowired
    private ApsNochangeRollerService apsNochangeRollerService;
    @Autowired
    private ApsProductionProcessesService apsProductionProcessesService;
    @Autowired
    private ApsProcessOperationEquService apsProcessOperationEquService;

    /**
     * Aps排程
     * @param apsBlankOrders
     * @param apsType cd：插单，lzcp：冷轧连续重排，mix：混合排程
     */
    @Override
    public void apsSchedule(List<ApsBlankOrderVo> apsBlankOrders,ApsTypeVo apsType,SysUserVo currentUser) {
        logger.info("**********排程请求开始**********");
        // 当前等路人所属工厂
        if(currentUser == null){
            currentUser = CXCommonUtils.getCurrentUser();
        }
        String tenantId = CXCommonUtils.getCurrentUserFactoryId(currentUser);
        if (StringUtils.isBlank(tenantId)) {
            throw new CustomException("所属工厂不能为空");
        }
        assert apsBlankOrders != null : "排程订单不能为空";
        // 按照所属工厂加锁
        RLock rLock = redissonClient.getLock(tenantId);
        boolean isLocked = rLock.isLocked();
        // 锁是否被占用
        if(isLocked){
            throw new CustomException("正在排程、请稍等一会！");
        }else{
            try {
                // 加锁最大1小时
                rLock.lock(24, TimeUnit.HOURS);
                redisService.redisCatchInit("apsUser-"+tenantId,currentUser,3600*24);
                // 合并待发布未锁定的订单一起排程
                String idStrs = null;
                if(apsBlankOrders != null && apsBlankOrders.size()>0){
                    List<String> hasIds = apsBlankOrders.stream().map(v -> v.getId()).collect(Collectors.toList());
                    idStrs = CollUtil.join(hasIds, "','");
                    idStrs = "'" + idStrs + "'";
                }
                logger.info("待排程订单："+idStrs);
                // 查询存在未锁定的作业坯料计划
                // 插单重排会优先排插单再排程其它的订单
                if("cd".equals(apsType) && apsBlankOrders != null && apsBlankOrders.size()>0){
                    for (ApsBlankOrderVo apsBlankOrder : apsBlankOrders) {
                        apsBlankOrder.setCdbs(1);
                        apsBlankOrder.setIfcp("Y");
                    }
                }else{
                    for (ApsBlankOrderVo apsBlankOrder : apsBlankOrders) {
                        apsBlankOrder.setCdbs(2);
                        apsBlankOrder.setIfcp("N");
                    }
                }
                List<ApsBlankOrderVo> fbNotLock = apsBlankOrderDao.getOrdersHasNotLockProcess(idStrs,tenantId);
                if (fbNotLock != null && fbNotLock.size() > 0) {
                    for (ApsBlankOrderVo apsBlankOrderVo : fbNotLock) {
                        apsBlankOrderVo.setCdbs(2);
                        apsBlankOrderVo.setIfcp("Y");
                    }
                    apsBlankOrders.addAll(fbNotLock);
                    List<String> repcIds = fbNotLock.stream().map(v -> v.getId()).collect(Collectors.toList());
                    logger.info("解锁重排订单："+repcIds);
                }
                // 冷轧连续性问题重排
                if(apsType != null && StrUtil.isNotBlank(apsType.getMixIf()) && "mix".equals(apsType.getMixIf())){
                    lzlxOrderSchedule(apsBlankOrders,currentUser,apsType);
                }else{
                    apsOrderScheduleNew(apsBlankOrders,currentUser,apsType);
                }
            } catch (Exception e) {
                e.printStackTrace();
                logger.info("排程异常",e);
                String msg = "排程服务异常";
                if(e instanceof CustomException){
                    msg = e.getMessage();
                }
                currentUser.setRoption(msg+" "+DateUtil.formatDateTime(new Date()));
                redisService.redisCatchInit("apsUser-"+tenantId,currentUser,3600*24);
                throw e;
            } finally {
                rLock.forceUnlock();
                System.out.println("解锁....");
                logger.info("解锁....");
            }
        }
    }

    private void apsOrderSchedule(List<ApsBlankOrderVo> apsBlankOrders,SysUserVo currentUser){
        // 坯料计划排序
        Collections.sort(apsBlankOrders,(v1,v2)->{
            // 合金
            String alloy1 = v1.getAlloy();
            String alloy2 = v2.getAlloy();
            // 合金状态
            String alloystatus1 = v1.getAlloystatus();
            String alloystatus2 = v2.getAlloystatus();
            // 产品类型
            String producttype1 = v1.getProducttype();
            String producttype2 = v2.getProducttype();
            // 宽度
            BigDecimal prowidth1 = v1.getProwidth();
            BigDecimal prowidth2 = v2.getProwidth();
            // 厚度
            BigDecimal thickness1 = v1.getThickness();
            BigDecimal thickness2 = v2.getThickness();
            // 重量
            BigDecimal singlerollweight1 = v1.getSinglerollweight();
            BigDecimal singlerollweight2 = v2.getSinglerollweight();

            int a = 0;
            // 插单优先
            if(v1.getCdbs().compareTo(v2.getCdbs()) == 0){
                // 合金
                if(alloy1.compareTo(alloy2) == 0){
                    // 产品类型
                    if(producttype1 == null || producttype2 == null || producttype1.compareTo(producttype2) == 0){
                        // 宽度
                        if(prowidth1.compareTo(prowidth2) == 0){
                            // 厚度
                            if(thickness1.compareTo(thickness2) == 0){
                                // 合金状态
                                if(alloystatus1 == null || alloystatus2 == null || alloystatus1.compareTo(alloystatus2) == 0){
                                    // 重量
                                    if(singlerollweight1.compareTo(singlerollweight2) == 0){
                                        // 按照订单排序
                                        if(v1.getProductionorderid().compareTo(v2.getProductionorderid()) == 0){
                                            // 卷数从大到小
                                            a = v2.getRollnum().compareTo(v1.getRollnum());
                                        }else{
                                            a = v1.getProductionorderid().compareTo(v2.getProductionorderid());
                                        }
                                    }else if(singlerollweight1.compareTo(singlerollweight2) > 0){
                                        a = -1;
                                    }else{
                                        a = 1;
                                    }
                                }else{
                                    a = alloystatus1.compareTo(alloystatus2);
                                }
                            }else{
                                if(thickness1.compareTo(thickness2) > 0){
                                    a = -1;
                                }else{
                                    a = 1;
                                }
                            }
                        }else{
                            if(prowidth1.compareTo(prowidth2) > 0){
                                a = -1;
                            }else{
                                a = 1;
                            }
                        }
                    }else{
                        a = producttype1.compareTo(producttype2);
                    }
                }else{
                    a = alloy1.compareTo(alloy2);
                }
            }else{
                a = v1.getCdbs().compareTo(v2.getCdbs());
            }
            return a;
        });
        // 排程前解锁所有待排程订单
        List<String> blankOrderIds = new ArrayList<>();
        apsBlankOrders.forEach((bo)->{
            blankOrderIds.add(bo.getId());
        });
        // 更新待排程的锁定的作业
        if(blankOrderIds != null && blankOrderIds.size()>0){
            String blankidStrs = CollUtil.join(blankOrderIds, "','");
            blankidStrs = "'" + blankidStrs + "'";
            apsBlankOrderDao.setLockMarkNullByToAps(blankidStrs);

            // 更新排程明细数据锁定状态为否
            /*processOperationProcessEquService.update(new LambdaUpdateWrapper<ApsProcessOperationProcessEquDo>().set(ApsProcessOperationProcessEquDo::getLockmark,"n")
                    .in(ApsProcessOperationProcessEquDo::getBlankid,blankOrderIds));*/
            apsBlankOrderDao.setProDetailLockMark(blankidStrs);
        }
        // 排程
        List<ProductionScheduleVo> productionScheduleVos = new ArrayList<>();
        Map<String,List<ApsBlankOrderVo>> dataMap = new HashMap<>();
        Map<String,ApsBlankOrderVo> dataMapOrder = new HashMap<>();
        JSONConfig jsonConfig = JSONConfig.create();
        jsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
        List<ApsScheduleConfigDo> apsConfigs = apsScheduleConfigService.list();
        // 所有设备
        List<AspCheckItemsDo> eqs = aspCheckItemsService.list(new LambdaQueryWrapper<>());
        Map<String, AspCheckItemsDo> eqMaps = new HashMap<>();
        for (AspCheckItemsDo eq : eqs) {
            eqMaps.put(eq.getId(), eq);
        }
        // 1卷一起排
        List<ApsBlankOrderVo> singleApsList = new ArrayList<>();

        List<ProductionScheduleVo> apsProductionSchedules = new ArrayList<>();
        // 多卷先排
        apsBlankOrders.forEach((bo)->{
            try{
                List<ApsBlankOrderVo> v = new ArrayList<>();
                v.add(bo);
                dataMapOrder.put(bo.getId(),bo);

                // 模型转换
                ProductionScheduleVo productionScheduleVo = apsProductionScheduleInit(v,new Date());
                productionScheduleVos.add(productionScheduleVo);
                dataMap.put(productionScheduleVo.getProductionScheduleId(),v);
//                        int mergeThNum = mergeThNum(bo, productionScheduleVo);
                // 排程计划设备集合
                List<Equipment> equipmentList1 = new ArrayList<>();
                List<ApsProcessOperationDo> operationDos1 = apsProcessOperationService.list(new LambdaQueryWrapper<ApsProcessOperationDo>()
                        .in(ApsProcessOperationDo::getBlankid, bo.getId()));
                List<String> blankids = new ArrayList<>();
                blankids.add(bo.getId());
                for (ApsProcessOperationDo operationDo : operationDos1) {
                    List<String> optionalEquipments = equipmentListInit(operationDo,equipmentList1,eqMaps,blankids,null,productionScheduleVo,apsConfigs.get(0),null);
                }
                productionScheduleVo.setEquipmentList(equipmentList1);
                apsProductionSchedules.add(productionScheduleVo);

                System.out.println("排程数据：" + JSONUtil.toJsonStr(productionScheduleVo, jsonConfig));
                logger.info("排程数据：" + JSONUtil.toJsonStr(productionScheduleVo, jsonConfig));
                // APS平台排程接口调用
                ProductionScheduleRetVo productionScheduleRetVo = rwApsServer.productionSchedule(productionScheduleVo);
                if (!"200".equals(productionScheduleRetVo.getCode())) {
                    logger.info("排程异常，坯料计划ID：" + bo.getId());
                    // 排程异常后恢复历史排程结果为锁定状态
                    processOperationProcessEquService.update(new LambdaUpdateWrapper<ApsProcessOperationProcessEquDo>().set(ApsProcessOperationProcessEquDo::getLockmark,"y")
                            .eq(ApsProcessOperationProcessEquDo::getBlankid,bo.getId()));
                    // 没有可排程工序的订单跳过
                    if("没有可排程的工序".equals(productionScheduleRetVo.getMsg())){
                        logger.info("排程异常：没有可排程的工序，坯料计划编号：" + bo.getBlanknumber());
                    }else{
                        throw new CustomException(productionScheduleRetVo.getMsg()+" "+DateUtil.formatDateTime(new Date()));
                    }
                }else{
                    // 获取坯料计划
                    List<ApsBlankOrderVo> apsBlankOrderss = new ArrayList<>();
                    apsBlankOrderss.add(bo);
                    apsBlankOrderService.apsAfter(productionScheduleRetVo,apsBlankOrderss,currentUser);
                }
            }catch (Exception e) {
                e.printStackTrace();
                logger.info("排程异常",e);
                String blankNos = bo.getBlanknumber();
                String msg = "排程服务异常（坯料计划号："+blankNos+"）"+DateUtil.formatDateTime(new Date());
                if(e instanceof CustomException){
                    msg = e.getMessage();
                }
                currentUser.setRoption(msg+" "+DateUtil.formatDateTime(new Date()));
                String tenantId = CXCommonUtils.getCurrentUserFactoryId(currentUser);
                redisService.redisCatchInit("apsUser-"+tenantId,currentUser,3600*24);
            }
        });
    }

    private void apsOrderScheduleNew(List<ApsBlankOrderVo> apsBlankOrders,SysUserVo currentUser,ApsTypeVo apsType){
        // 插单重排的优先排程
        List<ApsBlankOrderVo> cdorders = apsBlankOrders.stream().filter(v -> "1".equals(v.getCdbs())).collect(Collectors.toList());
        // 先按合金，合金状态分组，再每组分别排程
        for (ApsBlankOrderVo apsBlankOrder : apsBlankOrders) {
            apsBlankOrder.setVolumeMetalAndState(apsBlankOrder.getAlloy());
        }
        Map<String, List<ApsBlankOrderVo>> voms = apsBlankOrders.stream().collect(Collectors.groupingBy(ApsBlankOrderVo::getVolumeMetalAndState));
        Map<String,Equipment> allEqs = new HashMap<>();
        // 统一排程开始时间
        List<ApsScheduleConfigDo> apsConfigs = apsScheduleConfigService.list();
        Date apsPlanStartDate = new Date();
        if(apsConfigs != null && apsConfigs.size()>0){
            ApsScheduleConfigDo apsScheduleConfig = apsConfigs.get(0);
            int a = 8;
            if (apsScheduleConfig.getStartschedulerun() != null) {
                a = apsScheduleConfig.getStartschedulerun();
            }
            if (apsScheduleConfig.getApsplanstartdate() != null) {
                apsPlanStartDate = apsScheduleConfig.getApsplanstartdate();
            } else {
                apsPlanStartDate = DateUtil.date().offset(DateField.HOUR, a);
            }
        }
        Date finalApsPlanStartDate = apsPlanStartDate;
        if(cdorders != null && cdorders.size()>0){
            try{
                apsOrderScheduleApsNew(cdorders,currentUser,allEqs, finalApsPlanStartDate,apsType);
            }catch (Exception e) {
                e.printStackTrace();
                logger.info("排程异常",e);
                String blankNos = "";
                for (ApsBlankOrderVo apsBlankOrderVo : cdorders) {
                    if("".equals(blankNos)){
                        blankNos = apsBlankOrderVo.getBlanknumber();
                    }else{
                        blankNos = blankNos+"；"+apsBlankOrderVo.getBlanknumber();
                    }
                }
                String msg = "排程服务异常（坯料计划号："+blankNos+"）"+DateUtil.formatDateTime(new Date());
                if(e instanceof CustomException){
                    msg = e.getMessage();
                }
                currentUser.setRoption(msg+" "+DateUtil.formatDateTime(new Date()));
                String tenantId = CXCommonUtils.getCurrentUserFactoryId(currentUser);
                redisService.redisCatchInit("apsUser-"+tenantId,currentUser,3600*24);
//                    throw e;
            }
        }
        if(voms != null && voms.size()>0){
            voms.forEach((k, v)->{
                try{
                    // 坯料计划排序
                    Collections.sort(v,(v1,v2)->{
                        // 合金
                        String alloy1 = v1.getAlloy();
                        String alloy2 = v2.getAlloy();
                        // 合金状态
                        String alloystatus1 = v1.getAlloystatus();
                        String alloystatus2 = v2.getAlloystatus();
                        // 产品类型
                        String producttype1 = v1.getProducttype();
                        String producttype2 = v2.getProducttype();
                        // 宽度
                        BigDecimal prowidth1 = v1.getProwidth();
                        BigDecimal prowidth2 = v2.getProwidth();
                        // 厚度
                        BigDecimal thickness1 = v1.getThickness();
                        BigDecimal thickness2 = v2.getThickness();
                        // 重量
                        BigDecimal singlerollweight1 = v1.getSinglerollweight();
                        BigDecimal singlerollweight2 = v2.getSinglerollweight();

                        int a = 0;
                        // 插单优先
                        if(v1.getCdbs().compareTo(v2.getCdbs()) == 0){
                            // 产品类型
                            if(producttype1 == null || producttype2 == null || producttype1.compareTo(producttype2) == 0){
                                // 宽度
                                if(prowidth1.compareTo(prowidth2) == 0){
                                    // 厚度
                                    if(thickness1.compareTo(thickness2) == 0){
                                        // 合金状态
                                        if(alloystatus1 == null || alloystatus2 == null || alloystatus1.compareTo(alloystatus2) == 0){
                                            // 重量
                                            if(singlerollweight1.compareTo(singlerollweight2) == 0){
                                                // 按照订单排序
                                                if(v1.getProductionorderid().compareTo(v2.getProductionorderid()) == 0){
                                                    // 卷数从大到小
                                                    a = v2.getRollnum().compareTo(v1.getRollnum());
                                                }else{
                                                    a = v1.getProductionorderid().compareTo(v2.getProductionorderid());
                                                }
                                            }else if(singlerollweight1.compareTo(singlerollweight2) > 0){
                                                a = -1;
                                            }else{
                                                a = 1;
                                            }
                                        }else{
                                            a = alloystatus1.compareTo(alloystatus2);
                                        }
                                    }else{
                                        if(thickness1.compareTo(thickness2) > 0){
                                            a = -1;
                                        }else{
                                            a = 1;
                                        }
                                    }
                                }else{
                                    if(prowidth1.compareTo(prowidth2) > 0){
                                        a = -1;
                                    }else{
                                        a = 1;
                                    }
                                }
                            }else{
                                a = producttype1.compareTo(producttype2);
                            }
                        }else{
                            a = v1.getCdbs().compareTo(v2.getCdbs());
                        }
                        return a;
                    });
                    apsOrderScheduleApsNew(v,currentUser,allEqs, finalApsPlanStartDate,apsType);
                }catch (Exception e) {
                    e.printStackTrace();
                    logger.info("排程异常",e);
                    String blankNos = "";
                    for (ApsBlankOrderVo apsBlankOrderVo : v) {
                        if("".equals(blankNos)){
                            blankNos = apsBlankOrderVo.getBlanknumber();
                        }else{
                            blankNos = blankNos+"；"+apsBlankOrderVo.getBlanknumber();
                        }
                    }
                    String msg = "排程服务异常（坯料计划号："+blankNos+"）"+DateUtil.formatDateTime(new Date());
                    if(e instanceof CustomException){
                        msg = e.getMessage();
                    }
                    currentUser.setRoption(msg+" "+DateUtil.formatDateTime(new Date()));
                    String tenantId = CXCommonUtils.getCurrentUserFactoryId(currentUser);
                    redisService.redisCatchInit("apsUser-"+tenantId,currentUser,3600*24);
//                    throw e;
                }
            });
        }
    }

    /**
     * 冷轧连续混排
     * @param apsBlankOrders
     * @param currentUser
     */
    private void lzlxOrderSchedule(List<ApsBlankOrderVo> apsBlankOrders,SysUserVo currentUser,ApsTypeVo apsType){
        // 坯料计划排序
        Collections.sort(apsBlankOrders,(v1,v2)->{
            // 合金
            String alloy1 = v1.getAlloy();
            String alloy2 = v2.getAlloy();
            // 合金状态
            String alloystatus1 = v1.getAlloystatus();
            String alloystatus2 = v2.getAlloystatus();
            // 产品类型
            String producttype1 = v1.getProducttype();
            String producttype2 = v2.getProducttype();
            // 宽度
            BigDecimal prowidth1 = v1.getProwidth();
            BigDecimal prowidth2 = v2.getProwidth();
            // 厚度
            BigDecimal thickness1 = v1.getThickness();
            BigDecimal thickness2 = v2.getThickness();
            // 重量
            BigDecimal singlerollweight1 = v1.getSinglerollweight();
            BigDecimal singlerollweight2 = v2.getSinglerollweight();

            int a = 0;
            // 宽度
            if(prowidth1.compareTo(prowidth2) == 0){
                // 合金
                if(alloy1.compareTo(alloy2) == 0){
                    // 合金状态
                    if(alloystatus1 == null || alloystatus2 == null || alloystatus1.compareTo(alloystatus2) == 0){
                        // 产品类型
                        if(producttype1 == null || producttype2 == null || producttype1.compareTo(producttype2) == 0){
                            // 厚度
                            if(thickness1.compareTo(thickness2) == 0){
                                // 重量
                                if(singlerollweight1.compareTo(singlerollweight2) == 0){
                                    // 按照订单排序
                                    if(v1.getProductionorderid().compareTo(v2.getProductionorderid()) == 0){
                                        // 卷数从大到小
                                        a = v2.getRollnum().compareTo(v1.getRollnum());
                                    }else{
                                        a = v1.getProductionorderid().compareTo(v2.getProductionorderid());
                                    }
                                }else if(singlerollweight1.compareTo(singlerollweight2) > 0){
                                    a = -1;
                                }else{
                                    a = 1;
                                }
                            }else{
                                if(thickness1.compareTo(thickness2) > 0){
                                    a = -1;
                                }else{
                                    a = 1;
                                }
                            }
                        }else{
                            a = producttype1.compareTo(producttype2);
                        }
                    }else{
                        a = alloystatus1.compareTo(alloystatus2);
                    }
                }else{
                    a = alloy1.compareTo(alloy2);
                }
            }else{
                if(prowidth1.compareTo(prowidth2) > 0){
                    a = -1;
                }else{
                    a = 1;
                }
            }
            return a;
        });
        Map<String,Equipment> allEqs = new HashMap<>();
        // 统一排程开始时间
        List<ApsScheduleConfigDo> apsConfigs = apsScheduleConfigService.list();
        Date apsPlanStartDate = new Date();
        if(apsConfigs != null && apsConfigs.size()>0){
            ApsScheduleConfigDo apsScheduleConfig = apsConfigs.get(0);
            int a = 8;
            if (apsScheduleConfig.getStartschedulerun() != null) {
                a = apsScheduleConfig.getStartschedulerun();
            }
            if (apsScheduleConfig.getApsplanstartdate() != null) {
                apsPlanStartDate = apsScheduleConfig.getApsplanstartdate();
            } else {
                apsPlanStartDate = DateUtil.date().offset(DateField.HOUR, a);
            }
        }
        Date finalApsPlanStartDate = apsPlanStartDate;
        apsOrderScheduleApsNew(apsBlankOrders,currentUser,allEqs, finalApsPlanStartDate,apsType);
    }

    private void apsOrderScheduleApsNew(List<ApsBlankOrderVo> apsBlankOrders,SysUserVo currentUser,Map<String,Equipment> allEqs,Date apsPlanStartDate,ApsTypeVo apsType){
        // 设备数据每批次开始清空
        allEqs.clear();
        // 排程前解锁所有待排程订单
        List<String> blankOrderIds = new ArrayList<>();
        apsBlankOrders.forEach((bo)->{
            blankOrderIds.add(bo.getId());
        });
        System.out.println("当前批次排程坯料计划ID：" + blankOrderIds);
        logger.info("当前批次排程坯料计划ID：" + blankOrderIds);
        // 更新待排程的锁定的作业
        if(blankOrderIds != null && blankOrderIds.size()>0){
            String blankidStrs = CollUtil.join(blankOrderIds, "','");
            blankidStrs = "'" + blankidStrs + "'";
            apsBlankOrderDao.setLockMarkNullByToAps(blankidStrs);

            // 更新排程明细数据锁定状态为否
            /*processOperationProcessEquService.update(new LambdaUpdateWrapper<ApsProcessOperationProcessEquDo>().set(ApsProcessOperationProcessEquDo::getLockmark,"n")
                    .in(ApsProcessOperationProcessEquDo::getBlankid,blankOrderIds));*/
            apsBlankOrderDao.setProDetailLockMark(blankidStrs);
        }
        // 排程
        List<ProductionScheduleVo> productionScheduleVos = new ArrayList<>();
        Map<String,List<ApsBlankOrderVo>> dataMap = new HashMap<>();
        Map<String,ApsBlankOrderVo> dataMapOrder = new HashMap<>();
        JSONConfig jsonConfig = JSONConfig.create();
        jsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
        List<ApsScheduleConfigDo> apsConfigs = apsScheduleConfigService.list();
        // 所有设备
        List<AspCheckItemsDo> eqs = aspCheckItemsService.list(new LambdaQueryWrapper<>());
        Map<String, AspCheckItemsDo> eqMaps = new HashMap<>();
        for (AspCheckItemsDo eq : eqs) {
            eqMaps.put(eq.getId(), eq);
        }
        // 1卷一起排
        List<ApsBlankOrderVo> singleApsList = new ArrayList<>();

        List<ProductionScheduleVo> apsProductionSchedules = new ArrayList<>();
        // 所有已取消的作业明细
        List<ProductionProcesses> hasCancelsTotal = new ArrayList<>();
        // 多卷先排
        apsBlankOrders.forEach((bo)->{
            try{
                List<ApsBlankOrderVo> v = new ArrayList<>();
                v.add(bo);
                dataMapOrder.put(bo.getId(),bo);

                // 模型转换
                ProductionScheduleVo productionScheduleVo = apsProductionScheduleInit(v,apsPlanStartDate);
                productionScheduleVos.add(productionScheduleVo);
                dataMap.put(productionScheduleVo.getProductionScheduleId(),v);
//                        int mergeThNum = mergeThNum(bo, productionScheduleVo);
                // 去掉已取消的作业
                List<ProductionProcesses> notCancels = productionScheduleVo.getProcesses().stream().filter(pop -> !pop.isCancel()).collect(Collectors.toList());
                List<ProductionProcesses> hasCancels = productionScheduleVo.getProcesses().stream().filter(pop -> pop.isCancel()).collect(Collectors.toList());
                hasCancelsTotal.addAll(hasCancels);
                productionScheduleVo.setProcesses(notCancels);

                // 排程计划设备集合
                List<Equipment> equipmentList1 = new ArrayList<>();
                List<ApsProcessOperationDo> operationDos1 = apsProcessOperationService.list(new LambdaQueryWrapper<ApsProcessOperationDo>()
                        .in(ApsProcessOperationDo::getBlankid, bo.getId()));
                List<String> blankids = new ArrayList<>();
                blankids.add(bo.getId());
                for (ApsProcessOperationDo operationDo : operationDos1) {
                    List<String> optionalEquipments = equipmentListInit(operationDo,equipmentList1,eqMaps,blankids,null,productionScheduleVo,apsConfigs.get(0),allEqs);
                }
                productionScheduleVo.setEquipmentList(equipmentList1);
                apsProductionSchedules.add(productionScheduleVo);
            }catch(Exception e){
                logger.info("坯料计划：+bo.getBlanknumber() + ;排程数据初始化异常",e);
                String msg = "坯料计划："+bo.getBlanknumber() + ";排程数据初始化异常";
                throw new CustomException(msg+" "+DateUtil.formatDateTime(new Date()));
            }
        });

        // 多个坯料计划合并排程
        if(apsProductionSchedules != null && apsProductionSchedules.size()>0){
            ProductionScheduleVo apsProductionSchedule = apsProductionSchedules.get(0);
            List<ProductionProcesses> processes = new ArrayList<>();
            List<Equipment> equipmentList = new ArrayList<>();
            for (ProductionScheduleVo productionSchedule : apsProductionSchedules) {
                processes.addAll(productionSchedule.getProcesses());
                for (Equipment equipment : productionSchedule.getEquipmentList()) {
                    if(equipmentList.size()>0){
//                        List<Equipment> haseqs = equipmentList.stream().filter(v -> v.getId().equals(equipment.getId())).collect(Collectors.toList());
                        int ia = -1;
                        for (int i = 0; i < equipmentList.size(); i++) {
                            if(equipmentList.get(i).getId().equals(equipment.getId())){
                                ia = i;
                                break;
                            }
                        }
                        if(ia == -1){
                            equipmentList.add(equipment);
                        }else{
                            Equipment equipment1 = equipmentList.get(ia);
                            if(equipment1.getEquipmentRunTimes() != null && equipment1.getEquipmentRunTimes().size()>0){
                                if(equipment.getEquipmentRunTimes() != null && equipment.getEquipmentRunTimes().size()>0){
                                    if(equipment.getEquipmentRunTimes().size() > equipment1.getEquipmentRunTimes().size()){
                                        equipmentList.set(ia,equipment);
                                    }
                                }
                            }else{
                                equipmentList.set(ia,equipment);
                            }
                        }
                    }else{
                        equipmentList.add(equipment);
                    }
                }
            }
            List<ApsProductionProcessesDo> productionProcessesDos = apsProductionProcessesService.list();
            Map<String,String> productionProcessesDosMap = new HashMap<>();
            for (ApsProductionProcessesDo productionProcessesDo : productionProcessesDos) {
                productionProcessesDosMap.put(productionProcessesDo.getProductprocessname(),productionProcessesDo.getProcesscategory());
            }
            for (ProductionProcesses process : processes) {
                process.setProcessCategory(productionProcessesDosMap.get(process.getProcessType()));
            }

            apsProductionSchedule.setProcesses(processes);
            apsProductionSchedule.setEquipmentList(equipmentList);
            // 是否混排
            if(apsType != null){
                apsProductionSchedule.setScheduleType(apsType);
            }

            System.out.println("排程数据：" + JSONUtil.toJsonStr(apsProductionSchedule, jsonConfig));
            logger.info("排程数据：" + JSONUtil.toJsonStr(apsProductionSchedule, jsonConfig));
            // APS平台排程接口调用
            ProductionScheduleRetVo productionScheduleRetVo = rwApsServer.productionSchedule(apsProductionSchedule);
            if (!"200".equals(productionScheduleRetVo.getCode())) {
                logger.info("排程异常，坯料计划ID：" + blankOrderIds);
                // 排程异常后恢复历史排程结果为锁定状态
                processOperationProcessEquService.update(new LambdaUpdateWrapper<ApsProcessOperationProcessEquDo>().set(ApsProcessOperationProcessEquDo::getLockmark,"y")
                        .in(ApsProcessOperationProcessEquDo::getBlankid,blankOrderIds));
                // 没有可排程工序的订单跳过
                if("没有可排程的工序".equals(productionScheduleRetVo.getMsg())){
                    logger.info("排程异常：没有可排程的工序，坯料计划编号：" + blankOrderIds);
                }else{
                    throw new CustomException(productionScheduleRetVo.getMsg()+" "+DateUtil.formatDateTime(new Date()));
                }
            }else{
                // 获取坯料计划
                /*List<ApsBlankOrderVo> apsBlankOrderss = new ArrayList<>();
                apsBlankOrderss.add(bo);*/
                apsBlankOrderService.apsAfter(productionScheduleRetVo,apsBlankOrders,currentUser);
                if(StrUtil.isNotBlank(productionScheduleRetVo.getMsg())){
                    // 排程异常后恢复历史排程结果为锁定状态
                    List<String> blankids = CollUtil.distinct(productionScheduleRetVo.getProcesses().stream().map(v -> v.getProduceOrder().get(0).getId()).collect(Collectors.toList()));
                    List<String> allblankids = apsBlankOrders.stream().map(v -> v.getId()).collect(Collectors.toList());
                    List<String> exblankids = null;
                    if(blankids != null && blankids.size()>0){
                        exblankids = allblankids.stream().filter(v->!blankids.contains(v)).collect(Collectors.toList());
                    }else{
                        exblankids = allblankids;
                    }
                    if(exblankids != null && exblankids.size()>0){
                        processOperationProcessEquService.update(new LambdaUpdateWrapper<ApsProcessOperationProcessEquDo>().set(ApsProcessOperationProcessEquDo::getLockmark,"y")
                                .in(ApsProcessOperationProcessEquDo::getBlankid,exblankids));
                    }

                    throw new CustomException(productionScheduleRetVo.getMsg()+" "+DateUtil.formatDateTime(new Date()));
                }
            }
        }
    }

    /**
     * 计算合并退火的个数
     * @return
     */
    private int mergeThNum(ApsBlankOrderVo apsBlankOrderVo,ProductionScheduleVo productionScheduleVo){
        int a = 4;
        List<ProductionProcesses> thpros = productionScheduleVo.getProcesses().stream().filter(v ->
                v.getProcessType().equals("成退") || v.getProcessType().equals("小卷成退") || v.getProcessType().equals("中退")
        ).collect(Collectors.toList());
        if(thpros != null && thpros.size()>0){
            String eqid = thpros.get(0).getOptionalEquipments().get(0);
            AspCheckItemsDo checkItemsDo = aspCheckItemsService.getById(eqid);
            if(checkItemsDo != null && checkItemsDo.getEquipmentbearing() != null){
                a = checkItemsDo.getEquipmentbearing().divide(apsBlankOrderVo.getSinglerollweight(), 2, RoundingMode.HALF_UP).intValue();
            }
        }
        return a;
    }

    private void getAllNextPross(ProductionProcesses rootProcesses,Map<String,ProductionProcesses> allProcesses,List<ProductionProcesses> pss,Set<String> opId){
        if(rootProcesses.getNextProcessesIds() != null && rootProcesses.getNextProcessesIds().size()>0){
            for (String nextProcessesId : rootProcesses.getNextProcessesIds()) {
                ProductionProcesses processes = allProcesses.get(nextProcessesId);
                if(processes != null){
                    pss.add(processes);
                    for (String s : processes.getBsProcessesId()) {
                        opId.add(s);
                    }
                    getAllNextPross(processes,allProcesses,pss,opId);
                }
            }
        }
    }

    private ProductionScheduleVo productionScheduleVoInit(Date apsPlanStartDate){
        ProductionScheduleVo productionScheduleVo = new ProductionScheduleVo();
        productionScheduleVo.setProductionScheduleId("批量排程-"+SecurityUtil.getUUID());
        List<ApsScheduleConfigDo> apsConfigs = apsScheduleConfigService.list();
        ApsScheduleConfigDo apsScheduleConfig = null;
        // 松散度
        if (apsConfigs != null && apsConfigs.size() > 0) {
            apsScheduleConfig = apsConfigs.get(0);
            productionScheduleVo.setLooseness(apsScheduleConfig.getLooseness());
            productionScheduleVo.setPlanSeconds(apsScheduleConfig.getScheduleruntime());
            productionScheduleVo.setPcspeed(apsScheduleConfig.getPcspeed());
            Map<String, Integer> roamTime = new HashMap<>();
            Integer workshopin = apsScheduleConfig.getWorkshopin();
            Integer workshopcross = apsScheduleConfig.getWorkshopcross();
            roamTime.put("WORKSHOP_IN", workshopin);
            roamTime.put("WORKSHOP_CROSS", workshopcross);
            productionScheduleVo.setRoamTime(roamTime);
            // 排程计划开始时间
            /*int a = 8;
            if (apsScheduleConfig.getStartschedulerun() != null) {
                a = apsScheduleConfig.getStartschedulerun();
            }
            if (apsScheduleConfig.getApsplanstartdate() != null) {
                productionScheduleVo.setApsPlanStartDate(apsScheduleConfig.getApsplanstartdate());
            } else {
                productionScheduleVo.setApsPlanStartDate(DateUtil.date().offset(DateField.HOUR, a));
            }*/
            productionScheduleVo.setApsPlanStartDate(apsPlanStartDate);
            productionScheduleVo.setWashingtime(apsScheduleConfig.getWashingtime());
            productionScheduleVo.setStandingtime(apsScheduleConfig.getStandingtime());
            productionScheduleVo.setStandingyield(apsScheduleConfig.getStandingyield());
            productionScheduleVo.setExpecteddays(apsScheduleConfig.getExpecteddays());
            if(productionScheduleVo.getStandingyield() == null){
                productionScheduleVo.setStandingyield(60);
            }
            // 默认宽差配置
            productionScheduleVo.setMiddifference(apsScheduleConfig.getMiddifference());
            productionScheduleVo.setFurnacedifference(apsScheduleConfig.getFurnacedifference());
            // 默认卷重差配置
            productionScheduleVo.setWeightdifference(apsScheduleConfig.getWeightdifference());
            productionScheduleVo.setMidweightdifference(apsScheduleConfig.getMidweightdifference());
        } else {
            throw new CustomException("排程参数缺失");
        }
        // 洗炉合金配置数据设置
        List<WashingMetal> washingMetalConfig = apsBlankOrderDao.getWashingMetalConfig();
        productionScheduleVo.setClosealloynames(washingMetalConfig);
        // 小卷退火合并
        List<ApsFurnaceInstallationDo> furnaceInstallationDos = apsFurnaceInstallationService.list();
        productionScheduleVo.setFurnaceInstallations(furnaceInstallationDos);
        // 小卷退火兼容
        List<ApsMergeFurnaceDo> mergeFurnaceDos = apsMergeFurnaceService.list();
        productionScheduleVo.setMergeFurnaces(mergeFurnaceDos);
        // 退火合并厚差配置数据
        List<ApsAnnealingDifferenceDo> apsAnnealingDifferenceDos = apsAnnealingDifferenceService.list();
        productionScheduleVo.setApsAnnealingDifferences(apsAnnealingDifferenceDos);
        // 铸轧兼容配置
        List<ApsNochangeRollerDo> nochangeRollerDos = apsNochangeRollerService.list();
        productionScheduleVo.setApsNochangeRollerDos(nochangeRollerDos);

        return productionScheduleVo;
    }

    /**
     * 原始订单表数据转换APS平台模型数据
     *
     * @param apsBlankOrders
     * @return
     */
    @Override
    public ProductionScheduleVo apsProductionScheduleInit(List<ApsBlankOrderVo> apsBlankOrders,Date apsPlanStartDate) {
        // 待排程坯料计划ID集合
        List<String> blankids = apsBlankOrders.stream().map(v -> v.getId()).collect(Collectors.toList());
        // 查询当前坯料计划的历史排程明细
        List<ApsProcessOperationProcessEquDo> apopes = processOperationProcessEquService.list(
                new LambdaQueryWrapper<ApsProcessOperationProcessEquDo>()
                        .in(ApsProcessOperationProcessEquDo::getBlankid,blankids)
                        .isNotNull(ApsProcessOperationProcessEquDo::getProcessdeviceid)
                        .ne(ApsProcessOperationProcessEquDo::getProcessdeviceid,"")
                        .orderByAsc(ApsProcessOperationProcessEquDo::getPlanstartdate));
        Map<String, List<ApsProcessOperationProcessEquDo>> proEqus = apopes.stream().collect(Collectors.groupingBy(ApsProcessOperationProcessEquDo::getProcessid));
        // 待排程坯料计划作业可选设备轧辊ID
        List<ApsProcessOperationEquDo> processOperationEquDos = apsProcessOperationEquService.list(
                new LambdaQueryWrapper<ApsProcessOperationEquDo>().in(ApsProcessOperationEquDo::getBlankid, blankids));

        ProductionScheduleVo productionScheduleVo = productionScheduleVoInit(apsPlanStartDate);
        // 排程计划工序任务集合
        List<ProductionProcesses> processesList = new ArrayList<>();
        // 坯料计划ID和所属工序作业ID对应关系
        Map<String, List<String>> blankProcessIds = new HashMap<>();
        // 待合并生产的订单工序
        List<ApsProcessOperationVo> processOperationMs = new ArrayList<>();
        if (apsBlankOrders != null && apsBlankOrders.size() > 0) {
            for (ApsBlankOrderVo apsBlankOrderVo : apsBlankOrders) {
                // 当前坯料计划作业集合
                List<ProductionProcesses> blankProcessesList = new ArrayList<>();
                // 父子ID对应关系处理
                List<String> processIdss = new ArrayList<>();
                // 坯料计划订单
                ProduceOrder produceOrder = new ProduceOrder(apsBlankOrderVo.getId(), apsBlankOrderVo.getMaterialname(), apsBlankOrderVo.getDeliverydate() == null ? null : DateUtil.offsetHour(apsBlankOrderVo.getDeliverydate(), apsBlankOrderVo.getDeliverytime() == null ? 0 : -apsBlankOrderVo.getDeliverytime()));
                produceOrder.setMaxheatroll(apsBlankOrderVo.getMaxheatroll());
                produceOrder.setOrderNo(apsBlankOrderVo.getBlanknumber());
                produceOrder.setCustomerOrderId(apsBlankOrderVo.getProductionorderid());
                produceOrder.setProwidth(apsBlankOrderVo.getProwidth());
                // 期望交货天数
                produceOrder.setExpecteddays(productionScheduleVo.getExpecteddays());
                if(apsBlankOrderVo.getExpecteddays() != null && apsBlankOrderVo.getExpecteddays()>0){
                    produceOrder.setExpecteddays(apsBlankOrderVo.getExpecteddays());
                }
                // 获取所有订单工序
                List<ApsProcessOperationDo> operationDos = apsProcessOperationService.list(new LambdaQueryWrapper<ApsProcessOperationDo>()
                        .eq(ApsProcessOperationDo::getBlankid, apsBlankOrderVo.getId()));
                // 起始节点
                ApsProcessOperationDo rootOperationDo = null;
                // 作业维度缓存
                Map<String,List<ProductionProcesses>> operationProductionProcesses = new HashMap<>();
                Map<String,ApsProcessOperationDo> operationMaps = new HashMap<>();
                // 锁定的合并工序缓存
                Map<String, ProductionProcesses> lockHbPp = new HashMap<>();
                // 转换工序模型数据
                for (ApsProcessOperationDo operationDo : operationDos) {
                    processIdss.add(operationDo.getId());
                    ProductionProcesses processes = new ProductionProcesses();
                    // 工序所属订单
                    processes.setProduceOrder(Arrays.asList(new ProduceOrder[]{produceOrder}));
                    // 判断是否合并生产工序,加工方式是“合并加工”
                    String productprocess = operationDo.getProcessway();
                    // 根节点判断
                    if(StringUtils.isBlank(operationDo.getPreviousprocessid())){
                        rootOperationDo = operationDo;
                    }
                    operationMaps.put(operationDo.getId(),operationDo);
                    // 设备列表初始化
//                    List<String> optionalEquipments = equipmentListInit(operationDo,equipmentList,eqMaps,blankids,productionScheduleVo,apsScheduleConfig);
                    // 工序作业相关数据初始化
                    productionProcessesInit(operationDo,produceOrder,processesList,operationProductionProcesses,apsBlankOrderVo,productionScheduleVo,proEqus,processOperationEquDos);
                }
                // 第一次排程需要建立关联关系
                if(!"Y".equals(apsBlankOrderVo.getIfcp())){
                    // 前后关联关系初始化
                    processesRelationInit(rootOperationDo,operationProductionProcesses,operationMaps,apsBlankOrderVo);
                }

                blankProcessIds.put(apsBlankOrderVo.getId(), processIdss);
            }
        }
        // 合并生产工序
        productionScheduleVo.setProcesses(processesList);
//        productionScheduleVo.setEquipmentList(equipmentList);
        productionScheduleVo.setBlankProcessIds(blankProcessIds);
        return productionScheduleVo;
    }

    private void thMergePs(List<ApsProcessOperationDo> operationDos){

    }

    private List<String> equipmentListInit(ApsProcessOperationDo operationDo,List<Equipment> equipmentList,Map<String, AspCheckItemsDo> eqMaps
            ,List<String> blankids,Set<String> opId,ProductionScheduleVo productionScheduleVo,ApsScheduleConfigDo apsScheduleConfig,Map<String,Equipment> allEqs){
        // 当前工序排程开始时间
        Date apsPlanStartDate = productionScheduleVo.getApsPlanStartDate();
        if(productionScheduleVo.getProcesses() != null && productionScheduleVo.getProcesses().size()>0){
            List<ProductionProcesses> bsProcess = productionScheduleVo.getProcesses().stream().filter(v -> v.getBsProcessesId().get(0).equals(operationDo.getId())).collect(Collectors.toList());
            if(bsProcess != null && bsProcess.size()>0){
                if(bsProcess.get(0).getApsOverallConfig() != null && bsProcess.get(0).getApsOverallConfig().getStartTime() != null){
                    apsPlanStartDate = Date.from(bsProcess.get(0).getApsOverallConfig().getStartTime().atZone(ZoneId.systemDefault()).toInstant());
                }
            }
        }
        String apsPlanStartDateStr = DateUtil.formatDateTime(apsPlanStartDate);
        // 设备列表
        List<String> optionalEquipments = new ArrayList<>();
        if (StringUtils.isNotBlank(operationDo.getCanchoosedeviceid())) {
            String canchoosedeviceid = operationDo.getCanchoosedeviceid();
            // 锁定作业添加可选设备里没有但已锁定排程明细的设备
            List<ApsProcessOperationProcessEquDo> pros = processOperationProcessEquService.list(new LambdaQueryWrapper<ApsProcessOperationProcessEquDo>()
                    .eq(ApsProcessOperationProcessEquDo::getProcessid, operationDo.getId()).eq(ApsProcessOperationProcessEquDo::getLockmarkdetail,"y"));
            if(pros != null && pros.size()>0){
                for (ApsProcessOperationProcessEquDo pro : pros) {
                    if(StrUtil.isNotBlank(pro.getProcessdeviceid()) && !canchoosedeviceid.contains(pro.getProcessdeviceid())){
                        if(StrUtil.isBlank(canchoosedeviceid)){
                            canchoosedeviceid = pro.getProcessdeviceid();
                        }else{
                            canchoosedeviceid = canchoosedeviceid + "," + pro.getProcessdeviceid();
                        }
                    }
                }
            }

            String[] sbIds = canchoosedeviceid.split(",");
            for (String equIds : sbIds) {
                if(equIds.equals("0001be252874536843730b100017")){
                    System.out.println(equIds);
                }
                String eqDateKey = apsPlanStartDateStr + " *** " + equIds;
                if(allEqs.containsKey(eqDateKey)){
                    equipmentList.add(allEqs.get(eqDateKey));
                    continue;
                }

                AspCheckItemsDo checkItemsD = eqMaps.get(equIds);
                if (checkItemsD != null) {
                    optionalEquipments.add(equIds);
                    List<Equipment> eqpts = equipmentList.stream().filter(v -> v.getId().equals(equIds)).collect(Collectors.toList());
                    // 设备集合里不存在时新增
                    if (eqpts == null || eqpts.size() == 0) {
                        Equipment equipment = new Equipment();
                        equipment.setBsEquipmentId(equIds);
                        equipment.setId(equIds);
                        equipment.setEquipmentName(checkItemsD.getCheckitemname());
                        equipment.setWorkshopid(checkItemsD.getUsedeptid());
                        equipment.setWorkshopname(checkItemsD.getUsedeptname());
                        equipment.setFactoryid(checkItemsD.getTenantid());
                        equipment.setFactory(checkItemsD.getOwnedfactory());
                        equipment.setEquassociated(checkItemsD.getEquassociated());
                        // 设备参数
                        EquipmentParameter ep = new EquipmentParameter();
                        ep.setEquipmentWidth(checkItemsD.getEquipmentlength());
                        ep.setEquipmentBearing(checkItemsD.getEquipmentbearing());
                        ep.setFurnace(apsScheduleConfig.getFurnace());
                        ep.setMaxfurance(checkItemsD.getMaxfurance());
                        equipment.setEquipmentParameter(ep);
                        // 查询设备锁定的已排程的时间段
                        List<ApsProcessOperationProcessEquDo> processEqus = null;
                        if(blankids != null && blankids.size()>0){
                            processEqus = processOperationProcessEquService.list(new LambdaQueryWrapper<ApsProcessOperationProcessEquDo>()
                                    .eq(ApsProcessOperationProcessEquDo::getProcessdeviceid, equIds)
                                    .eq(ApsProcessOperationProcessEquDo::getLockmark, "y")
//                                    .notIn(ApsProcessOperationProcessEquDo::getBlankid, blankids)
                                    .ge(ApsProcessOperationProcessEquDo::getPlanenddate, apsPlanStartDate)
                                    .orderByAsc(ApsProcessOperationProcessEquDo::getPlanstartdate)
                            );
                        }else if(opId != null && opId.size()>0){
                            processEqus = processOperationProcessEquService.list(new LambdaQueryWrapper<ApsProcessOperationProcessEquDo>()
                                    .eq(ApsProcessOperationProcessEquDo::getProcessdeviceid, equIds)
                                    .eq(ApsProcessOperationProcessEquDo::getLockmark, "y")
//                                    .notIn(ApsProcessOperationProcessEquDo::getProcessid, opId)
                                    .ge(ApsProcessOperationProcessEquDo::getPlanenddate, apsPlanStartDate)
                                    .orderByAsc(ApsProcessOperationProcessEquDo::getPlanstartdate)
                            );
                        }
                        // 过滤设备为空的明细
                        if(processEqus != null && processEqus.size()>0){
                            processEqus = processEqus.stream().filter(v->StringUtils.isNotBlank(v.getProcessdeviceid())).collect(Collectors.toList());
                        }

                        // 查询当前设备最后一个生产任务、连续生产需要考虑使用
                        List<ApsProcessOperationProcessEquDo> lastpros = null;
                        if(blankids != null && blankids.size()>0){
                            lastpros = processOperationProcessEquService.list(new LambdaQueryWrapper<ApsProcessOperationProcessEquDo>()
                                    .eq(ApsProcessOperationProcessEquDo::getProcessdeviceid, equIds)
                                    .eq(ApsProcessOperationProcessEquDo::getLockmark, "y")
//                                    .notIn(ApsProcessOperationProcessEquDo::getBlankid, blankids)
                                    .lt(ApsProcessOperationProcessEquDo::getPlanstartdate, apsPlanStartDate)
                                    .orderByDesc(ApsProcessOperationProcessEquDo::getPlanstartdate).last(" limit 100")
                            );
                        }else if(opId != null && opId.size()>0){
                            lastpros = processOperationProcessEquService.list(new LambdaQueryWrapper<ApsProcessOperationProcessEquDo>()
                                    .eq(ApsProcessOperationProcessEquDo::getProcessdeviceid, equIds)
                                    .eq(ApsProcessOperationProcessEquDo::getLockmark, "y")
//                                    .notIn(ApsProcessOperationProcessEquDo::getProcessid, opId)
                                    .lt(ApsProcessOperationProcessEquDo::getPlanstartdate, apsPlanStartDate)
                                    .orderByDesc(ApsProcessOperationProcessEquDo::getPlanstartdate).last(" limit 100")
                            );
                        }
                        // 过滤设备为空的明细
                        if(lastpros != null && lastpros.size()>0){
                            lastpros = lastpros.stream().filter(v->StringUtils.isNotBlank(v.getProcessdeviceid())).collect(Collectors.toList());
                        }

                        BigDecimal hasLbs = null;
                        if (lastpros != null && lastpros.size() > 0) {
                            boolean hasLast = true;
                            ApsProcessOperationProcessEquDo lastpro = lastpros.get(0);
                            if(processEqus != null && processEqus.size()>0){
                                List<ApsProcessOperationProcessEquDo> hasLasts = processEqus.stream().filter(v -> v.getId().equals(lastpro.getId())).collect(Collectors.toList());
                                if(hasLasts != null && hasLasts.size() > 0){
                                    hasLast = false;
                                }
                            }
                            // 获取加工设备当前开始时间第一道工序的立板周期
                            Set<String> prosids = new HashSet<>();
                            lastpros.forEach(v->{
                                prosids.add(v.getProcessid());
                            });
                            // 查询所有作业详情信息
                            List<ApsProcessOperationDo> lastops = (List<ApsProcessOperationDo>)apsProcessOperationService.listByIds(prosids);
                            Map<String,ApsProcessOperationDo> lastopsMap = new HashMap<>();
                            for (ApsProcessOperationDo lastop : lastops) {
                                lastopsMap.put(lastop.getId(),lastop);
                            }

                            // 遍历找到最近一个立板周期
                            String lbtj = null;
                            for (int i = 0; i < lastpros.size(); i++) {
                                ApsProcessOperationDo apo = lastopsMap.get(lastpros.get(i).getProcessid());
                                if(apo == null){
//                                    int aaa = 1;
                                    continue;
                                }
                                String thislbtj = apo.getMetal() + "^_^" + apo.getProducttype() + "^_^" + apo.getProwidth();
                                if(hasLbs == null){
                                    hasLbs = apo.getSinglerollweight();
                                    lbtj = thislbtj;
                                }else{
                                    if(lbtj.equals(thislbtj)){
                                        hasLbs = hasLbs.add(apo.getSinglerollweight());
                                    }else{
                                        break;
                                    }
                                }
                            }

                            Date lxDate = null;
                            String lxrollerid = null;
                            BigDecimal lxprowidth = null;
                            if("冷轧".equals(operationDo.getProcess()) || "箔轧".equals(operationDo.getProcess())){
                                for (int i = 0; i < lastpros.size(); i++) {
                                    ApsProcessOperationDo apo = lastopsMap.get(lastpros.get(i).getProcessid());
                                    Date planstartdate = lastpros.get(i).getPlanstartdate();
                                    if(lxDate == null){
                                        lxDate = planstartdate;
                                        lxrollerid = lastpros.get(i).getRollerid();
                                        lxprowidth = apo.getProwidth();
                                    }else{
                                        if(StrUtil.isNotBlank(lxrollerid) && lxrollerid.equals(lastpros.get(i).getRollerid()) && apo.getProwidth().compareTo(lxprowidth)>=0){
                                            lxDate = lastpros.get(i).getPlanstartdate();
                                        }else{
                                            break;
                                        }
                                    }
                                }
                            }

                            if(hasLast){
                                ApsProcessOperationDo lastop = apsProcessOperationService.getById(lastpro.getProcessid());
                                // 输出物料
                                List<ApsProcessOperationOutMaterDo> outMaterDos = apsProcessOperationOutMaterService.list(new LambdaQueryWrapper<ApsProcessOperationOutMaterDo>()
                                        .eq(ApsProcessOperationOutMaterDo::getMainid, lastpro.getProcessid()));
                                equipment.setLastProcessType(lastop.getProcess());
                                equipment.setLastProcessEndTime(lastpro.getPlanenddate());
                                equipment.setOnceprocessmin(lastop.getOnceprocessmin().intValue());
                                equipment.setLastProcessCutfinishmin(lastop.getCutfinishmin() == null ? null : lastop.getCutfinishmin().intValue());
                                equipment.setLastSinglerollweight(lastop.getSinglerollweight());
                                equipment.setLastSerialLbWeight(hasLbs);
                                // 合金+输入物料+宽度+厚度+输出物料厚度
                                equipment.setLastSeriesProduceMark(lastop.getMetal() + "^_^" + lastop.getProducttype() + "^_^" + lastop.getProwidth() + "^_^" + lastop.getThickness() + "^_^" + outMaterDos.get(0).getThickness());
                                equipment.setLastProcessCutfinishmin(lastop.getCutfinishmin() == null ? null : lastop.getCutfinishmin().intValue());
                                equipment.setLastZjgid(lastpro.getRollerid());
                            }
                            equipment.setLxzTime(lxDate);
                        }
                        // 设备占用时间段
                        List<EquipmentRunTime> equipmentRunTimes = new ArrayList<>();
                        // 查询相关工序作业
                        Set<String> processIds = new HashSet<>();
                        if (processEqus != null && processEqus.size() > 0) {
                            for (ApsProcessOperationProcessEquDo equs : processEqus) {
                                processIds.add(equs.getProcessid());
                            }
                            List<ApsProcessOperationDo> processOperationDos = null;
                            if (processIds.size() > 0) {
                                processOperationDos = apsProcessOperationService.list(new LambdaQueryWrapper<ApsProcessOperationDo>()
                                        .in(ApsProcessOperationDo::getId, processIds));
                            }
                            //
                            List<ApsProcessOperationOutMaterDo> outMaterDosAll = apsProcessOperationOutMaterService.list(new LambdaQueryWrapper<ApsProcessOperationOutMaterDo>()
                                    .in(ApsProcessOperationOutMaterDo::getMainid, processIds));

                            for (ApsProcessOperationProcessEquDo equs : processEqus) {
                                if(equs.getPlanstartdate() == null || equs.getPlanenddate() == null){
                                    continue;
                                }
                                EquipmentRunTime er = new EquipmentRunTime();
                                er.setStartRunTime(equs.getPlanstartdate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                                er.setEndRunTime(equs.getPlanenddate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                                er.setPcNum(equs.getPlanprocessrall());
                                er.setOccupyType("process");
                                er.setZjgid(equs.getRollerid());
                                // 设备占用时间设置连续生产标识，参与排程
                                if (processOperationDos != null) {
                                    List<ApsProcessOperationDo> pos = processOperationDos.stream().filter(v -> v.getId().equals(equs.getProcessid())).collect(Collectors.toList());
                                    if (pos != null && pos.size() > 0) {
                                        ApsProcessOperationDo processesDo = pos.get(0);
                                        // 输出物料
//                                        List<ApsProcessOperationOutMaterDo> outMaterDos = apsProcessOperationOutMaterService.list(new LambdaQueryWrapper<ApsProcessOperationOutMaterDo>()
//                                                .eq(ApsProcessOperationOutMaterDo::getMainid, processesDo.getId()));
                                        List<ApsProcessOperationOutMaterDo> outMaterDos = outMaterDosAll.stream().filter(v->v.getMainid().equals(processesDo.getId())).collect(Collectors.toList());
                                        if(outMaterDos == null || outMaterDos.size() == 0){
                                            throw new CustomException("坯料计划ID:"+processesDo.getBlankid()+",作业："+processesDo.getProcess()+",作业名"+processesDo.getProcessname()+" 没有相关输出物料信息!");
                                        }
                                        er.setProcessType(processesDo.getProcess());
                                        // 合金+输入物料+宽度+厚度
                                        er.setSeriesProduceMark(processesDo.getMetal() + "^_^" + processesDo.getProducttype() + "^_^" + processesDo.getProwidth() + "^_^" + processesDo.getThickness() + "^_^" + outMaterDos.get(0).getThickness());
                                        er.setVolumeMetal(processesDo.getMetal());
                                        if("成退".equals(processesDo.getProcess()) || "中退".equals(processesDo.getProcess()) || "小卷成退".equals(processesDo.getProcess())){
                                            er.setVolumeMetalstate(outMaterDos.get(0).getMetalstate());
                                        }else{
                                            er.setVolumeMetalstate(processesDo.getMetalstate());
                                        }
                                        er.setPrepressworkmin(processesDo.getPrepressworkmin() == null ? null : processesDo.getPrepressworkmin().intValue());
                                        er.setCutfinishmin(processesDo.getCutfinishmin() == null ? null : processesDo.getCutfinishmin().intValue());
                                        // 单卷宽度、重量数据赋值
                                        er.setTotalVolumeWidth(processesDo.getProwidth());
                                        if(processesDo.getProcess().equals("小卷成退")){
                                            er.setTotalSinglerollweight(processesDo.getSinglerollweight().multiply(new BigDecimal(equs.getPlanprocessrall())));
                                        }else{
                                            er.setTotalSinglerollweight(processesDo.getSinglerollweight());
                                        }

                                        er.setProducttype(processesDo.getProducttype());
                                        er.setTotalThickness(processesDo.getThickness());
                                        er.setOnceprocessmin(processesDo.getOnceprocessmin().intValue());
                                        if(lastpros != null && lastpros.size()>0 && equs.getId().equals(lastpros.get(0).getId())){
                                            er.setLastSerialLbWeight(hasLbs);
                                        }
                                    }
                                }
                                equipmentRunTimes.add(er);
                            }
                        }
                        // 设备日历不可用时间段
                        Date finalApsPlanStartDate = apsPlanStartDate;
                        List<ApsEquipmentCalendarDo> equipmentCalendarDos = apsEquipmentCalendarService.list(
                                new LambdaQueryWrapper<ApsEquipmentCalendarDo>().eq(ApsEquipmentCalendarDo::getProcessdeviceid, equipment.getBsEquipmentId())
                                        .and(i->i.ge(ApsEquipmentCalendarDo::getSdendtime, finalApsPlanStartDate).or().isNull(ApsEquipmentCalendarDo::getSdendtime)));
                        if (equipmentCalendarDos != null && equipmentCalendarDos.size() > 0) {
                            for (ApsEquipmentCalendarDo equipmentCalendarDo : equipmentCalendarDos) {
                                EquipmentRunTime er = new EquipmentRunTime();
                                er.setStartRunTime(equipmentCalendarDo.getSdstarttime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                                // 结束时间如果大于2099年，则认为空，没有停机结束时间
                                if(equipmentCalendarDo.getSdendtime() != null && equipmentCalendarDo.getSdendtime().compareTo(DateUtil.parseDateTime("2099-01-01 00:00:00)"))<0){
                                    er.setEndRunTime(equipmentCalendarDo.getSdendtime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                                }
                                er.setOccupyType("maintenance");
                                equipmentRunTimes.add(er);
                            }
                        }
                        if(equipmentRunTimes != null && equipmentRunTimes.size()>0){
                            equipment.setEquipmentRunTimes(equipmentRunTimes);
                        }

                        equipmentList.add(equipment);

                        allEqs.put(eqDateKey,equipment);
                    }
                }
            }
        }

        return optionalEquipments;
    }


    /**
     * 前后道工序作业关联关系初始化
     * @param rootOperationDo
     * @param operationProductionProcesses
     * @param operationMaps
     * @param apsBlankOrderVo
     */
    private void processesRelationInit(ApsProcessOperationDo rootOperationDo,Map<String,List<ProductionProcesses>> operationProductionProcesses
            ,Map<String,ApsProcessOperationDo> operationMaps,ApsBlankOrderVo apsBlankOrderVo){
        if(rootOperationDo.getId().equals("b4cf9ca488bb49268a9782ed1396c4f9")){
            System.out.println(rootOperationDo);
        }
        if(StringUtils.isNotBlank(rootOperationDo.getNextprocessid())){
            String[] nextids = rootOperationDo.getNextprocessid().split(",");
            // 前后道工序关联关系处理
            if(rootOperationDo == null){
                throw new CustomException("数据异常，ID为:"+apsBlankOrderVo.getId()+"的坯料计划作业模型初始化，作业为空");
            }else{
                boolean isEnd = true;
                // 当前作业计划加工卷数
                Integer planPres = rootOperationDo.getPlanprocessrall();
                // 下道工序按物料类型分组
                Map<String, List<ProductionProcesses>> wlPros = new HashMap<>();
                if(nextids != null && nextids.length>0){
                    for (String nextid : nextids) {
                        List<ProductionProcesses> productionProcesses = operationProductionProcesses.get(nextid);
                        if(productionProcesses != null && productionProcesses.size()>0 && operationMaps.get(nextid) != null){
                            if(wlPros.containsKey(operationMaps.get(nextid).getPlaninput())){
                                wlPros.get(operationMaps.get(nextid).getPlaninput()).addAll(productionProcesses);
                            }else{
                                wlPros.put(operationMaps.get(nextid).getPlaninput(),productionProcesses);
                            }
                        }
                    }
                }
                // 当前作业和下道工序建立关联关系
                if(wlPros.size()>0){
                    wlPros.forEach((k,v)->{
                        boolean isConnect = true;
                        int vi = 0;
                        List<ProductionProcesses> productionProcesses = operationProductionProcesses.get(rootOperationDo.getId());
                        while (vi<v.size()){
                            for(int i = 0;i <planPres;i++){
                                if(vi>=v.size()){
                                    break;
                                }
                                if(i == productionProcesses.size()){
                                    int aaa = 1;
                                }
                                if(productionProcesses.get(i).getNextProcessesIds() == null){
                                    List<String> ids = new ArrayList<>();
                                    ids.add(v.get(vi).getId());
                                    productionProcesses.get(i).setNextProcessesIds(ids);
                                }else{
                                    if(!productionProcesses.get(i).getNextProcessesIds().contains(v.get(vi).getId())){
                                        productionProcesses.get(i).getNextProcessesIds().add(v.get(vi).getId());
                                    }
                                }
                                if(v.get(vi).getPreviousProcessesIds() == null){
                                    List<String> ids = new ArrayList<>();
                                    ids.add(productionProcesses.get(i).getId());
                                    v.get(vi).setPreviousProcessesIds(ids);
                                }else{
                                    if(!v.get(vi).getPreviousProcessesIds().contains(productionProcesses.get(i).getId())){
                                        v.get(vi).getPreviousProcessesIds().add(productionProcesses.get(i).getId());
                                    }
                                }
                                vi++;
                            }
                        }
                    });
                }
            }
            // 递归处理下道工序数据
            if(nextids != null && nextids.length>0){
                for (String nextid : nextids) {
                    ApsProcessOperationDo apsProcessOperationDo = operationMaps.get(nextid);
                    processesRelationInit(apsProcessOperationDo,operationProductionProcesses,operationMaps,apsBlankOrderVo);
                }
            }
        }
    }

    /**
     * 工序作业模型初始化
     * @param operationDo
     * @param produceOrder
     * @param processesList
     * @param operationProductionProcesses
     */
    private void productionProcessesInit(ApsProcessOperationDo operationDo,ProduceOrder produceOrder
            ,List<ProductionProcesses> processesList,Map<String,List<ProductionProcesses>> operationProductionProcesses
            ,ApsBlankOrderVo apsBlankOrderVo,ProductionScheduleVo productionScheduleVo,Map<String, List<ApsProcessOperationProcessEquDo>> proEqus,List<ApsProcessOperationEquDo> processOperationEquDos){
        // 输出物料
        List<ApsProcessOperationOutMaterDo> outMaterDos = apsProcessOperationOutMaterService.list(new LambdaQueryWrapper<ApsProcessOperationOutMaterDo>()
                .eq(ApsProcessOperationOutMaterDo::getMainid, operationDo.getId()));
        List<ProductionProcesses> operationProcess = new ArrayList<>();
        if(operationDo != null && operationDo.getPlanprocessrall() != null && operationDo.getPlanprocessrall()>0){
            List<String> optionalEquipments = new ArrayList<>();
            String[] sbIds = operationDo.getCanchoosedeviceid().split(",");
            for (String equIds : sbIds) {
                optionalEquipments.add(equIds);
            }
            // 锁定的作业
            if(LOCKMARK_Y.equals(operationDo.getLockmark())){
                List<ApsProcessOperationProcessEquDo> processDetails = processOperationProcessEquService.list(new LambdaQueryWrapper<ApsProcessOperationProcessEquDo>()
                        .eq(ApsProcessOperationProcessEquDo::getProcessid, operationDo.getId())
                        .isNotNull(ApsProcessOperationProcessEquDo::getProcessdeviceid)
                        .ne(ApsProcessOperationProcessEquDo::getProcessdeviceid,"")
                        .orderByAsc(ApsProcessOperationProcessEquDo::getPlanstartdate));
                for (ApsProcessOperationProcessEquDo processDetail : processDetails) {
                    ProductionProcesses processes = productionProcessesDetailInit(operationDo, produceOrder, optionalEquipments,outMaterDos,apsBlankOrderVo,processOperationEquDos);
                    // 锁定的作业保留作业ID
                    processes.setId(processDetail.getId());
                    processes.setIfLock(true);
                    processes.setEquipmentId(processDetail.getProcessdeviceid());
                    // 锁定作业的关联关系设置
                    if(StrUtil.isNotBlank(processDetail.getPreviousprocessesids())){
                        processes.setPreviousProcessesIds(new ArrayList<>(Arrays.asList(processDetail.getPreviousprocessesids().split(","))));
                    }
                    if(StrUtil.isNotBlank(processDetail.getNextprocessesids())){
                        processes.setNextProcessesIds(new ArrayList<>(Arrays.asList(processDetail.getNextprocessesids().split(","))));
                    }

                    List<String> opeqs = new ArrayList<>();
                    opeqs.add(processDetail.getProcessdeviceid());
                    processes.setOptionalEquipments(opeqs);
                    processes.setDelay(0);
                    processes.setStartTime(processDetail.getPlanstartdate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                    processes.setEndTime(processDetail.getPlanenddate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                    if("小卷成退".equals(operationDo.getProcess()) || "小卷包装".equals(operationDo.getProcess())){
                        String previousprocessid = operationDo.getPreviousprocessid();
                        ApsProcessOperationDo preprocess = apsProcessOperationService.getById(previousprocessid);
                        processes.setMinThPcNum(processDetail.getPlanprocessrall());
                        processes.setProducePcNum(preprocess.getPlanprocessrall());
                    }
                    if(apsBlankOrderVo.getPlanhavematerialdate() != null){
                        // 全局配置
                        ApsOverallConfig apsOverallConfig = new ApsOverallConfig();
                        Date startDate = apsBlankOrderVo.getPlanhavematerialdate();
                        LocalDateTime startTime = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                        apsOverallConfig.setStartTimeLong(startDate.getTime());
                        apsOverallConfig.setStartTime(startTime);
                        // 排程全局配置
                        apsOverallConfig.setRoamTime(productionScheduleVo.getRoamTime());
                        apsOverallConfig.setWashingtime(productionScheduleVo.getWashingtime());
                        apsOverallConfig.setStandingtime(productionScheduleVo.getStandingtime());
                        apsOverallConfig.setClosealloynames(productionScheduleVo.getClosealloynames());
                        apsOverallConfig.setFurnaceInstallations(productionScheduleVo.getFurnaceInstallations());
                        apsOverallConfig.setMergeFurnaces(productionScheduleVo.getMergeFurnaces());
                        apsOverallConfig.setLooseness(productionScheduleVo.getLooseness());
                        apsOverallConfig.setStandingyield(productionScheduleVo.getStandingyield());
                        processes.setApsOverallConfig(apsOverallConfig);
                    }
                    operationProcess.add(processes);
                }
            }else{
                // 已排程的当前作业
                List<ApsProcessOperationProcessEquDo> processEquDos = proEqus.get(operationDo.getId());
                if("小卷成退".equals(operationDo.getProcess())){
                    Integer planprocessrall = null;
                    String previousprocessid = operationDo.getPreviousprocessid();
                    if(StringUtils.isNotBlank(previousprocessid)){
                        ApsProcessOperationDo preprocess = apsProcessOperationService.getById(previousprocessid);
                        if(preprocess == null){
                            throw new CustomException("小卷成退没有前道工序："+operationDo.getId());
                        }
                        planprocessrall = preprocess.getPlanprocessrall();
                    }else{
                        planprocessrall = new BigDecimal(operationDo.getPlanprocessrall())
                                .divide(new BigDecimal("20").divide(operationDo.getSinglerollweight(),2, BigDecimal.ROUND_HALF_UP)
                                        ,2, BigDecimal.ROUND_HALF_UP).setScale(0, RoundingMode.CEILING).intValue();
                    }
                    Integer ys = operationDo.getPlanprocessrall() % planprocessrall;
                    Integer js = operationDo.getPlanprocessrall() / planprocessrall;
                    for (Integer i = 0; i < planprocessrall; i++) {
                        ProductionProcesses processes = productionProcessesDetailInit(operationDo, produceOrder, optionalEquipments,outMaterDos,apsBlankOrderVo,processOperationEquDos);
                        // 已排程的作业明细数据保持ID不变
                        if(processEquDos != null && i<processEquDos.size()){
                            processes.setId(processEquDos.get(i).getId());
                            // 锁定作业的关联关系设置
                            if(StrUtil.isNotBlank(processEquDos.get(i).getPreviousprocessesids())){
                                processes.setPreviousProcessesIds(new ArrayList<>(Arrays.asList(processEquDos.get(i).getPreviousprocessesids().split(","))));
                            }
                            if(StrUtil.isNotBlank(processEquDos.get(i).getNextprocessesids())){
                                processes.setNextProcessesIds(new ArrayList<>(Arrays.asList(processEquDos.get(i).getNextprocessesids().split(","))));
                            }
                            if("Y".equals(processEquDos.get(i).getLockmarkdetail())){
                                processes.setIfLock(true);
                                processes.setEquipmentId(processEquDos.get(i).getProcessdeviceid());
                                List<String> opeqs = new ArrayList<>();
                                opeqs.add(processEquDos.get(i).getProcessdeviceid());
                                processes.setOptionalEquipments(opeqs);
                                processes.setDelay(0);
                                processes.setStartTime(processEquDos.get(i).getPlanstartdate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                                processes.setEndTime(processEquDos.get(i).getPlanenddate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                            }
                            // 判断是否已取消
                            if(processEquDos.get(i).getCancelroll() != null && processEquDos.get(i).getCancelroll()>=processEquDos.get(i).getPlanprocessrall()){
                                processes.setCancel(true);
                            }
                        }

                        if(apsBlankOrderVo.getPlanhavematerialdate() != null){
                            // 全局配置
                            ApsOverallConfig apsOverallConfig = new ApsOverallConfig();
                            Date startDate = apsBlankOrderVo.getPlanhavematerialdate();
                            LocalDateTime startTime = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                            apsOverallConfig.setStartTimeLong(startDate.getTime());
                            apsOverallConfig.setStartTime(startTime);
                            // 排程全局配置
                            apsOverallConfig.setRoamTime(productionScheduleVo.getRoamTime());
                            apsOverallConfig.setWashingtime(productionScheduleVo.getWashingtime());
                            apsOverallConfig.setStandingtime(productionScheduleVo.getStandingtime());
                            apsOverallConfig.setClosealloynames(productionScheduleVo.getClosealloynames());
                            apsOverallConfig.setFurnaceInstallations(productionScheduleVo.getFurnaceInstallations());
                            apsOverallConfig.setMergeFurnaces(productionScheduleVo.getMergeFurnaces());
                            apsOverallConfig.setLooseness(productionScheduleVo.getLooseness());
                            apsOverallConfig.setStandingyield(productionScheduleVo.getStandingyield());
                            processes.setApsOverallConfig(apsOverallConfig);
                        }
                        Integer alls = js;
                        if(i<ys){
                            alls = alls + 1;
                        }
                        processes.setProducePcNum(planprocessrall);
                        processes.setMinThPcNum(alls);
                        processes.setSinglerollweight(operationDo.getSinglerollweight().multiply(new BigDecimal(alls)));

                        operationProcess.add(processes);
                    }

                } else if ("小卷包装".equals(operationDo.getProcess())) {
                    String previousprocessid = operationDo.getPreviousprocessid();
                    ApsProcessOperationDo preprocess = apsProcessOperationService.getById(previousprocessid);
                    if(preprocess == null){
                        throw new CustomException("小卷成退没有前道工序："+operationDo.getId());
                    }
                    if("小卷成退".equals(preprocess.getProcess())){
                        preprocess = apsProcessOperationService.getById(preprocess.getPreviousprocessid());
                    }
                    Integer planprocessrall = null;
                    if(preprocess == null){
                        planprocessrall = new BigDecimal(operationDo.getPlanprocessrall())
                                .divide(new BigDecimal("20").divide(operationDo.getSinglerollweight(),2, BigDecimal.ROUND_HALF_UP)
                                        ,2, BigDecimal.ROUND_HALF_UP).setScale(0, RoundingMode.CEILING).intValue();
                    }else{
                        planprocessrall = preprocess.getPlanprocessrall();
                    }
                    Integer ys = operationDo.getPlanprocessrall() % planprocessrall;
                    Integer js = operationDo.getPlanprocessrall() / planprocessrall;
                    for (Integer i = 0; i < planprocessrall; i++) {
                        ProductionProcesses processes = productionProcessesDetailInit(operationDo, produceOrder, optionalEquipments,outMaterDos,apsBlankOrderVo,processOperationEquDos);
                        // 已排程的作业明细数据保持ID不变
                        if(processEquDos != null && i<processEquDos.size()){
                            processes.setId(processEquDos.get(i).getId());
                            // 锁定作业的关联关系设置
                            if(StrUtil.isNotBlank(processEquDos.get(i).getPreviousprocessesids())){
                                processes.setPreviousProcessesIds(new ArrayList<>(Arrays.asList(processEquDos.get(i).getPreviousprocessesids().split(","))));
                            }
                            if(StrUtil.isNotBlank(processEquDos.get(i).getNextprocessesids())){
                                processes.setNextProcessesIds(new ArrayList<>(Arrays.asList(processEquDos.get(i).getNextprocessesids().split(","))));
                            }
                            if("Y".equals(processEquDos.get(i).getLockmarkdetail())){
                                processes.setIfLock(true);
                                processes.setEquipmentId(processEquDos.get(i).getProcessdeviceid());
                                List<String> opeqs = new ArrayList<>();
                                opeqs.add(processEquDos.get(i).getProcessdeviceid());
                                processes.setOptionalEquipments(opeqs);
                                processes.setDelay(0);
                                processes.setStartTime(processEquDos.get(i).getPlanstartdate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                                processes.setEndTime(processEquDos.get(i).getPlanenddate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                            }
                            // 判断是否已取消
                            if(processEquDos.get(i).getCancelroll() != null && processEquDos.get(i).getCancelroll()>=processEquDos.get(i).getPlanprocessrall()){
                                processes.setCancel(true);
                            }
                        }
                        if(apsBlankOrderVo.getPlanhavematerialdate() != null){
                            // 全局配置
                            ApsOverallConfig apsOverallConfig = new ApsOverallConfig();
                            Date startDate = apsBlankOrderVo.getPlanhavematerialdate();
                            LocalDateTime startTime = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                            apsOverallConfig.setStartTimeLong(startDate.getTime());
                            apsOverallConfig.setStartTime(startTime);
                            // 排程全局配置
                            apsOverallConfig.setRoamTime(productionScheduleVo.getRoamTime());
                            apsOverallConfig.setWashingtime(productionScheduleVo.getWashingtime());
                            apsOverallConfig.setStandingtime(productionScheduleVo.getStandingtime());
                            apsOverallConfig.setClosealloynames(productionScheduleVo.getClosealloynames());
                            apsOverallConfig.setFurnaceInstallations(productionScheduleVo.getFurnaceInstallations());
                            apsOverallConfig.setMergeFurnaces(productionScheduleVo.getMergeFurnaces());
                            apsOverallConfig.setLooseness(productionScheduleVo.getLooseness());
                            apsOverallConfig.setStandingyield(productionScheduleVo.getStandingyield());
                            processes.setApsOverallConfig(apsOverallConfig);
                        }
                        Integer alls = js;
                        if(i<ys){
                            alls = alls + 1;
                        }
                        processes.setProducePcNum(planprocessrall);
                        processes.setMinThPcNum(alls);
                        processes.setProduceTime(operationDo.getOnceprocessmin().intValue() * alls);

                        operationProcess.add(processes);
                    }
                }else{
                    for (Integer i = 0; i < operationDo.getPlanprocessrall()-operationDo.getCancelrollsum(); i++) {
                        ProductionProcesses processes = productionProcessesDetailInit(operationDo, produceOrder, optionalEquipments,outMaterDos,apsBlankOrderVo,processOperationEquDos);
                        // 已排程的作业明细数据保持ID不变
                        if(processEquDos != null && i<processEquDos.size()){
                            processes.setId(processEquDos.get(i).getId());
                            // 锁定作业的关联关系设置
                            if(StrUtil.isNotBlank(processEquDos.get(i).getPreviousprocessesids())){
                                processes.setPreviousProcessesIds(new ArrayList<>(Arrays.asList(processEquDos.get(i).getPreviousprocessesids().split(","))));
                            }
                            if(StrUtil.isNotBlank(processEquDos.get(i).getNextprocessesids())){
                                processes.setNextProcessesIds(new ArrayList<>(Arrays.asList(processEquDos.get(i).getNextprocessesids().split(","))));
                            }
                            if("Y".equals(processEquDos.get(i).getLockmarkdetail())){
                                processes.setIfLock(true);
                                processes.setEquipmentId(processEquDos.get(i).getProcessdeviceid());
                                List<String> opeqs = new ArrayList<>();
                                opeqs.add(processEquDos.get(i).getProcessdeviceid());
                                processes.setOptionalEquipments(opeqs);
                                processes.setDelay(0);
                                processes.setStartTime(processEquDos.get(i).getPlanstartdate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                                processes.setEndTime(processEquDos.get(i).getPlanenddate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                            }
                            // 判断是否已取消
                            if(processEquDos.get(i).getCancelroll() != null && processEquDos.get(i).getCancelroll()>=processEquDos.get(i).getPlanprocessrall()){
                                processes.setCancel(true);
                            }
                        }
                        if(apsBlankOrderVo.getPlanhavematerialdate() != null){
                            // 全局配置
                            ApsOverallConfig apsOverallConfig = new ApsOverallConfig();
                            Date startDate = apsBlankOrderVo.getPlanhavematerialdate();
                            LocalDateTime startTime = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                            apsOverallConfig.setStartTimeLong(startDate.getTime());
                            apsOverallConfig.setStartTime(startTime);
                            // 排程全局配置
                            apsOverallConfig.setRoamTime(productionScheduleVo.getRoamTime());
                            apsOverallConfig.setWashingtime(productionScheduleVo.getWashingtime());
                            apsOverallConfig.setStandingtime(productionScheduleVo.getStandingtime());
                            apsOverallConfig.setClosealloynames(productionScheduleVo.getClosealloynames());
                            apsOverallConfig.setFurnaceInstallations(productionScheduleVo.getFurnaceInstallations());
                            apsOverallConfig.setMergeFurnaces(productionScheduleVo.getMergeFurnaces());
                            apsOverallConfig.setLooseness(productionScheduleVo.getLooseness());
                            apsOverallConfig.setStandingyield(productionScheduleVo.getStandingyield());
                            processes.setApsOverallConfig(apsOverallConfig);
                        }
                        operationProcess.add(processes);
                    }
                }
            }
            processesList.addAll(operationProcess);
            operationProductionProcesses.put(operationDo.getId(),operationProcess);
        }
    }

    private ProductionProcesses productionProcessesDetailInit(ApsProcessOperationDo operationDo,ProduceOrder produceOrder
            ,List<String> optionalEquipments,List<ApsProcessOperationOutMaterDo> outMaterDos,ApsBlankOrderVo apsBlankOrderVo,List<ApsProcessOperationEquDo> processOperationEquDos){
        String warnPreMsg = "坯料计划号："+apsBlankOrderVo.getBlanknumber()+"  作业类型："+operationDo.getProcess()+"  作业名称："+operationDo.getProcessname();
        ProductionProcesses processes = new ProductionProcesses();
        // 工序所属订单
        processes.setProduceOrder(Arrays.asList(new ProduceOrder[]{produceOrder}));
        // 模型ID
        processes.setId(SecurityUtil.getUUID());
        // 业务表主键ID
        List<String> bss = new ArrayList<>();
        bss.add(operationDo.getId());
        processes.setBsProcessesId(bss);
        processes.setProcessName(operationDo.getProcessname());
        // 工序任务可选设备
        processes.setOptionalEquipments(optionalEquipments);
        // 批次
        processes.setProducePcNum(operationDo.getPlanprocessrall());
        processes.setOpeProducePcNum(1);
        processes.setProcessType(operationDo.getProcess());
        // 单次加工时长
        if(operationDo.getOnceprocessmin() == null){
            throw new CustomException(warnPreMsg + "的作业单卷加工时间为空");
        }
        // 是否分卷作业
        processes.setIssubsection(operationDo.getIssubsection());
        processes.setUnitProduceTime(operationDo.getOnceprocessmin().intValue());
        processes.setProduceTime(operationDo.getOnceprocessmin().intValue());
        // 轧辊ID
        List<ApsProcessOperationEquDo> operationEquDos = processOperationEquDos.stream().filter(v ->
                v.getBlankid().equals(operationDo.getBlankid()) && v.getMainid().equals(operationDo.getId())).collect(Collectors.toList());
        if(operationEquDos != null && operationEquDos.size()>0){
            Map<String,String> optionalEquipmentZg = new HashMap<>();
            for (ApsProcessOperationEquDo operationEquDo : operationEquDos) {
                optionalEquipmentZg.put(operationEquDo.getResourceid(),operationEquDo.getRollerid());
            }
            processes.setOptionalEquipmentZg(optionalEquipmentZg);
        }
        // 单卷宽度和重量
        if(operationDo.getProwidth() == null){
            throw new CustomException(warnPreMsg + "的作业单卷宽度为空");
        }
        if(operationDo.getSinglerollweight() == null){
            throw new CustomException(warnPreMsg + "的作业单卷重量为空");
        }
        if(operationDo.getThickness() == null){
            throw new CustomException(warnPreMsg + "的作业单卷厚度为空");
        }
        processes.setVolumeWidth(operationDo.getProwidth());
        processes.setSinglerollweight(operationDo.getSinglerollweight());
        processes.setVolumeThickness(operationDo.getThickness());
        if (operationDo.getMinflowwaitmin() != null) {
            processes.setMinWaitTime(operationDo.getMinflowwaitmin().intValue());
        }
        if (operationDo.getMaxflowwaitmin() != null) {
            processes.setMaxWaitTime(operationDo.getMaxflowwaitmin().intValue());
        }
        // 合金
        if(operationDo.getMetal() == null){
            throw new CustomException(warnPreMsg + "的作业合金为空");
        }
        processes.setVolumeMetal(operationDo.getMetal());
        if("成退".equals(operationDo.getProcess()) || "中退".equals(operationDo.getProcess()) || "小卷成退".equals(operationDo.getProcess())){
            processes.setVolumeMetalstate(outMaterDos.get(0).getMetalstate());
        }else{
            processes.setVolumeMetalstate(operationDo.getMetalstate());
        }
        processes.setProducttype(operationDo.getProducttype());
        // 连续生产标识设置
        // 合金+输入物料+宽度+输入物料厚度+输出物料厚度（取第一个冷轧工序使用）
        processes.setSeriesProduceMark(operationDo.getMetal() + "^_^" + operationDo.getProducttype() + "^_^" + operationDo.getProwidth() + "^_^" + operationDo.getThickness() + "^_^" + outMaterDos.get(0).getThickness());
        processes.setPrepressworkmin(operationDo.getPrepressworkmin() == null ? null : operationDo.getPrepressworkmin().intValue());
        processes.setCutfinishmin(operationDo.getCutfinishmin() == null ? null : operationDo.getCutfinishmin().intValue());
        return processes;
    }

}
