NpwEasyForManualAction.java

package com.mycim.webapp.actions.npwlotwork;

import com.fa.sesa.exception.Assert;
import com.fa.sesa.exception.Errors;
import com.fa.sesa.exception.SystemIllegalArgumentException;
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.utils.lang.time.DateUtils;
import com.mycim.framework.utils.msg.JsonUtils;
import com.mycim.server.prp.service.PrpService;
import com.mycim.server.wip.service.DiffBatchQueryService;
import com.mycim.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.SystemConstant;
import com.mycim.valueobject.bas.Relation;
import com.mycim.valueobject.consts.ActionPointList;
import com.mycim.valueobject.consts.EventName;
import com.mycim.valueobject.consts.LinkTypeList;
import com.mycim.valueobject.consts.TransactionNames;
import com.mycim.valueobject.edcspc.*;
import com.mycim.valueobject.edcspc.rule.CollectionRule;
import com.mycim.valueobject.ems.Entity;
import com.mycim.valueobject.ems.Equipment;
import com.mycim.valueobject.prp.EqpMonitorLotSpecialStep;
import com.mycim.valueobject.prp.EqpMonitorUnitSpecialStep;
import com.mycim.valueobject.prp.Recipe;
import com.mycim.valueobject.prp.RecipeVersion;
import com.mycim.valueobject.security.User;
import com.mycim.valueobject.wip.*;
import com.mycim.valueobject.wip.dto.*;
import com.mycim.webapp.Constants;
import com.mycim.webapp.WebUtils;
import com.mycim.webapp.actions.NpwSetupAction;
import com.mycim.webapp.forms.LotInfoFormNpw;
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.lang.reflect.Constructor;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author shijie.deng
 * @version 6.0.0
 * @date 2019/11/20
 **/
public class NpwEasyForManualAction extends NpwSetupAction {

    private static final String ACCOUNTSTEPEND = "DMM-NO-ACCOUNT-STEP-END";

    protected DiffBatchQueryService diffBatchQueryService = SpringContext.getBean(DiffBatchQueryService.class);

    public ActionForward openRecipeSetPage(ActionMapping mapping, LotInfoFormNpw theform, HttpServletRequest request,
                                           HttpServletResponse response) {
        Long lotRrn = NumberUtils.toLong(request.getParameter("lotRrn"));
        Long lotSpecialStepRrn = NumberUtils.toLong(request.getParameter("lotSpecialStepRrn"));
        String recipeList = request.getParameter("recipeList");

        List<EqpMonitorUnitSpecialStep> list = dmmLotService.getUnitSpecialStepList(lotSpecialStepRrn);

        if (StringUtils.isBlank(recipeList)) {
            Map<String, String> map = new HashMap<String, String>();
            for (EqpMonitorUnitSpecialStep step : list) {
                map.put(step.getUnitRrn() + "", step.getRecipeStr());
            }
            recipeList = JsonUtils.toString(map);
        } else {
            recipeList = StringUtils.replace(recipeList, "\\", "\\\\");
            Map map = JsonUtils.toMap(recipeList);
            for (EqpMonitorUnitSpecialStep step : list) {
                String recipeStr = MapUtils.getString(map, step.getUnitRrn() + "");
                step.setRecipeStr(recipeStr);
            }
        }

        request.setAttribute("unitList", list);
        request.setAttribute("recipeList", recipeList);
        request.setAttribute("lotRrn", lotRrn);

        return mapping.findForward("recipe");
    }

    public ActionForward transMoveout(ActionMapping mapping, LotInfoFormNpw theform, HttpServletRequest request,
                                      HttpServletResponse response) throws Exception {

        long facilityRrn = LocalContext.getFacilityRrn();
        String userId = LocalContext.getUserId();
        String facilityId = LocalContext.getFacilityId();

        String eqptId = request.getParameter("eqptId");
        long eqptRrn = getInstanceRrn(eqptId, facilityRrn, ObjectList.ENTITY_KEY);
        Assert.isFalse(eqptRrn <= 0,
                       Errors.create().key(MessageIdList.EQUIPMENT_MISSING_ID).content("Equipment does not exist")
                             .build());

        String lotId = request.getParameter("lotId");
        Lot lot = lotQueryService.getLot(lotId, facilityRrn);

        //检查批次状态
        Assert.isFalse(StringUtils.equals(lot.getLotStatus(), LotStatus.FINISH) ||
                               StringUtils.equals(lot.getLotStatus(), LotStatus.HOLD) ||
                               StringUtils.equals(lot.getLotStatus(), LotStatus.RUNNINGHOLD) ||
                               StringUtils.equals(lot.getLotStatus(), LotStatus.TERMINATED) ||
                               StringUtils.equals(lot.getLotStatus(), LotStatus.SCRAPPED),
                       Errors.create().key(MessageIdList.LOT_STATUS_CANT_MOVEOUT)
                             .content("Lot:{} status is {} ,can't move out!").args(lot.getLotId(), lot.getLotStatus())
                             .build());

        List<Lot> lotInfos = new ArrayList<Lot>();
        lotInfos.add(lot);
        List<LotInfoDto> lotInfoDtos = new ArrayList<LotInfoDto>();
        LotInfoDto lotInfoDto = new LotInfoDto();
        Map<String, Object> lotBaseInfo = new HashMap<String, Object>();

        lotBaseInfo.put("facilityRrn", facilityRrn);
        lotBaseInfo.put("lotId", lotId);
        lotBaseInfo.put("lotRrn", lot.getLotRrn());
        lotBaseInfo.put("qty1", lot.getQty1());
        lotBaseInfo.put("reticleGroupId", lot.getReticleGroupId());
        lotBaseInfo.put("reticleGroupRrn", lot.getReticleGroupRrn());
        lotBaseInfo.put("reticleId", lot.getRecipeId() == null ? "" : lot.getRecipeId());

        EqpMonitorLotSpecialStep lotSpecialStep = dmmLotService
                .getDMMLotSpecialStepByOperation(lot.getOperationRrn(), lot.getLotRrn());


        LotStepHistory lotStepHistory = lotQueryService.getLotStepHistory(lot.getLotRrn(), lot.getStepSequence());

        if (lotSpecialStep != null) {
            List<EqpMonitorUnitSpecialStep> unitList = dmmLotService
                    .getUnitSpecialStepList(lotSpecialStep.getLotSpecialStepRrn());

            if (StringUtils.isNotBlank(lotSpecialStep.getParameterSetId()) &&
                    StringUtils.isNotBlank(request.getParameter("decide")) &&
                    (lotStepHistory.getAdHocDcolRrn() == null || lotStepHistory.getAdHocDcolRrn() < 1)) {
                Map<String, String> lotInfo = getLotInfo(lot, lotSpecialStep);
                lotInfo.put("eqptId", eqptId);
                lotInfo.put("carrierId", lot.getCarrierId());
                lotInfo.put("parameterId", lotSpecialStep.getParameterId());
                request.setAttribute("lotInfo", lotInfo);
                return initEdc(mapping, theform, request, response, lotSpecialStep.getParameterSetId(), lotInfos);
            }

            lotSpecialStep.setLotId(lot.getLotId());

            String recipeStr = lotSpecialStep.getRecipeStr();
            if (!StringUtils.contains(recipeStr, ",")) {
                lotBaseInfo.put("ppid", theform.getRecipeId());
                lotBaseInfo.put("recipePhysicalId", theform.getRecipeId());
                lotBaseInfo.put("recipeLogicalRrn", theform.getRecipeRrn());
            } else {
                lotBaseInfo.put("ppid", "");
                lotBaseInfo.put("recipePhysicalId", "");
                lotBaseInfo.put("recipeLogicalRrn", "");
            }
            lotBaseInfo.put("chamberType", theform.getChamberType());
            if (StringUtils.isNotBlank(lotSpecialStep.getParameterSetId()) &&
                    (lotStepHistory.getAdHocDcolRrn() == null || lotStepHistory.getAdHocDcolRrn() < 1)) {
                List<Map> collection = (List<Map>) WebUtils.getCacheString2Obj(theform.getCacheCollection());
                if (CollectionUtils.isNotEmpty(collection)) {
                    Map map = collection.get(0);
                    lotInfoDto.setParameterSet(
                            buildParameterSetDto(theform, request, (List) map.get("parameterSetVersions"), lot));
                }
            }
        }

        LotBaseInfoDto lotBaseInfoDto = new LotBaseInfoDto();
        BeanUtils.copyMapToBean(lotBaseInfoDto, lotBaseInfo);
        lotInfoDto.setLotBaseInfo(lotBaseInfoDto);
        lotInfoDtos.add(lotInfoDto);
        Equipment equipment = new Equipment(eqptId, getNamedSpace(ObjectList.ENTITY_KEY, LocalContext.getFacilityRrn()),
                                            ObjectList.ENTITY_KEY);
        //判断是否是手动batch move in
        List<BatchLotStore> lotInBatch = diffBatchQueryService.getBatchStoreListByLot(lot.getLotRrn());
        if (CollectionUtils.isEmpty(lotInBatch)) {
            dmmLotService.dispatchLot(lotInfos, emsService.getEquipment(equipment), lotInfoDtos);
        } else {
            manualBatchDispatch(lotInfos, lotInBatch, emsService.getEquipment(equipment), lotInfoDtos,
                                ActionPointList.MOVEOUT_KEY);
        }
        Lot movedLot = lotQueryService.getLot(lot.getLotRrn());
        EqpMonitorLotSpecialStep lotSpecialStepNext = dmmLotService
                .getDMMLotSpecialStepByOperation(movedLot.getOperationRrn(), movedLot.getLotRrn());
        if (lotSpecialStepNext == null) {
            //dmm流程最后一步
            request.setAttribute("dmmEndSuccessed", "1");
        } else {
            //dmm出站
            WebUtils.setSuccessMsg(request, "dmm.lot_already_track_out", "Lot already track out!");
        }
        return init(mapping, theform, request, response);
    }

