RecipeSaveAction.java

/*
 *        @ Copyright 2001 FA Software;
 *        All right reserved. No part of this program may be reproduced or
 *        transmitted in any form or by any means, electronic or
 *        mechanical, including photocopying, recording, or by any
 *        information storage or retrieval system without written
 *        permission from FA Software, except for inclusion of brief
 *        quotations in a review.
 */
package com.mycim.webapp.actions.recipe;

import com.fa.sesa.exception.Assert;
import com.fa.sesa.exception.Errors;
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.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.utils.FieldValidateUtils;
import com.mycim.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.SystemConstant;
import com.mycim.valueobject.bas.ObjectDocument;
import com.mycim.valueobject.bas.ObjectVersion;
import com.mycim.valueobject.bas.Relation;
import com.mycim.valueobject.consts.LinkTypeList;
import com.mycim.valueobject.consts.SessionNames;
import com.mycim.valueobject.prp.Context;
import com.mycim.valueobject.prp.Recipe;
import com.mycim.valueobject.prp.RecipeStatus;
import com.mycim.valueobject.prp.RecipeVersion;
import com.mycim.webapp.Constants;
import com.mycim.webapp.WebUtils;
import com.mycim.webapp.actions.RecipeSetupAction;
import com.mycim.webapp.forms.RecipeVersionInfoForm;
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.*;

/**
 * recipe 定义功能
 *
 * @author pinyan.song
 * @version 6.0.0
 * @date 2019-8-30
 **/
public class RecipeSaveAction extends RecipeSetupAction {

    public ActionForward copy(ActionMapping mapping, ActionForm form, HttpServletRequest request) throws Exception {
        RecipeVersionInfoForm theform = (RecipeVersionInfoForm) form;
        Recipe recipe = getRecipeInfo(theform);

        String id = request.getParameter(Constants.COPY_KEY);

        recipe.setInstanceId(id);

        doCopy(theform, recipe);

        theform.setTransId(Constants.CREATE_KEY);
        request.setAttribute(SessionNames.CONTEXT_KEY, new Context());

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

        if (StringUtils.isEmpty(operatetiponly)) {
            operatetiponly = "N";
        }

        request.setAttribute("operatetiponly", operatetiponly);
        return mapping.findForward(Constants.MODIFY_KEY);
    }

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

        Assert.isFalse(StringUtils.isEmpty(theform.getInstanceId()),
                       Errors.create().key(MessageIdList.RECIPE_RECIPE_ID_MISSING).content("Recipe Id is Null!")
                             .build());
        // 转大写,华为有出现小写recipe的现象
        theform.setInstanceId(theform.getInstanceId().toUpperCase());

        Recipe recipe = getRecipeInfo(theform);

        //#45489 recipe ID字符输入合法性校验 允许$R开头 与Recipe setup 一致
        String msg = FieldValidateUtils.validateRecipeId(recipe.getInstanceId());
        Assert.state(StringUtils.isEmpty(msg),Errors.create().content(msg).build());

        PropertyUtils.copyProperties(recipe, theform);

        String roleId = theform.getRoleId().trim();
        if (roleId.length() > 0) {
            long roleRrn = getInstanceRrn(roleId, getNamedSpace(ObjectList.ROLE_KEY, LocalContext.getFacilityRrn()),
                                          ObjectList.ROLE_KEY);

            Assert.isFalse(roleRrn <= 0, Errors.create().key(MessageIdList.SYSTEM_INSTANCE_NOT_FOUND).content("对象{}未找到")
                                               .args(ObjectList.ROLE_KEY).build());

            recipe.setRoleRrn(roleRrn);
        } else {
            recipe.setRoleRrn(null);
        }

        recipe.setTransId(Constants.CREATE_KEY);
        buildObjDocument(theform, recipe);
        process(recipe);
        recipe = getRecipeInfo(theform);

        changeRecipeStatusView(recipe);
        if (StringUtils.equalsIgnoreCase(StringUtils.STRING_ON, recipe.getAttributeData1())) {
            updateRelationExpireTime(recipe);
        }
        String time = request.getParameter("recipeTime");
        recipeService.saveRecipeTime(recipe.getInstanceRrn(), time, theform.getAttributeData3());

