RunCardLotDispatchAction.java

package com.mycim.webapp.actions.splitruncardlot;

import com.fa.sesa.exception.Assert;
import com.fa.sesa.exception.Errors;
import com.fa.sesa.exception.SystemIllegalArgumentException;
import com.fa.sesa.i18n.I18nUtils;
import com.fa.sesa.threadlocal.LocalContext;
import com.mycim.framework.utils.beans.BeanUtils;
import com.mycim.framework.utils.lang.StringUtils;
import com.mycim.framework.utils.lang.collections.CollectionUtils;
import com.mycim.framework.utils.lang.collections.MapUtils;
import com.mycim.framework.utils.lang.math.NumberUtils;
import com.mycim.utils.CheckRegexUtils;
import com.mycim.utils.SorterUtils;
import com.mycim.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.SystemConstant;
import com.mycim.valueobject.bas.Relation;
import com.mycim.valueobject.consts.*;
import com.mycim.valueobject.edcspc.ReadingPrompts;
import com.mycim.valueobject.ems.Entity;
import com.mycim.valueobject.ems.Equipment;
import com.mycim.valueobject.prp.Recipe;
import com.mycim.valueobject.prp.RecipeVersion;
import com.mycim.valueobject.runcard.util.RunCardConstants;
import com.mycim.valueobject.sorter.SortJobBean;
import com.mycim.valueobject.sorter.SortJobCacheBean;
import com.mycim.valueobject.sorter.SorterModel;
import com.mycim.valueobject.spc.RunCardRawDataInfo;
import com.mycim.valueobject.wip.*;
import com.mycim.valueobject.wip.dto.*;
import com.mycim.webapp.Constants;
import com.mycim.webapp.WebUtils;
import com.mycim.webapp.actions.RunCardAction;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author finatice.yang
 * @date 2021/7/27
 **/
public class RunCardLotDispatchAction extends RunCardAction {

    /**
     * Action 方法: init
     */
    @Override
    public ActionForward init(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                              HttpServletResponse response) throws Exception {
        return dispatchInfo(mapping, form, request, response);
    }

    /**
     * Action 方法: dispatchLot
     **/
    public ActionForward dispatchLot(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                                     HttpServletResponse response) throws Exception {

        String lotId = WebUtils.getParameter("lotId", request);
        String eqptId = StringUtils.isEmpty(eqptId = WebUtils.getParameter("eqptId", request))?(String) request.getAttribute("eqptId"):eqptId;

        Lot lot = lotInqService.getLot(lotId);
        Assert.state(lot != null, Errors.create().key(MessageIdList.LOT_LOTRRN_NOT_FOUND).content("批次不存在!").build());

        Equipment equipment = emsService.getEquipment(eqptId, LocalContext.getFacilityRrn());
        Assert.isFalse(equipment == null || equipment.getInstanceRrn() <= 0,
                       Errors.create().key(MessageIdList.EQUIPMENT_ID_NOT_EXIST)
                             .content("Do not find the equipment, please check the equipment id!").build());

        LotRunCardStore lotStore = lotRunCardQueryService.getSplitRunCardLotStore(lot.getLotRrn());
        Long stepRrn = lotStore.getLotSpecialStepRrn();
        Integer stepSeq = lotStore.getStepSequence();
        SRCLotSpecialStep lotSpecialStep = lotRunCardQueryService.getLotSplitRunCardSpecialStep(stepRrn, stepSeq);

        if (LotStatus.isMoveInCheckStatus(lot.getLotStatus())) {
            doTransMoveIn(lot, equipment, lotSpecialStep, request);
        } else if (LotStatus.isMoveOutCheckStatus(lot.getLotStatus())) {
            //check是否是inline sorte
            SortJobBean sortJobBean = getSortJobListByCarrierRrn(lot);
            if(needSorterPage(sortJobBean, lot, equipment, request)){
                return mapping.findForward("inlineSorter");
            }
            if (needEdcPage(lot, lotSpecialStep, lotStore, eqptId, request)) {
                return mapping.findForward("edcPage");
            }
            doTransMoveOut(lot, equipment, lotSpecialStep, request);
        }
        return mapping.findForward(Constants.LOTLOCATION_KEY);
    }