    @Override
    public ActionForward init(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                              HttpServletResponse response) throws Exception {
        LotInfoFormNpw theform = (LotInfoFormNpw) form;
        if (TransactionNames.ADJUST_RECIPE_BY_OPERATION.equalsIgnoreCase(theform.getTransId())) {
            return initAdjustRecipe(mapping, form, request, response);
        }
        String carrierId = StringUtils.trimToUpperCase(request.getParameter("carrierId"));
        if ("operate_panel".equals(request.getParameter("operate_panel"))) {
            request.setAttribute("operate_panel", "operate_panel");
        }
        theform.setTransId(Constants.INIT_KEY);
        if (StringUtils.isNotBlank(carrierId)) {
            Lot lot = lotQueryService.getLotByCarrierId(carrierId, LocalContext.getFacilityRrn());
            Assert.isFalse(lot == null || lot.getLotRrn() < 1,
                           Errors.create().key(MessageIdList.DELETELOT_CASSETTE_SIZE_LOT)
                                 .content("Carrier is not used!").build());
            //如果是炉管陪片则需要展示产品批次信息
            List<BatchLotStore> lotInBatch = diffBatchQueryService.getBatchStoreListByLot(lot.getLotRrn());

            Map condition = new HashMap();
            condition.put("lotId", lot.getLotId());
            List<NpwBank> bankInfos = lotQueryService.getNPWBankLot(condition);

            Assert.isFalse(!dmmLotService.isMonitorLot(lot) && CollectionUtils.isEmpty(lotInBatch) &&
                                   CollectionUtils.isEmpty(bankInfos),
                           Errors.create().key(MessageIdList.LOT_NOT_BATCHED_CANT_OPERATE)
                                 .content("Lot not create batched,can't " + "operate!").build());
            if (CollectionUtils.isNotEmpty(lotInBatch)) {
                List<Lot> productLots = new ArrayList<Lot>();
                Long monitorLotRrn = null;
                for (BatchLotStore inBatch : lotInBatch) {
                    Long lotRrn = inBatch.getLotRrn();
                    Lot productLot = lotQueryService.getLot(lotRrn);
                    productLots.add(productLot);
                    monitorLotRrn = inBatch.getMonitorLotRrn();
                }
                request.setAttribute("productLots", productLots);
                //如果输入的是产品的lot,但是界面最终还是展示配片的lot作业信息
                if (monitorLotRrn != null) {
                    lot = lotQueryService.getLot(monitorLotRrn);
                }
            }
            theform.setCarrierId(lot.getCarrierId());
            String stauts = lot.getLotStatus();
            Long operationRrn = lot.getOperationRrn();
            EqpMonitorLotSpecialStep lotSpecialStep = dmmLotService
                    .getDMMLotSpecialStepByOperation(operationRrn, lot.getLotRrn());

            Map<String, String> lotInfo = getLotInfo(lot, lotSpecialStep);
            if (lotSpecialStep != null) {
                if (StringUtils.equalsIgnoreCase(LotStatus.RUNNING, stauts) ||
                        StringUtils.equalsIgnoreCase(LotStatus.RUNNINGHOLD, stauts) ||
                        StringUtils.equalsIgnoreCase(LotStatus.PROCESSED, stauts)) {
                    lotInfo.put("eqptId", getInstanceId(lot.getEqptRrn()));
                    theform.setTransId(Constants.MOVEOUT_KEY);
                } else {
                    String eqpt = lotSpecialStep.getRealEquipmentId();
                    if (StringUtils.isEmpty(eqpt)) {
                        Long entityGroupRrn = lotSpecialStep.getEntityGroupRrn();
                        if (entityGroupRrn > 0) {
                            List<Relation> entities = emsService.getAllEntities(entityGroupRrn);
                            if (entities != null && entities.size() > 0) {
                                for (Relation relation : entities) {
                                    Long eqptRrn = relation.getFromRrn();
                                    Entity en = emsService.getEntity(eqptRrn);
                                    if (en != null) {
                                        String enInstanceId = en.getInstanceId();
                                        int _index = enInstanceId.lastIndexOf("_");
                                        int _length = enInstanceId.length();
                                        if (_index > -1) {
                                            if (_index != _length - 2) {
                                                eqpt = en.getInstanceId();
                                            }
                                        } else {
                                            eqpt = en.getInstanceId();
                                        }
                                    }
                                }
                            }
                        }
                    }
                    lotInfo.put("eqptId", eqpt);
                    theform.setTransId(Constants.MOVEIN_KEY);
                }
            }

            request.setAttribute("lotInfo", lotInfo);
        }
        theform.setReason("");
        return mapping.findForward(Constants.INIT_KEY);
    }

