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

import cn.estsh.i3plus.ext.mes.pcn.api.base.*;
import cn.estsh.i3plus.ext.mes.pcn.api.base.jx.IJxTimeSegmentStatisticsService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IOutPutStatisticsService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IPackageExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IProduceSnTravelExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.ISxOutPutStatisticsTravelService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.jx.IJxOutPutStatisticsTimeSegmentService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.jx.IJxProdBusiStrategyService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.jx.IJxProduceSnExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.jx.IJxProduceSnMcRecordService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.bean.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.jx.JxProdBusiStrategyParamsBuilder;
import cn.estsh.i3plus.ext.mes.pcn.pojo.repository.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.ConvertBeanExt;
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.actor.shipping.dispatch.IFsmRouteDataService;
import cn.estsh.i3plus.mes.pcn.serviceimpl.busi.dispatch.cachedispatch.WorkCellDataCacheDispatch;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.tool.MathOperation;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.enumutil.MesPcnEnumUtil;
import cn.estsh.i3plus.pojo.mes.bean.*;
import cn.estsh.i3plus.pojo.mes.model.StationRequestBean;
import cn.estsh.i3plus.pojo.mes.model.StepResult;
import cn.estsh.i3plus.pojo.mes.repository.MesPackageDetailRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesProductDataRepository;
import com.alibaba.fastjson.JSONObject;
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 java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.stream.Collectors;

/**
 * @Author: wangjie
 * @CreateDate: 2021/01/18 11:41 上午
 * @Description: 工单通用处理
 **/
@Slf4j
@Service
public class JxProdBusiStrategyCommonService implements IJxProdBusiStrategyService {

    @Autowired
    private IJxProduceSnMcRecordService produceSnMcRecordService;

    @Autowired
    private IJxProduceSnExtService produceSnExtService;

    @Autowired
    private MesProduceSnMcRecordRepository produceSnMcRecordRepository;

    @Autowired
    private MesProduceSnExtRepository produceSnExtRepository;

    @Autowired
    private IProduceSnTravelExtService produceSnTravelExtService;

    @Autowired
    private MesBadCellDetailRepository badCellDetailRepository;

    @Autowired
    private MesProdBindRecordExtRepository prodBindRecordExtRepository;

    @Autowired
    private MesRepairRecordExtRepository repairRecordExtRepository;

    @Autowired
    private MesRepairTaskRepository repairTaskRepository;

    @Autowired
    private MesProductDataRepository productDataRepository;

    @Autowired
    private IFsmRouteDataService fsmRouteDataService;

    @Autowired
    private IWorkCenterExtService workCenterExtService;

    @Autowired
    private IShiftExtService shiftExtService;

    @Autowired
    private IShiftProdCenterRecordService shiftProdCenterRecordService;

    @Autowired
    private ISxWorkOrderExtService workOrderExtService;

    @Autowired
    private MesWorkOrderExtRepository workOrderExtRepository;

    @Autowired
    private IOutPutStatisticsService outPutStatisticsService;

    @Autowired
    private MesOutPutStatisticsRepository outPutStatisticsRepository;

    @Autowired
    private MesOutPutStatisticsOqcRepository outPutStatisticsOqcRepository;

    @Autowired
    private ISxOutPutStatisticsTravelService outPutStatisticsTravelService;

    @Autowired
    private SxProductOffLineRepository productOffLineRepository;

    @Autowired
    private SxWorkCellLineOffRecordRepository workCellLineOffRecordRepository;

    @Autowired
    private IPartExtService partExtService;

    @Autowired
    private MesPackageExtRepository packageExtRepository;

    @Autowired
    private MesPackageDetailRepository packageDetailRepository;

    @Autowired
    private IPackageExtService packageExtService;

    @Autowired
    private IJxTimeSegmentStatisticsService timeSegmentStatisticsService;

    @Autowired
    private IJxOutPutStatisticsTimeSegmentService outPutStatisticsTimeSegmentService;

    @Autowired
    private MesOutPutStatisticsTimeSegmentRepository outPutStatisticsTimeSegmentRepository;

    @Override
    public StepResult checkLineOn(JxProdBusiStrategyParamsBuilder params) {

        StepResult stepResult = checkShiftStart(params);
        if (!stepResult.isCompleted()) return stepResult;

        if (MesPcnExtEnumUtil.WORK_ORDER_TYPE.REWORK_ORDER.getValue() != params.getOrderModel().getWorkOrderType()) queryBusiData4Mc(params.manageCode(params.getScanInfo()));
        else queryProduceSnInfo(params.productSn(params.getScanInfo())).scanName();
        return StepResult.getSuccessComplete();
    }

    @Override
    public JxProdBusiStrategyParamsBuilder queryBusiData4Mc(JxProdBusiStrategyParamsBuilder params) {

        queryManageCodeInfo(params.manageCode(params.getScanInfo()));

        if (null == params.getManageCodeDb()) params.productSn(params.getScanInfo());

        queryProduceSnInfo(params);

        return params.scanName();

    }

    @Override
    public JxProdBusiStrategyParamsBuilder queryBusiData4Ps(JxProdBusiStrategyParamsBuilder params) {

        queryProduceSnInfo(params.productSn(params.getScanInfo()));

        if (null == params.getProduceSnExtDb()) params.manageCode(params.getScanInfo());

        queryManageCodeInfo(params);

        return params.scanName();

    }

    @Override
    public JxProdBusiStrategyParamsBuilder queryManageCodeInfo(JxProdBusiStrategyParamsBuilder params) {

        if (StringUtils.isEmpty(params.getManageCode())) return params;

        MesManageCode manageCodeDb = produceSnMcRecordService.getManageCodeDb(params.getOrganizeCode(), params.getManageCode(), params.getWorkCenterCode());

        if (null == manageCodeDb) return params.manageCode();

        MesProduceSnMcRecord produceSnMcRecordDb = produceSnMcRecordService.getProduceSnMcRecordDb(params.getOrganizeCode(), params.getManageCode());

        if (null != produceSnMcRecordDb) params.produceSnMcRecordDb(produceSnMcRecordDb).sn(produceSnMcRecordDb.getSerialNumber(), produceSnMcRecordDb.getProductSn());

        return params.manageCodeDb(manageCodeDb);
    }

    @Override
    public JxProdBusiStrategyParamsBuilder queryProduceSnInfo(JxProdBusiStrategyParamsBuilder params) {

        if (StringUtils.isEmpty(params.getSerialNumber()) && StringUtils.isEmpty(params.getProductSn())) return params;

        MesProduceSnExt produceSnExtDb = produceSnExtService.getProduceSnExtDb(params.getOrganizeCode(), params.getSerialNumber(), params.getProductSn());

        if (null == produceSnExtDb) return params.sn();

        return params.produceSnExtDb(produceSnExtDb).sn(produceSnExtDb.getSerialNumber(), produceSnExtDb.getProductSn()).manageCode(produceSnExtDb.getTrayNo());

    }

    @Override
    public Integer queryOrderBindedQty(JxProdBusiStrategyParamsBuilder params) {
        List<MesProduceSnMcRecord> produceSnMcRecordList = produceSnMcRecordService.getProduceSnMcRecordDbList(params.getOrganizeCode(), params.getOrderModel().getOrderNo());
        return CollectionUtils.isEmpty(produceSnMcRecordList) ? MesPcnExtConstWords.ZERO : produceSnMcRecordList.size();
    }