    private boolean needSorterPage(SortJobBean sortJobBean, Lot lot, Equipment equipment, HttpServletRequest request) {
        Object rcSortFlag = Objects.isNull(rcSortFlag = WebUtils.getParameter(SystemConstant.Str.RC_SORT_OVER, request))?
                request.getAttribute(SystemConstant.Str.RC_SORT_OVER): rcSortFlag;
        if (sortJobBean.getMainJobRrn() > 0
                && StringUtils.equalsIgnoreCase(sortJobBean.getJobType(), SorterEnum.Constant.FLIP_SIDE)
                && rcSortFlag == null){
            //传递inline sorter需要的参数
            List<Map> lots = new ArrayList<>();
            Map lotInfo = new HashMap();
            Map parameters = new HashMap();
            lotInfo.put("carrierRrn", lot.getCarrierRrn());
            lotInfo.put("lotRrn", lot.getLotRrn());
            lots.add(lotInfo);
            parameters.put("eqptRrn", equipment.getInstanceRrn());
            request.setAttribute(SessionNames.COLLECTION_KEY, lots);
            request.setAttribute(SessionNames.PARAMETERSINFO_KEY, parameters);
            return true;
        }
        return false;
    }

    private Boolean needEdcPage(Lot lot, SRCLotSpecialStep lotSpecialStep, LotRunCardStore lotStore, String eqptId,
                                HttpServletRequest request) {
        if (lotSpecialStep != null && lotSpecialStep.getParameterSetRrn() > 0 &&
                request.getParameter("edcOver") == null) {
            List<RunCardRawDataInfo> rawDatas = edcChartService
                    .getRunCardRawDataInfoList(lot.getLotRrn(), lot.getStepSequence());
            if (CollectionUtils.isEmpty(rawDatas)) {
                request.setAttribute("lotId", lot.getLotId());
                request.setAttribute("parameterSetId", lotSpecialStep.getParameterSetId());
                request.setAttribute("lot", lot);
                request.setAttribute("lotStore", lotStore);
                request.setAttribute("eqptId", eqptId);
                return true;
            }
        }
        return false;
    }