    public ActionForward transMovein(ActionMapping mapping, LotInfoFormNpw theform, HttpServletRequest request,
                                     HttpServletResponse response) throws Exception {

        long facilityRrn = LocalContext.getFacilityRrn();
        String facilityId = LocalContext.getFacilityId();

        String eqptId = StringUtils.trimToUpperCase(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 || equipment.getInstanceRrn() <= 0,
                       Errors.create().key(MessageIdList.EQUIPMENT_MISSING_ID).content("设备不存在").build());

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

        Lot lot = lotQueryService.getLot(lotId, facilityRrn);

        //检查批次状态
        Assert.isFalse(StringUtils.equals(lot.getLotStatus(), LotStatus.PROCESSED) ||
                               StringUtils.equals(lot.getLotStatus(), LotStatus.RUNNING),
                       Errors.create().key(MessageIdList.LOT_STATUS_CANT_MOVEIN)
                             .content("Lot:{} status is {} ,can't move in!").args(lot.getLotId(), lot.getLotStatus())
                             .build());

        Assert.isFalse(StringUtils.equals(lot.getLotStatus(), LotStatus.DISPATCH) && lot.getJobRrn() <= 0,
                       Errors.create().content("create lot job error!").build());

        Assert.isFalse(StringUtils.equals(lot.getLotStatus(), LotStatus.FINISH) ||
                               StringUtils.equals(lot.getLotStatus(), LotStatus.HOLD) ||
                               StringUtils.equals(lot.getLotStatus(), LotStatus.RUNNINGHOLD) ||
                               StringUtils.equals(lot.getLotStatus(), LotStatus.TERMINATED) ||
                               StringUtils.equals(lot.getLotStatus(), LotStatus.SCRAPPED),
                       Errors.create().key(MessageIdList.LOT_STATUS_CANT_MOVEIN)
                             .content("Lot:{} status is {} ,can't move in!").args(lot.getLotId(), lot.getLotStatus())
                             .build());


        String errorMsg = dmmLotService.checkBatchLotParameterSet(lot.getLotRrn());
        Assert.isFalse(StringUtils.isNotBlank(errorMsg), Errors.create().content(errorMsg).build());

        //check设备状态
        Assert.isTrue(dmmLotService.validateEntityStatusInAvailable(equipment, lot),
                      Errors.create().key(MessageIdList.EQUIPMENT_CURRENT_STATE_CANT_WORK).content(
                              "The equipment " + "current " + "status:{}" + " does not" + " allow to" + " move in!")
                            .args(emsService.getEntityCurrentStatus(equipment.getInstanceRrn())).build());
        List<Lot> lotInfos = new ArrayList<Lot>();
        List<LotInfoDto> lotInfoDtos = new ArrayList<LotInfoDto>();
        lotInfos.add(lot);
        lot.setEqptRrn(equipment.getInstanceRrn());
        Map<String, Object> transData = new HashMap<String, Object>();
        Map<String, Object> lotBaseInfo = new HashMap<String, Object>();

        lotBaseInfo.put("facilityRrn", facilityRrn);
        lotBaseInfo.put("lotId", lotId);
        lotBaseInfo.put("lotRrn", lot.getLotRrn());

        EqpMonitorLotSpecialStep lotSpecialStep = dmmLotService
                .getDMMLotSpecialStepByOperation(lot.getOperationRrn(), lot.getLotRrn());
        if (lotSpecialStep != null) {
            lotSpecialStep.setLotId(lot.getLotId());

            String recipeStr = lotSpecialStep.getRecipeStr();
            if (!StringUtils.contains(recipeStr, ",")) {
                long recipeRrn = getInstanceRrn(recipeStr, facilityRrn, ObjectList.RECIPE_KEY);
                String ppid = recipeService.buildRecipePhysicalId(recipeStr, BeanUtils.copyBeanToMap(lot));
                if (BooleanUtils.toBoolean(equipment.getIsChamberEquip())) {
                    Map<String, Object> subRecipeMap = wipService
                            .getAvailableSubRecipes(lot, equipment.getInstanceRrn(), EventName.IDLE_TO_RUN, recipeRrn,
                                                    NumberUtils.toLong(lot.getQty1().toString()));

                    List<Map<String, Object>> childRecipes = (List<Map<String, Object>>) MapUtils
                            .getObject(subRecipeMap, "childRecipes");
                    if (CollectionUtils.isNotEmpty(childRecipes)) {
                        Map<String, Object> childRecipeMap = childRecipes.iterator().next();
                        String recipeId = MapUtils.getString(childRecipeMap, "recipeId");
                        lotBaseInfo.put("ppid", recipeId);
                        lotBaseInfo.put("recipePhysicalId", recipeId);
                        lotBaseInfo.put("recipeLogicalRrn", MapUtils.getLong(childRecipeMap, "recipeRrn"));
                        setEnableChamberList(lotBaseInfo, recipeId, equipment.getInstanceRrn());
                    } else {
                        lotBaseInfo.put("ppid", ppid);
                        lotBaseInfo.put("recipePhysicalId", ppid);
                        lotBaseInfo.put("recipeLogicalRrn", recipeRrn);
                    }
                } else {
                    lotBaseInfo.put("ppid", ppid);
                    lotBaseInfo.put("recipePhysicalId", ppid);
                    lotBaseInfo.put("recipeLogicalRrn", recipeRrn);
                }
            } else {
                lotBaseInfo.put("ppid", "");
                lotBaseInfo.put("recipePhysicalId", "");
                lotBaseInfo.put("recipeLogicalRrn", "");
            }
            theform.setRecipeId(MapUtils.getString(lotBaseInfo, "ppid"));
            theform.setRecipeRrn(MapUtils.getLong(lotBaseInfo, "recipeLogicalRrn"));
            theform.setChamberType(MapUtils.getString(lotBaseInfo, "chamberType"));

            // unit recipe设定
            String recipeList = MapUtils.getString(lotBaseInfo, "ppid");
            List<EqpMonitorUnitSpecialStep> list = dmmLotService
                    .getUnitSpecialStepList(lotSpecialStep.getLotSpecialStepRrn());
            Map<String, String> unitRecipeMap = new HashMap<>();
            for (EqpMonitorUnitSpecialStep step : list) {
                if (StringUtils.isNotBlank(recipeList)) {
                    unitRecipeMap.put(step.getUnitRrn() + "", recipeList);
                } else {
                    unitRecipeMap.put(step.getUnitRrn() + "", step.getRecipeStr());
                }
            }

            List eqptRecipeList = baseService
                    .getFullRelation4Recipe(equipment.getInstanceRrn(), LinkTypeList.ENTITY_TO_RECIPE);
            for (Object key : unitRecipeMap.keySet()) {
                String _recipeStr = MapUtils.getString(unitRecipeMap, key);
                Assert.isFalse(StringUtils.isBlank(_recipeStr) || StringUtils.equalsIgnoreCase("null", _recipeStr),
                               Errors.create().key(MessageIdList.DMM_RECIPE_NOT_SPECIFIED_SETUP)
                                     .content("Recipe not all specified!").build());
                long recipeRrn = getInstanceRrn(_recipeStr, facilityRrn, ObjectList.RECIPE_KEY);
                Assert.isFalse(recipeRrn <= 0,
                               Errors.create().key(MessageIdList.DMM_RECIPE_NOT_EXIST).content("Recipe:{} not exist!")
                                     .args(_recipeStr).build());
                boolean boo = true;
                if (!StringUtils.equalsIgnoreCase(equipment.getChamberMode(), SystemConstant.Str.PARALLEL)) {
                    for (Object obj : eqptRecipeList) {
                        Map map = (Map) obj;
                        if (StringUtils.equals(_recipeStr, MapUtils.getString(map, "recipeId"))) {
                            String status = MapUtils.getString(map, "status");
                            if (StringUtils.equals(SystemConstant.Str.ON, status) || StringUtils.equals(SystemConstant.Str.EXIST, status)) {
                                boo = false;
                                break;
                            }
                        }
                    }
                } else {
                    long mainRecipeRrn = recipeService.isMainRecipe(
                            getInstanceRrn(_recipeStr, LocalContext.getFacilityRrn(), ObjectList.RECIPE_KEY));
                    String parentRecipeId = getInstanceId(mainRecipeRrn);
                    List<String> recipeList1 = new ArrayList<String>();
                    List<String> recipeList2 = new ArrayList<String>();
                    String temp1 = _recipeStr.substring(_recipeStr.lastIndexOf("-") + 1);
                    for (int i = 0; i < temp1.length(); i++) {
                        recipeList1.add(parentRecipeId + "-" + temp1.charAt(i));
                    }
                    for (Object obj : eqptRecipeList) {
                        Map map = (Map) obj;
                        String recipeId = MapUtils.getString(map, "recipeId");
                        if (!StringUtils.equalsIgnoreCase(recipeId, parentRecipeId)) {
                            String status = MapUtils.getString(map, "status");
                            if (StringUtils.equals("ON", status) || StringUtils.equals("EXIST", status)) {
                                recipeList2.add(recipeId);
                            }
                        }
                    }
                    if (recipeList2.containsAll(recipeList1)) {
                        boo = false;
                    }

                }
                Assert.isFalse(boo, Errors.create().key(MessageIdList.DMM_EQPT_RECIPES_NOT_CONTAIN)
                                          .content("Equipment available recipe does not contain: {}").args(_recipeStr)
                                          .build());
            }
            lotBaseInfo.put("unitRecipeMap", unitRecipeMap);
        }

        lotBaseInfo.put("qty1", lot.getQty1());

        lotBaseInfo.put("reticleGroupId", lot.getReticleGroupId());
        lotBaseInfo.put("reticleGroupRrn", lot.getReticleGroupRrn());
        lotBaseInfo.put("reticleId", lot.getReticleId() == null ? "" : lot.getReticleId());

        LotBaseInfoDto lotBaseInfoDto = new LotBaseInfoDto();
        BeanUtils.copyMapToBean(lotBaseInfoDto, lotBaseInfo);
        LotInfoDto lotInfoDto = new LotInfoDto();
        lotInfoDto.setLotBaseInfo(lotBaseInfoDto);
        lotInfoDtos.add(lotInfoDto);
        buildLotData(lot, equipment.getInstanceRrn(), lotBaseInfoDto);
        //判断是否是手动batch move in
        List<BatchLotStore> lotInBatch = diffBatchQueryService.getBatchStoreListByLot(lot.getLotRrn());
        if (CollectionUtils.isEmpty(lotInBatch)) {
            dmmLotService.dispatchLot(lotInfos, equipment, lotInfoDtos);
        } else {
            manualBatchDispatch(lotInfos, lotInBatch, equipment, lotInfoDtos, ActionPointList.MOVEIN_KEY);
        }

        theform.setTransId(Constants.MOVEOUT_KEY);
        lot = lotQueryService.getLot(lotId, facilityRrn);
        Map<String, String> lotInfo = getLotInfo(lot, lotSpecialStep);
        lotInfo.put("eqptId", eqptId);
        request.setAttribute("lotInfo", lotInfo);
        request.setAttribute("moveinSuccessed", "1");
        WebUtils.setSuccessMsg(request, "dmm.lot_already_track_in", "Lot already track in!");
        return init(mapping, theform, request, response);
    }

