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.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.rongwei.bscommon.sys.dao.*;
import com.rongwei.bscommon.sys.fegin.RwApsServer;
import com.rongwei.bscommon.sys.service.*;
import com.rongwei.bscommon.sys.utils.ApsUtils;
import com.rongwei.bsentity.domain.*;
import com.rongwei.bsentity.vo.*;
import com.rongwei.rwadmincommon.system.vo.SysUserVo;
import com.rongwei.rwcommon.base.BaseDo;
import com.rongwei.rwcommon.base.R;
import com.rongwei.rwcommon.base.exception.CustomException;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

import static com.rongwei.bscommon.sys.service.impl.ApsProductionOrderServiceImpl.ERROR_MSG;
import static com.rongwei.safecommon.utils.SaveConstans.DatePattern.DATE_PATTERN_YMDHMS;
import static com.rongwei.safecommon.utils.SaveConstans.JobStatus.JOBSTATUS_TO_BE_START;
import static com.rongwei.safecommon.utils.SaveConstans.LockmarkType.LOCKMARK_N;
import static com.rongwei.safecommon.utils.SaveConstans.LockmarkType.LOCKMARK_Y;
import static com.rongwei.safecommon.utils.SaveConstans.ProductionStatus.*;
import static com.rongwei.safecommon.utils.SaveConstans.SchedulingStatus.PUBLISHED;

/**
 * <p>
 * 生产订单_坯料计划 服务实现类
 * </p>
 *
 * @author fpy
 * @since 2024-03-01
 */
@Service
public class ApsBlankOrderServiceImpl extends ServiceImpl<ApsBlankOrderDao, ApsBlankOrderDo> implements ApsBlankOrderService {

    private static final Logger logger = LoggerFactory.getLogger(ApsBlankOrderServiceImpl.class);

    @Autowired
    private ApsProcessOperationService apsProcessOperationService;
    @Autowired
    private AspCheckItemsService aspCheckItemsService;
    @Autowired
    private ApsBlankOrderDao apsBlankOrderDao;
    @Autowired
    private RwApsServer rwApsServer;
    @Autowired
    private ApsProcessOperationProcessEquServiceImpl processOperationProcessEquService;
    @Autowired
    private ApsScheduleConfigService apsScheduleConfigService;
    @Autowired
    private ApsProductionOrderService apsProductionOrderService;
    @Autowired
    private ApsProcessOperationBackupDao apsProcessOperationBackupDao;
    @Autowired
    private ApsProcessOperationProcessEquBackupDao apsProcessOperationProcessEquBackupDao;
    @Autowired
    private ApsProductionOrderDao apsProcessOperationDao;
    @Autowired
    private ApsProductDetailService apsProductDetailService;
    @Autowired
    private ApsProductDetailDao apsProductDetailDao;
    @Autowired
    private ApsWorkInProgressInventoryService apsWorkInProgressInventoryService;
    @Autowired
    private ApsProcessOutputProductService apsProcessOutputProductService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void test() {
        ApsBlankOrderDo a1 = this.getById("19fcf845701746968602e5298f7b9144");
        this.removeById("19fcf845701746968602e5298f7b9144");
        ApsBlankOrderDo a2 = this.getById("19fcf845701746968602e5298f7b9144");
        System.out.println(a1.getMaterialname());
    }

    /**
     * 取消订单排程
     *
     * @param apsProductionOrderIds
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderApsCancel(List<String> apsProductionOrderIds) throws Exception {
        if (apsProductionOrderIds.isEmpty()) {
            log.debug("取消排程参数为空");
            return;
        }
        // 获取坯料计划
        List<ApsBlankOrderDo> blankOrderDos = this.list(new LambdaQueryWrapper<ApsBlankOrderDo>()
                .in(ApsBlankOrderDo::getProductionorderid, apsProductionOrderIds));
        if (blankOrderDos.isEmpty()) {
            return;
        }
        // 校验取消的订单中是否存在已加工的工序作业
        List<String> startWorkOrderNo = apsProcessOperationDao.getStartWorkById(apsProductionOrderIds);
        if (!startWorkOrderNo.isEmpty()) {
            throw new CustomException(CollUtil.join(startWorkOrderNo, ",") + " 以上客户所对应的订单存在已开工的坯料计划，不可以取消排程=!");
        }
        List<String> blankids = blankOrderDos.stream().map(ApsBlankOrderDo::getId).collect(Collectors.toList());
        //清除排程备份和状态修改
        deleteBackup(blankids, apsProductionOrderIds);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void blankApsCancel(List<String> apsBlankIds) {
        if (ObjectUtil.isEmpty(apsBlankIds)) {
            log.debug("坯料计划排程取消参数为空");
            return;
        }
        // 判断批量计划是否存在已开工的数据
        // 校验取消的订单中是否存在已加工的工序作业
        List<String> startWorkOrderNo = apsProcessOperationDao.getStartWorkByBlankId(apsBlankIds);
        if (!startWorkOrderNo.isEmpty()) {
            throw new CustomException(CollUtil.join(startWorkOrderNo, ",") + " 以上客户所对应的订单存在已开工的坯料计划，不可以取消排程=!");
        }
        //获取订单ID
        List<ApsBlankOrderDo> blankOrderDoList = this.list(new QueryWrapper<ApsBlankOrderDo>().lambda().in(ApsBlankOrderDo::getId, apsBlankIds));
        Set<String> orderIds = blankOrderDoList.stream().map(ApsBlankOrderDo::getProductionorderid).collect(Collectors.toSet());
        //清除排程备份
        deleteBackup(apsBlankIds, new ArrayList<>(orderIds));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R publish(List<String> blankIds) {
        if (blankIds == null || blankIds.isEmpty()) {
            log.debug("坯料计划为空");
            return R.error("坯料计划id 必传");
        }
        // 校验是否存在冲突的工序作业明细
        int i = this.baseMapper.checkConflictByBlankId(blankIds);
        if (i != 0) {
            logger.error("所选坯料计划:{}存在冲突", blankIds);
            return R.error("请先解决排程冲突在发布");
        }
        // 判断是否存在已发布的工序作业
        List<ApsBlankOrderDo> apsBlankOrderDos = this.baseMapper.selectBatchIds(blankIds);
        List<String> searchCondition = new ArrayList<String>() {{
            add("30");
            add("20");
            add("10");
        }};
        List<ApsBlankOrderDo> collect1 = apsBlankOrderDos.stream().filter(info -> !searchCondition.contains(info.getProductstatus())).collect(Collectors.toList());
        if (!collect1.isEmpty()) {
            logger.error("存在已开工的坯料计划：{}", collect1);
            return R.error("存在已开工的坯料计划");
        }
        // 如果 订单排程交货期>承诺交货期 抛出异常信息
        List<ApsProductionOrderDo> dataByBlankId = apsProcessOperationDao.getDataByBlankId(blankIds);
        if (!dataByBlankId.isEmpty()) {
            String collect = dataByBlankId.stream()
                    .map(info -> info.getOrderno() + "-" + info.getCustomname())
                    .collect(Collectors.joining(";"));
            logger.error("存在排程交货期大于承诺交货期 的订单：{}", collect);
            return R.error(String.format(ERROR_MSG, collect));
        }
        // 获取工序作业明细信息判断是否存在 冲突或者警告
        List<ApsProcessOperationProcessEquDo> processOperationProcessEquDos = processOperationProcessEquService.list(new LambdaQueryWrapper<ApsProcessOperationProcessEquDo>()
                .in(ApsProcessOperationProcessEquDo::getBlankid, blankIds)
                .eq(BaseDo::getDeleted, "0"));
        if(processOperationProcessEquDos.isEmpty()){
            log.error("当前坯料计划不存在工序作业明细");
            return R.error("无法根据坯料计划找到工序作业明细");
        }
        // 判断是否存在强制冲突不为空的数据
        boolean b = processOperationProcessEquDos.stream().anyMatch(info -> StringUtils.isNotBlank(info.getConflictdes()));
        if(b){
            log.error("存在强制冲突无法发布");
            return R.error("请先解决冲突在发布");
        }
        // 更新坯料计划的生产状态为已发布
        this.update(new LambdaUpdateWrapper<ApsBlankOrderDo>().in(ApsBlankOrderDo::getId, blankIds)
                .set(ApsBlankOrderDo::getProductstatus, "30")
                .set(ApsBlankOrderDo::getSchedulingstatus, PUBLISHED)
                .set(ApsBlankOrderDo::getLockmark, LOCKMARK_Y));
        // 更新坯料计划对应工序作业的状态为待开工
        apsProcessOperationService.update(new LambdaUpdateWrapper<ApsProcessOperationDo>()
                .in(ApsProcessOperationDo::getBlankid, blankIds)
                .set(ApsProcessOperationDo::getProcessstatus, "30")
                .set(ApsProcessOperationDo::getLockmark, LOCKMARK_Y)
                .set(ApsProcessOperationDo::getWorkstatus, JOBSTATUS_TO_BE_START));
        // 更新坯料计划对应产品明细的生产状态为待开工
        apsProductDetailDao.updateProductStatusByBlankId(blankIds, "30");
        // 更新工序作业明细的生产状态为待开工
        processOperationProcessEquService.update(new LambdaUpdateWrapper<ApsProcessOperationProcessEquDo>()
                .in(ApsProcessOperationProcessEquDo::getId, processOperationProcessEquDos.stream().map(ApsProcessOperationProcessEquDo::getId).collect(Collectors.toList()))
                .set(ApsProcessOperationProcessEquDo::getLockmark, LOCKMARK_Y)
                .set(ApsProcessOperationProcessEquDo::getWorkstatus, JOBSTATUS_TO_BE_START)
        );
        List<String> collect = apsBlankOrderDos.stream().map(ApsBlankOrderDo::getProductionorderid).distinct().collect(Collectors.toList());
        // 更新工序作业的状态
        apsProcessOperationDao.publish(collect);
        // 根据坯料ID 删除 备份数据
        ApsUtils.clearBackup(null);
        return R.ok();
    }

    /**
     * 取消发布
     *
     * @param blankIds
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R publishCancel(List<String> blankIds) {
        if (blankIds == null || blankIds.isEmpty()) {
            log.debug("坯料计划为空");
            return R.error("坯料计划id 必传");
        }
        List<String> searchCondition = new ArrayList<String>() {{
            add("40");
            add("50");
        }};
        // 判断是否存在已发布的工序作业
        List<ApsBlankOrderDo> apsBlankOrderDos = this.baseMapper.selectBatchIds(blankIds);
        List<ApsBlankOrderDo> collect1 = apsBlankOrderDos.stream().filter(info -> searchCondition.contains(info.getProductstatus())).collect(Collectors.toList());
        if (!collect1.isEmpty()) {
            logger.error("存在已开工的坯料计划：{}", collect1);
            return R.error("存在已开工的坯料计划");
        }
        // 更新坯料计划的生产状态为已发布
        this.update(new LambdaUpdateWrapper<ApsBlankOrderDo>().in(ApsBlankOrderDo::getId, blankIds)
                .set(ApsBlankOrderDo::getProductstatus, "20")
                .set(ApsBlankOrderDo::getSchedulingstatus, TO_BE_PUBLISHED)
                .set(ApsBlankOrderDo::getLockmark, LOCKMARK_N));
        // 更新坯料计划对应工序作业的状态为待开工
        apsProcessOperationService.update(new LambdaUpdateWrapper<ApsProcessOperationDo>()
                .in(ApsProcessOperationDo::getBlankid, blankIds)
                .set(ApsProcessOperationDo::getProcessstatus, "20")
                .set(ApsProcessOperationDo::getLockmark, LOCKMARK_N)
                .set(ApsProcessOperationDo::getWorkstatus, JOBSTATUS_TO_BE_START));
        // 更新坯料计划对应产品明细的生产状态为待开工
        apsProductDetailDao.updateProductStatusByBlankId(blankIds, "20");
        // 更新工序作业明细的生产状态为待开工
        processOperationProcessEquService.update(new LambdaUpdateWrapper<ApsProcessOperationProcessEquDo>()
                .in(ApsProcessOperationProcessEquDo::getBlankid, blankIds)
                .set(ApsProcessOperationProcessEquDo::getLockmark, LOCKMARK_N)
                .set(ApsProcessOperationProcessEquDo::getWorkstatus, JOBSTATUS_TO_BE_START)
        );
        List<String> collect = apsBlankOrderDos.stream().map(ApsBlankOrderDo::getProductionorderid).distinct().collect(Collectors.toList());
        // 更新工序作业的状态
        apsProcessOperationDao.publishCancel(collect);
        // 根据坯料ID 删除 备份数据
        ApsUtils.clearBackup(null);
        return R.ok();
    }

    /*
    插单
     */
    @Override
    public R insertOrder(Map<String, Object> params) throws Exception {
        String productionOrderId = params.get("PRODUCTIONORDERID").toString();
        String blankOrderId = params.get("BLANKORDERID").toString();
        String deliveryDateStr = params.get("DELIVERYDATE").toString();
        SimpleDateFormat formatter = new SimpleDateFormat(DATE_PATTERN_YMDHMS);
        Date deliveryDate = formatter.parse(deliveryDateStr);

        //更新订单期望交货期
        ApsProductionOrderDo productionOrderDo = apsProductionOrderService.getById(productionOrderId);
        productionOrderDo.setDeliverydate(deliveryDate);
        boolean bool1 = apsProductionOrderService.updateById(productionOrderDo);

        // 更新坯料计划的生产状态为已发布
        boolean bool2 = this.update(new LambdaUpdateWrapper<ApsBlankOrderDo>().eq(ApsBlankOrderDo::getId, blankOrderId)
                .set(ApsBlankOrderDo::getLockmark, LOCKMARK_N));

        // 解锁订单所有作业状态=待开工的作业明细（是否锁定=否）
        boolean bool3 = apsProcessOperationService.update(new LambdaUpdateWrapper<ApsProcessOperationDo>()
                .eq(ApsProcessOperationDo::getBlankid, blankOrderId)
                .eq(ApsProcessOperationDo::getWorkstatus, JOBSTATUS_TO_BE_START)
                .set(ApsProcessOperationDo::getLockmark, LOCKMARK_N));

        if (bool1 && bool2 && bool3) {
            //重新排程
            this.apsReScheduling();
            return R.ok();
        } else {
            return R.error();
        }
    }