    @Override
    public void insertProduceSnMcRecord(JxProdBusiStrategyParamsBuilder params) {
        MesProduceSnMcRecord produceSnMcRecord = new MesProduceSnMcRecord();
        produceSnMcRecord.setManageCode(params.getManageCode());
        produceSnMcRecord.setSerialNumber(params.getSerialNumber());
        produceSnMcRecord.setPartNo(params.getOrderModel().getPartNo());
        produceSnMcRecord.setPartNameRdd(params.getOrderModel().getPartNameRdd());
        produceSnMcRecord.setWorkCenterCode(params.getWorkCenterCode());
        produceSnMcRecord.setWorkOrderNo(params.getOrderModel().getOrderNo());
        produceSnMcRecord.setSnStatus(MesPcnExtEnumUtil.MC_RECORD_SN_STATUS.LINE_ON.getValue());
        produceSnMcRecord.setOperateType(MesPcnExtEnumUtil.SN_OPERATE_TYPE.QUALIFIED.getValue());
        produceSnMcRecord.setLineOnStatus(MesPcnExtEnumUtil.MC_RECORD_LINE_ON_STATUS.FALSE.getValue());
        produceSnMcRecord.setQcStatus(MesPcnExtEnumUtil.MC_RECORD_QC_STATUS.TRUE.getValue());
        produceSnMcRecord.setOrganizeCode(params.getOrganizeCode());
        produceSnMcRecord.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        ConvertBean.serviceModelInitialize(produceSnMcRecord, params.getUserInfo());
        params.produceSnMcRecordDb(produceSnMcRecordRepository.insert(produceSnMcRecord));
    }

    @Override
    public StepResult execLineOnComplete(JxProdBusiStrategyParamsBuilder params) {

        StepResult stepResult = saveProduceSn4LineOn(params);

        if (!stepResult.isCompleted()) return stepResult;

        StepResult result = saveProduceSnMcRecord4LineOn(params);

        if (!result.isCompleted()) return result;

        insertProduceSnTravel(params);

        return stepResult;

    }

    private StepResult saveProduceSn4LineOn(JxProdBusiStrategyParamsBuilder params) {

        StepResult stepResult = StepResult.getSuccessComplete();

        if (StringUtils.isEmpty(params.getSerialNumber()) && StringUtils.isEmpty(params.getProductSn())) return stepResult;

        String serialNumber = params.getSerialNumber();
        String productSn = params.getProductSn();

        queryProduceSnInfo(params);

        MesProduceSnExt produceSnExtDb = params.getProduceSnExtDb();

        if (null == produceSnExtDb) return stepResult.isCompleted(false).msg(String.format("过程条码[%s]产品条码[%s]对应的信息不存在!", serialNumber, productSn));

        if (MesPcnExtEnumUtil.SN_OPERATE_TYPE.REPAIR.getValue() == produceSnExtDb.getOperateType()) return stepResult.isCompleted(false).msg(String.format("过程条码[%s]产品条码[%s]对应的信息当前业务状态[返修]!", params.getSerialNumber(), params.getProductSn()));

        if (MesPcnExtEnumUtil.PRODUCE_SN_STATUS.REPAIR_PROCESS.getValue() != produceSnExtDb.getSnStatus() &&
                MesPcnExtEnumUtil.PRODUCE_SN_QC_STATUS.QUALIFIED.getValue() == produceSnExtDb.getQcStatus()) produceSnExtDb.setSnStatus(MesPcnExtEnumUtil.PRODUCE_SN_STATUS.PROCESS.getValue());
        if (MesPcnExtEnumUtil.PRODUCE_SN_STATUS.REPAIR_PROCESS.getValue() != produceSnExtDb.getSnStatus() &&
                MesPcnExtEnumUtil.PRODUCE_SN_QC_STATUS.DEFECTED.getValue() == produceSnExtDb.getQcStatus()) produceSnExtDb.setSnStatus(MesPcnExtEnumUtil.PRODUCE_SN_STATUS.REPAIR_PROCESS.getValue());

        produceSnExtService.doPackSnExtProcess((StationRequestBean) params.getObj(), produceSnExtDb);
        ConvertBean.serviceModelUpdate(produceSnExtDb, params.getUserInfo());
        produceSnExtDb.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        new ConvertBeanExt(produceSnExtDb).convertBean(produceSnExtDb);

        params.produceSnExtDb(produceSnExtRepository.save(produceSnExtDb));

        return stepResult;

    }

    private StepResult saveProduceSnMcRecord4LineOn(JxProdBusiStrategyParamsBuilder params) {

        StepResult stepResult = StepResult.getSuccessComplete();

        if (StringUtils.isEmpty(params.getManageCode()) || !params.getManageCode().contains(MesPcnExtConstWords.AND)) return stepResult;

        String[] manageCodeArr = params.getManageCode().split(MesPcnExtConstWords.AND);

        MesProduceSnMcRecord produceSnMcRecordDb = produceSnMcRecordRepository.getById(Long.parseLong(manageCodeArr[1]));

        if (null == produceSnMcRecordDb) return stepResult.isCompleted(false).msg(String.format("管理编码[%s]ID[%s]对应的管理编码与工单条码关系信息不存在!", manageCodeArr[0], manageCodeArr[1]));

        if (MesPcnExtEnumUtil.SN_OPERATE_TYPE.REPAIR.getValue() == produceSnMcRecordDb.getOperateType()) return stepResult.isCompleted(false).msg(String.format("管理编码[%s]ID[%s]对应的管理编码与工单条码关系信息当前业务状态[返修]!", manageCodeArr[0], manageCodeArr[1]));

        if (MesPcnExtEnumUtil.MC_RECORD_LINE_ON_STATUS.TRUE.getValue() == produceSnMcRecordDb.getLineOnStatus()) return stepResult;

        produceSnMcRecordDb.setLineOnStatus(MesPcnExtEnumUtil.MC_RECORD_LINE_ON_STATUS.TRUE.getValue());
        ConvertBean.serviceModelUpdate(produceSnMcRecordDb, params.getUserInfo());
        produceSnMcRecordDb.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        produceSnMcRecordRepository.save(produceSnMcRecordDb);

        return stepResult;
    }

    @Override
    public void insertProduceSnTravel(JxProdBusiStrategyParamsBuilder params) {
        if (null == params.getProduceSnExtDb()) return;
        produceSnTravelExtService.insertProduceSnTravelExt(params.getProduceSnExtDb());
    }

    @Override
    public StepResult checkProcessing(JxProdBusiStrategyParamsBuilder params) { return this.checkFinalInspection(params); }

    @Override
    public StepResult checkFinalInspection(JxProdBusiStrategyParamsBuilder params) {

        StepResult stepResult = checkShiftStart(params);

        if (!stepResult.isCompleted()) return stepResult;

        if (MesPcnExtEnumUtil.WORK_ORDER_TYPE.REWORK_ORDER.getValue() != params.getOrderModel().getWorkOrderType()) queryBusiData4Mc(params.manageCode(params.getScanInfo()));
        else queryProduceSnInfo(params.productSn(params.getScanInfo())).scanName();

        if (null == params.getProduceSnExtDb()) return stepResult.isCompleted(false).msg(String.format("%s[%s]未匹配到有效的产品条码信息,验证失败!", params.getScanName(), params.getScanInfo()));

        if (!checkFinalInspection4Ps(params, stepResult).isCompleted() || !StringUtils.isEmpty(stepResult.getNextTriggerEvent())) return stepResult;

        return checkSnProcessIsValid(params, stepResult);

    }