    public ActionForward cancelMoveIn(ActionMapping mapping, LotInfoFormNpw theform, HttpServletRequest request,
                                      HttpServletResponse response) throws Exception {

        String userId = request.getParameter("userId");
        String reasonCode = request.getParameter("reasonCode");
        String deptExt = request.getParameter("deptExt");
        String reason = request.getParameter("reason");

        reason = reasonCode + " " + deptExt.trim().toUpperCase() + " " + userId + " " + reason;

        Assert.isFalse(reason != null && reason.getBytes("UTF-8").length > 1024,
                       Errors.create().content("The input exceeds the" + " length limit!").build());

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

        Lot lot = lotQueryService.getLot(lotId, LocalContext.getFacilityRrn());
        long jobRrn = lot.getJobRrn();
        Assert.state(jobRrn > 0, Errors.create().content("There is no operation record for this Lot!").build());

        Assert.isFalse(
                !LotStatus.DISPATCH.equals(lot.getLotStatus()) && !LotStatus.RUNNING.equals(lot.getLotStatus()) &&
                        !LotStatus.PROCESSED.equals(lot.getLotStatus()),
                Errors.create().content("LOT.STATUS_NOT_ALLOW").build());

        TransReason transReason = new TransReason();
        transReason.setReasonCode(reasonCode);
        transReason.setReason(reason);
        transReason.setResponsibility(LocalContext.getUserId());
        transReason.setTransQty1(lot.getQty1());
        transReason.setTransQty2(lot.getQty2());
        Long operationRrn = theform.getOperationRrn();

        dmmLotService.cancelMoveIn(lot.getLotRrn(), lot.getLotStatus(), jobRrn, LocalContext.getUserId(), reason,
                                   transReason);
        WebUtils.setSuccessMsg(request, "dmm.lot_already_cancel_track_in", "Lot already cancel track in!");
        return init(mapping, theform, request, response);
    }

    public ActionForward initHoldOrRelease(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                                           HttpServletResponse response) throws Exception {
        LotInfoFormNpw theform = (LotInfoFormNpw) form;
        Lot lot = lotQueryService.getLot(theform.getLotId());
        theform.setProductId(lot.getProductId());
        theform.setCarrierId(lot.getCarrierId());
        List<Map> holdInfos = new ArrayList<>();
        if (lot != null && lot.getLotRrn() > 0) {
            holdInfos = wipQueryService.getHoldReasons(lot.getLotRrn());
            request.setAttribute("lotId", lot.getLotId());
        }
        request.setAttribute("collection", holdInfos);
        String flag = WebUtils.getParameter("flag", request);
        if (StringUtils.equalsIgnoreCase("hold", flag)) {
            if (StringUtils.equals(lot.getLotStatus(), LotStatus.WAITING) ||
                    StringUtils.equals(lot.getLotStatus(), LotStatus.HOLD)) {
                return mapping.findForward(Constants.HOLD_KEY);
            } else if (StringUtils.equals(lot.getLotStatus(), LotStatus.RUNNING) ||
                    StringUtils.equals(lot.getLotStatus(), LotStatus.RUNNINGHOLD)) {
                return mapping.findForward(Constants.RUNNING_HOLD_KEY);
            } else {
                throw new SystemIllegalArgumentException(
                        Errors.create().key(MessageIdList.LOT_STATUS_NOT_ALLOW).content("Lot status not allow")
                              .build());
            }
        } else if (StringUtils.equalsIgnoreCase("release", flag)) {
            if (StringUtils.equals(lot.getLotStatus(), LotStatus.HOLD)) {
                return mapping.findForward(Constants.RELEASE_KEY);
            } else if (StringUtils.equals(lot.getLotStatus(), LotStatus.RUNNINGHOLD)) {
                return mapping.findForward(Constants.RUNNING_RELEASE_KEY);
            } else {
                throw new SystemIllegalArgumentException(
                        Errors.create().key(MessageIdList.LOT_STATUS_NOT_ALLOW).content("Lot status not allow")
                              .build());
            }
        } else {
            return mapping.findForward(Constants.INIT_KEY);
        }
    }

    public ActionForward initAdjustRecipe(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                                          HttpServletResponse response) throws Exception {
        LotInfoFormNpw theform = (LotInfoFormNpw) form;
        String carrierId = StringUtils.trimToUpperCase(theform.getCarrierId());
        Lot lot = lotQueryService.getLotByCarrierId(carrierId, LocalContext.getFacilityRrn());
        theform.setTransId(TransactionNames.ADJUST_RECIPE_BY_OPERATION);
        Long operationRrn = lot.getOperationRrn();
        EqpMonitorLotSpecialStep lotSpecialStep = dmmLotService
                .getDMMLotSpecialStepByOperation(operationRrn, lot.getLotRrn());
        theform.setProductId(lot.getProductId());
        theform.setCarrierId(lot.getCarrierId());
        theform.setLotStatus(lot.getLotStatus());
        theform.setRecipePhysicalId(lotSpecialStep.getRecipeStr());
        if (StringUtils.equals(lot.getLotStatus(), LotStatus.HOLD)) {
            theform.setRecipeId("");
            return mapping.findForward(Constants.ADJUST_KEY);
        } else {
            throw new SystemIllegalArgumentException(
                    Errors.create().key(MessageIdList.LOT_STATUS_NOT_ALLOW).content("Lot status not allow").build());
        }
    }