    /**
     * Action 方法: dispatchInfo
     **/
    public ActionForward dispatchInfo(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                                      HttpServletResponse response) throws Exception {
        String lotId = request.getParameter("lotId");
        Lot lot = lotInqService.getLot(lotId);
        String eqptId = request.getParameter("eqptId");
        Equipment equipment = emsService.getEquipment(eqptId, LocalContext.getFacilityRrn());

        Assert.state(StringUtils.isBlank(lot.getBatchId()),
                     Errors.create().key(MessageIdList.LOT_IN_BATCH).content("Lot in batch!").build());

        String transId = "";

        RunCardLotInfo runCardLotInfo = runCardLotInqService.getRunCardLotInfo(lot.getLotRrn());
        LotRunCardStore lotStore = lotRunCardQueryService.getSplitRunCardLotStore(lot.getLotRrn());
        Long lotSpecialStepRrn = lotStore.getLotSpecialStepRrn();
        Integer stepSeq = lotStore.getStepSequence();
        SRCLotSpecialStep lotSpecialStep = lotRunCardQueryService
                .getLotSplitRunCardSpecialStep(lotSpecialStepRrn, stepSeq);
        if (lotSpecialStep != null) {
            if (StringUtils.isNotBlank(lot.getRecipeId())) {
                runCardLotInfo.setRecipeId(lot.getRecipeId());
                runCardLotInfo.setChamberType(lot.getChamberType());
            } else {
                Recipe recipe = recipeService.getRecipe(lotSpecialStep.getRecipeId(), LocalContext.getFacilityRrn());
                if (CheckRegexUtils.checkFlagOn(equipment.getIsChamberEquip()) &&
                        CheckRegexUtils.checkFlagOn(lotSpecialStep.getCheckRcp())) {
                    setRecipeDto(lot, equipment.getInstanceRrn(), recipe.getInstanceRrn());
                    runCardLotInfo.setRecipeId(lot.getRecipeId());
                    runCardLotInfo.setChamberType(lot.getChamberType());
                }
            }

            if (LotStatus.isMoveInCheckStatus(lot.getLotStatus())) {
                transId = "trackIn";
                lot.setRecipeId(lotSpecialStep.getRecipeId());
                List<Entity> chamberEntitieList = emsService.getChamberEntities(equipment.getInstanceRrn());
                StringBuilder piLotMsg = new StringBuilder();
                if (CollectionUtils.isNotEmpty(chamberEntitieList)) {
                    chamberEntitieList.forEach(chamberEntitie -> {
                        String msg = wipCheckService.checkEquipmentPiLot(lot, chamberEntitie.getInstanceRrn());
                        piLotMsg.append(msg);
                    });
                }
                Assert.state(StringUtils.isBlank(piLotMsg),
                               Errors.create().content(piLotMsg + I18nUtils.getMessage(MessageIdList.RECIPE_NO_CHAMBER)).build());

                String checkEqptAvailableMsg = wipCheckService
                        .checkAvailableEquipmentByRuncard(lot, equipment.getInstanceRrn(), LocalContext.getUserId());

                String flipTypeAvailable = StringUtils
                        .equalsIgnoreCase(lot.getFlipType(), lotSpecialStep.getFlipType())||StringUtils.equalsIgnoreCase(lot.getFlipType(),StringUtils.beforeFirst(lotSpecialStep.getFlipType(),'-')) ? StringUtils.EMPTY :
                        SystemConstant.Str.BR + I18nUtils.buildMessage(MessageIdList.LOT_FLOW_NOT_SAME,
                                                                       "Flip attribute {} of Lot {} is inconsistent " +
                                                                               "with Flip attribute {} of " +
                                                                               "corresponding work step on target " +
                                                                               "Flow!",
                                                                       lot.getFlipType(), lot.getLotId(),
                                                                       lotSpecialStep.getFlipType());

                checkEqptAvailableMsg += flipTypeAvailable;
                Assert.isFalse(StringUtils.isNotBlank(checkEqptAvailableMsg),
                               Errors.create().content(checkEqptAvailableMsg).build());

                List<Map<String, Object>> reticelInfos = new ArrayList<Map<String, Object>>();
                if (lotSpecialStep.getReticleRrn() != null && lotSpecialStep.getReticleRrn() > 0) {
                    reticelInfos.addAll(wipService.buildInuseReticleInfoList(lotSpecialStep.getReticleRrn()));
                } else if (lotSpecialStep.getReticleGroupRrn() != null && lotSpecialStep.getReticleGroupRrn() > 0) {
                    List<Relation> reticles = wipService
                            .getReticlesForMovein(lotSpecialStep.getReticleGroupRrn(), 0, false);
                    for (Relation relation : reticles) {
                        reticelInfos.addAll(wipService.buildInuseReticleInfoList(relation.getInstanceRrn()));
                    }
                }

                if (reticelInfos.size() > 0) {
                    List<Map<String, Object>> collect = reticelInfos.stream().
                            filter(map -> StringUtils.equals(MapUtils.getString(map, "entityLocation"), eqptId))
                                                                    .collect(Collectors.toList());
                    request.setAttribute("reticleIdList", collect);
                }
            } else if (LotStatus.isMoveOutCheckStatus(lot.getLotStatus())) {
                transId = "trackOut";
                if (lot.getReticleRrn() != null && lot.getReticleRrn().longValue() > 0) {
                    runCardLotInfo.setReticleId(getInstanceId(lot.getReticleRrn()));
                    runCardLotInfo.setReticleRrn(lot.getReticleRrn());
                }
                //#44941 Manual Move Out根据Certificate卡控权限
                Assert.state(StringUtils.isBlank(wipCheckService.checkEquipmentCertification(LocalContext.getUserId(),equipment.getInstanceRrn())),
                             Errors.create().key(MessageIdList.EQPT_NO_PERMISSION).content("The current user {} has no permission to operate the EQP {}!")
                                   .args(LocalContext.getUserId(), eqptId).build());

                //这里做一次设备状态卡控
                //这里的lot rrn 是 runcard 的lot rrn
                //按照系统业务,如果出站没有job对象 则说明有问题 这种异常应该直接甩出来
                //根据##45514要求,出站不再卡控机台状态
                //long jobRrn = wipQueryService.getJobRrn(lotStore.getLotRrn());
                //Job job = wipQueryService.getJob(jobRrn);
                //wipCheckService.checkEqptStateByJobMove(job, ActionPointList.MOVEOUT_KEY);
            }
        }
        request.setAttribute("lot", runCardLotInfo);
        request.setAttribute("eqptId", eqptId);
        request.setAttribute("transId", transId);

        return mapping.findForward("jobservice");
    }