        WebUtils.setSuccessMsg(request);
        return init(mapping, theform, request, response);
    }

    @Override
    public ActionForward init(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                              HttpServletResponse response) throws Exception {
        RecipeVersionInfoForm theform = (RecipeVersionInfoForm) form;
        theform.setInstanceId(StringUtils.trimToUpperCase(theform.getInstanceId()));

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

        if (StringUtils.isEmpty(operatetiponly)) {
            operatetiponly = "N";
        }

        request.setAttribute("operatetiponly", operatetiponly);

        // 初始化跳转
        if (StringUtils.isNotEmpty(request.getParameter(Constants.NAV_KEY)) ||
                StringUtils.isEmpty(theform.getInstanceId())) {
            request.setAttribute(SessionNames.CONTEXT_KEY, new Context());
            theform = new RecipeVersionInfoForm();
            theform.setTransId(Constants.INIT_KEY);
            request.setAttribute(mapping.getAttribute(), theform);
            return mapping.findForward(Constants.MODIFY_KEY);
        }

        Recipe recipe = getRecipeInfo(theform);

        Context context = new Context();
        context.setInstanceRrn(
                getInstanceRrn(Constants.RECIPECONTEXT_KEY, LocalContext.getFacilityRrn(), ObjectList.CONTEXT_KEY));
        context = ctxService.getContext(context);

        if (recipe.getInstanceRrn() != 0) {
            context.setValues(recipeService.getContextValues(theform.getInstanceId()));
        }
        request.setAttribute(SessionNames.CONTEXT_KEY, context);

        PropertyUtils.copyProperties(theform, recipe);
        request.setAttribute(SessionNames.RECIPE_KEY, recipe);

        // 创建 跳转
        if (recipe.getInstanceRrn() == 0) {
            //这里主要卡控新增的recipe 要求可以$R 开头
            String msg = FieldValidateUtils.validateRecipeId(recipe.getInstanceId());
            Assert.state(StringUtils.isEmpty(msg),Errors.create().content(msg).build());
            theform.setTransId(Constants.CREATE_KEY);
            theform.setVersionEditEnable(BooleanUtils.toStringTrueFalse(false));
            return (mapping.findForward(Constants.MODIFY_KEY));
        }

        List<ObjectVersion> versions = (List<ObjectVersion>) recipe.getVersions();
        if (CollectionUtils.isNotEmpty(versions)) {
            RecipeVersion recipeVersion = new RecipeVersion();
            recipeVersion.copyObjectVersion(versions.get(0));
            if (recipeVersion.getChamberTypes() != null) {
                request.setAttribute("chamberTypes", recipeService.getChamberTypes(Arrays.asList(
                        StringUtils.split(recipeVersion.getChamberTypes(), RecipeVersion.CHAMBERSEPARATOR))));
            }
        }

        String recipeTime = recipeService.getRecipeTime(recipe.getInstanceRrn());
        if (recipeTime == null) {
            recipeTime = "";
        }
        request.setAttribute("recipeTime", recipeTime);

        List<Relation> attachedEqpt = recipeService.getEqptByRecipe(recipe.getInstanceRrn());

        // check recipe for prod_process_context_dtl
        boolean isSetFlag = recipeService.isSetForTemp(recipe.getInstanceRrn());

        theform.setVersionEditEnable(String.valueOf(checkVersionEditEnable(versions)));

        boolean hasUseFlag = false;
        if (context.getValues() != null && context.getValues().size() > 0) {
            hasUseFlag = true;
        }
        boolean deleteEnable = versions.size() <= 0 && attachedEqpt.isEmpty() && (!hasUseFlag) && (!isSetFlag);
        theform.setObjectDeleteEnable(BooleanUtils.toStringTrueFalse(deleteEnable));
        theform.setTransId(Constants.MODIFY_KEY);
        if (recipe.getObjectDocument() != null) {
            theform.setDocumentFile(recipe.getObjectDocument().getDocumentFile());
            theform.setDocumentFileCompulsorydisplay(recipe.getObjectDocument().getDocumentFileCompulsorydisplay());
        }
        return mapping.findForward(Constants.MODIFY_KEY);
    }

    public ActionForward modify(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                                HttpServletResponse response) throws Exception {
        RecipeVersionInfoForm theform = (RecipeVersionInfoForm) form;
        theform.setInstanceId(theform.getInstanceId().toUpperCase());
        Recipe recipe = getRecipeInfo(theform);
        PropertyUtils.copyProperties(recipe, theform);
        String roleId = theform.getRoleId().trim();
        if (roleId.length() > 0) {
            long roleRrn = getInstanceRrn(roleId, getNamedSpace(ObjectList.ROLE_KEY, LocalContext.getFacilityRrn()),
                                          ObjectList.ROLE_KEY);

            Assert.isFalse(roleRrn <= 0, Errors.create().key(MessageIdList.SYSTEM_INSTANCE_NOT_FOUND).content("对象{}未找到")
                                               .args(ObjectList.ROLE_KEY).build());

            recipe.setRoleRrn(roleRrn);
        } else {
            recipe.setRoleRrn(null);
        }
        recipe.setTransId(Constants.MODIFY_KEY);
        //除了description之外的数据发生变更,则不跳过验证
        if(notOnlyChangeDes(recipe,recipeService.getRecipe(recipe.getInstanceRrn()))) {
            isAllowModifyRecipe(recipe.getInstanceRrn(), recipe.getInstanceId());
        }
        buildObjDocument(theform, recipe);
        process(recipe);
        recipe = getRecipeInfo(theform);

        changeRecipeStatusView(recipe);
        if (StringUtils.equalsIgnoreCase(StringUtils.STRING_ON, recipe.getAttributeData1())) {
            updateRelationExpireTime(recipe);
        }
        String time = request.getParameter("recipeTime");
        recipeService.saveRecipeTime(recipe.getInstanceRrn(), time, theform.getAttributeData3());

        WebUtils.setSuccessMsg(request);
        return init(mapping, theform, request, response);
    }
    //功能#41424 rcp无法Modify description   将新旧两个recipe的数据进行比对,若除了description之外的数据发生变更,则不跳过验证
    public Boolean notOnlyChangeDes(Recipe newRecipe,Recipe oldRecipe){
        Map<String,Object> newRecipeMap =  BeanUtils.copyBeanToMap(newRecipe);
        Map<String, Object> oldRecipeMap = BeanUtils.copyBeanToMap(oldRecipe);
        newRecipeMap.entrySet().removeIf(entry -> entry.getValue()==null||StringUtils.equalsIgnoreCase(entry.getKey(),"objectDocument")||StringUtils.equalsIgnoreCase(entry.getKey(),"instanceDesc"));
        oldRecipeMap.entrySet().removeIf(entry -> entry.getValue()==null);

        for(Map.Entry<String,Object> item:newRecipeMap.entrySet()){
            String key  = item.getKey();
            if(oldRecipeMap.containsKey(key)){
                if (!StringUtils.equalsIgnoreCase(item.getValue().toString(), MapUtils.getString(oldRecipeMap,key))) {
                    return true;      //意味着页面和数据库中的值不一致
                }
            }
        }
        return false;
    }
    public ActionForward delete(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                                HttpServletResponse response) throws Exception {
        RecipeVersionInfoForm theform = (RecipeVersionInfoForm) form;
        Recipe recipe = getRecipeInfo(theform);

        recipe.setTransId(Constants.DELETE_KEY);
        theform.setInstanceId(StringUtils.EMPTY);

        isAllowDeleteRecipe(recipe.getInstanceRrn(), recipe.getInstanceId());

        process(recipe);

        WebUtils.setSuccessMsg(request);
        return init(mapping, theform, request, response);
    }

    private void changeRecipeStatusView(Recipe recipe) {
        Relation relation = new Relation();
        if (StringUtils.isNotBlank(recipe.getAttributeData1())) {
            relation.setTransId(Constants.UPDATE_KEY);
            relation.setTransPerformedby(LocalContext.getUserId());
            relation.setLinkType(LinkTypeList.ENTITY_TO_RECIPE);
            relation.setAttributedata2(String.valueOf(LocalContext.getUserRrn()));
            recipeService.updateRecipesStatus(RecipeStatus.ON_KEY, RecipeStatus.EXIST_KEY,
                                                    String.valueOf(recipe.getInstanceRrn()), relation);
            recipeService.updateRecipesStatus(RecipeStatus.OFF_KEY, RecipeStatus.NOTEXIST_KEY,
                                                    String.valueOf(recipe.getInstanceRrn()), relation);
        } else {
            relation.setTransId(Constants.UPDATE_KEY);
            relation.setTransPerformedby(LocalContext.getUserId());
            relation.setLinkType(LinkTypeList.ENTITY_TO_RECIPE);
            relation.setAttributedata2(String.valueOf(LocalContext.getUserRrn()));
            recipeService.updateRecipesStatus(RecipeStatus.EXIST_KEY, RecipeStatus.ON_KEY,
                                                    String.valueOf(recipe.getInstanceRrn()), relation);
            recipeService.updateRecipesStatus(RecipeStatus.NOTEXIST_KEY, RecipeStatus.OFF_KEY,
                                                    String.valueOf(recipe.getInstanceRrn()), relation);
        }
    }

    private void buildObjDocument(RecipeVersionInfoForm theform, Recipe recipe) {
        String documentFile = theform.getDocumentFile();
        // checked = "checked" on , no checked null
        String commons = theform.getDocumentFileCompulsorydisplay();

        long instanceRrn = recipe.getInstanceRrn();
        int version = 0;
        ObjectDocument obj = new ObjectDocument();
        obj.setDocumentFile(documentFile);
        obj.setDocumentFileCompulsorydisplay(commons);
        obj.setInstanceRrn(instanceRrn);
        // To be continued
        obj.setInstanceVersion(version);
        obj.setDocumentId(theform.getInstanceId());
        recipe.setObjectDocument(obj);
    }

    private void isAllowModifyRecipe(long recipeRrn, String recipeId) {
        Assert.isFalse(recipeService.isHasRunningLotForRecipe(LocalContext.getFacilityRrn(), recipeId),
                       Errors.create().key(MessageIdList.RECIPE_NOT_MODIFY_HAS_RUN_LOT)
                             .content("Cannot modify, there are RUNNING or RUNNINGHOLD lots under this").build());

        Assert.isFalse(recipeService.isHasEqptForRecipe(recipeRrn),
                       Errors.create().key(MessageIdList.RECIPE_NOT_MODIFY_HAS_EQP)
                             .content("Cannot modify, the EQP " + "associated with the recipe!").build());

        Assert.isFalse(recipeService.isHasRunEqptForRecipe(recipeRrn),
                       Errors.create().key(MessageIdList.RECIPE_NOT_MODIFY_HAS_RUN_EQP)
                             .content("Cannot modify, the EQP " + "associated with the " + "recipe is RUN!").build());
    }

    private void isAllowDeleteRecipe(long recipeRrn, String recipeId) {
        Assert.isFalse(recipeService.isHasRunningLotForRecipe(LocalContext.getFacilityRrn(), recipeId),
                       Errors.create().key(MessageIdList.RECIPE_NOT_DELETE_HAS_RUN_LOT)
                             .content("Cannot delete, there are RUNNING or RUNNINGHOLD lots under this ").build());

        Assert.isFalse(recipeService.isHasEqptForRecipe(recipeRrn),
                       Errors.create().key(MessageIdList.RECIPE_NOT_DELETE_HAS_EQP)
                             .content("Cannot delete, the EQP associated " + "with the recipe!").build());

        Assert.isFalse(recipeService.isHasRunEqptForRecipe(recipeRrn),
                       Errors.create().key(MessageIdList.RECIPE_NOT_DELETE_HAS_RUN_EQP)
                             .content("Cannot delete, the EQP associated with the recipe is RUN!").build());

        Assert.isFalse(recipeService.isHasProdProcContextSetup(LocalContext.getFacilityRrn(), recipeRrn),
                       Errors.create().key(MessageIdList.RECIPE_NOT_DELETE_HAS_PRODUCT_PROCESS)
                             .content("Cannot delete, there are recipe settings on the product-process!").build());
    }

    protected void updateRelationExpireTime(Recipe recipe) {
        HashMap<String, Object> map = new HashMap<String, Object>(2);
        map.put("expireTime", recipe.getAttributeData2());
        map.put("recipeRrn", recipe.getInstanceRrn());
        recipeService.updateExpireTime4ExperimentRecipe(map);
        List<Map> list = new ArrayList<Map>();
        list.add(map);
        recipeService.validateRecipeExipreTime(list);
    }

}