    public ActionForward adjustRecipe(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                                      HttpServletResponse response) throws Exception {
        LotInfoFormNpw theform = (LotInfoFormNpw) form;
        String carrierId = StringUtils.trimToUpperCase(theform.getCarrierId());
        Lot lot = lotQueryService.getLotByCarrierId(carrierId, LocalContext.getFacilityRrn());
        Long operationRrn = lot.getOperationRrn();
        EqpMonitorLotSpecialStep lotSpecialStep = dmmLotService
                .getDMMLotSpecialStepByOperation(operationRrn, lot.getLotRrn());
        long facilityRrn = LocalContext.getFacilityRrn();
        long userRrn = LocalContext.getUserRrn();
        String newRecipeId = StringUtils.trimToUpperCase(theform.getRecipeId());

        Assert.isFalse(StringUtils.isBlank(newRecipeId),
                       Errors.create().key(MessageIdList.RECIPE_INVALID_ID).content("Recipe cannot be empty!").build());
        Recipe newRecipe = recipeService.getRecipe(newRecipeId, facilityRrn);
        Assert.isFalse(newRecipe == null,
                       Errors.create().key(MessageIdList.RECIPE_RECIPE_ID_NOT_EXIST).content("Recipe ID:{} not exists!")
                             .args(newRecipeId).build());

        if (lot.getRecipeId().equalsIgnoreCase(newRecipeId)) {
            //新旧Recipe都一样,无需修改
            return initAdjustRecipe(mapping, form, request, response);
        }

        lotSpecialStep.setAttributeData1(lotSpecialStep.getRecipeStr() + "->" + newRecipeId);
        dmmLotService.updateDMMLotSpecialStepRecipe(lotSpecialStep, newRecipeId);
        request.setAttribute("operationMsg", "true");
        return initAdjustRecipe(mapping, form, request, response);
    }

    public ActionForward hold(ActionMapping mapping, ActionForm form, HttpServletRequest request) throws Exception {
        LotInfoFormNpw theform = (LotInfoFormNpw) form;
        long facilityRrn = LocalContext.getFacilityRrn();
        String lotId = theform.getLotId();
        long userRrn = LocalContext.getUserRrn();
        String userId = LocalContext.getUserId();
        User user = securityService.getUser(NumberUtils.toLong(theform.getUserId()));
        String userName = user.getInstanceId() + " " + user.getUserName();

        Lot lot = lotQueryService.getLot(lotId, facilityRrn);

        Assert.isFalse(lot.getLotRrn() <= 0,
                       Errors.create().key(MessageIdList.LOT_LOTRRN_NOT_FOUND).content("Cannot Find Lot!").build());

        //        if (!StringUtils.equals(StringUtils.trim(theform.getHoldPassword()),
        //                                StringUtils.trim(theform.getPasswordConfirm()))) {
        //            throw new WebException("error.password_mismatch","Password Mismatch!");
        //        }

        Assert.isFalse((theform.getReason() == null) || ("".equalsIgnoreCase(theform.getReason())),
                       Errors.create().key(MessageIdList.ERROR_REASON_IS_EMPTY).content("Reason is empty!").build());

        Assert.isFalse(
                !((lot.getLotStatus().equalsIgnoreCase("WAITING")) || (lot.getLotStatus().equalsIgnoreCase("HOLD"))),
                Errors.create().key(MessageIdList.LOT_STATUS_CANT_NOT_BE_HOLD)
                      .content("Lot status must be 'HOLD' or 'WAITING'!").build());

        String reason = theform.getDepartment() + " Reason:" + "Holdcode is " + theform.getReasonCode() + ". " +
                theform.getReason();
        TransReason transReason = new TransReason();
        transReason.setReasonCode(theform.getReasonCode());
        transReason.setReason(reason);
        transReason.setTransQty1(lot.getQty1());
        transReason.setTransQty2(lot.getQty2());
        transReason.setResponsibility(userName);
        HashMap holdInfo = new HashMap();
        holdInfo.put("lotRrn", new Long(lot.getLotRrn()).toString());
        holdInfo.put("lotId", lot.getLotId());
        holdInfo.put("lotStatus", lot.getLotStatus());
        holdInfo.put("transPerformedBy", userId);
        holdInfo.put("holdBy", userRrn + "");
        //holdInfo.put("holdPassword", StringUtils.trim(theform.getHoldPassword()));
        holdInfo.put("transComments", reason);
        holdInfo.put("operation", lot.getOperationId());
        holdInfo.put("holdcode", theform.getReasonCode());
        holdInfo.put("transReason", transReason);

        lotService.holdLot(holdInfo);
        return mapping.findForward("toInit");

    }

    public ActionForward runningHold(ActionMapping mapping, ActionForm form,
                                     HttpServletRequest request) throws Exception {
        LotInfoFormNpw theform = (LotInfoFormNpw) form;

        long facilityRrn = LocalContext.getFacilityRrn();
        String lotId = theform.getLotId();
        long userRrn = LocalContext.getUserRrn();
        String userId = LocalContext.getUserId();

        Lot lot = lotQueryService.getLot(lotId, facilityRrn);

        Assert.isFalse(lot.getLotRrn() <= 0,
                       Errors.create().key(MessageIdList.LOT_LOTRRN_NOT_FOUND).content("Cannot Find Lot!").build());

        //        if (!StringUtils.equals(StringUtils.trim(theform.getHoldPassword()),
        //                                StringUtils.trim(theform.getPasswordConfirm()))) {
        //            throw new WebException("error.password_mismatch", "Password Mismatch!");
        //        }

        Assert.isFalse((theform.getReason() == null) || ("".equalsIgnoreCase(theform.getReason())),
                       Errors.create().key(MessageIdList.ERROR_REASON_IS_EMPTY).content("Reason is empty!").build());

        Assert.isFalse(!((lot.getLotStatus().equalsIgnoreCase(LotStatus.RUNNING)) ||
                               (lot.getLotStatus().equalsIgnoreCase(LotStatus.RUNNINGHOLD))),
                       Errors.create().key(MessageIdList.LOT_STATUS_CANT_NOT_BE_HOLD)
                             .content("Lot status must be 'RUNNING' or 'RUNNINGHOLD'!").build());

        String reason = theform.getDepartment() + " Reason:" + "Holdcode is " + theform.getReasonCode() + ". " +
                theform.getReason();
        TransReason transReason = new TransReason();
        transReason.setReasonCode(theform.getReasonCode());
        transReason.setReason(reason);
        transReason.setTransQty1(lot.getQty1());
        transReason.setTransQty2(lot.getQty2());
        transReason.setResponsibility(userId);
        HashMap holdInfo = new HashMap();
        holdInfo.put("lotRrn", new Long(lot.getLotRrn()).toString());
        holdInfo.put("lotId", lot.getLotId());
        holdInfo.put("lotStatus", lot.getLotStatus());
        holdInfo.put("transPerformedBy", userId);
        holdInfo.put("holdBy", userRrn + "");
        //holdInfo.put("holdPassword", StringUtils.trim(theform.getHoldPassword()));
        holdInfo.put("transComments", reason);
        holdInfo.put("operation", lot.getOperationId());
        holdInfo.put("holdcode", theform.getReasonCode());
        holdInfo.put("transReason", transReason);

        lotService.holdRunningLot(holdInfo);
        return mapping.findForward("toInit");

    }