    /**
     * Action 方法: getEdcPlanInfo
     **/
    public Map<String, Object> getEdcPlanInfo(HttpServletRequest request, HttpServletResponse response,
                                              Map<String, Object> params) {
        Map<String, Object> msg = MapUtils.newHashMap();

        String lotId = MapUtils.getString(params, "lotId");
        Lot lot = lotQueryService.getLot(lotId, LocalContext.getFacilityRrn());

        if (StringUtils.equals(LotStatus.RUNNINGHOLD, lot.getLotStatus())) {
            msg.put("returnLotInfo", "true");
            return msg;
        }

        LotRunCardStore lotStore = lotRunCardQueryService.getSplitRunCardLotStore(lot.getLotRrn());
        Long lotSpecialStepRrn = lotStore.getLotSpecialStepRrn();
        Integer stepSeq = lotStore.getStepSequence();
        SRCLotSpecialStep lotSpecialStep = lotRunCardQueryService
                .getLotSplitRunCardSpecialStep(lotSpecialStepRrn, stepSeq);

        if (lotSpecialStep.getParameterSetRrn() > 0 && request.getParameter("edcOver") == null) {
            Long parameterSetRrn = lotSpecialStep.getParameterSetRrn();
            List<LotRunCardStepParameter> stepParameter = lotRunCardQueryService
                    .getLotRunCardStepParameterList(lotStore.getRuncardRrn(),
                                                    NumberUtils.toInt(lotSpecialStep.getStepNo()), parameterSetRrn);
            List<Map<String, Object>> outParameters = new ArrayList<Map<String, Object>>();
            for (LotRunCardStepParameter parameter : stepParameter) {
                Map<String, Object> parameterMap = MapUtils.newHashMap();
                parameterMap.put("parameterId", getInstanceId(parameter.getParameterRrn()));
                parameterMap.put("parameterSize", parameter.getReadingPromptsSize());
                parameterMap.put("upperLimit", parameter.getUpperSpecificationLimit());
                parameterMap.put("lowerLimit", parameter.getLowerSpecificationLimit());
                outParameters.add(parameterMap);
            }
            msg.put("success", "true");
            msg.put("parameters", outParameters);

            //unitIdStr中的晶圆要和otSpecialStep.getMeasSlotId()中取交集
            List<String> newMeasSlotId = new ArrayList<String>();
            if (StringUtils.isNotEmptyTrim(lotSpecialStep.getUnitId())) {
                List<String> unitPos = Arrays.asList(StringUtils.split(lotSpecialStep.getUnitId(), ","));
                String[] measSlotId = StringUtils.split(lotSpecialStep.getMeasSlotId(), ",");
                for (String slotId : measSlotId) {
                    String substringAfter = "#" + StringUtils.substringAfter(slotId, "#");
                    if (unitPos.contains(substringAfter)) {
                        newMeasSlotId.add(slotId);
                    }
                }
            }

            msg.put("measSlotIds", StringUtils.collectionToCommaDelimitedString(newMeasSlotId));
            msg.put("measSlotId", newMeasSlotId);
        }
        return msg;
    }

