ChangeLotRouteAction.java

package com.mycim.webapp.actions.lot.changeflow;

import com.fa.sesa.exception.Assert;
import com.fa.sesa.exception.Errors;
import com.fa.sesa.i18n.I18nUtils;
import com.fa.sesa.threadlocal.LocalContext;
import com.mycim.framework.utils.beans.BeanUtils;
import com.mycim.framework.utils.beans.PropertyUtils;
import com.mycim.framework.utils.lang.ObjectUtils;
import com.mycim.framework.utils.lang.StringUtils;
import com.mycim.framework.utils.lang.collections.MapUtils;
import com.mycim.framework.utils.lang.math.NumberUtils;
import com.mycim.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.bas.Relation;
import com.mycim.valueobject.consts.*;
import com.mycim.valueobject.ems.Carrier;
import com.mycim.valueobject.ems.pilot.PiLotView;
import com.mycim.valueobject.prp.Operation;
import com.mycim.valueobject.prp.ProcessSpecItemDto;
import com.mycim.valueobject.security.User;
import com.mycim.valueobject.sys.ReferenceFileDetail;
import com.mycim.valueobject.wip.BatchLotStore;
import com.mycim.valueobject.wip.Lot;
import com.mycim.valueobject.wip.LotStatus;
import com.mycim.valueobject.wip.TransReason;
import com.mycim.valueobject.wip.dto.LotProcessStepDto;
import com.mycim.webapp.WebUtils;
import com.mycim.webapp.actions.WipSetupAction;
import com.mycim.webapp.forms.RootForm;
import com.mycim.webapp.forms.lot.LotInfoForm;
import org.apache.commons.compress.utils.Sets;
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.*;

/**
 * @author shijie.deng
 * @version 6.0.0
 * @date 2019/9/21
 **/
public class ChangeLotRouteAction extends WipSetupAction {

    @Override
    public ActionForward init(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                              HttpServletResponse response) {
        long facilityRrn = LocalContext.getFacilityRrn();
        long userRrn = LocalContext.getUserRrn();
        // Populate the form bean instance
        if (form == null) {
            form = new RootForm();
            if ("request".equals(mapping.getScope())) {
                request.setAttribute(mapping.getAttribute(), form);
            }
        }

        RootForm theform = (RootForm) form;

        // Populate the new valid format id
        Lot lot = initLotBaseInfoForJsp(request, true, null, null);
        Carrier carrier = carrierService.getCarrier(lot.getCarrierRrn());
        Assert.isFalse(carrier == null || carrier.getInstanceRrn() <= 0,
                       Errors.create().key(MessageIdList.LOT_CARRIER_MISSING)
                             .content("Can not find this carrier of " + "Lot.").build());

        Assert.isFalse(StringUtils.equalsIgnoreCase(carrier.getObjectSubtype(), CarrierType.DUMMY) &&
                               lot.getAutoSplitMergFlag() != 1, Errors.create().key(MessageIdList.LOT_CARRIER_REMOVED)
                                                                      .content(
                                                                              "This carrier of Lot is already removed.")
                                                                      .build());

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

        boolean approveFlag = checkUserBtnByLotCategory(userRrn, facilityRrn, lot);
        Assert.isTrue(approveFlag, Errors.create().key(MessageIdList.SYSTEM_NO_PERMISSION_SKIP_LOT)
                                         .content("You do not have permission to Skip!").build());

        wipQueryService.checkActiveInlineOcapId(lot.getLotRrn());

        boolean pilotFlag = WebUtils.getParameterBoolean("pilotFlag", request);
        wipCheckService.checkPilotRepositionStep(lot, pilotFlag);
        if(pilotFlag) {
            request.setAttribute("lotRrn", lot.getLotRrn());
        }
        //check sortJob
        checkWaitJobs(lot.getCarrierRrn(), 0L, 0L, null);

        // added by Junfeng: Ignore the status--
        Assert.isFalse(lot.getLotStatus() == null || !lot.getLotStatus().equals(LotStatus.HOLD),
                       Errors.create().key(MessageIdList.SCRAPLOT_STATUS_NOT_ALLOW)
                             .content("Lot status must be " + "Hold!").build());

        //卡控post future hold被hold住的lot
        checkPostFutureHold(lot.getLotRrn());

        super.checkCstRemoved(Sets.newHashSet(lot.getLotRrn()));

        theform.setInstanceStatus(lot.getLotStatus());

        // populate lot information for next page
        LotInfoForm lotInfoForm = new LotInfoForm();
        PropertyUtils.copyProperties(lotInfoForm, lot);
        Map conditionMap = BeanUtils.copyBeanToMap(lot);
        lotInfoForm.setOperationDesc(ctxExecService.getOperationDescByProcessInfo(conditionMap));
        lotInfoForm.setRecipePhysicalId(getRecipePhysicalId(lot));
        lotInfoForm.setFlowSeq(ctxExecService.getFlowSeqByProcessInfo(conditionMap));

        String equipmentRrns = request.getParameter("avaliableEqtRrn");
        request.setAttribute("equipmentRrns", equipmentRrns);
        request.setAttribute("oldOperationRrn", lot.getOperationRrn());
        request.setAttribute(SessionNames.LOT_INFO_FORM_KEY, lotInfoForm);

        request.setAttribute("processId", lot.getProcessId());
        request.setAttribute("productId", lot.getProductId());
        request.setAttribute("productVersion", lot.getProductVersion());
        request.setAttribute("processVersion", lot.getProcessVersion());
        request.setAttribute("isRework", StringUtils.isNotBlank(lot.getReworkCategory()));

        if (lot.getReworkTransRrn() > 0) {
            request.setAttribute("isRework", "y");
        } else {
            request.setAttribute("isRework", "n");
        }
        request.setAttribute("executionRrn", lot.getExecutionRrn());
        String s_flag = request.getParameter("flag");
        if (s_flag != null) {
            request.setAttribute("cancelFlag", "Y");
        }
        request.setAttribute("skip_flag", s_flag);

        // futrue hold 查询
        Collection allFutureHoldInfos = getAllFutureHoldForLot(facilityRrn, lot);
        request.setAttribute(SessionNames.ALL_FUTUREHOLDLIST_KEY, allFutureHoldInfos);
        return new ActionForward(mapping.getInput());
    }