    public ActionForward release(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                                 HttpServletResponse response) throws Exception {
        LotInfoFormNpw theform = (LotInfoFormNpw) form;

        String releasePage = WebUtils.getParameter("page", request);
        boolean superReleaseFlag = StringUtils.isNotEmpty((String) request.getParameter("superrelease"));
        long facilityRrn = LocalContext.getFacilityRrn();
        String lotId = theform.getLotId();
        long userRrn = LocalContext.getUserRrn();
        String userId = LocalContext.getUserId();
        String[] newPasswords = request.getParameterValues("newPassword");
        String fieldFlag = request.getParameter("fieldFlags");
        String[] fieldFlags = fieldFlag.split(",");

        Lot lot = lotQueryService.getLot(lotId, facilityRrn);

        Assert.isFalse(lot.getLotRrn() <= 0,
                       Errors.create().key(MessageIdList.LOT_LOTRRN_NOT_FOUND).content("Cannot Find Lot!").build());

        Assert.isTrue(StringUtils.equals(lot.getLotStatus(), LotStatus.HOLD),
                      Errors.create().key(MessageIdList.LOT_STATUS_NOT_ALLOW).content("Lot status not allow").build());

        List<Map> holdReasons = wipQueryService.getHoldReasons(lot.getLotRrn());
        List<Map> releaseReasons = new ArrayList();
        List<Map> unReleaseReasons = new ArrayList();

        //是否存在trackOutHold释放
        boolean trackOutHoldExisted = false;
        //工步变更检查flag
        boolean lotStepChanged = false;
        // 是否存在Bonding绑定错误
        boolean sapphireBondedError = false;
        for (int i = 0; i < holdReasons.size(); i++) {
            Map holdReason = holdReasons.get(i);
            String reasonCode = MapUtils.getString(holdReason, "reasonCode");

            if (StringUtils.equals(TransReason.reasonCode.BONDERROR.name(), reasonCode)) {
                sapphireBondedError = true;
            }

            if (StringUtils.equals("0", fieldFlags[i])) {
                Assert.isFalse(StringUtils.contains(MapUtils.getString(holdReason, "reasonCode"), "SRCHOLD") &&
                                       StringUtils.equalsIgnoreCase(lot.getLotStatus(), LotStatus.RUNCARD_HOLD),
                               Errors.create().content("Can't release SRCHOLD!").build());

                if (StringUtils.equals("TRACKOUTHOLD", MapUtils.getString(holdReason, "reasonCategory"))) {
                    trackOutHoldExisted = true;
                }

                String holdPassword =
                        holdReason.get("holdPassword") != null ? ((String) holdReason.get("holdPassword")).trim() : "";
                String newPassword = newPasswords[i] != null ? newPasswords[i].trim() : "";

                Assert.isTrue(StringUtils.equals(holdPassword, newPassword),
                              Errors.create().content("Invalid Release Password!").build());

                releaseReasons.add(holdReason);
            } else {
                unReleaseReasons.add(holdReason);
            }

        }

        Assert.isFalse(releaseReasons.size() <= 0,
                       Errors.create().key(MessageIdList.LOT_RELEASE_HOLD_EMPTY).content("please select release hold!")
                             .build());

        Assert.isFalse(trackOutHoldExisted == true && unReleaseReasons.size() > 0,
                       Errors.create().key(MessageIdList.LOT_TRACKOUT_HOLD_CANNOT_RELEASE).content(
                               "Before " + "Trackout " + "hold " + "released, " + "Please " + "release " +
                                       "other hold " + "first!").build());

        if (trackOutHoldExisted) {
            lotStepChanged = lotService.checkLotStepChange(lot.getLotRrn());
        }

        HashMap releaseInfo = new HashMap();
        releaseInfo.put("lotRrn", new Long(lot.getLotRrn()).toString());
        releaseInfo.put("lotId", lot.getLotId());
        releaseInfo.put("releaseReasons", releaseReasons);
        releaseInfo.put("transPerformedBy", userId);
        releaseInfo.put("transComments", theform.getLotComments());
        releaseInfo.put("operation", lot.getOperationId());

        TransReason transReason = new TransReason();
        transReason.setReasonCode(theform.getReasonCode());

        transReason.setReason(theform.getLotComments());
        transReason.setTransQty1(lot.getQty1());
        transReason.setTransQty2(lot.getQty2());
        transReason.setResponsibility(userId);
        transReason.setReason(theform.getReason());

        releaseInfo.put("transReason", transReason);
        releaseInfo.put("superFlag", "0");

        lotService.releaseLot(releaseInfo);

        /*if (sapphireBondedError || (trackOutHoldExisted && unReleaseReasons.isEmpty() && !lotStepChanged)) {
            //查询最新批次信息
            lot = lotQueryService.getLot(lot.getLotRrn());
            dispatchLotAfterRelease(mapping, request, response, userId, facilityRrn, lot);
        }*/

        return mapping.findForward("toInit");
    }

    public ActionForward runningRelease(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                                        HttpServletResponse response) throws Exception {
        LotInfoFormNpw theform = (LotInfoFormNpw) form;

        boolean superReleaseFlag = StringUtils.isNotEmpty((String) request.getParameter("superrelease"));
        long facilityRrn = LocalContext.getFacilityRrn();
        String lotId = theform.getLotId();
        long userRrn = LocalContext.getUserRrn();
        String userId = LocalContext.getUserId();
        String[] newPasswords = request.getParameterValues("newPassword");
        String fieldFlag = request.getParameter("fieldFlags");
        String[] fieldFlags = fieldFlag.split(",");

        Lot lot = lotQueryService.getLot(lotId, facilityRrn);

        Assert.isFalse(lot.getLotRrn() <= 0,
                       Errors.create().key(MessageIdList.LOT_LOTRRN_NOT_FOUND).content("Cannot Find Lot!").build());

        Assert.isTrue(StringUtils.equals(lot.getLotStatus(), LotStatus.RUNNINGHOLD),
                      Errors.create().key(MessageIdList.LOT_STATUS_NOT_ALLOW).content("Lot status not " + "allow")
                            .build());

        List<Map> holdReasons = wipQueryService.getHoldReasons(lot.getLotRrn());
        List<Map> releaseReasons = new ArrayList();
        List<Map> unReleaseReasons = new ArrayList();

        //是否存在trackOutHold释放
        boolean trackOutHoldExisted = false;
        //工步变更检查flag
        boolean lotStepChanged = false;
        // 是否存在Bonding绑定错误
        boolean sapphireBondedError = false;
        for (int i = 0; i < holdReasons.size(); i++) {
            Map holdReason = holdReasons.get(i);
            String reasonCode = MapUtils.getString(holdReason, "reasonCode");

            if (StringUtils.equals(TransReason.reasonCode.BONDERROR.name(), reasonCode)) {
                sapphireBondedError = true;
            }

            if (StringUtils.equals("0", fieldFlags[i])) {
                Assert.isFalse(StringUtils.contains(MapUtils.getString(holdReason, "reasonCode"), "SRCHOLD") &&
                                       StringUtils.equalsIgnoreCase(lot.getLotStatus(), LotStatus.RUNCARD_HOLD),
                               Errors.create().content("Can't release SRCHOLD!").build());
                if (StringUtils.equals("TRACKOUTHOLD", MapUtils.getString(holdReason, "reasonCategory"))) {
                    trackOutHoldExisted = true;
                }

                String holdPassword =
                        holdReason.get("holdPassword") != null ? ((String) holdReason.get("holdPassword")).trim() : "";
                String newPassword = newPasswords[i] != null ? newPasswords[i].trim() : "";

                Assert.isTrue(StringUtils.equals(holdPassword, newPassword),
                              Errors.create().content("Invalid Release Password!").build());

                releaseReasons.add(holdReason);
            } else {
                unReleaseReasons.add(holdReason);
            }

        }

        Assert.isFalse(releaseReasons.size() <= 0,
                       Errors.create().key(MessageIdList.LOT_RELEASE_HOLD_EMPTY).content("please select release hold!")
                             .build());

        Assert.isFalse(trackOutHoldExisted == true && unReleaseReasons.size() > 0,
                       Errors.create().key(MessageIdList.LOT_TRACKOUT_HOLD_CANNOT_RELEASE).content(
                               "Before " + "Trackout " + "hold " + "released, " + "Please " + "release " +
                                       "other hold " + "first!").build());

        if (trackOutHoldExisted) {
            lotStepChanged = lotService.checkLotStepChange(lot.getLotRrn());
        }

        HashMap releaseInfo = new HashMap();
        releaseInfo.put("lotRrn", new Long(lot.getLotRrn()).toString());
        releaseInfo.put("lotId", lot.getLotId());
        releaseInfo.put("releaseReasons", releaseReasons);
        releaseInfo.put("transPerformedBy", userId);
        releaseInfo.put("transComments", theform.getLotComments());
        releaseInfo.put("operation", lot.getOperationId());

        TransReason transReason = new TransReason();
        transReason.setReasonCode(theform.getReasonCode());

        transReason.setReason(theform.getLotComments());
        transReason.setTransQty1(lot.getQty1());
        transReason.setTransQty2(lot.getQty2());
        transReason.setResponsibility(userId);
        transReason.setReason(theform.getReason());

        releaseInfo.put("transReason", transReason);
        releaseInfo.put("superFlag", "0");


        lotService.releaseRunningLot(releaseInfo);
        return mapping.findForward("toInit");
    }

