package cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.busi;

import cn.estsh.i3plus.ext.mes.pcn.api.base.IPartExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.base.ISxWorkOrderExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IOqcManageService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IPackageExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IProduceSnExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IProduceSnRepairService;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.dao.IOutPutStatisticsDao;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.dao.IPackageExtDao;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.dao.IProduceSnRepairDao;
import cn.estsh.i3plus.ext.mes.pcn.pojo.bean.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.bu.BuOutPutStatisticsModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.ep.EpQmsOutPutStatisticsModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.repository.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.sqlpack.MesPcnExtHqlPack;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtEnumUtil;
import cn.estsh.i3plus.mes.pcn.api.iservice.busi.ISyncFuncService;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.exception.ImppExceptionEnum;
import cn.estsh.i3plus.platform.common.tool.MathOperation;
import cn.estsh.i3plus.pojo.base.bean.BaseResultBean;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.bean.ListPager;
import cn.estsh.i3plus.pojo.base.common.Pager;
import cn.estsh.i3plus.pojo.base.common.PagerHelper;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.enumutil.MesPcnEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.MesPackageDetail;
import cn.estsh.i3plus.pojo.mes.model.GenSerialNoModel;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import cn.estsh.impp.framework.boot.util.ImppRedis;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

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

/**
 * @author wangjie
 * @version 1.0
 * @date 2021/1/13 9:28
 *
 * 成品：
 * 1.日常&拆机&空洞：抽检数量=1，批次范围(日常=拆机),必须先做日常||空洞,才能做拆机
 * 2.一个条码日常||空洞跟拆机都只能做一次，批次范围内的条码不能再生成单据
 * 3.新产量数据时批次范围内有未关联完成的单据时不能再生成日常或拆机单据
 * 4.日常&拆机&空洞:新产量数据时,批次范围可大于产量,但要小于剩余批次,   剩余批次=计划数量-(汇总旧产量数据的产量+新产量数据的批次范围)
 *                旧产量数据时,批次范围小于剩余批次,    剩余批次=此产量数据的产量-此产量数据批次范围
 * 5.新产量数据时判断旧产量数据是否存在批次范围大于产量的 改成等于产量, 总单据批次范围也需要调整
 *
 * 组件：
 * 1.组件不做拆机
 * 2.日常跟空洞,一个工单只能生成一个类型的单据,有单据未点结果则不能再生成
 * 3.日常&空洞:新产量数据时,批次范围可大于产量,但要小于剩余批次,   剩余批次=计划数量-(汇总旧产量数据的产量+新产量数据的批次范围)
 *            旧产量数据时,批次范围小于剩余批次,    剩余批次=此产量数据的产量-此产量数据批次范围
 * 4.新产量数据时判断旧产量数据是否存在批次范围大于产量的 改成等于产量, 总单据批次范围也需要调整
 *
 **/
@Slf4j
@Service
public class OqcManageService implements IOqcManageService {

    @Autowired
    private MesOutPutStatisticsRepository outPutStatisticsRepository;

    @Autowired
    private MesOutPutStatisticsOqcRepository outPutStatisticsOqcRepository;

    @Autowired
    private MesOqcCheckRepository oqcCheckRepository;

    @Autowired
    private SxOqcCheckRepository sxOqcCheckRepository;

    @Autowired
    private MesOqcCheckDetailRepository oqcCheckDetailRepository;

    @Autowired
    private MesOqcProjectRepository oqcProjectRepository;

    @Autowired
    private MesOqcPackageDetailRepository oqcPackageDetailRepository;

    @Autowired
    private SxOqcSingleRepository sxOqcSingleRepository;

    @Autowired
    private SxOqcBatchRepository sxOqcBatchRepository;

    @Autowired
    private IPartExtService partExtService;

    @Autowired
    private ISxWorkOrderExtService workOrderExtService;

    @Autowired
    private IPackageExtService packageExtService;

    @Autowired
    private IProduceSnExtService produceSnExtService;

    @Autowired
    private IPackageExtDao packageExtDao;

    @Autowired
    private IProduceSnRepairDao produceSnRepairDao;

    @Autowired
    private IProduceSnRepairService produceSnRepairService;

    @Autowired
    private ISyncFuncService syncFuncService;

    @Autowired
    private IOutPutStatisticsDao outPutStatisticsDao;

    @Autowired
    private MesErrorLineOffRepository errorLineOffRepository;

    @Resource(name = MesPcnExtConstWords.REDIS_RES_PCN)
    private ImppRedis redisMesPcn;