    public String checkTargetProcessInfo(Map<String, Object> theform) {

        String lotId = MapUtils.getString(theform, "lotId");
        long facilityRrn = LocalContext.getFacilityRrn();
        Lot lot = lotQueryService.getLot(lotId, facilityRrn);
        Map tempInfo = getStepsInfoByLot(lot, lot.getProcessRrn(), MapUtils.getString(theform, "stepNumber"));

        Long targetStepRrn = MapUtils.getLongValue(tempInfo, "operationRrn");
        Long targetRouRrn = parseRouteRrn((String) tempInfo.get("processStepVersion"));
        String skipFlag = getSkipFlag(lot, targetRouRrn, targetStepRrn);

        int processVersion = MapUtils.getIntValue(tempInfo, "processVersion");

        Lot lotTemp = new Lot();
        BeanUtils.copyProperties(lot, lotTemp);
        lotTemp.setProcessStepVersion(MapUtils.getString(tempInfo, "processStepVersion"));// For RouteRrn
        lotTemp.setOperationRrn(targetStepRrn);

        checkIfProcessLocationIsSame(lot, targetStepRrn, targetRouRrn);

        //check flip
        ProcessSpecItemDto psi = processSpecService.queryProcessSpecItem(
                new ProcessSpecItemDto(lot.getProcessRrn(), lot.getProcessVersion(), targetRouRrn, targetStepRrn));
        this.checkFlip4LotAndFlow(lot, psi);

        StringBuilder sb = new StringBuilder();
        buildSpecialStepInfo(lot, skipFlag, targetRouRrn, targetStepRrn, processVersion, sb);

        Operation operation = prpService.getOperation(targetStepRrn);
        boolean isEqptAvailable = isSamePollutionLevel(operation.getEntityGroupRrn(), lot);

        if (!isEqptAvailable) {
            //TODO : csv
            sb.append(I18nUtils.getMessage("lot.pollution_level_mismatch",
                                           "No eqpt available or pollution level matches in target step! " + "<br>"));
        }
        return sb.toString();
    }