    private void manualBatchDispatch(List<Lot> monitorLot, List<BatchLotStore> batchProductLots, Equipment equipment,
                                     List<LotInfoDto> monitorLotInfos, String action) {
        List<Lot> productLots = new ArrayList<Lot>();
        for (BatchLotStore batchProductLot : batchProductLots) {
            //取monitorlot的配置
            productLots.add(buildProductLotData(batchProductLot.getLotRrn(), equipment, monitorLotInfos.get(0)));
        }

        List<LotInfoDto> productLotInfos = productLots.parallelStream().map(lot1 -> {
            LotInfoDto lotInfoDto = new LotInfoDto();
            LotBaseInfoDto lotBaseInfoDto = new LotBaseInfoDto();
            PropertyUtils.copyProperties(lotBaseInfoDto, lot1);
            lotInfoDto.setLotBaseInfo(lotBaseInfoDto);
            return lotInfoDto;
        }).collect(Collectors.toList());
        //check 批次状态
        checkLotStatusByMove(productLots, action);
        dmmLotService.dispatchBatchLot(productLots, monitorLot, equipment, productLotInfos, monitorLotInfos);
    }

    private void checkLotStatusByMove(List<Lot> lots, String action) {
        for (Lot lot : lots) {
            Assert.isFalse(StringUtils.equalsIgnoreCase(action, ActionPointList.MOVEIN_KEY) &&
                                   !StringUtils.equalsIgnoreCase(LotStatus.WAITING, lot.getLotStatus()),
                           Errors.create().key(MessageIdList.LOT_STATUS_CANT_MOVEIN)
                                 .content("Lot:{} status is {} ,can't move in!")
                                 .args(lot.getLotId(), lot.getLotStatus()).build());
            //因为后量时,产品批次为waiting,不会进站
            Assert.isFalse(StringUtils.equalsIgnoreCase(action, ActionPointList.MOVEOUT_KEY) &&
                                   !(StringUtils.equalsIgnoreCase(LotStatus.RUNNING, lot.getLotStatus()) ||
                                           StringUtils.equalsIgnoreCase(LotStatus.WAITING, lot.getLotStatus())),
                           Errors.create().key(MessageIdList.LOT_STATUS_CANT_MOVEOUT)
                                 .content("Lot:{} " + "status " + "is {}" + " ,can't move out!")
                                 .args(lot.getLotId(), lot.getLotStatus()).build());

        }
    }

    private Lot buildProductLotData(Long productLotRrn, Equipment equipment, LotInfoDto monitorLotDto) {
        Lot lot = lotQueryService.getLot(productLotRrn);
        LotBaseInfoDto monitorLotBaseInfo = monitorLotDto.getLotBaseInfo();
        lot.setRecipeLogicalRrn(monitorLotBaseInfo.getRecipeLogicalRrn());
        lot.setPpid(monitorLotBaseInfo.getPpid());
        lot.setRecipePhysicalId(monitorLotBaseInfo.getRecipeId());
        lot.setRecipeId(monitorLotBaseInfo.getRecipeId());
        lot.setRecipeRrn(monitorLotBaseInfo.getRecipeLogicalRrn());
        lot.setChamberType(monitorLotBaseInfo.getChamberType());
        lot.setEqptRrn(equipment.getInstanceRrn());
        lot.setReticleId(monitorLotBaseInfo.getReticleId());
        lot.setReticleRrn(monitorLotBaseInfo.getReticleRrn());
        return lot;
    }

    private ParameterSetDto buildParameterSetDto(LotInfoFormNpw theform, HttpServletRequest request,
                                                 List<ParameterSetVersion> parameterSetVersions,
                                                 Lot lot) throws Exception {

        List<ParameterDto> parameterDtos = new ArrayList<ParameterDto>();
        for (ParameterSetVersion parameterSetVersion : parameterSetVersions) {
            Parameter parameter = (Parameter) parameterSetVersion.getParameters().iterator().next();
            String collectionLevel = parameterSetVersion.getCollectionLevel();
            String unitRrn = String.valueOf(lot.getLotRrn());
            String parameterName = parameter.getInstanceId() + "|" + lot.getLotId();
            List<SampleDto> sampleDtos = buildSampleList(request, parameter, unitRrn, parameterName);
            Assert.isFalse(sampleDtos.size() == 0, Errors.create().key(MessageIdList.DMM_SAMPLE_DATA_NOT_COLLECTED)
                                                         .content("Sample data not collected!").build());
            ParameterDto parameterDto = new ParameterDto();
            parameterDto.setParameterId(parameter.getInstanceId());
            parameterDto.setParameterRrn(parameter.getInstanceRrn());
            parameterDto.setParameterSequence(sampleDtos.size());
            parameterDto.setSamplePrompts(sampleDtos);
            parameterDtos.add(parameterDto);
        }
        ParameterSetVersion parameterSetVersion = parameterSetVersions.get(0);
        ParameterSetDto parameterSet = new ParameterSetDto();
        parameterSet.setParameterSetRrn(parameterSetVersion.getInstanceRrn());
        parameterSet.setParameterSetSpecRrn(parameterSetVersion.getParameterSetSpecRrn());
        parameterSet.setParameterSetVersion(parameterSetVersion.getInstanceVersion());
        parameterSet.setParameterSize(parameterSetVersions.size());
        parameterSet.setParameters(parameterDtos);
        return parameterSet;
    }

    private List<SampleDto> buildSampleList(HttpServletRequest request, Parameter parameter, String unitRrn,
                                            String parameterName) throws Exception {

        List<SampleDto> sampleList = new ArrayList<SampleDto>();
        for (int i = 1; i <= parameter.getSelectedUnitIds().length; i++) {

            String sampleName = parameterName + "|sample|" + (i - 1);

            List<ReadingDto> readingList = new ArrayList();
            String readingName;
            int reSeq = 0;
            for (Iterator iterator2 = parameter.getReadingPrompts().iterator(); iterator2.hasNext(); ) {
                Prompt readingPrompt = (Prompt) iterator2.next();

                readingName = sampleName + "|reading|" + readingPrompt.getPromptId();

                String readingId = edcService.getReadingId(request.getParameter("readingId" + readingName));
                String readingValue = request.getParameter(readingName);
                if (readingValue == null || readingValue.trim().length() < 1) {
                    continue;
                }
                Assert.isTrue(NumberUtils.isNumber(readingValue),
                              Errors.create().key(MessageIdList.DMM_ILLEGAL_SAMPLE_DATA)
                                    .content("Illegal characters in sample " + "data!").build());

                ReadingDto reading = buildReading(i, ++reSeq, readingId, readingValue);

                readingList.add(reading);
            }

            if (!readingList.isEmpty()) {
                String sampleId = request.getParameter(sampleName);
                sampleId = StringUtils.isNotEmpty(sampleId) ? sampleId : "LOT_LEVEL";

                String recipeId = request.getParameter(sampleName + "recipes");

                SampleDto sample = buildSample(i, sampleId, null, recipeId, unitRrn, readingList);

                sampleList.add(sample);
            }
        }

        return sampleList;
    }

    private SampleDto buildSample(Integer seq, String sampleId, String sampleValue, String recipeId, String unitRrn,
                                  List<ReadingDto> readingList) throws Exception {
        SampleDto sample = new SampleDto();

        sample.setSampleSequence(seq);
        sample.setRecipeId(recipeId);
        sample.setUnitId(sampleId);
        sample.setSampleId(sampleId);
        if (StringUtils.isNotEmpty(sampleValue) && NumberUtils.isNumber(sampleValue)) {
            this.SetObjPropertyVlaue(sample, sampleValue, "sampleValue");
        }
        this.SetObjPropertyVlaue(sample, unitRrn, "unitRrn");
        sample.setReadingPrompts(readingList);

        return sample;
    }

