CreateJobAtEquipmentExtAction.java

package com.mycim.webapp.actions.operation;

import com.fa.sesa.exception.Assert;
import com.fa.sesa.exception.Errors;
import com.fa.sesa.exception.SystemIllegalArgumentException;
import com.fa.sesa.i18n.I18nUtils;
import com.fa.sesa.threadlocal.LocalContext;
import com.mycim.framework.utils.beans.BeanUtils;
import com.mycim.framework.utils.lang.StringUtils;
import com.mycim.framework.utils.lang.collections.MapUtils;
import com.mycim.framework.utils.lang.time.DateUtils;
import com.mycim.utils.WetBatchUtils;
import com.mycim.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.SystemConstant;
import com.mycim.valueobject.bas.ErrorMsg;
import com.mycim.valueobject.consts.JobStatus;
import com.mycim.valueobject.consts.LinkTypeList;
import com.mycim.valueobject.consts.SessionNames;
import com.mycim.valueobject.ems.Entity;
import com.mycim.valueobject.ems.Equipment;
import com.mycim.valueobject.ems.SpcResultEquipment;
import com.mycim.valueobject.prp.Operation;
import com.mycim.valueobject.prp.RecipeVersion;
import com.mycim.valueobject.security.Station;
import com.mycim.valueobject.wip.*;
import com.mycim.webapp.Constants;
import com.mycim.webapp.WebUtils;
import com.mycim.webapp.actions.WipSetupAction;
import com.mycim.webapp.forms.JobOfEquipmentInfoForm;
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.*;

/**
 * CreateJobAtEquipmentExt
 *
 * @author pinyan.song
 * @version 6.0.0
 * @date 2019-10-24
 **/
public class CreateJobAtEquipmentExtAction extends WipSetupAction {

    @Override
    public ActionForward init(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                              HttpServletResponse response) throws Exception {
        // Create方法抛出异常时, 通过init转到error.jsp
        return mapping.findForward(Constants.ERROR_KEY);
    }