    private LotInfoDto buildMoveOutLotInfoDto(Lot lot) {
        LotBaseInfoDto lotBaseInfoDto = new LotBaseInfoDto();
        lotBaseInfoDto.setLotId(lot.getLotId());
        lotBaseInfoDto.setLotRrn(lot.getLotRrn());
        lotBaseInfoDto.setTrackFlag(ActionPointList.MOVEOUT_KEY);

        LotInfoDto lotInfoDto = new LotInfoDto();
        lotInfoDto.setLotBaseInfo(lotBaseInfoDto);

        return lotInfoDto;
    }

    private void doTransMoveOut(Lot lot, Equipment equipment, SRCLotSpecialStep lotSpecialStep,
                                HttpServletRequest request) {

        LotInfoDto lotInfoDto = buildMoveOutLotInfoDto(lot);

        if (request.getParameter("edcOver") != null) {
            ParameterSetDto parameterSetDto = buildRunCardPatameterSetDto(lot, equipment, lotSpecialStep, request);
            if (Objects.nonNull(parameterSetDto)) {
                lotInfoDto.setParameterSet(parameterSetDto);
            }
        }

        List<Lot> lotInfos = new ArrayList<>();
        lotInfos.add(lot);
        List<LotInfoDto> lotInfoDtos = new ArrayList<>();
        lotInfoDtos.add(lotInfoDto);

        // check runcard outlimit
        String runCardOutLimitMsg = checkRunCardLotEdcInfo(lot, lotInfoDto);
        Assert.isFalse(StringUtils.isNotBlank(runCardOutLimitMsg), Errors.create().content(runCardOutLimitMsg).build());
        runCardExecService.dispatchLot(lotInfos, equipment, lotInfoDtos);
    }

    private ParameterSetDto buildRunCardPatameterSetDto(Lot lot, Equipment equipment, SRCLotSpecialStep lotSpecialStep,
                                                        HttpServletRequest request) {
        String[] parameterIds = request.getParameterValues("parameterIds");
        String measSlotIds = request.getParameter("measSlotIds");
        String[] unitIds = StringUtils.split(measSlotIds, StringUtils.COMMA_SIGN);

        List<ParameterDto> parameterDtoList = new ArrayList<ParameterDto>();
        for (String parameterId : parameterIds) {
            List<SampleDto> sampleDtoList = new ArrayList<>();
            for (int j = 0; j < unitIds.length; j++) {
                String unitId = unitIds[j];

                SampleDto sampleDto = new SampleDto();
                Unit unit = wipQueryService.getUnit(LocalContext.getFacilityRrn(), unitId);
                sampleDto.setPosition(unit.getPositionInCarrier().toString());

                String[] dataValues = request.getParameterValues(parameterId + unitId);
                if (dataValues != null) {
                    sampleDto.setReadingPromptSize(dataValues.length);

                    List<ReadingDto> readingDtoList = new ArrayList<>();
                    StringBuilder outLowerLimit = new StringBuilder();
                    StringBuilder outUpperLimit = new StringBuilder();
                    for (int k = 0; k < dataValues.length; k++) {

                        Assert.isTrue(NumberUtils.isNumber(dataValues[k]),
                                      Errors.create().content("Sample data have illegal characters").build());
                        ReadingDto readingDto = new ReadingDto();
                        readingDto.setDataValue(NumberUtils.toDouble(dataValues[k]));
                        readingDto.setReadingSequence(k + 1);
                        readingDtoList.add(readingDto);
                    }
                    sampleDto.setReadingPrompts(readingDtoList);
                }
                sampleDto.setSampleSequence(j + 1);
                sampleDto.setUnitId(unit.getUnitId());
                sampleDto.setUnitRrn(unit.getUnitRrn());
                sampleDtoList.add(sampleDto);
            }

            ParameterDto parameterDto = new ParameterDto();
            parameterDto.setParameterId(parameterId);
            parameterDto.setParameterRrn(
                    getInstanceRrn(parameterId, LocalContext.getFacilityRrn(), ObjectList.PARAMETER_KEY));
            parameterDto.setParameterSequence(sampleDtoList.size());
            parameterDto.setSamplePrompts(sampleDtoList);
            parameterDtoList.add(parameterDto);
        }

        ParameterSetDto parameterSetDto = new ParameterSetDto();
        parameterSetDto.setParameterSetRrn(lotSpecialStep.getParameterSetRrn());
        parameterSetDto.setParameters(parameterDtoList);
        return parameterSetDto;
    }