    public ActionForward saveChangeRoute(ActionMapping mapping, RootForm theform, HttpServletRequest request) {
        long facilityRrn = LocalContext.getFacilityRrn();
        String userId = LocalContext.getUserId();
        long userRrn = LocalContext.getUserRrn();


        String lotId = request.getParameter("lotId");
        Lot lot = lotQueryService.getLot(lotId, facilityRrn);
        Map tempInfo = getStepsInfoByLot(lot, lot.getProcessRrn(), request.getParameter("stepNumber"));

        Long targetStepRrn = MapUtils.getLongValue(tempInfo, "operationRrn");
        Long targetRouRrn = parseRouteRrn((String) tempInfo.get("processStepVersion"));
        Carrier carrier = carrierService.getCarrier(lot.getCarrierRrn());
        Assert.isFalse(carrier == null || carrier.getInstanceRrn() <= 0,
                       Errors.create().key(MessageIdList.LOT_CARRIER_MISSING)
                             .content("Can not find this carrier of " + "Lot.").build());

        Assert.isFalse(StringUtils.equalsIgnoreCase(carrier.getObjectSubtype(), CarrierType.DUMMY) &&
                               lot.getAutoSplitMergFlag() != 1, Errors.create().key(MessageIdList.LOT_CARRIER_REMOVED)
                                                                      .content(
                                                                              "This carrier of Lot is already removed.")
                                                                      .build());

        Assert.isFalse(lot.getLotStatus() == null || !lot.getLotStatus().equals(LotStatus.HOLD),
                       Errors.create().key(MessageIdList.SCRAPLOT_STATUS_NOT_ALLOW)
                             .content("Lot status must be " + "Hold!").build());

        Assert.isFalse(lotStatusCheckService.hasValidRcHold(lot),
                       Errors.create().content("Lot has valid RunCard!").build());

        //checkIfProcessLocationIsSame(lot, targetStepRrn, targetRouRrn);

        //check flip
        ProcessSpecItemDto psi = processSpecService.queryProcessSpecItem(
                new ProcessSpecItemDto(lot.getProcessRrn(), lot.getProcessVersion(), targetRouRrn, targetStepRrn));
        this.checkFlip4LotAndFlow(lot, psi);

        //check sortJob
        checkWaitJobs(lot.getCarrierRrn(), 0L, 0L, null);

        Map changeProcessInfo = null;

        changeProcessInfo = new HashMap();
        changeProcessInfo.put("lotRrn", new Long(lot.getLotRrn()));
        changeProcessInfo.put("lotId", lot.getLotId());
        changeProcessInfo.put("lotStatus", lot.getLotStatus());
        changeProcessInfo.put("qty", "" + lot.getQty1());
        changeProcessInfo.put("lotOwner", lot.getLotOwner());
        changeProcessInfo.put("currOperation", lot.getOperationId());
        changeProcessInfo.put("transPerformedBy", userId);
        changeProcessInfo.put("productRrn", lot.getProductRrn());
        changeProcessInfo.put("productId", lot.getProductId());

        changeProcessInfo.put("processRrn", lot.getProcessRrn());

        // check if technology is valid for product specified
        String stepNumber = request.getParameter("stepNumber");
        if (!stepNumber.contains("|")) {
            changeProcessInfo.put("reworkSkip", "reworkSkip");
        }

        //卡控lot当前站为pilot起始站P站不允许跳过
        checkPilotRepositionStep(lot);


        Boolean isFirstStepInProcess = prpService.isFirstStepInProcess(
                MapUtils.getLongValue(changeProcessInfo, "productRrn"),
                MapUtils.getLongValue(changeProcessInfo, "processRrn"),
                MapUtils.getIntValue(changeProcessInfo, "processVersion"), targetRouRrn, targetStepRrn);

        Assert.isFalse(isFirstStepInProcess, Errors.create().key(MessageIdList.LOT_CANT_SKIP_TO_FIRST_STEP)
                                                   .content("Can't skip to the first step of the process!").build());
        changeProcessInfo.put("stageId", tempInfo.get("stageId"));
        changeProcessInfo.put("layerId", tempInfo.get("layerId"));
        changeProcessInfo.put("executionRrn", tempInfo.get("executionRrn"));
        changeProcessInfo.put("operationRrn", tempInfo.get("operationRrn"));

        Long operationRrn = (Long) tempInfo.get("operationRrn");

        Assert.isTrue(checkOperationInFacility(operationRrn, facilityRrn),
                      Errors.create().key(MessageIdList.STEP_NOT_IN_CURRENT_FACILITY)
                            .content("The new subplan/step " + "is not in current " + "facility!").build());
        changeProcessInfo.put("operationId", getInstanceId(((Long) tempInfo.get("operationRrn")).longValue()));

        changeProcessInfo.put("operationVer", tempInfo.get("operationVer"));
        changeProcessInfo.put("processStepVersion", tempInfo.get("processStepVersion"));
        //changeProcessInfo.put("processVersion", tempInfo.get("processVersion"));
        changeProcessInfo.put("processVersion", lot.getProcessVersion());

        changeProcessInfo.put("processStepIdVersion", tempInfo.get("processStepIdVersion"));
        changeProcessInfo.put("processStepVersion4wfl", tempInfo.get("processStepVersion4wfl"));
        changeProcessInfo.put("nextoperationRrn1", tempInfo.get("nextoperationRrn1"));
        changeProcessInfo.put("nextoperationRrn2", tempInfo.get("nextoperationRrn2"));
        changeProcessInfo.put("nextprocessStepVersion1", tempInfo.get("nextprocessStepVersion1"));
        changeProcessInfo.put("nextprocessStepIdVersion1", tempInfo.get("nextprocessStepIdVersion1"));
        changeProcessInfo.put("nextprocessStepVersion2", tempInfo.get("nextprocessStepVersion2"));
        changeProcessInfo.put("nextprocessStepIdVersion2", tempInfo.get("nextprocessStepIdVersion2"));

        String temp = (String) tempInfo.get("processStepVersion");
        String route = "";

        if (temp != null) {
            int i = 0;
            int j = 0;
            i = temp.indexOf("|");

            // find first '|'
            if (i != -1) {
                j = temp.indexOf("|", i + 1);

                // find se '|'
                // string is aaa|bbb|cccc
                if (j > 0) {
                    route = temp.substring(i + 1, j);
                } else if (i > 0) { // aaa|bbb
                    route = temp.substring(0, i);
                }
            }
        }

        route = route.replace(',', '.');
        changeProcessInfo.put("route", route);
        Operation operation = prpService.getOperation(MapUtils.getLong(tempInfo, "operationRrn"));
        changeProcessInfo.put("trackUnitFlag", operation.getTrackUnitFlag());
        changeProcessInfo.put("keepUnitHistoryFlag", operation.getKeepUnitHistoryFlag());

        // get Context info
        tempInfo = new HashMap();
        tempInfo.put("productRrn", changeProcessInfo.get("productRrn"));
        // tempInfo.put("routeId", null);
        tempInfo.put("routeRrn", parseRouteRrn(MapUtils.getString(changeProcessInfo, "processStepVersion")));
        tempInfo.put("recipeRrn", null);
        tempInfo.put("operationRrn", changeProcessInfo.get("operationRrn"));
        tempInfo.put("technologyRrn", changeProcessInfo.get("processRrn"));
        tempInfo.put("lotRrn", changeProcessInfo.get("lotRrn"));
        tempInfo.put("facilityRrn", lot.getFacilityRrn());
        tempInfo.put("isOverrideConstrain", theform.isTargetCheckEquipConstrain());
        tempInfo.put("userRrn", userRrn);
        tempInfo.put("processStepVersion", changeProcessInfo.get("processStepVersion"));

        changeProcessInfo.put("borRrn", ctxExecService.getBomRrn(tempInfo));

        changeProcessInfo.put("reticleRrn", tempInfo.get("reticleRrn")); // to do

        changeProcessInfo.put("transPerformedBy", userId);
        changeProcessInfo.put("transComments", request.getParameter("comments"));
        // add for fmi reason code
        String userRRN = theform.getUserRrn();
        User userEntity = securityService.getUser(Long.parseLong(userRRN));
        String reason = theform.getReasonCode() + " " + theform.getDeptExt().trim().toUpperCase() + " " +
                userEntity.getUserName() + " " + theform.getReason();
        TransReason transReason = new TransReason();
        transReason.setReasonCode(theform.getReasonCode());
        transReason.setReason(reason);
        transReason.setTransQty1(lot.getQty1());
        transReason.setTransQty2(lot.getQty2());
        transReason.setResponsibility(userId);
        changeProcessInfo.put("transReason", transReason);
        String skipFlag = getSkipFlag(lot, targetRouRrn, targetStepRrn);
        // after the workstream
        if ("before".equals(skipFlag)) {
            changeProcessInfo.put("changeflow", "before");
        } else if ("after".equals(skipFlag)) {
            changeProcessInfo.put("changeflow", "after");
        }
        // List<Lot> lockLots = new ArrayList<Lot>();
        // lockLots.add(lot);
        // checkAndCreateLotsTransLock(LocalContext.getUserRrn(), TransactionNames.LOCK_CHANGE_ROUTE, lockLots,
        //                             "change route in ChangeLotRouteAction by " + userId);

        //额外添加 为了让后面的操作下沉到 sercie
        changeProcessInfo.put("actionFlag", "ChangeLotRouteAction");
        changeProcessInfo.put("formStatus", theform.getInstanceStatus());
        changeProcessInfo.put("oldOperationRrn", request.getParameter("oldOperationRrn"));
        //end
        try {
            lotService.changeLotProcess(changeProcessInfo);
            // removeLotLock(userRrn, lot, TransactionNames.LOCK_CHANGE_ROUTE,
            //               "Delete change route is ChangeLotRouteAction by:" + userId);
        } catch (Exception e) {
            // removeLotLockWhenTransError(userRrn, lockLots, TransactionNames.LOCK_CHANGE_ROUTE,
            //                             "Delete change route is ChangeLotRouteAction by:" + userId);
            throw e;
        }

        // String lotStatus = theform.getInstanceStatus();
        //
        // lot = lotQueryService.getLot(lot.getLotRrn());
        //
        // if (lotStatus.equals(LotStatus.HOLD) && !lot.getLotStatus().equals(LotStatus.TERMINATED)) {
        //     lotService.updateLotStatus(lot.getLotRrn(), "HOLD");
        // } else if (lotStatus.equals(LotStatus.BANKED)) {
        //     lotService.updateLotStatus(lot.getLotRrn(), LotStatus.BANKED);
        // }
        // if (lotStatus.equals(LotStatus.BANKED)) {
        //     String oldOperationRrn = request.getParameter("oldOperationRrn");
        //     lotService.updateLotOperationRrn(lot.getLotRrn(), Long.parseLong(oldOperationRrn),
        //                                      (Long) changeProcessInfo.get("operationRrn"));
        // }
        // 处理覆盖机限
        //TODO:暂时不要
        //            handleOverrideConstrain(tempInfo);

        return (mapping.findForward("lotlocation"));
    }