    @Override
    public OqcManageModel queryOqcData(OqcManageModel model) {
        OqcManageModel result = new OqcManageModel();

        Map<Integer, Boolean> spotCheckQtyReadOnlyMap = new HashMap<>();
        spotCheckQtyReadOnlyMap.put(10, true);
        spotCheckQtyReadOnlyMap.put(20, true);
        spotCheckQtyReadOnlyMap.put(30, true);

        Map<Integer, Boolean> batchLimitReadOnlyMap = new HashMap<>();
        batchLimitReadOnlyMap.put(10, true);
        batchLimitReadOnlyMap.put(20, true);
        batchLimitReadOnlyMap.put(30, true);

        Map<Integer, Boolean> genOqcReadOnlyMap = new HashMap<>();
        genOqcReadOnlyMap.put(10, true);
        genOqcReadOnlyMap.put(20, true);
        genOqcReadOnlyMap.put(30, true);

        Map<Integer, Double> batchLimitMap = new HashMap<>();
        batchLimitMap.put(10, new Double(1));
        batchLimitMap.put(20, new Double(1));
        batchLimitMap.put(30, new Double(1));

        String key = new StringJoiner(MesPcnExtConstWords.COLON).add(model.getOrganizeCode()).add(MesPcnExtConstWords.OQC_MANAGE_DATA).toString();

        if (StringUtils.isEmpty(model.getSn()) && StringUtils.isEmpty(model.getId())) {
            Object obj = redisMesPcn.getHash(key, model.getUserId());
            if (null == obj) {
                result.setBatchLimitMap(batchLimitMap);
                result.setSpotCheckQtyReadOnlyMap(spotCheckQtyReadOnlyMap);
                result.setBatchLimitReadOnlyMap(batchLimitReadOnlyMap);
                result.setGenOqcReadOnlyMap(genOqcReadOnlyMap);
                return result;
            }
            if (obj instanceof Map) {
                Map<String, String> scanInfoMap = (Map<String, String>) obj;
                if (CollectionUtils.isEmpty(scanInfoMap)) {
                    result.setBatchLimitMap(batchLimitMap);
                    result.setSpotCheckQtyReadOnlyMap(spotCheckQtyReadOnlyMap);
                    result.setBatchLimitReadOnlyMap(batchLimitReadOnlyMap);
                    result.setGenOqcReadOnlyMap(genOqcReadOnlyMap);
                    return result;
                }
            } else if (obj instanceof Long) {
                model.setId((Long) obj);
            } else {
                result.setBatchLimitMap(batchLimitMap);
                result.setSpotCheckQtyReadOnlyMap(spotCheckQtyReadOnlyMap);
                result.setBatchLimitReadOnlyMap(batchLimitReadOnlyMap);
                result.setGenOqcReadOnlyMap(genOqcReadOnlyMap);
                return result;
            }
        }

        //组件抽检查询
        if (!StringUtils.isEmpty(model.getId())) {
            result.setSnReadOnly(true);
            result.setChangeReadOnly(true);

            MesOutPutStatistics outPutStatistics = outPutStatisticsRepository.getById(model.getId());
            if (null == outPutStatistics) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("组件抽检:产量统计信息ID[%s]无效", model.getId())
                        .build();
            }
            MesPartExt partExt = partExtService.getPartExt(model.getOrganizeCode(), outPutStatistics.getPartNo());
            if (null == partExt) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("组件抽检:产量统计信息ID[%s]关联的物料编码[%s]无效", model.getId(), outPutStatistics.getPartNo())
                        .build();
            }
            if (StringUtils.isEmpty(partExt.getIsOqc()) || CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue() == partExt.getIsOqc()) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("组件抽检:产量统计信息ID[%s]关联的物料编码[%s]不支持出货检验", model.getId(), outPutStatistics.getPartNo())
                        .build();
            }

            if (StringUtils.isEmpty(partExt.getCategoryCode2())) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("组件抽检:产量统计信息ID[%s]关联的物料编码[%s]的产品类型不是组件", model.getId(), outPutStatistics.getPartNo())
                        .build();
            }

            MesOutPutStatisticsOqc outPutStatisticsOqc = outPutStatisticsOqcRepository.getByProperty(
                    new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.PID},
                    new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getId()});
            if (null == outPutStatisticsOqc) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("组件抽检:产量统计信息ID[%s]未关联出货检验信息数据", model.getId())
                        .build();
            }

            MesWorkOrderExt workOrderExt = workOrderExtService.getWorkOrderExtByOrderNo(model.getOrganizeCode(), outPutStatistics.getWorkOrderNo());
            if (null == workOrderExt) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("组件抽检:产量统计信息ID[%s]关联的工单编码[%s]无效", model.getId(), outPutStatistics.getWorkOrderNo())
                        .build();
            }

            result.setWorkOrderNo(outPutStatistics.getWorkOrderNo());
            result.setWorkOrderType(workOrderExt.getWorkOrderType());
            result.setWorkOrderTypeName(MesPcnExtEnumUtil.WORK_ORDER_TYPE.valueOfDescription(workOrderExt.getWorkOrderType()));
            result.setPartNo(outPutStatistics.getPartNo());
            result.setPartNameRdd(outPutStatistics.getPartNameRdd());
            result.setWorkCenterCode(outPutStatistics.getWorkCenterCode());
            result.setWorkTime(outPutStatistics.getWorkTime());
            result.setShiftCode(outPutStatistics.getShiftCode());
            result.setCategoryCode3(partExt.getCategoryCode3());
            result.setPlanQty(outPutStatistics.getPlanQty());
            result.setCompleteQty(outPutStatistics.getQty());
            result.setCheckLimit(outPutStatisticsOqc.getCheckLimit());

            spotCheckQtyReadOnlyMap.put(10, false);
            spotCheckQtyReadOnlyMap.put(20, true);
            spotCheckQtyReadOnlyMap.put(30, false);

            batchLimitReadOnlyMap.put(10, false);
            batchLimitReadOnlyMap.put(20, true);
            batchLimitReadOnlyMap.put(30, false);

            genOqcReadOnlyMap.put(10, false);
            genOqcReadOnlyMap.put(20, true);
            genOqcReadOnlyMap.put(30, false);

            batchLimitMap.put(10, MathOperation.sub(outPutStatistics.getQty(), outPutStatisticsOqc.getCheckLimit()) > 0 ?
                    MathOperation.sub(outPutStatistics.getQty(), outPutStatisticsOqc.getCheckLimit()) : new Double(0));
            batchLimitMap.put(20, new Double(1));
            batchLimitMap.put(30, batchLimitMap.get(10));

            DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());
            DdlPreparedPack.getStringEqualPack(outPutStatistics.getWorkOrderNo(), MesPcnExtConstWords.ORDER_NO, packBean);
            DdlPreparedPack.getStringEqualPack(outPutStatistics.getShiftCode(), MesPcnExtConstWords.SHIFT_CODE, packBean);
            DdlPreparedPack.getStringEqualPack(outPutStatistics.getWorkTime(), MesPcnExtConstWords.WORK_TIME, packBean);
            DdlPreparedPack.getIsNull(MesPcnExtConstWords.SERIAL_NUMBER, packBean);
            DdlPreparedPack.getOrderByPack(new Object[]{CommonEnumUtil.ASC_OR_DESC.DESC.getValue()}, new String[]{MesPcnExtConstWords.CREATE_DATE_TIME}, packBean);
            List<MesOqcCheck> oqcCheckList = oqcCheckRepository.findByHqlWhere(packBean);
            if (CollectionUtils.isEmpty(oqcCheckList)) {

                result.setBatchLimitMap(batchLimitMap);
                result.setSpotCheckQtyReadOnlyMap(spotCheckQtyReadOnlyMap);
                result.setBatchLimitReadOnlyMap(batchLimitReadOnlyMap);
                result.setGenOqcReadOnlyMap(genOqcReadOnlyMap);

            } else {
                MesOqcCheck oqcCheck;
                Optional<MesOqcCheck> oqcCheckOp;
                if (!StringUtils.isEmpty(model.getOqcNo())) {
                    oqcCheckOp = oqcCheckList.stream().filter(o -> (null != o && o.getOqcNo().equals(model.getOqcNo()))).findFirst();
                } else {
                    oqcCheckOp = oqcCheckList.stream().filter(o -> (null != o &&
                            (StringUtils.isEmpty(StringUtils.isEmpty(o.getCheckResult())) || null == MesPcnExtEnumUtil.OQC_CHECK_RESULT.getByValue(o.getCheckResult())))).findFirst();
                }
                if (null != oqcCheckOp && oqcCheckOp.isPresent()) {
                    oqcCheck = oqcCheckOp.get();
                } else {
                    oqcCheck = oqcCheckList.get(0);
                }

                result.setOqcNo(oqcCheck.getOqcNo());
                result.setCurOqcTypeName(MesPcnExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(oqcCheck.getOqcType()));
                result.setCurOqcType(oqcCheck.getOqcType());
                result.setCurSpotCheckQty(oqcCheck.getSpotCheckQty());
                result.setCurBatchLimit(oqcCheck.getBatchLimit());
                result.setCurCheckResultName((StringUtils.isEmpty(oqcCheck.getCheckResult()) || null == MesPcnExtEnumUtil.OQC_CHECK_RESULT.getByValue(oqcCheck.getCheckResult()))
                        ? null : MesPcnExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(oqcCheck.getCheckResult()));
                result.setOqcType(oqcCheck.getOqcType());
                result.setReloadCheckReadOnly(false);

                Optional<MesOqcCheck> unTeardownOp = oqcCheckList.stream().filter(o -> (null != o && MesPcnExtEnumUtil.OQC_CHECK_TYPE.TEARDOWN_INSPECTION.getValue() != o.getOqcType())).findFirst();
                if (null != unTeardownOp && unTeardownOp.isPresent()) {
                    if (MesPcnExtEnumUtil.OQC_CHECK_TYPE.DAILY_INSPECTION.getValue() == unTeardownOp.get().getOqcType()) {
                        genOqcReadOnlyMap.put(30, true);
                        batchLimitReadOnlyMap.put(30, true);
                        spotCheckQtyReadOnlyMap.put(30, true);
                    } else {
                        genOqcReadOnlyMap.put(10, true);
                        batchLimitReadOnlyMap.put(10, true);
                        spotCheckQtyReadOnlyMap.put(10, true);
                    }
                }

                Optional<MesOqcCheck> unTeardownUnCheckOp = oqcCheckList.stream().filter(o -> (null != o && MesPcnExtEnumUtil.OQC_CHECK_TYPE.TEARDOWN_INSPECTION.getValue() != o.getOqcType() &&
                        (StringUtils.isEmpty(StringUtils.isEmpty(oqcCheck.getCheckResult())) || null == MesPcnExtEnumUtil.OQC_CHECK_RESULT.getByValue(oqcCheck.getCheckResult())))).findFirst();
                if (null != unTeardownUnCheckOp && unTeardownUnCheckOp.isPresent()) {
                    genOqcReadOnlyMap.put(unTeardownUnCheckOp.get().getOqcType(), true);
                }

                if (StringUtils.isEmpty(StringUtils.isEmpty(oqcCheck.getCheckResult())) || null == MesPcnExtEnumUtil.OQC_CHECK_RESULT.getByValue(oqcCheck.getCheckResult())) {
                    spotCheckQtyReadOnlyMap.put(oqcCheck.getOqcType(), true);
                    batchLimitReadOnlyMap.put(oqcCheck.getOqcType(), true);

                    result.setQcReadOnly(false);
                    result.setUnQcReadOnly(false);
                    batchLimitMap.put(oqcCheck.getOqcType(), oqcCheck.getBatchLimit());
                } else {
                    batchLimitMap.put(oqcCheck.getOqcType(), MathOperation.sub(outPutStatistics.getQty(), outPutStatisticsOqc.getCheckLimit()) > 0 ?
                            MathOperation.sub(outPutStatistics.getQty(), outPutStatisticsOqc.getCheckLimit()) : new Double(0));
                }

                result.setBatchLimitMap(batchLimitMap);
                result.setSpotCheckQtyReadOnlyMap(spotCheckQtyReadOnlyMap);
                result.setBatchLimitReadOnlyMap(batchLimitReadOnlyMap);
                result.setGenOqcReadOnlyMap(genOqcReadOnlyMap);
            }

            redisMesPcn.putHash(key, model.getUserId(), model.getId(), MesPcnEnumUtil.EXPIRE_TIME.NEVER.getValue());
            return result;
        } else {
            //成品抽检查询
            Map<String, String> scanInfoMap = (Map<String, String>) redisMesPcn.getHash(key, model.getUserId());
            if (CollectionUtils.isEmpty(scanInfoMap)) {
                MesPackageDetail packageDetail = packageExtService.getPackageDetailByPackNo(model.getOrganizeCode(), model.getSn());
                if (null == packageDetail || StringUtils.isEmpty(packageDetail.getSerialNumber())) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("出货检验:包装条码[%s]无效", model.getSn())
                            .build();
                }

                MesPartExt partExt = partExtService.getPartExt(model.getOrganizeCode(), packageDetail.getPartNo());
                if (null == partExt) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("出货检验:包装条码[%s]关联的物料编码[%s]无效", model.getSn(), packageDetail.getPartNo())
                            .build();
                }
                if (!StringUtils.isEmpty(partExt.getCategoryCode2())) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("出货检验:包装条码[%s]关联的物料编码[%s]的产品类型不是成品", model.getSn(), packageDetail.getPartNo())
                            .build();
                }
                if (StringUtils.isEmpty(partExt.getIsOqc()) || CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue() == partExt.getIsOqc()) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("出货检验:包装条码[%s]关联的物料编码[%s]不支持出货检验", model.getSn(), packageDetail.getPartNo())
                            .build();
                }
                if (StringUtils.isEmpty(partExt.getGoodsCode())) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("出货检验:包装条码[%s]关联的物料编码[%s]未维护商品码", model.getSn(), packageDetail.getPartNo())
                            .build();
                }
                MesProduceSnExt produceSnExt = produceSnExtService.getProduceSnExtBySn(model.getOrganizeCode(), packageDetail.getSerialNumber());
                if (null == produceSnExt) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("出货检验:包装条码[%s]关联的产品条码[%s]无效", model.getSn(), packageDetail.getSerialNumber())
                            .build();
                }
                if (MesPcnExtEnumUtil.PRODUCE_SN_QC_STATUS.QUALIFIED.getValue() != produceSnExt.getQcStatus()) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("出货检验:包装条码[%s]关联的产品条码[%s]的质量状态为[%s]",
                                    model.getSn(), packageDetail.getSerialNumber(), MesPcnExtEnumUtil.PRODUCE_SN_QC_STATUS.valueOfDescription(produceSnExt.getQcStatus()))
                            .build();
                }
                if (MesPcnExtEnumUtil.PRODUCE_SN_STATUS.OFFLINE.getValue() != produceSnExt.getSnStatus()) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("出货检验:包装条码[%s]关联的产品条码[%s]的状态为[%s]",
                                    model.getSn(), packageDetail.getSerialNumber(), MesPcnExtEnumUtil.PRODUCE_SN_STATUS.valueOfDescription(produceSnExt.getSnStatus()))
                            .build();
                }

                scanInfoMap = new HashMap<>();
                scanInfoMap.put(MesPcnExtConstWords.SN, model.getSn());
                scanInfoMap.put(MesPcnExtConstWords.PACKAGENO, model.getSn());
                scanInfoMap.put(MesPcnExtConstWords.SERIAL_NUMBER, packageDetail.getSerialNumber());
                scanInfoMap.put(MesPcnExtConstWords.PART_NO, packageDetail.getPartNo());
                scanInfoMap.put(MesPcnExtConstWords.CATEGORY_CODE3, partExt.getCategoryCode3());
                scanInfoMap.put(MesPcnExtConstWords.GOODS_CODE, partExt.getGoodsCode());
                scanInfoMap.put(MesPcnExtConstWords.WORK_CENTER_CODE, produceSnExt.getWorkCenterCode());
                MesWorkOrderExt workOrderExt = workOrderExtService.getWorkOrderExtByOrderNo(model.getOrganizeCode(), produceSnExt.getLastWorkOrderNo());
                if (StringUtils.isEmpty(produceSnExt.getLastWorkOrderNo()) || produceSnExt.getLastWorkOrderNo().equals(produceSnExt.getWorkOrderNo())) {
                    if (null == workOrderExt) {
                        throw ImppExceptionBuilder.newInstance()
                                .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                                .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                                .setErrorDetail("出货检验:包装条码[%s]关联的生产工单[%s]无效",
                                        model.getSn(), produceSnExt.getLastWorkOrderNo())
                                .build();
                    }
                    scanInfoMap.put(MesPcnExtConstWords.WORK_ORDER_NO, produceSnExt.getWorkOrderNo());
                    scanInfoMap.put(MesPcnExtConstWords.WORK_TIME, produceSnExt.getWorkTime());
                    scanInfoMap.put(MesPcnExtConstWords.SHIFT_CODE, produceSnExt.getShiftCode());
                } else {
                    if (null == workOrderExt) {
                        throw ImppExceptionBuilder.newInstance()
                                .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                                .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                                .setErrorDetail("出货检验:包装条码[%s]关联的返工工单[%s]无效",
                                        model.getSn(), produceSnExt.getLastWorkOrderNo())
                                .build();
                    }
                    MesProduceSnRepair produceSnRepair = produceSnRepairService.getProduceSnRepairBySn(model.getOrganizeCode(), packageDetail.getSerialNumber());
                    if (null == produceSnRepair) {
                        throw ImppExceptionBuilder.newInstance()
                                .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                                .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                                .setErrorDetail("出货检验:包装条码[%s]关联的产品条码[%s]已绑定返工工单[%s],但未查询到返工条码关联关系",
                                        model.getSn(), packageDetail.getSerialNumber(), produceSnExt.getLastWorkOrderNo())
                                .build();
                    }
                    scanInfoMap.put(MesPcnExtConstWords.WORK_ORDER_NO, produceSnRepair.getWorkOrderNo());
                    scanInfoMap.put(MesPcnExtConstWords.WORK_TIME, produceSnRepair.getWorkTime());
                    scanInfoMap.put(MesPcnExtConstWords.SHIFT_CODE, produceSnRepair.getShiftCode());
                }
                scanInfoMap.put(MesPcnExtConstWords.WORK_ORDER_TYPE_NAME, MesPcnExtEnumUtil.WORK_ORDER_TYPE.valueOfDescription(workOrderExt.getWorkOrderType()));
                scanInfoMap.put(MesPcnExtConstWords.WORK_ORDER_TYPE, workOrderExt.getWorkOrderType().toString());
                redisMesPcn.putHash(key, model.getUserId(), scanInfoMap, MesPcnEnumUtil.EXPIRE_TIME.NEVER.getValue());
                result.setMsg(String.format("包装条码[%s]扫描成功,请继续扫描商品码", model.getSn()));

                result.setSn(model.getSn());
                return result;
            } else {
                String sn = scanInfoMap.get(MesPcnExtConstWords.SN);
                String packageNo = scanInfoMap.get(MesPcnExtConstWords.PACKAGENO);
                String serialNumber = scanInfoMap.get(MesPcnExtConstWords.SERIAL_NUMBER);
                String partNo = scanInfoMap.get(MesPcnExtConstWords.PART_NO);
                String categoryCode3 = scanInfoMap.get(MesPcnExtConstWords.CATEGORY_CODE3);
                String goodsCode = scanInfoMap.get(MesPcnExtConstWords.GOODS_CODE);
                String workCenterCode = scanInfoMap.get(MesPcnExtConstWords.WORK_CENTER_CODE);
                String workOrderType = scanInfoMap.get(MesPcnExtConstWords.WORK_ORDER_TYPE);
                String workOrderTypeName = scanInfoMap.get(MesPcnExtConstWords.WORK_ORDER_TYPE_NAME);
                String workOrderNo = scanInfoMap.get(MesPcnExtConstWords.WORK_ORDER_NO);
                String workTime = scanInfoMap.get(MesPcnExtConstWords.WORK_TIME);
                String shiftCode = scanInfoMap.get(MesPcnExtConstWords.SHIFT_CODE);
                if (StringUtils.isEmpty(sn) || StringUtils.isEmpty(packageNo) || StringUtils.isEmpty(serialNumber) || StringUtils.isEmpty(workOrderTypeName) ||
                        StringUtils.isEmpty(workOrderType) ||StringUtils.isEmpty(partNo) || StringUtils.isEmpty(goodsCode) || StringUtils.isEmpty(workCenterCode) ||
                        StringUtils.isEmpty(workOrderNo) || StringUtils.isEmpty(workTime) || StringUtils.isEmpty(shiftCode)) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("出货检验:缓存数据异常,请点击重置按钮")
                            .build();
                }
                String[] snArr = sn.split(MesPcnExtConstWords.COMMA);
                if (snArr.length == 1) {
                    if (StringUtils.isEmpty(model.getSn())) {
                        redisMesPcn.deleteHash(key, model.getUserId());
                        result.setBatchLimitMap(batchLimitMap);
                        result.setSpotCheckQtyReadOnlyMap(spotCheckQtyReadOnlyMap);
                        result.setBatchLimitReadOnlyMap(batchLimitReadOnlyMap);
                        result.setGenOqcReadOnlyMap(genOqcReadOnlyMap);
                        return result;
                    }
                    if (!model.getSn().equals(goodsCode)) {
                        throw ImppExceptionBuilder.newInstance()
                                .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                                .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                                .setErrorDetail("出货检验:包装条码[%s]关联的物料编码[%s]维护的商品码[%s]与扫描的商品码[%s]不匹配", packageNo, partNo, goodsCode, model.getSn())
                                .build();
                    }
                    result.setMsg(String.format("商品码[%s]扫描成功,请继续扫描产品条码", model.getSn()));
                } else if (snArr.length == 2) {
                    if (StringUtils.isEmpty(model.getSn())) {
                        redisMesPcn.deleteHash(key, model.getUserId());
                        result.setBatchLimitMap(batchLimitMap);
                        result.setSpotCheckQtyReadOnlyMap(spotCheckQtyReadOnlyMap);
                        result.setBatchLimitReadOnlyMap(batchLimitReadOnlyMap);
                        result.setGenOqcReadOnlyMap(genOqcReadOnlyMap);
                        return result;
                    }
                    if (!model.getSn().equals(serialNumber)) {
                        throw ImppExceptionBuilder.newInstance()
                                .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                                .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                                .setErrorDetail("出货检验:包装条码[%s]关联的产品条码[%s]与扫描的产品条码[%s]不匹配", packageNo, serialNumber, model.getSn())
                                .build();
                    }
                    result.setMsg(String.format("产品条码[%s]扫描成功,请继续扫描商品码", model.getSn()));
                } else {
                    if (snArr.length == 3) {
                        if (StringUtils.isEmpty(model.getSn())) {
                            redisMesPcn.deleteHash(key, model.getUserId());
                            result.setBatchLimitMap(batchLimitMap);
                            result.setSpotCheckQtyReadOnlyMap(spotCheckQtyReadOnlyMap);
                            result.setBatchLimitReadOnlyMap(batchLimitReadOnlyMap);
                            result.setGenOqcReadOnlyMap(genOqcReadOnlyMap);
                            return result;
                        }

                        if (!model.getSn().equals(goodsCode)) {
                            throw ImppExceptionBuilder.newInstance()
                                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                                    .setErrorDetail("出货检验:包装条码[%s]关联的物料编码[%s]维护的商品码[%s]与扫描的商品码[%s]不匹配", packageNo, partNo, goodsCode, model.getSn())
                                    .build();
                        }
                    }

                    //snArr.length == 3 || snArr.length == 4
                    MesOutPutStatistics outPutStatistics = outPutStatisticsRepository.getByProperty(
                            new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID,
                                    MesPcnExtConstWords.WORK_ORDER_NO, MesPcnExtConstWords.SHIFT_CODE, MesPcnExtConstWords.WORK_TIME},
                            new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(),
                                    workOrderNo, shiftCode, workTime});
                    if (null == outPutStatistics) {
                        if (snArr.length == 3) {
                            throw ImppExceptionBuilder.newInstance()
                                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                                    .setErrorDetail("出货检验:根据包装条码[%s]关联的工单[%s]班次[%s]作业时间[%s],未查询到产量统计数据",
                                            packageNo, workOrderNo, shiftCode, workTime)
                                    .build();
                        } else {
                            redisMesPcn.deleteHash(key, model.getUserId());
                            result.setBatchLimitMap(batchLimitMap);
                            result.setSpotCheckQtyReadOnlyMap(spotCheckQtyReadOnlyMap);
                            result.setBatchLimitReadOnlyMap(batchLimitReadOnlyMap);
                            result.setGenOqcReadOnlyMap(genOqcReadOnlyMap);
                            return result;
                        }
                    }
                    MesOutPutStatisticsOqc outPutStatisticsOqc = outPutStatisticsOqcRepository.getByProperty(
                            new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.PID},
                            new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), outPutStatistics.getId()});
                    if (null == outPutStatisticsOqc) {
                        if (snArr.length == 3) {
                            throw ImppExceptionBuilder.newInstance()
                                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                                    .setErrorDetail("出货检验:根据包装条码[%s]关联的工单[%s]物料[%s]生产线[%s]班次[%s]作业时间[%s],未查询到产量统计出货检验关联数据",
                                            packageNo, workOrderNo, partNo, workCenterCode, shiftCode, workTime)
                                    .build();
                        } else {
                            redisMesPcn.deleteHash(key, model.getUserId());
                            result.setBatchLimitMap(batchLimitMap);
                            result.setSpotCheckQtyReadOnlyMap(spotCheckQtyReadOnlyMap);
                            result.setBatchLimitReadOnlyMap(batchLimitReadOnlyMap);
                            result.setGenOqcReadOnlyMap(genOqcReadOnlyMap);
                            return result;
                        }
                    }

                    result.setWorkOrderNo(outPutStatistics.getWorkOrderNo());
                    result.setWorkOrderType(Integer.valueOf(workOrderType));
                    result.setWorkOrderTypeName(workOrderTypeName);
                    result.setPartNo(outPutStatistics.getPartNo());
                    result.setPartNameRdd(outPutStatistics.getPartNameRdd());
                    result.setWorkCenterCode(outPutStatistics.getWorkCenterCode());
                    result.setWorkTime(outPutStatistics.getWorkTime());
                    result.setShiftCode(outPutStatistics.getShiftCode());
                    result.setCategoryCode3(categoryCode3);
                    result.setPlanQty(outPutStatistics.getPlanQty());
                    result.setCompleteQty(outPutStatistics.getQty());
                    result.setCheckLimit(outPutStatisticsOqc.getCheckLimit());

                    spotCheckQtyReadOnlyMap.put(10, true);
                    spotCheckQtyReadOnlyMap.put(20, true);
                    spotCheckQtyReadOnlyMap.put(30, true);

                    batchLimitReadOnlyMap.put(10, false);
                    batchLimitReadOnlyMap.put(20, false);
                    batchLimitReadOnlyMap.put(30, false);

                    genOqcReadOnlyMap.put(10, false);
                    genOqcReadOnlyMap.put(20, false);
                    genOqcReadOnlyMap.put(30, false);

                    batchLimitMap.put(10, MathOperation.sub(outPutStatistics.getQty(), outPutStatisticsOqc.getCheckLimit()) > 0 ?
                            MathOperation.sub(outPutStatistics.getQty(), outPutStatisticsOqc.getCheckLimit()) : new Double(0));
                    batchLimitMap.put(20, batchLimitMap.get(10));
                    batchLimitMap.put(30, batchLimitMap.get(10));

                    DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());
                    DdlPreparedPack.getStringEqualPack(outPutStatistics.getWorkOrderNo(), MesPcnExtConstWords.ORDER_NO, packBean);
                    DdlPreparedPack.getStringEqualPack(outPutStatistics.getShiftCode(), MesPcnExtConstWords.SHIFT_CODE, packBean);
                    DdlPreparedPack.getStringEqualPack(outPutStatistics.getWorkTime(), MesPcnExtConstWords.WORK_TIME, packBean);
                    DdlPreparedPack.getStringEqualPack(serialNumber, MesPcnExtConstWords.SERIAL_NUMBER, packBean);
                    DdlPreparedPack.getOrderByPack(new Object[]{CommonEnumUtil.ASC_OR_DESC.DESC.getValue()}, new String[]{MesPcnExtConstWords.CREATE_DATE_TIME}, packBean);
                    List<MesOqcCheck> oqcCheckList = oqcCheckRepository.findByHqlWhere(packBean);

                    if (CollectionUtils.isEmpty(oqcCheckList)) {

                        result.setBatchLimitMap(batchLimitMap);
                        result.setSpotCheckQtyReadOnlyMap(spotCheckQtyReadOnlyMap);
                        result.setBatchLimitReadOnlyMap(batchLimitReadOnlyMap);
                        result.setGenOqcReadOnlyMap(genOqcReadOnlyMap);

                    } else {
                        MesOqcCheck oqcCheck;
                        Optional<MesOqcCheck> oqcCheckOp;
                        if (!StringUtils.isEmpty(model.getOqcNo())) {
                            oqcCheckOp = oqcCheckList.stream().filter(o -> (null != o && o.getOqcNo().equals(model.getOqcNo()))).findFirst();
                        } else {
                            oqcCheckOp = oqcCheckList.stream().filter(o -> (null != o &&
                                    (StringUtils.isEmpty(StringUtils.isEmpty(o.getCheckResult())) || null == MesPcnExtEnumUtil.OQC_CHECK_RESULT.getByValue(o.getCheckResult())))).findFirst();
                        }
                        if (null != oqcCheckOp && oqcCheckOp.isPresent()) {
                            oqcCheck = oqcCheckOp.get();
                        } else {
                            oqcCheck = oqcCheckList.get(0);
                        }
                        result.setOqcNo(oqcCheck.getOqcNo());
                        result.setCurOqcTypeName(MesPcnExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(oqcCheck.getOqcType()));
                        result.setCurOqcType(oqcCheck.getOqcType());
                        result.setCurSpotCheckQty(oqcCheck.getSpotCheckQty());
                        result.setCurBatchLimit(oqcCheck.getBatchLimit());
                        result.setCurCheckResultName((StringUtils.isEmpty(oqcCheck.getCheckResult()) || null == MesPcnExtEnumUtil.OQC_CHECK_RESULT.getByValue(oqcCheck.getCheckResult()))
                                ? null : MesPcnExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(oqcCheck.getCheckResult()));
                        result.setOqcType(oqcCheck.getOqcType());
                        result.setReloadCheckReadOnly(false);

                        Optional<MesOqcCheck> unTeardownOp = oqcCheckList.stream().filter(o -> (null != o && MesPcnExtEnumUtil.OQC_CHECK_TYPE.TEARDOWN_INSPECTION.getValue() != o.getOqcType())).findFirst();
                        Optional<MesOqcCheck> teardownUnCheckOp = oqcCheckList.stream().filter(o -> (null != o && MesPcnExtEnumUtil.OQC_CHECK_TYPE.TEARDOWN_INSPECTION.getValue() == o.getOqcType())).findFirst();
                        if (null != unTeardownOp && unTeardownOp.isPresent()) {
                            genOqcReadOnlyMap.put(10, true);
                            genOqcReadOnlyMap.put(30, true);
                            batchLimitReadOnlyMap.put(10, true);
                            batchLimitReadOnlyMap.put(30, true);
                        } else {
                            genOqcReadOnlyMap.put(20, true);
                        }

                        if (null != teardownUnCheckOp && teardownUnCheckOp.isPresent()) {
                            genOqcReadOnlyMap.put(20, true);
                            batchLimitReadOnlyMap.put(20, true);
                        } else {
                            if (null != unTeardownOp && unTeardownOp.isPresent()) {
                                batchLimitMap.put(20, unTeardownOp.get().getBatchLimit());
                                batchLimitReadOnlyMap.put(20, true);
                            }
                        }

                        if (StringUtils.isEmpty(StringUtils.isEmpty(oqcCheck.getCheckResult())) || null == MesPcnExtEnumUtil.OQC_CHECK_RESULT.getByValue(oqcCheck.getCheckResult())) {
                            result.setQcReadOnly(false);
                            result.setUnQcReadOnly(false);
                        }

                        batchLimitMap.put(oqcCheck.getOqcType(), oqcCheck.getBatchLimit());

                        result.setBatchLimitMap(batchLimitMap);
                        result.setSpotCheckQtyReadOnlyMap(spotCheckQtyReadOnlyMap);
                        result.setBatchLimitReadOnlyMap(batchLimitReadOnlyMap);
                        result.setGenOqcReadOnlyMap(genOqcReadOnlyMap);

                    }

                    result.setSerialNumber(serialNumber);
                    result.setSnReadOnly(true);
                    if (!StringUtils.isEmpty(model.getSn())) {
                        result.setMsg(String.format("商品码[%s]扫描成功,可生成出货检验单", model.getSn()));
                    } else {
                        result.setSn(snArr[3]);
                    }
                }

                if (!StringUtils.isEmpty(model.getSn())) {
                    scanInfoMap.put(MesPcnExtConstWords.SN, new StringJoiner(MesPcnExtConstWords.COMMA).add(sn).add(model.getSn()).toString());
                    redisMesPcn.putHash(key, model.getUserId(), scanInfoMap, MesPcnEnumUtil.EXPIRE_TIME.NEVER.getValue());
                    result.setSn(model.getSn());
                }
                return result;
            }

        }
    }

    @Override
    public ListPager<MesOqcCheckDetail> queryOqcDetail(String organizeCode, String oqcNo, Pager pager) {
        DdlPackBean hqlPack = MesPcnExtHqlPack.getOqcCheckDetail(organizeCode, oqcNo);
        pager = PagerHelper.getPager(pager, oqcCheckDetailRepository.findByHqlWhereCount(hqlPack));
        hqlPack.setOrderByStr(" order by seq asc ");
        return new ListPager(oqcCheckDetailRepository.findByHqlWherePage(hqlPack, pager), pager);
    }

    @Override
    public void doOqcDetailReload(OqcManageModel model) {

        MesPartExt partExt = partExtService.getPartExt(model.getOrganizeCode(), model.getPartNo());
        if (null == partExt) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("重载检验项:物料编码[%s]无效", model.getPartNo())
                    .build();
        }
        MesOqcCheck oqcCheck = oqcCheckRepository.getByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.OQC_NO},
                new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getOqcNo()});
        if (null == oqcCheck) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("重载检验项:单据[%s]无效", model.getOqcNo())
                    .build();
        }

        Integer oqcType = model.getOqcType();
        String partNo = null;
        String categoryCode3 = null;

        List<MesOqcCheckDetail> oqcCheckDetailList = oqcCheckDetailRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.OQC_NO},
                new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getOqcNo()});

        if (MesPcnExtEnumUtil.OQC_CHECK_TYPE.DAILY_INSPECTION.getValue() != model.getOqcType()) {
            if (StringUtils.isEmpty(oqcCheck.getCategoryCode3())) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("重载检验项:单据[%s]类型[%s]未关联产品类型",
                                model.getOqcNo(), MesPcnExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(model.getOqcType()))
                        .build();
            }
            if (StringUtils.isEmpty(partExt.getCategoryCode3())) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("重载检验项:物料编码[%s]未配置产品类型", model.getPartNo())
                        .build();
            }

            if (!partExt.getCategoryCode3().equals(oqcCheck.getCategoryCode3())) {
                oqcCheck.setCategoryCode3(partExt.getCategoryCode3());
                ConvertBean.serviceModelUpdate(oqcCheck, model.getUserInfo());
                oqcCheckRepository.save(oqcCheck);

                for (MesOqcCheckDetail oqcCheckDetail : oqcCheckDetailList) {
                    if (null == oqcCheckDetail) {
                        continue;
                    }
                    oqcCheckDetail.setIsDeleted(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue());
                    ConvertBean.serviceModelUpdate(oqcCheckDetail, model.getUserInfo());
                    oqcCheckDetailRepository.save(oqcCheckDetail);
                }

                oqcCheckDetailList = new ArrayList<>();
            }
            categoryCode3 = partExt.getCategoryCode3();
        } else {
            partNo = model.getPartNo();
        }

        List<MesOqcProject> oqcProjectList;
        if (!StringUtils.isEmpty(partNo)) {
            oqcProjectList = oqcProjectRepository.findByProperty(
                    new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.PART_NO, MesPcnExtConstWords.OQC_TYPE},
                    new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), partNo, oqcType});
            if (CollectionUtils.isEmpty(oqcProjectList)) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("重载检验项:根据物料编码[%s]检验类型[%s]未查询到出货检验基础检验项目",
                                model.getPartNo(), MesPcnExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(model.getOqcType()))
                        .build();
            }
        } else {
            oqcProjectList = oqcProjectRepository.findByProperty(
                    new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.OQC_TYPE, MesPcnExtConstWords.CATEGORY_CODE3},
                    new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), oqcType, categoryCode3});
            if (CollectionUtils.isEmpty(oqcProjectList)) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("重载检验项:根据产品类型[%s]检验类型[%s]未查询到出货检验基础检验项目",
                                categoryCode3, MesPcnExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(model.getOqcType()))
                        .build();
            }
        }

        Map<Long, MesOqcProject> oqcProjectMap = CollectionUtils.isEmpty(oqcProjectList) ? null :
                oqcProjectList.stream().filter(o -> null != o).collect(Collectors.toMap(MesOqcProject::getId, o -> o));

        List<MesOqcCheckDetail> needDelOqcCheckDetailList = oqcCheckDetailList.stream()
                .filter(o -> (null != o && (StringUtils.isEmpty(o.getPid()) || !oqcProjectMap.containsKey(o.getPid())))).collect(Collectors.toList());
        List<Long> needDelIdList = CollectionUtils.isEmpty(needDelOqcCheckDetailList) ? new ArrayList<>() :
                needDelOqcCheckDetailList.stream().filter(o -> null != o).map(MesOqcCheckDetail::getId).collect(Collectors.toList());

        for (MesOqcCheckDetail oqcCheckDetail : needDelOqcCheckDetailList) {
            if (null == oqcCheckDetail) {
                continue;
            }
            oqcCheckDetail.setIsDeleted(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue());
            ConvertBean.serviceModelUpdate(oqcCheckDetail, model.getUserInfo());
            oqcCheckDetailRepository.save(oqcCheckDetail);
        }

        List<MesOqcCheckDetail> needCompareOqcCheckDetailList = oqcCheckDetailList.stream().filter(o -> (null != o && !needDelIdList.contains(o.getId()))).collect(Collectors.toList());

        Map<Long, MesOqcCheckDetail> oqcCheckDetailMap = CollectionUtils.isEmpty(needCompareOqcCheckDetailList) ? new HashMap<>() :
                needCompareOqcCheckDetailList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getPid()))).collect(Collectors.toMap(MesOqcCheckDetail::getPid, o -> o));


        for (Long id : oqcProjectMap.keySet()) {
            if (StringUtils.isEmpty(id)) {
                continue;
            }
            MesOqcProject project = oqcProjectMap.get(id);
            MesOqcCheckDetail detail = oqcCheckDetailMap.get(id);
            if (null != detail) {
                Boolean oqcProjectBoo = compareString(project.getOqcProject(), detail.getOqcProject());
                Boolean standardBoo = compareString(project.getStandard(), detail.getStandard());
                Boolean upLimitBoo = compareString(project.getUpLimit(), detail.getUpLimit());
                Boolean downLimitBoo = compareString(project.getDownLimit(), detail.getDownLimit());
                Boolean seqBoo = compareDouble(project.getSeq(), detail.getSeq());
                if (oqcProjectBoo && standardBoo && upLimitBoo && downLimitBoo) {
                    if (seqBoo) {
                        continue;
                    } else {
                        detail.setSeq(StringUtils.isEmpty(project.getSeq()) ? new Double(0) : project.getSeq());
                        ConvertBean.serviceModelUpdate(detail, model.getUserInfo());
                        oqcCheckDetailRepository.save(detail);
                        continue;
                    }
                } else {
                    detail.setOqcProject(project.getOqcProject());
                    detail.setStandard(project.getStandard());
                    detail.setUpLimit(project.getUpLimit());
                    detail.setDownLimit(project.getDownLimit());
                    detail.setAppliance(null);
                    detail.setCheckValue(null);
                    detail.setRemark(null);
                    detail.setResult(null);
                    ConvertBean.serviceModelUpdate(detail, model.getUserInfo());
                    oqcCheckDetailRepository.save(detail);
                    continue;
                }
            }

            detail = new MesOqcCheckDetail();
            BeanUtils.copyProperties(project, detail, MesPcnExtConstWords.ID);
            detail.setOqcNo(model.getOqcNo());
            detail.setPartNo(model.getPartNo());
            detail.setOrderNo(oqcCheck.getOrderNo());
            detail.setSerialNumber(oqcCheck.getSerialNumber());
            detail.setPid(project.getId());
            detail.setWorkCenterCode(oqcCheck.getWorkCenterCode());
            detail.setWorkTime(oqcCheck.getWorkTime());
            detail.setShiftCode(oqcCheck.getShiftCode());
            ConvertBean.serviceModelInitialize(detail, model.getUserInfo());
            oqcCheckDetailRepository.insert(detail);
        }
    }

    private Boolean compareString(String str1, String str2) {
        if (StringUtils.isEmpty(str1)) {
            str1 = "null";
        }
        if (StringUtils.isEmpty(str2)) {
            str2 = "null";
        }
        if (str1.equals(str2)) {
            return true;
        } else {
            return false;
        }
    }

    private Boolean compareDouble(Double dou1, Double dou2) {
        if (StringUtils.isEmpty(dou1)) {
            dou1 = new Double(0);
        }
        if (StringUtils.isEmpty(dou2)) {
            dou2 = new Double(0);
        }
        if (dou1.compareTo(dou2) == 0) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public OqcManageModel changeOqcData(OqcManageModel model) {
        OqcManageModel result = new OqcManageModel();
        if (!StringUtils.isEmpty(model.getSn())) {
            result.setSn(model.getSn());

            String key = new StringJoiner(MesPcnExtConstWords.COLON).add(model.getOrganizeCode()).add(MesPcnExtConstWords.OQC_MANAGE_DATA).toString();
            Map<String, String> scanInfoMap = (Map<String, String>) redisMesPcn.getHash(key, model.getUserId());
            String serialNumber = scanInfoMap.get(MesPcnExtConstWords.SERIAL_NUMBER);
            if (StringUtils.isEmpty(serialNumber)) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("切换:缓存缺失产品条码,请点击重置按钮")
                        .build();
            }
            result.setSerialNumber(serialNumber);
        } else {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("切换:因为组件不拆机,组件抽检不支持切换")
                    .build();
        }
        result.setSnReadOnly(true);

        MesPartExt partExt = partExtService.getPartExt(model.getOrganizeCode(), model.getPartNo());
        if (null == partExt) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("切换:物料编码[%s]无效", model.getPartNo())
                    .build();
        }

        if (!StringUtils.isEmpty(partExt.getCategoryCode2())) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("切换:因为组件不拆机,工单[%s]不支持切换", model.getWorkOrderNo())
                    .build();
        }

        MesWorkOrderExt workOrderExt = workOrderExtService.getWorkOrderExtByOrderNo(model.getOrganizeCode(), model.getWorkOrderNo());
        if (null == workOrderExt) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("切换:工单编码[%s]无效", model.getWorkOrderNo())
                    .build();
        }

        MesOutPutStatistics outPutStatistics = outPutStatisticsRepository.getByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID,
                        MesPcnExtConstWords.WORK_ORDER_NO, MesPcnExtConstWords.SHIFT_CODE, MesPcnExtConstWords.WORK_TIME},
                new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(),
                        model.getWorkOrderNo(), model.getShiftCode(), model.getWorkTime()});
        if (null == outPutStatistics) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("切换:根据工单[%s]班次[%s]作业时间[%s],未查询到产量统计数据",
                            model.getWorkOrderNo(), model.getShiftCode(), model.getWorkTime())
                    .build();
        }

        MesOutPutStatisticsOqc outPutStatisticsOqc = outPutStatisticsOqcRepository.getByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.PID},
                new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), outPutStatistics.getId()});
        if (null == outPutStatisticsOqc) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("切换:根据工单[%s]物料[%s]生产线[%s]班次[%s]作业时间[%s],未查询到产量统计出货检验关联数据",
                            model.getWorkOrderNo(), model.getPartNo(), model.getWorkCenterCode(), model.getShiftCode(), model.getWorkTime())
                    .build();
        }

        result.setWorkOrderNo(outPutStatistics.getWorkOrderNo());
        result.setWorkOrderType(workOrderExt.getWorkOrderType());
        result.setWorkOrderTypeName(MesPcnExtEnumUtil.WORK_ORDER_TYPE.valueOfDescription(workOrderExt.getWorkOrderType()));
        result.setPartNo(outPutStatistics.getPartNo());
        result.setPartNameRdd(outPutStatistics.getPartNameRdd());
        result.setWorkCenterCode(outPutStatistics.getWorkCenterCode());
        result.setWorkTime(outPutStatistics.getWorkTime());
        result.setShiftCode(outPutStatistics.getShiftCode());
        result.setCategoryCode3(partExt.getCategoryCode3());
        result.setPlanQty(outPutStatistics.getPlanQty());
        result.setCompleteQty(outPutStatistics.getQty());
        result.setCheckLimit(outPutStatisticsOqc.getCheckLimit());

        Map<Integer, Boolean> spotCheckQtyReadOnlyMap = new HashMap<>();
        Map<Integer, Boolean> batchLimitReadOnlyMap = new HashMap<>();
        Map<Integer, Boolean> genOqcReadOnlyMap = new HashMap<>();
        Map<Integer, Double> batchLimitMap = new HashMap<>();

        spotCheckQtyReadOnlyMap.put(10, true);
        spotCheckQtyReadOnlyMap.put(20, true);
        spotCheckQtyReadOnlyMap.put(30, true);

        batchLimitReadOnlyMap.put(10, true);
        batchLimitReadOnlyMap.put(20, true);
        batchLimitReadOnlyMap.put(30, true);

        genOqcReadOnlyMap.put(10, true);
        genOqcReadOnlyMap.put(20, true);
        genOqcReadOnlyMap.put(30, true);

        DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(outPutStatistics.getWorkOrderNo(), MesPcnExtConstWords.ORDER_NO, packBean);
        DdlPreparedPack.getStringEqualPack(outPutStatistics.getShiftCode(), MesPcnExtConstWords.SHIFT_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(outPutStatistics.getWorkTime(), MesPcnExtConstWords.WORK_TIME, packBean);
        DdlPreparedPack.getStringEqualPack(result.getSerialNumber(), MesPcnExtConstWords.SERIAL_NUMBER, packBean);
        DdlPreparedPack.getOrderByPack(new Object[]{CommonEnumUtil.ASC_OR_DESC.DESC.getValue()}, new String[]{MesPcnExtConstWords.CREATE_DATE_TIME}, packBean);
        List<MesOqcCheck> oqcCheckList = oqcCheckRepository.findByHqlWhere(packBean);

        if (CollectionUtils.isEmpty(oqcCheckList)) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("切换:根据工单[%s]物料[%s]生产线[%s]班次[%s]作业时间[%s],未查询到出货检验单数据",
                            model.getWorkOrderNo(), model.getPartNo(), model.getWorkCenterCode(), model.getShiftCode(), model.getWorkTime())
                    .build();
        }

        Optional<MesOqcCheck> oqcCheckOldOp = oqcCheckList.stream().filter(o -> (null != o && o.getOqcNo().equals(model.getOqcNo()))).findFirst();
        if (null == oqcCheckOldOp || !oqcCheckOldOp.isPresent()) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("切换:检验单号[%s]无效", model.getOqcNo())
                    .build();
        }

        oqcCheckList = oqcCheckList.stream().filter(o -> (null != o && o.getOqcType() != oqcCheckOldOp.get().getOqcType())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(oqcCheckList)) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("切换:根据工单[%s]物料[%s]生产线[%s]班次[%s]作业时间[%s],未查询到除[%s]类型以外的检验单",
                            model.getWorkOrderNo(), model.getPartNo(), model.getWorkCenterCode(), model.getShiftCode(), model.getWorkTime(),
                            MesPcnExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(oqcCheckOldOp.get().getOqcType()))
                    .build();
        }

        MesOqcCheck oqcCheck;
        Optional<MesOqcCheck> oqcCheckOp = oqcCheckList.stream().filter(o -> (null != o &&
                (StringUtils.isEmpty(StringUtils.isEmpty(o.getCheckResult())) || null == MesPcnExtEnumUtil.OQC_CHECK_RESULT.getByValue(o.getCheckResult())))).findFirst();
        if (null != oqcCheckOp && oqcCheckOp.isPresent()) {
            oqcCheck = oqcCheckOp.get();
        } else {
            oqcCheck = oqcCheckList.get(0);
        }

        result.setOqcNo(oqcCheck.getOqcNo());
        result.setCurOqcTypeName(MesPcnExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(oqcCheck.getOqcType()));
        result.setCurOqcType(oqcCheck.getOqcType());
        result.setCurSpotCheckQty(oqcCheck.getSpotCheckQty());
        result.setCurBatchLimit(oqcCheck.getBatchLimit());
        result.setCurCheckResultName((StringUtils.isEmpty(oqcCheck.getCheckResult()) || null == MesPcnExtEnumUtil.OQC_CHECK_RESULT.getByValue(oqcCheck.getCheckResult()))
                ? null : MesPcnExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(oqcCheck.getCheckResult()));
        result.setOqcType(oqcCheck.getOqcType());
        result.setReloadCheckReadOnly(false);

        batchLimitMap.put(10, oqcCheck.getBatchLimit());
        batchLimitMap.put(20, batchLimitMap.get(10));
        batchLimitMap.put(30, batchLimitMap.get(10));

        if (StringUtils.isEmpty(StringUtils.isEmpty(oqcCheck.getCheckResult())) || null == MesPcnExtEnumUtil.OQC_CHECK_RESULT.getByValue(oqcCheck.getCheckResult())) {
            result.setQcReadOnly(false);
            result.setUnQcReadOnly(false);
        }

        result.setBatchLimitMap(batchLimitMap);
        result.setSpotCheckQtyReadOnlyMap(spotCheckQtyReadOnlyMap);
        result.setBatchLimitReadOnlyMap(batchLimitReadOnlyMap);
        result.setGenOqcReadOnlyMap(genOqcReadOnlyMap);

        return result;
    }

    @Override
    public OqcManageModel resetOqcData(OqcManageModel model) {

        String key = new StringJoiner(MesPcnExtConstWords.COLON).add(model.getOrganizeCode()).add(MesPcnExtConstWords.OQC_MANAGE_DATA).toString();
        redisMesPcn.deleteHash(key, model.getUserId());

        Map<Integer, Boolean> spotCheckQtyReadOnlyMap = new HashMap<>();
        spotCheckQtyReadOnlyMap.put(10, true);
        spotCheckQtyReadOnlyMap.put(20, true);
        spotCheckQtyReadOnlyMap.put(30, true);

        Map<Integer, Boolean> batchLimitReadOnlyMap = new HashMap<>();
        batchLimitReadOnlyMap.put(10, true);
        batchLimitReadOnlyMap.put(20, true);
        batchLimitReadOnlyMap.put(30, true);

        Map<Integer, Boolean> genOqcReadOnlyMap = new HashMap<>();
        genOqcReadOnlyMap.put(10, true);
        genOqcReadOnlyMap.put(20, true);
        genOqcReadOnlyMap.put(30, true);

        Map<Integer, Double> batchLimitMap = new HashMap<>();
        batchLimitMap.put(10, new Double(1));
        batchLimitMap.put(20, new Double(1));
        batchLimitMap.put(30, new Double(1));

        OqcManageModel result = new OqcManageModel();
        result.setBatchLimitMap(batchLimitMap);
        result.setSpotCheckQtyReadOnlyMap(spotCheckQtyReadOnlyMap);
        result.setBatchLimitReadOnlyMap(batchLimitReadOnlyMap);
        result.setGenOqcReadOnlyMap(genOqcReadOnlyMap);
        return result;
    }

    @Override
    public void insertOqcData(OqcManageModel model) {
        if ((StringUtils.isEmpty(model.getSn()) && !StringUtils.isEmpty(model.getSerialNumber())) ||
                (!StringUtils.isEmpty(model.getSn()) && StringUtils.isEmpty(model.getSerialNumber()))) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("生成检验单:商品码[%s]产品条码[%s]成品检验参数异常", model.getSn(), model.getSerialNumber())
                    .build();
        }

        //成品
        if (!StringUtils.isEmpty(model.getSerialNumber())) {
            if (MathOperation.compareTo(model.getSpotCheckQty(), new Double(1)) != 0) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("生成检验单:成品抽检数量只能为[1]")
                        .build();
            }
            if (MathOperation.compareTo(model.getBatchLimit(), new Double(0)) <= 0) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("生成检验单:成品抽检批次范围必须大于[0]")
                        .build();
            }

            String key = new StringJoiner(MesPcnExtConstWords.COLON).add(model.getOrganizeCode()).add(MesPcnExtConstWords.OQC_MANAGE_DATA).toString();
            Map<String, String> scanInfoMap = (Map<String, String>) redisMesPcn.getHash(key, model.getUserId());
            String serialNumber = scanInfoMap.get(MesPcnExtConstWords.SERIAL_NUMBER);
            if (StringUtils.isEmpty(serialNumber)) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("生成检验单:缓存丢失产品条码记录,请点击重置按钮")
                        .build();
            }
            if (!model.getSerialNumber().equals(serialNumber)) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("生成检验单:缓存的产品条码[%s]与当前界面的产品条码[%s]不一致,请点击重置按钮", serialNumber, model.getSerialNumber())
                        .build();
            }

            List<MesOqcCheck> oqcCheckList = oqcCheckRepository.findByProperty(
                    new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.ORDER_NO},
                    new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getWorkOrderNo()});

            Map<Integer, List<MesOqcCheck>> oqcTypeMap = CollectionUtils.isEmpty(oqcCheckList) ? null :
                    oqcCheckList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesOqcCheck::getOqcType));

            List<MesOqcProject> oqcProjectList;
            List<MesOqcCheck> curOqcTpyeCheckList = CollectionUtils.isEmpty(oqcTypeMap) ? null : oqcTypeMap.get(model.getOqcType());
            Optional<MesOqcCheck> oqcCheckOp;
            if (MesPcnExtEnumUtil.OQC_CHECK_TYPE.TEARDOWN_INSPECTION.getValue() != model.getOqcType()) {
                //日常&空洞
                if (MesPcnExtEnumUtil.OQC_CHECK_TYPE.DAILY_INSPECTION.getValue() == model.getOqcType()) {
                    if (!CollectionUtils.isEmpty(oqcTypeMap) && oqcTypeMap.containsKey(MesPcnExtEnumUtil.OQC_CHECK_TYPE.EMPTY_INSPECTION.getValue())) {
                        throw ImppExceptionBuilder.newInstance()
                                .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                                .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                                .setErrorDetail("生成检验单:生产工单[%s]已经生成空洞检验单,不能再生成日常检验单,操作失败", model.getWorkOrderNo())
                                .build();
                    }
                    oqcProjectList = oqcProjectRepository.findByProperty(
                            new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.PART_NO, MesPcnExtConstWords.OQC_TYPE},
                            new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getPartNo(), model.getOqcType()});
                } else {
                    if (!CollectionUtils.isEmpty(oqcTypeMap) && oqcTypeMap.containsKey(MesPcnExtEnumUtil.OQC_CHECK_TYPE.DAILY_INSPECTION.getValue())) {
                        throw ImppExceptionBuilder.newInstance()
                                .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                                .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                                .setErrorDetail("生成检验单:生产工单[%s]已经生成日常检验,不能再生成空洞检验单,操作失败", model.getWorkOrderNo())
                                .build();
                    }

                    if (StringUtils.isEmpty(model.getCategoryCode3())) {
                        throw ImppExceptionBuilder.newInstance()
                                .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                                .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                                .setErrorDetail("生成检验单:生产工单[%s]关联的物料编码[%s]未维护产品类型,操作失败", model.getWorkOrderNo(), model.getPartNo())
                                .build();
                    }
                    oqcProjectList = oqcProjectRepository.findByProperty(
                            new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.OQC_TYPE, MesPcnExtConstWords.CATEGORY_CODE3},
                            new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getOqcType(), model.getCategoryCode3()});
                }

                if (CollectionUtils.isEmpty(oqcProjectList)) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:物料编码[%s]检验类型[%s]未维护出货检验项,操作失败",
                                    model.getPartNo(), MesPcnExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(model.getOqcType()))
                            .build();
                }

                MesOqcPackageDetail oqcPackageDetail = oqcPackageDetailRepository.getByProperty(
                        new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.SERIAL_NUMBER, MesPcnExtConstWords.ORDER_NO},
                        new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), serialNumber, model.getWorkOrderNo()});
                if (null != oqcPackageDetail) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:工单号[%s]关联的产品条码[%s]已被检验单[%s]关联,操作失败", model.getWorkOrderNo(), serialNumber, oqcPackageDetail.getOqcNo())
                            .build();
                }

                List<MesOutPutStatisticsOqc> outPutStatisticsOqcList = outPutStatisticsOqcRepository.findByProperty(
                        new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.WORK_ORDER_NO},
                        new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getWorkOrderNo()},
                        " order by createDatetime desc ");
                if (CollectionUtils.isEmpty(outPutStatisticsOqcList)) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:工单[%s]缺失产量统计出货检验数据", model.getWorkOrderNo())
                            .build();
                }
                Optional<MesOutPutStatisticsOqc> outPutStatisticsOqcOp = outPutStatisticsOqcList.stream()
                        .filter(o -> (null != o && o.getShiftCode().equals(model.getShiftCode()) && o.getWorkTime().equals(model.getWorkTime()))).findFirst();
                if (null == outPutStatisticsOqcOp || !outPutStatisticsOqcOp.isPresent()) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:工单[%s]缺失班次[%s]作业时间[%s]的产量统计出货检验数据", model.getWorkOrderNo(), model.getShiftCode(), model.getWorkTime())
                            .build();
                }

                Double unCheckBatchLimit;
                if (outPutStatisticsOqcList.get(0).getWorkTime().equals(model.getWorkTime()) && outPutStatisticsOqcList.get(0).getShiftCode().equals(model.getShiftCode())) {
                    List<MesOutPutStatistics> outPutStatisticsList = outPutStatisticsRepository.findByProperty(
                            new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.WORK_ORDER_NO},
                            new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getWorkOrderNo()},
                            " order by createDatetime desc ");
                    if (CollectionUtils.isEmpty(outPutStatisticsList)) {
                        throw ImppExceptionBuilder.newInstance()
                                .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                                .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                                .setErrorDetail("生成检验单:工单[%s]缺失产量统计数据", model.getWorkOrderNo())
                                .build();
                    }

                    oqcCheckOp = CollectionUtils.isEmpty(curOqcTpyeCheckList) ? null :
                            curOqcTpyeCheckList.stream().filter(o -> (null != o && o.getWorkTime().equals(model.getWorkTime()) &&
                                    o.getShiftCode().equals(model.getShiftCode()) && MesPcnExtEnumUtil.ASSOCIATED_STATUS.OPEN.getValue() == o.getAssociatedStatus())).findFirst();
                    if (null != oqcCheckOp && oqcCheckOp.isPresent()) {
                        throw ImppExceptionBuilder.newInstance()
                                .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                                .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                                .setErrorDetail("生成检验单:工单[%s]存在检验单[%s]批次范围内未处理完毕的包装条码,操作失败", model.getWorkOrderNo(), oqcCheckOp.get().getOqcNo())
                                .build();
                    }

                    Double checkedLimitAmount = outPutStatisticsList.stream().filter(o -> (null != o &&
                            o.getId().compareTo(outPutStatisticsOqcList.get(0).getPid()) != 0 && !StringUtils.isEmpty(o.getQty()))).mapToDouble(MesOutPutStatistics::getQty).sum();
                    checkedLimitAmount = MathOperation.add(checkedLimitAmount, outPutStatisticsOqcList.get(0).getCheckLimit());
                    unCheckBatchLimit = MathOperation.sub(outPutStatisticsOqcOp.get().getPlanQty(), checkedLimitAmount);
                } else {
                    MesOutPutStatistics outPutStatistics = outPutStatisticsRepository.getById(outPutStatisticsOqcOp.get().getPid());
                    if (null == outPutStatistics) {
                        throw ImppExceptionBuilder.newInstance()
                                .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                                .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                                .setErrorDetail("生成检验单:工单[%s]缺失班次[%s]作业时间[%s]的产量统计数据", model.getWorkOrderNo(), model.getShiftCode(), model.getWorkTime())
                                .build();
                    }
                    unCheckBatchLimit = MathOperation.sub(outPutStatistics.getQty(), outPutStatisticsOqcOp.get().getCheckLimit());
                }

                if (MathOperation.compareTo(unCheckBatchLimit, new Double(0)) < 0) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:工单[%s]检验类型[%s]批次范围计算有误,请联系运维人员", model.getWorkOrderNo(), MesPcnExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(model.getOqcType()))
                            .build();
                }

                if (MathOperation.compareTo(unCheckBatchLimit, model.getBatchLimit()) < 0) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:工单[%s]班次[%s]作业时间[%s]检验类型[%s]剩余最大未检批次范围为[%s],请重新输入批次范围",
                                    model.getWorkOrderNo(), model.getShiftCode(), model.getWorkTime(), MesPcnExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(model.getOqcType()), unCheckBatchLimit)
                            .build();
                }

                List<MesOqcPackageDetail> oqcPackageDetailList = oqcPackageDetailRepository.findByProperty(
                        new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.ORDER_NO},
                        new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getWorkOrderNo()});
                List<String> serialNumberList = CollectionUtils.isEmpty(oqcPackageDetailList) ? new ArrayList<>() :
                        oqcPackageDetailList.stream().filter(o -> null != o).map(MesOqcPackageDetail::getSerialNumber).collect(Collectors.toList());

                List<MesProduceSnExt> produceSnExtList;
                List<ProduceSnExtModel> produceSnExtModelList;

                if (MesPcnExtEnumUtil.WORK_ORDER_TYPE.REWORK_ORDER.getValue() != model.getWorkOrderType()) {
                    produceSnExtList = produceSnExtService.getProduceSnExtListByOrderNo(model.getOrganizeCode(), model.getWorkOrderNo());
                    List<SnAndPackageNoCorrelationModel> packageList = packageExtDao.getSnAndPackCorrelationListByOrderNo(model.getOrganizeCode(), model.getWorkOrderNo());
                    Map<String, String> snMap = CollectionUtils.isEmpty(packageList) ? new HashMap<>() :
                            packageList.stream().filter(o -> null != o).collect(Collectors.toMap(SnAndPackageNoCorrelationModel::getSerialNumber, SnAndPackageNoCorrelationModel::getPackageNo));
                    produceSnExtModelList = new ArrayList<>();
                    for (MesProduceSnExt produceSnExt : produceSnExtList) {
                        if (null == produceSnExt) {
                            continue;
                        }
                        ProduceSnExtModel produceSnExtModel = new ProduceSnExtModel();
                        BeanUtils.copyProperties(produceSnExt, produceSnExtModel, MesPcnExtConstWords.ID);
                        produceSnExtModel.setPackageNo(snMap.get(produceSnExtModel.getSerialNumber()));
                        produceSnExtModelList.add(produceSnExtModel);
                    }
                } else {
                    ProduceSnExtModel produceSnExtModel = new ProduceSnExtModel(model.getOrganizeCode(), model.getWorkOrderNo());
                    produceSnExtModelList = produceSnRepairDao.queryProduceSnRepairAndPackageNoList(produceSnExtModel);
                }

                produceSnExtModelList = produceSnExtModelList.stream().filter(o -> (null != o && !serialNumberList.contains(o.getSerialNumber()))).collect(Collectors.toList());
                if (CollectionUtils.isEmpty(produceSnExtModelList)) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:工单[%s]筛除已经抽检完成的批次条码后不存在未抽检范围的条码,操作失败", model.getWorkOrderNo())
                            .build();
                }

                produceSnExtModelList = produceSnExtModelList.stream().filter(o -> (null != o
                        && (MesPcnExtEnumUtil.PRODUCE_SN_STATUS.OFFLINE.getValue() == o.getSnStatus() || MesPcnExtEnumUtil.PRODUCE_SN_STATUS.ERR_OFFLINE.getValue() == o.getSnStatus())
                                && model.getShiftCode().equals(o.getShiftCode()) && model.getWorkTime().equals(o.getWorkTime()))).collect(Collectors.toList());
                Optional<ProduceSnExtModel> produceSnExtModelOp = CollectionUtils.isEmpty(produceSnExtModelList) ? null :
                        produceSnExtModelList.stream().filter(o -> (null != o && o.getSerialNumber().equals(model.getSerialNumber()))).findFirst();
                if (null == produceSnExtModelOp || !produceSnExtModelOp.isPresent()) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:工单[%s]筛除已经抽检完成的批次条码后不包含当前扫描的产品条码[%s],操作失败", model.getWorkOrderNo(), model.getSerialNumber())
                            .build();
                }
                produceSnExtModelList = produceSnExtModelList.stream().filter(o -> (null != o && !o.getSerialNumber().equals(model.getSerialNumber())))
                        .sorted(Comparator.comparing(ProduceSnExtModel::getOutWorkCenterTime)).collect(Collectors.toList());
                if (CollectionUtils.isEmpty(produceSnExtModelList)) {
                    produceSnExtModelList = new ArrayList<>();
                }
                produceSnExtModelList.add(0, produceSnExtModelOp.get());

                MesOqcCheck oqcCheck = new MesOqcCheck();
                oqcCheck.setOqcNo(getOqcNo(model.getUserInfo(), model.getOrganizeCode()));
                oqcCheck.setOrderNo(model.getWorkOrderNo());
                oqcCheck.setPartNo(model.getPartNo());
                oqcCheck.setPartName(outPutStatisticsOqcOp.get().getPartNameRdd());
                oqcCheck.setWorkCenterCode(model.getWorkCenterCode());
                oqcCheck.setWorkTime(model.getWorkTime());
                oqcCheck.setShiftCode(model.getShiftCode());
                oqcCheck.setPlanQty(outPutStatisticsOqcOp.get().getPlanQty());
                if (Integer.valueOf(produceSnExtModelList.size()).compareTo(Integer.valueOf(model.getBatchLimit().intValue())) >= 0) {
                    produceSnExtModelList = produceSnExtModelList.subList(0, model.getBatchLimit().intValue());
                    oqcCheck.setAssociatedStatus(MesPcnExtEnumUtil.ASSOCIATED_STATUS.CLOSE.getValue());
                } else {
                    oqcCheck.setAssociatedStatus(MesPcnExtEnumUtil.ASSOCIATED_STATUS.OPEN.getValue());
                }
                oqcCheck.setCheckLimit(new Double(produceSnExtModelList.size()));
                oqcCheck.setSerialNumber(model.getSerialNumber());
                oqcCheck.setSpotCheckQty(model.getSpotCheckQty());
                oqcCheck.setBatchLimit(model.getBatchLimit());
                oqcCheck.setOqcType(model.getOqcType());
                oqcCheck.setCategoryCode3(model.getCategoryCode3());
                oqcCheck.setOrganizeCode(model.getOrganizeCode());
                ConvertBean.serviceModelInitialize(oqcCheck, model.getUserInfo());
                oqcCheckRepository.insert(oqcCheck);

                for (ProduceSnExtModel snModel : produceSnExtModelList) {
                    if (null == snModel) {
                        continue;
                    }
                    MesOqcPackageDetail detail = new MesOqcPackageDetail();
                    detail.setOrderNo(model.getWorkOrderNo());
                    detail.setWorkCenterCode(model.getWorkCenterCode());
                    detail.setOqcNo(oqcCheck.getOqcNo());
                    detail.setSerialNumber(snModel.getSerialNumber());
                    detail.setPackageNo(snModel.getPackageNo());
                    detail.setOrganizeCode(model.getOrganizeCode());
                    ConvertBean.serviceModelInitialize(detail, model.getUserInfo());
                    oqcPackageDetailRepository.insert(detail);
                }

                for (MesOqcProject oqcProject : oqcProjectList) {
                    if (null == oqcProject) {
                        continue;
                    }
                    MesOqcCheckDetail oqcCheckDetail = new MesOqcCheckDetail();
                    BeanUtils.copyProperties(oqcProject, oqcCheckDetail, MesPcnExtConstWords.ID);
                    oqcCheckDetail.setOqcNo(oqcCheck.getOqcNo());
                    oqcCheckDetail.setPartNo(model.getPartNo());
                    oqcCheckDetail.setPartName(oqcCheck.getPartName());
                    oqcCheckDetail.setOrderNo(model.getWorkOrderNo());
                    oqcCheckDetail.setSerialNumber(model.getSerialNumber());
                    oqcCheckDetail.setPid(oqcProject.getId());
                    oqcCheckDetail.setWorkCenterCode(model.getWorkCenterCode());
                    oqcCheckDetail.setWorkTime(model.getWorkTime());
                    oqcCheckDetail.setShiftCode(model.getShiftCode());
                    ConvertBean.serviceModelInitialize(oqcCheckDetail, model.getUserInfo());
                    oqcCheckDetailRepository.insert(oqcCheckDetail);
                }

                MesOutPutStatisticsOqc outPutStatisticsOqc = outPutStatisticsOqcOp.get();
                outPutStatisticsOqc.setSpotCheckQty(MathOperation.add(outPutStatisticsOqc.getSpotCheckQty(), model.getSpotCheckQty()));
                outPutStatisticsOqc.setCheckLimit(MathOperation.add(outPutStatisticsOqc.getCheckLimit(), model.getBatchLimit()));
                ConvertBean.serviceModelUpdate(outPutStatisticsOqc, model.getUserInfo());
                outPutStatisticsOqc.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
                outPutStatisticsOqcRepository.save(outPutStatisticsOqc);

            } else {
                //拆机
                List<MesOqcCheck> snCheckList = CollectionUtils.isEmpty(oqcCheckList) ? null :
                        oqcCheckList.stream().filter(o -> (null != o && o.getSerialNumber().equals(model.getSerialNumber()))).collect(Collectors.toList());
                Map<Integer, List<MesOqcCheck>> snCheckByTypeMap = CollectionUtils.isEmpty(snCheckList) ? null :
                        snCheckList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesOqcCheck::getOqcType));
                if (CollectionUtils.isEmpty(snCheckByTypeMap)) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:产品条码[%s]不能先生成拆机检验单,请先生成其他类型的检验单", model.getSerialNumber())
                            .build();
                }
                if (snCheckByTypeMap.size() == 2) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:产品条码[%s]已经生成过拆机检验单,请勿重复生成,操作失败", model.getSerialNumber())
                            .build();
                }

                if (MathOperation.compareTo(snCheckList.get(0).getBatchLimit(), model.getBatchLimit()) != 0) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:产品条码[%s]班次[%s]作业时间[%s]已经存在的[%s]的批次范围为[%s],生成拆机检验单的批次范围需要保持一致,请修改批次范围",
                                    model.getSerialNumber(), model.getShiftCode(), model.getWorkTime(),
                                    MesPcnExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(snCheckList.get(0).getOqcType()), snCheckList.get(0).getBatchLimit())
                            .build();
                }

                MesOutPutStatistics outPutStatistics = outPutStatisticsRepository.getByProperty(
                        new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID,
                                MesPcnExtConstWords.WORK_ORDER_NO, MesPcnExtConstWords.SHIFT_CODE, MesPcnExtConstWords.WORK_TIME},
                        new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(),
                                model.getWorkOrderNo(), model.getShiftCode(), model.getWorkTime()});
                if (null == outPutStatistics) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("出货检验:根据工单[%s]班次[%s]作业时间[%s],未查询到产量统计数据",
                                    model.getWorkOrderNo(), model.getShiftCode(), model.getWorkTime())
                            .build();
                }

                if (StringUtils.isEmpty(model.getCategoryCode3())) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:生产工单[%s]关联的物料编码[%s]未维护产品类型,操作失败", model.getWorkOrderNo(), model.getPartNo())
                            .build();
                }
                oqcProjectList = oqcProjectRepository.findByProperty(
                        new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.OQC_TYPE, MesPcnExtConstWords.CATEGORY_CODE3},
                        new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getOqcType(), model.getCategoryCode3()});

                if (CollectionUtils.isEmpty(oqcProjectList)) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:物料编码[%s]检验类型[%s]未维护出货检验项,操作失败",
                                    model.getPartNo(), MesPcnExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(model.getOqcType()))
                            .build();
                }

                MesOqcCheck oqcCheck = new MesOqcCheck();
                oqcCheck.setOqcNo(getOqcNo(model.getUserInfo(), model.getOrganizeCode()));
                oqcCheck.setOrderNo(model.getWorkOrderNo());
                oqcCheck.setPartNo(model.getPartNo());
                oqcCheck.setPartName(outPutStatistics.getPartNameRdd());
                oqcCheck.setWorkCenterCode(model.getWorkCenterCode());
                oqcCheck.setWorkTime(model.getWorkTime());
                oqcCheck.setShiftCode(model.getShiftCode());
                oqcCheck.setPlanQty(outPutStatistics.getPlanQty());
                oqcCheck.setAssociatedStatus(MesPcnExtEnumUtil.ASSOCIATED_STATUS.CLOSE.getValue());
                oqcCheck.setCheckLimit(model.getBatchLimit());
                oqcCheck.setSerialNumber(model.getSerialNumber());
                oqcCheck.setSpotCheckQty(model.getSpotCheckQty());
                oqcCheck.setBatchLimit(model.getBatchLimit());
                oqcCheck.setOqcType(model.getOqcType());
                oqcCheck.setCategoryCode3(model.getCategoryCode3());
                oqcCheck.setOrganizeCode(model.getOrganizeCode());
                ConvertBean.serviceModelInitialize(oqcCheck, model.getUserInfo());
                oqcCheckRepository.insert(oqcCheck);

                for (MesOqcProject oqcProject : oqcProjectList) {
                    if (null == oqcProject) {
                        continue;
                    }
                    MesOqcCheckDetail oqcCheckDetail = new MesOqcCheckDetail();
                    BeanUtils.copyProperties(oqcProject, oqcCheckDetail, MesPcnExtConstWords.ID);
                    oqcCheckDetail.setOqcNo(oqcCheck.getOqcNo());
                    oqcCheckDetail.setPartNo(model.getPartNo());
                    oqcCheckDetail.setPartName(oqcCheck.getPartName());
                    oqcCheckDetail.setOrderNo(model.getWorkOrderNo());
                    oqcCheckDetail.setSerialNumber(model.getSerialNumber());
                    oqcCheckDetail.setPid(oqcProject.getId());
                    oqcCheckDetail.setWorkCenterCode(model.getWorkCenterCode());
                    oqcCheckDetail.setWorkTime(model.getWorkTime());
                    oqcCheckDetail.setShiftCode(model.getShiftCode());
                    ConvertBean.serviceModelInitialize(oqcCheckDetail, model.getUserInfo());
                    oqcCheckDetailRepository.insert(oqcCheckDetail);
                }
            }
        } else {
            //组件
            if (MesPcnExtEnumUtil.OQC_CHECK_TYPE.TEARDOWN_INSPECTION.getValue() == model.getOqcType()) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("切换:组件不支持生成拆机检验单,操作失败")
                        .build();
            }

            if (MathOperation.compareTo(model.getSpotCheckQty(), new Double(0)) <= 0) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("生成检验单:组件抽检数量必须大于[0]")
                        .build();
            }
            if (MathOperation.compareTo(model.getBatchLimit(), new Double(0)) <= 0) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("生成检验单:组件抽检批次范围必须大于[0]")
                        .build();
            }
            if (MathOperation.compareTo(model.getSpotCheckQty(), model.getBatchLimit()) > 0) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("生成检验单:组件抽检数量必须小于等于批次范围")
                        .build();
            }

            List<MesOqcCheck> oqcCheckList = oqcCheckRepository.findByProperty(
                    new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.ORDER_NO},
                    new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getWorkOrderNo()});

            List<MesOqcProject> oqcProjectList;
            if (MesPcnExtEnumUtil.OQC_CHECK_TYPE.DAILY_INSPECTION.getValue() == model.getOqcType()) {
                if (!CollectionUtils.isEmpty(oqcCheckList) && oqcCheckList.get(0).getOqcType() == MesPcnExtEnumUtil.OQC_CHECK_TYPE.EMPTY_INSPECTION.getValue()) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:生产工单[%s]已经生成空洞检验单,不能再生成日常检验单,操作失败", model.getWorkOrderNo())
                            .build();
                }
                oqcProjectList = oqcProjectRepository.findByProperty(
                        new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.PART_NO, MesPcnExtConstWords.OQC_TYPE},
                        new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getPartNo(), model.getOqcType()});
            } else {
                if (!CollectionUtils.isEmpty(oqcCheckList) && oqcCheckList.get(0).getOqcType() == MesPcnExtEnumUtil.OQC_CHECK_TYPE.DAILY_INSPECTION.getValue()) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:生产工单[%s]已经生成日常检验,不能再生成空洞检验单,操作失败", model.getWorkOrderNo())
                            .build();
                }

                if (StringUtils.isEmpty(model.getCategoryCode3())) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:生产工单[%s]关联的物料编码[%s]未维护产品类型,操作失败", model.getWorkOrderNo(), model.getPartNo())
                            .build();
                }
                oqcProjectList = oqcProjectRepository.findByProperty(
                        new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.OQC_TYPE, MesPcnExtConstWords.CATEGORY_CODE3},
                        new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getOqcType(), model.getCategoryCode3()});
            }

            if (CollectionUtils.isEmpty(oqcProjectList)) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("生成检验单:物料编码[%s]检验类型[%s]未维护出货检验项,操作失败",
                                model.getPartNo(), MesPcnExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(model.getOqcType()))
                        .build();
            }

            Optional<MesOqcCheck> oqcCheckOp = !CollectionUtils.isEmpty(oqcCheckList) ? null : oqcCheckList.stream()
                    .filter(o -> (null != o && (StringUtils.isEmpty(o.getCheckResult()) || null == MesPcnExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(o.getCheckResult())))).findFirst();
            if (null != oqcCheckOp && oqcCheckOp.isPresent()) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("生成检验单:工单[%s]班次[%s]时间[%s]存在未处理的检验单[%s],操作失败",
                                model.getWorkOrderNo(), model.getShiftCode(), model.getWorkTime(), oqcCheckOp.get().getOqcNo())
                        .build();
            }


            List<MesOutPutStatisticsOqc> outPutStatisticsOqcList = outPutStatisticsOqcRepository.findByProperty(
                    new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.WORK_ORDER_NO},
                    new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getWorkOrderNo()},
                    " order by createDatetime desc ");
            if (CollectionUtils.isEmpty(outPutStatisticsOqcList)) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("生成检验单:工单[%s]缺失产量统计出货检验数据", model.getWorkOrderNo())
                        .build();
            }
            Optional<MesOutPutStatisticsOqc> outPutStatisticsOqcOp = outPutStatisticsOqcList.stream()
                    .filter(o -> (null != o && o.getShiftCode().equals(model.getShiftCode()) && o.getWorkTime().equals(model.getWorkTime()))).findFirst();
            if (null == outPutStatisticsOqcOp || !outPutStatisticsOqcOp.isPresent()) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("生成检验单:工单[%s]缺失班次[%s]作业时间[%s]的产量统计出货检验数据", model.getWorkOrderNo(), model.getShiftCode(), model.getWorkTime())
                        .build();
            }

            Double unCheckBatchLimit;
            if (outPutStatisticsOqcList.get(0).getWorkTime().equals(model.getWorkTime()) && outPutStatisticsOqcList.get(0).getShiftCode().equals(model.getShiftCode())) {
                List<MesOutPutStatistics> outPutStatisticsList = outPutStatisticsRepository.findByProperty(
                        new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.WORK_ORDER_NO},
                        new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getWorkOrderNo()},
                        " order by createDatetime desc ");
                if (CollectionUtils.isEmpty(outPutStatisticsList)) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:工单[%s]缺失产量统计数据", model.getWorkOrderNo())
                            .build();
                }

                Double checkedLimitAmount = outPutStatisticsList.stream().filter(o -> (null != o
                        && o.getId().compareTo(outPutStatisticsOqcList.get(0).getPid()) != 0 && !StringUtils.isEmpty(o.getQty()))).mapToDouble(MesOutPutStatistics::getQty).sum();
                checkedLimitAmount = MathOperation.add(checkedLimitAmount, outPutStatisticsOqcList.get(0).getCheckLimit());
                unCheckBatchLimit = MathOperation.sub(outPutStatisticsOqcOp.get().getPlanQty(), checkedLimitAmount);
            } else {
                MesOutPutStatistics outPutStatistics = outPutStatisticsRepository.getById(outPutStatisticsOqcOp.get().getPid());
                if (null == outPutStatistics) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                            .setErrorDetail("生成检验单:工单[%s]缺失班次[%s]作业时间[%s]的产量统计数据", model.getWorkOrderNo(), model.getShiftCode(), model.getWorkTime())
                            .build();
                }
                unCheckBatchLimit = MathOperation.sub(outPutStatistics.getQty(), outPutStatisticsOqcOp.get().getCheckLimit());
            }

            if (MathOperation.compareTo(unCheckBatchLimit, new Double(0)) < 0) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("生成检验单:工单[%s]检验类型[%s]批次范围计算有误,请联系运维人员", model.getWorkOrderNo(), MesPcnExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(model.getOqcType()))
                        .build();
            }

            if (MathOperation.compareTo(unCheckBatchLimit, model.getBatchLimit()) < 0) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("生成检验单:工单[%s]班次[%s]作业时间[%s]检验类型[%s]剩余最大未检批次范围为[%s],请重新输入批次范围",
                                model.getWorkOrderNo(), model.getShiftCode(), model.getWorkTime(), MesPcnExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(model.getOqcType()), unCheckBatchLimit)
                        .build();
            }

            MesOqcCheck oqcCheck = new MesOqcCheck();
            oqcCheck.setOqcNo(getOqcNo(model.getUserInfo(), model.getOrganizeCode()));
            oqcCheck.setOrderNo(model.getWorkOrderNo());
            oqcCheck.setPartNo(model.getPartNo());
            oqcCheck.setPartName(outPutStatisticsOqcOp.get().getPartNameRdd());
            oqcCheck.setWorkCenterCode(model.getWorkCenterCode());
            oqcCheck.setWorkTime(model.getWorkTime());
            oqcCheck.setShiftCode(model.getShiftCode());
            oqcCheck.setPlanQty(outPutStatisticsOqcOp.get().getPlanQty());
            oqcCheck.setAssociatedStatus(MesPcnExtEnumUtil.ASSOCIATED_STATUS.CLOSE.getValue());
            oqcCheck.setCheckLimit(model.getBatchLimit());
            oqcCheck.setSpotCheckQty(model.getSpotCheckQty());
            oqcCheck.setBatchLimit(model.getBatchLimit());
            oqcCheck.setOqcType(model.getOqcType());
            oqcCheck.setCategoryCode3(model.getCategoryCode3());
            oqcCheck.setOrganizeCode(model.getOrganizeCode());
            ConvertBean.serviceModelInitialize(oqcCheck, model.getUserInfo());
            oqcCheckRepository.insert(oqcCheck);

            for (MesOqcProject oqcProject : oqcProjectList) {
                if (null == oqcProject) {
                    continue;
                }
                MesOqcCheckDetail oqcCheckDetail = new MesOqcCheckDetail();
                BeanUtils.copyProperties(oqcProject, oqcCheckDetail, MesPcnExtConstWords.ID);
                oqcCheckDetail.setOqcNo(oqcCheck.getOqcNo());
                oqcCheckDetail.setPartNo(model.getPartNo());
                oqcCheckDetail.setPartName(oqcCheck.getPartName());
                oqcCheckDetail.setOrderNo(model.getWorkOrderNo());
                oqcCheckDetail.setPid(oqcProject.getId());
                oqcCheckDetail.setWorkCenterCode(model.getWorkCenterCode());
                oqcCheckDetail.setWorkTime(model.getWorkTime());
                oqcCheckDetail.setShiftCode(model.getShiftCode());
                ConvertBean.serviceModelInitialize(oqcCheckDetail, model.getUserInfo());
                oqcCheckDetailRepository.insert(oqcCheckDetail);
            }

            MesOutPutStatisticsOqc outPutStatisticsOqc = outPutStatisticsOqcOp.get();
            outPutStatisticsOqc.setSpotCheckQty(MathOperation.add(outPutStatisticsOqc.getSpotCheckQty(), model.getSpotCheckQty()));
            outPutStatisticsOqc.setCheckLimit(MathOperation.add(outPutStatisticsOqc.getCheckLimit(), model.getBatchLimit()));
            ConvertBean.serviceModelUpdate(outPutStatisticsOqc, model.getUserInfo());
            outPutStatisticsOqc.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            outPutStatisticsOqcRepository.save(outPutStatisticsOqc);

        }
    }

    private String getOqcNo(String userName, String organizeCode) {
        BaseResultBean oneCodeResult = syncFuncService.syncSerialNo(new GenSerialNoModel(MesPcnExtEnumUtil.COMMON_SN.OQC_NO.getCode()), userName, organizeCode, 1);
        if (oneCodeResult != null && oneCodeResult.isSuccess()) {
            return oneCodeResult.getResultList().get(0).toString();
        } else {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.CLOUD_CALL_EXCEPTION.getCode())
                    .setErrorDetail("生成唯一单号失败")
                    .build();
        }
    }

    @Override
    public void updateOqcDetail(MesOqcCheckDetail oqcCheckDetail) {
        MesOqcCheckDetail oqcCheckDetailDb = oqcCheckDetailRepository.getById(oqcCheckDetail.getId());
        if (null == oqcCheckDetailDb) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("修改检验项:ID[%s]数据不存在", oqcCheckDetail.getId())
                    .build();
        }
        oqcCheckDetailDb.setAppliance(oqcCheckDetail.getAppliance());
        oqcCheckDetailDb.setRemark(oqcCheckDetail.getRemark());
        oqcCheckDetailDb.setCheckValue(oqcCheckDetail.getCheckValue());
        oqcCheckDetailDb.setResult(oqcCheckDetail.getResult());
        ConvertBean.serviceModelUpdate(oqcCheckDetailDb, oqcCheckDetail.getModifyUser());
        oqcCheckDetailRepository.save(oqcCheckDetailDb);
     }

    //TODO 操作结果跟下线同时进行的话若偶发条码未入[SxOqcSingle]表,再从下线处做补偿处理
    @Override
    public void updateOqcCheck(OqcManageModel model) {
        MesOqcCheck oqcCheckDb = oqcCheckRepository.getByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.OQC_NO},
                new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getOqcNo()});
        if (null == oqcCheckDb) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单结果:单据[%s]无效", model.getOqcNo())
                    .build();
        }
        if (!StringUtils.isEmpty(oqcCheckDb.getCheckResult()) && null != MesPcnExtEnumUtil.OQC_CHECK_RESULT.getByValue(oqcCheckDb.getCheckResult())) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单结果:单据[%s]已经存在结果[%s],操作失败",
                            model.getOqcNo(), MesPcnExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(oqcCheckDb.getCheckResult()))
                    .build();
        }
        oqcCheckDb.setCheckResult(model.getCheckResult());
        oqcCheckDb.setCheckUser(model.getUserInfo());
        ConvertBean.serviceModelUpdate(oqcCheckDb, model.getUserInfo());
        oqcCheckDb.setCheckTime(oqcCheckDb.getModifyDatetime());
        oqcCheckRepository.save(oqcCheckDb);

        SxOqcCheck sxOqcCheck = new SxOqcCheck();
        BeanUtils.copyProperties(oqcCheckDb, sxOqcCheck, MesPcnExtConstWords.ID);
        sxOqcCheck.setSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        sxOqcCheck.setWorkOrderNo(oqcCheckDb.getOrderNo());
        ConvertBean.serviceModelInitialize(sxOqcCheck, model.getUserInfo());
        sxOqcCheckRepository.insert(sxOqcCheck);

        if (!StringUtils.isEmpty(oqcCheckDb.getSerialNumber())) {
            List<MesOqcPackageDetail> oqcPackageDetailList = oqcPackageDetailRepository.findByProperty(
                    new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.OQC_NO},
                    new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getOqcNo()});
            if (!CollectionUtils.isEmpty(oqcPackageDetailList)) {
                for (MesOqcPackageDetail oqcPackageDetail : oqcPackageDetailList) {
                    SxOqcSingle sxOqcSingle = new SxOqcSingle();
                    sxOqcSingle.setOqcNo(model.getOqcNo());
                    sxOqcSingle.setCheckResult(oqcCheckDb.getCheckResult());
                    sxOqcSingle.setProductSn(oqcPackageDetail.getSerialNumber());
                    sxOqcSingle.setSerialNumber(oqcPackageDetail.getSerialNumber());
                    sxOqcSingle.setPackageNo(oqcPackageDetail.getPackageNo());
                    sxOqcSingle.setPartNo(oqcCheckDb.getPartNo());
                    sxOqcSingle.setWorkOrderNo(oqcPackageDetail.getOrderNo());
                    sxOqcSingle.setSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
                    sxOqcSingle.setOrganizeCode(model.getOrganizeCode());
                    ConvertBean.serviceModelInitialize(sxOqcSingle, model.getUserInfo());
                    sxOqcSingleRepository.insert(sxOqcSingle);
                }
            }
        }

    }

    @Override
    public ListPager<OqcLastCheckModel> queryOqcLastCheckPager(OqcLastCheckModel model, Pager pager) {
        pager = PagerHelper.getPager(pager, outPutStatisticsDao.queryOutPutStatisticsOqcByPagerCount(model));
        List<OqcLastCheckModel> modelList = outPutStatisticsDao.queryOutPutStatisticsOqcByPager(model , pager);
        if (!CollectionUtils.isEmpty(modelList)) {
            List<String> partNoList = (modelList.stream().filter(o -> null != o).map(OqcLastCheckModel::getPartNo).collect(Collectors.toList()))
                    .stream().distinct().filter(o -> !StringUtils.isEmpty(o)).collect(Collectors.toList());
            List<MesPartExt> partExtList = partExtService.getPartExtListByPartNoList(model.getOrganizeCode(), partNoList);
            Map<String, List<MesPartExt>> partNoMap = CollectionUtils.isEmpty(partExtList) ? new HashMap<>() :
                    partExtList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesPartExt::getPartNo));

            for (OqcLastCheckModel oqcLastCheckModel : modelList) {
                if (null != oqcLastCheckModel) {
                    if (StringUtils.isEmpty(oqcLastCheckModel.getCheckResult()) ||
                            MesPcnExtEnumUtil.OQC_TOTAL_STATUS.UNTREATED.getValue() == oqcLastCheckModel.getCheckResult() ||
                            StringUtils.isEmpty(MesPcnExtEnumUtil.OQC_TOTAL_STATUS.valueOfDescription(oqcLastCheckModel.getCheckResult()))) {
                        oqcLastCheckModel.setColor("white");
                    } else if (MesPcnExtEnumUtil.OQC_TOTAL_STATUS.QUALIFIED.getValue() == oqcLastCheckModel.getCheckResult()) {
                        oqcLastCheckModel.setColor("green");
                    } else {
                        oqcLastCheckModel.setColor("red");
                    }

                    oqcLastCheckModel.setCheckResultName(MesPcnExtEnumUtil.OQC_TOTAL_STATUS.valueOfDescription(oqcLastCheckModel.getCheckResult()));
                    if (partNoMap.containsKey(oqcLastCheckModel.getPartNo()) &&
                            !StringUtils.isEmpty(partNoMap.get(oqcLastCheckModel.getPartNo()).get(0).getCategoryCode2())) {
                        oqcLastCheckModel.setZjCheckReadOnly(false);
                    } else {
                        oqcLastCheckModel.setZjCheckReadOnly(true);
                    }
                }
            }
        }
        return new ListPager(modelList, pager);
    }

    @Override
    public void updateOutPutStatisticsOqcCheck(OqcLastCheckParamModel model) {
        for (OqcLastCheckParamModel item : model.getModelList()) {
            MesOutPutStatisticsOqc oqc = outPutStatisticsOqcRepository.getById(item.getId());
            oqc.setCheckResult(model.getCheckResult());
            oqc.setCheckUser(model.getUserInfo());
            oqc.setRemark(item.getRemark());
            oqc.setCheckNo(getTotalOqcNo(model.getUserInfo(), model.getOrganizeCode()));
            ConvertBean.serviceModelUpdate(oqc, model.getUserInfo());
            oqc.setConfirmTime(oqc.getModifyDatetime());
            oqc.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            outPutStatisticsOqcRepository.save(oqc);

            SxOqcBatch sxOqcBatch = new SxOqcBatch();
            sxOqcBatch.setWorkTime(oqc.getWorkTime());
            sxOqcBatch.setShiftCode(oqc.getShiftCode());
            sxOqcBatch.setWorkOrderNo(oqc.getWorkOrderNo());
            sxOqcBatch.setCheckResult(oqc.getCheckResult());
            sxOqcBatch.setSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            sxOqcBatch.setOrganizeCode(model.getOrganizeCode());
            ConvertBean.serviceModelInitialize(sxOqcBatch, model.getUserInfo());
            sxOqcBatchRepository.insert(sxOqcBatch);
        }
    }

    private String getTotalOqcNo(String userName, String organizeCode) {
        BaseResultBean oneCodeResult = syncFuncService.syncSerialNo(new GenSerialNoModel(MesPcnExtEnumUtil.COMMON_SN.TOQC_NO.getCode()), userName, organizeCode, 1);
        if (oneCodeResult != null && oneCodeResult.isSuccess()) {
            return oneCodeResult.getResultList().get(0).toString();
        } else {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.CLOUD_CALL_EXCEPTION.getCode())
                    .setErrorDetail("生成唯一工单号失败")
                    .build();
        }
    }

    @Override
    public MissPartConfirmModel queryMissingPart(String serialNumber, String organizeCode, Pager pager) {
        MissPartConfirmModel missPartConfirm = getMissPartConfirm( serialNumber, organizeCode );
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(missPartConfirm.getOrderNo(), MesPcnExtConstWords.WORK_ORDER_NO, packBean);
        DdlPreparedPack.getOrderByPack(new Object[]{CommonEnumUtil.ASC_OR_DESC.ASC.getValue()}, new String[]{MesPcnExtConstWords.SERIAL_NUMBER}, packBean);
        pager = PagerHelper.getPager(pager, errorLineOffRepository.findByHqlWhereCount(packBean));
        List<MesErrorLineOff> missPartList = errorLineOffRepository.findByHqlWherePage(packBean, pager);
        if (CollectionUtils.isEmpty(missPartList)) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                    .setErrorDetail("产品条码[%s]关联的生产工单[%s]不存在缺件数据", serialNumber, missPartConfirm.getOrderNo())
                    .build();
        }

        missPartConfirm.setMesErrorLineOffs(new ListPager(missPartList, pager));
        return missPartConfirm;
    }

    @Override
    public void updateErrorLineOff(Long[] idsStr, String organizeCode, String userInfo) {
        if (null == idsStr) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("请选勾选缺件数据")
                    .build();
        }

        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getInPackArray(idsStr, MesPcnExtConstWords.ID, packBean);
        List<MesErrorLineOff> errorLineOffList = errorLineOffRepository.findByHqlWhere(packBean);
        if (CollectionUtils.isEmpty(errorLineOffList)) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                    .setErrorDetail("选择的数据不存在")
                    .build();
        }

        for (MesErrorLineOff errorLineOff : errorLineOffList) {
            if (null == errorLineOff) {
                continue;
            }
            if (CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue() == errorLineOff.getFreStatus() ||
                    CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue() == errorLineOff.getConfirmStatus()) {
                continue;
            }
            errorLineOff.setConfirmStatus(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue());
            ConvertBean.serviceModelUpdate(errorLineOff, userInfo);
            errorLineOff.setConfirmTime(errorLineOff.getModifyDatetime());
            errorLineOff.setConfirmUser(userInfo);
            errorLineOffRepository.save(errorLineOff);
        }
    }

    @Override
    public MissPartConfirmModel getMissingPartAndWorkOrderBySn(String serialNumber, String organizeCode) {
        return getMissPartConfirm(serialNumber, organizeCode);
    }

    @Override
    public List<BuOutPutStatisticsModel> queryOutPutStatisticsModelList(OqcLastCheckModel model, String organizeCode) {
        List<MesOutPutStatistics> mesOutPutStatistics = queryOutPutStatisticsList(model, organizeCode);
        List<BuOutPutStatisticsModel> outPutStatisticsModels = new ArrayList<>();
        mesOutPutStatistics.stream().forEach(outPutStatistics -> {
            BuOutPutStatisticsModel outPutStatisticsModel = new BuOutPutStatisticsModel();
            BeanUtils.copyProperties(outPutStatistics, outPutStatisticsModel);
            outPutStatisticsModels.add(outPutStatisticsModel);
        });
        return outPutStatisticsModels;
    }

    @Override
    public List<MesOutPutStatistics> queryOutPutStatisticsList(OqcLastCheckModel model, String organizeCode) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(model.getWorkCenterCode(), MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(model.getPartNo(), MesPcnExtConstWords.PART_NO, packBean);
        DdlPreparedPack.getStringEqualPack(model.getWorkOrderNo(), MesPcnExtConstWords.WORK_ORDER_NO, packBean);
        DdlPreparedPack.getStringEqualPack(model.getShiftCode(), MesPcnExtConstWords.SHIFT_CODE, packBean);
        DdlPreparedPack.timeBuilder(model.getWorkTimeStart(), model.getWorkTimeEnd(), MesPcnExtConstWords.WORK_TIME, packBean, false);
        return outPutStatisticsRepository.findByHqlWhere(packBean);
    }


    private MissPartConfirmModel getMissPartConfirm(String serialNumber, String organizeCode) {
        String workOrderNo;
        String workTime;
        MesProduceSnExt produceSnExt = produceSnExtService.getProduceSnExtBySn(organizeCode, serialNumber);
        if (null == produceSnExt) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                    .setErrorDetail("产品条码[%s]无效", serialNumber)
                    .build();
        }

        if (!StringUtils.isEmpty(produceSnExt.getLastWorkOrderNo()) && !produceSnExt.getLastWorkOrderNo().equals(produceSnExt.getWorkOrderNo())) {
            MesProduceSnRepair produceSnRepair = produceSnRepairService.getProduceSnRepairBySn(organizeCode, serialNumber);
            if (null == produceSnRepair) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                        .setErrorDetail("产品条码[%s]与返工工单[%s]的关联关系不存在", serialNumber, produceSnExt.getLastWorkOrderNo())
                        .build();
            }
            workOrderNo = produceSnRepair.getWorkOrderNo();
            workTime = produceSnRepair.getWorkTime();
        } else {
            workOrderNo = produceSnExt.getWorkOrderNo();
            workTime = produceSnExt.getWorkTime();
        }

        MissPartConfirmModel missPartConfirm = new MissPartConfirmModel();
        missPartConfirm.setOrderNo(workOrderNo);
        missPartConfirm.setPartNo(produceSnExt.getPartNo());
        missPartConfirm.setPartName(produceSnExt.getPartNameRdd());
        missPartConfirm.setWorkTime(workTime);
        return missPartConfirm;
    }

}