    private void holdLotWithOutLimit(String outLimitMsg, Lot lot) {
        if (StringUtils.isNotBlank(outLimitMsg.toString())) {
            TransReason transReason = new TransReason();
            transReason.setReasonCode(HoldCodeNames.RUNCARD_OUTLIMIT_KEY);
            transReason.setReason(outLimitMsg.toString());
            transReason.setTransQty1(lot.getQty1());
            transReason.setTransQty2(lot.getQty2());
            transReason.setResponsibility(WebUtils.getSystemUser().getInstanceId());
            HashMap<String, Object> holdInfo = MapUtils.newHashMap();
            holdInfo.put("lotRrn", lot.getLotRrn());
            holdInfo.put("lotId", lot.getLotId());
            holdInfo.put("lotStatus", lot.getLotStatus());
            holdInfo.put("transPerformedBy", WebUtils.getSystemUser().getInstanceId());
            holdInfo.put("holdPassword", "");
            holdInfo.put("transComments", "");
            holdInfo.put("operation", lot.getOperationId());
            holdInfo.put("holdcode", HoldCodeNames.RUNCARD_OUTLIMIT_KEY);
            holdInfo.put("transReason", transReason);
            lotService.holdRunningLot(holdInfo);
            throw new SystemIllegalArgumentException(Errors.create().content(outLimitMsg.toString()).build());
        }
    }