    private void checkIfProcessLocationIsSame(Lot lot, Long targetOperationRrn, Long targetRouteRrn) {
        // 获取 类表中 所有 XX TO YY 中的 YY
        List<ReferenceFileDetail> referenceFileDetails = getReferenceFileDetails(
                ReferenceDetailNames.PROCESS_LOCARION_CARRIER_TYPE);
        List<String> processLocations = new ArrayList<>();
        for (ReferenceFileDetail referenceFileDetail : referenceFileDetails) {
            String afterProcessLocation = ProcessLocationConst.getAfterProcessLocation(referenceFileDetail.getKey1Value());
            if (StringUtils.isNotBlank(afterProcessLocation)) {
                processLocations.add(afterProcessLocation);
            }
        }

        LotProcessStepDto targetProcessStep = new LotProcessStepDto();

        targetProcessStep.setProductRrn(lot.getProductRrn());
        targetProcessStep.setProductVersion(lot.getProductVersion());
        targetProcessStep.setProcessRrn(lot.getProcessRrn());
        targetProcessStep.setProcessVersion(lot.getProcessVersion());
        targetProcessStep.setRouteRrn(targetRouteRrn);
        targetProcessStep.setOperationRrn(targetOperationRrn);

        String targetProcessLocation = lotInqService.getProcessLocation(targetProcessStep);
        // 如果目标processLocation 与 集合中匹配 则跳过 processLocation 校验
        for (String processLocation : processLocations) {
            if (StringUtils.equalsIgnoreCase(processLocation, targetProcessLocation)) {
                return;
            }
        }

        Assert.isTrue(wipCheckService.isSameProcessLocation(lot, targetProcessStep),
                      Errors.create().content("Process location not match !<br>").build());
    }

