JobServiceAction.java

package com.mycim.webapp.actions.operation;

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.context.spring.SpringContext;
import com.mycim.framework.utils.beans.BeanUtils;
import com.mycim.framework.utils.beans.PropertyUtils;
import com.mycim.framework.utils.lang.BooleanUtils;
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.framework.workflow.engine.WorkflowEngineService;
import com.mycim.server.wip.service.LotDispatchService;
import com.mycim.utils.SorterUtils;
import com.mycim.utils.WflLinkContextSetupAttributeUtil;
import com.mycim.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.bas.ErrorMsg;
import com.mycim.valueobject.bas.NamedObject;
import com.mycim.valueobject.bas.ObjectVersion;
import com.mycim.valueobject.consts.*;
import com.mycim.valueobject.ems.Entity;
import com.mycim.valueobject.ems.Equipment;
import com.mycim.valueobject.prp.Operation;
import com.mycim.valueobject.prp.Recipe;
import com.mycim.valueobject.prp.RecipeVersion;
import com.mycim.valueobject.sorter.SorterModel;
import com.mycim.valueobject.wip.*;
import com.mycim.valueobject.wip.dto.LotBaseInfoDto;
import com.mycim.valueobject.wip.dto.LotInfoDto;
import com.mycim.webapp.Constants;
import com.mycim.webapp.WebUtils;
import com.mycim.webapp.actions.WipSetupAction;
import com.mycim.webapp.forms.JobInfoForm;
import com.mycim.webapp.forms.RootForm;
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 Johnson.Wang
 * @version 6.0.0
 * @date 2019/9/26
 **/
public class JobServiceAction extends WipSetupAction {

    protected LotDispatchService lotDispatchService = SpringContext.getBean(LotDispatchService.class);

    @Override
    public ActionForward perform(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                                 HttpServletResponse response) throws Exception {

        String operationRrn = "";
        String type = "";
        Job job = new Job();
        List<Map> lots = null;

        RootForm theform = (RootForm) form;

        String transId = theform.getTransId();
        if (StringUtils.isBlank(transId)) {
            transId = WebUtils.getParameter("trandId", request);
            if (StringUtils.isNotBlank(transId)) {
                theform.setTransId(transId);
            }
        }
        request.setAttribute("transId", theform.getTransId());
        String wfl_type = "MOVEIN";
        String handleType = TransactionNames.MOVEIN_KEY;

        if (request.getAttribute(SessionNames.RUNCARD_LOT_ID) == null) {
            String runcardLotId = request.getParameter(SessionNames.RUNCARD_LOT_ID);
            request.setAttribute(SessionNames.RUNCARD_LOT_ID, runcardLotId);
        }

        if (request.getParameter(SessionNames.OBJECT_TYPE_KEY) != null) {
            request.setAttribute("workflow_flag", "true");
            request.setAttribute("jobservice_flag", "true");
            if ("operation".equalsIgnoreCase(request.getParameter(SessionNames.OBJECT_TYPE_KEY))) {
                return mapping.findForward("jobmanagement4operation");
            } else if ("equipment".equalsIgnoreCase(request.getParameter(SessionNames.OBJECT_TYPE_KEY)) ||
                    (request.getAttribute(SessionNames.OBJECT_KEY) != null &&
                            request.getAttribute(SessionNames.OBJECT_KEY).equals("equipment"))) {
                return mapping.findForward("jobmanagement");
            } else {
                return mapping.findForward("jobmanagement4operation");
            }
        }

        // todo
        //
        //        if (StringUtils.isNotEmpty(WebUtils.getParameter("setReticleInfo", request))) {
        //            return setReticleInfo(mapping, form, request, response);
        //        }
        //
        //        if (StringUtils.isNotEmpty(WebUtils.getParameter("getChamber", request))) {
        //            job = (Job) request.getAttribute(SessionNames.JOB_KEY);
        //            lots = (Collection) request.getAttribute(SessionNames.COLLECTION_KEY);
        //            return semoAuto4Page(mapping, request, facilityRrn, job, lots, form);
        //        }
        //
        //        if (StringUtils.isNotEmpty(WebUtils.getParameter("setrecipe4unit", request))) {
        //            return setRecipe4Unit(mapping, form, request, response);
        //        }
        //
        //        if (StringUtils.isNotEmpty(WebUtils.getParameter("saveUnitRecipe", request))) {
        //            return saveUnitRecipe(mapping, form, request, response);
        //        }

        if (StringUtils.isNotEmpty(WebUtils.getParameter("semiAutoCancel", request))) {
            return mapping.findForward("viewlotlocation4CSEC");
        }

        if (request.getParameter(Constants.CANCEL_KEY) != null) {
            return cancel(mapping, form, request, response);
        }

        if ((request.getParameter(Constants.MOVEIN_KEY) != null) ||
                (request.getParameter(Constants.MOVEOUT_KEY) != null) ||
                (request.getParameter(Constants.ABORTJOB_KEY) != null)) {
            //            return move(mapping, theform, wfl_type, handleType, request, response);
            if (request.getParameter(Constants.MOVEIN_KEY) != null) {
                return moveIn(mapping, theform, request, response);
            }

            if (request.getParameter(Constants.MOVEOUT_KEY) != null) {
                return moveOut(mapping, theform, request, response);
            }


        } else if (StringUtils.isNotEmpty(WebUtils.getParameter("gonext", request))) {
            return gonext(mapping, request);
        } else if (request.getParameter(Constants.MEMBERS_KEY) != null) {
            String equipmentRrns = request.getParameter("avaliableEqtRrn");
            request.setAttribute("equipmentRrns", equipmentRrns);

            String j_flag = "true";
            Assert.isTrue(j_flag.equals(request.getAttribute("jobservice_flag")), Errors.create().content(
                    "Cannot submit " + "this form " + "out of " + "order,please" + " click cancel").build());
            request.setAttribute("jobservice_flag", "false");
            request.setAttribute("workflow_flag", "true");

            Map curjob = (Map) request.getAttribute("cur_job");
            type = request.getAttribute("type").toString();
            String jobRrn = curjob.get("jobRrn").toString();
            operationRrn = curjob.get("operationRrn").toString();
            String equipmentRrn = curjob.get("equipmentRrn").toString();
            String lotExecutionRrn = curjob.get("lotExecutionRrn").toString();
            String operationVersion = curjob.get("operationVersion").toString();
            String excutionRrn = "";
            if (curjob.get("executionRrn") != null) {
                excutionRrn = curjob.get("executionRrn").toString();
            }

            if (StringUtils.isNotEmptyTrim(jobRrn) && !StringUtils.isEqual(jobRrn, "0")) {
                Assert.isFalse(type.equals("") || lotExecutionRrn.equals("0") || operationRrn.equals("") ||
                                       operationVersion.equals("") || equipmentRrn.equals(""),
                               Errors.create().key(MessageIdList.SYSTEM_INVALID_PARAMETERS)
                                     .content("Invalid Parameters!").build());

                job = wipQueryService.getJob(Long.parseLong(jobRrn));

                // check if the job's execution_rrn is valid
                Long executionRrn = job.getExecutionRrn();
                if (job.getJobStatus().equals(JobStatus.RUNNING) && job.getTransExecutionId().equals("MOVEIN") &&
                        executionRrn != null && executionRrn > 0) {

                    boolean existFlag = wipWorkflowQueryService.isExistExecutionRrn(executionRrn);
                    if (!existFlag) {
                        wipService.clearUpExecutionInfo(job.getJobRrn());
                        job.setExecutionRrn(0L);
                    }

                }

                request.setAttribute(SessionNames.JOB_KEY, job);
            }

            // Step2: check if movout is needed(only when lot status is
            boolean moveInFlag = false;

            if (job.getJobRrn() <= 0) {
                job = (Job) request.getAttribute(SessionNames.JOB_KEY);
            }

            if (job.getJobStatus().equals(JobStatus.WAITING) || (job.getJobStatus().equals(JobStatus.HOLD) ||
                    job.getJobStatus().equals(JobStatus.RUNNING) &&
                            (Long.parseLong((excutionRrn).equals("") ? "0" : excutionRrn) > 0))) {
                moveInFlag = true;
            }

            Long _eventRrn = 0L;
            Long abortEventRrn = 0L;
            String _wflRrn = "0";
            String abortWflRrn = "0";
            Long _operationRrn = new Long(operationRrn);
            Integer _operationVersion = new Integer(operationVersion);

            Entity entity = new Entity();
            entity.setInstanceRrn(job.getEqptRrn());
            entity = emsService.getEntity(entity);
            if (moveInFlag) {
                if (StringUtils.equalsIgnoreCase(Constants.SEMI_AUTO_KEY, entity.getOperationMode())) {
                    _wflRrn = getWFLRrn(_operationRrn, "in", null);
                } else {
                    _wflRrn = getWFLRrn(_operationRrn, "in", null);
                }
                wfl_type = "MOVEIN";
            } else {
                if (StringUtils.equalsIgnoreCase(Constants.SEMI_AUTO_KEY, entity.getOperationMode())) {
                    _wflRrn = getWFLRrn(_operationRrn, "out", entity.getInstanceRrn());
                } else {
                    _wflRrn = getWFLRrn(_operationRrn, "out", entity.getInstanceRrn());
                }
                abortWflRrn = getWFLRrn(_operationRrn, "abort", null);
                wfl_type = "MOVEOUT";
            }

            HashMap parameters = new HashMap();

            parameters.put("eqptRrn", equipmentRrn);

            parameters.put("abortEventRrn", (abortEventRrn == null) ? "1" : abortEventRrn.toString());
            parameters.put("abortWflRrn", abortWflRrn);
            parameters.put("operationRrn", operationRrn);
            parameters.put("operationVersion", operationVersion);

            parameters.put("recipeRrn", job.getRecipeString());

            parameters.put(SessionNames.WFL_RRN, _wflRrn);

            parameters.put(SessionNames.RUNSTEP_FLAG, "1");
            parameters.put(SessionNames.ROOT_WFL_EXEC_RRN, lotExecutionRrn);
            parameters.put(SessionNames.PARENT_WFL_EXEC_RRN, "0");
            parameters.put(SessionNames.RUNPARENTSTEP_FLAG, "0");
            parameters.put(SessionNames.WFL_EXEC_RRN, ((excutionRrn).equals("") ? "0" : excutionRrn));

            request.setAttribute(SessionNames.PARAMETERSINFO_KEY, parameters);

            theform.setTransId(type);
            request.setAttribute(SessionNames.OBJECT_KEY, type);
            theform.setCacheObject(type);

            request.setAttribute(SessionNames.MOVEDISABLE_FLAG_KEY, "TRUE");
        } else if (request.getParameter("refreshSession") != null) {
            return refreshSession(request);
        } else if (StringUtils.isNotEmpty(request.getParameter("automovein")) &&
                StringUtils.isEmpty(request.getParameter("selectRecipeId_flag"))) {
            request.setAttribute("automovein", "automovein");
            // autoMove(mapping, theform, request, response);
            preAutoMove(mapping, theform, request, response);
        }

        JobInfoForm jobInfoForm = new JobInfoForm();
        job = (Job) request.getAttribute(SessionNames.JOB_KEY);
        if (job == null) {
            job = (Job) WebUtils.getCacheString2Obj(theform.getCacheJob());
            request.setAttribute(SessionNames.JOB_KEY, job);
        }
        PropertyUtils.copyProperties(jobInfoForm, job);
        request.setAttribute("jobInfoForm", jobInfoForm);
        lots = (List<Map>) request.getAttribute(SessionNames.COLLECTION_KEY);
        if (lots == null) {
            lots = (List<Map>) WebUtils.getCacheString2Obj(theform.getCacheCollection());
            request.setAttribute(SessionNames.COLLECTION_KEY, lots);
        }

        Assert.isFalse(lots == null || job == null, Errors.create().content("Parameters are not enough!").build());
        buildLotinfo(job, lots);

        HashMap _lot = null;
        int i = 1;
        int j = 1;
        String _carrierId = null;

        String _lotId = "";
        Long _operationRrn = job.getOperationRrn();
        if (_operationRrn != null) {
            if (StringUtils.isNotEmpty(operationRrn)) {
                _operationRrn = new Long(operationRrn);
            }
        }

        for (Iterator it = lots.iterator(); it.hasNext(); ) {

            _lot = (HashMap) it.next();
            _lot.put("isUniqueCarrierFlag", "1");

            if (_lot.get("jobRrn") == null || String.valueOf(_lot.get("jobRrn")).equals("0")) {
                _lot.put("jobRrn", job.getJobRrn() + "");
            } else if (Long.parseLong(String.valueOf(_lot.get("jobRrn"))) != job.getJobRrn()) {
                it.remove();
                j++;
            } else {
                if ((i == 1) || (i == j)) {
                    _carrierId = (String) _lot.get("carrierId");

                    _lotId = (String) _lot.get("lotId");
                } else {
                    if (_lot.get("carrierId").equals(_carrierId)) {
                        _lot.put("isUniqueCarrierFlag", "0");
                    } else {
                        _carrierId = (String) _lot.get("carrierId");
                    }
                }
                _lot = null;
                i++;
            }
        }
        if (StringUtils.equals(wfl_type, "MOVEIN") || StringUtils.equals(wfl_type, "MOVEOUT")) {
            int _index = 0;
            Long totalWaferQty = 0L;
            Iterator it = lots.iterator();
            while (it.hasNext()) {
                _lot = (HashMap) it.next();
                long qty = MapUtils.getDouble(_lot, "qty1").longValue();
                totalWaferQty += qty;
            }

            for (Iterator iterator = lots.iterator(); iterator.hasNext(); ) {
                _lot = (HashMap) iterator.next();
                setChildRecipe(request, _lot, totalWaferQty);
                replaceChildRecipeId(_lot);
                selectRecipeId(request, _lot, _index++);
            }
        }
        if (StringUtils.equals(wfl_type, "MOVEIN")) {
            List<Lot> lotList = new ArrayList<>();
            for (Map lot : lots) {
                Long lotRrn = MapUtils.getLong(lot, "lotRrn");
                if (lotRrn > 0) {
                    lotList.add(lotQueryService.getLot(lotRrn));
                }
            }
            //move out 时判断是否为byManual设置的multipath,如果是将路径传递下去
            boolean byManualFlag = wipCheckService.checkMultipathByManual(lotList);
            if (byManualFlag) {
                Assert.isTrue(NumberUtils.INTEGER_ONE.equals(lots.size()),
                              Errors.create().key(MessageIdList.MULTIPATH_BY_MANUAL_CHECK_LOT)
                                    .content("has a multipath set by manual.lot quantity can only be 1!").build());
            }
        }
        request.setAttribute("currentlots", lots);
        theform.setCacheCurrentlots(WebUtils.getCacheObj2String(lots));

        String edcBack = (String) request.getAttribute("edcback");

        if (!"edcback".equalsIgnoreCase(edcBack)) {
            if ("moveout".equalsIgnoreCase(request.getParameter(Constants.MEMBERS_KEY)) &&
                    job.getJobStatus().equals(JobStatus.RUNNING)) {

                boolean edcflg = false;
                HashMap edcCollect = new HashMap();
                // todo edc
                //                edcflg = this.getPrpManager().checkEdcNeed(_operationRrn);
                if (edcflg) {

                    edcCollect.put("objectType", type);
                    edcCollect.put("operationRrn", _operationRrn);
                    edcCollect.put("lotId", _lotId);
                    //session.setAttribute("edcCollect", edcCollect);
                    request.setAttribute("edcCollect", edcCollect);
                    return (mapping.findForward("edcCollect"));
                }
            }
        }
        //        Entity entity = new Entity();
        //        entity.setInstanceRrn(job.getEqptRrn());
        //        entity = emsService.getEntity(entity);
        String selectRecipeId_flag = request.getParameter("selectRecipeId_flag");
        if (StringUtils.equalsIgnoreCase(selectRecipeId_flag, "true")) {
            if (wipCheckService.checkEqupStatusForMove(job.getJobRrn(), job.getEqptRrn())) {
                request.setAttribute(SessionNames.MOVEDISABLE_FLAG_KEY, "TRUE");
                request.setAttribute("workflow_flag", "true");
                theform.setCacheCollection(WebUtils.getCacheObj2String(lots));
            } else {
                request.setAttribute(SessionNames.MOVEDISABLE_FLAG_KEY, "FALSE");
            }
        } else {
            setCache4WFL(request, theform);
        }
        return new ActionForward(mapping.getInput());
    }

    @Override
    public ActionForward cancel(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                                HttpServletResponse response) throws Exception {
        String lotId = WebUtils.getParameter("lotId", request);
        //批次作业出站,点击取消,删除lot lock
        // Lot lot = lotQueryService.getLot(lotId, LocalContext.getFacilityRrn());
        // if (StringUtils.equalsIgnoreCase(lot.getLotStatus(), LotStatus.RUNNING)) {
        // long userRrn = LocalContext.getUserRrn();
        // removeLotLock(userRrn, lot, TransactionNames.LOCK_MOVEOUT,
        //               "Cancel moveOut, in JobServiceAction by " + LocalContext.getUserId());
        // }
        request.getRequestDispatcher(mapping.findForward("jobmanagement4lot").getPath() + "&lotId=" + lotId)
               .forward(request, response);
        return null;
        //        return mapping.findForward("viewlotlocation4CSEC").;
    }