    private void doTransMoveIn(Lot lot, Equipment equipment, SRCLotSpecialStep lotSpecialStep,
                               HttpServletRequest request) {
        lot.setRecipeId(lotSpecialStep.getRecipeId());
        String checkEqptAvailableMsg = wipCheckService
                .checkAvailableEquipmentByRuncard(lot, equipment.getInstanceRrn(), LocalContext.getUserId());
        Assert.isFalse(StringUtils.isNotBlank(checkEqptAvailableMsg),
                       Errors.create().content(checkEqptAvailableMsg).build());

        Map entityExtMap = emsService.getEquipmentExtMap(equipment.getInstanceRrn());
        if (CheckRegexUtils.checkFlagOn(MapUtils.getString(entityExtMap, "isChamberEquip")) &&
                CheckRegexUtils.checkFlagOn(lotSpecialStep.getCheckRcp())) {
            setRecipeDto(lot, equipment.getInstanceRrn(),
                         getInstanceRrn(lotSpecialStep.getRecipeId(), LocalContext.getFacilityRrn(),
                                        ObjectList.RECIPE_KEY));
        } else {
            String recipeId = lotSpecialStep.getRecipeId();
            Recipe recipe = recipeService.getRecipe(recipeId, LocalContext.getFacilityRrn());
            Assert.state(recipe != null,
                         Errors.create().key(MessageIdList.DMM_RECIPE_NOT_EXIST).content("Recipe not exist").
                                 args(recipeId).build());
            Assert.state(recipe.getInstanceRrn() > 0, Errors.create().key(MessageIdList.DMM_RECIPE_NOT_EXIST).
                    args(recipeId).build());

            lot.setPpid(recipe.getInstanceId());
            lot.setRecipeId(recipe.getInstanceId());
            lot.setRecipeRrn(recipe.getInstanceRrn());
            lot.setRecipePhysicalId(recipe.getInstanceId());
            lot.setRecipeLogicalRrn(recipe.getInstanceRrn());
        }
        String errorMsg = wipCheckService.checkEquipmentAvailableForLotRecipe(lot, equipment);
        Assert.state(StringUtils.isBlank(errorMsg), Errors.create().content(errorMsg).build());

        LotInfoDto lotInfoDto = buildMoveInLotInfoDto(lot);

        String needReticleFlag = WebUtils.getParameter("needReticleFlag", request);
        if (StringUtils.isNotBlank(needReticleFlag)) {
            String reticleIdSelect = StringUtils.trimToUpperCase(request.getParameter("reticleIdSelect"));
            String reticleIdInput = StringUtils.trimToUpperCase(request.getParameter("reticleIdInput"));
            Assert.isTrue(StringUtils.isNotBlank(reticleIdSelect) && StringUtils.isNotBlank(reticleIdInput) &&
                                  StringUtils.equalsIgnoreCase(reticleIdSelect, reticleIdInput),
                          Errors.create().content("Input Reticle ID error,please check!").build());
            lotInfoDto.getLotBaseInfo().setReticleRequired(Boolean.TRUE);
            lotInfoDto.getLotBaseInfo().setReticleId(reticleIdInput);
        }

        List<Lot> lotInfos = new ArrayList<>();
        lotInfos.add(lot);
        List<LotInfoDto> lotInfoDtos = new ArrayList<LotInfoDto>();
        lotInfoDtos.add(lotInfoDto);

        carrierService.checkPcdInfo(lotInfos, ActionPointList.MOVEIN_KEY);
        //创建sorter job
        SorterModel sorterModel = checkSorterModelAndCreateInLineSorterJob(lot,equipment);
        if (SorterUtils.isInLineSorter(sorterModel.getSorterType())) {
            SorterUtils.anError(sorterModel.getMsg());
        }
        runCardExecService.dispatchLot(lotInfos, equipment, lotInfoDtos);
    }

    private LotInfoDto buildMoveInLotInfoDto(Lot lot) {
        LotBaseInfoDto lotBaseInfoDto = new LotBaseInfoDto();
        lotBaseInfoDto.setLotId(lot.getLotId());
        lotBaseInfoDto.setLotRrn(lot.getLotRrn());
        lotBaseInfoDto.setPpid(lot.getRecipeId());
        lotBaseInfoDto.setRecipeId(lot.getRecipeId());
        lotBaseInfoDto.setRecipeLogicalRrn(lot.getRecipeLogicalRrn());
        lotBaseInfoDto.setTrackFlag(ActionPointList.MOVEIN_KEY);

        LotInfoDto lotInfoDto = new LotInfoDto();
        lotInfoDto.setLotBaseInfo(lotBaseInfoDto);

        return lotInfoDto;
    }

    private void setRecipeDto(Lot lot, Long eqptRrn, Long logicRecipeRrn) {
        RecipeVersion recipeVersion = recipeService.getAvailableRecipeVersion(lot, eqptRrn, logicRecipeRrn);
        if (recipeVersion != null) {
            lot.setRecipeId(recipeVersion.getInstanceId());
            lot.setRecipePhysicalId(recipeVersion.getPpid());
            lot.setPpid(recipeVersion.getPpid());
            lot.setChamberType(recipeVersion.getChamberTypes());
            lot.setRecipeLogicalRrn(recipeVersion.getInstanceRrn());
        }
    }

    private String checkRunCardLotEdcInfo(Lot lot, LotInfoDto lotInfoDto) {

        ParameterSetDto parameterSetDto = lotInfoDto.getParameterSet();
        String errorMsg = runCardExecService.checkRunCardLotEdcInfo(lot, parameterSetDto);

        if (StringUtils.isNotBlank(errorMsg)) {
            holdLotWithOutLimit(errorMsg, lot);
        }

        return errorMsg;
    }

}