    private void buildSpecialStepInfo(Lot lot, String type, Long targetRouRrn, Long targetStepRrn, int processVersion,
                                      StringBuilder sb) {

        List<Map<String, Object>> allProcessStep = prpService.getProcessAllStepInfo(lot.getProcessRrn(), processVersion,
                                                                                    null, null, new Long(99999), null,
                                                                                    null, 0);
        Long operationRrn = lot.getOperationRrn();
        Long routeRrn = lot.getRouteRrn();
        String operationSeq = lot.getOperationSeq();
        boolean currentStepFlag = false;
        boolean targetStepFlag = false;

        for (int i = 0; i < allProcessStep.size(); i++) {
            Map<String, Object> mainProStep = allProcessStep.get(i);
            Long tempOperationRrn = MapUtils.getLong(mainProStep, "operationRrn");
            Long tempRouteRrn = MapUtils.getLong(mainProStep, "routeRrn");
            String stepSeq = MapUtils.getString(mainProStep, "operationRouteSeq");
            String stepNumber = MapUtils.getLong(mainProStep, "processRrn") + "." +
                    MapUtils.getIntValue(mainProStep, "processVersion") + "." +
                    MapUtils.getLong(mainProStep, "routeStepRrn") + "|" + MapUtils.getLong(mainProStep, "routeRrn") +
                    "." + MapUtils.getIntValue(mainProStep, "routeVersion") + "." +
                    MapUtils.getLong(mainProStep, "operationStepRrn");
            mainProStep.put("stepNumber", stepNumber);
            mainProStep.put("stepPath", stepNumber);
            mainProStep.put("routeSeq", MapUtils.getString(mainProStep, "routeProcessSeq"));
            mainProStep.put("operationSeq", MapUtils.getString(mainProStep, "operationRouteSeq"));
            mainProStep.put("productRrn", lot.getProductRrn());

            if (StringUtils.equalsIgnoreCase("before", type)) {

                if (currentStepFlag) {
                    break;
                }
                if (targetStepFlag) {
                    buildSpecialStepInfo(tempOperationRrn, sb);
                } else {
                    targetStepFlag = targetStepRrn.longValue() == tempOperationRrn.longValue() &&
                            targetRouRrn.longValue() == tempRouteRrn.longValue();
                }
                currentStepFlag = (operationRrn.longValue() == tempOperationRrn.longValue() &&
                        routeRrn.longValue() == tempRouteRrn.longValue() &&
                        StringUtils.equalsIgnoreCase(operationSeq, stepSeq));

            }
            if (StringUtils.equalsIgnoreCase("after", type)) {

                targetStepFlag = targetStepRrn.longValue() == tempOperationRrn.longValue() &&
                        targetRouRrn.longValue() == tempRouteRrn.longValue();
                if (targetStepFlag) {
                    break;
                }
                if (currentStepFlag) {
                    buildSpecialStepInfo(tempOperationRrn, sb);
                } else {
                    currentStepFlag = (operationRrn.longValue() == tempOperationRrn.longValue() &&
                            routeRrn.longValue() == tempRouteRrn.longValue() &&
                            StringUtils.equalsIgnoreCase(operationSeq, stepSeq));
                }

            }

        }

        if (sb.length() > 0) {
            sb.insert(0, "Following steps are special step:<br>");
        }

    }