    /***
     * 根据所选recipe设置可用腔
     *
     * @param request
     * @param lotInfo
     * @param recipeId
     * @throws Exception
     */
    @Override
    public void setEnableChamberList(HttpServletRequest request, Map lotInfo, String recipeId) {

        if (StringUtils.isEmpty(recipeId)) {
            return;
        }
        Recipe recipe = recipeService.getRecipe(recipeId, LocalContext.getFacilityRrn());

        Collection versions = recipeService.getRecipeVersions(recipe.getInstanceRrn());
        if (versions.size() > 0) {
            ObjectVersion objectVersion = null;
            Iterator iterator = versions.iterator();
            while (iterator.hasNext()) {
                objectVersion = (ObjectVersion) iterator.next();
            }
            RecipeVersion recipeVersion = new RecipeVersion();
            recipeVersion.copyObjectVersion(objectVersion);
            recipeVersion = recipeService.getRecipeVersion(recipeVersion);
            recipeVersion.copyNamedObject(recipe);
            //Job job = (Job) session.getAttribute("job");
            Job job = (Job) request.getAttribute("job");
            List<String> enableChambers = new ArrayList<String>();
            StringBuffer chamberType = new StringBuffer();
            if (!StringUtils.isEmpty(recipeVersion.getChamberTypes())) {
                String[] recipeChambers = StringUtils.split(recipeVersion.getChamberTypes(),
                                                            RecipeVersion.CHAMBERSEPARATOR);
                for (String chamberKeys : recipeChambers) {
                    String[] c = chamberKeys.split(",");
                    // 所选可用腔组合一个不可用则这个组合不可用
                    boolean enable = true;
                    for (int a = 0; a < c.length; a++) {
                        Entity entity = emsService.getChildChamberEquip(job.getEqptRrn(), c[a]);
                        // 腔体设备存在 且enable log event
                        if (entity == null) {
                            enable = false;
                        }
                    }
                    if (enable) {
                        enableChambers.add(chamberKeys);
                        chamberType.append(chamberKeys);
                    }
                }

            }
            request.setAttribute("chamberJoin", chamberType.toString());
            lotInfo.put("chamberTypes", recipeService.getChamberTypes(enableChambers));

        }
    }

    public ActionForward moveIn(ActionMapping mapping, RootForm theform, HttpServletRequest request,
                                HttpServletResponse response) throws Exception {
        String wfl_type = "MOVEIN";
        String handleType = TransactionNames.MOVEIN_KEY;
        if (StringUtils.isNotEmptyTrim(request.getParameter("dojob"))) {
            // 将 批次作业 界面的操作和 批次派工作业 页面上的操作分开
            if (StringUtils.isEqual("automovein", request.getParameter("automovein"))) {
                // 批次派工作业 页面的操作
                handleAutoMoveJob(mapping, theform, request, response);
            } else if (StringUtils.isEqual("movein", request.getParameter(Constants.MOVEIN_KEY))) {
                // 批次作业 页面的操作
                request.setAttribute(Constants.MEMBERS_KEY, handleType);
                request.setAttribute("jobservice_flag", "true");
                request.setAttribute("type", "equipment");
                jobIn(request, theform);
            }

            validJob(theform, wfl_type, request);
            // auto move for extjs 2011.7.4 andy
            if ("automovein".equals(request.getParameter(Constants.MOVEIN_KEY)) ||
                    "automoveout".equals(request.getParameter(Constants.MOVEOUT_KEY))) {
                // check throw exception for forward error page
                if ("automovein".equals(request.getParameter(Constants.MOVEIN_KEY))) {
                    //session.setAttribute("automovein", "automovein");
                    request.setAttribute("automovein", "automovein");
                } else if ("automoveout".equals(request.getParameter(Constants.MOVEOUT_KEY))) {
                    //session.setAttribute("automoveout", "automoveout");
                    request.setAttribute("automoveout", "automoveout");
                }
                return autoMove(mapping, theform, request, response);
            }
        } else {
            String confirmQueueTime = request.getParameter("confirmQueueTime");

            if (!StringUtils.isNotEmptyTrim(request.getParameter("dojob"))) {
                if ("ConfirmQueueTime".equalsIgnoreCase(confirmQueueTime)) {

                } else {
                    String w_flag = "true";
                    Assert.isTrue(w_flag.equals(request.getParameter("workflow_flag")),
                                  Errors.create().key(MessageIdList.WORKFLOW_SUBMIT_OUT)
                                        .content("Cannot submit this form out of order,please click cancel").build());
                    request.setAttribute("workflow_flag", "false");
                }
            }
        }
        String equipmentRrns = request.getParameter("avaliableEqtRrn");
        request.setAttribute("equipmentRrns", equipmentRrns);

        Job job = (Job) request.getAttribute(SessionNames.JOB_KEY);
        if (job == null || job.getJobRrn() <= 0) {
            job = (Job) WebUtils.getCacheString2Obj(theform.getCacheJob());
        }
        request.setAttribute(SessionNames.JOB_KEY, job);
        List lots = (List) request.getAttribute(SessionNames.COLLECTION_KEY);
        if (CollectionUtils.isEmpty(lots)) {
            lots = (List) WebUtils.getCacheString2Obj(theform.getCacheCollection());
        }
        request.setAttribute(SessionNames.COLLECTION_KEY, lots);

        Assert.isFalse(job == null || lots == null, Errors.create().key(MessageIdList.EQUIPMENT_MISSING_PARAMETER)
                                                          .content("Parameters are not enough!").build());

        //若多lot进站必须满足在当前步都设置了post future hold  若不满足不允许同时进站
        wipCheckService.checkPostFHAndBond(lots);

        Entity parentEntity = emsService.getEntity(job.getEqptRrn());
        if (BooleanUtils.toBoolean(parentEntity.getIsChamberEquip()) &&
                StringUtils.isNotEmpty(parentEntity.getChamberMode())) {
            List<Map<String, Object>> recipes = recipeService.getRecipeList4Equipment(parentEntity.getInstanceRrn());
            Map<String, String> recipeMap = new HashMap<>(recipes.size());
            for (Map<String, Object> recipe : recipes) {
                recipeMap.put(MapUtils.getString(recipe, "recipeId"), MapUtils.getString(recipe, "status"));
            }
            int indexid = 0;
            for (Iterator it = lots.iterator(); it.hasNext(); indexid++) {
                Map lotInfo = (Map) it.next();
                String selectedRecipeId = request.getParameter("selectedRecipeId" + indexid);
                if (StringUtils.isNotEmpty(selectedRecipeId)) {
                    String lotId = request.getParameter("lotIdShow" + indexid);
                    if (StringUtils.equals(lotId, MapUtils.getString(lotInfo, "lotId"))) {
                        boolean isRecipeOk = true;
                        if ("SERIAL".equals(parentEntity.getChamberMode())) {
                            String recipeStatus = recipeMap.get(selectedRecipeId);
                            isRecipeOk = StringUtils.isNotBlank(recipeStatus) &&
                                    (StringUtils.equals("ON", recipeStatus) ||
                                            StringUtils.equals("EXIST", recipeStatus));
                        } else if ("PARALLEL".equals(parentEntity.getChamberMode())) {
                            String parentRecipe = MapUtils.getString(lotInfo, "recipeId");
                            String racipeNumber = StringUtils.removeStart(selectedRecipeId, parentRecipe + "-");
                            for (int i = 0; i < racipeNumber.length(); i++) {
                                String recipeStatus = recipeMap.get(parentRecipe + "-" + racipeNumber.charAt(i));
                                isRecipeOk = StringUtils.isNotBlank(recipeStatus) &&
                                        (StringUtils.equals("ON", recipeStatus) ||
                                                StringUtils.equals("EXIST", recipeStatus));
                                if (!isRecipeOk) {
                                    break;
                                }
                            }
                        }
                        if (!isRecipeOk) {
                            request.setAttribute("workflow_flag", "true");
                            throw new SystemIllegalArgumentException(Errors.create().key(MessageIdList.RECIPE_NOT_MATCH)
                                                                           .content("The available Recipe on the EQP " +
                                                                                            "does not match the " +
                                                                                            "recipe " +
                                                                                            "required on lot!")
                                                                           .build());
                        }
                    }
                }
            }
        }
        for (Iterator it = lots.iterator(); it.hasNext(); ) {
            Map lotInfo = (Map) it.next();
            Lot lot = lotQueryService.getLot(MapUtils.getLongValue(lotInfo, "lotRrn"));
            Equipment equipment = emsService.getEquipment(job.getEqptRrn());
            ErrorMsg errorMsg = constrainService.checkLotConstrain(equipment, lot);
            //需求40590,卡控,卡控内容:修改后的lot create category 必须与cassette create category保持一致
            Assert.isFalse(!StringUtils.equalsIgnoreCase(lot.getCreateCategory(),
                                                         carrierService.getCarrier(lot.getCarrierRrn()).getFlagType()),
                           Errors.create().key(MessageIdList.CARRIER_CATEGORY_IS_NOT_CONSISTENT).build());
            boolean overrideConstrain = wipCheckService.isOverrideConstrain(lot);
            if (overrideConstrain) {
                errorMsg.setError(false);
                errorMsg.setErrorMsg("OK");
            }
            Assert.isFalse(errorMsg.getError(), Errors.create().content(errorMsg.getErrorMsg()).build());
        }
        // 2.2reconstruct lots to show reticle combo box
        buildLotinfo(job, lots);

        HashMap parameters = (HashMap) request.getAttribute(SessionNames.PARAMETERSINFO_KEY);
        if (MapUtils.isEmpty(parameters)) {
            parameters = (HashMap) WebUtils.getCacheString2Obj(theform.getCacheParametersInfo());
        }

        // step2: update parameters info if abort is needed

        if (request.getParameter(Constants.ABORTJOB_KEY) != null) {
            parameters.put(SessionNames.WFL_RRN, parameters.get("abortWflRrn"));
        }

        // step3: create execution rrn if execution does not exist
        request.setAttribute(SessionNames.PROCESS_NEXT_STEP_INFO_KEY, lots);
        request.setAttribute(SessionNames.PARAMETERSINFO_KEY, parameters);
        request.setAttribute(SessionNames.JOB_KEY, job);
        int i = 0;
        for (Iterator it = lots.iterator(); it.hasNext(); ) {
            HashMap item = (HashMap) it.next();
            request.setAttribute("reticleString" + i, item.get("reticleString" + i));
            i++;
        }

        // step3: call workflow engine
        if (StringUtils.isNotEmptyTrim(request.getParameter("dojob"))) {
            parameters.put("showReticleRrn", request.getParameter("showReticleRrn"));
            parameters.put("reticleRrn", request.getParameter("reticleRrn"));
            parameters.put("recipeId", request.getParameter("recipeId"));
            parameters.put("recipeIds", request.getParameterValues("recipeId"));
            parameters.put("chamberJoin", request.getParameter("chamberJoin"));
            parameters.put("lotIdShow", request.getParameterValues("lotIdShow"));
            parameters.put("avaliableEqtRrn", request.getParameter("avaliableEqtRrn"));
            parameters.put(Constants.OK_KEY, "movein");
            request.getRequestDispatcher("WFLEngine").forward(request, response);
            return null;
        } else {
            request.setAttribute(Constants.MOVEIN_KEY, request.getParameter(Constants.MOVEIN_KEY));
            return mapping.findForward("movein");
        }
    }


    public ActionForward moveOut(ActionMapping mapping, RootForm theform, HttpServletRequest request,
                                 HttpServletResponse response) throws Exception {
        String wfl_type = "MOVEOUT";
        String handleType = TransactionNames.MOVEOUT_KEY;
        return move(mapping, theform, wfl_type, handleType, request, response);
    }