    private StepResult checkFinalInspection4Ps(JxProdBusiStrategyParamsBuilder params, StepResult stepResult) {

        if (MesPcnExtEnumUtil.SN_OPERATE_TYPE.REPAIR.getValue() == params.getProduceSnExtDb().getOperateType())
            return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的产品条码信息当前业务类型[返修],验证失败!", params.getScanName(), params.getScanInfo()));

        if (params.getProduceSnExtDb().getLastWorkOrderNo().equals(params.getOrderModel().getOrderNo()) && null != params.getProduceSnMcRecordDb() && MesPcnExtEnumUtil.SN_OPERATE_TYPE.REPAIR.getValue() == params.getProduceSnMcRecordDb().getOperateType())
            return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的管理编码与工单条码关系信息当前业务类型[返修],验证失败!", params.getScanName(), params.getScanInfo()));

        if (params.getProduceSnExtDb().getLastWorkOrderNo().equals(params.getOrderModel().getOrderNo()) && null != params.getProduceSnMcRecordDb() && !params.getProduceSnMcRecordDb().getWorkOrderNo().equals(params.getOrderModel().getOrderNo()))
            return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的管理编码与工单条码关系信息关联的工单号[%s]与当前生产的工单号[%s]不一致,验证失败!", params.getScanName(), params.getScanInfo(), params.getProduceSnMcRecordDb().getWorkOrderNo(), params.getOrderModel().getOrderNo()));

        if (params.getProduceSnExtDb().getSnStatus() < MesPcnExtEnumUtil.PRODUCE_SN_STATUS.PROCESS.getValue() ||
                (!((StationRequestBean) params.getObj()).getWcpcMap().containsKey(MesPcnExtConstWords.KEY_PART_RECHECK) && params.getProduceSnExtDb().getSnStatus() > MesPcnExtEnumUtil.PRODUCE_SN_STATUS.REPAIR_PROCESS.getValue()))
            return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的产品条码信息当前条码状态[%s],验证失败!", params.getScanName(), params.getScanInfo(), MesPcnExtEnumUtil.PRODUCE_SN_STATUS.valueOfDescription(params.getProduceSnExtDb().getSnStatus())));

        if (!params.getProduceSnExtDb().getLastWorkOrderNo().equals(params.getOrderModel().getOrderNo()) && params.getProduceSnExtDb().getSnStatus() < MesPcnExtEnumUtil.PRODUCE_SN_STATUS.REPAIR_PROCESS.getValue())
            return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的产品条码信息关联的工单号[%s]与当前生产的工单号[%s]不一致,验证失败!", params.getScanName(), params.getScanInfo(), params.getProduceSnExtDb().getLastWorkOrderNo(), params.getOrderModel().getOrderNo()));

        String suffix = String.format("%s[%s]已匹配产品条码信息%s", params.getScanName(), params.getScanInfo(),
                params.getProduceSnExtDb().getSnStatus() < MesPcnExtEnumUtil.PRODUCE_SN_STATUS.REPAIR_PROCESS.getValue() ? MesPcnExtConstWords.EMPTY :
                        (params.getProduceSnExtDb().getSnStatus() == MesPcnExtEnumUtil.PRODUCE_SN_STATUS.REPAIR_PROCESS.getValue() ? "[已被标记为返修品]" : "[已被标记为出货检验还线品]"));

        if (!params.getProduceSnExtDb().getLastWorkOrderNo().equals(params.getOrderModel().getOrderNo())) return stepResult.nextTriggerEvent(MesPcnExtConstWords.TMP_ORDER).msg(String.format("%s,即将切换到临时工单[%s]!", suffix, params.getProduceSnExtDb().getLastWorkOrderNo()));

        if (params.getProduceSnExtDb().getSnStatus() > MesPcnExtEnumUtil.PRODUCE_SN_STATUS.REPAIR_PROCESS.getValue()) stepResult.nextTriggerEvent(MesPcnExtConstWords.KEY_PART_RECHECK);

        return stepResult.msg(String.format("%s,验证成功!", suffix));

    }

    @Override
    public void execFinalInspectionBindPs(JxProdBusiStrategyParamsBuilder params) {

        saveProduceSnMcRecord4FinalInspection(params);

        doRestoreBusiData(params);

        saveProduceSn4FinalInspection(params);

        insertProduceSnTravel4ProcessMerge(params);

    }

    private void insertProduceSnTravel4ProcessMerge(JxProdBusiStrategyParamsBuilder params) {
        if (null == params.getProduceSnExtDb()) return;
        MesProduceSnExt produceSnExt = ((StationRequestBean) params.getObj()).getWcpcMap().containsKey(MesPcnExtConstWords.PROCESS_MERGE_FLAG) ? doPackSnExtProcess(params) : params.getProduceSnExtDb();
        produceSnTravelExtService.insertProduceSnTravelExt(produceSnExt);
    }

    private MesProduceSnExt doPackSnExtProcess(JxProdBusiStrategyParamsBuilder params) {
        MesProduceSnExt produceSnExt = new MesProduceSnExt();
        BeanUtils.copyProperties(params.getProduceSnExtDb(), produceSnExt, MesPcnExtConstWords.ID);
        produceSnExtService.doPackSnExtProcess((StationRequestBean) params.getObj(), produceSnExt);
        ((StationRequestBean) params.getObj()).setProductSn(produceSnExt.getProductSn());
        return produceSnExt;
    }

    private void saveProduceSnMcRecord4FinalInspection(JxProdBusiStrategyParamsBuilder params) {

        if (StringUtils.isEmpty(params.getManageCode()) || !params.getManageCode().contains(MesPcnExtConstWords.AND)) return;

        String[] manageCodeArr = params.getManageCode().split(MesPcnExtConstWords.AND);

        MesProduceSnMcRecord produceSnMcRecordDb = produceSnMcRecordRepository.getById(Long.parseLong(manageCodeArr[1]));

        produceSnMcRecordDb.setSnStatus(MesPcnExtEnumUtil.MC_RECORD_SN_STATUS.LINE_OFF.getValue());
        if (StringUtils.isEmpty(produceSnMcRecordDb.getProductSn())) produceSnMcRecordDb.setProductSn(params.getScanInfo());
        if (MesPcnExtEnumUtil.MC_RECORD_QC_STATUS.TRUE.getValue() != produceSnMcRecordDb.getQcStatus()) produceSnMcRecordDb.setQcStatus(MesPcnExtEnumUtil.MC_RECORD_QC_STATUS.TRUE.getValue());
        ConvertBean.serviceModelUpdate(produceSnMcRecordDb, params.getUserInfo());
        produceSnMcRecordDb.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());