    private ReadingDto buildReading(Integer sampleSeq, Integer readingSeq, String readingId,
                                    String readingValue) throws Exception {
        ReadingDto reading = new ReadingDto();

        reading.setSampleSequence(sampleSeq);
        reading.setReadingSequence(readingSeq);
        reading.setReadingId(readingId);
        this.SetObjPropertyVlaue(reading, readingValue, "dataValue");

        SimpleDateFormat formatter = new SimpleDateFormat(DateUtils.DATE_FORMAT);
        Date time = new Date(System.currentTimeMillis());
        reading.setCollectionTimestamp(formatter.format(time));

        return reading;
    }

    private void SetObjPropertyVlaue(Object bean, String value, String propertyName) throws Exception {

        Class propertyType = PropertyUtils.getPropertyType(bean, propertyName);
        Constructor ctor = propertyType.getConstructor(new Class[]{String.class});

        Object obj = ctor.newInstance(new Object[]{value});
        PropertyUtils.setSimpleProperty(bean, propertyName, obj);
    }

    private ActionForward initEdc(ActionMapping mapping, LotInfoFormNpw theform, HttpServletRequest request,
                                  HttpServletResponse response, String parameterSetId,
                                  List<Lot> lotInfos) throws Exception {

        List<Map> collection = new ArrayList();
        for (Lot lot : lotInfos) {
            List<Map> parameterInfos = new ArrayList<>();

            String actionPoint = Constants.MOVEOUT_KEY;
            ParameterSet parameterSet = new ParameterSet(parameterSetId, getNamedSpace(ObjectList.PARAMETERSET_KEY,
                                                                                       LocalContext.getFacilityRrn()),
                                                         ObjectList.PARAMETERSET_KEY);
            parameterSet = edcService.getParameterSet(parameterSet);

            Assert.isFalse(parameterSet == null || parameterSet.getInstanceRrn() < 1,
                           Errors.create().key(MessageIdList.ERROR_EDC_CONTEXTVALUE_NOT_FOUND)
                                 .content("未找到EDC ContextValue").build());
            Long parameterSetRrn = parameterSet.getInstanceRrn();

            //1.获取parameter
            List<ParameterSetVersion> parameterSetVersions = edcService.getActiveParameterSetVersion(parameterSetRrn);

            if (CollectionUtils.isNotEmpty(parameterSetVersions)) {
                for (ParameterSetVersion parameterSetVersion : parameterSetVersions) {
                    List<Unit> unitList = wipQueryService.getUnitList(lot.getLotRrn());

                    List<Parameter> parameters = (List<Parameter>) parameterSetVersion.getParameters();

                    for (Parameter parameter : parameters) {
                        HashMap map = new HashMap();

                        //因为关系表DATA_COLLECTION_RULE中,分别存了参数、规则(此时PARAMETER_SET_RRN、PARAMETER_SET_VERSION都为定值0)
                        //和参数集、参数、规则两种关系。因为参数界面和参数集界面都是以第一种关系展示,
                        // 故这里也使用第一种关系,即PARAMETER_SET_RRN、PARAMETER_SET_VERSION都为0
                        CollectionRule collectionRule = wipQueryService
                                .getAvailableDataCollectionRule(unitList, parameter.getInstanceRrn());

                        String dataCollectionRuleInfo = "NONE";
                        parameter.setDataCollectionRule(collectionRule.getAvailableDataCollectionRule());
                        parameter.setSelectedUnitIds(collectionRule.getSelectedUnitIds());
                        parameter.setSelectedUnitPositions(collectionRule.getSelectedUnitPositions());

                        DataCollectionRule dataCollectionRule = parameter.getDataCollectionRule();
                        if (dataCollectionRule == null) {
                            dataCollectionRuleInfo = parameterSetVersion.getRuleType() != null ? parameterSetVersion
                                    .getRuleType() : dataCollectionRuleInfo;
                        } else {
                            dataCollectionRuleInfo = dataCollectionRule.toString();
                        }

                        map.put("dataCollectionRuleInfo", dataCollectionRuleInfo);
                        map.put("parameterSetVersion", parameterSetVersion);
                        map.put("lot", lot);
                        map.put("parameter", parameter);


                        parameterInfos.add(map);
                    }
                }
            } else {
                throw new SystemIllegalArgumentException(
                        Errors.create().content("EDC CONTEXT SETUP NOT RIGHT.").build());
            }

            HashMap parameterInfoMap = new HashMap();
            parameterInfoMap.put("sourceLot", lot);
            parameterInfoMap.put("parameterInfo", parameterInfos);
            parameterInfoMap.put("parameterSetVersions", parameterSetVersions);
            collection.add(parameterInfoMap);
        }

        theform.setCacheCollection(WebUtils.getCacheObj2String(collection));
        theform.setRecipeId(theform.getRecipeId());
        theform.setRecipeRrn(theform.getRecipeRrn());
        theform.setChamberType(theform.getChamberType());
        request.setAttribute("edcDataInfo", collection);

        return mapping.findForward("edcout");
    }

    private void setEnableChamberList(Map<String, Object> lotBaseInfo, String recipeId, long equipmentRrn) {
        Recipe recipe = recipeService.getRecipe(recipeId, LocalContext.getFacilityRrn());

        List<RecipeVersion> versions = recipeService.getRecipeVersions(recipe.getInstanceRrn());
        if (CollectionUtils.isNotEmpty(versions)) {
            versions = versions.stream().filter(o -> o.getVersionStatus().equals("ACTIVE"))
                               .collect(Collectors.toList());
            RecipeVersion recipeVersion = versions.stream().max(Comparator.comparing(RecipeVersion::getVersionId))
                                                  .get();
            recipeVersion.copyNamedObject(recipe);
            String chamberTypes = recipeVersion.getChamberTypes();
            List<String> enableChambers = new ArrayList<>();
            StringBuffer chamberType = new StringBuffer();
            if (StringUtils.isNotEmpty(chamberTypes)) {
                List<String> recipeChambers = Arrays
                        .asList(StringUtils.split(chamberTypes, 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(equipmentRrn, c[a]);
                        // 腔体设备存在 且enable log event
                        if (entity == null) {
                            enable = false;
                        }
                    }
                    if (enable) {
                        enableChambers.add(chamberKeys);
                        chamberType.append(chamberKeys);
                    }
                }
            }
            lotBaseInfo.put("chamberType", chamberType.toString());
            /*  lotBaseInfo.put("chamberType", recipeService.getChamberTypes(enableChambers));*/
        }
    }

    private void buildLotData(Lot lot, Long eqptRrn, LotBaseInfoDto lotBaseInfo) {
        if (StringUtils.equals(lot.getOperationId(), ACCOUNTSTEPEND)) {
            Recipe recipe = recipeService.getRecipe(lotBaseInfo.getPpid(), LocalContext.getFacilityRrn());
            if (recipe != null && recipe.getInstanceRrn() > 0) {
                lot.setRecipeRrn(recipe.getInstanceRrn());
                lot.setRecipeLogicalRrn(recipe.getInstanceRrn());
                lot.setRecipePhysicalId(lotBaseInfo.getPpid());
            }
        } else {
            lot.setRecipeLogicalRrn(lotBaseInfo.getRecipeLogicalRrn());
            lot.setRecipePhysicalId(lotBaseInfo.getPpid());
        }
        lot.setChamberType(lotBaseInfo.getChamberType());
        lot.setEqptRrn(eqptRrn);
        //        lot.setMonitorcarrId(StringUtils.trimToUpperCase(lotBaseInfo.getMonitorcarrId()));
        //        lot.setMonitorqty(lotBaseInfo.getMonitorqty());
        //        lot.setHasmonitor(lotBaseInfo.getHasmonitor());
    }

}