    public ActionForward move(ActionMapping mapping, RootForm theform, String wfl_type, String handleType,
                              HttpServletRequest request, HttpServletResponse response) throws Exception {
        String equipmentRrns = request.getParameter("avaliableEqtRrn");
        request.setAttribute("equipmentRrns", equipmentRrns);

        if (request.getParameter(Constants.MOVEIN_KEY) != null) {
            Job job = (Job) request.getAttribute(SessionNames.JOB_KEY);
            if (job == null) {
                job = (Job) WebUtils.getCacheString2Obj(theform.getCacheJob());
                request.setAttribute(SessionNames.JOB_KEY, job);
            }
            long _jobrrn = -1;
            _jobrrn = (request.getParameter("jobRrn") != null) ? Long.parseLong(request.getParameter("jobRrn")) :
                    job == null ? -1 : job.getJobRrn();
            if (_jobrrn > 0) {
                job = wipQueryService.getJob(_jobrrn);
            }
            Assert.isFalse(job == null,
                           Errors.create().key(MessageIdList.JOB_MISSING).content("job不存在!请关闭当前tab页面重新创建!").build());
            Long eqptRrn = job.getEqptRrn();

            // todo pm
            //            if (validateEqptPmOvertime(eqptRrn.longValue(), facilityRrn)) {
            //                if (StringUtils.equalsIgnoreCase("CN", language)) {
            //                    request.setAttribute(ErrorDef.MYCIM_ERR_KEY,
            //                                         new ValidateFailureException("当前设备PM有超时,不能进站!"));
            //                } else {
            //                    request.setAttribute(ErrorDef.MYCIM_ERR_KEY, new ValidateFailureException(
            //                            "The current EQP's PM is timeout, so it can't move in!"));
            //                }
            //                return (mapping.findForward("error"));
            //            }
        }

        // auto move for extjs 2011.7.4 andy
        if ("automovein".equals(request.getParameter(Constants.MOVEIN_KEY)) ||
                "automoveout".equals(request.getParameter(Constants.MOVEOUT_KEY))) {
            // check throw exception for forward error page
            if ("automovein".equals(request.getParameter(Constants.MOVEIN_KEY))) {
                //session.setAttribute("automovein", "automovein");
                request.setAttribute("automovein", "automovein");
            } else if ("automoveout".equals(request.getParameter(Constants.MOVEOUT_KEY))) {
                //session.setAttribute("automoveout", "automoveout");
                request.setAttribute("automoveout", "automoveout");
            }
            return autoMove(mapping, theform, request, response);
        }

        String confirmQueueTime = request.getParameter("confirmQueueTime");

        if ("ConfirmQueueTime".equalsIgnoreCase(confirmQueueTime)) {

        } else {
            // add by fan
            String w_flag = "true";
            Assert.isTrue(w_flag.equals(request.getParameter("workflow_flag")),
                          Errors.create().key(MessageIdList.WORKFLOW_SUBMIT_OUT)
                                .content("Cannot submit " + "this form out " + "of order," + "please click " + "cancel")
                                .build());
            request.setAttribute("workflow_flag", "false");

        }
        Job job = (Job) WebUtils.getCacheString2Obj(theform.getCacheJob());
        request.setAttribute(SessionNames.JOB_KEY, job);

        List lots = (List) WebUtils.getCacheString2Obj(theform.getCacheCollection());
        request.setAttribute(SessionNames.COLLECTION_KEY, lots);
        Assert.isFalse(job == null || lots == null,
                       Errors.create().key(MessageIdList.SYSTEM_MISSING_PARAMETER).content("Parameters are not enough!")
                             .build());
        if (StringUtils.equals(wfl_type, "MOVEIN")) {
            //    Equipment equipment    = emsService.getEquipment(job.getEqptRrn());
            Entity parentEntity = emsService.getEntity(job.getEqptRrn());
            if (BooleanUtils.toBoolean(parentEntity.getIsChamberEquip()) &&
                    StringUtils.isNotEmpty(parentEntity.getChamberMode())) {
                List<Map<String, Object>> recipes = recipeService.getRecipeList4Equipment(
                        parentEntity.getInstanceRrn());
                Map<String, String> recipeMap = new HashMap<>(recipes.size());
                for (Map<String, Object> recipe : recipes) {
                    recipeMap.put(MapUtils.getString(recipe, "recipeId"), MapUtils.getString(recipe, "status"));
                }
                int indexid = 0;
                for (Iterator it = lots.iterator(); it.hasNext(); indexid++) {
                    Map lotInfo = (Map) it.next();
                    String selectedRecipeId = request.getParameter("selectedRecipeId" + indexid);
                    if (StringUtils.isNotEmpty(selectedRecipeId)) {
                        String lotId = request.getParameter("lotIdShow" + indexid);
                        if (StringUtils.equals(lotId, MapUtils.getString(lotInfo, "lotId"))) {
                            boolean isRecipeOk = true;
                            if ("SERIAL".equals(parentEntity.getChamberMode())) {
                                String recipeStatus = recipeMap.get(selectedRecipeId);
                                isRecipeOk = StringUtils.isNotBlank(recipeStatus) &&
                                        (StringUtils.equals("ON", recipeStatus) ||
                                                StringUtils.equals("EXIST", recipeStatus));
                            } else if ("PARALLEL".equals(parentEntity.getChamberMode())) {
                                String parentRecipe = MapUtils.getString(lotInfo, "recipeId");
                                String racipeNumber = StringUtils.removeStart(selectedRecipeId, parentRecipe + "-");
                                for (int i = 0; i < racipeNumber.length(); i++) {
                                    String recipeStatus = recipeMap.get(parentRecipe + "-" + racipeNumber.charAt(i));
                                    isRecipeOk = StringUtils.isNotBlank(recipeStatus) &&
                                            (StringUtils.equals("ON", recipeStatus) ||
                                                    StringUtils.equals("EXIST", recipeStatus));
                                    if (!isRecipeOk) {
                                        break;
                                    }
                                }
                            }
                            if (!isRecipeOk) {
                                request.setAttribute("workflow_flag", "true");
                                throw new SystemIllegalArgumentException(
                                        Errors.create().key(MessageIdList.RECIPE_NOT_MATCH).content(
                                                "The available Recipe on" + " " + "the EQP does not " +
                                                        "match the recipe " + "required on lot!").build());
                            }
                        }
                    }
                }
            }
        } else if (StringUtils.equals(wfl_type, "MOVEOUT")) {
            List<Lot> lotsByJobRrn = lotQueryService.getLotsByJobRrn(job.getJobRrn());
            Assert.isFalse(lots.size() != lotsByJobRrn.size(), Errors.create().key(MessageIdList.LOT_MOVEOUT_TOGETHER)
                                                                     .content("If Lot move in together, it must " +
                                                                                      "move out together!").build());
            //move out 时判断是否为byManual设置的multipath,如果是将路径传递下去
            boolean byManualFlag = wipCheckService.checkMultipathByManual(lotsByJobRrn);
            if (byManualFlag) {
                Assert.isTrue(NumberUtils.INTEGER_ONE.equals(lots.size()),
                              Errors.create().key(MessageIdList.MULTIPATH_BY_MANUAL_CHECK_LOT)
                                    .content("has a multipath set by manual.lot quantity can only be 1!").build());
                Lot multipathLot = lotQueryService.getLot(lotsByJobRrn.get(0).getLotRrn());
                List<Map<String, Object>> wflPathoperation = super.getWflPathoperation(multipathLot);
                List<Map<String, Object>> wflPathRoute = super.getWflPathRoute(multipathLot);
                if (wflPathoperation.size() > 1) {
                    request.setAttribute(WflLinkContextSetupAttributeUtil.MANUAL_OPERATION, wflPathoperation);
                    request.setAttribute("byManualStepFlag", "true");
                }
                if (wflPathRoute.size() > 1 &&
                        wipCheckService.checkOperationIsLastOperationInRoute(multipathLot.getWflStepPath(),
                                                                             multipathLot.getProcessRrn(),
                                                                             multipathLot.getProcessVersion())) {
                    request.setAttribute(WflLinkContextSetupAttributeUtil.MANUAL_ROUTE, wflPathRoute);
                    request.setAttribute("byManualRouteFlag", "true");
                }
            }

            boolean holdFlag = lotService.handleRunningHoldWithMultiPath(job.getJobRrn(), MultiPathCheckType.SETUP);
            if (holdFlag) {
                return super.showRunningHoldInfoDetail(mapping, request, job.getJobRrn());
            }

            //AUTO跳转至DispatchService执行
            //处理AUTO出站未完成的情况。已经有了job和excutionRrn,判断一下,此job是否来自AUTO
            if (checkIsAutoMoveOut(job, job.getExecutionRrn())) {
                //Auto操作
                List<Lot> jobLotList = lotQueryService.getLotsByJobRrn(job.getJobRrn());
                Equipment equipment = new Equipment(job.getEqptId(),
                                                    getNamedSpace(ObjectList.ENTITY_KEY, LocalContext.getFacilityRrn()),
                                                    ObjectList.ENTITY_KEY);

                List<Lot> lotInfos = new ArrayList<>();
                List<LotInfoDto> lotInfoDtos = new ArrayList<>();
                List<String> lotRrns = new ArrayList<>();
                for (Lot lotBaseInfoDto : jobLotList) {
                    Lot lot = lotQueryService.getLot(lotBaseInfoDto.getLotId(), LocalContext.getFacilityRrn());
                    LotInfoDto lotInfoDto = new LotInfoDto();
                    LotBaseInfoDto baseDto = new LotBaseInfoDto();
                    baseDto.setLotId(lot.getLotId());
                    baseDto.setLotRrn(lot.getLotRrn());
                    baseDto.setCarrierId(lot.getCarrierId());
                    baseDto.setOutCarrierId(lotBaseInfoDto.getCarrierId());
                    baseDto.setPpid(lot.getPpid());
                    baseDto.setRecipeId(lot.getRecipeId());
                    baseDto.setRecipeLogicalRrn(lot.getRecipeLogicalRrn());
                    baseDto.setChamberType(lot.getChamberType());
                    baseDto.setReticleId(lot.getReticleId());
                    baseDto.setReticleRrn(lot.getReticleRrn());
                    baseDto.setTrackFlag(ActionPointList.MOVEOUT_KEY);
                    baseDto.setManualFlag(Boolean.TRUE);
                    lotInfoDto.setLotBaseInfo(baseDto);

                    lotInfos.add(lot);
                    lotInfoDtos.add(lotInfoDto);
                    lotRrns.add(StringUtils.toString(lot.getLotRrn()));
                }

                lotDispatchService.dispatchLot(lotInfos, equipment, lotInfoDtos, lotRrns);

                //处理完以后的跳转
                String moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "out", job.getEqptRrn());
                List<Map> nextLots = new ArrayList<>();
                for (Lot l : jobLotList) {
                    Lot lot = lotQueryService.getLot(l.getLotRrn());
                    Map lotInfo = new HashMap();
                    lotInfo.put("lotId", lot.getLotId());
                    lotInfo.put("lotRrn", lot.getLotRrn());
                    lotInfo.put("productId", lot.getProductId());
                    lotInfo.put("processId", lot.getProcessId());
                    lotInfo.put("lotStatus", lot.getLotStatus());
                    lotInfo.put("stageId", lot.getStageId());
                    lotInfo.put("operationId", lot.getOperationId());
                    lotInfo.put("operationDesc", lot.getOperationDesc());
                    lotInfo.put("recipeId", lot.getRecipeId());
                    try {
                        lotInfo.put("recipePhysicalId", getRecipePhysicalId(lot));
                    } catch (Exception e) {
                        lotInfo.put("recipePhysicalId", "");
                    }
                    lotInfo.put("qty1", lot.getQty1());
                    nextLots.add(lotInfo);
                }

                request.setAttribute(SessionNames.PROCESS_NEXT_STEP_INFO_KEY, nextLots);
                request.setAttribute(SessionNames.JOB_KEY, job);
                request.setAttribute(SessionNames.PARAMETERSINFO_KEY, new HashMap<>());
                request.getRequestDispatcher("/wflendaction.do?WFL_RRN=" + moveoutWflRrn + "&WFL_TYPE=")
                       .forward(request, response);
                return null;
            }

        }

        if (request.getParameter(Constants.MOVEIN_KEY) != null) {
            wipCheckService.validJobSize(job);
        }

        // 2.2reconstruct lots to show reticle combo box
        buildLotinfo(job, lots);

        Object parametersObj = WebUtils.getCacheString2Obj(theform.getCacheParametersInfo());
        HashMap parameters = null;
        if (parametersObj instanceof HashMap) {
            parameters = (HashMap) WebUtils.getCacheString2Obj(theform.getCacheParametersInfo());
        }
        Assert.isFalse(parameters == null,
                       Errors.create().key(MessageIdList.LOT_LOT_PARAMETER_ERROR).content("Class case is not Map")
                             .build());

        parameters.put("comments", request.getParameter("comments"));
        parameters.put("jobRrn", job.getJobRrn() + "");
        parameters.put("AttributeValue", job.getOperationRrn().toString() + "." + job.getEqptRrn().toString());


        parameters.put("lotRrns", getLotRrns(lotQueryService.getLotsByJobRrn(job.getJobRrn())));

        // step2: update parameters info if abort is needed

        String copy_wfl_rrn = (String) parameters.get(SessionNames.WFL_RRN);

        if (request.getParameter(Constants.ABORTJOB_KEY) != null) {
            parameters.put(SessionNames.WFL_RRN, parameters.get("abortWflRrn"));
        }

        Long _test_excutionRrn = new Long((String) parameters.get(SessionNames.WFL_EXEC_RRN));

        boolean existFlag = false;

        // set the wfl_type by yunsong 2008-4-17
        String lockType = TransactionNames.LOCK_MOVEIN;
        if (request.getParameter(Constants.MOVEIN_KEY) != null) {
            wfl_type = "MOVEIN";
            lockType = TransactionNames.LOCK_MOVEIN;
        }
        if (request.getParameter(Constants.MOVEOUT_KEY) != null) {
            wfl_type = "MOVEOUT";
            lockType = TransactionNames.LOCK_MOVEOUT;
        }
        if (request.getParameter(Constants.ABORTJOB_KEY) != null) {
            wfl_type = "ABORT";
            lockType = TransactionNames.LOCK_ABOUT;
        }