        params.produceSnMcRecordDb(produceSnMcRecordRepository.save(produceSnMcRecordDb)).manageCode(produceSnMcRecordDb.getManageCode());

    }

    private void saveProduceSn4FinalInspection(JxProdBusiStrategyParamsBuilder params) {

        MesProduceSnExt produceSnExtDb = queryProduceSnInfo(params).getProduceSnExtDb();

        if (StringUtils.isEmpty(produceSnExtDb.getProductSn())) produceSnExtDb.setProductSn(params.getScanInfo());
        if (MesPcnExtEnumUtil.PRODUCE_SN_QC_STATUS.QUALIFIED.getValue() != produceSnExtDb.getQcStatus()) produceSnExtDb.setQcStatus(MesPcnExtEnumUtil.PRODUCE_SN_QC_STATUS.QUALIFIED.getValue());

        produceSnExtService.doCheckIsNeedPackSnExtProcess((StationRequestBean) params.getObj(), produceSnExtDb);
        ConvertBean.serviceModelUpdate(produceSnExtDb, params.getUserInfo());
        produceSnExtDb.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        new ConvertBeanExt(produceSnExtDb).convertBean(produceSnExtDb);

        params.produceSnExtDb(produceSnExtRepository.save(produceSnExtDb));

    }

    private void doRestoreBusiData(JxProdBusiStrategyParamsBuilder params) {

        if (null == params.getProduceSnMcRecordDb()) return;

        doRestoreProdBindRecord(params);

        if (!doRestoreBadCellDetail(params)) return;

        doRestoreRepairRecord(params);

        doRestoreRepairTask(params);

        doRestoreProductData(params);

    }

    private void doRestoreProdBindRecord(JxProdBusiStrategyParamsBuilder params) {

        if (null == params.getProduceSnMcRecordDb()) return;

        List<MesProdBindRecordExt> prodBindRecordExtList = prodBindRecordExtRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.THIRD_PARTY_PID},
                new Object[]{params.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), params.getProduceSnMcRecordDb().getId().toString()});

        if (CollectionUtils.isEmpty(prodBindRecordExtList)) return;

        for (MesProdBindRecordExt item : prodBindRecordExtList) {
            if (null == item) continue;

            if (!StringUtils.isEmpty(item.getSerialNumber()) && !StringUtils.isEmpty(item.getProductSn())) continue;
            item.setSerialNumber(params.getProduceSnMcRecordDb().getSerialNumber());
            item.setProductSn(params.getProduceSnMcRecordDb().getProductSn());
            ConvertBean.serviceModelUpdate(item, params.getUserInfo());
            new ConvertBeanExt(item).convertBean(item);
            prodBindRecordExtRepository.save(item);
        }

    }

    private Boolean doRestoreBadCellDetail(JxProdBusiStrategyParamsBuilder params) {

        if (null == params.getProduceSnMcRecordDb()) return false;

        List<MesBadCellDetail> badCellDetailList = badCellDetailRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.THIRD_PARTY_PID},
                new Object[]{params.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), params.getProduceSnMcRecordDb().getId().toString()});

        if (CollectionUtils.isEmpty(badCellDetailList)) return false;

        Boolean result = false;
        for (MesBadCellDetail item : badCellDetailList) {
            if (null == item) continue;

            if (!StringUtils.isEmpty(item.getSerialNumber()) && !StringUtils.isEmpty(item.getProductSn())) continue;
            item.setSerialNumber(params.getProduceSnMcRecordDb().getSerialNumber());
            item.setProductSn(params.getProduceSnMcRecordDb().getProductSn());
            ConvertBean.serviceModelUpdate(item, params.getUserInfo());
            badCellDetailRepository.save(item);

            result = true;
        }

        return result;
    }

    private void doRestoreRepairRecord(JxProdBusiStrategyParamsBuilder params) {

        if (null == params.getProduceSnMcRecordDb()) return;

        List<MesRepairRecordExt> repairRecordExtList = repairRecordExtRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.THIRD_PARTY_PID},
                new Object[]{params.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), params.getProduceSnMcRecordDb().getId().toString()});

        if (CollectionUtils.isEmpty(repairRecordExtList)) return;

        for (MesRepairRecordExt item : repairRecordExtList) {
            if (null == item) continue;

            if (!StringUtils.isEmpty(item.getSerialNumber()) && !StringUtils.isEmpty(item.getProductSn())) continue;
            item.setSerialNumber(params.getProduceSnMcRecordDb().getSerialNumber());
            item.setProductSn(params.getProduceSnMcRecordDb().getProductSn());
            ConvertBean.serviceModelUpdate(item, params.getUserInfo());
            repairRecordExtRepository.save(item);
        }

    }

    private void doRestoreRepairTask(JxProdBusiStrategyParamsBuilder params) {

        if (null == params.getProduceSnMcRecordDb()) return;

        List<MesRepairTask> repairTaskList = repairTaskRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.THIRD_PARTY_PID},
                new Object[]{params.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), params.getProduceSnMcRecordDb().getId().toString()});

        if (CollectionUtils.isEmpty(repairTaskList)) return;

        for (MesRepairTask item : repairTaskList) {
            if (null == item) continue;

            if (!StringUtils.isEmpty(item.getSerialNumber()) && !StringUtils.isEmpty(item.getProductSn())) continue;
            item.setSerialNumber(params.getProduceSnMcRecordDb().getSerialNumber());
            item.setProductSn(params.getProduceSnMcRecordDb().getProductSn());
            ConvertBean.serviceModelUpdate(item, params.getUserInfo());
            repairTaskRepository.save(item);
        }

    }

    private void doRestoreProductData(JxProdBusiStrategyParamsBuilder params) {

        if (null == params.getProduceSnMcRecordDb()) return;

        List<MesProductData> productDataList = productDataRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.SERIAL_NUMBER},
                new Object[]{params.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), params.getProduceSnMcRecordDb().getSerialNumber()});

        for (MesProductData item : productDataList) {
            if (null == item) continue;
            if (!StringUtils.isEmpty(item.getProductSn())) continue;
            item.setProductSn(params.getProduceSnMcRecordDb().getProductSn());
            item.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            ConvertBean.serviceModelUpdate(item, params.getUserInfo());
            productDataRepository.save(item);
        }

    }

    @Override
    public void execFinalInspectionMarkRepair(JxProdBusiStrategyParamsBuilder params) {

        saveProduceSn4MarkRepair(params);

        saveProduceSnMcRecord4MarkRepair(params);

        insertProduceSnTravel(params);

    }

    private void saveProduceSn4MarkRepair(JxProdBusiStrategyParamsBuilder params) {

        if (StringUtils.isEmpty(params.getSerialNumber()) && StringUtils.isEmpty(params.getProductSn())) return;

        queryProduceSnInfo(params);

        MesProduceSnExt produceSnExtDb = params.getProduceSnExtDb();

        produceSnExtDb.setOperateType(MesPcnExtEnumUtil.SN_OPERATE_TYPE.REPAIR.getValue());
        produceSnExtService.clearProduceSnProcess(produceSnExtDb);
        ConvertBean.serviceModelUpdate(produceSnExtDb, params.getUserInfo());
        produceSnExtDb.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        new ConvertBeanExt(produceSnExtDb).convertBean(produceSnExtDb);

        params.produceSnExtDb(produceSnExtRepository.save(produceSnExtDb));

    }

    private void saveProduceSnMcRecord4MarkRepair(JxProdBusiStrategyParamsBuilder params) {

        if (StringUtils.isEmpty(params.getManageCode()) || !params.getManageCode().contains(MesPcnExtConstWords.AND)) return;

        String[] manageCodeArr = params.getManageCode().split(MesPcnExtConstWords.AND);

        MesProduceSnMcRecord produceSnMcRecordDb = produceSnMcRecordRepository.getById(Long.parseLong(manageCodeArr[1]));

        produceSnMcRecordDb.setOperateType(MesPcnExtEnumUtil.SN_OPERATE_TYPE.REPAIR.getValue());

        ConvertBean.serviceModelUpdate(produceSnMcRecordDb, params.getUserInfo());
        produceSnMcRecordDb.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        produceSnMcRecordRepository.save(produceSnMcRecordDb);

    }

    @Override
    public StepResult checkLineOff(JxProdBusiStrategyParamsBuilder params) {

        StepResult stepResult = StepResult.getSuccessComplete();

        queryProduceSnInfo(params.productSn(params.getScanInfo())).scanName();

        if (null == params.getProduceSnExtDb()) return stepResult.isCompleted(false).msg(String.format("产品条码[%s]信息不存在,操作失败!", params.getScanInfo()));

        if (!checkLineOff4Ps(params, stepResult).isCompleted() || !StringUtils.isEmpty(stepResult.getNextTriggerEvent())) return stepResult;

        return checkSnProcessIsValid(params, stepResult);

    }

    private StepResult checkLineOff4Ps(JxProdBusiStrategyParamsBuilder params, StepResult stepResult) {

        if (MesPcnExtEnumUtil.SN_OPERATE_TYPE.REPAIR.getValue() == params.getProduceSnExtDb().getOperateType())
            return stepResult.isCompleted(false).msg(String.format("产品条码[%s]信息当前业务类型[返修],验证失败!", params.getScanInfo()));

        if (MesPcnExtEnumUtil.PRODUCE_SN_QC_STATUS.DEFECTED.getValue() == params.getProduceSnExtDb().getQcStatus())
            return stepResult.isCompleted(false).msg(String.format("产品条码[%s]信息当前质量状态[不合格],验证失败!", params.getScanInfo()));

        if (params.getProduceSnExtDb().getSnStatus() < MesPcnExtEnumUtil.PRODUCE_SN_STATUS.PROCESS.getValue() ||
                (!((StationRequestBean) params.getObj()).getWcpcMap().containsKey(MesPcnExtConstWords.KEY_PART_RECHECK) && params.getProduceSnExtDb().getSnStatus() > MesPcnExtEnumUtil.PRODUCE_SN_STATUS.REPAIR_PROCESS.getValue()))
            return stepResult.isCompleted(false).msg(String.format("产品条码[%s]信息当前状态[%s],验证失败!", params.getScanInfo(), MesPcnExtEnumUtil.PRODUCE_SN_STATUS.valueOfDescription(params.getProduceSnExtDb().getSnStatus())));

        if (!params.getProduceSnExtDb().getLastWorkOrderNo().equals(params.getOrderModel().getOrderNo()) && params.getProduceSnExtDb().getSnStatus() < MesPcnExtEnumUtil.PRODUCE_SN_STATUS.REPAIR_PROCESS.getValue())
            return stepResult.isCompleted(false).msg(String.format("产品条码[%s]信息关联的工单号[%s]与当前生产的工单号[%s]不一致,验证失败!", params.getScanInfo(), params.getProduceSnExtDb().getLastWorkOrderNo(), params.getOrderModel().getOrderNo()));

        String suffix = String.format("产品条码[%s]信息%s", params.getScanName(), params.getScanInfo(),
                params.getProduceSnExtDb().getSnStatus() < MesPcnExtEnumUtil.PRODUCE_SN_STATUS.REPAIR_PROCESS.getValue() ? MesPcnExtConstWords.EMPTY :
                        (params.getProduceSnExtDb().getSnStatus() == MesPcnExtEnumUtil.PRODUCE_SN_STATUS.REPAIR_PROCESS.getValue() ? "[已被标记为返修品]" : "[已被标记为出货检验还线品]"));

        if (!params.getProduceSnExtDb().getLastWorkOrderNo().equals(params.getOrderModel().getOrderNo()))
            return stepResult.nextTriggerEvent(MesPcnExtConstWords.TMP_ORDER).msg(String.format("%s,即将切换到临时工单[%s]!", suffix, params.getProduceSnExtDb().getLastWorkOrderNo()));

        if (params.getProduceSnExtDb().getSnStatus() > MesPcnExtEnumUtil.PRODUCE_SN_STATUS.REPAIR_PROCESS.getValue()) stepResult.nextTriggerEvent(MesPcnExtConstWords.KEY_PART_RECHECK);

        return stepResult.msg(String.format("%s,验证成功!", suffix));

    }

    @Override
    public StepResult checkSnProcessIsValid(JxProdBusiStrategyParamsBuilder params, StepResult stepResult) {

        StationRequestBean reqBean = (StationRequestBean) params.getObj();
        MesProduceSnExt produceSnExt = params.getProduceSnExtDb();

        if (null == reqBean) return stepResult.isCompleted(false).msg("验证流程工序:入参缺失[StationRequestBean]对象信息,操作失败!");
        if (null == produceSnExt) return stepResult.isCompleted(false).msg("验证流程工序:入参缺失[MesProduceSnExt]对象信息,操作失败!");

        List<MesRouteProcess> routeProcessAllList = fsmRouteDataService.getCachedFsmRouteProcessData(reqBean);

        if (CollectionUtils.isEmpty(routeProcessAllList)) return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的流程代码[%s]未关联工序,操作失败!", params.getScanName(), params.getScanInfo(), reqBean.getRouteCode()));

        Optional<MesRouteProcess> routeProcessBySn = StringUtils.isEmpty(produceSnExt.getProcessCode()) ? Optional.of(routeProcessAllList.get(0)) : routeProcessAllList.stream().filter(o -> (null != o && o.getProcessCode().equals(produceSnExt.getProcessCode()))).findFirst();
        if (null == routeProcessBySn || !routeProcessBySn.isPresent())
            return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的工序代码[%s]不匹配当前流程代码[%s],操作失败!", params.getScanName(), params.getScanInfo(), produceSnExt.getProcessCode(), reqBean.getRouteCode()));

        Optional<MesRouteProcess> routeProcessOp = routeProcessAllList.stream().filter(o -> (null != o && o.getProcessCode().equals(reqBean.getProcessCode()))).findFirst();
        if (null == routeProcessOp || !routeProcessOp.isPresent())
            return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的流程代码[%s]不匹配当前工序代码[%s],操作失败!", params.getScanName(), params.getScanInfo(), reqBean.getRouteCode(), reqBean.getProcessCode()));

        if (!StringUtils.isEmpty(produceSnExt.getProcessCode()) && produceSnExt.getProcessCode().equals(reqBean.getProcessCode()))
            return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的产品条码信息已经过当前工序[%s],操作失败!", params.getScanName(), params.getScanInfo(), reqBean.getProcessCode()));

        List<MesRouteProcess> routeProcessList = routeProcessAllList.stream().filter(o -> (null != o && o.getSeq().compareTo(routeProcessOp.get().getSeq()) < 0)).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(routeProcessList) && (!StringUtils.isEmpty(produceSnExt.getProcessCode()) || !StringUtils.isEmpty(produceSnExt.getNextProcessCode())))
            return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的产品条码信息已经过首道工序[%s],操作失败!", params.getScanName(), params.getScanInfo(), routeProcessAllList.get(0).getProcessCode()));

        if (CollectionUtils.isEmpty(routeProcessList)) return stepResult;

        if (StringUtils.isEmpty(produceSnExt.getProcessCode()) && routeProcessList.get(0).getIsNecessary() == CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue())
            return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的产品条码信息未经过首道工序[%s],操作失败!", params.getScanName(), params.getScanInfo(), routeProcessList.get(0).getProcessCode()));

        List<MesRouteProcess> unCompleteProcessList;
        if (StringUtils.isEmpty(produceSnExt.getProcessCode())) unCompleteProcessList = routeProcessList;
        else {
            Optional<MesRouteProcess> completeProcessOp = routeProcessList.stream().filter(o -> (null != o && o.getProcessCode().equals(produceSnExt.getProcessCode()))).findFirst();
            if (null == completeProcessOp || !completeProcessOp.isPresent())
                return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的产品条码信息已经过当前工序[%s],操作失败!", params.getScanName(), params.getScanInfo(), reqBean.getProcessCode()));

            unCompleteProcessList = routeProcessList.stream().filter(o -> (null != o && o.getSeq().compareTo(completeProcessOp.get().getSeq()) > 0)).collect(Collectors.toList());
        }

        if (CollectionUtils.isEmpty(unCompleteProcessList)) return stepResult;

        unCompleteProcessList = unCompleteProcessList.stream().filter(o -> null != o).sorted(Comparator.comparing(MesRouteProcess::getSeq)).collect(Collectors.toList());

        Optional<MesRouteProcess> unCompleteProcessOp = unCompleteProcessList.stream().filter(o -> (null != o && o.getIsNecessary() == CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue())).findFirst();
        if (null != unCompleteProcessOp && unCompleteProcessOp.isPresent())
            return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的产品条码信息经过的上道工序[%s]与当前工序[%s]之间还存在必过工序[%s],操作失败!", params.getScanName(), params.getScanInfo(), produceSnExt.getProcessCode(), reqBean.getProcessCode(), unCompleteProcessOp.get().getProcessCode()));

        return stepResult;
    }

    @Override
    public StepResult checkShiftStart(JxProdBusiStrategyParamsBuilder params) {

        StepResult stepResult = StepResult.getNonComplete();

        MesWorkCenterExt workCenterExtDb = workCenterExtService.getWorkCenterExtByWorkCenterCode(params.getOrganizeCode(), params.getWorkCenterCode());
        if (null == workCenterExtDb) return stepResult.msg(String.format("生产线[%s]信息不存在,操作失败", params.getWorkCenterCode()));
        if (StringUtils.isEmpty(workCenterExtDb.getWorkTime()) || StringUtils.isEmpty(workCenterExtDb.getShiftCode())) return stepResult.msg(String.format("生产线[%s]未启动班次,操作失败", params.getWorkCenterCode()));

        WorkCellDataCacheDispatch dispatch = new WorkCellDataCacheDispatch.builder()
                .key(new StringJoiner(MesPcnExtConstWords.COLON).add(params.getOrganizeCode()).add(MesPcnExtConstWords.JX_PROD_SHIFT_DATA).toString())
                .item(new StringJoiner(MesPcnExtConstWords.AND).add(params.getWorkCenterCode()).add(workCenterExtDb.getShiftCode()).toString())
                .org(params.getOrganizeCode()).build().get();

        MesShift shiftDb;
        if (null != dispatch && !StringUtils.isEmpty(dispatch.getValue())) shiftDb = JSONObject.parseObject(dispatch.getValue(), MesShift.class);
        else {
            shiftDb = shiftExtService.getShiftByShiftCodeAndCenterCode(params.getOrganizeCode(), params.getWorkCenterCode(), workCenterExtDb.getShiftCode());
            if (null != shiftDb && !StringUtils.isEmpty(shiftDb.getStartTime()) && !StringUtils.isEmpty(shiftDb.getEndTime()))
                new WorkCellDataCacheDispatch.builder()
                        .key(new StringJoiner(MesPcnExtConstWords.COLON).add(params.getOrganizeCode()).add(MesPcnExtConstWords.JX_PROD_SHIFT_DATA).toString())
                        .item(new StringJoiner(MesPcnExtConstWords.AND).add(params.getWorkCenterCode()).add(workCenterExtDb.getShiftCode()).toString())
                        .value(JSONObject.toJSONString(shiftDb))
                        .timeSecond(MesPcnEnumUtil.EXPIRE_TIME.NEVER.getValue())
                        .org(params.getOrganizeCode()).build().save();
        }

        if (null == shiftDb || (StringUtils.isEmpty(shiftDb.getStartTime()) || StringUtils.isEmpty(shiftDb.getEndTime()))) return stepResult.msg(String.format("未配置有效的生产线[%s]班次代码[%s]信息,操作失败", params.getWorkCenterCode(), workCenterExtDb.getShiftCode()));

        String workTime = shiftProdCenterRecordService.getWorkTime(shiftDb.getStartTime(), shiftDb.getEndTime());
        if (StringUtils.isEmpty(workTime) || !workTime.equals(workCenterExtDb.getWorkTime())) return stepResult.msg(String.format("生产线[%s]需要重新启动班次,操作失败", params.getWorkCenterCode()));

        params.workCenterExtDb(workCenterExtDb);

        return stepResult.isCompleted(true);
    }

    private void getPartDb(JxProdBusiStrategyParamsBuilder params) {
        MesPart partDb = partExtService.getPart(params.getOrganizeCode(), params.getOrderModel().getPartNo());
        if (null != partDb) params.setPartDb(partDb);
    }

    @Override
    public StepResult execLineOff(JxProdBusiStrategyParamsBuilder params) {

        StepResult stepResult = checkShiftStart(params);

        if (!stepResult.isCompleted()) return stepResult;

        getPartDb(params);

        saveWorkOrder4LineOff(params);

        saveProduceSnLineOff(params);

        insertProduceSnTravel(params);

        savePackageInfo(params);

        saveOutPutStatisticsByTimeSegment(params, saveOutPutStatistics(params));

        doProductOffLine(params);

        saveLineOffRecord(params);

        return stepResult;
    }

    private void saveWorkOrder4LineOff(JxProdBusiStrategyParamsBuilder params) {

        MesWorkOrderExt workOrderExt = workOrderExtService.getWorkOrderExtByOrderNo(params.getOrganizeCode(), params.getOrderModel().getOrderNo());

        workOrderExt.setCompleteQty(StringUtils.isEmpty(workOrderExt.getCompleteQty()) ? new Double(1) : MathOperation.add(workOrderExt.getCompleteQty(), new Double(1)));
        if (MathOperation.compareTo(workOrderExt.getCompleteQty(), workOrderExt.getQty()) == 0) workOrderExt.setWorkOrderStatus(MesPcnExtEnumUtil.WORK_ORDER_STATUS.CLOSE.getValue());
        workOrderExt.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        ConvertBean.serviceModelUpdate(workOrderExt, params.getUserInfo());
        new ConvertBeanExt(workOrderExt).convertBean(workOrderExt);

        workOrderExtRepository.save(workOrderExt);
    }

    private void saveProduceSnLineOff(JxProdBusiStrategyParamsBuilder params) {

        MesProduceSnExt produceSnExtDb = queryProduceSnInfo(params).getProduceSnExtDb();

        produceSnExtDb.setSnStatus(MesPcnExtEnumUtil.PRODUCE_SN_STATUS.OFFLINE.getValue());
        ConvertBean.serviceModelUpdate(produceSnExtDb, params.getUserInfo());
        if (MesPcnExtEnumUtil.WORK_ORDER_TYPE.REWORK_ORDER.getValue() != params.getOrderModel().getWorkOrderType()) packProduceSnLineOff(params, produceSnExtDb);
        produceSnExtService.doPackSnExtProcess((StationRequestBean) params.getObj(), produceSnExtDb);
        produceSnExtDb.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        new ConvertBeanExt(produceSnExtDb).convertBean(produceSnExtDb);

        params.produceSnExtDb(produceSnExtRepository.save(produceSnExtDb));
    }

    private void packProduceSnLineOff(JxProdBusiStrategyParamsBuilder params, MesProduceSnExt produceSnExtDb) {
        produceSnExtDb.setOutWorkCenterTime(produceSnExtDb.getModifyDatetime());
        produceSnExtDb.setWorkTime(params.getWorkCenterExtDb().getWorkTime());
        produceSnExtDb.setShiftCode(params.getWorkCenterExtDb().getShiftCode());
        produceSnExtDb.setLotNo(produceSnExtDb.getWorkTime());
    }

    private void savePackageInfo(JxProdBusiStrategyParamsBuilder params) {
        if (MesPcnExtEnumUtil.WORK_ORDER_TYPE.REWORK_ORDER.getValue() != params.getOrderModel().getWorkOrderType()) {
            MesPackageExt pack = new MesPackageExt();
            pack.setPackageNo(params.getProduceSnExtDb().getProductSn());
            pack.setPartNo(params.getProduceSnExtDb().getPartNo());
            pack.setPartNameRdd(params.getProduceSnExtDb().getPartNameRdd());
            pack.setQty(new Double(1));
            pack.setPackSpecQty(new Double(1));
            pack.setUnit(params.getPartDb().getUnit());
            pack.setIsSealed(MesPcnEnumUtil.PACKAGE_IS_SEALED.SEALED.getValue());
            pack.setPrintStatus(MesPcnEnumUtil.PACKAGE_PRINT_STATUS.PRINTED.getValue());
            pack.setPackLevel(MesPcnEnumUtil.PACKAGE_PACKLEVEL.FIRST.getValue());
            pack.setWorkOrderNo(params.getProduceSnExtDb().getWorkOrderNo());
            pack.setLastWorkOrderNo(pack.getWorkOrderNo());
            pack.setWorkCenterCode(params.getWorkCenterCode());
            pack.setWorkCellCode(params.getWorkCellCode());
            pack.setLotNo(params.getProduceSnExtDb().getLotNo());
            pack.setWorkTime(params.getProduceSnExtDb().getWorkTime());
            pack.setShiftCode(params.getProduceSnExtDb().getShiftCode());
            pack.setOrganizeCode(params.getOrganizeCode());
            ConvertBean.serviceModelInitialize(pack, params.getUserInfo());
            pack.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            new ConvertBeanExt(pack).convertBean(pack);
            packageExtRepository.insert(pack);

            MesPackageDetail packageDetail = new MesPackageDetail();
            packageDetail.setPackageNo(pack.getPackageNo());
            packageDetail.setProductSn(params.getProduceSnExtDb().getProductSn());
            packageDetail.setSerialNumber(params.getProduceSnExtDb().getSerialNumber());
            packageDetail.setPartNo(pack.getPartNo());
            packageDetail.setPartNameRdd(pack.getPartNameRdd());
            packageDetail.setOrganizeCode(params.getOrganizeCode());
            packageDetail.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            ConvertBean.serviceModelInitialize(packageDetail, params.getUserInfo());
            packageDetailRepository.insert(packageDetail);
        } else {
            MesPackageExt pack = packageExtService.getPackageByPackNo(params.getOrganizeCode(), params.getProduceSnExtDb().getProductSn());
            pack.setLastWorkOrderNo(params.getOrderModel().getOrderNo());
            pack.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            ConvertBean.serviceModelUpdate(pack, params.getUserInfo());
            packageExtRepository.save(pack);
        }

    }

    private MesOutPutStatistics saveOutPutStatistics(JxProdBusiStrategyParamsBuilder params) {

        MesOutPutStatistics outPutStatistics = outPutStatisticsService.getOutPutStatisticsByTimeAndOrderNo(
                params.getOrganizeCode(), params.getOrderModel().getOrderNo(), params.getWorkCenterExtDb().getWorkTime(), params.getWorkCenterExtDb().getShiftCode());
        if (null == outPutStatistics) {
            outPutStatistics = new MesOutPutStatistics();
            outPutStatistics.setWorkCenterCode(params.getWorkCenterCode());
            outPutStatistics.setWorkOrderNo(params.getOrderModel().getOrderNo());
            outPutStatistics.setPartNo(params.getOrderModel().getPartNo());
            outPutStatistics.setPartNameRdd(params.getOrderModel().getPartNameRdd());
            outPutStatistics.setShiftCode(params.getWorkCenterExtDb().getShiftCode());
            outPutStatistics.setWorkTime(params.getWorkCenterExtDb().getWorkTime());
            outPutStatistics.setOrderStartTime(params.getOrderModel().getStartTime());
            outPutStatistics.setQty(new Double(1));
            outPutStatistics.setPlanQty(params.getOrderModel().getQty());
            outPutStatistics.setRemakeQty(new Double(0));
            outPutStatistics.setWorkOrderType(params.getOrderModel().getWorkOrderType());
            outPutStatistics.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            outPutStatistics.setOrganizeCode(params.getOrganizeCode());
            ConvertBean.serviceModelInitialize(outPutStatistics, params.getUserInfo());
            outPutStatistics.setStartTime(outPutStatistics.getModifyDatetime());
            outPutStatistics.setEndTime(outPutStatistics.getStartTime());
            outPutStatistics.setCategoryCode(params.getWorkCenterExtDb().getCategoryCode());
            outPutStatistics.setCareerCode(params.getWorkCenterExtDb().getCareerCode());
            outPutStatistics = outPutStatisticsRepository.insert(outPutStatistics);

            MesOutPutStatisticsOqc outPutStatisticsOqc = new MesOutPutStatisticsOqc();
            BeanUtils.copyProperties(outPutStatistics, outPutStatisticsOqc);
            outPutStatisticsOqc.setCheckLimit(new Double(0));
            outPutStatisticsOqc.setSpotCheckQty(new Double(0));
            outPutStatisticsOqc.setCheckResult(MesPcnExtEnumUtil.OQC_TOTAL_STATUS.UNTREATED.getValue());
            outPutStatisticsOqc.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            outPutStatisticsOqc.setPid(outPutStatistics.getId());
            outPutStatisticsOqcRepository.insert(outPutStatisticsOqc);

        } else {
            outPutStatistics.setQty(MathOperation.add(outPutStatistics.getQty(), new Double(1)));
            ConvertBean.serviceModelUpdate(outPutStatistics, params.getUserInfo());
            outPutStatistics.setEndTime(outPutStatistics.getModifyDatetime());
            outPutStatistics.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            outPutStatistics = outPutStatisticsRepository.save(outPutStatistics);
        }
        outPutStatisticsTravelService.insertOutPutStatisticsTravel(outPutStatistics);

        return outPutStatistics;

    }

    private void saveOutPutStatisticsByTimeSegment(JxProdBusiStrategyParamsBuilder params, MesOutPutStatistics outPutStatistics) {

        List<MesTimeSegmentStatistics> timeCfgList = timeSegmentStatisticsService.getTimeSegmentStatisticsListByShiftCode(params.getOrganizeCode(), params.getWorkCenterCode(), params.getWorkCenterExtDb().getShiftCode());

        if (CollectionUtils.isEmpty(timeCfgList)) return;

        String nowTime = TimeTool.getNowTime(MesPcnExtConstWords.TIME_TRUNCATE_SECOND_FORMAT);

        Optional<MesTimeSegmentStatistics> cfgOp = timeCfgList.stream().filter(o -> (null != o &&
                TimeTool.stringParseToDate(o.getStartTime(), MesPcnExtConstWords.TIME_TRUNCATE_SECOND_FORMAT).compareTo(TimeTool.stringParseToDate(nowTime, MesPcnExtConstWords.TIME_TRUNCATE_SECOND_FORMAT)) <= 0 &&
                TimeTool.stringParseToDate(o.getEndTime(), MesPcnExtConstWords.TIME_TRUNCATE_SECOND_FORMAT).compareTo(TimeTool.stringParseToDate(nowTime, MesPcnExtConstWords.TIME_TRUNCATE_SECOND_FORMAT)) >= 0)).findFirst();

        if (null == cfgOp || !cfgOp.isPresent()) return;

        List<MesOutPutStatisticsTimeSegment> outPutStatisticsTimeSegmentList = outPutStatisticsTimeSegmentService.
                getOutPutStatisticsTimeSegmentByOrderAndTsCode(params.getOrganizeCode(), params.getOrderModel().getOrderNo(), params.getWorkCenterExtDb().getWorkTime(), params.getWorkCenterExtDb().getShiftCode(), cfgOp.get().getTimeSegmentCode());

        MesOutPutStatisticsTimeSegment outPutStatisticsTimeSegment;
        if (CollectionUtils.isEmpty(outPutStatisticsTimeSegmentList) || !outPutStatisticsTimeSegmentList.get(0).getTimeSegmentCode().equals(cfgOp.get().getTimeSegmentCode())) {
            outPutStatisticsTimeSegment = new MesOutPutStatisticsTimeSegment();
            outPutStatisticsTimeSegment.setWorkCenterCode(params.getWorkCenterCode());
            outPutStatisticsTimeSegment.setWorkOrderNo(params.getOrderModel().getOrderNo());
            outPutStatisticsTimeSegment.setPartNo(params.getOrderModel().getPartNo());
            outPutStatisticsTimeSegment.setPartNameRdd(params.getOrderModel().getPartNameRdd());
            outPutStatisticsTimeSegment.setShiftCode(params.getWorkCenterExtDb().getShiftCode());
            outPutStatisticsTimeSegment.setWorkTime(params.getWorkCenterExtDb().getWorkTime());
            Double qty = CollectionUtils.isEmpty(outPutStatisticsTimeSegmentList) ? new Double(0) : outPutStatisticsTimeSegmentList.stream().filter(o -> null != o).mapToDouble(MesOutPutStatisticsTimeSegment::getQty).sum();
            outPutStatisticsTimeSegment.setQty(MathOperation.sub(outPutStatistics.getQty(), qty));
            outPutStatisticsTimeSegment.setPlanQty(params.getOrderModel().getQty());
            outPutStatisticsTimeSegment.setWorkOrderType(params.getOrderModel().getWorkOrderType());
            outPutStatisticsTimeSegment.setTimeSegmentCode(cfgOp.get().getTimeSegmentCode());
            outPutStatisticsTimeSegment.setTimeSegmentsStartTime(cfgOp.get().getStartTime());
            outPutStatisticsTimeSegment.setTimeSegmentEndTime(cfgOp.get().getEndTime());
            outPutStatisticsTimeSegment.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            outPutStatisticsTimeSegment.setOrganizeCode(params.getOrganizeCode());
            ConvertBean.serviceModelInitialize(outPutStatisticsTimeSegment, params.getUserInfo());
            outPutStatisticsTimeSegment.setStartTime(outPutStatisticsTimeSegment.getModifyDatetime());
            outPutStatisticsTimeSegment.setEndTime(outPutStatisticsTimeSegment.getStartTime());
            outPutStatisticsTimeSegmentRepository.insert(outPutStatisticsTimeSegment);
        } else {
            outPutStatisticsTimeSegment = outPutStatisticsTimeSegmentList.get(0);
            outPutStatisticsTimeSegment.setTimeSegmentsStartTime(cfgOp.get().getStartTime());
            outPutStatisticsTimeSegment.setTimeSegmentEndTime(cfgOp.get().getEndTime());
            outPutStatisticsTimeSegment.setQty(MathOperation.add(outPutStatisticsTimeSegment.getQty(), new Double(1)));
            ConvertBean.serviceModelUpdate(outPutStatisticsTimeSegment, params.getUserInfo());
            outPutStatisticsTimeSegment.setEndTime(outPutStatisticsTimeSegment.getModifyDatetime());
            outPutStatisticsTimeSegment.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            outPutStatisticsTimeSegmentRepository.save(outPutStatisticsTimeSegment);
        }

    }

    private void doProductOffLine(JxProdBusiStrategyParamsBuilder params) {

        if (MesPcnExtEnumUtil.WORK_ORDER_TYPE.STANDARD_ORDER.getValue() != params.getOrderModel().getWorkOrderType()) return;

        SxProductOffLine productOffLine = new SxProductOffLine();
        productOffLine.setWorkOrderNo(params.getOrderModel().getOrderNo());
        productOffLine.setPackageNo(params.getProductSn());
        productOffLine.setSerialNumber(params.getSerialNumber());
        productOffLine.setPartNo(params.getOrderModel().getPartNo());
        productOffLine.setPartName(params.getOrderModel().getPartNameRdd());
        productOffLine.setQty(new Double(1));
        productOffLine.setLotNo(params.getWorkCenterExtDb().getWorkTime());
        productOffLine.setShiftCode(params.getWorkCenterExtDb().getShiftCode());
        productOffLine.setWorkCenterCode(params.getWorkCenterCode());
        productOffLine.setErpWarehouse(params.getOrderModel().getErpWarehouse());
        if (MesPcnExtEnumUtil.WORK_ORDER_TYPE.REWORK_ORDER.getValue() != params.getOrderModel().getWorkOrderType()) productOffLine.setSnType(params.getProduceSnExtDb().getSnType());
        else productOffLine.setSnType(MesPcnExtEnumUtil.PRODUCE_SN_TYPE.REWORK_SN.getValue());
        if (null != params.getPartDb()) {
            productOffLine.setUnit(params.getPartDb().getUnit());
            productOffLine.setProdType(getProdType(params.getPartDb().getCategoryCode1()));
        }
        productOffLine.setSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        productOffLine.setOrganizeCode(params.getOrganizeCode());
        ConvertBean.serviceModelInitialize(productOffLine, params.getUserInfo());
        productOffLineRepository.insert(productOffLine);

    }

    private Integer getProdType(String categoryCode1) {
        try {
            if (StringUtils.isEmpty(categoryCode1)) return null;
            else return Integer.valueOf(categoryCode1);
        } catch (NumberFormatException e) {
            return null;
        }
    }

    private void saveLineOffRecord(JxProdBusiStrategyParamsBuilder params) {
        SxWorkCellLineOffRecord record = new SxWorkCellLineOffRecord();
        record.setWorkCenterCode(params.getWorkCenterCode());
        record.setWorkCellCode(params.getWorkCellCode());
        record.setWorkTime(params.getWorkCenterExtDb().getWorkTime());
        record.setShiftCode(params.getWorkCenterExtDb().getShiftCode());
        record.setProductSn(params.getProductSn());
        record.setWorkOrderNo(params.getOrderModel().getOrderNo());
        record.setPartNo(params.getOrderModel().getPartNo());
        record.setWorkOrderType(params.getOrderModel().getWorkOrderType());
        record.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        record.setOrganizeCode(params.getOrganizeCode());
        ConvertBean.serviceModelInitialize(record, params.getUserInfo());
        workCellLineOffRecordRepository.insert(record);
    }

    @Override
    public void execProcessing(JxProdBusiStrategyParamsBuilder params) {

        queryProduceSnInfo(params);

        MesProduceSnExt produceSnExtDb = queryProduceSnInfo(params).getProduceSnExtDb();

        ConvertBean.serviceModelUpdate(produceSnExtDb, params.getUserInfo());
        produceSnExtService.doPackSnExtProcess((StationRequestBean) params.getObj(), produceSnExtDb);
        produceSnExtDb.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        new ConvertBeanExt(produceSnExtDb).convertBean(produceSnExtDb);

        insertProduceSnTravel(params.produceSnExtDb(produceSnExtRepository.save(produceSnExtDb)));

    }

}