    private void buildSpecialStepInfo(Long tempOperationRrn, StringBuilder sb) {
        Operation operation = prpService.getOperation(tempOperationRrn);

        if (operation.isPlainStep()) {
            return;
        }

        if (StringUtils.equals(operation.getMvinWflId(), TransRoutineNames.MOVEIN_BONDED_STD) &&
                StringUtils.equals(operation.getMvouWflId(), TransRoutineNames.MOVEOUT_AUTOBONDED_STD)) {
            sb.append(operation.getInstanceId() + " is bond step! <br> ");

        }

        if (StringUtils.equals(operation.getMvinWflId(), TransRoutineNames.MOVEIN_STD) &&
                StringUtils.equals(operation.getMvouWflId(), TransRoutineNames.MOVEOUT_AUTODEBONDED_STD)) {
            sb.append(operation.getInstanceId() + " is debond step! <br> ");

        }
        if (StringUtils.equals(operation.getMvinWflId(), TransRoutineNames.MOVEIN_STD) &&
                StringUtils.equals(operation.getMvouWflId(), TransRoutineNames.MOVEOUT_STD_TERMINATE)) {
            sb.append(operation.getInstanceId() + " is terminate step! <br> ");

        }

        if (StringUtils.equals(operation.getMvinWflId(), TransRoutineNames.MOVEIN_STD) &&
                StringUtils.equals(operation.getMvouWflId(), TransRoutineNames.MOVEOUT_TAPE_STD)) {
            sb.append(operation.getInstanceId() + " is tape step! <br> ");

        }
    }