        if (_test_excutionRrn.longValue() > 0) {
            existFlag = wipWorkflowQueryService.isExistExecutionRrn(_test_excutionRrn);
            Entity entity = new Entity();
            entity.setInstanceRrn(job.getEqptRrn());
            entity = emsService.getEntity(entity);
            if (!existFlag && "ABORT".equalsIgnoreCase(job.getTransExecutionId())) {
                String abortWflRrn = getWFLRrn(job.getOperationRrn(), "abort", null);
                parameters.put(SessionNames.WFL_RRN, abortWflRrn);
                parameters.put(SessionNames.WFL_EXEC_RRN, "0"); // if the execution does not exist, set it to 0,
                // add by yunsong 2008-4-18
                wfl_type = "ABORT";
                handleType = TransactionNames.ABORT_KEY;
                lockType = TransactionNames.LOCK_ABOUT;
            }
            // add move out/move in, add by yunsong 2008-4-17
            if (!existFlag && "MOVEOUT".equalsIgnoreCase(job.getTransExecutionId())) {
                String moveoutWflRrn = "";
                if (StringUtils.equalsIgnoreCase(Constants.SEMI_AUTO_KEY, entity.getOperationMode())) {
                    // moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "wsout");
                    moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "out", entity.getInstanceRrn());
                } else {
                    moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "out", entity.getInstanceRrn());
                }
                parameters.put(SessionNames.WFL_RRN, moveoutWflRrn);
                parameters.put(SessionNames.WFL_EXEC_RRN, "0"); // if the execution does not exist, set it to 0,
                // add by yunsong 2008-4-18
                wfl_type = "MOVEOUT";
                handleType = TransactionNames.MOVEOUT_KEY;
                lockType = TransactionNames.LOCK_MOVEOUT;
            }

            if (!existFlag && "MOVEIN".equalsIgnoreCase(job.getTransExecutionId())) {
                String moveoutWflRrn = "";
                if (StringUtils.equalsIgnoreCase(Constants.SEMI_AUTO_KEY, entity.getOperationMode())) {
                    // moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "wsin");
                    moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "in", null);
                } else {
                    moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "in", null);
                }
                parameters.put(SessionNames.WFL_RRN, moveoutWflRrn);
                parameters.put(SessionNames.WFL_EXEC_RRN, "0"); // if the execution does not exist, set it to 0,
                // add by yunsong 2008-4-18
                wfl_type = "MOVEIN";
                handleType = TransactionNames.MOVEIN_KEY;
                lockType = TransactionNames.LOCK_MOVEIN;
            }

        }
        //检查是否有lot lock
        List<Lot> lockLots = new ArrayList<>();
        long userRrn = LocalContext.getUserRrn();
        for (Iterator it = lots.iterator(); it.hasNext(); ) {
            Map lotInfo = (Map) it.next();
            Lot lot = lotQueryService.getLot(MapUtils.getString(lotInfo, "lotId"), LocalContext.getFacilityRrn());
            lockLots.add(lot);
        }
        //        checkAndCreateLotsTransLock(userRrn, lockType, lockLots, handleType
        //                                                                 + " in JobServiceAction by: " +
        //                                                                 LocalContext.getUserId());

        // step3: create execution rrn if execution does not exist
        if (parameters.get(SessionNames.WFL_EXEC_RRN).equals("") ||
                parameters.get(SessionNames.WFL_EXEC_RRN).equals("0")) {
            long _workflowRrn = MapUtils.getLongValue(parameters, SessionNames.WFL_RRN);
            if (_workflowRrn <= 0) {
                parameters.put(SessionNames.WFL_RRN, copy_wfl_rrn);

                throw new SystemIllegalArgumentException(
                        Errors.create().key(MessageIdList.WORKFLOW_INVALID_ROUTINE_STEP_IN_THIS_STEP)
                              .content("Invalid workflow routine setup in this " + "step.").build());
            }

            String _multiRootInstanceRrn = (String) parameters.get(SessionNames.ROOT_WFL_EXEC_RRN);
            long _parentInstanceRrn = MapUtils.getLongValue(parameters, SessionNames.PARENT_WFL_EXEC_RRN);

            long executionRrn = -1;

            WorkflowEngineService workflowEngineService = SpringContext.getBean(WorkflowEngineService.class);

            executionRrn = workflowEngineService.createExecutionRrn(_workflowRrn, _multiRootInstanceRrn,
                                                                    _parentInstanceRrn, null, parameters);

            wipService.maintainExecutionRrn(job.getJobRrn(), executionRrn, wfl_type);

            parameters.put(SessionNames.WFL_EXEC_RRN, executionRrn + "");
        }
        request.setAttribute(SessionNames.PROCESS_NEXT_STEP_INFO_KEY, lots);
        request.setAttribute(SessionNames.PARAMETERSINFO_KEY, parameters);
        request.setAttribute(SessionNames.JOB_KEY, job);
        request.setAttribute("runcardLotId", request.getParameter("runcardLotId"));
        int i = 0;
        for (Iterator it = lots.iterator(); it.hasNext(); ) {
            HashMap item = (HashMap) it.next();
            request.setAttribute("reticleString" + i, item.get("reticleString" + i));
            i++;
        }

        // step3: call workflow engine
        request.getRequestDispatcher("WFLEngine").forward(request, response);
        //return (mapping.findForward("workflow"));
        return null;

    }

    public ActionForward viewRecipe(HttpServletRequest request, ActionMapping mapping, ActionForm form) {
        String lotList = request.getParameter("lotList");
        String[] lotRrns = lotList.split("#");
        Assert.isTrue(lotRrns.length > 0,
                      Errors.create().key(MessageIdList.LOT_EMPTY).content("Lot can't be empty!").build());

        Lot lot = lotQueryService.getLot(new Long(lotRrns[0]));
        Long jobRrn = lot.getJobRrn();
        Job job = wipQueryService.getJob(jobRrn);
        request.setAttribute(SessionNames.JOB_KEY, job);
        boolean viewFlag = true;
        for (int i = 1; i < lotRrns.length; i++) {
            Lot _lot = lotQueryService.getLot(new Long(lotRrns[i]));
            Long _jobRrn = _lot.getJobRrn();
            if (!jobRrn.equals(_jobRrn) && jobRrn > 0) {
                viewFlag = false;
                break;
            }
            Assert.isTrue(diffBatchQueryService.checkLotInBatch(_lot.getLotRrn()),
                          Errors.create().content("Lot:{} not in batch").args(_lot.getLotId()).build());
        }
        Assert.isTrue(viewFlag, Errors.create().key(MessageIdList.LOT_JOBS_ERROR).content("Lot's Job error!").build());
        List lots = new ArrayList();
        if (jobRrn > 0) {
            Collection jobList = wipQueryService.getJobList(new Long(jobRrn), ObjectList.JOB_KEY);
            for (Iterator it = jobList.iterator(); it.hasNext(); ) {
                Map lotInfo = (Map) it.next();
            }
            for (Iterator it = jobList.iterator(); it.hasNext(); ) {
                Map lotInfo = (Map) it.next();
                Lot _lot = lotQueryService.getLot(MapUtils.getLongValue(lotInfo, "lotRrn"));
                buildRecipeId(_lot);
                String lotCategoryStr = sysService.getRefFileValue("$LOT_CREATE_CATEGORY", _lot.getCreateCategory(),
                                                                   ReferenceFileConst.DATA_1_VALUE);
                _lot.setCreateCategory(lotCategoryStr);
                lots.add(BeanUtils.copyBeanToMap(_lot));
            }
        } else {
            for (int i = 0; i < lotRrns.length; i++) {
                List<BatchLotStore> bondList = diffBatchQueryService.getBatchStoreListByLot(
                        NumberUtils.toLong(lotRrns[i]));
                for (BatchLotStore bond : bondList) {
                    Lot _lot = lotQueryService.getLot(bond.getLotRrn());
                    buildRecipeId(_lot);
                    String lotCategoryStr = sysService.getRefFileValue("$LOT_CREATE_CATEGORY", _lot.getCreateCategory(),
                                                                       ReferenceFileConst.DATA_1_VALUE);
                    _lot.setCreateCategory(lotCategoryStr);
                    lots.add(BeanUtils.copyBeanToMap(_lot));
                }
            }
        }

        request.setAttribute("viewBatch", "viewBatch");
        request.setAttribute(SessionNames.COLLECTION_KEY, lots);
        request.setAttribute("automovein", "automovein");
        return semoAuto4Page(mapping, request, job, lots, form);
    }

    public Lot getMonitorLot(ActionMapping mapping, RootForm form, HttpServletRequest request,
                             HttpServletResponse response) {
        String lotId = request.getParameter("monitorLotId");
        Lot lot = lotQueryService.getLot(lotId, LocalContext.getFacilityRrn());

        long eqptRrn = NumberUtils.toLong(request.getParameter("eqptRrn"));
        long recipeRrn = NumberUtils.toLong(request.getParameter("recipeRrn"));

        Assert.isFalse(lot == null, Errors.create().content("LotId error!").build());

        Assert.isTrue(checkLotIsMonitorLot(lot), Errors.create().content("Not is a monitor lot!").build());

        Assert.isFalse(diffBatchQueryService.checkLotInBatch(lot.getLotRrn()),
                       Errors.create().content("Lot:{} had batch").args(lot.getLotId()).build());

        List<EqpRcpDiffBatchSetupInfo> recipeSetList = diffBatchQueryService.getEqpRecipeDiffBatchSet(eqptRrn);
        Integer limitCount = 0;
        for (EqpRcpDiffBatchSetupInfo recipeSet : recipeSetList) {
            if (recipeRrn == recipeSet.getRecipeRrn().longValue()) {
                limitCount = recipeSet.getMonitorLimit();
            }
        }

        Assert.isFalse(lot.getInt_qty1().intValue() < limitCount.intValue(),
                       Errors.create().content("Monitor lot qty are less" + " than {}").args(limitCount).build());

        String lotCategoryStr = sysService.getRefFileValue("$LOT_CREATE_CATEGORY", lot.getCreateCategory(),
                                                           ReferenceFileConst.DATA_1_VALUE);
        lot.setCreateCategory(lotCategoryStr);

        return lot;
    }

    public ActionForward refreshSession(HttpServletRequest request) {
        request.removeAttribute(SessionNames.PARAMETERSINFO_KEY);
        request.removeAttribute(SessionNames.COLLECTION_KEY);
        request.removeAttribute("currentlots");
        request.removeAttribute(SessionNames.JOB_KEY);
        request.removeAttribute("automovein");
        request.removeAttribute("automoveout");
        request.removeAttribute("operate_panel");
        return WebUtils.NULLActionForward;
    }

    private boolean checkIsAutoMoveOut(Job job, Long excutionRrn) {
        if ("MOVEOUT".equals(job.getTransExecutionId()) && excutionRrn > 0) {
            //卡控AUTO出站失败,已经有了job和excutionRrn,判断一下,此job来自AUTO还是来自MANUAL
            List<String> methodIdList = wipWorkflowQueryService.getMethodIdListByExecutionRrn(excutionRrn);
            if (CollectionUtils.isNotEmpty(methodIdList)) {
                for (String s : methodIdList) {
                    if (s.contains("#$#")) { //Auto操作
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private ActionForward gonext(ActionMapping mapping, HttpServletRequest request) {
        String _userName = StringUtils.trimToUpperCase(request.getParameter("userId"));
        String _password = StringUtils.trim(request.getParameter("password"));
        _password = StringUtils.encodeByMD5(_password);

        long userRrn = getInstanceRrn(_userName, LocalContext.getFacilityRrn(), ObjectList.USER_KEY);
        boolean checkPassword = securityService.checkPassword(userRrn, _password);
        Assert.isTrue(checkPassword,
                      Errors.create().key(MessageIdList.USER_INVALID_PWD).content("Wrong user name or password!")
                            .build());
        return mapping.findForward("workflow");
    }

    private ActionForward semoAuto4Page(ActionMapping mapping, HttpServletRequest request, Job job, List lots,
                                        ActionForm form) {
        JobInfoForm jobInfoForm = new JobInfoForm();
        Lot monitorLot = (Lot) request.getAttribute("monitorLot");
        if (monitorLot == null) {
            for (Iterator it = lots.iterator(); it.hasNext(); ) {
                Map lotInfo = (Map) it.next();

                List<BatchLotStore> batchLotStoreList = diffBatchQueryService.getBatchStoreListByLot(
                        MapUtils.getLongValue(lotInfo, "lotRrn"));
                if (CollectionUtils.isNotEmpty(batchLotStoreList)) {
                    monitorLot = lotQueryService.getLot(batchLotStoreList.iterator().next().getLotRrn());
                    break;
                }
            }
        }
        if (monitorLot != null) {
            request.setAttribute("monitorLot", monitorLot);
        }

        if (job != null) {
            buildLotinfo(job, lots);
            // set recipe
            PropertyUtils.copyProperties(jobInfoForm, job);

            int i = 0;
            Long totalWaferQty = 0L;
            for (Iterator it = lots.iterator(); it.hasNext(); ) {
                Map lotInfo = (Map) it.next();
                long qty = MapUtils.getDouble(lotInfo, "qty1").longValue();
                totalWaferQty += qty;
            }
            for (Iterator it = lots.iterator(); it.hasNext(); ) {
                Map lotInfo = (Map) it.next();
                lotInfo.put("recipeParam", job.getRecipeString());
                if (StringUtils.isBlank(MapUtils.getString(lotInfo, "recipePhysicalId")) &&
                        StringUtils.isNotBlank(MapUtils.getString(lotInfo, "recipeId"))) {
                    lotInfo.put("eqptID", MapUtils.getString(lotInfo, "equipmentId"));
                    lotInfo.put("facilityRrn", LocalContext.getFacilityRrn());
                    String id = recipeService.buildRecipePhysicalId(MapUtils.getString(lotInfo, "recipeId"), lotInfo);
                }
                Lot lot = lotQueryService.getLot(MapUtils.getString(lotInfo, "lotId"), LocalContext.getFacilityRrn());

                RecipeVersion recipeVersion = recipeService.getLotRecipe(lot);
                if (recipeVersion != null) {
                    String physicalId = recipeVersion.getPpid();
                    lotInfo.put("recipeId", recipeVersion.getPpid());
                    lotInfo.put("ppid", recipeVersion.getPpid());
                    lotInfo.put("recipePhysicalId", recipeVersion.getPpid());
                }
            }
        } else {
            jobInfoForm.setJobStatus(LotStatus.WAITING);
            long eqptRrn = NumberUtils.toLong(request.getParameter("eqptRrn"));
            String eqptId = getInstanceId(eqptRrn);
            jobInfoForm.setEqptRrn(eqptRrn);
            jobInfoForm.setEqptId(eqptId);
        }
        request.setAttribute("jobInfoForm", jobInfoForm);
        if (StringUtils.isNotBlank(request.getParameter("view"))) {
            request.setAttribute("view", "1");
        }
        setCache4WFL(request, form);
        return (mapping.findForward("recipeSet4eap"));
    }

    private String getWFLRrn(Long operationRrn, String type, Long equipmentRrn) {
        Operation operationInfo = prpService.getOperation(operationRrn);
        Long wflRrn;

        switch (type) {
            case "in":
                wflRrn = operationInfo.getMvinWflRrn();
                break;
            case "out":
                wflRrn = operationInfo.getMvouWflRrn();
                if (equipmentRrn != null) {
                    Equipment equipment = emsService.getEquipment(equipmentRrn);
                    if (StringUtils.equalsIgnoreCase(equipment.getSorterFlag(), "1")) {
                        String wflId = SorterEnum.WorkFlow.SORT_MOVE_OUT_STD;
                        NamedObject routine = new NamedObject(wflId, baseService
                                .getNamedSpace(LocalContext.getFacilityRrn(), ObjectList.WFL_KEY), ObjectList.WFL_KEY);
                        routine.setObject(ObjectList.WFL_KEY);
                        routine.setObjectType(ObjectList.ROUTE_KEY);
                        routine.setObjectSubtype(ObjectList.WFL_TRANSACTION_KEY);
                        wflRrn = baseService.getNamedObjectRrn(routine);
                    }
                }
                break;
            case "wsin":
                wflRrn = operationInfo.getWsMvinWflRrn();
                break;
            case "wsout":
                wflRrn = operationInfo.getWsMvouWflRrn();
                break;
            default:
                wflRrn = operationInfo.getAbortWflRrn();
                break;
        }

        Assert.isFalse(wflRrn == null,
                       Errors.create().content("Parameter Move In/Out WFL not existed in step!").build());
        return wflRrn.toString();
    }

    private ActionForward autoMove(ActionMapping mapping, RootForm theform, HttpServletRequest request,
                                   HttpServletResponse response) throws Exception {

        // redirect to the login page if there is no session
        Job job = null;
        long jobRrn = 0L;
        List lots = null;
        HashMap _lot = null;
        // step NO.1 jobservice--->memebers

        if ("automovein".equals(request.getParameter(Constants.MOVEIN_KEY)) ||
                StringUtils.isNotEmpty(request.getParameter("automovein"))) {
            if (request.getParameter("jobRrn") != null && !"0".equals(request.getParameter("jobRrn"))) {
                jobRrn = WebUtils.getParameterLong("jobRrn", request);
            } else {
                //job = (Job) session.getAttribute(SessionNames.JOB_KEY);
                job = (Job) request.getAttribute(SessionNames.JOB_KEY);
                jobRrn = job.getJobRrn();
            }
        } else if ("automoveout".equals(request.getParameter(Constants.MOVEOUT_KEY))) {
            jobRrn = WebUtils.getParameterLong("jobRrn", request);
        }

        Assert.isFalse(jobRrn == 0,
                       Errors.create().key(MessageIdList.JOB_NOT_FIND).content("Can not find job!").build());

        job = wipQueryService.getJob(jobRrn);
        request.setAttribute(SessionNames.JOB_KEY, job);
        // ------------操作工设备认证--------------
        //#44941 Manual Move Out根据Certificate卡控权限
        Assert.state(StringUtils.isBlank(wipCheckService.checkEquipmentCertification(LocalContext.getUserId(), job.getEqptRrn())),Errors.create().key(MessageIdList.EQPT_NO_PERMISSION)
                                                    .content("The current user {} has no permission to operate the EQP {}!").args(LocalContext.getUserId(), job.getEqptId()).build());

        lots = wipQueryService.getJobList(job.getJobRrn(), ObjectList.JOB_KEY);


        _lot = (HashMap) lots.get(0);

        // dummy lot check
        Lot firstNDlot = null;
        boolean dummyBatch = false;
        boolean isAllDummy = true;
        for (Object o : lots) {
            Map lotInfo = (Map) o;
            Lot sLot = lotQueryService.getLot(lotInfo.get("lotId").toString(), LocalContext.getFacilityRrn());

            Assert.isFalse(StringUtils.equalsIgnoreCase(sLot.getLotStatus(), LotStatus.RUNNINGHOLD),
                           Errors.create().key(MessageIdList.LOT_VALID_RUNNING_HOLD)
                                 .content("Lot: {} in RUNNINGHOLD status").args(sLot.getLotId()).build());

            if (firstNDlot == null && (!"".equals(sLot.getRecipeId()))) {
                firstNDlot = sLot;
            }

            if (!"D".equals(sLot.getLotType())) {
                if (lots.size() > 1) {
                    isAllDummy = false;
                }
                Assert.isFalse(sLot.getRecipeId() == null || "".equals(sLot.getRecipeId()),
                               Errors.create().key(MessageIdList.LOT_EMPTY_RECIPE)
                                     .content("Lot: {}  RECIPE can't be empty!").args(sLot.getLotId()).build());
            } else {
                if (lots.size() > 1) {
                    dummyBatch = true;
                }
            }

            Assert.isFalse(diffBatchQueryService.checkLotInBatch(sLot.getLotRrn()),
                           Errors.create().key(MessageIdList.LOT_IN_BATCH).content("Lot in batch!").build());

            String eqptAvailableMsg = wipCheckService.checkAvailableEdc(sLot,
                                                                        emsService.getEquipment(sLot.getEqptRrn()));
            Assert.isFalse(StringUtils.isNotBlank(eqptAvailableMsg),
                           Errors.create().key(MessageIdList.PARAM_ERROR_RULE).content(eqptAvailableMsg).build());
        }

        if (dummyBatch) {
            for (Object lot : lots) {
                Map lotInfo = (Map) lot;
                Lot sLot = lotQueryService.getLot(lotInfo.get("lotId").toString(), LocalContext.getFacilityRrn());
                Assert.isFalse(sLot.getOperationRrn().longValue() != firstNDlot.getOperationRrn().longValue(),
                               Errors.create().key(MessageIdList.LOT_JOB_OPERATION_NOT_SAME)
                                     .content("The lots operation in the " + "job list are not " + "the same!")
                                     .build());

                Assert.isFalse(!firstNDlot.getRecipeId().equals(sLot.getRecipeId()) && !isAllDummy,
                               Errors.create().key(MessageIdList.LOT_JOB_RECIPE_NOT_SAME).content(
                                             "The lots recipe " + "in the " + "job list" + " are not" + " the " +
                                             "same!")
                                     .build());
            }
        }

        // check if the job's execution_rrn is valid
        Long executionRrn = job.getExecutionRrn();
        if (job.getJobStatus().equals(JobStatus.RUNNING) && job.getTransExecutionId().equals("MOVEIN") &&
                executionRrn != null && executionRrn > 0) {
            boolean existFlag = wipWorkflowQueryService.isExistExecutionRrn(executionRrn);
            if (!existFlag) {
                wipService.clearUpExecutionInfo(job.getJobRrn());
                job.setExecutionRrn(0L);
            }
        }


        // Step2: check if movout is needed(only when lot status is
        // running and execution does not exist)
        boolean moveInFlag = false;

        if (job.getJobStatus().equals(JobStatus.WAITING) || (job.getJobStatus().equals(JobStatus.HOLD) ||
                job.getJobStatus().equals(JobStatus.RUNNING) && (Long.parseLong(
                        StringUtils.isEmpty(MapUtils.getString(_lot, "executionRrn")) ? "0" : (String) _lot.get(
                                "executionRrn")) > 0))) {
            moveInFlag = true;
        }

        String wfl_type = "MOVEIN";
        String lockType = TransactionNames.LOCK_AUTO_MOVEIN;
        String handleType = TransactionNames.MOVEIN_KEY;
        // 获得PM信息
        Map holdPMMap = wipCheckService.validateEquipPMStatus(emsService.getEntity(new Entity(job.getEqptRrn())));
        String msg = StringUtils.EMPTY;
        String msgPMInfo = wipCheckService.validateEquipPMStatusReturnMsg(holdPMMap);
        if (moveInFlag) {
            if (Boolean.parseBoolean(MapUtils.getString(holdPMMap, "pmHold"))) {
                if (holdPMMap.get("checklistSize") != null) {
                    msg = I18nUtils.getMessage(MessageIdList.EQUIPMENT_PM_SUSPENDED, "该设备被PM暂停,不能加工批次!", msgPMInfo,
                                               (MapUtils.getString(holdPMMap, "checklistJobIds")));
                }
                throw new SystemIllegalArgumentException(Errors.create().content(msg).build());
            }
            if (holdPMMap.get("checklistSize") != null) {
                msg = msgPMInfo;
                if (holdPMMap.get("checklistSize") != null) {
                    msg += "\n" + ((String) holdPMMap.get("checklistJobIds")).replaceAll("<br>", "\n");
                }
                request.setAttribute("PM_CHECKLIST_INFO", msg);
            }
        } else {
            if (holdPMMap.get("checklistSize") != null) {
                msg = msgPMInfo + "\n";
                if (holdPMMap.get("checklistSize") != null) {
                    msg += ((String) holdPMMap.get("checklistJobIds")).replaceAll("<br>", "\n");
                }
                request.setAttribute("PM_CHECKLIST_INFO", msg);
            }
        }

        // FIXME: 2019-11-15  获得批号相近批次 其中逻辑存在问题,确认之后,暂时去除.后续有需要直接修改
        //        msg = "";
        //        Collection similiarLot = checkSimiliarLot(job.getEqptRrn(), lots);
        //        for (Iterator itSimiliarLot = similiarLot.iterator(); itSimiliarLot.hasNext(); ) {
        //            String result = (String) itSimiliarLot.next();
        //            if (msg.length() > 0) {
        //                msg = msg + "\n";
        //            }
        //            msg = msg + result;
        //        }
        //
        //        if (msg.length() > 0) {
        //            if (StringUtils.equalsIgnoreCase("CN", I18nUtils.getCurrentLanguage())) {
        //                msg = "*** 注意: 有批号相近批次, 请仔细检查 ***\n\n" + msg;
        //            } else {
        //                msg = "*** Attention: there is a similar lot, please check it carefully ***\n\n"
        //                + msg;
        //            }
        //        }
        //
        //        request.setAttribute("SIMILIARLOT_INFO", msg);

        // Step3: Perpare the parameters for calling
        // workflow(eventRrn,wflRrn)
        Long _eventRrn = 0L;
        Long abortEventRrn = 0L;
        String _wflRrn = "0";
        String abortWflRrn = "0";
        Long _operationRrn = job.getOperationRrn();

        Entity entity = new Entity();
        entity.setInstanceRrn(job.getEqptRrn());
        entity = emsService.getEntity(entity);
        if (moveInFlag) {
            _wflRrn = getWFLRrn(_operationRrn, "in", null);
            wfl_type = "MOVEIN";
            lockType = TransactionNames.LOCK_MOVEIN;
        } else {
            _wflRrn = getWFLRrn(_operationRrn, "out", entity.getInstanceRrn());
            abortWflRrn = getWFLRrn(_operationRrn, "abort", null);
            wfl_type = "MOVEOUT";
            lockType = TransactionNames.LOCK_MOVEOUT;
        }

        Equipment equipment = emsService.getEquipment(job.getEqptRrn());
        boolean available = wipCheckService.checkEqptStatusAvailable(
                lotQueryService.getLot(MapUtils.getLongValue(_lot, "lotRrn")), equipment);
        Assert.isTrue(available,
                      Errors.create().content("The current state of EQP is not available, please confirm!").build());

        HashMap parameters = new HashMap();

        parameters.put("eqptRrn", String.valueOf(_lot.get("equipmentRrn")));
        parameters.put("abortEventRrn", (abortEventRrn == null) ? "1" : abortEventRrn.toString());
        parameters.put("abortWflRrn", abortWflRrn);
        parameters.put("operationRrn", String.valueOf(_lot.get("operationRrn")));
        parameters.put("operationVersion", String.valueOf(_lot.get("operationVersion")));// 2004-04-19 roy add
        parameters.put("recipeRrn", job.getRecipeString());
        parameters.put(SessionNames.WFL_RRN, _wflRrn);
        parameters.put(SessionNames.RUNSTEP_FLAG, "1");
        parameters.put(SessionNames.ROOT_WFL_EXEC_RRN, String.valueOf(_lot.get("lotExecutionRrn")));
        parameters.put(SessionNames.PARENT_WFL_EXEC_RRN, "0");
        parameters.put(SessionNames.RUNPARENTSTEP_FLAG, "0");
        parameters.put(SessionNames.WFL_EXEC_RRN,
                       ("null".equals(String.valueOf(_lot.get("executionRrn")))) ? "0" : String.valueOf(
                               _lot.get("executionRrn")));
        request.setAttribute(SessionNames.OBJECT_KEY, "equipment");

        if (wipCheckService.checkEqupStatusForMove(job.getJobRrn(), MapUtils.getLongValue(_lot, "equipmentRrn"))) {
            request.setAttribute(SessionNames.MOVEDISABLE_FLAG_KEY, "TRUE");
        } else {
            request.setAttribute(SessionNames.MOVEDISABLE_FLAG_KEY, "FALSE");
        }

        if (request.getParameter(Constants.MOVEIN_KEY) != null) {

            boolean eqptBusyFlag = wipCheckService.validJobSize(job);
            Assert.isTrue(eqptBusyFlag, Errors.create().key(MessageIdList.EQUIPMENT_CURRENTLY_BUSY)
                                              .content("Equipment currently busy.").build());
        }
        if (request.getParameter(Constants.MOVEOUT_KEY) != null) {
            List<Lot> lotsByJobRrn = lotQueryService.getLotsByJobRrn(job.getJobRrn());
            //move out 时判断是否为byManual设置的multipath,如果是将路径传递下去
            boolean byManualFlag = wipCheckService.checkMultipathByManual(lotsByJobRrn);
            if (byManualFlag) {
                Assert.isTrue(NumberUtils.INTEGER_ONE.equals(lots.size()),
                              Errors.create().key(MessageIdList.MULTIPATH_BY_MANUAL_CHECK_LOT)
                                    .content("has a multipath set by manual.lot quantity can only be 1!").build());
                Lot multipathLot = lotQueryService.getLot(lotsByJobRrn.get(0).getLotRrn());
                List<Map<String, Object>> wflPathoperation = super.getWflPathoperation(multipathLot);
                List<Map<String, Object>> wflPathRoute = super.getWflPathRoute(multipathLot);
                if (wflPathoperation.size() > 1) {
                    request.setAttribute(WflLinkContextSetupAttributeUtil.MANUAL_OPERATION, wflPathoperation);
                    request.setAttribute("byManualStepFlag", "true");
                }
                if (wflPathRoute.size() > 1 &&
                        wipCheckService.checkOperationIsLastOperationInRoute(multipathLot.getWflStepPath(),
                                                                             multipathLot.getProcessRrn(),
                                                                             multipathLot.getProcessVersion())) {
                    request.setAttribute(WflLinkContextSetupAttributeUtil.MANUAL_ROUTE, wflPathRoute);
                    request.setAttribute("byManualRouteFlag", "true");
                }
            }
            boolean holdFlag = lotService.handleRunningHoldWithMultiPath(job.getJobRrn(), MultiPathCheckType.SETUP);
            if (holdFlag) {
                return super.showRunningHoldInfoDetail(mapping, request, job.getJobRrn());
            }

        }

        // step2: prepare the parameters
        // 2.2reconstruct lots to show reticle combo box
        buildLotinfo(job, lots);


        parameters.put("comments", request.getParameter("comments"));// TODO comment??
        parameters.put("jobRrn", job.getJobRrn() + "");
        parameters.put("AttributeValue", job.getOperationRrn().toString() + "." + job.getEqptRrn().toString());


        parameters.put("lotRrns", getLotRrns(lotQueryService.getLotsByJobRrn(job.getJobRrn())));

        // step2: update parameters info if abort is needed

        String copy_wfl_rrn = (String) parameters.get(SessionNames.WFL_RRN);

        if (request.getParameter(Constants.ABORTJOB_KEY) != null) {
            parameters.put(SessionNames.WFL_RRN, parameters.get("abortWflRrn"));
        }

        Long _test_excutionRrn = new Long((String) parameters.get(SessionNames.WFL_EXEC_RRN));

        boolean existFlag = false;


        if (_test_excutionRrn > 0) {
            existFlag = wipWorkflowQueryService.isExistExecutionRrn(_test_excutionRrn);

            if (!existFlag && "ABORT".equalsIgnoreCase(job.getTransExecutionId())) {
                abortWflRrn = getWFLRrn(job.getOperationRrn(), "abort", null);
                parameters.put(SessionNames.WFL_RRN, abortWflRrn);
                parameters.put(SessionNames.WFL_EXEC_RRN, "0"); // if the execution does not exist, set it to 0, add
                // by yunsong 2008-4-18
                wfl_type = "ABORT";
                lockType = TransactionNames.LOCK_ABOUT;
            }
            entity = new Entity();
            entity.setInstanceRrn(job.getEqptRrn());
            entity = emsService.getEntity(entity);
            // add move out/move in, add by yunsong 2008-4-17
            if (!existFlag && "MOVEOUT".equalsIgnoreCase(job.getTransExecutionId())) {
                String moveoutWflRrn = "";
                if (StringUtils.equalsIgnoreCase(Constants.SEMI_AUTO_KEY, entity.getOperationMode())) {
                    // moveoutWflRrn = getWFLRrn(_operationRrn, "wsout");
                    moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "out", entity.getInstanceRrn());
                } else {
                    moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "out", entity.getInstanceRrn());
                }
                parameters.put(SessionNames.WFL_RRN, moveoutWflRrn);
                parameters.put(SessionNames.WFL_EXEC_RRN, "0"); // if the execution does not exist, set it to 0, add
                // by yunsong 2008-4-18
                wfl_type = "MOVEOUT";
                lockType = TransactionNames.LOCK_MOVEOUT;
            }

            if (!existFlag && "MOVEIN".equalsIgnoreCase(job.getTransExecutionId())) {
                String moveoutWflRrn = "";
                if (StringUtils.equalsIgnoreCase(Constants.SEMI_AUTO_KEY, entity.getOperationMode())) {
                    // moveoutWflRrn = getWFLRrn(_operationRrn, "wsin");
                    moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "in", null);
                } else {
                    moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "in", null);
                }
                parameters.put(SessionNames.WFL_RRN, moveoutWflRrn);
                parameters.put(SessionNames.WFL_EXEC_RRN, "0"); // if the execution does not exist, set it to 0, add
                // by yunsong 2008-4-18
                wfl_type = "MOVEIN";
                lockType = TransactionNames.LOCK_MOVEIN;
            }

        }
        // end add by ben

        // step3: create execution rrn if execution does not exist
        if (parameters.get(SessionNames.WFL_EXEC_RRN).equals("") ||
                parameters.get(SessionNames.WFL_EXEC_RRN).equals("0")) {
            long _workflowRrn = MapUtils.getLongValue(parameters, SessionNames.WFL_RRN);
            // if no move in/out, abort routine setup trigger an error.
            if (_workflowRrn <= 0) {
                parameters.put(SessionNames.WFL_RRN, copy_wfl_rrn);
                throw new SystemIllegalArgumentException(Errors.create().key(MessageIdList.WORKFLOW_INVALID_ROUTINE)
                                                               .content("Invalid workflow routine setup in this " +
                                                                                "step .").build());
            }

            String _multiRootInstanceRrn = (String) parameters.get(SessionNames.ROOT_WFL_EXEC_RRN);
            long _parentInstanceRrn = MapUtils.getLongValue(parameters, SessionNames.PARENT_WFL_EXEC_RRN);


            WorkflowEngineService workflowEngineService = SpringContext.getBean(WorkflowEngineService.class);
            executionRrn = workflowEngineService.createExecutionRrn(_workflowRrn, _multiRootInstanceRrn,
                                                                    _parentInstanceRrn, null, parameters);

            wipService.maintainExecutionRrn(job.getJobRrn(), executionRrn, wfl_type);

            parameters.put(SessionNames.WFL_EXEC_RRN, executionRrn + "");
        }
        String popDummyFlag = null;
        popDummyFlag = prpService.getOperation(job.getOperationRrn()).getPopDummyFlag();

        request.setAttribute(SessionNames.PARAMETERSINFO_KEY, parameters);
        fillRecipeInfo(lots);
        request.setAttribute(SessionNames.COLLECTION_KEY, lots);
        if (lots.size() > 1) {
            Collection buildLots = new ArrayList();
            for (Object o : lots) {
                Map lotMap = (Map) o;
                long productRrn = MapUtils.getLongValue(lotMap, "productRrn");
                String result = getObjectValue(productRrn, "FLD_BONDING");
                if (StringUtils.equals(result, Unit.BONDED_TYPE_KEY)) {
                    result = "D";
                } else if (StringUtils.equals(result, Unit.BY_BONDED_TYPE_KEY)) {
                    result = "H";
                } else {
                    result = "";
                }

                String sapphire = "";
                Operation operation = prpService.getOperation(MapUtils.getLongValue(lotMap, "operationRrn"));
                if (operation.isBondedOperation()) {
                    Lot lot = lotQueryService.getLot(MapUtils.getLongValue(lotMap, "lotRrn"));
                    boolean isSapphire = isSapphire(lots, lot);
                    if (isSapphire) {
                        sapphire = Sapphire.SAPPHIRE;
                    }
                }

                lotMap.put("isSapphire", getIsSapphire(request, MapUtils.getString(lotMap, "lotId")));

                lotMap.put("sapphire", sapphire);
                lotMap.put("lotTypeBonded", result);
                buildLots.add(lotMap);
            }
            request.setAttribute(SessionNames.COLLECTION_KEY, buildLots);

        }
        request.setAttribute("currentlots", lots);
        request.setAttribute(SessionNames.JOB_KEY, job);
        request.setAttribute("popDummyFlag", popDummyFlag);

        // step3: call workflow engine
        if (StringUtils.isEmpty(request.getParameter("automovein"))) {
            // 检查 lot lock
            // String lockTransId = TransactionNames.LOCK_MOVEIN;
            // List<Lot> lockLots = new ArrayList<>();
            // for (Iterator it = lots.iterator(); it.hasNext(); ) {
            // HashMap lotItem = (HashMap) it.next();
            // Long lotRrn = new Long((String) lotItem.get("lotRrn"));
            // Lot lot = lotQueryService.getLot(lotRrn);
            // if (StringUtils.equalsIgnoreCase(lot.getLotStatus(), LotStatus.RUNNING)) {
            //     lockTransId = TransactionNames.LOCK_MOVEOUT;
            // }
            // lockLots.add(lot);
            // }
            // if (lots != null && lots.size() > 0) {
            //     checkAndCreateLotsTransLock(LocalContext.getUserRrn(), lockTransId, lockLots,
            //                                 "autoMove: " + handleType + " in JobServiceAction by " +
            //                                         LocalContext.getUserId());
            // }
            entity.setInstanceRrn(job.getEqptRrn());
            entity = emsService.getEntity(entity);
            if (StringUtils.equalsIgnoreCase(Constants.SEMI_AUTO_KEY, entity.getOperationMode())) {
                // return semoAuto4Page(mapping, request, facilityRrn, job, lots, theform);
            }
            String checkUser = getObjectValue(Long.parseLong(parameters.get("operationRrn") + ""), "FLD_CHECK_USER");
            if (!(StringUtils.isNotEmpty(checkUser) && StringUtils.equals(checkUser, "1"))) {
                parameters.put("showReticleRrn", request.getParameter("showReticleRrn"));
                parameters.put("reticleRrn", request.getParameter("reticleRrn"));
                parameters.put("recipeId", request.getParameter("recipeId"));
                parameters.put("recipeIds", request.getParameterValues("recipeId"));
                parameters.put("chamberJoin", request.getParameter("chamberJoin"));
                parameters.put("lotIdShow", request.getParameterValues("lotIdShow"));
                parameters.put("avaliableEqtRrn", request.getParameter("avaliableEqtRrn"));
                parameters.put(Constants.OK_KEY, "automovein");
                request.getRequestDispatcher(mapping.findForward("workflow").getPath() + "?action=init")
                       .forward(request, response);
                return null;
            }
            return mapping.findForward("checkuser");
        } else {
            request.setAttribute("jobservice_flag", "false");
            request.setAttribute("workflow_flag", "true");
            return null;
        }
    }

    private void fillRecipeInfo(List<Map> lots) {
        for (Map map : lots) {
            long lotRrn = MapUtils.getLongValue(map, "lotRrn");
            Lot lot = lotQueryService.getLot(lotRrn);
            map.put("recipePhysicalId", lot.getRecipePhysicalId());
            map.put("recipeId", lot.getRecipeId());
            map.put("recipeRrn", baseService.getNamedObjectRrn(lot.getRecipeId(),
                                                               baseService.getNamedSpace(LocalContext.getFacilityRrn(),
                                                                                         ObjectList.RECIPE_KEY),
                                                               ObjectList.RECIPE_KEY));
        }
    }

    private boolean checkLotIsMonitorLot(Lot lot) {
        String category = lot.getCreateCategory();
        String lotType = lot.getLotType();
        return StringUtils.equalsIgnoreCase("C", category) &&
                (StringUtils.equalsIgnoreCase("C", lotType) || StringUtils.equalsIgnoreCase("D", lotType));
    }

    private String getLotRrns(List<Lot> lots) {
        StringBuffer sb = new StringBuffer();

        for (Iterator it = lots.iterator(); it.hasNext(); ) {
            Lot lot = (Lot) it.next();

            sb.append("" + lot.getLotRrn() + ",");
        }
        if (sb.length() > 0) {
            return sb.substring(0, sb.length() - 1);
        }
        return "";
    }

    private boolean isSapphire(Collection lots, Lot lot) {
        boolean isSapphire = false;
        String lotId = lot.getLotId();
        String lotSapphire = lot.getIsSapphire();
        Long productRrn = lot.getProductRrn();
        for (Iterator iterator = lots.iterator(); iterator.hasNext(); ) {
            Map lotMap = (HashMap) iterator.next();
            if (StringUtils.equalsIgnoreCase("1", lotSapphire) &&
                    !StringUtils.equals(lotId, MapUtils.getString(lotMap, "lotId"))) {
                Collection productSapphires = prpService.getProductSapphireListByItem(
                        MapUtils.getLong(lotMap, "productRrn"));
                for (Iterator iterator2 = productSapphires.iterator(); iterator2.hasNext(); ) {
                    Map productSapphire = (Map) iterator2.next();
                    if (productRrn.equals(MapUtils.getLong(productSapphire, "instancerrn"))) {
                        return true;
                    }
                }
            }
        }
        return isSapphire;
    }

    private boolean getIsSapphire(HttpServletRequest request, String lotId) {

        String cou = request.getParameter("cou");
        if (StringUtils.isNotBlank(cou)) {
            for (int i = 0; i < new Long(cou).intValue(); i++) {
                String lId = request.getParameter("lotId" + i);
                String isSapphire = request.getParameter("isSapphire" + i);
                if (StringUtils.isNotBlank(lId) && StringUtils.isNotBlank(isSapphire) &&
                        StringUtils.equalsIgnoreCase(lotId, lId) && StringUtils.equalsIgnoreCase("Y", isSapphire)) {
                    return true;
                }
            }
        }
        return false;
    }

    private void handleAutoMoveJob(ActionMapping mapping, RootForm theform, HttpServletRequest request,
                                   HttpServletResponse response) throws Exception {
        List<Long> jobLots = new ArrayList<>();
        List<Lot> lockLots = new ArrayList<>();
        Lot lot = new Lot();
        theform.setTransId("nomal");
        /*int index = 0;
        while (request.getParameter("lotIdShow" + index) != null) {
            String lotId = request.getParameter("lotIdShow" + index);
            lot = lotQueryService.getLot(lotId);
            jobLots.add(lot.getLotRrn());
            lockLots.add(lot);
            index++;
        }*/
        List<Map> lotInfos = (List) request.getAttribute(SessionNames.COLLECTION_KEY);
        if (CollectionUtils.isEmpty(lotInfos)) {
            lotInfos = (List) WebUtils.getCacheString2Obj(theform.getCacheCollection());
        }
        for (Map lotInfo : lotInfos) {
            String lotId = MapUtils.getString(lotInfo, "lotId");
            lot = lotQueryService.getLot(lotId);
            jobLots.add(lot.getLotRrn());
            lockLots.add(lot);
        }

        String eqptId = request.getParameter("eqptId");
        Equipment equipment = new Equipment(eqptId, getNamedSpace(ObjectList.ENTITY_KEY, LocalContext.getFacilityRrn()),
                                            ObjectList.ENTITY_KEY);
        equipment = emsService.getEquipment(equipment);
        Assert.isFalse(equipment == null,
                       Errors.create().key(MessageIdList.EQUIPMENT_MISSING_PARAMETER).content("缺少参数").build());

        Job job = new Job();
        job.setTransPerformedby(LocalContext.getUserId());
        job.setEqptRrn(equipment.getInstanceRrn());
        // get operation and recipe,recipeParameter
        Iterator _temp = lockLots.iterator();

        if (_temp.hasNext()) {
            lot = (Lot) _temp.next();
        }

        Long operationRrn = lot.getOperationRrn();

        job.setOperationRrn(operationRrn);
        job.setJobStatus(JobStatus.WAITING);

        // prepare recipe string according to context values
        Map context = new HashMap();
        context.put("operationRrn", job.getOperationRrn());
        context.put("facilityRrn", LocalContext.getFacilityRrn());

        Assert.isTrue(wipCheckService.validJobSize(job),
                      Errors.create().key(MessageIdList.EQUIPMENT_CURRENTLY_BUSY).content("Equipment currently busy.")
                            .build());

        validLotInEqp(job.getEqptRrn(), lockLots);

        job = wipService.createJob(job, jobLots);
        request.setAttribute(SessionNames.JOB_KEY, job);
        request.setAttribute("automovein", "automovein");
        request.setAttribute("transId", theform.getTransId());

        request.setAttribute("automovein", "automovein");
        autoMove(mapping, theform, request, response);

        JobInfoForm jobInfoForm = new JobInfoForm();
        job = (Job) request.getAttribute(SessionNames.JOB_KEY);
        if (job == null || job.getJobRrn() <= 0) {
            job = (Job) WebUtils.getCacheString2Obj(theform.getCacheJob());
            request.setAttribute(SessionNames.JOB_KEY, job);
        }
        PropertyUtils.copyProperties(jobInfoForm, job);
        request.setAttribute("jobInfoForm", jobInfoForm);
        List lots = (List<Map>) request.getAttribute(SessionNames.COLLECTION_KEY);
        if (lots == null) {
            lots = (List<Map>) WebUtils.getCacheString2Obj(theform.getCacheCollection());
            request.setAttribute(SessionNames.COLLECTION_KEY, lots);
        }

        Assert.isFalse(job == null || lots == null, Errors.create().key(MessageIdList.EQUIPMENT_MISSING_PARAMETER)
                                                          .content("Parameters are not enough!").build());
        buildLotinfo(job, lots);

        HashMap _lot = null;
        int i = 1;
        int j = 1;
        String _carrierId = null;

        String _lotId = "";
        String wfl_type = "MOVEIN";
        Long _operationRrn = job.getOperationRrn();

        for (Iterator it = lots.iterator(); it.hasNext(); ) {

            _lot = (HashMap) it.next();
            _lot.put("isUniqueCarrierFlag", "1");

            if (_lot.get("jobRrn") == null) {
                _lot.put("jobRrn", job.getJobRrn() + "");
            } else if (Long.parseLong((String) _lot.get("jobRrn")) != job.getJobRrn()) {
                it.remove();
                j++;
            } else {
                if ((i == 1) || (i == j)) {
                    _carrierId = (String) _lot.get("carrierId");

                    _lotId = (String) _lot.get("lotId");
                } else {
                    if (((String) _lot.get("carrierId")).equals(_carrierId)) {
                        _lot.put("isUniqueCarrierFlag", "0");
                    } else {
                        _carrierId = (String) _lot.get("carrierId");
                    }
                }
                _lot = null;
                i++;
            }
        }
        if (StringUtils.equals(wfl_type, "MOVEIN") || StringUtils.equals(wfl_type, "MOVEOUT")) {
            int _index = 0;
            Long totalWaferQty = 0L;
            Iterator it = lots.iterator();
            while (it.hasNext()) {
                _lot = (HashMap) it.next();
                long qty = MapUtils.getDouble(_lot, "qty1").longValue();
                totalWaferQty += qty;
            }

            for (Iterator iterator = lots.iterator(); iterator.hasNext(); ) {
                _lot = (HashMap) iterator.next();
                setChildRecipe(request, _lot, totalWaferQty);
                replaceChildRecipeId(_lot);
                selectRecipeId(request, _lot, _index++);
            }
        }
        request.setAttribute("currentlots", lots);
        theform.setCacheCurrentlots(WebUtils.getCacheObj2String(lots));

        String selectRecipeId_flag = request.getParameter("selectRecipeId_flag");
        if (StringUtils.equalsIgnoreCase(selectRecipeId_flag, "true")) {
            if (wipCheckService.checkEqupStatusForMove(job.getJobRrn(), job.getEqptRrn())) {
                request.setAttribute(SessionNames.MOVEDISABLE_FLAG_KEY, "TRUE");
                request.setAttribute("workflow_flag", "true");
                theform.setCacheCollection(WebUtils.getCacheObj2String(lots));
            } else {
                request.setAttribute(SessionNames.MOVEDISABLE_FLAG_KEY, "FALSE");
            }
        } else {
            setCache4WFL(request, theform);
        }
    }

    private void jobIn(HttpServletRequest request, RootForm theform) {
        Equipment equipment = null;
        String eqptId = request.getParameter("eqptId");
        equipment = new Equipment(eqptId, getNamedSpace(ObjectList.ENTITY_KEY, LocalContext.getFacilityRrn()),
                                  ObjectList.ENTITY_KEY);
        equipment = emsService.getEquipment(equipment);

        Assert.isFalse(equipment.getInstanceRrn() <= 0,
                       Errors.create().key(MessageIdList.SYSTEM_INSTANCE_NOT_FOUND).content("{} 没有找到对象!")
                             .args("Equipment").build());

        String lotId = request.getParameter("lotId");
        lotId = StringUtils.isNotEmptyTrim(lotId) ? lotId : request.getParameter("lotIdShow");
        long lotRrn = lotQueryService.getLotRrn(lotId);
        List<BatchLotStore> batchLotStores = diffBatchQueryService.getBatchStoreListByLot(lotRrn);
        Assert.isFalse(CollectionUtils.isNotEmpty(batchLotStores), Errors.create().key(MessageIdList.BATCH_CONTAIN_LOT)
                                                                         .content(
                                                                                 "The Lot in batch ,can not dispatch " +
                                                                                         "lot by manual mode!")
                                                                         .build());

        Lot lot = lotQueryService.getLot(lotRrn);

        // 系统check是否需要自动创建一个Inline Sorter Job
        SorterModel sorterModel = sorterExecInqService.checkSorterModelAndCreateInLineSorterJob(lot,
                                                                                                equipment.getInstanceId(), null);
        if (SorterUtils.isInLineSorter(sorterModel.getSorterType())) {
            SorterUtils.anError(sorterModel.getMsg());
        }
        // SorterModel sorterModel = sorterQueryService.getSorterModel(lot, equipment);
        // Assert.state(StringUtils.isEmpty(sorterModel.getMsg()), Errors.create().content(sorterModel.getMsg())
        // .build());
        // if (StringUtils.equalsIgnoreCase(SorterEnum.Type.INLINE.getName(), sorterModel.getSorterType())) {
        //     String msg = SorterUtils.checkEqptSorterFlag(equipment);
        //     Assert.state(StringUtils.isEmpty(msg), Errors.create().content(msg).build());
        //     if (StringUtils.isEmpty(msg)) {
        //         sorterService.createSorterJobByInLine(sorterModel, lot);
        //     }
        // }

        List<Map> jobList = wipQueryService.getJobList(equipment.getInstanceRrn(), ObjectList.EQUIPMENT_KEY);
        long jobRrn = 0;
        if (CollectionUtils.isEmpty(jobList)) {
            List<Lot> jobLots = new ArrayList<>();
            Job job = new Job();
            job.setTransPerformedby(LocalContext.getUserId());
            job.setEqptRrn(equipment.getInstanceRrn());
            Long operationRrn = lot.getOperationRrn();
            job.setOperationRrn(operationRrn);
            job.setJobStatus(JobStatus.WAITING);
            job.setEqptId(equipment.getInstanceId());

            long total_slots_qty = 0;

            if (CollectionUtils.isNotEmpty(batchLotStores)) {
                for (BatchLotStore batch : batchLotStores) {
                    Lot batchLot = lotQueryService.getLot(batch.getLotRrn());

                    Assert.isFalse(batchLot.getExecutionRrn() == null || batchLot.getExecutionRrn() == 0,
                                   Errors.create().content("Lot's executionRrn is null, and can not be dispatched.")
                                         .build());

                    // 检查下是否做过跳步跳出了跨境时间,如果超过了则不做hold的检查。
                    wipCheckService.validateLotOverQueueTime(lot);
                    validateLotStatusForHold(batchLot);

                    if (jobLots.stream().noneMatch(l -> l.getLotRrn() == batchLot.getLotRrn())) {
                        jobLots.add(batchLot);
                    }

                    long qty = batchLot.getQty1().longValue();
                    total_slots_qty = total_slots_qty + qty;
                }
            } else {

                wipCheckService.validateLotOverQueueTime(lot);
                validateLotStatusForHold(lot);

                jobLots.add(lot);

                long qty = lot.getQty1().longValue();
                total_slots_qty = total_slots_qty + qty;
            }

            Assert.isTrue(wipCheckService.isValidJobSize(equipment.getInstanceRrn(), 1, total_slots_qty),
                          Errors.create().key(MessageIdList.LOT_INVALID_JOB_SIZE).content("Invalid Job Size!").build());

            Assert.isTrue(wipCheckService.validJobSize(job), Errors.create().key(MessageIdList.EQUIPMENT_CURRENTLY_BUSY)
                                                                   .content("Equipment currently busy.").build());

            validLotInEqp(equipment.getInstanceRrn(), jobLots);

            job = wipService.createJob(job, jobLots.stream().map(Lot::getLotRrn).collect(Collectors.toList()));
            request.setAttribute(SessionNames.JOB_KEY, job);
            HashMap parameters = (HashMap) request.getAttribute(SessionNames.PARAMETERSINFO_KEY);
            if (MapUtils.isEmpty(parameters)) {
                parameters = (HashMap) WebUtils.getCacheString2Obj(theform.getCacheParametersInfo());
            }
            createWflExecution(parameters, request);
            request.setAttribute(SessionNames.PARAMETERSINFO_KEY, parameters);

            jobRrn = job.getJobRrn();
            jobList = wipQueryService.getJobList(equipment.getInstanceRrn(), ObjectList.EQUIPMENT_KEY);

        } else {
            List l = new ArrayList();
            for (Map m : jobList) {

                if (batchLotStores.size() > 0) {
                    for (BatchLotStore batch : batchLotStores) {
                        if (MapUtils.getLongValue(m, "lotRrn") == batch.getLotRrn()) {
                            l.add(m);
                        }
                    }
                    jobList = l;
                } else {
                    if ((String.valueOf(lot.getLotRrn()).equals(m.get("lotRrn").toString()))) {
                        // 提取设备上当前批次信息
                        l.add(m);
                        jobList = l;
                    }
                }
            }

            // 当前设备有作业信息但无当前批次的信息
            if (l.size() == 0) {
                List<Lot> jobLots = new ArrayList<>();
                Job job = new Job();

                job.setTransPerformedby(LocalContext.getUserId());
                job.setEqptRrn(equipment.getInstanceRrn());
                Long operationRrn = new Long(lot.getOperationRrn());
                job.setOperationRrn(operationRrn);
                job.setJobStatus(JobStatus.WAITING);
                job.setEqptId(equipment.getInstanceId());

                long total_slots_qty = 0;

                if (batchLotStores.size() > 0) {
                    for (BatchLotStore batch : batchLotStores) {
                        Lot batchLot = lotQueryService.getLot(batch.getLotRrn());

                        Assert.isFalse(batchLot.getExecutionRrn() == null || batchLot.getExecutionRrn() <= 0,
                                       Errors.create().content("Lot's executionRrn is null, and can not be dispatched.")
                                             .build());

                        // 检查下是否做过跳步跳出了跨境时间,如果超过了则不做hold的检查。
                        wipCheckService.validateLotOverQueueTime(lot);
                        validateLotStatusForHold(batchLot);

                        if (jobLots.stream().noneMatch(temp -> temp.getLotRrn() == batchLot.getLotRrn())) {
                            jobLots.add(batchLot);
                        }

                        long qty = lot.getQty1().longValue();
                        total_slots_qty = total_slots_qty + qty;
                    }
                } else {

                    Assert.isFalse(lot.getExecutionRrn() == null || lot.getExecutionRrn() <= 0,
                                   Errors.create().content("Lot's executionRrn is null, and can not be dispatched.")
                                         .build());

                    // 检查下是否做过跳步跳出了跨境时间,如果超过了则不做hold的检查。
                    wipCheckService.validateLotOverQueueTime(lot);
                    validateLotStatusForHold(lot);

                    if (jobLots.stream().noneMatch(temp -> temp.getLotRrn() == lot.getLotRrn())) {
                        jobLots.add(lot);
                    }

                    long qty = lot.getQty1().longValue();
                    total_slots_qty = total_slots_qty + qty;
                }

                Assert.isTrue(wipCheckService.isValidJobSize(equipment.getInstanceRrn(), 1, total_slots_qty),
                              Errors.create().key(MessageIdList.LOT_INVALID_JOB_SIZE).content("Invalid Job Size!")
                                    .build());

                wipCheckService.validJobSize(job);

                validLotInEqp(equipment.getInstanceRrn(), jobLots);

                job = wipService.createJob(job, jobLots.stream().map(Lot::getLotRrn).collect(Collectors.toList()));
                request.setAttribute(SessionNames.JOB_KEY, job);
                HashMap parameters = (HashMap) request.getAttribute(SessionNames.PARAMETERSINFO_KEY);
                if (MapUtils.isEmpty(parameters)) {
                    parameters = (HashMap) WebUtils.getCacheString2Obj(theform.getCacheParametersInfo());
                }
                createWflExecution(parameters, request);
                request.setAttribute(SessionNames.PARAMETERSINFO_KEY, parameters);

                jobRrn = job.getJobRrn();
                jobList = wipQueryService.getJobList(equipment.getInstanceRrn(), ObjectList.EQUIPMENT_KEY);
            } else {
                for (Map jobLot : jobList) {
                    Lot _lot = lotQueryService.getLot(MapUtils.getLong(jobLot, "lotRrn"));
                    Assert.isTrue(LotStatus.WAITING.equals(_lot.getLotStatus()) ||
                                          LotStatus.DISPATCH.equals(_lot.getLotStatus()),
                                  Errors.create().content("The lot status shoud be WAITING or DISPATCH!").build());
                }
                Map jobMap = (Map) l.iterator().next();
                jobRrn = MapUtils.getLong(jobMap, "jobRrn");
            }
        }
        jobList = jobList.stream().filter(j -> Long.valueOf((String) j.get("lotRrn")) == lot.getLotRrn())
                         .collect(Collectors.toList());

        Job curJob = wipQueryService.getJob(jobRrn);
        request.setAttribute(SessionNames.JOB_KEY, curJob);
        int i = 1;
        String _JobNumber = null;

        for (Map job : jobList) {

            job.put("isUniqueJobFlag", "1");

            if (i == 1) {
                _JobNumber = (String) job.get("jobRrn");
            } else {
                if (((String) job.get("jobRrn")).equals(_JobNumber)) {
                    job.put("isUniqueJobFlag", "0");
                } else {
                    _JobNumber = (String) job.get("jobRrn");
                }
            }

            i++;

            job.put("priority", MapUtils.getString(job, "priority"));
        }

        replaceJobListRecipeId(jobList);

        request.setAttribute(SessionNames.COLLECTION_KEY, jobList);
        request.setAttribute("currentlots", jobList);

        handleJob(jobList, theform, request);
    }

    private void validJob(RootForm theForm, String wfl_type, HttpServletRequest request) {
        if (request.getParameter(Constants.MOVEIN_KEY) != null && request.getParameter("dojob") != null) {
            Job job = (Job) request.getAttribute(SessionNames.JOB_KEY);
            if (job == null || job.getJobRrn() <= 0) {
                job = (Job) WebUtils.getCacheString2Obj(theForm.getCacheJob());
                request.setAttribute(SessionNames.JOB_KEY, job);
            }
            long _jobrrn = -1;
            _jobrrn = (request.getParameter("jobRrn") != null) ? Long.parseLong(request.getParameter("jobRrn")) :
                    job == null ? -1 : job.getJobRrn();
            if (_jobrrn > 0) {
                job = wipQueryService.getJob(_jobrrn);
            }
            Assert.isFalse(job == null,
                           Errors.create().key(MessageIdList.JOB_MISSING).content("job不存在! 请关闭当前tab页面重新创建!").build());

        }

        Job job = (Job) request.getAttribute(SessionNames.JOB_KEY);
        if (job == null || job.getJobRrn() <= 0) {
            job = (Job) WebUtils.getCacheString2Obj(theForm.getCacheJob());
        }
        request.setAttribute(SessionNames.JOB_KEY, job);
        List lots = (List) request.getAttribute(SessionNames.COLLECTION_KEY);
        if (CollectionUtils.isEmpty(lots)) {
            lots = (List) WebUtils.getCacheString2Obj(theForm.getCacheCollection());
        }
        request.setAttribute(SessionNames.COLLECTION_KEY, lots);
        Assert.isFalse(job == null || lots == null, Errors.create().key(MessageIdList.EQUIPMENT_MISSING_PARAMETER)
                                                          .content("Parameters are not enough!").build());

        if (request.getParameter(Constants.MOVEIN_KEY) != null) {
            wipCheckService.validJobSize(job);
        }

        HashMap parameters = (HashMap) request.getAttribute(SessionNames.PARAMETERSINFO_KEY);
        if (MapUtils.isEmpty(parameters)) {
            parameters = (HashMap) WebUtils.getCacheString2Obj(theForm.getCacheParametersInfo());
        }
        parameters.put("comments", request.getParameter("comments"));
        parameters.put("jobRrn", job.getJobRrn() + "");
        parameters.put("AttributeValue", job.getOperationRrn().toString() + "." + job.getEqptRrn().toString());
        parameters.put("lotRrns", getLotRrns(lotQueryService.getLotsByJobRrn(job.getJobRrn())));

        String copy_wfl_rrn = (String) parameters.get(SessionNames.WFL_RRN);
        String wflExecRrn = String.valueOf(parameters.get(SessionNames.WFL_EXEC_RRN));
        Long _test_excutionRrn = Long.parseLong(StringUtils.isNumeric(wflExecRrn) ? wflExecRrn : "0");

        boolean existFlag = false;

        if (_test_excutionRrn > 0) {
            existFlag = wipWorkflowQueryService.isExistExecutionRrn(_test_excutionRrn);
            Entity entity = new Entity();
            entity.setInstanceRrn(job.getEqptRrn());
            entity = emsService.getEntity(entity);
            if (!existFlag && "ABORT".equalsIgnoreCase(job.getTransExecutionId())) {
                String abortWflRrn = getWFLRrn(job.getOperationRrn(), "abort", null);
                parameters.put(SessionNames.WFL_RRN, abortWflRrn);
                parameters.put(SessionNames.WFL_EXEC_RRN, "0");
                wfl_type = "ABORT";
            }
            // add move out/move in, add by yunsong 2008-4-17
            if (!existFlag && "MOVEOUT".equalsIgnoreCase(job.getTransExecutionId())) {
                String moveoutWflRrn = "";
                if (StringUtils.equalsIgnoreCase(Constants.SEMI_AUTO_KEY, entity.getOperationMode())) {
                    // moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "wsout");
                    moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "out", entity.getInstanceRrn());
                } else {
                    moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "out", entity.getInstanceRrn());
                }
                parameters.put(SessionNames.WFL_RRN, moveoutWflRrn);
                parameters.put(SessionNames.WFL_EXEC_RRN, "0");
                wfl_type = "MOVEOUT";
            }

            if (!existFlag && "MOVEIN".equalsIgnoreCase(job.getTransExecutionId())) {
                String moveoutWflRrn = "";
                if (StringUtils.equalsIgnoreCase(Constants.SEMI_AUTO_KEY, entity.getOperationMode())) {
                    // moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "wsin");
                    moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "in", null);
                } else {
                    moveoutWflRrn = getWFLRrn(job.getOperationRrn(), "in", null);
                }
                parameters.put(SessionNames.WFL_RRN, moveoutWflRrn);
                parameters.put(SessionNames.WFL_EXEC_RRN, "0");
                wfl_type = "MOVEIN";
            }

        }

        // step3: create execution rrn if execution does not exist
        String eflExecRrn = (String) parameters.get(SessionNames.WFL_EXEC_RRN);
        boolean existExecutionRrn = wipWorkflowQueryService.isExistExecutionRrn(Long.parseLong(eflExecRrn));
        if (!existExecutionRrn) {
            long _workflowRrn = MapUtils.getLongValue(parameters, SessionNames.WFL_RRN);
            if (_workflowRrn <= 0) {
                parameters.put(SessionNames.WFL_RRN, copy_wfl_rrn);

                throw new SystemIllegalArgumentException(
                        Errors.create().key(MessageIdList.WORKFLOW_INVALID_ROUTINE_STEP_IN_THIS_STEP)
                              .content("Invalid workflow routine setup in this step.").build());
            }

            String _multiRootInstanceRrn = (String) parameters.get(SessionNames.ROOT_WFL_EXEC_RRN);
            long _parentInstanceRrn = MapUtils.getLongValue(parameters, SessionNames.PARENT_WFL_EXEC_RRN);

            long executionRrn = -1;

            WorkflowEngineService workflowEngineService = SpringContext.getBean(WorkflowEngineService.class);

            executionRrn = workflowEngineService.createExecutionRrn(_workflowRrn, _multiRootInstanceRrn,
                                                                    _parentInstanceRrn, null, parameters);

            wipService.maintainExecutionRrn(job.getJobRrn(), executionRrn, wfl_type);

            parameters.put(SessionNames.WFL_EXEC_RRN, executionRrn + "");
        }
    }

    private String validateLotStatusForHold(Lot lot) {
        if (LotStatus.HOLD.equalsIgnoreCase(lot.getLotStatus())) {
            List<Map> holdReasons = wipQueryService.getHoldReasons(lot.getLotRrn());
            if (!holdReasons.isEmpty()) {
                for (Map hashMap : holdReasons) {
                    Assert.isFalse(
                            HoldCodeNames.QTIMEHOLD_KEY.equalsIgnoreCase(MapUtils.getString(hashMap, "reasonCode")),
                            Errors.create().key(MessageIdList.LOT_EXCEEDS_MAX)
                                  .content("Lot exceeds the maximum waiting time, it was hold by the system!").build());
                }
            }
        }
        return null;
    }

    private void createWflExecution(HashMap parameters, HttpServletRequest request) {
        Job job = (Job) request.getAttribute(SessionNames.JOB_KEY);
        String copy_wfl_rrn = (String) parameters.get(SessionNames.WFL_RRN);
        String wfl_type = (String) request.getAttribute(Constants.MEMBERS_KEY);
        String eflExecRrn = (String) parameters.get(SessionNames.WFL_EXEC_RRN);
        if (!wipWorkflowQueryService.isExistExecutionRrn(Long.parseLong(eflExecRrn))) {
            long _workflowRrn = MapUtils.getLongValue(parameters, SessionNames.WFL_RRN);
            if (_workflowRrn <= 0) {
                parameters.put(SessionNames.WFL_RRN, copy_wfl_rrn);

                throw new SystemIllegalArgumentException(
                        Errors.create().key(MessageIdList.WORKFLOW_INVALID_ROUTINE_STEP_IN_THIS_STEP)
                              .content("Invalid workflow routine setup in this step.").build());
            }

            String _multiRootInstanceRrn = (String) parameters.get(SessionNames.ROOT_WFL_EXEC_RRN);
            long _parentInstanceRrn = MapUtils.getLongValue(parameters, SessionNames.PARENT_WFL_EXEC_RRN);

            long executionRrn = -1;

            WorkflowEngineService workflowEngineService = SpringContext.getBean(WorkflowEngineService.class);

            executionRrn = workflowEngineService.createExecutionRrn(_workflowRrn, _multiRootInstanceRrn,
                                                                    _parentInstanceRrn, null, parameters);

            wipService.maintainExecutionRrn(job.getJobRrn(), executionRrn, wfl_type);

            parameters.put(SessionNames.WFL_EXEC_RRN, executionRrn + "");
        }
    }

    private void replaceJobListRecipeId(List<Map> jobList) {
        for (Map map : jobList) {
            map.put("eqptID", MapUtils.getString(map, "eqptID", MapUtils.getString(map, "equipmentId")));
            map.put("facilityRrn", LocalContext.getFacilityRrn());

            long lotRrn = MapUtils.getLongValue(map, "lotRrn");
            Lot lot = lotQueryService.getLot(lotRrn);
            map.put("recipePhysicalId", lot.getRecipePhysicalId());
            map.put("recipeId", lot.getRecipeId());
            map.put("recipeRrn", baseService.getNamedObjectRrn(lot.getRecipeId(),
                                                               baseService.getNamedSpace(LocalContext.getFacilityRrn(),
                                                                                         ObjectList.RECIPE_KEY),
                                                               ObjectList.RECIPE_KEY));
        }
    }

    private void handleJob(List jobList, RootForm theform, HttpServletRequest request) {
        String operationRrn = "";
        String type = "";
        Job job = new Job();
        List<Map> lots = null;
        String wfl_type = "MOVEIN";
        if (request.getAttribute(Constants.MEMBERS_KEY) != null) {
            Map jobMap = (Map) jobList.iterator().next();
            String equipmentRrns = request.getParameter("avaliableEqtRrn");
            request.setAttribute("equipmentRrns", equipmentRrns);

            String j_flag = "true";
            Assert.isTrue(j_flag.equals(request.getAttribute("jobservice_flag")),
                          Errors.create().key(MessageIdList.WORKFLOW_SUBMIT_OUT)
                                .content("Cannot submit this form out of order,please click cancel").build());

            request.setAttribute("jobservice_flag", "false");
            request.setAttribute("workflow_flag", "true");

            type = request.getAttribute("type").toString();
            String jobRrn = jobMap.get("jobRrn").toString();
            operationRrn = jobMap.get("operationRrn").toString();
            String equipmentRrn = jobMap.get("equipmentRrn").toString();
            String lotExecutionRrn = jobMap.get("lotExecutionRrn").toString();
            String operationVersion = jobMap.get("operationVersion").toString();
            String excutionRrn = "";
            if (jobMap.get("executionRrn") != null) {
                excutionRrn = jobMap.get("executionRrn").toString();
            }

            Assert.isFalse(
                    type.equals("") || jobRrn.equals("") || lotExecutionRrn.equals("0") || operationRrn.equals("") ||
                            operationVersion.equals("") || equipmentRrn.equals(""),
                    Errors.create().key(MessageIdList.SYSTEM_INVALID_PARAMETERS).content("Invalid Parameters!")
                          .build());

            job = wipQueryService.getJob(Long.parseLong(jobRrn));

            // check if the job's execution_rrn is valid
            Long executionRrn = job.getExecutionRrn();
            if (job.getJobStatus().equals(JobStatus.RUNNING) && job.getTransExecutionId().equals("MOVEIN") &&
                    executionRrn != null && executionRrn > 0) {

                boolean existFlag = wipWorkflowQueryService.isExistExecutionRrn(executionRrn);
                if (!existFlag) {
                    wipService.clearUpExecutionInfo(job.getJobRrn());
                    job.setExecutionRrn(0L);
                }

            }

            // Step2: check if movout is needed(only when lot status is
            boolean moveInFlag = false;

            if (job.getJobStatus().equals(JobStatus.WAITING) || (job.getJobStatus().equals(JobStatus.HOLD) ||
                    job.getJobStatus().equals(JobStatus.RUNNING) &&
                            (Long.parseLong((excutionRrn).equals("") ? "0" : excutionRrn) > 0))) {
                moveInFlag = true;
            }

            Long _eventRrn = 0L;
            Long abortEventRrn = 0L;
            String _wflRrn = "0";
            String abortWflRrn = "0";
            Long _operationRrn = new Long(operationRrn);
            Integer _operationVersion = new Integer(operationVersion);

            Entity entity = new Entity();
            entity.setInstanceRrn(job.getEqptRrn());
            entity = emsService.getEntity(entity);
            if (moveInFlag) {
                if (StringUtils.equalsIgnoreCase(Constants.SEMI_AUTO_KEY, entity.getOperationMode())) {
                    _wflRrn = getWFLRrn(_operationRrn, "in", null);
                } else {
                    _wflRrn = getWFLRrn(_operationRrn, "in", null);
                }
                wfl_type = "MOVEIN";
            } else {
                if (StringUtils.equalsIgnoreCase(Constants.SEMI_AUTO_KEY, entity.getOperationMode())) {
                    _wflRrn = getWFLRrn(_operationRrn, "out", entity.getInstanceRrn());
                } else {
                    _wflRrn = getWFLRrn(_operationRrn, "out", entity.getInstanceRrn());
                }
                abortWflRrn = getWFLRrn(_operationRrn, "abort", null);
                wfl_type = "MOVEOUT";
            }

            HashMap parameters = new HashMap();

            parameters.put("eqptRrn", equipmentRrn);

            parameters.put("abortEventRrn", (abortEventRrn == null) ? "1" : abortEventRrn.toString());
            parameters.put("abortWflRrn", abortWflRrn);
            parameters.put("operationRrn", operationRrn);
            parameters.put("operationVersion", operationVersion);

            parameters.put("recipeRrn", job.getRecipeString());

            parameters.put(SessionNames.WFL_RRN, _wflRrn);

            parameters.put(SessionNames.RUNSTEP_FLAG, "1");
            parameters.put(SessionNames.ROOT_WFL_EXEC_RRN, lotExecutionRrn);
            parameters.put(SessionNames.PARENT_WFL_EXEC_RRN, "0");
            parameters.put(SessionNames.RUNPARENTSTEP_FLAG, "0");
            parameters.put(SessionNames.WFL_EXEC_RRN, ((excutionRrn).equals("") ? "0" : excutionRrn));

            request.setAttribute(SessionNames.PARAMETERSINFO_KEY, parameters);

            theform.setTransId(type);
            request.setAttribute(SessionNames.OBJECT_KEY, type);
            theform.setCacheObject(type);

            if (wipCheckService.checkEqupStatusForMove(job.getJobRrn(), NumberUtils.toLong(equipmentRrn))) {
                request.setAttribute(SessionNames.MOVEDISABLE_FLAG_KEY, "TRUE");
            } else {
                request.setAttribute(SessionNames.MOVEDISABLE_FLAG_KEY, "FALSE");
            }
        }
        JobInfoForm jobInfoForm = new JobInfoForm();
        job = (Job) request.getAttribute(SessionNames.JOB_KEY);
        if (job == null || job.getJobRrn() <= 0) {
            job = (Job) WebUtils.getCacheString2Obj(theform.getCacheJob());
            request.setAttribute(SessionNames.JOB_KEY, job);
        }
        PropertyUtils.copyProperties(jobInfoForm, job);
        request.setAttribute("jobInfoForm", jobInfoForm);
        lots = (List<Map>) request.getAttribute(SessionNames.COLLECTION_KEY);
        if (lots == null) {
            lots = (List<Map>) WebUtils.getCacheString2Obj(theform.getCacheCollection());
            request.setAttribute(SessionNames.COLLECTION_KEY, lots);
        }

        Assert.isFalse(job == null || lots == null,
                       Errors.create().key(MessageIdList.SYSTEM_MISSING_PARAMETER).content("Parameters are not enough!")
                             .build());
        buildLotinfo(job, lots);

        HashMap _lot = null;
        int i = 1;
        int j = 1;
        String _carrierId = null;

        String _lotId = "";
        Long _operationRrn = job.getOperationRrn();
        if (_operationRrn != null) {
            if (StringUtils.isNotEmpty(operationRrn)) {
                _operationRrn = new Long(operationRrn);
            }
        }

        for (Iterator it = lots.iterator(); it.hasNext(); ) {

            _lot = (HashMap) it.next();
            _lot.put("isUniqueCarrierFlag", "1");

            if (_lot.get("jobRrn") == null) {
                _lot.put("jobRrn", job.getJobRrn() + "");
            } else if (Long.parseLong((String) _lot.get("jobRrn")) != job.getJobRrn()) {
                it.remove();
                j++;
            } else {
                if ((i == 1) || (i == j)) {
                    _carrierId = (String) _lot.get("carrierId");

                    _lotId = (String) _lot.get("lotId");
                } else {
                    if (((String) _lot.get("carrierId")).equals(_carrierId)) {
                        _lot.put("isUniqueCarrierFlag", "0");
                    } else {
                        _carrierId = (String) _lot.get("carrierId");
                    }
                }
                _lot = null;
                i++;
            }
        }
        if (StringUtils.equals(wfl_type, "MOVEIN") || StringUtils.equals(wfl_type, "MOVEOUT")) {
            int _index = 0;
            Long totalWaferQty = 0L;
            Iterator it = lots.iterator();
            while (it.hasNext()) {
                _lot = (HashMap) it.next();
                long qty = MapUtils.getDouble(_lot, "qty1").longValue();
                totalWaferQty += qty;
            }

            for (Iterator iterator = lots.iterator(); iterator.hasNext(); ) {
                _lot = (HashMap) iterator.next();
                setChildRecipe(request, _lot, totalWaferQty);
                replaceChildRecipeId(_lot);
                selectRecipeId(request, _lot, _index++);
            }
        }
        request.setAttribute("currentlots", lots);
        theform.setCacheCurrentlots(WebUtils.getCacheObj2String(lots));

        String edcBack = (String) request.getAttribute("edcback");

        if (!"edcback".equalsIgnoreCase(edcBack)) {
            if ("moveout".equalsIgnoreCase(request.getParameter(Constants.MEMBERS_KEY)) &&
                    job.getJobStatus().equals(JobStatus.RUNNING)) {

                boolean edcflg = false;
                HashMap edcCollect = new HashMap();
                if (edcflg) {

                    edcCollect.put("objectType", type);
                    edcCollect.put("operationRrn", _operationRrn);
                    edcCollect.put("lotId", _lotId);
                    request.setAttribute("edcCollect", edcCollect);
                    return;
                }
            }
        }

        String selectRecipeId_flag = request.getParameter("selectRecipeId_flag");
        if (StringUtils.equalsIgnoreCase(selectRecipeId_flag, "true")) {
            if (wipCheckService.checkEqupStatusForMove(job.getJobRrn(), job.getEqptRrn())) {
                request.setAttribute(SessionNames.MOVEDISABLE_FLAG_KEY, "TRUE");
                request.setAttribute("workflow_flag", "true");
                theform.setCacheCollection(WebUtils.getCacheObj2String(lots));
            } else {
                request.setAttribute(SessionNames.MOVEDISABLE_FLAG_KEY, "FALSE");
            }
        } else {
            setCache4WFL(request, theform);
        }
    }

    private ActionForward preAutoMove(ActionMapping mapping, RootForm theform, HttpServletRequest request,
                                      HttpServletResponse response) throws Exception {
        // redirect to the login page if there is no session
        Job job = null;
        List lots = null;
        HashMap _lot = null;
        HashMap parameters = new HashMap();
        // step NO.1 jobservice--->memebers

        if ("automovein".equals(request.getParameter(Constants.MOVEIN_KEY)) ||
                StringUtils.isNotEmpty(request.getParameter("automovein"))) {
            job = (Job) request.getAttribute(SessionNames.JOB_KEY);
            if (job == null) {
                job = (Job) WebUtils.getCacheString2Obj(theform.getCacheJob());
            }
            request.setAttribute(SessionNames.JOB_KEY, job);
            lots = (List) request.getAttribute(SessionNames.COLLECTION_KEY);
            if (lots == null) {
                lots = (List) WebUtils.getCacheString2Obj(theform.getCacheCollection());
            }
            parameters.put("jobRrn", job.getJobRrn() + "");

            parameters.put("lotRrns", getLotRrns(lotQueryService.getLotsByJobRrn(job.getJobRrn())));
        } else if ("automoveout".equals(request.getParameter(Constants.MOVEOUT_KEY))) {
            long jobRrn = WebUtils.getParameterLong("jobRrn", request);

            Assert.isFalse(jobRrn == 0,
                           Errors.create().key(MessageIdList.JOB_NOT_FIND).content("Can not find job!").build());

            job = wipQueryService.getJob(jobRrn);
            Assert.isFalse(job == null,
                           Errors.create().key(MessageIdList.JOB_MISSING).content("job不存在! 请关闭当前tab页面重新创建!").build());
            request.setAttribute(SessionNames.JOB_KEY, job);

            lots = wipQueryService.getJobList(job.getJobRrn(), ObjectList.JOB_KEY);
            parameters.put("jobRrn", job.getJobRrn() + "");

            parameters.put("lotRrns", getLotRrns(lotQueryService.getLotsByJobRrn(job.getJobRrn())));
        }

        // ------------操作工设备认证--------------
        wipCheckService.checkEquipmentCertification(LocalContext.getUserId(), job.getEqptRrn());

        _lot = (HashMap) ((ArrayList) lots).get(0);

        // dummy lot check
        Lot firstNDlot = null;
        boolean dummyBatch = false;
        boolean isAllDummy = true;
        for (Object o : lots) {
            Map lotInfo = (Map) o;
            Lot sLot = lotQueryService.getLot(lotInfo.get("lotId").toString(), LocalContext.getFacilityRrn());

            Assert.isFalse(StringUtils.equalsIgnoreCase(sLot.getLotStatus(), LotStatus.RUNNINGHOLD),
                           Errors.create().key(MessageIdList.LOT_VALID_RUNNING_HOLD)
                                 .content("Lot: {} in RUNNINGHOLD status").args(sLot.getLotId()).build());

            if (firstNDlot == null && (!"".equals(sLot.getRecipeId()))) {
                firstNDlot = sLot;
            }

            if (!"D".equals(sLot.getLotType())) {
                if (lots.size() > 1) {
                    isAllDummy = false;
                }
                Assert.isFalse(sLot.getRecipeId() == null || "".equals(sLot.getRecipeId()),
                               Errors.create().key(MessageIdList.LOT_EMPTY_RECIPE)
                                     .content("Lot: {}  RECIPE can't be empty!").args(sLot.getLotId()).build());
            } else {
                if (lots.size() > 1) {
                    dummyBatch = true;
                }
            }

            Assert.isFalse(diffBatchQueryService.checkLotInBatch(sLot.getLotRrn()),
                           Errors.create().key(MessageIdList.LOT_IN_BATCH).content("Lot in batch!").build());

        }

        if (dummyBatch) {
            for (Object lot : lots) {
                Map lotInfo = (Map) lot;
                Lot sLot = lotQueryService.getLot(lotInfo.get("lotId").toString(), LocalContext.getFacilityRrn());
                Assert.isFalse(sLot.getOperationRrn().longValue() != firstNDlot.getOperationRrn().longValue(),
                               Errors.create().key(MessageIdList.LOT_JOB_OPERATION_NOT_SAME)
                                     .content("The lots operation in the job list are not the same!").build());

                Assert.isFalse(!firstNDlot.getRecipeId().equals(sLot.getRecipeId()) && !isAllDummy,
                               Errors.create().key(MessageIdList.LOT_JOB_RECIPE_NOT_SAME)
                                     .content("The lots recipe in the job list are not the same!").build());
            }
        }

        // check if the job's execution_rrn is valid
        Long executionRrn = job.getExecutionRrn();
        if (job.getJobStatus().equals(JobStatus.RUNNING) && job.getTransExecutionId().equals("MOVEIN") &&
                executionRrn != null && executionRrn > 0) {
            boolean existFlag = wipWorkflowQueryService.isExistExecutionRrn(executionRrn);
            if (!existFlag) {
                wipService.clearUpExecutionInfo(job.getJobRrn());
                job.setExecutionRrn(0L);
            }
        }


        // Step2: check if movout is needed(only when lot status is
        // running and execution does not exist)
        boolean moveInFlag = false;

        if (job.getJobStatus().equals(JobStatus.WAITING) || (job.getJobStatus().equals(JobStatus.HOLD) ||
                job.getJobStatus().equals(JobStatus.RUNNING) && (Long.parseLong(
                        StringUtils.isEmpty(MapUtils.getString(_lot, "executionRrn")) ? "0" : (String) _lot.get(
                                "executionRrn")) > 0))) {
            moveInFlag = true;
        }

        String wfl_type = "MOVEIN";

        // 获得PM信息
        Map holdPMMap = wipCheckService.validateEquipPMStatus(emsService.getEntity(new Entity(job.getEqptRrn())));
        String msg = StringUtils.EMPTY;
        String msgPMInfo = wipCheckService.validateEquipPMStatusReturnMsg(holdPMMap);
        if (moveInFlag) {
            if (Boolean.parseBoolean(MapUtils.getString(holdPMMap, "pmHold"))) {
                if (holdPMMap.get("checklistSize") != null) {
                    msg = I18nUtils.getMessage(MessageIdList.EQUIPMENT_PM_SUSPENDED, "该设备被PM暂停,不能加工批次!", msgPMInfo,
                                               (MapUtils.getString(holdPMMap, "checklistJobIds")));
                }
                throw new SystemIllegalArgumentException(Errors.create().content(msg).build());
            }
            if (holdPMMap.get("checklistSize") != null) {
                msg = msgPMInfo;
                if (holdPMMap.get("checklistSize") != null) {
                    msg += "\n" + ((String) holdPMMap.get("checklistJobIds")).replaceAll("<br>", "\n");
                }
                request.setAttribute("PM_CHECKLIST_INFO", msg);
            }
        } else {
            if (holdPMMap.get("checklistSize") != null) {
                msg = msgPMInfo + "\n";
                if (holdPMMap.get("checklistSize") != null) {
                    msg += ((String) holdPMMap.get("checklistJobIds")).replaceAll("<br>", "\n");
                }
                request.setAttribute("PM_CHECKLIST_INFO", msg);
            }
        }

        Long _eventRrn = 0L;
        Long abortEventRrn = 0L;
        String _wflRrn = "0";
        String abortWflRrn = "0";
        Long _operationRrn = job.getOperationRrn();

        Entity entity = new Entity();
        entity.setInstanceRrn(job.getEqptRrn());
        entity = emsService.getEntity(entity);
        if (moveInFlag) {
            _wflRrn = getWFLRrn(_operationRrn, "in", null);
            wfl_type = "MOVEIN";
        } else {
            _wflRrn = getWFLRrn(_operationRrn, "out", entity.getInstanceRrn());
            abortWflRrn = getWFLRrn(_operationRrn, "abort", null);
            wfl_type = "MOVEOUT";
        }

        Equipment equipment = emsService.getEquipment(job.getEqptRrn());
        boolean available = wipCheckService.checkEqptStatusAvailable(
                lotQueryService.getLot(MapUtils.getLongValue(_lot, "lotRrn")), equipment);
        Assert.isTrue(available,
                      Errors.create().content("The current state of EQP is not available, please confirm!").build());

        parameters.put("eqptRrn", String.valueOf(_lot.get("equipmentRrn")));
        parameters.put("abortEventRrn", (abortEventRrn == null) ? "1" : abortEventRrn.toString());
        parameters.put("abortWflRrn", abortWflRrn);
        parameters.put("operationRrn", String.valueOf(_lot.get("operationRrn")));
        parameters.put("operationVersion", String.valueOf(_lot.get("operationVersion")));// 2004-04-19 roy add
        parameters.put("recipeRrn", job.getRecipeString());
        parameters.put(SessionNames.WFL_RRN, _wflRrn);
        parameters.put(SessionNames.RUNSTEP_FLAG, "1");
        parameters.put(SessionNames.ROOT_WFL_EXEC_RRN, String.valueOf(_lot.get("lotExecutionRrn")));
        parameters.put(SessionNames.PARENT_WFL_EXEC_RRN, "0");
        parameters.put(SessionNames.RUNPARENTSTEP_FLAG, "0");
        parameters.put(SessionNames.WFL_EXEC_RRN,
                       ("null".equals(String.valueOf(_lot.get("executionRrn")))) ? "0" : String.valueOf(
                               _lot.get("executionRrn")));
        request.setAttribute(SessionNames.OBJECT_KEY, "equipment");

        if (StringUtils.isNotEmpty(request.getParameter("automovein"))) {
            parameters.put("automovein", request.getParameter("automovein"));
        } else if (StringUtils.isNotEmpty(request.getParameter("automoveout"))) {
            parameters.put("automoveout", request.getParameter("automoveout"));
        }

        request.setAttribute(SessionNames.MOVEDISABLE_FLAG_KEY, "TRUE");

        if (request.getParameter(Constants.MOVEIN_KEY) != null) {
            Assert.isTrue(wipCheckService.validJobSize(job), Errors.create().key(MessageIdList.EQUIPMENT_CURRENTLY_BUSY)
                                                                   .content("Equipment currently busy.").build());
        }

        // step2: prepare the parameters
        // 2.2reconstruct lots to show reticle combo box
        buildLotinfo(job, lots);


        parameters.put("comments", request.getParameter("comments"));// TODO comment??
        parameters.put("AttributeValue", job.getOperationRrn().toString() + "." + job.getEqptRrn().toString());

        String popDummyFlag = null;
        popDummyFlag = prpService.getOperation(job.getOperationRrn()).getPopDummyFlag();

        request.setAttribute(SessionNames.PARAMETERSINFO_KEY, parameters);
        fillRecipeInfo(lots);
        request.setAttribute(SessionNames.COLLECTION_KEY, lots);
        Boolean materialBondFlag = Boolean.FALSE;
        if (lots.size() > 1) {
            Collection buildLots = new ArrayList();
            for (Object o : lots) {
                Map lotMap = (Map) o;
                long productRrn = MapUtils.getLongValue(lotMap, "productRrn");
                String result = getObjectValue(productRrn, "FLD_BONDING");
                if (StringUtils.equals(result, Unit.BONDED_TYPE_KEY)) {
                    result = "D";
                } else if (StringUtils.equals(result, Unit.BY_BONDED_TYPE_KEY)) {
                    result = "H";
                } else {
                    result = "";
                }

                String sapphire = "";
                Operation operation = prpService.getOperation(MapUtils.getLongValue(lotMap, "operationRrn"));
                if (operation.isBondedOperation()) {
                    Lot lot = lotQueryService.getLot(MapUtils.getLongValue(lotMap, "lotRrn"));
                    boolean isSapphire = isSapphire(lots, lot);
                    if (isSapphire) {
                        sapphire = Sapphire.SAPPHIRE;
                    }
                    materialBondFlag = Boolean.TRUE;
                }

                lotMap.put("isSapphire", getIsSapphire(request, MapUtils.getString(lotMap, "lotId")));

                lotMap.put("sapphire", sapphire);
                lotMap.put("lotTypeBonded", result);
                buildLots.add(lotMap);
            }
            request.setAttribute(SessionNames.COLLECTION_KEY, buildLots);

        }
        if (materialBondFlag) {
            request.setAttribute("materialBondFlag", true);
        }else {
            request.setAttribute("materialBondFlag", false);
        }
        request.setAttribute("currentlots", lots);
        request.setAttribute(SessionNames.JOB_KEY, job);
        request.setAttribute("popDummyFlag", popDummyFlag);

        // step3: call workflow engine
        if (StringUtils.isEmpty(request.getParameter("automovein"))) {
            entity.setInstanceRrn(job.getEqptRrn());
            entity = emsService.getEntity(entity);
            if (StringUtils.equalsIgnoreCase(Constants.SEMI_AUTO_KEY, entity.getOperationMode())) {

            }
            String checkUser = getObjectValue(Long.parseLong(parameters.get("operationRrn") + ""), "FLD_CHECK_USER");
            if (!(StringUtils.isNotEmpty(checkUser) && StringUtils.equals(checkUser, "1"))) {
                request.getRequestDispatcher(mapping.findForward("workflow").getPath() + "?action=init")
                       .forward(request, response);
                return null;
            }
            return mapping.findForward("checkuser");
        } else {
            request.setAttribute("jobservice_flag", "false");
            request.setAttribute("workflow_flag", "true");
            return null;
        }
    }

}