    /**
     * 获取锁定和解锁的 搜索事件
     *
     * @param lockStartTime
     * @param startSchedulerun
     * @return
     */
    private Date orderLockGetSearChDate(Date lockStartTime, int startSchedulerun, String lockMark) {
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.HOUR_OF_DAY, startSchedulerun);
        Date time = instance.getTime();
        if (LOCKMARK_Y.equals(lockMark)) {
            return lockStartTime.compareTo(time) > 0 ? lockStartTime : time;
        } else {
            return lockStartTime.compareTo(time) > 0 ? lockStartTime : time;
        }
    }

    /**
     * 锁定、解锁
     *
     * @param orderLockVo
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R orderLock(OrderLockVo orderLockVo) {
        String lockMark = orderLockVo.getLockMark();
        if (StringUtils.isBlank(lockMark)) {
            log.error("锁定状态必填");
            return R.error("锁定状态必填");
        }
        List<String> blackOrderId = orderLockVo.getBlackOrderId();
        blackOrderId = blackOrderId.stream().filter(StringUtils::isNotBlank).collect(Collectors.toList());
        Date lockStartTime = orderLockVo.getLockStartTime();
        if (blackOrderId.isEmpty() && lockStartTime == null) {
            log.error("坯料计划ID和解锁时间都为空");
            return R.error("坯料计划ID和解锁时间都为空");
        }

        if (!blackOrderId.isEmpty()) {
            // 校验坯料计划是否开工
            Integer integer = apsBlankOrderDao.selectCount(new LambdaQueryWrapper<ApsBlankOrderDo>()
                    .in(ApsBlankOrderDo::getId, blackOrderId)
                    .in(ApsBlankOrderDo::getProductstatus, "40", "50"));
            if (integer > 0) {
                log.error("所选作业坯料计划已开工，不可以解锁");
                return R.error("所选作业坯料计划已开工，不可以解锁");
            }
        }
        if (lockStartTime != null) {
            // 获取排程参数设置
            List<ApsScheduleConfigDo> apsConfigs = apsScheduleConfigService.list();
            // 默认最小排程时间
            int defaultStartStartSchedulerun = 8;
            if (!apsConfigs.isEmpty()) {
                defaultStartStartSchedulerun = apsConfigs.get(0).getStartschedulerun();
            }
            Date date = orderLockGetSearChDate(lockStartTime, defaultStartStartSchedulerun, lockMark);
            // 获取所有 待发布 待开工的 坯料计划
            blackOrderId = this.baseMapper.getIdByLockTime(date, lockMark);
        }
        if (blackOrderId.isEmpty()) {
            log.debug("暂无需要锁定或者解锁的批量计划");
            return R.ok("暂无需要锁定或者解锁的批量计划");
        }
        // 组装待更新坯料计划实体
        List<ApsBlankOrderDo> blankOrderDos = new ArrayList<>();

        for (String id : blackOrderId) {
            ApsBlankOrderDo blankOrderDo = new ApsBlankOrderDo();
            blankOrderDo.setId(id);
            blankOrderDo.setLockmark(lockMark);
            if (LOCKMARK_N.equals(lockMark)) {
                blankOrderDo.setProductstatus("20");
            }
            blankOrderDos.add(blankOrderDo);
        }
        // 坯料计划锁定标识更新
        if (blankOrderDos.size() > 0) {
            this.updateBatchById(blankOrderDos);
        }
        // 工序作业锁定标识更新
        apsProcessOperationService.update(new LambdaUpdateWrapper<ApsProcessOperationDo>()
                .set(ApsProcessOperationDo::getLockmark, lockMark)
                .in(ApsProcessOperationDo::getBlankid, blackOrderId));
        // 工序作业排程计划锁定
        processOperationProcessEquService.update(new LambdaUpdateWrapper<ApsProcessOperationProcessEquDo>()
                .set(ApsProcessOperationProcessEquDo::getLockmark, lockMark)
                .in(ApsProcessOperationProcessEquDo::getBlankid, blackOrderId));
        if (LOCKMARK_N.equals(lockMark)) {
            // 更新坯料计划对应工序作业的生产状态为待发布
            apsProcessOperationService.update(new LambdaUpdateWrapper<ApsProcessOperationDo>()
                    .in(ApsProcessOperationDo::getBlankid, blackOrderId)
                    .set(ApsProcessOperationDo::getProcessstatus, "20"));
        }
        // 回传坯料计划ID 用于前段更新锁定状态
        return R.ok(blackOrderId);
    }

    /**
     * 重新排程
     * 所有待发布的未锁定的订单重新排程
     */
    @Override
    public void apsReScheduling() throws Exception {
        //获取当前用户的所属工厂
        SysUserVo currentUser = CXCommonUtils.getCurrentUser();
        String tenantId = currentUser.getOrganizationDoList().get(0).getFullpid().split(",")[1];

        List<ApsBlankOrderVo> notLockOrders = apsBlankOrderDao.getNotLockOrders(tenantId);
        blankOrderAps(notLockOrders);
        //更新生产状态为“待发布”（20）
        updateProductStatusByOrderIds(notLockOrders.stream().map(ApsBlankOrderVo::getProductionorderid).collect(Collectors.toSet()));
    }

    /**
     * 订单批量排程
     *
     * @param apsPlanVo
     */
    public void apsScheduling(ApsPlanVo apsPlanVo) throws Exception {
        List<ApsBlankOrderVo> apsBlankOrders = new ArrayList<>();
        if (apsPlanVo.getApsProductionOrders() != null) {
            for (ApsProductionOrderDo apsProductionOrder : apsPlanVo.getApsProductionOrders()) {
                List<ApsBlankOrderVo> byOrderId = apsBlankOrderDao.getByOrderId(apsProductionOrder.getId());
                if (byOrderId != null && byOrderId.size() > 0) {
                    apsBlankOrders.addAll(byOrderId);
                }
            }
        }
        if (apsPlanVo.getApsBlankOrderDos() != null && apsPlanVo.getApsBlankOrderDos().size() > 0) {
            apsBlankOrders.addAll(apsPlanVo.getApsBlankOrderDos());
        }
        //去重
        Set<String> blankIds = new HashSet<>();
        //去重后的坯料计划集合
        List<ApsBlankOrderVo> resBlankList = new LinkedList<>();
        for (ApsBlankOrderVo apsBlankOrder : apsBlankOrders) {
            String id = apsBlankOrder.getId();
            if (blankIds.contains(id)) {
                continue;
            }
            blankIds.add(id);
            resBlankList.add(apsBlankOrder);
        }
        blankOrderAps(resBlankList);
        //blankOrderAps(apsBlankOrders);
        //更新生产状态为“待发布”（20）
        updateProductStatusByOrderIds(resBlankList.stream().map(ApsBlankOrderVo::getProductionorderid).collect(Collectors.toSet()));
    }

    /**
     * 生产订单排程
     *
     * @param apsBlankOrders
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void blankOrderAps(List<ApsBlankOrderVo> apsBlankOrders) {
        assert apsBlankOrders != null : "排程订单不能为空";
        // 合并待发布未锁定的订单一起排程
        List<String> hasIds = apsBlankOrders.stream().map(v -> v.getId()).collect(Collectors.toList());
        String idStrs = CollUtil.join(hasIds, "','");
        idStrs = "'" + idStrs + "'";
        // 查询存在未锁定的作业坯料计划
        List<ApsBlankOrderVo> fbNotLock = apsBlankOrderDao.getFbNotLock(idStrs);
        if (fbNotLock != null && fbNotLock.size() > 0) {
            apsBlankOrders.addAll(fbNotLock);
        }

        // 先删除所有作业的明细
        List<String> blankids = apsBlankOrders.stream().map(v -> v.getId()).collect(Collectors.toList());
        processOperationProcessEquService.remove(new LambdaUpdateWrapper<ApsProcessOperationProcessEquDo>().in(ApsProcessOperationProcessEquDo::getBlankid, blankids));
        // 模型转换
        ProductionScheduleVo productionScheduleVo = apsPlanModelSet(apsBlankOrders);
        JSONConfig jsonConfig = JSONConfig.create();
        jsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("排程数据：" + JSONUtil.toJsonStr(productionScheduleVo, jsonConfig));
        logger.info("排程数据：" + JSONUtil.toJsonStr(productionScheduleVo, jsonConfig));
        // APS平台排程接口调用
        ProductionScheduleRetVo productionScheduleRetVo = rwApsServer.productionSchedule(productionScheduleVo);
        // 排程结果保存
        List<ApsProcessOperationProcessEquDo> apsProcessOperationProcessEquDos = new ArrayList<>();
        // 最后节点集合
        List<ProductionProcesses> lastProcess = new ArrayList<>();
        if (productionScheduleRetVo.getProcesses() != null && productionScheduleRetVo.getProcesses().size() > 0) {
            for (ProductionProcesses process : productionScheduleRetVo.getProcesses()) {
                // 非合并生产工序
                if (process.getAluminumCoils() == null) {
                    ApsProcessOperationProcessEquDo apsProcessOperationProcessEqu = new ApsProcessOperationProcessEquDo();
                    apsProcessOperationProcessEqu.setId(SecurityUtil.getUUID());
                    apsProcessOperationProcessEqu.setProcessid(process.getId());
                    apsProcessOperationProcessEqu.setBlankid(process.getProduceOrder().get(0).getId());
                    apsProcessOperationProcessEqu.setProcessdeviceid(process.getEquipment().getId());
                    apsProcessOperationProcessEqu.setProcessdevice(process.getEquipment().getEquipmentName());
                    apsProcessOperationProcessEqu.setProcessworkshopid(process.getEquipment().getWorkshopid());
                    apsProcessOperationProcessEqu.setProcessworkshop(process.getEquipment().getWorkshopname());
                    apsProcessOperationProcessEqu.setTenantid(process.getEquipment().getFactoryid());
                    apsProcessOperationProcessEqu.setPlanstartdate(Date.from(process.getStartTime().atZone(ZoneId.systemDefault()).toInstant()));
                    apsProcessOperationProcessEqu.setPlanenddate(Date.from(process.getEndTime().atZone(ZoneId.systemDefault()).toInstant()));
                    apsProcessOperationProcessEqu.setPlanprocessrall(process.getProducePcNum());
                    apsProcessOperationProcessEqu.setHasconflict(process.getHasConflict());
                    apsProcessOperationProcessEqu.setConflictdes(process.getConflictDes());
                    apsProcessOperationProcessEqu.setSoftconflictdes(process.getSoftconflictdes());
                    apsProcessOperationProcessEqu.setDeleted("0");
                    apsProcessOperationProcessEquDos.add(apsProcessOperationProcessEqu);
                }
                // 合并生产工序
                else {
                    // 保存到明细表
                    Map<String, List<AluminumCoil>> bsAl = new HashMap<>();
                    for (AluminumCoil aluminumCoil : process.getAluminumCoils()) {
                        if (bsAl.containsKey(aluminumCoil.getBsId())) {
                            bsAl.get(aluminumCoil.getBsId()).add(aluminumCoil);
                        } else {
                            List<AluminumCoil> coils = new ArrayList<>();
                            coils.add(aluminumCoil);
                            bsAl.put(aluminumCoil.getBsId(), coils);
                        }
                    }
                    bsAl.forEach((k, v) -> {
                        ApsProcessOperationProcessEquDo apsProcessOperationProcessEqu = new ApsProcessOperationProcessEquDo();
                        apsProcessOperationProcessEqu.setId(SecurityUtil.getUUID());
                        apsProcessOperationProcessEqu.setProcessid(k);
                        apsProcessOperationProcessEqu.setBlankid(v.get(0).getBlankid());
                        apsProcessOperationProcessEqu.setProcessdeviceid(process.getEquipment().getId());
                        apsProcessOperationProcessEqu.setProcessdevice(process.getEquipment().getEquipmentName());
                        apsProcessOperationProcessEqu.setPlanstartdate(Date.from(process.getStartTime().atZone(ZoneId.systemDefault()).toInstant()));
                        apsProcessOperationProcessEqu.setPlanenddate(Date.from(process.getEndTime().atZone(ZoneId.systemDefault()).toInstant()));
                        apsProcessOperationProcessEqu.setPlanprocessrall(v.size());
                        apsProcessOperationProcessEqu.setProcessworkshopid(process.getEquipment().getWorkshopid());
                        apsProcessOperationProcessEqu.setProcessworkshop(process.getEquipment().getWorkshopname());
                        apsProcessOperationProcessEqu.setTenantid(process.getEquipment().getFactoryid());
                        apsProcessOperationProcessEqu.setHasconflict(process.getHasConflict());
                        apsProcessOperationProcessEqu.setConflictdes(process.getConflictDes());
                        apsProcessOperationProcessEqu.setSoftconflictdes(process.getSoftconflictdes());
                        apsProcessOperationProcessEqu.setDeleted("0");
                        apsProcessOperationProcessEquDos.add(apsProcessOperationProcessEqu);
                    });
                }

                // 是否为最后一个节点
                if (process.getNextProcessesIds() == null || process.getNextProcessesIds().size() == 0) {
                    lastProcess.add(process);
                }
            }
        }
        if (apsProcessOperationProcessEquDos != null && apsProcessOperationProcessEquDos.size() > 0) {
            // 再保存新数据
            processOperationProcessEquService.saveBatch(apsProcessOperationProcessEquDos);
            // 回写订单排程交货期
            Map<String, Date> orderDeliveryTime = new HashMap<>();
            for (ProductionProcesses process : lastProcess) {
                List<ProduceOrder> produceOrder = process.getProduceOrder();
                if (produceOrder != null && produceOrder.size() > 0) {
                    for (ProduceOrder order : produceOrder) {
                        Date endDate = Date.from(process.getEndTime().atZone(ZoneId.systemDefault()).toInstant());
                        ApsBlankOrderDo blankOrder = this.getById(order.getId());
                        if (orderDeliveryTime.containsKey(blankOrder.getProductionorderid())) {
                            // 对比取最大值
                            if (endDate.compareTo(orderDeliveryTime.get(blankOrder.getProductionorderid())) > 0) {
                                orderDeliveryTime.put(blankOrder.getProductionorderid(), endDate);
                            }
                        } else {
                            orderDeliveryTime.put(blankOrder.getProductionorderid(), endDate);
                        }
                    }
                }
            }
            // 更新订单的排程交货期、排程状态
            if (orderDeliveryTime.size() > 0) {
                orderDeliveryTime.forEach((k, v) -> {
                    ApsProductionOrderDo productionOrderDo = apsProductionOrderService.getById(k);
                    ApsProductionOrderDo apsProductionOrderDo = new ApsProductionOrderDo();
                    apsProductionOrderDo.setId(k);
                    apsProductionOrderDo.setScheduledeliverydate(v);
                    if (productionOrderDo.getDeliverytime() != null && productionOrderDo.getDeliverytime() > 0 && v != null) {
                        apsProductionOrderDo.setScheduledeliverydate(DateUtil.offsetHour(v, productionOrderDo.getDeliverytime()));
                    }
                    // 排程状态更新为待发布
//                    apsProductionOrderDo.setSchedulstatus(SCHEDULSTATUS_TORELEASE);
                    apsProductionOrderService.updateById(apsProductionOrderDo);
                });
            }

        }

        backupProcessOperation(apsProcessOperationProcessEquDos, productionScheduleRetVo.getProcesses());
    }

    /**
     * 工序作业备份
     *
     * @param apsProcessOperationProcessEquDos
     * @param processes
     */
    private void backupProcessOperation(List<ApsProcessOperationProcessEquDo> apsProcessOperationProcessEquDos,
                                        List<ProductionProcesses> processes) {


        // 工序作业明细ID
        List<String> apsProcessOperationIds = processes.stream().map(ProductionProcesses::getId).distinct().collect(Collectors.toList());
        SysUserVo currentUser = CXCommonUtils.getCurrentUser();
        //删除备份
        ApsUtils.clearBackup(null);
        //增加备份
        List<List<String>> partition1 = Lists.partition(apsProcessOperationIds, 500);
        partition1.forEach(data -> {
            apsProcessOperationBackupDao.processOperationBackup(apsProcessOperationIds,
                    currentUser == null ? null : currentUser.getId(), currentUser == null ? null : currentUser.getName());
        });
        List<List<ApsProcessOperationProcessEquDo>> partition = Lists.partition(apsProcessOperationProcessEquDos, 100);
        partition.forEach(data -> {
            apsProcessOperationProcessEquBackupDao.processOperationEquBackup(apsProcessOperationProcessEquDos,
                    currentUser == null ? null : currentUser.getId(), currentUser == null ? null : currentUser.getName());
        });

    }

    /**
     * 原始订单表数据转换APS平台模型数据
     *
     * @param apsBlankOrders
     * @return
     */
    @Override
    public ProductionScheduleVo apsPlanModelSet(List<ApsBlankOrderVo> apsBlankOrders) {
        ProductionScheduleVo productionScheduleVo = new ProductionScheduleVo();
        productionScheduleVo.setProductionScheduleId("批量排程");
        List<ApsScheduleConfigDo> apsConfigs = apsScheduleConfigService.list();
        ApsScheduleConfigDo apsScheduleConfig = null;
        // 松散度
        BigDecimal looseness = null;
        if (apsConfigs != null && apsConfigs.size() > 0) {
            apsScheduleConfig = apsConfigs.get(0);
            looseness = apsScheduleConfig.getLooseness();
            productionScheduleVo.setPlanSeconds(apsScheduleConfig.getScheduleruntime());
            Map<String, Integer> roamTime = new HashMap<>();
            Integer workshopin = new BigDecimal(apsScheduleConfig.getWorkshopin()).multiply((looseness.divide(new BigDecimal("100"))).add(new BigDecimal("1")))
                    .setScale(0, RoundingMode.CEILING).intValue();
            Integer workshopcross = new BigDecimal(apsScheduleConfig.getWorkshopin()).multiply((looseness.divide(new BigDecimal("100"))).add(new BigDecimal("1")))
                    .setScale(0, RoundingMode.CEILING).intValue();
            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));
            }
        } else {
            throw new CustomException("排程参数缺失");
        }

        // 所有设备
        List<AspCheckItemsDo> eqs = aspCheckItemsService.list(new LambdaQueryWrapper<>());
        Map<String, AspCheckItemsDo> eqMaps = new HashMap<>();
        for (AspCheckItemsDo eq : eqs) {
            eqMaps.put(eq.getId(), eq);
        }
        // 排程计划设备集合
        List<Equipment> equipmentList = new ArrayList<>();
        // 排程计划工序任务集合
        List<ProductionProcesses> processesList = new ArrayList<>();
        // 待合并生产的订单工序
        List<ApsProcessOperationVo> processOperationMs = new ArrayList<>();
        if (apsBlankOrders != null && apsBlankOrders.size() > 0) {
            for (ApsBlankOrderVo apsBlankOrderVo : apsBlankOrders) {
                // 坯料计划订单
                ProduceOrder produceOrder = new ProduceOrder(apsBlankOrderVo.getId(), apsBlankOrderVo.getMaterialname(), apsBlankOrderVo.getDeliverydate());
                // 获取所有订单工序
                List<ApsProcessOperationDo> operationDos = apsProcessOperationService.list(new LambdaQueryWrapper<ApsProcessOperationDo>()
                        .eq(ApsProcessOperationDo::getBlankid, apsBlankOrderVo.getId()));
                // 转换工序模型数据
                for (ApsProcessOperationDo operationDo : operationDos) {
                    ProductionProcesses processes = new ProductionProcesses();
                    // 工序所属订单
                    processes.setProduceOrder(Arrays.asList(new ProduceOrder[]{produceOrder}));
                    // 判断是否合并生产工序,加工方式是“合并加工”
                    String productprocess = operationDo.getProcessway();
                    // 设备列表
                    List<String> optionalEquipments = new ArrayList<>();
                    if (StringUtils.isNotBlank(operationDo.getCanchoosedeviceid())) {
                        String[] sbIds = operationDo.getCanchoosedeviceid().split(",");
                        for (String equIds : sbIds) {
                            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());
                                    // 查询设备锁定的已排程的时间段
                                    List<ApsProcessOperationProcessEquDo> processEqus = processOperationProcessEquService.list(new LambdaQueryWrapper<ApsProcessOperationProcessEquDo>()
                                            .eq(ApsProcessOperationProcessEquDo::getProcessdeviceid, equIds)
                                            .ge(ApsProcessOperationProcessEquDo::getPlanstartdate, productionScheduleVo.getApsPlanStartDate())
                                            .orderByAsc(ApsProcessOperationProcessEquDo::getPlanstartdate)
                                    );
                                    // 查询当前设备最后一个生产任务、连续生产需要考虑使用
                                    List<ApsProcessOperationProcessEquDo> processLastEqus = processOperationProcessEquService.list(new LambdaQueryWrapper<ApsProcessOperationProcessEquDo>()
                                            .eq(ApsProcessOperationProcessEquDo::getProcessdeviceid, equIds)
                                            .gt(ApsProcessOperationProcessEquDo::getPlanstartdate, productionScheduleVo.getApsPlanStartDate())
                                            .orderByAsc(ApsProcessOperationProcessEquDo::getPlanstartdate)
                                    );
                                    if(processLastEqus != null && processLastEqus.size()>0){
                                        ApsProcessOperationProcessEquDo lastpro = processLastEqus.get(processLastEqus.size()-1);
                                        ApsProcessOperationDo lastop = apsProcessOperationService.getById(lastpro.getProcessid());
                                        equipment.setLastProcessType(lastop.getProcess());
                                        // 铸轧
                                        if ("铸轧".equals(lastop.getProcess())) {
                                            // 合金+宽度
                                            equipment.setLastSeriesProduceMark(lastop.getMetal() + "^_^" + lastop.getProwidth());
                                        }
                                        // 冷轧
                                        else if ("冷轧".equals(lastop.getProcess())) {
                                            // 合金+输入物料+宽度
                                            equipment.setLastSeriesProduceMark(lastop.getMetal() + "^_^" + lastop.getPlaninput() + "^_^" + lastop.getProwidth());
                                        }
                                    }
                                    // 查询相关工序作业
                                    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<EquipmentRunTime> equipmentRunTimes = new ArrayList<>();
                                        for (ApsProcessOperationProcessEquDo equs : processEqus) {
                                            EquipmentRunTime er = new EquipmentRunTime();
                                            er.setStartRunTime(equs.getPlanstartdate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                                            er.setEndRunTime(equs.getPlanenddate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                                            equipmentRunTimes.add(er);
                                            // 设备占用时间设置连续生产标识，参与排程
                                            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);
                                                    er.setProcessType(processesDo.getProcess());
                                                    // 铸轧
                                                    if ("铸轧".equals(processesDo.getProcess())) {
                                                        // 合金+宽度
                                                        er.setSeriesProduceMark(operationDo.getMetal() + "^_^" + operationDo.getProwidth());
                                                    }
                                                    // 冷轧
                                                    else if ("冷轧".equals(processesDo.getProcess())) {
                                                        // 合金+输入物料+宽度
                                                        er.setSeriesProduceMark(operationDo.getMetal() + "^_^" + operationDo.getPlaninput() + "^_^" + operationDo.getProwidth());
                                                    }
                                                }
                                            }
                                        }
                                        equipment.setEquipmentRunTimes(equipmentRunTimes);
                                    }
                                    equipmentList.add(equipment);
                                }
                            }
                        }
                    }

                    if (SaveConstans.ProcessWay.PROCESS_WAY_MERGE.equals(productprocess)) {
                        // 合并生产工序
                        ApsProcessOperationVo processOperationVo = new ApsProcessOperationVo();
                        BeanUtil.copyProperties(operationDo, processOperationVo);
                        processOperationVo.setProduceOrder(produceOrder);
                        processOperationVo.setDeliverydate(apsBlankOrderVo.getDeliverydate());
                        processOperationVo.setApsBlankOrderVo(apsBlankOrderVo);
                        processOperationMs.add(processOperationVo);
                    } else {
                        // 非合并生产工序

                        // 模型ID
                        processes.setId(operationDo.getId());
                        // 业务表主键ID
                        List<String> bss = new ArrayList<>();
                        bss.add(operationDo.getId());
                        processes.setBsProcessesId(bss);
                        // 工序任务可选设备
                        processes.setOptionalEquipments(optionalEquipments);
                        // 批次
                        processes.setProducePcNum(operationDo.getPlanprocessrall());
                        processes.setProcessType(operationDo.getProcess());
                        // 单次加工时长
                        processes.setUnitProduceTime(operationDo.getOnceprocessmin().intValue());
//                        processes.setProduceTime(processes.getUnitProduceTime()*processes.getProducePcNum());
                        processes.setProduceTime(operationDo.getProcesstotaltime().intValue());
                        if(operationDo.getMinflowwaitmin() != null){
                            processes.setMinWaitTime(operationDo.getMinflowwaitmin().intValue());
                        }
                        if (operationDo.getMaxflowwaitmin() != null) {
                            processes.setMaxWaitTime(operationDo.getMaxflowwaitmin().intValue());
                        }
                        // 上道工序
                        if (StringUtils.isNotBlank(operationDo.getPreviousprocessid())) {
                            processes.setPreviousProcessesIds(Arrays.asList(operationDo.getPreviousprocessid().split(",")));
                        }
                        // 下道工序
                        if (StringUtils.isNotBlank(operationDo.getNextprocessid())) {
                            processes.setNextProcessesIds(Arrays.asList(operationDo.getNextprocessid().split(",")));
                        }
                        // 连续生产标识设置
                        // 铸轧
                        if ("铸轧".equals(processes.getProcessType())) {
                            // 合金+宽度
                            processes.setSeriesProduceMark(operationDo.getMetal() + "^_^" + operationDo.getProwidth());
                        }
                        // 冷轧
                        else if ("冷轧".equals(processes.getProcessType())) {
                            // 合金+输入物料+宽度
                            processes.setSeriesProduceMark(operationDo.getMetal() + "^_^" + operationDo.getPlaninput() + "^_^" + operationDo.getProwidth());
                        }

                        processesList.add(processes);
                    }
                }
            }
        }
        // 合并生产工序
        List<ProductionProcesses> productionProcesses = mergeProcesses(processOperationMs, eqMaps,apsScheduleConfig);
        processesList.addAll(productionProcesses);
        // 加工时间松散度设置
        /*if(looseness != null){
            for (ProductionProcesses process : processesList) {
                // 加工时间乘以松散度并向上取整
                process.setProduceTime(new BigDecimal(process.getProduceTime()).multiply((looseness.divide(new BigDecimal("100"))).add(new BigDecimal("1"))).setScale(0, RoundingMode.CEILING).intValue());
            }
        }*/
        productionScheduleVo.setProcesses(processesList);
        productionScheduleVo.setEquipmentList(equipmentList);
        return productionScheduleVo;
    }

    /**
     * 合并生产工序
     *
     * @param processOperationMs
     * @return
     */
    private List<ProductionProcesses> mergeProcesses(List<ApsProcessOperationVo> processOperationMs, Map<String, AspCheckItemsDo> eqMaps,ApsScheduleConfigDo apsScheduleConfig) {
        // 最终的合并工序
        List<ProductionProcesses> processesList = new ArrayList<>();
        if (processOperationMs != null && processOperationMs.size() > 0) {
            // 按照期望交货期排序
            processOperationMs.sort(Comparator.comparing(ApsProcessOperationVo::getDeliverydate));
            // 获取所有设备，并按已存在最晚完工时间排序
            String allSelEqs = null;
            for (ApsProcessOperationVo processOperationM : processOperationMs) {
                if (StringUtils.isNotBlank(processOperationM.getCanchoosedeviceid())) {
                    String[] sbIds = processOperationM.getCanchoosedeviceid().split(",");
                    for (String equIds : sbIds) {
                        if (allSelEqs == null) {
                            allSelEqs = "'" + equIds + "'";
                        } else {
                            if (!allSelEqs.contains(equIds)) {
                                allSelEqs = allSelEqs + ",'" + equIds + "'";
                            }
                        }
                    }
                }
            }
            // 设备排序
            List<AspCheckItemsDo> aspCheckItemsDos = apsBlankOrderDao.eqAscs(allSelEqs);
            // 记录当前设备已排程个数
            Map<String, Integer> aspCheckItemUse = new HashMap<>();
            Map<String, AspCheckItemsDo> aspCheckItemMap = new HashMap<>();
            for (AspCheckItemsDo aspCheckItemsDo : aspCheckItemsDos) {
                aspCheckItemMap.put(aspCheckItemsDo.getId(), aspCheckItemsDo);
                aspCheckItemUse.put(aspCheckItemsDo.getId(), 0);
                // 退火炉套筒间隙扣除
                if(apsScheduleConfig != null){
                    aspCheckItemsDo.setEquipmentwidth(aspCheckItemsDo.getEquipmentwidth().subtract(apsScheduleConfig.getLooseness()));
                }
            }
            for (ApsProcessOperationVo processOperationM : processOperationMs) {
                // 首先查看是否有可以合并的已存在的工序
                hasProcessmerge(processesList, processOperationM, aspCheckItemMap);
                // 剩下作业加工卷数,启用新的作业
                int planprocessrall = processOperationM.getPlanprocessrall();
                if (planprocessrall <= 0) {
                    continue;
                }
                Boolean a = true;
                while (a) {
                    int lastnum = processOperationM.getPlanprocessrall();
                    // 剩余的料卷
                    if (lastnum > 0) {
                        Integer minUse = null;
                        int haslast = 0;
                        AspCheckItemsDo aspCheckItem = null;
                        for (int i = 0; i < aspCheckItemsDos.size(); i++) {
                            // 选择的设备要在可选设备的范围内
                            if (processOperationM.getCanchoosedeviceid().contains(aspCheckItemsDos.get(i).getId())) {
                                // 单卷宽度不能超过设备宽度并且单卷重不能超过设备的承重
                                if (processOperationM.getProwidth().compareTo(aspCheckItemsDos.get(i).getEquipmentwidth()) < 0
                                        && processOperationM.getSinglerollweight().compareTo(aspCheckItemsDos.get(i).getEquipmentbearing()) < 0) {
                                    // 获取使用次数最小的可选设备
                                    if (aspCheckItem == null) {
                                        minUse = aspCheckItemUse.get(aspCheckItemsDos.get(i).getId());
                                        aspCheckItem = aspCheckItemsDos.get(i);
                                    } else {
                                        if (minUse > aspCheckItemUse.get(aspCheckItemsDos.get(i).getId())) {
                                            minUse = aspCheckItemUse.get(aspCheckItemsDos.get(i).getId());
                                            aspCheckItem = aspCheckItemsDos.get(i);
                                        }
                                    }
                                }
                            }
                        }
                        // 新增工序作业
                        if (aspCheckItem != null) {
                            // 选择的设备要在可选设备的范围内
                            if (processOperationM.getCanchoosedeviceid().contains(aspCheckItem.getId())) {
                                // 单卷宽度不能超过设备宽度并且单卷重不能超过设备的承重
                                if (processOperationM.getProwidth().compareTo(aspCheckItem.getEquipmentwidth()) < 0
                                        && processOperationM.getSinglerollweight().compareTo(aspCheckItem.getEquipmentbearing()) < 0) {
                                    for (int n = 1; n <= lastnum; n++) {
                                        // 宽度余量
                                        if (aspCheckItem.getEquipmentwidth().compareTo(processOperationM.getProwidth().multiply(new BigDecimal(n))) < 0) {
                                            break;
                                        }
                                        // 重量余量
                                        if (aspCheckItem.getEquipmentbearing().compareTo(processOperationM.getSinglerollweight().multiply(new BigDecimal(n))) < 0) {
                                            break;
                                        }
                                        haslast = n;
                                    }
                                    if (haslast > 0) {
                                        ProductionProcesses processes = new ProductionProcesses();
                                        processes.setId(SecurityUtil.getUUID());
                                        List<String> bss = new ArrayList<>();
                                        bss.add(processOperationM.getId());
                                        processes.setBsProcessesId(bss);
                                        processes.setProcessType(processOperationM.getProcess());
                                        processes.setOptionalEquipments(Arrays.asList(new String[]{aspCheckItem.getId()}));
                                        // 坯料计划订单
                                        ProduceOrder produceOrder = new ProduceOrder(processOperationM.getApsBlankOrderVo().getId(), processOperationM.getApsBlankOrderVo().getMaterialname(), processOperationM.getApsBlankOrderVo().getDeliverydate());
                                        List<ProduceOrder> produceOrders = new ArrayList<>();
                                        produceOrders.add(produceOrder);
                                        processes.setProduceOrder(produceOrders);

                                        processes.setAluminumCoils(new ArrayList<>());
                                        for (int j = 1; j <= haslast; j++) {
                                            AluminumCoil aluminumCoil = new AluminumCoil();
                                            aluminumCoil.setBsId(processOperationM.getId());
                                            aluminumCoil.setBlankid(processOperationM.getBlankid());
                                            aluminumCoil.setVolumeWidth(processOperationM.getProwidth());
                                            aluminumCoil.setVolumeThickness(processOperationM.getThickness());
                                            aluminumCoil.setVolumeWeight(processOperationM.getSinglerollweight());
                                            aluminumCoil.setVolumeMetal(processOperationM.getMetal());
                                            aluminumCoil.setVolumeMetalstate(processOperationM.getMetalstate());
                                            processes.getAluminumCoils().add(aluminumCoil);
                                        }
                                        // 批次
                                        processes.setProducePcNum(1);
                                        // 最小等待时长
                                        if (processOperationM.getMinflowwaitmin() != null) {
                                            processes.setMinWaitTime(processOperationM.getMinflowwaitmin().intValue());
                                        }
                                        // 最大等待时长
                                        if (processOperationM.getMaxflowwaitmin() != null) {
                                            processes.setMaxWaitTime(processOperationM.getMaxflowwaitmin().intValue());
                                        }
                                        // 合并加工的为瓶颈工序
                                        processes.setBottleneck(true);
                                        // 单次加工时长
                                        processes.setUnitProduceTime(processOperationM.getOnceprocessmin().intValue());
                                        processes.setProduceTime(processOperationM.getOnceprocessmin().intValue());
                                        // 上道工序
                                        if (StringUtils.isNotBlank(processOperationM.getPreviousprocessid())) {
                                            processes.setPreviousProcessesIds(new ArrayList<>(Arrays.asList(processOperationM.getPreviousprocessid().split(","))));
                                        }
                                        // 下道工序
                                        if (StringUtils.isNotBlank(processOperationM.getNextprocessid())) {
                                            processes.setNextProcessesIds(new ArrayList<>(Arrays.asList(processOperationM.getNextprocessid().split(","))));
                                        }
                                        processesList.add(processes);

                                        lastnum = lastnum - haslast;
                                        // 更新设备使用次数
                                        aspCheckItemUse.put(aspCheckItem.getId(), aspCheckItemUse.get(aspCheckItem.getId()) + 1);
                                    }
                                }
                            }
                        }
                    }
                    // 重新设置计划加工卷数
                    processOperationM.setPlanprocessrall(lastnum);
                    if (lastnum <= 0) {
                        a = false;
                    }
                }
            }
        }
        return processesList;
    }

    /**
     * 查看是否有可以合并的已存在的工序
     *
     * @param processesList
     * @param processOperationM
     * @param aspCheckItemMap
     */
    private void hasProcessmerge(List<ProductionProcesses> processesList, ApsProcessOperationVo processOperationM, Map<String, AspCheckItemsDo> aspCheckItemMap) {
        // 首先看已合并生产的设备是否还有余量继续排产
        for (ProductionProcesses processes : processesList) {
            // 加工设备
            String eq = processes.getOptionalEquipments().get(0);
            AspCheckItemsDo aspCheckItem = aspCheckItemMap.get(eq);

            // 工序类型一致，合金和合金状态要一致
            if (processes.getProcessType().equals(processOperationM.getProcess()) && processes.getAluminumCoils().get(0).getVolumeMetal().equals(processOperationM.getMetal())
                    && processes.getAluminumCoils().get(0).getVolumeMetalstate().equals(processOperationM.getMetalstate())) {
                // 宽度不超过50mm，厚度不超过0.05mm，重量不超过1吨
                boolean bol = true;
                BigDecimal totalWidth = null;
                BigDecimal totalWeight = null;
                // 宽度、厚度、重量绝对值差限制
                BigDecimal knum = null;
                BigDecimal hnum = null;
                BigDecimal znum = null;
                if (SaveConstans.ProcessType.PROCESS_TYPE_CHENTUI.equals(processes.getProcessType())) {
                    knum = new BigDecimal("50");
                    hnum = new BigDecimal("0.05");
                    znum = new BigDecimal("1");
                } else if (SaveConstans.ProcessType.PROCESS_TYPE_ZHONGTUI.equals(processes.getProcessType())) {
                    knum = new BigDecimal("100");
                    hnum = new BigDecimal("0.08");
                    znum = new BigDecimal("1");
                }
                if (knum == null || hnum == null || znum == null) {
                    continue;
                }

                for (AluminumCoil aluminumCoil : processes.getAluminumCoils()) {
                    // 宽度不超过50mm
                    if (aluminumCoil.getVolumeWidth().subtract(processOperationM.getProwidth()).abs().compareTo(knum) > 0) {
                        bol = false;
                    }
                    // 厚度不超过0.05mm
                    if (aluminumCoil.getVolumeThickness().subtract(processOperationM.getThickness()).abs().compareTo(hnum) > 0) {
                        bol = false;
                    }
                    // 重量不超过1吨
                    if (aluminumCoil.getVolumeWeight().subtract(processOperationM.getSinglerollweight()).abs().compareTo(znum) > 0) {
                        bol = false;
                    }
                    if (totalWidth == null) {
                        totalWidth = aluminumCoil.getVolumeWidth();
                    } else {
                        totalWidth = totalWidth.add(aluminumCoil.getVolumeWidth());
                    }
                    if (totalWeight == null) {
                        totalWeight = aluminumCoil.getVolumeWeight();
                    } else {
                        totalWeight = totalWeight.add(aluminumCoil.getVolumeWeight());
                    }
                }
                if (bol) {
                    Integer sy = 0;
                    for (int j = 1; j <= processOperationM.getPlanprocessrall(); j++) {
                        // 宽度余量
                        if (aspCheckItem.getEquipmentwidth().subtract(totalWidth).compareTo(processOperationM.getProwidth().multiply(new BigDecimal(j))) < 0) {
                            break;
                        }
                        // 重量余量
                        if (aspCheckItem.getEquipmentbearing().subtract(totalWeight).compareTo(processOperationM.getSinglerollweight().multiply(new BigDecimal(j))) < 0) {
                            break;
                        }
                        sy = j;
                    }
                    if (sy > 0) {
                        // 更新计划加工卷数
                        processOperationM.setPlanprocessrall(processOperationM.getPlanprocessrall() - sy);
                        for (int j = 1; j <= sy; j++) {
                            AluminumCoil aluminumCoil = new AluminumCoil();
                            aluminumCoil.setBsId(processOperationM.getId());
                            aluminumCoil.setBlankid(processOperationM.getBlankid());
                            aluminumCoil.setVolumeWidth(processOperationM.getProwidth());
                            aluminumCoil.setVolumeThickness(processOperationM.getThickness());
                            aluminumCoil.setVolumeWeight(processOperationM.getSinglerollweight());
                            aluminumCoil.setVolumeMetal(processOperationM.getMetal());
                            aluminumCoil.setVolumeMetalstate(processOperationM.getMetalstate());
                            processes.getAluminumCoils().add(aluminumCoil);
                        }

                        // 上道工序
                        if (StringUtils.isNotBlank(processOperationM.getPreviousprocessid())) {
                            if (processes.getPreviousProcessesIds() == null) {
                                List<String> list = new ArrayList<>();
                                list.addAll(Arrays.asList(processOperationM.getPreviousprocessid().split(",")));
                                processes.setPreviousProcessesIds(list);
                            } else {
                                processes.getPreviousProcessesIds().addAll(new ArrayList<>(Arrays.asList(processOperationM.getPreviousprocessid().split(","))));
                            }
                        }
                        // 下道工序
                        if (StringUtils.isNotBlank(processOperationM.getNextprocessid())) {
                            if (processes.getNextProcessesIds() == null) {
                                List<String> list = new ArrayList<>();
                                list.addAll(Arrays.asList(processOperationM.getNextprocessid().split(",")));
                                processes.setNextProcessesIds(list);
                            } else {
                                processes.getNextProcessesIds().addAll(new ArrayList<>(Arrays.asList(processOperationM.getNextprocessid().split(","))));
                            }
                        }
                        // 所属订单
                        List<ProduceOrder> produceOrders = processes.getProduceOrder().stream().filter(v ->
                                v.getId().equals(processOperationM.getApsBlankOrderVo().getId())).collect(Collectors.toList());
                        if (produceOrders == null || produceOrders.size() == 0) {
                            ProduceOrder produceOrder = new ProduceOrder(processOperationM.getApsBlankOrderVo().getId(), processOperationM.getApsBlankOrderVo().getMaterialname(), processOperationM.getApsBlankOrderVo().getDeliverydate());
                            processes.getProduceOrder().add(produceOrder);
                        }
                        // 单次加工时长
                        if (processes.getUnitProduceTime() == null) {
                            processes.setUnitProduceTime(processOperationM.getOnceprocessmin().intValue());
                            processes.setProduceTime(processOperationM.getOnceprocessmin().intValue());
                        }
                        // 加工时长取最大值
                        else {
                            if (processes.getUnitProduceTime() < processOperationM.getOnceprocessmin().intValue()) {
                                processes.setUnitProduceTime(processOperationM.getOnceprocessmin().intValue());
                                processes.setProduceTime(processOperationM.getOnceprocessmin().intValue());
                            }
                        }
                        processes.getBsProcessesId().add(processOperationM.getId());
                    }
                }
            }
        }
    }

    private void checkIfCanMerge(){

    }

    /**
     * 排程结束之后根据订单IDs修改生产状态
     */
    private void updateProductStatusByOrderIds(Set<String> orderIds) {
        String idStrs = CollUtil.join(orderIds, "','");
        idStrs = "'" + idStrs + "'";

        //更新工序作业的生产状态为‘待发布’(20)
        this.baseMapper.updateProcessOperationByOrderIds(idStrs);
        //更新所有坯料计划的生产状态
        ApsBlankOrderDo apsBlankOrderDo = new ApsBlankOrderDo();
        apsBlankOrderDo.setProductstatus(TO_BE_PUBLISHED);
        apsBlankOrderDo.setSchedulingstatus(SaveConstans.SchedulingStatus.TO_BE_PUBLISHED);
        this.update(apsBlankOrderDo, new QueryWrapper<ApsBlankOrderDo>().lambda().in(ApsBlankOrderDo::getProductionorderid, orderIds).eq(ApsBlankOrderDo::getProductstatus, "10"));
        //更新所有产品明细的生产状态
        ApsProductDetailDo apsProductDetailDo = new ApsProductDetailDo();
        apsProductDetailDo.setProductstatus(TO_BE_PUBLISHED);
        apsProductDetailService.update(apsProductDetailDo, new QueryWrapper<ApsProductDetailDo>().lambda().in(ApsProductDetailDo::getMainid, orderIds).eq(ApsProductDetailDo::getProductstatus, "10"));
        //更新订单的生产状态
        ApsProductionOrderDo apsProductionOrderDo = new ApsProductionOrderDo();
        apsProductionOrderDo.setProductionstatus(TO_BE_PUBLISHED);
        apsProductionOrderService.update(apsProductionOrderDo, new QueryWrapper<ApsProductionOrderDo>().lambda().in(ApsProductionOrderDo::getId, orderIds).eq(ApsProductionOrderDo::getProductionstatus, "10"));
    }

    /**
     * 物理删除排程备份（工序作业备份【aps_process_operation_backup】、加工设备备份【aps_process_operation_process_equ_backup】）
     * 更新状态
     */
    public void deleteBackup(List<String> blankids, List<String> apsProductionOrderIds) {
        // 删除工序作业和工序作业明备份数据
        ApsUtils.clearBackup(null);
        // 更工序作业生产状态=待排程，是否锁定=否，
        apsProcessOperationService.update(new LambdaUpdateWrapper<ApsProcessOperationDo>()
                .in(ApsProcessOperationDo::getBlankid, blankids)
                .set(ApsProcessOperationDo::getProcessstatus,TO_BE_SCHEDULED)
                .set(ApsProcessOperationDo::getLockmark,LOCKMARK_N)
        );
        // 清空作业明细
        processOperationProcessEquService.remove(new LambdaUpdateWrapper<ApsProcessOperationProcessEquDo>()
                .in(ApsProcessOperationProcessEquDo::getBlankid, blankids));
        // 更新订单的排程状态
        List<ApsProductionOrderDo> productionOrderDos = new ArrayList<>();
        for (String apsProductionOrderId : apsProductionOrderIds) {
            ApsProductionOrderDo productionOrderDo = new ApsProductionOrderDo();
            productionOrderDo.setId(apsProductionOrderId);
//            productionOrderDo.setSchedulstatus(SaveConstans.SchedulstatusTyep.SCHEDULSTATUS_TOSCHEDULE);
            productionOrderDo.setScheduledeliverydate(null);
            productionOrderDo.setProductionstatus(TO_BE_SCHEDULED);
            productionOrderDos.add(productionOrderDo);
        }
        // 更新生产订单的状态
        apsProductionOrderService.updateBatchById(productionOrderDos);
        // 更新坯料计划的状态
        this.baseMapper.cancelSchedulingUpdate(blankids);
        //获取坯料计划用到的产品明细ID
        String idStrs = CollUtil.join(blankids, "','");
        idStrs = "'" + idStrs + "'";
        List<String> productIdList = this.baseMapper.selectOutputProductIdList(idStrs);
        List<ApsProductDetailDo> productDetailDoList = new LinkedList<>();
        for (String productId : productIdList) {
            ApsProductDetailDo apsProductDetailDo = new ApsProductDetailDo();
            apsProductDetailDo.setId(productId);
            apsProductDetailDo.setProductstatus(TO_BE_SCHEDULED);
            productDetailDoList.add(apsProductDetailDo);
        }
        // 更新坯料计划产品明细的的生产状态
        apsProductDetailService.updateBatchById(productDetailDoList);
//        apsProductDetailDao.updateProductstatus(apsProductionOrderIds);
    }

    @Override
    @Transactional
    public R checkAndSaveOrUpdateBlank(CheckAndSaveOrUpdateBlankReq req) {
        //获取坯料计划内容
        ApsBlankOrderDo apsBlankOrderDo = req.getApsBlankOrderDo();
        //获取当前用户信息
        //获取当前用户的所属工厂
        SysUserVo currentUser = CXCommonUtils.getCurrentUser();
        String tenantId = currentUser.getOrganizationDoList().get(0).getFullpid().split(",")[1];


        //=============校验坯料长度=================
        //如果坯料产品类型对应产品外观类型是铝板或板锭，并且坯料长度为空，则提示：坯料是铝板和板锭时长度必填
        if (ObjectUtil.isNotEmpty(apsBlankOrderDo.getProducttypeid())) {
            //目前数据字典存在3层关系，选择只能选择最后一层，二开查询最后一层的父节点对应数据的父节点，判断是否为铝板或板锭的主键ID
            String pid = this.baseMapper.selectDictAboutProductType(apsBlankOrderDo.getProductionorderid());
            //如果是铝板或板锭
            if (ObjectUtil.isNotEmpty(pid) && (pid.equals(SaveConstans.ProductionType.BANDING_ID) || pid.equals(SaveConstans.ProductionType.LVBAN_ID))) {
                //坯料长度为空
                if (ObjectUtil.isEmpty(apsBlankOrderDo.getProlength())) {
                    return R.error("坯料是铝板和板锭时长度必填");
                }
            }
        }
        //==============拼接工艺路线输出成品==============
        //查询坯料计划对应工艺路线的输出成品
        List<String> processOutputList = this.baseMapper.selectProcessByBlankId(apsBlankOrderDo.getId());
        if (processOutputList != null && processOutputList.size() > 0) {
            String outputProcessMaterial = "";
            //排序
            processOutputList.sort(String::compareTo);
            for (int i = 0; i < processOutputList.size(); i++) {
                outputProcessMaterial += "[" + (i + 1) + "]" + processOutputList.get(i);
                if (i < processOutputList.size() - 1) {
                    outputProcessMaterial += ",\r\n";
                }
            }
            apsBlankOrderDo.setOutputmaterial(outputProcessMaterial);
        } else {
            return R.error("工艺路线没有输出成品");
        }

        //=============校验输出成品==============
        //产品明细
        List<ApsProductDetailDo> apsProductDetailDoList = req.getApsProductDetailDoList();
        //输出成品
        List<ApsProcessOutputProductDo> apsProcessOutputProductDoList = req.getApsProcessOutputProductDoList();

        //如果坯料计划未开工(生产状态<=30)
        if (apsBlankOrderDo.getProductstatus().compareTo(TO_BE_STARTED) <= 0) {
            for (ApsProcessOutputProductDo apsProcessOutputProductDo : apsProcessOutputProductDoList) {
                boolean haveProductDetail = false;
                for (ApsProductDetailDo apsProductDetailDo : apsProductDetailDoList) {
                    //判断是否存在对应的产品明细
                    if (apsProcessOutputProductDo.getProductid().equals(apsProductDetailDo.getId())) {
                        haveProductDetail = true;

                        if (apsProductDetailDo.getInputmaterialdescription().equals(apsProcessOutputProductDo.getProductname())) {
                            //如果输出单卷重<单卷重（起）或 输出单卷重>单卷重（止），错误提示：输出成品：{订单产品} 输出单卷重不符合订单要求
                            if (apsProcessOutputProductDo.getOutputonerollweigth().compareTo(apsProductDetailDo.getSinglerollweightstart()) < 0
                                    || apsProcessOutputProductDo.getOutputonerollweigth().compareTo(apsProductDetailDo.getSinglerollweightend()) > 0) {
                                return R.error("输出成品：" + apsProcessOutputProductDo.getProductname() + " 输出单卷重不符合订单要求");
                            }
                        } else {//如果对应订单产品明细的订单产品字段值不等于输出成品的订单产品字段值，错误提示：输出成品：{订单产品} 对应订单产品已修改或已删除，请重新选择订单产品
                            return R.error("输出成品：" + apsProcessOutputProductDo.getProductname() + " 对应订单产品已修改或已删除，请重新选择订单产品");
                        }
                        break;
                    }
                }
                //存在对应的产品明细
                if (haveProductDetail) {
                    //如果输出单卷重>坯料单卷重，错误提示：输出单卷重不能超过坯料单卷重
                    //（注意：成品重量和坯料重量单位吨和公斤需要转换后比较）
                    //转化单卷重 单位统一为 公斤（kg）

                    //输出的单卷重
                    BigDecimal outputWeight = new BigDecimal(0);
                    //坯料的单卷重
                    BigDecimal blankWeight = new BigDecimal(0);
                    //统一输出的重量
                    //公斤/千克
                    if (apsProcessOutputProductDo.getCountunit().equals(SaveConstans.CountUnit.KG)) {
                        outputWeight = apsProcessOutputProductDo.getOutputonerollweigth();
                    }
                    //吨
                    if (apsProcessOutputProductDo.getCountunit().equals(SaveConstans.CountUnit.TON)) {
                        outputWeight = apsProcessOutputProductDo.getOutputonerollweigth().multiply(new BigDecimal(1000));
                    }

                    //统一坯料的重量
                    if (apsBlankOrderDo.getNumberunit().equals(SaveConstans.CountUnit.KG)) {
                        blankWeight = apsBlankOrderDo.getSinglerollweight();
                    }
                    if (apsBlankOrderDo.getNumberunit().equals(SaveConstans.CountUnit.TON)) {
                        blankWeight = apsBlankOrderDo.getSinglerollweight().multiply(new BigDecimal(1000));
                    }
                    //输出单卷重>坯料单卷重
                    if (outputWeight.compareTo(blankWeight) > 0) {
                        return R.error("输出成品：" + apsProcessOutputProductDo.getProductname() + " 输出单卷重不能超过坯料单卷重");
                    }
                } else {//不存在对应的产品明细
                    return R.error("输出成品：" + apsProcessOutputProductDo.getProductname() + " 对应订单产品已修改或已删除，请重新选择订单产品");
                }
            }
        }

        //不论坯料计划的状态，需要增加的判断
        for (ApsProcessOutputProductDo apsProcessOutputProductDo : apsProcessOutputProductDoList) {
            boolean haveProductDetail = false;
            for (ApsProductDetailDo apsProductDetailDo : apsProductDetailDoList) {
                //判断是否存在对应的产品明细
                if (apsProcessOutputProductDo.getProductid().equals(apsProductDetailDo.getId())) {
                    haveProductDetail = true;
                    //计划输出订单重量 > 对应订单产品订单总数量；错误提示：输出成品 {订单产品} 计划输出订单重量 不能大于 订单总数量
                    if (apsProcessOutputProductDo.getPlanoutputonerollweight().compareTo(apsProductDetailDo.getTotalordercount()) > 0) {
                        return R.error("输出成品：" + apsProcessOutputProductDo.getProductname() + " 计划输出订单重量 不能大于 订单总数量");
                    }
                }
            }
            if (!haveProductDetail && apsProcessOutputProductDo.getPlanoutputonerollweight().compareTo(new BigDecimal(0)) > 0) {
                return R.error("输出成品：" + apsProcessOutputProductDo.getProductname() + " 已修改或已删除，并已开工，计划输出订单重量 不能大于 0");
            }
        }

        //===========坯料计划保存之前的校验=============
        //校验坯料需求
        //后台校验备料:如果是备料计划，
        //并且保存前备料已经被其他计划员新增的备料计划选择并保存了
        //（即：坯料的是否备料=是，并且所选在制品的备料计划ID不为空，并且不是该备料计划ID），
        //则错误提示：所选在制品已被其他备料计划使用
        ApsWorkInProgressInventoryDo progressWork = null;
        if (apsBlankOrderDo.getPreparematerial().equals("是") && ObjectUtil.isNotEmpty(req.getProgressId())) {
            progressWork = apsWorkInProgressInventoryService.getById(req.getProgressId());
            if (ObjectUtil.isNotEmpty(progressWork.getPlanmaterialid())) {
                return R.error("所选在制品已被其他备料计划使用");
            }
        }

        //============校验工艺路线=============
        //如果坯料需求的坯料输出成品字段值不等于坯料需求的工艺输出成品字段值，错误提示：工艺路线输出成品与坯料输出成品不一致
        if (!apsBlankOrderDo.getOutputfinishproduct().equals(apsBlankOrderDo.getOutputmaterial())) {
            return R.error("工艺路线输出成品与坯料输出成品不一致");
        }
        //如果坯料需求的是否备料=是，并且首道工序作业的是否坯料工序=是，错误提示：工艺路线错误，首道工序作业是坯料工序，备料不能作为输入物料
        //是否备料
        if (apsBlankOrderDo.getPreparematerial().equals("是")) {
            //查询坯料计划的工序作业
            List<ApsProcessOperationDo> processOperationList = apsProcessOperationService.list(new QueryWrapper<ApsProcessOperationDo>().lambda().eq(ApsProcessOperationDo::getBlankid, apsBlankOrderDo.getId()));
            for (ApsProcessOperationDo processOperationDo : processOperationList) {
                //没有前道工序作业ID
                if (ObjectUtil.isEmpty(processOperationDo.getPreviousprocessid())) {
                    if (processOperationDo.getIfblankprocess().equals("是")) {
                        return R.error("工艺路线错误，首道工序作业是坯料工序，备料不能作为输入物料");
                    }
                    break;
                }
            }
        }

        //============校验工序作业=============
        Map<String, Object> params = new HashMap<>();
        params.put("BLANKID", apsBlankOrderDo.getId());
        R r = apsProcessOperationService.checkOperation(params);
        if (!(r.getCode().equals("200"))) {
            return R.error(r.getMsg());
        }

        //更新或保存坯料计划和输出成品
        apsBlankOrderDo.setTenantid(tenantId);
        this.saveOrUpdate(apsBlankOrderDo);
        for (ApsProcessOutputProductDo apsProcessOutputProductDo : apsProcessOutputProductDoList) {
            apsProcessOutputProductDo.setBlankid(apsBlankOrderDo.getId());
            apsProcessOutputProductDo.setTenantid(tenantId);
        }
        apsProcessOutputProductService.saveOrUpdateBatch(apsProcessOutputProductDoList);

        //如果在制品不为空，并且为新增备料
        if (ObjectUtil.isNotEmpty(req.getProgressId()) && apsBlankOrderDo.getPreparematerial().equals("是")) {
            //将对应备料库（在制品库存表【aps_work_in_progress_inventory表】）中的备料计划ID（PLANMATERIALID）字段设置为坯料计划的ID
            ApsWorkInProgressInventoryDo apsWorkInProgressInventoryDo = new ApsWorkInProgressInventoryDo();
            apsWorkInProgressInventoryDo.setId(req.getProgressId());
            apsWorkInProgressInventoryDo.setPlanmaterialid(apsBlankOrderDo.getId());
            apsWorkInProgressInventoryDo.setWorkinprocessstatus(SaveConstans.WorkInProgressStatus.WAIT_WORK);
            apsWorkInProgressInventoryService.updateById(apsWorkInProgressInventoryDo);

            //借调逻辑
            if (progressWork.getWorkinprocessstatus().equals(SaveConstans.WorkInProgressStatus.WAIT_WORK)) {
                //获取该在制品的工序作业ID
                String processoperationid = progressWork.getProcessoperationid();
                //获取该在制品的批次号
                String batchnumber = progressWork.getBatchnumber();
                //该对应工序作业的已借调卷数=已借调卷数+1
                this.baseMapper.processAddSecondRoll(processoperationid);
                //将在制品的作业输出物料ID对应的所有后道工序作业的所有作业明细的待加工料卷批次号去掉“{批次号}，”
                this.baseMapper.processDeleteBatchNumber(batchnumber, processoperationid);
                //处理后续工序状态
                Map<String, Object> params2 = new HashMap<>();
                params2.put("processId", processoperationid);
                R r2 = apsProcessOperationService.updateBorrowProcess(params2);
                if (!r2.getCode().equals("200")) {
                    return R.error(r2.getMsg());
                }
            }
        }

        return R.ok();
    }

}