    private String getSkipFlag(Lot lot, Long targetRouRrn, Long targetStepRrn) {
        String s_flag = null;
        long facilityRrn = LocalContext.getFacilityRrn();
        Map<String, Object> processInfoMap = new HashMap<String, Object>();
        processInfoMap.put("facilityRrn", facilityRrn);
        processInfoMap.put("processRrn", lot.getProcessRrn());
        processInfoMap.put("processVersion", lot.getProcessVersion());
        processInfoMap.put("routeRrn", lot.getRouteRrn());
        processInfoMap.put("operationRrn", lot.getOperationRrn());
        String currentFlowSeqStr = ctxExecService.getFlowSeqByProcessInfo(processInfoMap);
        currentFlowSeqStr = StringUtils.join(StringUtils.split(currentFlowSeqStr, StringUtils.POINT_SIGN), "");


        processInfoMap = new HashMap<String, Object>();
        processInfoMap.put("facilityRrn", facilityRrn);
        processInfoMap.put("processRrn", lot.getProcessRrn());
        processInfoMap.put("processVersion", lot.getProcessVersion());
        processInfoMap.put("routeRrn", targetRouRrn);
        processInfoMap.put("operationRrn", targetStepRrn);
        String targetFlowSeqStr = ctxExecService.getFlowSeqByProcessInfo(processInfoMap);
        targetFlowSeqStr = StringUtils.join(StringUtils.split(targetFlowSeqStr, StringUtils.POINT_SIGN), "");

        Integer currentFlowSeq = (Integer) NumberUtils.parseNumber(currentFlowSeqStr, Integer.class);
        Integer targetFlowSeq = (Integer) NumberUtils.parseNumber(targetFlowSeqStr, Integer.class);
        if (currentFlowSeq > targetFlowSeq) {
            s_flag = "before";
        } else {
            s_flag = "after";
        }
        return s_flag;
    }

    protected boolean checkUserBtnByLotCategory(long userRrn, Long facilityRrn, Lot lot) {
        String btnId = "";
        if (StringUtils.equalsIgnoreCase("C", lot.getCreateCategory())) {
            btnId = "SKIP_FOR_DUMMY";
        } else {
            btnId = "SKIP_FOR_PRO";
        }
        long buttonRrn = getInstanceRrn(btnId, facilityRrn, ObjectList.BUTTON_KEY);
        List<Relation> roles = baseService.getRelationsUseFromRrn(userRrn, LinkTypeList.USER_ROLE_KEY);
        List<Relation> userGroup = baseService.getRelationsUseFromRrn(userRrn, LinkTypeList.USER_USERGROUP_KEY);
        for (Relation relation : userGroup) {
            roles.addAll(baseService.getRelationsUseFromRrn(relation.getToRrn(), LinkTypeList.USERGROUP_ROLE_KEY));
        }
        Iterator<Relation> res = roles.iterator();
        boolean approveFlag = false;
        while (res.hasNext()) {
            Relation relation = res.next();
            relation.setLinkType(LinkTypeList.ROLE_TO_BUTTON_KEY);
            relation.setFromRrn(relation.getToRrn());
            relation.setToRrn(buttonRrn);
            relation = baseService.getRelation(relation);
            if (relation != null) {
                approveFlag = true;
                break;
            }
        }
        return approveFlag;
    }

    //卡控lot当前站为pilot起始站P站不允许跳过
    private void checkPilotRepositionStep(Lot lot) {
        PiLotView view = new PiLotView();
        if (lot.getLotRrn() == lot.getBasedLotRrn()) {
            view = wipQueryService.getPiLotViewByLotRrn(lot.getBasedLotRrn());
        } else {
            view = wipQueryService.getPiLotViewByChildLotRrn(lot.getLotRrn());
        }

        if (ObjectUtils.isNotEmpty(view)) {
            Assert.state(!(StringUtils.equalsIgnoreCase(lot.getRouteId(),view.getStartRoute())
                                 && StringUtils.equalsIgnoreCase(lot.getOperationId(),view.getStartStep())),
                         Errors.create().key(MessageIdList.PILOT_REPOSITION_STEP_ERROR)
                           .content("Pilot reposition step cannot skip the pilot start station P!").build());
        }
    }

}