    public ActionForward create(ActionMapping mapping, JobOfEquipmentInfoForm theform, HttpServletRequest request,
                                HttpServletResponse response) throws Exception {

        String user = LocalContext.getUserId();
        long userRrn = LocalContext.getUserRrn();
        Long facilityRrn = LocalContext.getFacilityRrn();
        request.setAttribute("automovein", "automovein");
        List<Lot> s_lots = new ArrayList<>();

        Station station = new Station(getInstanceId(new Long(request.getParameter("stationRrn"))),
                                      getNamedSpace(ObjectList.STATION_KEY, facilityRrn), ObjectList.STATION_KEY);
        station = securityService.getStation(station);
        station.setUsers(securityService.getUserOfStation(station.getInstanceRrn()));

        String lotList = request.getParameter("lotList");
        String cou = request.getParameter("cou");
        String cou1 = request.getParameter("cou1");
        String stationRrn = request.getParameter("stationRrn");

        Long eqptRrn = WebUtils.getParameterLong("eqptRrn", request);
        Equipment equipment = new Equipment();
        equipment.setInstanceRrn(eqptRrn);
        Equipment e = emsService.getEquipment(equipment);
        equipment = e == null ? equipment : e;

        Equipment _eqt = emsService.getEquipment(eqptRrn);
        String operationMode = _eqt.getOperationMode();

        Map entityExtMap = this.emsService.getEquipmentExtMap(equipment.getInstanceRrn());
        Entity entity = new Entity(baseService.getNamedObject(equipment).getInstanceId(),
                                   getNamedSpace(ObjectList.ENTITY_KEY, facilityRrn), ObjectList.ENTITY_KEY);
        entity = emsService.getEntity(entity);
        String diffFlag = MapUtils.getString(entityExtMap, "diffFlag");

        // Check special dispatch rule, added by yichao, 20130723
        if ("on".equals(station.getDispatchRuleFlag())) {
            // 在批次track in时候,对此时该设备下的waitting批次判断,是否有和该批次使用菜单相同批次,
            // 如果没有,正常track in,如果有,弹出提示框,让选择是继续,还是cancel。
            // 说明:在JS页面中做检查

            // 在按机台作业设备下,看到的批次只对waitting状态的批次进行判断,有大于其优先等级两个等级的批次,该批次不能track in作业。
            // 如果由于机台设置一次可以track in多个批次,其中如有1个批次是上面规则判断可以track in的,那允许track in。
            // 除非多批次中每个批次都无法track in,才禁止此次操作。
            String passLots = "";
            String forbidLots = "";
            String highLevelLots = "";
            for (int j = 0; j < new Long(cou).intValue(); j++) { // Lots to be move in
                String lId = request.getParameter("lotId" + j);
                Lot sLot = getLot(lId);
                for (int i = 0; i < new Long(cou1).intValue(); i++) { // Lots at waiting
                    String lIdA = request.getParameter("lotIdA" + i);
                    Lot sLotA = getLot(lIdA);
                    if ("WAITING".equalsIgnoreCase(sLotA.getLotStatus())) {
                        if (sLotA.getPriority() <= sLot.getPriority() - 2) {
                            if (!(forbidLots.indexOf(lId) > 0)) {
                                forbidLots += ":" + lId;
                            }
                            if (!(highLevelLots.indexOf(lIdA) > 0)) {
                                highLevelLots += "," + lIdA;
                            }
                        }
                    }
                }
                if (!(forbidLots.indexOf(lId) > 0)) {
                    passLots += ":" + lId;
                }
            }
            Assert.isFalse("".equals(passLots), Errors.create().content(
                    "The priority of {} is two grades higher than the " + "current lot.The current lot " +
                            "cannot be " + "MoveIn!").args(highLevelLots).build());
        }

        Map holdPMMap = wipCheckService.validateEquipPMStatus(entity);
        String msg = "";
        String msgPMInfo = wipCheckService.validateEquipPMStatusReturnMsg(holdPMMap);
        if (Boolean.parseBoolean(MapUtils.getString(holdPMMap, "pmHold"))) {
            if (holdPMMap.get("checklistSize") != null) {
                msg = I18nUtils.getMessage(MessageIdList.EQUIPMENT_PM_SUSPENDED,
                                           "The EQP is suspended by PM and cannot be processed.!", msgPMInfo,
                                           (MapUtils.getString(holdPMMap, "checklistJobIds")));
            }
            throw new SystemIllegalArgumentException(Errors.create().content(msg).build());
        }

        List list = emsService.getEquipmentHoldInfo(equipment.getInstanceRrn());
        for (int i = 0; i < new Long(cou).intValue(); i++) {
            String id = request.getParameter("lotId" + i);
            Lot lot = getLot(id);
            Assert.isFalse(!list.isEmpty() && lot.getLotStatus().equals("WAITING"),
                           Errors.create().content("EQP suspended,lot {} Can't send " + "out work {}")
                                 .args(lot.getLotId(), SpcResultEquipment.getReasonInfo(list)).build());

            // Recipe超时提醒.
            List<Map> lots = new ArrayList<>();
            Map item = new HashMap();
            item.put("lotRrn", lot.getLotRrn() + "");
            lots.add(item);
            String recipeTimeOutMsg = checkRecipeTimeOutMsg(lots);
            if (StringUtils.isNotBlank(recipeTimeOutMsg)) {
                int index = recipeTimeOutMsg.indexOf("|");
                if (index >= 0) {
                    String timeOutAction = recipeTimeOutMsg.substring(0, index);
                    recipeTimeOutMsg = recipeTimeOutMsg.substring(index + 1);
                    Assert.isFalse(timeOutAction.equalsIgnoreCase("HOLD"),
                                   Errors.create().content(recipeTimeOutMsg).build());
                }
                request.setAttribute("TIMEOUT_INFO", recipeTimeOutMsg);
            }
        }

        if (holdPMMap.get("checklistSize") != null) {
            msg = msgPMInfo;
            if (holdPMMap.get("checklistSize") != null) {
                msg += "\n" + ((String) holdPMMap.get("checklistJobIds")).replaceAll("<br>", "\n");
            }
            request.setAttribute("PM_CHECKLIST_INFO", msg);
        }

        //session.setAttribute(SessionNames.ENTITY_KEY, equipment);
        request.setAttribute(SessionNames.ENTITY_KEY, equipment);
        theform.setTransId("nomal");

        String eqptId = getInstanceId(eqptRrn);
        // 检查设备上recipe失效间隔限制
        emsService.checkEquipmentRecipeInvalid(equipment.getInstanceRrn());
        List<Map> recipes = recipeService.getRelation4Recipe(equipment.getInstanceRrn(), LinkTypeList.ENTITY_TO_RECIPE);
        // check product constrain
        Lot firstNDlot = null;
        // boolean dummyBatch = false;
        // boolean isAllDummy = true;
        Long recipeRrn = null;
        for (int i = 0; i < new Long(cou).intValue(); i++) {

            String lId = request.getParameter("lotId" + i);
            Lot sLot = getLot(lId);
            //            sLot = getLot(sLot);

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

            String recipePhysicalId = sLot.getRecipePhysicalId();
            if (StringUtils.isBlank(recipePhysicalId) || recipePhysicalId.contains("*")) {
                sLot.setEqptID(getInstanceId(equipment.getInstanceRrn()));
                RecipeVersion version = recipeService.getLotRecipe(sLot);
                Assert.isFalse(version == null || StringUtils.isBlank(version.getPpid()),
                               Errors.create().content("Do not get the Recipe ID, please confirm!").build());
                recipePhysicalId = version.getPpid();
            }
            boolean isRecipeOk = false;

                /*// dummy lot check
                if (new Long(cou).intValue() > 1) {
                    isAllDummy = false;
                }
                if (new Long(cou).intValue() > 1) {
                    dummyBatch = true;
                }*/

            long physicalRecipeRrn = getInstanceRrn(recipePhysicalId, facilityRrn, ObjectList.RECIPE_KEY);
            Assert.isFalse(physicalRecipeRrn <= 0,
                           Errors.create().content("The recipe is not defined in the system!").build());
            // dummy lot不验证recipe
            // if ("D".equals(sLot.getLotType()) || recipes.isEmpty()) {
            // isRecipeOk = true;
            // } else {
            for (Object o : recipes) {
                Map recipe = (Map) o;
                String status = MapUtils.getString(recipe, "status");
                if (StringUtils.equalsIgnoreCase(recipePhysicalId, MapUtils.getString(recipe, "recipeId")) &&
                        (StringUtils.equals("ON", status) || StringUtils.equals("EXIST", status))) {
                    isRecipeOk = true;
                    break;
                }
            }
            // }

            Assert.isTrue(isRecipeOk, Errors.create().content(
                    "The available recipe and lot on the EQP. Recipe does not " + "match!").build());

            if (recipeRrn == null) {
                recipeRrn = physicalRecipeRrn;
            } else {
                Assert.isFalse(recipeRrn != physicalRecipeRrn, Errors.create().content("Not the same recipe!").build());
            }

            ErrorMsg errorMsg = constrainService.checkLotConstrain(equipment, sLot);

            Assert.isFalse(errorMsg.getError(), Errors.create().content(errorMsg.getErrorMsg()).build());

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

        /*
         * if (dummyBatch) { for (int i = 0; i < new Long(cou).intValue(); i++) { String lId =
         * request.getParameter("lotId" + i); log.info("lId" + i + "===" + lId); Lot sLot = getLot
         * (lId); sLot =
         * getLot(sLot); if (sLot.getOperationRrn().longValue() != firstNDlot.getOperationRrn()
         * .longValue()) {
         * if(StringUtils.equalsIgnoreCase("CN", language)){ // request.setAttribute(ErrorDef
         * .MYCIM_ERR_KEY, new
         * ValidateFailureException("作业列表中的批次步骤不相同")); }else{ // request.setAttribute(ErrorDef
         * .MYCIM_ERR_KEY, new
         * ValidateFailureException("The lot steps in the job list are different.")); } // return
         * (mapping.findForward("error")); } if (!firstNDlot.getRecipeId().equals(sLot.getRecipeId()) &&
         * !isAllDummy) { request.setAttribute(ErrorDef.MYCIM_ERR_KEY, new
         * ValidateFailureException("作业列表中的批次recipe不相同")); return (mapping.findForward("error")); } } }
         */
        // end

        for (int i = 0; i < new Long(cou).intValue(); i++) {
            String lId = request.getParameter("lotId" + i);
            Lot sLot = getLot(lId);
            s_lots.add(sLot);
        }

        Lot slot = s_lots.iterator().next();
        String operationId = slot.getOperationId();
        Operation operation = new Operation();
        operation.setInstanceId(operationId);
        operation.setNamedSpace(getNamedSpace(ObjectList.OPERATION_KEY, facilityRrn));
        operation = prpService.getOperation(operation.getInstanceId(), operation.getNamedSpace());
        for (Lot lotInfo : s_lots) {
            lotInfo = lotQueryService.getLot(lotInfo.getLotRrn());
            String lotOperationId = lotInfo.getOperationId();
            Operation lotOperation = new Operation();
            lotOperation.setInstanceId(lotOperationId);
            lotOperation.setNamedSpace(getNamedSpace(ObjectList.OPERATION_KEY, facilityRrn));
            lotOperation = prpService.getOperation(lotOperation.getInstanceId(), lotOperation.getNamedSpace());

            Assert.isTrue(StringUtils.equals(operation.getMvinWflId(), lotOperation.getMvinWflId()), Errors.create()
                                                                                                           .content(
                                                                                                                   "The Lot's Start Routine not same,please re-select Lots with same " +
                                                                                                                           "Start Routine!")
                                                                                                           .build());

            Assert.isTrue(StringUtils.equals(operation.getMvouWflId(), lotOperation.getMvouWflId()), Errors.create()
                                                                                                           .content(
                                                                                                                   "The Lot's End Routine not same, please re-select Lots with same End " +
                                                                                                                           "Routine!")
                                                                                                           .build());
        }
        List<Long> jobLots = new ArrayList<>();
        List<Lot> lockLots = new ArrayList<>();
        List<Map> lotInfos = new ArrayList<>();
        Lot tLot = new Lot();
        Job job = (Job) request.getAttribute(SessionNames.JOB_KEY);

        if (s_lots.size() < 1) {
            Assert.isFalse(request.getParameter(Constants.CREATE_KEY) != null,
                           Errors.create().content("No lot selected to be " + "created !").build());

            Assert.isTrue(request.getParameter(Constants.CREATE_KEY) != null,
                          Errors.create().content("Use cancel job to delete" + " all lots in job" + " list").build());
        }

        long total_slots_qty = 0;
        for (Lot s_lot : s_lots) {
            long qty = s_lot.getQty1().longValue();
            total_slots_qty = total_slots_qty + qty;

        }
        Assert.isTrue(wipCheckService.isValidJobSize(eqptRrn, s_lots.size(), total_slots_qty),
                      Errors.create().key(MessageIdList.LOT_INVALID_JOB_SIZE).content("Invalid Job Size!").build());

        boolean createFlag = true;

        if (createFlag) {
            job = new Job();
            job.setTransPerformedby(user);
            job.setJobComments(theform.getJobComments());
            job.setEqptRrn(eqptRrn);
            equipment.setInstanceRrn(job.getEqptRrn().longValue());
            // get operation and recipe,recipeParameter
            Iterator _temp = s_lots.iterator();

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

            Long operationRrn = tLot.getOperationRrn();

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

        for (Lot _tlot : s_lots) {
            Lot lot = lotQueryService.getLot(_tlot.getLotRrn());

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

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

            long lotJobRrn = lot.getJobRrn();
            /*if (StringUtils.equalsIgnoreCase(LotStatus.DISPATCH, lot.getLotStatus()) && lotJobRrn > 0 &&
                    StringUtils.isBlank(lot.getRecipePhysicalId())) {
                autoCancelMoveIn(user, facilityRrn, lot);
            }*/

            String category = lot.getCreateCategory();
            String lotType = lot.getLotType();

            wipCheckService.validateLotOverQueueTime(lot);
            jobLots.add(_tlot.getLotRrn());
            lockLots.add(_tlot);
            checkLotAndSetParameters(_tlot,lot,equipment,lotInfos);

        }

        if (createFlag) {
            if (theform.getTransId().equals("nomal")) {

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

                // get first lot
                Lot firstLot = new Lot();

                Iterator _it = s_lots.iterator();

                if (_it.hasNext()) {
                    firstLot = (Lot) _it.next();
                }

                context.put("lotRrn", firstLot.getLotRrn());
                Assert.isTrue(wipCheckService.validJobSize(job),
                              Errors.create().content("Equipment currently busy.").build());
                validLotInEqp(eqptRrn, lockLots);

                job.setEqptId(equipment.getInstanceId());
                job.setExecutionRrn(0L);
                job.setUOM1(firstLot.getUOM1());
                job.setUOM2(firstLot.getUOM2());
                //                checkAndCreateLotsTransLock(userRrn, TransactionNames.LOCK_MOVEIN, lockLots,
                //                                            " movein-createJob in
                //                                            CreateJobAtEquipmentExtAction by: "
                //                                            + LocalContext.getUserId());
                // job = wipService.createJob(job, jobLots);
                request.setAttribute(SessionNames.JOB_KEY, job);
                request.setAttribute(SessionNames.COLLECTION_KEY, lotInfos);
                request.setAttribute("automovein", "automovein");
                request.setAttribute("transId", theform.getTransId());
                return mapping.findForward("jobservice");
            }
        }

        if (theform.getTransId().equals("future")) {
            return new ActionForward(mapping.getInput());
        } else if (theform.getTransId().equals("nomal")) {
            return mapping.findForward("jobmanagement");
        } else {
            // session.setAttribute(SessionNames.COLLECTION_KEY, s_lots);
            request.setAttribute(SessionNames.COLLECTION_KEY, s_lots);
            // session.setAttribute(SessionNames.OBJECT_KEY, "equipment");
            request.setAttribute(SessionNames.OBJECT_KEY, "equipment");
            return mapping.findForward("jobservice");
        }
    }

    public String validateEqptPMCounterStatus(Map params) {
        long eqptRrn = MapUtils.getLong(params, "eqptRrn");
        List<String> lotIds = (List<String>) MapUtils.getObject(params, "lotIds");

        if (lotIds.size()>=2){//判断lot的当前step id是否一致
            for (int i = 0; i < lotIds.size()-1; i++) {
                Assert.isTrue(StringUtils.equalsIgnoreCase(lotQueryService.getLot(lotIds.get(i), LocalContext.getFacilityRrn()).getOperationId(),
                                                           lotQueryService.getLot(lotIds.get(i+1), LocalContext.getFacilityRrn()).getOperationId()),
                              Errors.create().content("The current step ID of main and by-products is inconsistent").build());
            }
        }
        Equipment equipment = new Equipment();
        equipment.setInstanceRrn(eqptRrn);
        Entity entity = emsService.getEntity(equipment);


        Long recipeRrn = null;
        List<Lot> lotsTempForCheckEqpt = new ArrayList<>();
        for (String lotId : lotIds) {
            Lot lot = lotQueryService.getLot(lotId, LocalContext.getFacilityRrn());
            Assert.isFalse(lot == null || lot.getLotRrn() <= 0,
                           Errors.create().key(MessageIdList.LOT_MISSING_ID).content("Lot id does not exist!").build());
            // 目前PMCounter不支持多工艺菜单的判断数量扣减,故与PMCounterAction一致,指定第一个批次的recipeRrn。
            recipeRrn = recipeRrn == null ? lot.getRecipeLogicalRrn() : recipeRrn;

            lotsTempForCheckEqpt.add(lot);
        }

        Equipment checkEqpt = emsService.getEquipment(equipment);
        if (lotsTempForCheckEqpt.size() > 1
                && SystemConstant.Str.NUM_TRUE.equalsIgnoreCase(checkEqpt.getWetFlag())
                && !checkEqpt.getWetMap().isEmpty()){
            String message = WetBatchUtils.checkWetBatchList(lotsTempForCheckEqpt, checkEqpt);
            Assert.isFalse(StringUtils.isNotBlank(message),
                           Errors.create().key(MessageIdList.NOT_EXIST_WET_LIST).content("ProductID of {} is not in the list of Wet Batch!").args(message).build());
        }

        return wipCheckService.validateEqptPMCounterStatus(entity, recipeRrn, lotsTempForCheckEqpt);
    }

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

    private void autoCancelMoveIn(String user, Long facilityRrn, Lot lot) throws Exception {
        String reason = "SYSTEM 0 SYSTEM AutoCancelMoveIn";

        TransReason transReason = new TransReason();
        transReason.setReasonCode("SYSTEM");
        transReason.setReason(reason);
        transReason.setResponsibility(user);
        transReason.setTransQty1(lot.getQty1());
        transReason.setTransQty2(lot.getQty2());

        lotService
                .autoCancelMoveIn(lot.getLotRrn(), lot.getLotStatus(), lot.getJobRrn(), user, "System AutoCancelMoveIn",
                                  transReason);
    }

    private Lot getLot(String id) {
        Lot l = lotQueryService.getLot(id);
        return l == null ? new Lot() : l;
    }

    private void checkLotAndSetParameters(Lot _tlot,Lot lot,Equipment equipment,List<Map>  lotInfos) {
        Map lotInfo = BeanUtils.copyBeanToMap(_tlot);

        long spent = DateUtils.getDistanceTime4Now(lot.getQueueTimestamp());

        lotInfo.put("queueTimestamp", new Long(spent / 60).toString());
        lotInfo.put("recipeId", baseService.getNamedObjectId(MapUtils.getLongValue(lotInfo, "recipeRrn", 0)));
        lotInfo.put("processId", baseService.getNamedObjectId(MapUtils.getLongValue(lotInfo, "processRrn", 0)));
        lotInfo.put("productId", baseService.getNamedObjectId(MapUtils.getLongValue(lotInfo, "productRrn", 0)));

        lotInfo.put("operationDesc", lot.getOperationDesc());
        lotInfo.put("reticleId", baseService.getNamedObjectId(MapUtils.getLong(lotInfo, "reticleRrn")));
        lotInfo.put("equipmentRrn", equipment.getInstanceRrn());
        lotInfo.put("eqptId", equipment.getInstanceId());
        lotInfo.put("executionRrn", "0");
        lotInfo.put("isUniqueCarrierFlag", "1");
        lotInfo.put("isUniqueJobFlag", "0");
        lotInfo.put("facilityRrn", LocalContext.getFacilityRrn());

        lotInfo.put("recipePhysicalId", lot.getRecipePhysicalId());
        lotInfo.put("recipeId", lot.getRecipeId());
        lotInfo.put("recipeRrn", baseService.getNamedObjectRrn(lot.getRecipeId(), baseService
                .getNamedSpace(LocalContext.getFacilityRrn(), ObjectList.RECIPE_KEY), ObjectList.RECIPE_KEY));
        lotInfos.add(lotInfo);
    }

}