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

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rongwei.bscommon.sys.dao.ApsProcessOperationDao;
import com.rongwei.bscommon.sys.dao.ApsProcessOperationProcessEquDao;
import com.rongwei.bscommon.sys.dao.ApsProcessOutputProductDao;
import com.rongwei.bscommon.sys.dao.ApsReportRecordsDao;
import com.rongwei.bscommon.sys.service.*;
import com.rongwei.bsentity.domain.*;
import com.rongwei.bsentity.vo.*;
import com.rongwei.rwadmincommon.system.vo.SysUserVo;
import com.rongwei.rwcommon.base.R;
import com.rongwei.rwcommon.base.exception.CustomException;
import com.rongwei.rwcommon.utils.SecurityUtil;
import com.rongwei.rwcommonentity.commonservers.vo.SysSerialVo;
import com.rongwei.safecommon.fegin.CXAdminFeginClient;
import com.rongwei.safecommon.utils.CXCommonUtils;
import com.rongwei.safecommon.utils.SaveConstans;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 *
 */
@Service
@Log4j2
public class ApsReportRecordsServiceImpl extends ServiceImpl<ApsReportRecordsDao, ApsReportRecordsDo>
        implements ApsReportRecordsService {

    //开工锁
    private final ConcurrentHashMap<String, String> startWorkLock = new ConcurrentHashMap<>();

    //报工锁
    private final ConcurrentHashMap<String, String> reportWorkLock = new ConcurrentHashMap<>();

    @Autowired
    private ApsReportOutputService apsReportOutputService;
    @Autowired
    private ApsReportCheckoutService apsReportCheckoutService;
    @Autowired
    private ApsReportMachiningService apsReportMachiningService;
    @Autowired
    private ApsWorkInProgressInventoryService apsWorkInProgressInventoryService;
    @Autowired
    private ApsProcessOperationProcessEquService apsProcessOperationProcessEquService;
    @Resource
    private ApsProcessOperationProcessEquDao apsProcessOperationProcessEquDao;
    @Resource
    private ApsProcessOperationDao apsProcessOperationDao;
    @Autowired
    private ApsProcessOperationService apsProcessOperationService;
    @Autowired
    private ApsProductionOrderService apsProductionOrderService;
    @Autowired
    private ApsBlankOrderService apsBlankOrderService;
    @Autowired
    private ApsProcessOperationOutMaterService apsProcessOperationOutMaterService;
    @Autowired
    private ApsAlloyService apsAlloyService;
    @Autowired
    private ApsAlloyCompositionService apsAlloyCompositionService;
    @Autowired
    private ApsReportBlankCompentService apsReportBlankCompentService;
    @Resource
    private CXAdminFeginClient cxAdminFeginClient;
    @Autowired
    private ApsCraftStepService apsCraftStepService;
    @Autowired
    private ApsCraftEquService apsCraftEquService;
    @Autowired
    private ReportCheckServiceImpl reportCheckService;
    @Resource
    private ApsProcessOutputProductDao apsProcessOutputProductDao;

    @Override
    @Transactional
    public R cancelRecord(Map<String, String> req) {
        String recordId;
        try {
            recordId = req.get("ID");
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("报工记录ID错误");
        }
        //查询报工详情
        ApsReportRecordsDo recordsDo = this.getById(recordId);
        if (ObjectUtil.isEmpty(recordsDo)) {
            return R.error("报工记录未找到");
        }
        //删除报工记录
        this.removeById(recordId);
        //删除报工输出物料
        apsReportOutputService.remove(new QueryWrapper<ApsReportOutputDo>().lambda().eq(ApsReportOutputDo::getMainid, recordId));
        //删除报工加工参数
        apsReportMachiningService.remove(new QueryWrapper<ApsReportMachiningDo>().lambda().eq(ApsReportMachiningDo::getMainid, recordId));
        //删除报工检查项
        apsReportCheckoutService.remove(new QueryWrapper<ApsReportCheckoutDo>().lambda().eq(ApsReportCheckoutDo::getMainid, recordId));

        //批次号list
        List<String> batchNumberList = new LinkedList<>();
        //更新输入物料在制品：如果输入物料有批次号，并且在制品库存中有输入物料批次号的在制品，则更新该在制品的在制品状态=待加工
        if (ObjectUtil.isNotEmpty(recordsDo.getBatchnumber())) {
            batchNumberList = Arrays.asList(recordsDo.getBatchnumber().split(","));
            ApsWorkInProgressInventoryDo apsWorkInProgressInventoryDo = new ApsWorkInProgressInventoryDo();
            apsWorkInProgressInventoryDo.setWorkinprocessstatus("待加工");
            apsWorkInProgressInventoryService.update(apsWorkInProgressInventoryDo, new QueryWrapper<ApsWorkInProgressInventoryDo>().lambda()
                    .in(ApsWorkInProgressInventoryDo::getBatchnumber, batchNumberList)
                    .eq(ApsWorkInProgressInventoryDo::getDeleted, "0"));
        }

        //更新工序作业和作业明细
        //明细的已开工卷数=已开工卷数-1 ;明细的待报工记录ID=（空），设备的带报工记录ID=（空）；工序作业的已开工卷数-1

        //工序作业ID
        String processoperationid = recordsDo.getProcessoperationid();
        //工序作业明细ID
        String processequid = recordsDo.getProcessequid();

        int reduceNum = 1;
        if (batchNumberList.size() > 0) {
            reduceNum = batchNumberList.size();
        }

        //=========更新工序作业明细===========
        //查询工序作业明细详情
        ApsProcessOperationProcessEquDo apsProcessOperationProcessEquDo = apsProcessOperationProcessEquService.getById(processequid);
        //定义作业明细的更新语句
        LambdaUpdateWrapper<ApsProcessOperationProcessEquDo> processEquUpdateWrapper = new UpdateWrapper<ApsProcessOperationProcessEquDo>().lambda().eq(ApsProcessOperationProcessEquDo::getId, processequid);

        //当前已开工卷数
        Integer startingroll = apsProcessOperationProcessEquDo.getStartingroll();
        //已开工卷数=已开工卷数-输入批次号数量
        Integer newStartingRoll = startingroll - reduceNum;
        //增加容错
        if (newStartingRoll <= 0) {
            newStartingRoll = 0;
        }
        processEquUpdateWrapper.set(ApsProcessOperationProcessEquDo::getStartingroll, newStartingRoll);
        //待报工记录ID=（空）
        processEquUpdateWrapper.set(ApsProcessOperationProcessEquDo::getWaitreportid, null);
        //加工中批次号=(空)
        processEquUpdateWrapper.set(ApsProcessOperationProcessEquDo::getDoingbatchnumber, null);
        /**
         * 如果已开工卷数=0，则更新该作业明细
         * 实际开工时间=（空），
         * 作业状态=待开工
         */
        if (newStartingRoll == 0) {
            processEquUpdateWrapper.set(ApsProcessOperationProcessEquDo::getActualstartdate, null);
            processEquUpdateWrapper.set(ApsProcessOperationProcessEquDo::getWorkstatus, "待开工");
        }
        //更新
        apsProcessOperationProcessEquService.update(processEquUpdateWrapper);

        //=========更新工序作业============
        //工序作业详情
        ApsProcessOperationDo apsProcessOperationDo = apsProcessOperationService.getById(processoperationid);
        //定义作业明细的更新语句
        LambdaUpdateWrapper<ApsProcessOperationDo> processUpdateWrapper = new UpdateWrapper<ApsProcessOperationDo>().lambda().eq(ApsProcessOperationDo::getId, processoperationid);

        //当前已开工卷数
        Integer operationStartingroll = apsProcessOperationDo.getStartingroll();
        //已开工卷数=已开工卷数-输入批次号数量
        Integer newOperationStartingRoll = operationStartingroll - reduceNum;
        //增加容错
        if (newOperationStartingRoll <= 0) {
            newOperationStartingRoll = 0;
        }
        processUpdateWrapper.set(ApsProcessOperationDo::getStartingroll, newOperationStartingRoll);
        //剩余待开工卷数=计划加工卷数-已开工卷数-输入已取消卷数-已取消卷数
        Integer leavewaitworkroll = apsProcessOperationDo.getPlanprocessrall() - newOperationStartingRoll - apsProcessOperationDo.getInputunqualifiedroll() - apsProcessOperationDo.getCancelroll();
        if (leavewaitworkroll <= 0) {
            leavewaitworkroll = 0;
        }
        processUpdateWrapper.set(ApsProcessOperationDo::getLeavewaitworkroll, leavewaitworkroll);
        /**
         * 如果已开工卷数=0，则更新工序作业
         * 实际开工时间=（空）
         * 作业状态=待开工，
         * 生产状态=待开工
         * 如果已开工卷数>0，则更新工序作业
         * 实际开工时间=该工序作业所有已开工卷数>0的作业明细中最小实际开工时间
         */
        if (leavewaitworkroll == 0) {
            processUpdateWrapper.set(ApsProcessOperationDo::getActualstartdate, null)
                    .set(ApsProcessOperationDo::getWorkstatus, "待开工")
                    .set(ApsProcessOperationDo::getProcessstatus, SaveConstans.ProductionStatus.TO_BE_STARTED);
        } else {
            //根据工序作业ID查询其作业明细中，已开工卷数>0的最小的实际开工时间
            ApsProcessOperationProcessEquDo minDateProcessEqu = apsProcessOperationProcessEquDao.selectMinStartWorkDate(processoperationid);
            if (ObjectUtil.isNotEmpty(minDateProcessEqu) && ObjectUtil.isNotEmpty(minDateProcessEqu.getActualstartdate())) {
                processUpdateWrapper.set(ApsProcessOperationDo::getActualstartdate, minDateProcessEqu.getActualstartdate());
            }
        }
        //更新
        apsProcessOperationService.update(processUpdateWrapper);


        //查询作业明细详情
        ApsProcessOperationProcessEquDo equDo = apsProcessOperationProcessEquDao.selectById(processequid);

//        //更新设备的待报工记录ID
//        apsProcessOperationProcessEquDao.updateEquByCancelRecord(recordId, equDo.getProcessdeviceid());

        //作业明细的作业状态
        /**
         * 如果已开工卷数=0，则=待开工；
         * 如果已开工卷数>0，并且完工状态=未完工，则=加工中；（先更新完工状态）
         * 如果未完工卷数=0，并且完工状态=已完工，则=已完工（先更新完工状态）
         */
        LambdaUpdateWrapper<ApsProcessOperationProcessEquDo> set = new UpdateWrapper<ApsProcessOperationProcessEquDo>().lambda();
        if (equDo.getStartingroll() == 0) {
            set.set(ApsProcessOperationProcessEquDo::getWorkstatus, "待开工");
            set.set(ApsProcessOperationProcessEquDo::getActualstartdate, null);
        }
        if (equDo.getStartingroll() > 0 && equDo.getClosestatus().equals("未完工")) {
            set.set(ApsProcessOperationProcessEquDo::getWorkstatus, "加工中");
        }
        if (ObjectUtil.isNotEmpty(equDo.getUnfinishroll()) && equDo.getUnfinishroll() == 0) {
            set.set(ApsProcessOperationProcessEquDo::getWorkstatus, "已完工");
        }

        /**
         * 如果输入物料有批次号，则
         */
        if (ObjectUtil.isNotEmpty(recordsDo.getBatchnumber())) {
//            //查询工序作业
//            ApsProcessOperationDo apsProcessOperationDo = apsProcessOperationService.getById(processoperationid);
//            //没有前道工序
//            if (ObjectUtil.isEmpty(apsProcessOperationDo.getPreviousprocessid())) {
//                apsProcessOperationDao.updateBatchNumberByProcessId(recordsDo.getBatchnumber(), processoperationid);
//            }
//            //有前道工序
//            if (ObjectUtil.isNotEmpty(apsProcessOperationDo.getPreviousprocessid())) {
//                //查询所有同级工序
//                List<ApsProcessOperationDo> list = apsProcessOperationService.list(new QueryWrapper<ApsProcessOperationDo>().lambda().eq(ApsProcessOperationDo::getPreviousprocessid, apsProcessOperationDo.getPreviousprocessid()));
//                List<String> processIdList = list.stream().map(ApsProcessOperationDo::getId).collect(Collectors.toList());
//                if (StringUtils.isNotBlank(recordsDo.getBatchnumber())) {
//                    //更新所有同级工序作业的明细，增加批次号
//                    apsProcessOperationDao.updateBatchNumberByProcessList(recordsDo.getBatchnumber(), processIdList);
//                }
//
//            }
            /**
             * 如果该工序作业明细有前道工序作业明细，则将前道工序作业明细的所有后道工序作业明细的待加工料卷批次号加上“{批次号}，”
             */
            if (ObjectUtil.isNotEmpty(equDo.getPreviousprocessesids()) && ObjectUtil.isNotEmpty(recordsDo.getBatchnumber())) {
                apsProcessOperationDao.updateBatchNumberByPrevious(recordsDo.getBatchnumber(), equDo.getPreviousprocessesids());
            }
            /**
             * 如果该工序作业明细没有前道工序作业明细，则该作业明细对应作业的所有作业明细的待加工料卷批次号加上“{批次号}，”
             */
            if (ObjectUtil.isEmpty(equDo.getPreviousprocessesids()) && ObjectUtil.isNotEmpty(recordsDo.getBatchnumber())) {
                //更新坯料计划的第一道工序作业的所有工序作业明细的待加工料卷批次号=领料批次号逗号拼接
                apsProcessOperationProcessEquService.update(new UpdateWrapper<ApsProcessOperationProcessEquDo>().lambda()
                        .setSql("BACHMATERIALPROCESS = IF(BACHMATERIALPROCESS is null || BACHMATERIALPROCESS = '','" + String.join(",", batchNumberList) + "',CONCAT(BACHMATERIALPROCESS,'," + String.join(",", batchNumberList) + "'))")
                        .eq(ApsProcessOperationProcessEquDo::getDeleted, "0")
                        .eq(ApsProcessOperationProcessEquDo::getProcessid, recordsDo.getProcessoperationid()));
            }
        }
        set.eq(ApsProcessOperationProcessEquDo::getId, equDo.getId());
        apsProcessOperationProcessEquService.update(set);

        //如果没有输入批次号，取消开工需要还原
        if (ObjectUtil.isEmpty(recordsDo.getBatchnumber())) {
            //如果开工时间是当前月，需要取消流水号
            if (DateUtil.month(recordsDo.getStartworktime()) == DateUtil.month(DateUtil.date())) {
                //如果是铸轧，需要减去 输出物料的单卷数合计
                this.cancelNumber(equDo);
            }
        }

        //如果当前工序作业明细  不存在（其他合并工序作业明细，并且其他合并作业明细的 待报工记录ID 不为空） 则炉号-1
        List<ApsProcessOperationProcessEquDo> equDoMergeStartingList = this.baseMapper.selectOtherMergeProcessStarting(equDo.getId(), equDo.getProcessdeviceid(), equDo.getPlanstartdate());
        if (equDoMergeStartingList.size() <= 0) {
            //炉号-1
            //加工设备ID
            String processdeviceid = equDo.getProcessdeviceid();
            //在流水表中的 标识
            String moduleCode = "aps_report_output_heat_" + processdeviceid;
            apsProcessOperationProcessEquDao.updateSerialNumber(moduleCode, 1);
        }

        //更新其余信息
        CommonUpdateProductionStatusReq commonUpdateProductionStatusReq = new CommonUpdateProductionStatusReq();
        commonUpdateProductionStatusReq.setProcessOperationEquId(equDo.getId());
        apsProcessOperationProcessEquService.updateProductionStatus(commonUpdateProductionStatusReq);

        return R.ok();
    }

    private void cancelNumber(ApsProcessOperationProcessEquDo equDo) {
        //加工设备ID
        String processdeviceid = equDo.getProcessdeviceid();

        //查询坯料计划
        ApsBlankOrderDo apsBlankOrderDo = apsBlankOrderService.getById(equDo.getBlankid());
        if (ObjectUtil.isNotEmpty(apsBlankOrderDo.getBlanktype()) && apsBlankOrderDo.getBlanktype().equals("铸轧")) {
            //查询 工序作业明细对应的 输出物料
            List<ApsProcessOperationOutMaterDo> list = apsProcessOperationOutMaterService.list(new QueryWrapper<ApsProcessOperationOutMaterDo>().lambda().eq(ApsProcessOperationOutMaterDo::getMainid, equDo.getProcessid()));
            //合计需要减的值
            int needCancelValue = 0;
            for (ApsProcessOperationOutMaterDo apsProcessOperationOutMaterDo : list) {
                needCancelValue += apsProcessOperationOutMaterDo.getOutval();
            }
            apsProcessOperationProcessEquDao.updateSerialNumber("aps_report_output_" + processdeviceid, needCancelValue);
        }

    }

    @Override
    @Transactional
    public R startReport(StartRePortReq req) {

        SysUserVo currentUser = CXCommonUtils.getCurrentUser();
        if (startWorkLock.containsKey(req.getUseDeviceId())) {
            log.error("该作业已被：{}开工", startWorkLock.get(req.getUseDeviceId()));
            return R.error("该作业已被开工");
        }
        startWorkLock.put(req.getUseDeviceId(), currentUser.getId());
        try {

            //根据作业明细ID查询作业明细详情
            ApsProcessOperationProcessEquDo apsProcessOperationProcessEquDo = apsProcessOperationProcessEquService.getById(req.getUseDeviceId());
            //如果已开工卷数！= 已报工卷数，说明已经开工了，提示已开工
            if (!apsProcessOperationProcessEquDo.getStartingroll().equals(apsProcessOperationProcessEquDo.getReportroll())) {
                return R.error("此作业已开工，请刷新列表后重试");
            }

            //查询工序作业的详情
            ApsProcessOperationDo apsProcessOperationDo = apsProcessOperationService.getById(apsProcessOperationProcessEquDo.getProcessid());
            //查询坯料计划的详情
            ApsBlankOrderDo apsBlankOrderDo = apsBlankOrderService.getById(apsProcessOperationDo.getBlankid());
            //查询订单的详情
            ApsProductionOrderDo apsProductionOrderDo = apsProductionOrderService.getById(apsBlankOrderDo.getProductionorderid());

            if (ObjectUtil.isEmpty(req.getInputBatchNumber())) {
                //根据设备ID查询对应车间代号和设备代号
                OrganizationCodeAndDeviceCodeVo organizationCodeAndDeviceCodeVo = this.baseMapper.selectOrganizationCodeAndDeviceCode(apsProcessOperationProcessEquDo.getProcessdeviceid());
                if (ObjectUtil.isEmpty(organizationCodeAndDeviceCodeVo) || ObjectUtil.isEmpty(organizationCodeAndDeviceCodeVo.getDeviceCode()) || ObjectUtil.isEmpty(organizationCodeAndDeviceCodeVo.getOrganizationCode())) {
                    return R.error("未找到对应的车间代号和设备代号");
                }
            }
            /**
             * 如果工序作业明细加工设备已有其他作业明细正在加工（待报工记录ID不为空），
             * 并且（不是排程合并作业，或者与工序作业明细不是同一排程合并作业），
             * 则错误提示：该设备当前加工中的作业还未报工，不能开工新的作业
             */
            //当前工序作业明细的加工设备ID
            String processdeviceid = apsProcessOperationProcessEquDo.getProcessdeviceid();
            //当前工序作业明细的ID
            String apsProcessOperationProcessEquDoId = apsProcessOperationProcessEquDo.getId();
            //查询当前工序作业的作业明细的 加工设备 对应的其他工序作业的作业明细 并且待报工记录ID不为空
            List<ApsProcessOperationProcessEquDo> list = apsProcessOperationProcessEquDao.selectOtherDeviceList(processdeviceid, apsProcessOperationProcessEquDoId);
//        List<ApsProcessOperationProcessEquDo> list = apsProcessOperationProcessEquService.list(
//                new QueryWrapper<ApsProcessOperationProcessEquDo>().lambda()
//                        .eq(ApsProcessOperationProcessEquDo::getProcessdeviceid, processdeviceid)//当前工序作业的作业明细的 加工设备
//                        .ne(ApsProcessOperationProcessEquDo::getId, apsProcessOperationProcessEquDoId)//对应的其他工序作业的作业明细
//                        .isNotNull(ApsProcessOperationProcessEquDo::getWaitreportid)//待报工记录ID不为空
//        );
            //存在已使用,判断是否是合并作业 （计划开工时间相同）
            if (ObjectUtil.isNotEmpty(list)) {
                //已开工的作业明细的计划开工时间
                Date planstartdate = list.get(0).getPlanstartdate();
                //开工时间不用
                if (planstartdate.compareTo(apsProcessOperationProcessEquDo.getPlanstartdate()) != 0) {
                    return R.error("该设备当前加工中的作业还未报工，不能开工新的作业");
                }
            }


//        //设备的待加工ID
//        String waitReportId = organizationCodeAndDeviceCodeVo.getWaitReportId();
//        //如果工序作业加工设备已有其他作业状态为已开工，错误提示：该设备当前加工中的作业还未报工，不能开工新的作业
//        if (ObjectUtil.isNotEmpty(waitReportId)) {
//            String oldWaitReportId = waitReportId.split(",")[0];
//            //查询当前报工的工序作业明细详情
//            ApsReportRecordsDo apsReportRecordsDo = this.getById(oldWaitReportId);
//            String processequid = apsReportRecordsDo.getProcessequid();
//            ApsProcessOperationProcessEquDo doingProcessEqu = apsProcessOperationProcessEquService.getById(processequid);
//            //计划开工时间不相等，表示不是合并工序
//            if (doingProcessEqu.getPlanstartdate().compareTo(apsProcessOperationProcessEquDo.getPlanstartdate()) != 0) {
//                return R.error("该设备当前加工中的作业还未报工，不能开工新的作业");
//            }
//        }


            //获取当前用户相关信息
//            SysUserVo currentUser = CXCommonUtils.getCurrentUser();
            String tenantId = CXCommonUtils.getCurrentUserFactoryId(currentUser);

            //查询此工序对应工艺步骤中，对应设备的设备参数
            String equparames = "";
            //查询工序步骤
//        String process = apsProcessOperationDo.getProcess();
//        String processname = apsProcessOperationDo.getProcessname();
            String stepnum = apsProcessOperationDo.getStepnum();
            ApsCraftStepDo craftStepDo = apsCraftStepService.getOne(new QueryWrapper<ApsCraftStepDo>().lambda().eq(ApsCraftStepDo::getStepnum, stepnum));
            if (ObjectUtil.isNotEmpty(craftStepDo)) {
                //查询设备参数子表
                ApsCraftEquDo apsCraftEquDo = apsCraftEquService.getOne(new QueryWrapper<ApsCraftEquDo>().lambda().eq(ApsCraftEquDo::getMainid, craftStepDo.getId()).eq(ApsCraftEquDo::getResourceid, apsProcessOperationProcessEquDo.getProcessdeviceid()).eq(ApsCraftEquDo::getTenantid, tenantId));
                if (ObjectUtil.isNotEmpty(apsCraftEquDo)) {
                    equparames = apsCraftEquDo.getEquparames();
                }
            }


            //新增主表报工记录信息
            ApsReportRecordsDo apsReportRecordsDo = new ApsReportRecordsDo();
            apsReportRecordsDo.setId(SecurityUtil.getUUID());
            apsReportRecordsDo.setTenantid(tenantId);
            //工序作业ID
            apsReportRecordsDo.setProcessoperationid(apsProcessOperationDo.getId());
            //作业明细ID
            apsReportRecordsDo.setProcessequid(apsProcessOperationProcessEquDo.getId());
            //输入物料的批次号
            apsReportRecordsDo.setBatchnumber(req.getInputBatchNumber());
            //实际输入物料
            apsReportRecordsDo.setActualinputmaterial(apsProcessOperationDo.getPlaninput());
            //主操作员
            apsReportRecordsDo.setChiefoperatorid(currentUser.getId());
            apsReportRecordsDo.setChiefoperatorname(currentUser.getName());
            //开工时间
            apsReportRecordsDo.setStartworktime(DateUtil.date());
//        //报工时间
//        apsReportRecordsDo.setReportworktime(DateUtil.date());
            //报工状态
            apsReportRecordsDo.setReportworkstatus("已开工");
            apsReportRecordsDo.setCheckstatus("待检验");
            //设备参数
            apsReportRecordsDo.setDeviceparm(equparames);
            //注意事项
            apsReportRecordsDo.setAttention(apsProcessOperationDo.getRemark());


            //=================更新工序作业明细的报工ID、已开工卷数============
            //将报工记录ID存入工序作业的设备子表中
            ApsProcessOperationProcessEquDo needUpdateProcessOperationProcessEqu = new ApsProcessOperationProcessEquDo();
            needUpdateProcessOperationProcessEqu.setId(apsProcessOperationProcessEquDo.getId());

            //更新待报工记录ID
            needUpdateProcessOperationProcessEqu.setWaitreportid(apsReportRecordsDo.getId());
            //获取作业明细的已开工卷数
            Integer startingroll = apsProcessOperationProcessEquDo.getStartingroll();
            Integer newStartingRoll = startingroll + 1;
            //更新已开工卷数
            needUpdateProcessOperationProcessEqu.setStartingroll(newStartingRoll);
            if (newStartingRoll.equals(1)) {
                //更新实际开工时间
                needUpdateProcessOperationProcessEqu.setActualstartdate(DateUtil.date());
            }
            //加工中批次号
            if (ObjectUtil.isNotEmpty(req.getInputBatchNumber())) {
                needUpdateProcessOperationProcessEqu.setDoingbatchnumber(req.getInputBatchNumber());
            }
            //更新工序作业明细的完工状态和作业状态
            if (apsProcessOperationProcessEquDo.getWorkstatus().equals("待开工")) {
                needUpdateProcessOperationProcessEqu.setWorkstatus("加工中");
            }
            apsProcessOperationProcessEquService.updateById(needUpdateProcessOperationProcessEqu);

            //===============更新工序作业==================
            ApsProcessOperationDo needUpdateProcessOperation = new ApsProcessOperationDo();
            needUpdateProcessOperation.setId(apsProcessOperationDo.getId());
            Integer processStartingRoll = apsProcessOperationDo.getStartingroll();
            //已开工卷数
            Integer newProcessStartingRoll = processStartingRoll + 1;
            //剩余待开工卷数=计划加工卷数-已开工卷数-输入已取消卷数-已取消卷数
            needUpdateProcessOperation.setLeavewaitworkroll(apsProcessOperationDo.getPlanprocessrall() - newProcessStartingRoll - apsProcessOperationDo.getInputunqualifiedroll() - apsProcessOperationDo.getCancelroll());
            needUpdateProcessOperation.setStartingroll(newProcessStartingRoll);
            if (newProcessStartingRoll.equals(1)) {
                needUpdateProcessOperation.setActualstartdate(DateUtil.date());
                needUpdateProcessOperation.setWorkstatus("加工中");
                needUpdateProcessOperation.setProcessstatus(SaveConstans.ProductionStatus.PROCESSING);
            }
            apsProcessOperationService.updateById(needUpdateProcessOperation);
//        this.baseMapper.updateProcessActualStartDate(apsProcessOperationDo.getId());

//        //=============更新设备的报工记录ID=============
//        String newWaitReportId = "";
//        if (ObjectUtil.isNotEmpty(waitReportId)) {
//            newWaitReportId = waitReportId + "," + apsReportRecordsDo.getId();
//        }
//        this.baseMapper.updateDeviceWaitReportId(newWaitReportId, apsProcessOperationProcessEquDo.getProcessdeviceid());

            //==========输入物料有批次号==============
            if (ObjectUtil.isNotEmpty(req.getInputBatchNumber())) {
                //如果该工序作业没有前道工序作业
//            if (ObjectUtil.isEmpty(apsProcessOperationDo.getPreviousprocessid())) {
//                //该工序作业的待加工料卷批次号去掉“{批次号}，”或者“,{批次号}”
//                this.baseMapper.updateBatchMaterialProcess(req.getInputBatchNumber(), apsProcessOperationProcessEquDo.getId());
//            } else {//如果该工序作业有前道工序作业
//                //前道工序作业 的 所有后道工序作业（包含本工序作业【即所有与本工序同级的工序作业】） 的待加工料卷批次号去掉“{批次号}，”或者“,{批次号}”
//                //查询前道工序作业的所有后道工序作业
//                List<ApsProcessOperationDo> nextProcessList = apsProcessOperationService.list(new QueryWrapper<ApsProcessOperationDo>().lambda().eq(ApsProcessOperationDo::getPreviousprocessid, apsProcessOperationDo.getPreviousprocessid()));
//                String collect = nextProcessList.stream().map(ApsProcessOperationDo::getId).collect(Collectors.joining("','"));
//                String processIds = "'" + collect + "'";
//                this.baseMapper.updateBatchMaterialProcessBatch(req.getInputBatchNumber(), processIds);
//            }
                //更新在制品状态
                apsWorkInProgressInventoryService.update(new UpdateWrapper<ApsWorkInProgressInventoryDo>().lambda()
                        .set(ApsWorkInProgressInventoryDo::getWorkinprocessstatus, "加工中")
                        .eq(ApsWorkInProgressInventoryDo::getBatchnumber, req.getInputBatchNumber())
                        .eq(ApsWorkInProgressInventoryDo::getDeleted, "0"));
                /**
                 * 如果该工序作业明细有前道工序作业明细，
                 * 则将前道工序作业明细的所有后道工序作业明细的待加工料卷批次号去掉“{批次号}，”
                 */
                if (ObjectUtil.isNotEmpty(apsProcessOperationProcessEquDo.getPreviousprocessesids())) {
                    List<ApsProcessOperationProcessEquDo> needUpdateBatchNumber = apsProcessOperationProcessEquService.list(new QueryWrapper<ApsProcessOperationProcessEquDo>().lambda().eq(ApsProcessOperationProcessEquDo::getPreviousprocessesids, apsProcessOperationProcessEquDo.getPreviousprocessesids()));
                    if (ObjectUtil.isNotEmpty(needUpdateBatchNumber)) {
                        List<String> needUpdateIds = needUpdateBatchNumber.stream().map(ApsProcessOperationProcessEquDo::getId).collect(Collectors.toList());
                        String join = String.join(",", needUpdateIds);
                        this.baseMapper.updateAllProcessEquBatchNumberByIds(req.getInputBatchNumber(), join);
                    }
                }
                /**
                 * 如果该工序作业明细没有前道工序作业明细，则该作业明细对应作业的所有作业明细的待加工料卷批次号去掉“{输入物料批次号}，”
                 */
                if (ObjectUtil.isEmpty(apsProcessOperationProcessEquDo.getPreviousprocessesids())) {
                    List<ApsProcessOperationProcessEquDo> needUpdateProcessEqus = apsProcessOperationProcessEquService.list(new QueryWrapper<ApsProcessOperationProcessEquDo>().lambda().eq(ApsProcessOperationProcessEquDo::getProcessid, apsProcessOperationProcessEquDo.getProcessid()));
                    List<ApsProcessOperationProcessEquDo> updateList = new LinkedList<>();
                    //遍历所有第一道工序的明细
                    for (ApsProcessOperationProcessEquDo updateProcessEqu : needUpdateProcessEqus) {
                        String bachmaterialprocess = updateProcessEqu.getBachmaterialprocess();
                        //如果存在被使用的批次号，则删除此批次号
                        if (ObjectUtil.isNotEmpty(bachmaterialprocess)) {
                            LinkedList<String> strings = new LinkedList<>(Arrays.asList(bachmaterialprocess.split(",")));
                            if (strings.contains(req.getInputBatchNumber())) {
                                strings.remove(req.getInputBatchNumber());
                                ApsProcessOperationProcessEquDo equDo = new ApsProcessOperationProcessEquDo();
                                equDo.setId(updateProcessEqu.getId());
                                equDo.setBachmaterialprocess(String.join(",", strings));
                                updateList.add(equDo);
                            }
                        }
                    }
                    //更新
                    if (ObjectUtil.isNotEmpty(updateList)) {
                        apsProcessOperationProcessEquService.updateBatchById(updateList);
                    }
                }
            }

            //==========输出物料子表信息============
//        InsertMyReportOutputReq req2 = new InsertMyReportOutputReq();
//        req2.setProcessId(apsProcessOperationDo.getId());
//        req2.setIfBlankProcess(apsProcessOperationDo.getIfblankprocess());
//        req2.setBlankType(apsBlankOrderDo.getBlanktype());
//        req2.setMainId(apsReportRecordsDo.getId());
//        req2.setLevel(apsProcessOperationDo.getLevel());
//        R r = apsReportOutputService.insertMyReportOutputWithOutBatchNumber(req2);
//        if (!r.getCode().equals("200")) {
//            return R.error(r.getMsg());
//        }
            //============开工时，生成炉号和批次号=============
            //获取设备/炉 的炉号（每月、每个设备/炉 更新）
            String heatNumber;//初始化炉号
            //如果存在其他合并工序，并且其他合并工序已开工，则不去生成新的 炉次号 使用其他合并工序的 开工记录的 炉次号
            List<ApsProcessOperationProcessEquDo> apsProcessEquMergeStartingList = this.baseMapper.selectOtherMergeProcessStarting(apsProcessOperationProcessEquDo.getId(), apsProcessOperationProcessEquDo.getProcessdeviceid(), apsProcessOperationProcessEquDo.getPlanstartdate());

            if (apsProcessEquMergeStartingList.size() > 0) {
                //合并工序作业明细
                ApsProcessOperationProcessEquDo equDo = apsProcessEquMergeStartingList.get(0);
                //查询该合并工序作业明细的待报工记录ID
                String waitreportid = equDo.getWaitreportid();
                //待报工记录详情
                ApsReportRecordsDo aDo = this.getById(waitreportid);
                heatNumber = aDo.getHeatnumber();
            } else {
                //调用通用接口生成炉号
                SysSerialVo vo = new SysSerialVo();
                vo.setModulecode("aps_report_output_heat_" + apsProcessOperationProcessEquDo.getProcessdeviceid());
                vo.setRuleTemplateStr("@{serialNumber:#000}");
                vo.setResetrule("date:yyyyMM");
                vo.setIfautomaticreset("y");
                vo.setInitValue(0L);
                Map<String, Object> codeData = cxAdminFeginClient.getSerialNumberCode(vo).getData();
                heatNumber = codeData.get("code").toString();
            }

            apsReportRecordsDo.setHeatnumber(heatNumber);
            //保存主表
            this.save(apsReportRecordsDo);

            OrganizationCodeAndDeviceCodeVo organizationCodeAndDeviceCodeVo = this.baseMapper.selectOrganizationCodeAndDeviceCode(apsProcessOperationProcessEquDo.getProcessdeviceid());

            InsertMyReportOutputReq insertMyReportOutputReq = new InsertMyReportOutputReq();
            insertMyReportOutputReq.setMainId(apsReportRecordsDo.getId());
            insertMyReportOutputReq.setProcessId(apsProcessOperationDo.getId());
            insertMyReportOutputReq.setIfBlankProcess(apsProcessOperationDo.getIfblankprocess());
            insertMyReportOutputReq.setDeviceId(apsProcessOperationProcessEquDo.getProcessdeviceid());
            insertMyReportOutputReq.setMark(organizationCodeAndDeviceCodeVo.getOrganizationCode());
            insertMyReportOutputReq.setYearCode((DateUtil.year(DateUtil.date()) % 100) + "");
            insertMyReportOutputReq.setMonthCode(SaveConstans.MONTH_CODE_LIST.get(DateUtil.month(DateUtil.date())));
            insertMyReportOutputReq.setEquipmentCode(organizationCodeAndDeviceCodeVo.getDeviceCode());
            insertMyReportOutputReq.setHeatNumber(heatNumber);
            insertMyReportOutputReq.setInputBatchNumber(apsReportRecordsDo.getBatchnumber());
            insertMyReportOutputReq.setBlankType(apsBlankOrderDo.getBlanktype());
            insertMyReportOutputReq.setLevel(apsProcessOperationDo.getLevel());
            if (apsProcessOperationDo.getProcess().equals("铸轧")) {
                insertMyReportOutputReq.setInsepctionLevel(SaveConstans.CheckLevel.WAITING_JUDGMENT);
                insertMyReportOutputReq.setQualified("");
            }

            R r = apsReportOutputService.insertMyReportOutput(insertMyReportOutputReq);
            if (!r.getCode().equals("200")) {
                throw new CustomException(r.getMsg());
            }


            //=============加工参数子表信息、检查项目子表信息================
            if (ObjectUtil.isNotEmpty(apsProcessOperationDo.getProcess())) {
                //根据工序查询其工序的加工参数
                List<ApsParameterDo> parameterDoList = this.baseMapper.selectApsParameterByProcess(apsProcessOperationDo.getProcess());
                List<ApsReportMachiningDo> needInsertApsReportMachingList = new LinkedList<>();
                if (ObjectUtil.isNotEmpty(parameterDoList)) {
                    for (ApsParameterDo apsParameterDo : parameterDoList) {
                        if (ObjectUtil.isEmpty(apsParameterDo)) {
                            continue;
                        }
                        ApsReportMachiningDo apsReportMachiningDo = new ApsReportMachiningDo();
                        apsReportMachiningDo.setId(SecurityUtil.getUUID());
                        apsReportMachiningDo.setTenantid(tenantId);
                        apsReportMachiningDo.setMainid(apsReportRecordsDo.getId());
                        apsReportMachiningDo.setMatching(apsParameterDo.getParameter());
                        apsReportMachiningDo.setRemark(apsParameterDo.getRemark());
                        needInsertApsReportMachingList.add(apsReportMachiningDo);
                    }
                    if (ObjectUtil.isNotEmpty(needInsertApsReportMachingList)) {
                        apsReportMachiningService.saveBatch(needInsertApsReportMachingList);
                    }
                }

                //根据工序查询其工序的检查项目
                List<ApsCheckParameterDo> checkParameterDoList = this.baseMapper.selectApsCheckParameterByProcess(apsProcessOperationDo.getProcess());
                List<ApsReportCheckoutDo> needInsertApsReportCheckList = new LinkedList<>();
                if (ObjectUtil.isNotEmpty(checkParameterDoList)) {
                    for (ApsCheckParameterDo apsCheckParameterDo : checkParameterDoList) {
                        if (ObjectUtil.isEmpty(apsCheckParameterDo)) {
                            continue;
                        }
                        ApsReportCheckoutDo apsReportCheckoutDo = new ApsReportCheckoutDo();
                        apsReportCheckoutDo.setId(SecurityUtil.getUUID());
                        apsReportCheckoutDo.setTenantid(tenantId);
                        apsReportCheckoutDo.setMainid(apsReportRecordsDo.getId());
                        apsReportCheckoutDo.setCheckitem(apsCheckParameterDo.getCheckparameter());
                        needInsertApsReportCheckList.add(apsReportCheckoutDo);
                    }
                    if (ObjectUtil.isNotEmpty(needInsertApsReportCheckList)) {
                        apsReportCheckoutService.saveBatch(needInsertApsReportCheckList);
                    }
                }

            }
            //=============坯料成分子表信息=============
            //工序作业的是否坯料工序=是 时，根据客户合金成分设置自动生成
            if (apsProcessOperationDo.getIfblankprocess().equals("是")) {
                //工序作业的合金
                String metal = apsProcessOperationDo.getMetal();
                //订单的客户ID
                String customid = apsProductionOrderDo.getCustomid();
                String alloyId = "";
                //查询合金对应的所有主表信息
                List<ApsAlloyDo> apsAlloyDoList = apsAlloyService.list(new QueryWrapper<ApsAlloyDo>().lambda().eq(ApsAlloyDo::getAlloy, metal));
                if (ObjectUtil.isNotEmpty(apsAlloyDoList)) {
                    //查询客户标准
                    List<ApsAlloyDo> collect = apsAlloyDoList.stream().filter(item -> ObjectUtil.isNotEmpty(item.getCustomerid()) && item.getCustomerid().contains(customid)).collect(Collectors.toList());
                    if (ObjectUtil.isNotEmpty(collect)) {
                        alloyId = collect.get(0).getId();
                    } else {//查询国标
                        List<ApsAlloyDo> collect1 = apsAlloyDoList.stream().filter(item -> ObjectUtil.isEmpty(item.getCustomerid())).collect(Collectors.toList());
                        if (ObjectUtil.isNotEmpty(collect1)) {
                            alloyId = collect1.get(0).getId();
                        }
                    }
                }
                //查询合金成分要求
                if (ObjectUtil.isNotEmpty(alloyId)) {
                    List<ApsAlloyCompositionDo> apsAlloyCompositionDoList = apsAlloyCompositionService.list(new QueryWrapper<ApsAlloyCompositionDo>().lambda().eq(ApsAlloyCompositionDo::getAlloyid, alloyId));

                    if (ObjectUtil.isNotEmpty(apsAlloyCompositionDoList)) {
                        List<ApsReportBlankCompentDo> needInsertApsReportBlankCompentList = new LinkedList<>();
                        for (ApsAlloyCompositionDo apsAlloyCompositionDo : apsAlloyCompositionDoList) {
                            ApsReportBlankCompentDo apsReportBlankCompentDo = new ApsReportBlankCompentDo();
                            apsReportBlankCompentDo.setId(SecurityUtil.getUUID());
                            apsReportBlankCompentDo.setTenantid(tenantId);
                            apsReportBlankCompentDo.setMainid(apsReportRecordsDo.getId());
                            apsReportBlankCompentDo.setCompent(apsAlloyCompositionDo.getIngredient());
                            apsReportBlankCompentDo.setStartproportion(apsAlloyCompositionDo.getLeftproportion());
                            apsReportBlankCompentDo.setEndproportion(apsAlloyCompositionDo.getRightproportion());
                            needInsertApsReportBlankCompentList.add(apsReportBlankCompentDo);
                        }
                        if (ObjectUtil.isNotEmpty(needInsertApsReportBlankCompentList)) {
                            apsReportBlankCompentService.saveBatch(needInsertApsReportBlankCompentList);
                        }

                    }
                }
            } else {//不是坯料工序，根据输入物料批次号，查询来源报工的坯料成分，copy一份
                String inputBatchNumber = req.getInputBatchNumber();
                //查询上一个的报工ID
                String lastReportRecordId = this.baseMapper.selectLastReoprtRecordByBatchNumber(inputBatchNumber);
                if (ObjectUtil.isNotEmpty(lastReportRecordId)) {
                    //查询上一个报工的坯料成分
                    List<ApsReportBlankCompentDo> apsReportBlankCompentDoList = apsReportBlankCompentService.list(new QueryWrapper<ApsReportBlankCompentDo>().lambda().eq(ApsReportBlankCompentDo::getMainid, lastReportRecordId));
                    //复制新增
                    List<ApsReportBlankCompentDo> needAddList = new LinkedList<>();
                    for (ApsReportBlankCompentDo apsReportBlankCompentDo : apsReportBlankCompentDoList) {
                        ApsReportBlankCompentDo needAdd = new ApsReportBlankCompentDo();
                        needAdd.setId(SecurityUtil.getUUID());
                        needAdd.setTenantid(tenantId);
                        needAdd.setMainid(apsReportRecordsDo.getId());
                        needAdd.setCompent(apsReportBlankCompentDo.getCompent());
                        needAdd.setStartproportion(apsReportBlankCompentDo.getStartproportion());
                        needAdd.setEndproportion(apsReportBlankCompentDo.getEndproportion());
                        needAdd.setActualproportion(apsReportBlankCompentDo.getActualproportion());
                        needAddList.add(needAdd);
                    }
                    apsReportBlankCompentService.saveBatch(needAddList);
                }
            }
            //更新生产状态
            CommonUpdateProductionStatusReq req3 = new CommonUpdateProductionStatusReq();
            req3.setProcessOperationEquId(apsProcessOperationProcessEquDo.getId());
            R r2 = apsProcessOperationProcessEquService.updateProductionStatus(req3);
            if (!r2.getCode().equals("200")) {
                throw new CustomException(r2.getMsg());
            }
            return R.ok(apsReportRecordsDo);
        } finally {
            log.debug("开工完毕，从map中清空当前开工锁，作业明细ID:{}", req.getUseDeviceId());
            startWorkLock.remove(req.getUseDeviceId());
        }

    }

    @Override
    @Transactional
    public R saveReport(SaveReportReq req) {

        //报工主表
        ApsReportRecordsDo apsReportRecordsDo = req.getApsReportRecordsDo();

        SysUserVo currentUser = CXCommonUtils.getCurrentUser();
        if (reportWorkLock.containsKey(apsReportRecordsDo.getId())) {
            log.error("该作业已被：{}报工", reportWorkLock.get(apsReportRecordsDo.getId()));
            return R.error("该作业已被报工");
        }
        reportWorkLock.put(apsReportRecordsDo.getId(), currentUser.getId());
        try {


            //防止同时报工
            ApsReportRecordsDo recordsDo = this.getById(apsReportRecordsDo.getId());
            if (ObjectUtil.isEmpty(recordsDo) || !recordsDo.getReportworkstatus().equals("已开工")) {
                return R.error("此作业已取消开工或已报工，请刷新列表后重试");
            }

            //报工输出物料
            List<ApsReportOutputDo> apsReportOutputDoList = req.getApsReportOutputDoList();
            //报工加工参数
            List<ApsReportMachiningDo> apsReportMachiningDoList = req.getApsReportMachiningDoList();
            //报工坯料成分
            List<ApsReportBlankCompentDo> apsReportBlankCompentDoList = req.getApsReportBlankCompentDoList();

            for (ApsReportOutputDo apsReportOutputDo : apsReportOutputDoList) {
                if (ObjectUtil.isEmpty(apsReportOutputDo.getInsepctionlevel())) {
                    return R.error("检验等级不能为空");
                }
            }

            //没有新增，只会更新
            apsReportRecordsDo.setCheckstatus("待检验");

            if (ObjectUtil.isNotEmpty(apsReportOutputDoList)) {
                apsReportOutputService.updateBatchById(apsReportOutputDoList);
            }
            if (ObjectUtil.isNotEmpty(apsReportMachiningDoList)) {
                apsReportMachiningService.updateBatchById(apsReportMachiningDoList);
            }
            if (ObjectUtil.isNotEmpty(apsReportBlankCompentDoList)) {
                apsReportBlankCompentService.updateBatchById(apsReportBlankCompentDoList);
            }

            //查询当前的报工记录信息
            ApsReportRecordsDo nowReportRecordsDo = this.getById(apsReportRecordsDo.getId());

            //查询对应的工序作业信息
            ApsProcessOperationDo apsProcessOperationDo = apsProcessOperationService.getById(nowReportRecordsDo.getProcessoperationid());
            //查询对应的工序作业明细信息
            ApsProcessOperationProcessEquDo apsProcessOperationProcessEquDo = apsProcessOperationProcessEquService.getById(nowReportRecordsDo.getProcessequid());
            //查询对应的坯料计划信息
            ApsBlankOrderDo apsBlankOrderDo = apsBlankOrderService.getById(apsProcessOperationDo.getBlankid());
            //查询对应的订单评审信息
            ApsProductionOrderDo apsProductionOrderDo = apsProductionOrderService.getById(apsBlankOrderDo.getProductionorderid());

            //如果工序作业是否坯料工序=是，检查每个报工输出物料批次号
            if (ObjectUtil.isNotEmpty(apsProcessOperationDo.getIfblankprocess()) && apsProcessOperationDo.getIfblankprocess().equals("是")) {
                //如果存在在制品的坯料批次号=输出物料批次号，错误提示:该坯料批次号已经存在
                List<String> numbers = apsReportOutputDoList.stream().map(ApsReportOutputDo::getOutputnumber).collect(Collectors.toList());

                List<ApsWorkInProgressInventoryDo> apsWorkInProgressInventoryDos = apsWorkInProgressInventoryService.list(new QueryWrapper<ApsWorkInProgressInventoryDo>().lambda().eq(ApsWorkInProgressInventoryDo::getDeleted, "0").in(ApsWorkInProgressInventoryDo::getBatchnumber, numbers));
                if (ObjectUtil.isNotEmpty(apsWorkInProgressInventoryDos)) {
                    List<String> batchNumbers = apsWorkInProgressInventoryDos.stream().map(ApsWorkInProgressInventoryDo::getBatchnumber).distinct().collect(Collectors.toList());
                    return R.error("该坯料批次号:" + String.join(",", batchNumbers) + " 已经存在");
                }
            }

            //=============更新作业明细信息=============
            Integer reduceNum = 1;
            if (ObjectUtil.isNotEmpty(nowReportRecordsDo.getBatchnumber())) {
                List<String> batchNumberList = Arrays.asList(nowReportRecordsDo.getBatchnumber().split(","));
                reduceNum = batchNumberList.size();
            }

            //更新待报工记录ID、已报工卷数
            //已报工卷数
            Integer reportroll = apsProcessOperationProcessEquDo.getReportroll();
            LambdaUpdateWrapper<ApsProcessOperationProcessEquDo> processEquWrapper = new UpdateWrapper<ApsProcessOperationProcessEquDo>().lambda().eq(ApsProcessOperationProcessEquDo::getId, apsProcessOperationProcessEquDo.getId());
            //已报工卷数=已报工卷数+输入批次号数量
            Integer newReportRoll = reportroll + reduceNum;
            processEquWrapper.set(ApsProcessOperationProcessEquDo::getReportroll, newReportRoll);

            //计划加工卷数
            Integer planprocessrall = apsProcessOperationProcessEquDo.getPlanprocessrall();
            //未完工卷数=计划加工卷数-已报工卷数
            int unfinishroll = planprocessrall - newReportRoll;
            /**
             * 如果未完工卷数-已取消卷数=0，则完工状态=已完工，实际完工时间=当前时间
             * 如果未完工卷数-已取消卷数>0，则完工状态=未完工
             * 如果完工状态=未完工，并且已开工卷数=0，则作业状态=待开工；
             * 如果完工状态=未完工，并且已开工卷数>0，则作业状态=加工中；
             * 如果完工状态=已完工，则作业状态=已完工
             * 待报工记录ID=（空），
             * 加工中批次号=（空）
             */
            //未完工卷数-已取消卷数
            int needDoRoll = unfinishroll - apsProcessOperationProcessEquDo.getCancelroll();
            if (needDoRoll <= 0) {
                processEquWrapper.set(ApsProcessOperationProcessEquDo::getClosestatus, "已完工")
                        .set(ApsProcessOperationProcessEquDo::getActualfinishdate, DateUtil.date())
                        .set(ApsProcessOperationProcessEquDo::getWorkstatus, "已完工");
            }
            if (needDoRoll > 0) {
                processEquWrapper.set(ApsProcessOperationProcessEquDo::getClosestatus, "未完工");
                if (apsProcessOperationProcessEquDo.getStartingroll() == 0) {
                    processEquWrapper.set(ApsProcessOperationProcessEquDo::getWorkstatus, "待开工");
                } else {
                    processEquWrapper.set(ApsProcessOperationProcessEquDo::getWorkstatus, "加工中");
                }
            }
            processEquWrapper.set(ApsProcessOperationProcessEquDo::getWaitreportid, null)
                    .set(ApsProcessOperationProcessEquDo::getDoingbatchnumber, null);

            //更新
            apsProcessOperationProcessEquService.update(processEquWrapper);


            //==============更新工序作业信息==============
            ApsProcessOperationDo needUpdateProcessOperation = new ApsProcessOperationDo();
            needUpdateProcessOperation.setId(apsProcessOperationDo.getId());
            //已报工卷数=已报工卷数+输入批次号数量
            needUpdateProcessOperation.setReportroll(apsProcessOperationDo.getReportroll() + reduceNum);
            //未完工卷数=计划加工卷数-已报工卷数
            needUpdateProcessOperation.setUnfinishroll(apsProcessOperationDo.getPlanprocessrall() - needUpdateProcessOperation.getReportroll());
            //剩余待报工卷数=未完工卷数-输入已取消卷数-已取消卷数
            int needReportRoll = needUpdateProcessOperation.getUnfinishroll() - apsProcessOperationDo.getInputunqualifiedroll() - apsProcessOperationDo.getCancelroll();
            if (needReportRoll <= 0) {
                needReportRoll = 0;
            }
            needUpdateProcessOperation.setLeavewaitjobroll(needReportRoll);
            /**
             * 如果剩余待报工卷数=0，则完工状态=已完工，实际完工时间=当前时间
             * 如果剩余待报工卷数>0，则完工状态=未完工
             * 如果完工状态=未完工，则作业状态=加工中；
             * 如果完工状态=已完工，则作业状态=已完工
             * 生产状态=作业状态
             */
            if (needReportRoll <= 0) {
                needUpdateProcessOperation.setClosestatus("已完工");
                needUpdateProcessOperation.setActualfinishdate(DateUtil.date());
                needUpdateProcessOperation.setWorkstatus("已完工");
                needUpdateProcessOperation.setProcessstatus(SaveConstans.ProductionStatus.COMPLETED);
            }
            if (needReportRoll > 0) {
                needUpdateProcessOperation.setClosestatus("未完工");
                needUpdateProcessOperation.setWorkstatus("加工中");
                needUpdateProcessOperation.setProcessstatus(SaveConstans.ProductionStatus.PROCESSING);
            }

            apsProcessOperationService.updateById(needUpdateProcessOperation);
//        this.baseMapper.updateProcessReportRoll(apsProcessOperationDo.getId());

//        //=============更新设备的报工记录ID===========
//        apsProcessOperationProcessEquDao.updateEquByCancelRecord(apsReportRecordsDo.getId(), apsProcessOperationProcessEquDo.getProcessdeviceid());

//        //============保存（报工）时，生成炉号和批次号=============
//        //获取设备/炉 的炉号（每月、每个设备/炉 更新）
//        String heatNumber;//初始化炉号
//        //调用通用接口生成炉号
//        SysSerialVo vo = new SysSerialVo();
//        vo.setModulecode("aps_report_output_heat_" + apsProcessOperationProcessEquDo.getProcessdeviceid());
//        vo.setRuleTemplateStr("@{serialNumber:#000}");
//        vo.setResetrule("date:yyyyMM");
//        vo.setIfautomaticreset("y");
//        vo.setInitValue(1L);
//        Map<String, Object> codeData = cxAdminFeginClient.getSerialNumberCode(vo).getData();
//        heatNumber = codeData.get("code").toString();
//
//        apsReportRecordsDo.setHeatnumber(heatNumber);
            //报工状态
            apsReportRecordsDo.setReportworkstatus("已报工");
            //如过报工时间为空，填入当前时间
            if (ObjectUtil.isEmpty(apsReportRecordsDo.getReportworktime())) {
                apsReportRecordsDo.setReportworktime(DateUtil.date());
            }

            this.updateById(apsReportRecordsDo);

//        //物理删除原来的报工记录输出物料
//        this.baseMapper.deleteOutputmaterialbyMainId(apsReportRecordsDo.getId());
//
            OrganizationCodeAndDeviceCodeVo organizationCodeAndDeviceCodeVo = this.baseMapper.selectOrganizationCodeAndDeviceCode(apsProcessOperationProcessEquDo.getProcessdeviceid());
//        if (ObjectUtil.isEmpty(organizationCodeAndDeviceCodeVo)) {
//            return R.error("未找到对应的车间代号和设备代号");
//        }
//        InsertMyReportOutputReq insertMyReportOutputReq = new InsertMyReportOutputReq();
//        insertMyReportOutputReq.setMainId(apsReportRecordsDo.getId());
//        insertMyReportOutputReq.setProcessId(apsProcessOperationDo.getId());
//        insertMyReportOutputReq.setIfBlankProcess(apsProcessOperationDo.getIfblankprocess());
//        insertMyReportOutputReq.setDeviceId(apsProcessOperationProcessEquDo.getProcessdeviceid());
//        insertMyReportOutputReq.setMark(organizationCodeAndDeviceCodeVo.getOrganizationCode());
//        insertMyReportOutputReq.setYearCode((DateUtil.year(DateUtil.date()) % 100) + "");
//        insertMyReportOutputReq.setMonthCode(SaveConstans.MONTH_CODE_LIST.get(DateUtil.month(DateUtil.date())));
//        insertMyReportOutputReq.setEquipmentCode(organizationCodeAndDeviceCodeVo.getDeviceCode());
//        insertMyReportOutputReq.setHeatNumber(heatNumber);
//        insertMyReportOutputReq.setInputBatchNumber(apsReportRecordsDo.getBatchnumber());
//        insertMyReportOutputReq.setBlankType(apsBlankOrderDo.getBlanktype());
//        insertMyReportOutputReq.setLevel(apsProcessOperationDo.getLevel());
//
//        R r = apsReportOutputService.insertMyReportOutput(insertMyReportOutputReq);
//        if (!r.getCode().equals("200")) {
//            return R.error(r.getMsg());
//        }

            //查询新的输出物料
            List<ApsReportOutputDo> newOutputDos = apsReportOutputService.list(new QueryWrapper<ApsReportOutputDo>().lambda().eq(ApsReportOutputDo::getMainid, apsReportRecordsDo.getId()));
            //填补对应的检验等级和是否合格
            if (apsReportOutputDoList.size() == newOutputDos.size()) {
                for (int i = 0; i < newOutputDos.size(); i++) {
                    newOutputDos.get(i).setInsepctionlevel(apsReportOutputDoList.get(i).getInsepctionlevel());
                    newOutputDos.get(i).setQualified(apsReportOutputDoList.get(i).getQualified());
                }
            }
            //更新输出物料
            apsReportOutputService.updateBatchById(newOutputDos);

            //=================新增在制品库存=================
            //查询报工记录对应的物料子表
            List<ApsReportOutputDo> apsReportOutputDos = apsReportOutputService.list(new QueryWrapper<ApsReportOutputDo>().lambda().eq(ApsReportOutputDo::getMainid, apsReportRecordsDo.getId()));

            if (ObjectUtil.isNotEmpty(apsReportOutputDos)) {
                //如果主表的批次号不为空，查找 在制品库存中是否有此 批次号 的数据，有 复制并删除原数据，坯料批次号 等坯料数据不变，其余数据变更
                if (ObjectUtil.isNotEmpty(apsReportRecordsDo.getBatchnumber())) {
                    ApsWorkInProgressInventoryDo apsWorkInProgressInventoryDo = apsWorkInProgressInventoryService.getOne(new QueryWrapper<ApsWorkInProgressInventoryDo>().lambda().eq(ApsWorkInProgressInventoryDo::getDeleted, "0").eq(ApsWorkInProgressInventoryDo::getBatchnumber, apsReportRecordsDo.getBatchnumber()));
                    //不为空，则删除数据（逻辑删除）
                    if (ObjectUtil.isNotEmpty(apsWorkInProgressInventoryDo)) {
                        apsWorkInProgressInventoryService.removeById(apsWorkInProgressInventoryDo.getId());
                    }
                    //增加或者复制在制品库存
                    addOrCopyWorkInProgress(apsReportOutputDos,
                            apsWorkInProgressInventoryDo,
                            apsProcessOperationProcessEquDo,
                            apsProcessOperationDo,
                            organizationCodeAndDeviceCodeVo,
                            apsProductionOrderDo,
                            apsBlankOrderDo);
                } else {
                    addOrCopyWorkInProgress(apsReportOutputDos,
                            null,
                            apsProcessOperationProcessEquDo,
                            apsProcessOperationDo,
                            organizationCodeAndDeviceCodeVo,
                            apsProductionOrderDo,
                            apsBlankOrderDo);
                }

                //更新物料子表 对应 工序作业输出物料 的已输出卷数
                for (ApsReportOutputDo apsReportOutputDo : apsReportOutputDos) {
                    //需要更新（+1）的工序作业输出物料ID
                    String outputid = apsReportOutputDo.getOutputid();
                    apsProcessOutputProductDao.updateRollNumById(outputid);
                }
            }

            //=========更新生产状态等=============
            //更新生产状态
            CommonUpdateProductionStatusReq req3 = new CommonUpdateProductionStatusReq();
            req3.setProcessOperationEquId(apsProcessOperationProcessEquDo.getId());
            R r2 = apsProcessOperationProcessEquService.updateProductionStatus(req3);
            if (!r2.getCode().equals("200")) {
                return R.error(r2.getMsg());
            }

            //===========提交校验================
            //如果输出物料中不存在 检验等级 为 待判 的，则直接提交校验
            //获取当前的输出物料
            List<ApsReportOutputDo> outputDos = apsReportOutputService.list(new QueryWrapper<ApsReportOutputDo>().lambda().eq(ApsReportOutputDo::getMainid, apsReportRecordsDo.getId()));
            List<ApsReportOutputDo> collect = outputDos.stream().filter(item -> item.getInsepctionlevel().equals(SaveConstans.CheckLevel.WAITING_JUDGMENT)).collect(Collectors.toList());
            if (collect.size() > 0) {
                return R.ok();
            }
            //遍历输出物料 拼接输出物料描述，并更新
            for (ApsReportOutputDo outputDo : outputDos) {
                ApsReportOutputDo needUpdate = new ApsReportOutputDo();
                needUpdate.setId(outputDo.getId());
                String outputdesc = "";
                outputdesc += outputDo.getOutputmaterial().split(" ")[0];
                outputdesc += " 厚" + CXCommonUtils.removeExtraZerosAndDecimal(outputDo.getThickness()) + "*宽" + CXCommonUtils.removeExtraZerosAndDecimal(outputDo.getWidth());
                if (ObjectUtil.isNotEmpty(outputDo.getLength())) {
                    outputdesc += "*长" + CXCommonUtils.removeExtraZerosAndDecimal(outputDo.getLength());
                }
                outputdesc += " mm " + CXCommonUtils.removeExtraZerosAndDecimal(outputDo.getWeight()) + "吨";
                needUpdate.setOutputdesc(outputdesc);
                apsReportOutputService.updateById(needUpdate);
            }
            //调用提交检验接口
            R r1 = reportCheckService.updateRelevantInformation(apsReportRecordsDo.getId());
            if (!r1.getCode().equals("200")) {
                throw new CustomException(r1.getMsg());
            }
            //当前登录人
//        SysUserVo currentUser = CXCommonUtils.getCurrentUser();
            //更新检查记录的检验人、检验时间
            ApsReportRecordsDo needUpdate = new ApsReportRecordsDo();
            needUpdate.setId(apsReportRecordsDo.getId());
            needUpdate.setCheckid(currentUser.getId());
            needUpdate.setCheckusername(currentUser.getName());
            needUpdate.setCheckdate(DateUtil.date());
            this.updateById(needUpdate);
        } finally {
            log.debug("报工完毕，从map中清空当前报工记录:{}", apsReportRecordsDo.getId());
            reportWorkLock.remove(apsReportRecordsDo.getId());
        }

        return R.ok();
    }

    private void addOrCopyWorkInProgress(List<ApsReportOutputDo> apsReportOutputDos,
                                         ApsWorkInProgressInventoryDo apsWorkInProgressInventoryDo,
                                         ApsProcessOperationProcessEquDo apsProcessOperationProcessEquDo,
                                         ApsProcessOperationDo apsProcessOperationDo,
                                         OrganizationCodeAndDeviceCodeVo organizationCodeAndDeviceCodeVo,
                                         ApsProductionOrderDo apsProductionOrderDo,
                                         ApsBlankOrderDo apsBlankOrderDo) {
        //获取所有报工输出物料对应的工序输出物料
        List<String> apsProcessMaterialIds = apsReportOutputDos.stream().map(ApsReportOutputDo::getOutputid).distinct().collect(Collectors.toList());
        Collection<ApsProcessOperationOutMaterDo> apsProcessOperationOutMaterDos = apsProcessOperationOutMaterService.listByIds(apsProcessMaterialIds);

        List<ApsWorkInProgressInventoryDo> needAddWorkInProgressInventoryList = new LinkedList<>();
        for (ApsReportOutputDo apsReportOutputDo : apsReportOutputDos) {
            //获取报工输出物料对应的工序输出物料
            ApsProcessOperationOutMaterDo apsProcessOperationOutMaterDo = apsProcessOperationOutMaterDos.stream().filter(item -> item.getId().equals(apsReportOutputDo.getOutputid())).findFirst().orElse(null);

            ApsWorkInProgressInventoryDo workInProgressInventoryDo = new ApsWorkInProgressInventoryDo();
            workInProgressInventoryDo.setId(SecurityUtil.getUUID());
            //获取当前用户相关信息
            SysUserVo currentUser = CXCommonUtils.getCurrentUser();
            String tenantId = CXCommonUtils.getCurrentUserFactoryId(currentUser);
            workInProgressInventoryDo.setTenantid(tenantId);
            //报工输出物料的批次号
            workInProgressInventoryDo.setBlankbatchnumber(apsReportOutputDo.getOutputnumber());
            //报工输出物料的主键ID
            workInProgressInventoryDo.setBlankid(apsReportOutputDo.getId());
            //报工输出物料的报工物料描述
            workInProgressInventoryDo.setBlankname(apsReportOutputDo.getOutputmaterial());
            //报工对应工序作业的坯料计划的坯料类型
            workInProgressInventoryDo.setBlanktype(apsBlankOrderDo.getBlanktype());
            if (ObjectUtil.isNotEmpty(apsWorkInProgressInventoryDo)) {
                workInProgressInventoryDo.setBlankbatchnumber(apsWorkInProgressInventoryDo.getBlankbatchnumber());
                workInProgressInventoryDo.setBlankid(apsWorkInProgressInventoryDo.getBlankid());
                workInProgressInventoryDo.setBlankname(apsWorkInProgressInventoryDo.getBlankname());
                workInProgressInventoryDo.setBlanktype(apsWorkInProgressInventoryDo.getBlanktype());
            }
            //报工记录对应的作业明细ID
            workInProgressInventoryDo.setProcessoperationequid(apsProcessOperationProcessEquDo.getId());
            //报工记录对应的工序作业ID
            workInProgressInventoryDo.setProcessoperationid(apsProcessOperationDo.getId());
            //报工记录ID
            workInProgressInventoryDo.setWorkreportrecordid(apsProcessOperationProcessEquDo.getWaitreportid());
            //报工记录输出物料对应的工序作业输出物料的主键ID
            workInProgressInventoryDo.setJoboutputmaterialid(apsReportOutputDo.getOutputid());
            //报工记录输出物料的主键ID
            workInProgressInventoryDo.setReportoutputmaterialid(apsReportOutputDo.getId());
            //输出物料的批次号
            workInProgressInventoryDo.setBatchnumber(apsReportOutputDo.getOutputnumber());
            //报工记录输出物料的报工物料描述
            workInProgressInventoryDo.setWorkinprocess(apsReportOutputDo.getOutputmaterial());
            //报工记录的报工日期
            workInProgressInventoryDo.setProductdate(DateUtil.date());
            //报工记录对应工序作业的加工设备所属工厂名称
            workInProgressInventoryDo.setProductfactory(organizationCodeAndDeviceCodeVo.getOwnedFactory());
            //报工记录对应工序作业明细的加工车间
            workInProgressInventoryDo.setProductworkshop(apsProcessOperationProcessEquDo.getProcessworkshop());
            //报工记录对应工序作业明细的加工设备
            workInProgressInventoryDo.setProductdevice(apsProcessOperationProcessEquDo.getProcessdevice());
            //工序作业的客户名称
            workInProgressInventoryDo.setCustomername(apsProductionOrderDo.getCustomname());
            //报工记录对应工序作业的订单号
            workInProgressInventoryDo.setOrdernumber(apsProductionOrderDo.getOrderno());
            workInProgressInventoryDo.setWorkinprocessstatus("待检验");
            //客户订单号
            workInProgressInventoryDo.setCustomorderno(apsProductionOrderDo.getCustomorderno());
            //订单类型
            workInProgressInventoryDo.setOrdertype(apsProductionOrderDo.getOrdertype());
            //作业输出物料
            String outPut = "";
            try {
                outPut = apsProcessOperationOutMaterDo.getMetal()
                        + apsProcessOperationOutMaterDo.getMetalstate()
                        + apsProcessOperationOutMaterDo.getProducttype()
                        + " 厚" + CXCommonUtils.removeExtraZerosAndDecimal(apsProcessOperationOutMaterDo.getThickness())
                        + "*宽" + CXCommonUtils.removeExtraZerosAndDecimal(apsProcessOperationOutMaterDo.getProwidth());
                if (ObjectUtil.isNotEmpty(apsProcessOperationOutMaterDo.getProlength())
                        && !CXCommonUtils.removeExtraZerosAndDecimal(apsProcessOperationOutMaterDo.getProlength()).equals("0")) {
                    outPut = outPut + "*长" + CXCommonUtils.removeExtraZerosAndDecimal(apsProcessOperationOutMaterDo.getProlength());
                }
                outPut = outPut + "mm";
//                outPut = outPut + " " + CXCommonUtils.removeExtraZerosAndDecimal(apsProcessOperationOutMaterDo.getSinglerollweight()) + "吨";
            } catch (Exception ignored) {
            }
            workInProgressInventoryDo.setJoboutputmaterial(outPut);
            //计划输出卷重
            workInProgressInventoryDo.setPlansinglerollweight(apsProcessOperationOutMaterDo.getSinglerollweight());

            needAddWorkInProgressInventoryList.add(workInProgressInventoryDo);
        }
        if (ObjectUtil.isNotEmpty(needAddWorkInProgressInventoryList)) {
            apsWorkInProgressInventoryService.saveBatch(needAddWorkInProgressInventoryList);
        }
    }

    @Override
    public R checkMergeProcess(ApsReportRecordsDo req) {
        //作业明细的ID
        String processequid = req.getProcessequid();
        //当前报工的作业明细的详情
        ApsProcessOperationProcessEquDo apsProcessOperationProcessEquDo = apsProcessOperationProcessEquService.getById(processequid);
        //查询其他 与当前作业明细计划开工时间相同，并且未开工（待报工记录ID为空）的作业明细
        List<ApsProcessOperationProcessEquDo> list = this.baseMapper.selectOtherMergeProcessEqu(apsProcessOperationProcessEquDo.getId(), apsProcessOperationProcessEquDo.getProcessdeviceid(), apsProcessOperationProcessEquDo.getPlanstartdate());
        CheckMergeProcessResopnse res = new CheckMergeProcessResopnse();
        if (list.size() > 0) {
            //查询当前工序作业明细的工序详情
            ApsProcessOperationDo apsProcessOperationDo = apsProcessOperationService.getById(req.getProcessoperationid());
            res.setNeedWarning(true);
            res.setWarningMessage("该合并作业" + apsProcessOperationDo.getProcess() + "还有其他作业需要一起开工，请及时开工");
            return R.ok(res);
        }

        return R.ok(res);
    }

    @Override
    @Transactional
    public R smallRollStartReport(SmallRollStartReportReq req) {
        if (ObjectUtil.isEmpty(req.getUseDeviceId())) {
            return R.error("工序作业明细ID不能为空");
        }
        if (ObjectUtil.isEmpty(req.getInputBatchNumberList())) {
            return R.error("至少要有一个待加工料卷批次号");
        }

        SysUserVo currentUser = CXCommonUtils.getCurrentUser();
        if (startWorkLock.containsKey(req.getUseDeviceId())) {
            log.error("该小卷作业已被：{}开工", startWorkLock.get(req.getUseDeviceId()));
            return R.error("该作业已被开工");
        }
        startWorkLock.put(req.getUseDeviceId(), currentUser.getId());
        try {

            //根据作业明细ID查询作业明细详情
            ApsProcessOperationProcessEquDo apsProcessOperationProcessEquDo = apsProcessOperationProcessEquService.getById(req.getUseDeviceId());
            //如果已开工卷数！= 已报工卷数，说明已经开工了，提示已开工
            if (!apsProcessOperationProcessEquDo.getStartingroll().equals(apsProcessOperationProcessEquDo.getReportroll())) {
                return R.error("此作业已开工，请刷新列表后重试");
            }


//        String useDeviceId = req.getUseDeviceId();
//        ApsProcessOperationProcessEquDo apsProcessOperationProcessEquDo = apsProcessOperationProcessEquService.getById(useDeviceId);
            ApsProcessOperationDo apsProcessOperationDo = apsProcessOperationService.getById(apsProcessOperationProcessEquDo.getProcessid());
            ApsBlankOrderDo apsBlankOrderDo = apsBlankOrderService.getById(apsProcessOperationDo.getBlankid());
            ApsProductionOrderDo apsProductionOrderDo = apsProductionOrderService.getById(apsBlankOrderDo.getProductionorderid());

            List<String> inputBatchNumberList = req.getInputBatchNumberList();
            List<String> needWorkBatchNumberList = Arrays.asList(apsProcessOperationProcessEquDo.getBachmaterialprocess().split(","));
            //如果选择的批次号不在待加工料卷批次号中

            //错误的待加工料卷批次号集合
            List<String> withOutBatchNumberList = new LinkedList<>();
            for (String s : inputBatchNumberList) {
                if (!needWorkBatchNumberList.contains(s)) {
                    withOutBatchNumberList.add(s);
                }
            }
            //如果有批次号不在待加工料卷批次号中，则错误提示：批次号：{错误批次号逗号拼接}已经被其他作业开工，请重新选择
            if (withOutBatchNumberList.size() > 0) {
                return R.error("批次号：" + String.join(",", withOutBatchNumberList) + "已经被其他作业开工，请重新选择");
            }

            //当前登录用户信息
//        SysUserVo currentUser = CXCommonUtils.getCurrentUser();
            String tenantId = CXCommonUtils.getCurrentUserFactoryId(currentUser);

            //查询此工序对应工艺步骤中，对应设备的设备参数
            String equparames = "";
            //查询工序步骤
            String stepnum = apsProcessOperationDo.getStepnum();
            ApsCraftStepDo craftStepDo = apsCraftStepService.getOne(new QueryWrapper<ApsCraftStepDo>().lambda().eq(ApsCraftStepDo::getStepnum, stepnum));
            if (ObjectUtil.isNotEmpty(craftStepDo)) {
                //查询设备参数子表
                ApsCraftEquDo apsCraftEquDo = apsCraftEquService.getOne(new QueryWrapper<ApsCraftEquDo>().lambda().eq(ApsCraftEquDo::getMainid, craftStepDo.getId()).eq(ApsCraftEquDo::getResourceid, apsProcessOperationProcessEquDo.getProcessdeviceid()).eq(ApsCraftEquDo::getTenantid, tenantId));
                if (ObjectUtil.isNotEmpty(apsCraftEquDo)) {
                    equparames = apsCraftEquDo.getEquparames();
                }
            }

            //============生成报工记录===============
            //新增主表报工记录信息
            ApsReportRecordsDo apsReportRecordsDo = new ApsReportRecordsDo();
            apsReportRecordsDo.setId(SecurityUtil.getUUID());
            apsReportRecordsDo.setTenantid(tenantId);
            //工序作业ID
            apsReportRecordsDo.setProcessoperationid(apsProcessOperationDo.getId());
            //作业明细ID
            apsReportRecordsDo.setProcessequid(apsProcessOperationProcessEquDo.getId());
            //输入物料的批次号
            apsReportRecordsDo.setBatchnumber(String.join(",", inputBatchNumberList));
            //实际输入物料
            apsReportRecordsDo.setActualinputmaterial(apsProcessOperationDo.getPlaninput());
            //主操作员
            apsReportRecordsDo.setChiefoperatorid(currentUser.getId());
            apsReportRecordsDo.setChiefoperatorname(currentUser.getName());
            //开工时间
            apsReportRecordsDo.setStartworktime(DateUtil.date());
            //报工状态
            apsReportRecordsDo.setReportworkstatus("已开工");
            apsReportRecordsDo.setCheckstatus("待检验");
            //设备参数
            apsReportRecordsDo.setDeviceparm(equparames);
            //注意事项
            apsReportRecordsDo.setAttention(apsProcessOperationDo.getRemark());

            //============开工时，生成炉号和批次号=============
            //获取设备/炉 的炉号（每月、每个设备/炉 更新）
            String heatNumber;//初始化炉号
            //如果存在其他合并工序，并且其他合并工序已开工，则不去生成新的 炉次号 使用其他合并工序的 开工记录的 炉次号
            List<ApsProcessOperationProcessEquDo> apsProcessEquMergeStartingList = this.baseMapper.selectOtherMergeProcessStarting(apsProcessOperationProcessEquDo.getId(), apsProcessOperationProcessEquDo.getProcessdeviceid(), apsProcessOperationProcessEquDo.getPlanstartdate());

            if (apsProcessEquMergeStartingList.size() > 0) {
                //合并工序作业明细
                ApsProcessOperationProcessEquDo equDo = apsProcessEquMergeStartingList.get(0);
                //查询该合并工序作业明细的待报工记录ID
                String waitreportid = equDo.getWaitreportid();
                //待报工记录详情
                ApsReportRecordsDo aDo = this.getById(waitreportid);
                heatNumber = aDo.getHeatnumber();
            } else {
                //调用通用接口生成炉号
                SysSerialVo vo = new SysSerialVo();
                vo.setModulecode("aps_report_output_heat_" + apsProcessOperationProcessEquDo.getProcessdeviceid());
                vo.setRuleTemplateStr("@{serialNumber:#000}");
                vo.setResetrule("date:yyyyMM");
                vo.setIfautomaticreset("y");
                vo.setInitValue(0L);
                Map<String, Object> codeData = cxAdminFeginClient.getSerialNumberCode(vo).getData();
                heatNumber = codeData.get("code").toString();
            }

            apsReportRecordsDo.setHeatnumber(heatNumber);
            this.save(apsReportRecordsDo);

            /**
             * 如果该作业的工序是小卷成退或小卷包装，则每个输入物料的批次号根据工序作业输出物料自动生成报工明细输出物料，例如：有100个输入物料批次号则生成100个输出物料，参见【报工记录字段说明/输出物料字段说明】
             * 自动填入检验结果字段的默认值，检验等级=B级，是否合格=是，实测卷重=输出物料卷重，实测厚度=输出物料厚度，实测宽度=输出物料宽度，实测长度=输出物料长度，
             * 自动生成报工记录所有输出物料批次号，参见【自动生成批次号】，以及对应的二维码
             * 根据工序加工参数设置自动生成该工序所有加工参数明细，参见【报工记录字段说明/加工参数字段说明】
             * 根据工序检测参数设置自动生成该工序所有检测参数明细，参见【报工记录字段说明/检测参数字段说明】
             */
            //========生成输出物料子表===========
            OrganizationCodeAndDeviceCodeVo organizationCodeAndDeviceCodeVo = this.baseMapper.selectOrganizationCodeAndDeviceCode(apsProcessOperationProcessEquDo.getProcessdeviceid());
            for (String inputBatchNumber : inputBatchNumberList) {
                InsertMyReportOutputReq insertMyReportOutputReq = new InsertMyReportOutputReq();
                insertMyReportOutputReq.setMainId(apsReportRecordsDo.getId());
                insertMyReportOutputReq.setProcessId(apsProcessOperationDo.getId());
                insertMyReportOutputReq.setIfBlankProcess(apsProcessOperationDo.getIfblankprocess());
                insertMyReportOutputReq.setDeviceId(apsProcessOperationProcessEquDo.getProcessdeviceid());
                insertMyReportOutputReq.setMark(organizationCodeAndDeviceCodeVo.getOrganizationCode());
                insertMyReportOutputReq.setYearCode((DateUtil.year(DateUtil.date()) % 100) + "");
                insertMyReportOutputReq.setMonthCode(SaveConstans.MONTH_CODE_LIST.get(DateUtil.month(DateUtil.date())));
                insertMyReportOutputReq.setEquipmentCode(organizationCodeAndDeviceCodeVo.getDeviceCode());
                insertMyReportOutputReq.setHeatNumber(heatNumber);
                insertMyReportOutputReq.setInputBatchNumber(inputBatchNumber);
                insertMyReportOutputReq.setBlankType(apsBlankOrderDo.getBlanktype());
                insertMyReportOutputReq.setLevel(apsProcessOperationDo.getLevel());
                if (apsProcessOperationDo.getProcess().equals("铸轧")) {
                    insertMyReportOutputReq.setInsepctionLevel(SaveConstans.CheckLevel.WAITING_JUDGMENT);
                    insertMyReportOutputReq.setQualified("");
                }

                R r = apsReportOutputService.insertMyReportOutput(insertMyReportOutputReq);
                if (!r.getCode().equals("200")) {
                    throw new CustomException(r.getMsg());
                }
            }
            //=============加工参数子表信息、检查项目子表信息================
            if (ObjectUtil.isNotEmpty(apsProcessOperationDo.getProcess())) {
                //根据工序查询其工序的加工参数
                List<ApsParameterDo> parameterDoList = this.baseMapper.selectApsParameterByProcess(apsProcessOperationDo.getProcess());
                List<ApsReportMachiningDo> needInsertApsReportMachingList = new LinkedList<>();
                if (ObjectUtil.isNotEmpty(parameterDoList)) {
                    for (ApsParameterDo apsParameterDo : parameterDoList) {
                        if (ObjectUtil.isEmpty(apsParameterDo)) {
                            continue;
                        }
                        ApsReportMachiningDo apsReportMachiningDo = new ApsReportMachiningDo();
                        apsReportMachiningDo.setId(SecurityUtil.getUUID());
                        apsReportMachiningDo.setTenantid(tenantId);
                        apsReportMachiningDo.setMainid(apsReportRecordsDo.getId());
                        apsReportMachiningDo.setMatching(apsParameterDo.getParameter());
                        apsReportMachiningDo.setRemark(apsParameterDo.getRemark());
                        needInsertApsReportMachingList.add(apsReportMachiningDo);
                    }
                    if (ObjectUtil.isNotEmpty(needInsertApsReportMachingList)) {
                        apsReportMachiningService.saveBatch(needInsertApsReportMachingList);
                    }
                }

                //根据工序查询其工序的检查项目
                List<ApsCheckParameterDo> checkParameterDoList = this.baseMapper.selectApsCheckParameterByProcess(apsProcessOperationDo.getProcess());
                List<ApsReportCheckoutDo> needInsertApsReportCheckList = new LinkedList<>();
                if (ObjectUtil.isNotEmpty(checkParameterDoList)) {
                    for (ApsCheckParameterDo apsCheckParameterDo : checkParameterDoList) {
                        if (ObjectUtil.isEmpty(apsCheckParameterDo)) {
                            continue;
                        }
                        ApsReportCheckoutDo apsReportCheckoutDo = new ApsReportCheckoutDo();
                        apsReportCheckoutDo.setId(SecurityUtil.getUUID());
                        apsReportCheckoutDo.setTenantid(tenantId);
                        apsReportCheckoutDo.setMainid(apsReportRecordsDo.getId());
                        apsReportCheckoutDo.setCheckitem(apsCheckParameterDo.getCheckparameter());
                        needInsertApsReportCheckList.add(apsReportCheckoutDo);
                    }
                    if (ObjectUtil.isNotEmpty(needInsertApsReportCheckList)) {
                        apsReportCheckoutService.saveBatch(needInsertApsReportCheckList);
                    }
                }

            }
            //=============坯料成分子表信息=============
            //工序作业的是否坯料工序=是 时，根据客户合金成分设置自动生成
            if (apsProcessOperationDo.getIfblankprocess().equals("是")) {
                //工序作业的合金
                String metal = apsProcessOperationDo.getMetal();
                //订单的客户ID
                String customid = apsProductionOrderDo.getCustomid();
                String alloyId = "";
                //查询合金对应的所有主表信息
                List<ApsAlloyDo> apsAlloyDoList = apsAlloyService.list(new QueryWrapper<ApsAlloyDo>().lambda().eq(ApsAlloyDo::getAlloy, metal));
                if (ObjectUtil.isNotEmpty(apsAlloyDoList)) {
                    //查询客户标准
                    List<ApsAlloyDo> collect = apsAlloyDoList.stream().filter(item -> ObjectUtil.isNotEmpty(item.getCustomerid()) && item.getCustomerid().contains(customid)).collect(Collectors.toList());
                    if (ObjectUtil.isNotEmpty(collect)) {
                        alloyId = collect.get(0).getId();
                    } else {//查询国标
                        List<ApsAlloyDo> collect1 = apsAlloyDoList.stream().filter(item -> ObjectUtil.isEmpty(item.getCustomerid())).collect(Collectors.toList());
                        if (ObjectUtil.isNotEmpty(collect1)) {
                            alloyId = collect1.get(0).getId();
                        }
                    }
                }
                //查询合金成分要求
                if (ObjectUtil.isNotEmpty(alloyId)) {
                    List<ApsAlloyCompositionDo> apsAlloyCompositionDoList = apsAlloyCompositionService.list(new QueryWrapper<ApsAlloyCompositionDo>().lambda().eq(ApsAlloyCompositionDo::getAlloyid, alloyId));

                    if (ObjectUtil.isNotEmpty(apsAlloyCompositionDoList)) {
                        List<ApsReportBlankCompentDo> needInsertApsReportBlankCompentList = new LinkedList<>();
                        for (ApsAlloyCompositionDo apsAlloyCompositionDo : apsAlloyCompositionDoList) {
                            ApsReportBlankCompentDo apsReportBlankCompentDo = new ApsReportBlankCompentDo();
                            apsReportBlankCompentDo.setId(SecurityUtil.getUUID());
                            apsReportBlankCompentDo.setTenantid(tenantId);
                            apsReportBlankCompentDo.setMainid(apsReportRecordsDo.getId());
                            apsReportBlankCompentDo.setCompent(apsAlloyCompositionDo.getIngredient());
                            apsReportBlankCompentDo.setStartproportion(apsAlloyCompositionDo.getLeftproportion());
                            apsReportBlankCompentDo.setEndproportion(apsAlloyCompositionDo.getRightproportion());
                            needInsertApsReportBlankCompentList.add(apsReportBlankCompentDo);
                        }
                        if (ObjectUtil.isNotEmpty(needInsertApsReportBlankCompentList)) {
                            apsReportBlankCompentService.saveBatch(needInsertApsReportBlankCompentList);
                        }

                    }
                }
            } else {//不是坯料工序，根据输入物料批次号，查询来源报工的坯料成分，copy一份
                String inputBatchNumber = req.getInputBatchNumberList().get(0);
                //查询上一个的报工ID
                String lastReportRecordId = this.baseMapper.selectLastReoprtRecordByBatchNumber(inputBatchNumber);
                if (ObjectUtil.isNotEmpty(lastReportRecordId)) {
                    //查询上一个报工的坯料成分
                    List<ApsReportBlankCompentDo> apsReportBlankCompentDoList = apsReportBlankCompentService.list(new QueryWrapper<ApsReportBlankCompentDo>().lambda().eq(ApsReportBlankCompentDo::getMainid, lastReportRecordId));
                    //复制新增
                    List<ApsReportBlankCompentDo> needAddList = new LinkedList<>();
                    for (ApsReportBlankCompentDo apsReportBlankCompentDo : apsReportBlankCompentDoList) {
                        ApsReportBlankCompentDo needAdd = new ApsReportBlankCompentDo();
                        needAdd.setId(SecurityUtil.getUUID());
                        needAdd.setTenantid(tenantId);
                        needAdd.setMainid(apsReportRecordsDo.getId());
                        needAdd.setCompent(apsReportBlankCompentDo.getCompent());
                        needAdd.setStartproportion(apsReportBlankCompentDo.getStartproportion());
                        needAdd.setEndproportion(apsReportBlankCompentDo.getEndproportion());
                        needAdd.setActualproportion(apsReportBlankCompentDo.getActualproportion());
                        needAddList.add(needAdd);
                    }
                    apsReportBlankCompentService.saveBatch(needAddList);
                }
            }

            /**
             * 检查每个输入批次号，
             * 如果在制品库存中有输入物料批次号的在制品，则更新该在制品的在制品状态=加工中
             * 查找输入物料所有后道作业明细，即前道作业明细的所有后道作业明细中，
             * 其工序作业的输入物料ID和报工记录的工序作业的输入物料ID相同的所有作业明细，将这些作业明细的待加工料卷批次号去掉“{输入批次号}，”
             */
            //更新待加工料卷批次号
            if (ObjectUtil.isNotEmpty(apsProcessOperationProcessEquDo.getPreviousprocessesids())) {
                List<ApsProcessOperationProcessEquDo> needUpdateBatchNumber = apsProcessOperationProcessEquService.list(new QueryWrapper<ApsProcessOperationProcessEquDo>().lambda().eq(ApsProcessOperationProcessEquDo::getPreviousprocessesids, apsProcessOperationProcessEquDo.getPreviousprocessesids()));
                if (ObjectUtil.isNotEmpty(needUpdateBatchNumber)) {
                    List<ApsProcessOperationProcessEquDo> needUpdateList = new LinkedList<>();

                    for (ApsProcessOperationProcessEquDo processOperationProcessEquDo : needUpdateBatchNumber) {
                        List<String> oldList = new LinkedList<>();
                        //原待加工批次号不为空
                        if (ObjectUtil.isNotEmpty(processOperationProcessEquDo.getBachmaterialprocess())) {
                            oldList = new LinkedList<>(Arrays.asList(processOperationProcessEquDo.getBachmaterialprocess().split(",")));
                            oldList.removeAll(inputBatchNumberList);

                            String newBatch = String.join(",", oldList);
                            ApsProcessOperationProcessEquDo needUpdate = new ApsProcessOperationProcessEquDo();
                            needUpdate.setId(processOperationProcessEquDo.getId());
                            needUpdate.setBachmaterialprocess(newBatch);
                            needUpdateList.add(needUpdate);
                        }
                    }
                    if (ObjectUtil.isNotEmpty(needUpdateList)) {
                        apsProcessOperationProcessEquService.updateBatchById(needUpdateList);
                    }
                }
            }


            for (String inputBatchNumber : inputBatchNumberList) {
                //更新在制品状态
                apsWorkInProgressInventoryService.update(new UpdateWrapper<ApsWorkInProgressInventoryDo>().lambda()
                        .set(ApsWorkInProgressInventoryDo::getWorkinprocessstatus, "加工中")
                        .eq(ApsWorkInProgressInventoryDo::getBatchnumber, inputBatchNumber)
                        .eq(ApsWorkInProgressInventoryDo::getDeleted, "0"));

            }
            //========更新工序作业明细==========
            ApsProcessOperationProcessEquDo needUpdateProcessEqu = new ApsProcessOperationProcessEquDo();
            needUpdateProcessEqu.setId(apsProcessOperationProcessEquDo.getId());
            //该工序作业明细的加工中批次号=“{批次号}-{单个分卷序列号}”逗号拼接
            needUpdateProcessEqu.setDoingbatchnumber(String.join(",", inputBatchNumberList));

            //如果该作业明细的已开工卷数=0，则该作业明细的实际开工时间=当前时间；作业状态=加工中
            if (apsProcessOperationProcessEquDo.getStartingroll().equals(0)) {
                needUpdateProcessEqu.setActualstartdate(DateUtil.date());
                needUpdateProcessEqu.setWorkstatus("加工中");
            }

            //更新该作业明细已开工卷数=已开工卷数+输入批次号数量，待报工记录ID=该报工记录ID
            needUpdateProcessEqu.setStartingroll(apsProcessOperationProcessEquDo.getStartingroll() + inputBatchNumberList.size());
            needUpdateProcessEqu.setWaitreportid(apsReportRecordsDo.getId());

            apsProcessOperationProcessEquService.updateById(needUpdateProcessEqu);
            //========更新工序作业=============
            ApsProcessOperationDo needUpdateProcess = new ApsProcessOperationDo();
            needUpdateProcess.setId(apsProcessOperationDo.getId());
            //如果该工序作业已开工卷数=0，则
            //该工序作业的实际开工时间=当前时间，作业状态=加工中，生产状态=加工中

            if (apsProcessOperationDo.getStartingroll().equals(0)) {
                needUpdateProcess.setActualstartdate(DateUtil.date());
                needUpdateProcess.setWorkstatus("加工中");
                needUpdateProcess.setProcessstatus(SaveConstans.ProductionStatus.PROCESSING);
            }
            //更新该工序作业已开工卷数=已开工卷数+输入批次号数量
            needUpdateProcess.setStartingroll(apsProcessOperationDo.getStartingroll() + inputBatchNumberList.size());
            //剩余待开工卷数=计划加工卷数-已开工卷数-输入已取消卷数-已取消卷数
            needUpdateProcess.setLeavewaitworkroll(apsProcessOperationDo.getPlanprocessrall() - needUpdateProcess.getStartingroll() - apsProcessOperationDo.getInputunqualifiedroll() - apsProcessOperationDo.getCancelroll());
            apsProcessOperationService.updateById(needUpdateProcess);

            //更新坯料计划状态，参见【订单排程/一键自动排程/更新坯料计划状态】
            //=========更新生产状态等=============
            CommonUpdateProductionStatusReq req3 = new CommonUpdateProductionStatusReq();
            req3.setProcessOperationEquId(apsProcessOperationProcessEquDo.getId());
            R r2 = apsProcessOperationProcessEquService.updateProductionStatus(req3);
            if (!r2.getCode().equals("200")) {
                throw new CustomException(r2.getMsg());
            }

            return R.ok(apsReportRecordsDo);
        } finally {
            log.debug("小卷开工完毕，从map中清空当前开工锁，作业明细ID:{}", req.getUseDeviceId());
            startWorkLock.remove(req.getUseDeviceId());
        }
    }


}




