AutoMonitorLotDispatchAction.java

package com.mycim.webapp.actions;

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.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.msg.JsonUtils;
import com.mycim.server.edcchart.service.EdcChartService;
import com.mycim.server.ems.service.EmsService;
import com.mycim.server.rcp.service.RecipeService;
import com.mycim.server.wip.service.LotDispatchService;
import com.mycim.utils.CheckRegexUtils;
import com.mycim.utils.RcpUtils;
import com.mycim.valueobject.LocationNames;
import com.mycim.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.automonitor.dto.ReadingPromptDTO;
import com.mycim.valueobject.automonitor.entity.AutoMonitorItemStepEdcInfo;
import com.mycim.valueobject.automonitor.entity.LotAutoMonitorInfo;
import com.mycim.valueobject.automonitor.util.AutoMonitorOperationConstants;
import com.mycim.valueobject.automonitor.util.AutoMonitorUtils;
import com.mycim.valueobject.bas.InputObject;
import com.mycim.valueobject.bas.Relation;
import com.mycim.valueobject.consts.ActionPointList;
import com.mycim.valueobject.consts.TransactionNames;
import com.mycim.valueobject.ems.Equipment;
import com.mycim.valueobject.prp.Recipe;
import com.mycim.valueobject.prp.RecipeVersion;
import com.mycim.valueobject.wip.Lot;
import com.mycim.valueobject.wip.LotStatus;
import com.mycim.valueobject.wip.Unit;
import com.mycim.valueobject.wip.dto.*;
import com.mycim.webapp.Constants;
import com.mycim.webapp.WebUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * @author finatice.yang
 * @date 2021/9/8
 **/
public class AutoMonitorLotDispatchAction extends AutoMonitorAction {

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

    protected EdcChartService edcChartService = SpringContext.getBean(EdcChartService.class);

    @Override
    public ActionForward init(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                              HttpServletResponse response) {
        return dispatchInfo(mapping, form, request, response);
    }

    public ActionForward dispatchInfo(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                                      HttpServletResponse response) {

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

        Lot lot = lotInqService.getLot(lotId);

        String transId = "";
        if (LotStatus.isMoveInCheckStatus(lot.getLotStatus())) {
            transId = TransactionNames.MOVEIN_KEY;
        } else if (LotStatus.isMoveOutCheckStatus(lot.getLotStatus())) {
            transId = TransactionNames.MOVEOUT_KEY;
        } else {
            throw new SystemIllegalArgumentException(
                    Errors.create().key(MessageIdList.LOT_STATUS_NOT_ALLOW).content("Lot status not alolow").build());
        }

        String eqptId = WebUtils.getParameter("eqptId", request);
        Equipment equipment = emsService.getEquipment(eqptId, LocalContext.getFacilityRrn());

        LotAutoMonitorInfo lotMonitorInfo = lotAutoMonitorInqService.getLotActiveAutoMonitorInfo(lot.getLotRrn());
        Map<String, Object> lotMap = BeanUtils.copyBeanToMap(lot);
        lotMap.putAll(BeanUtils.copyBeanToMap(lotMonitorInfo));

        if (StringUtils.equals(TransactionNames.MOVEIN_KEY, transId)) {
            List<Lot> lotColls = new ArrayList<>();
            lotColls.add(lot);
            List<String> reticleIdList = new ArrayList<String>();
            if (lotMonitorInfo.getReticleRrn() != null && lotMonitorInfo.getReticleRrn() > 0) {
                reticleIdList.add(getInstanceId(lotMonitorInfo.getReticleRrn()));
            } else if (lotMonitorInfo.getReticleGroupRrn() != null && lotMonitorInfo.getReticleGroupRrn() > 0) {
                Collection<Relation> reticles = wipService
                        .getReticlesForMovein(lotMonitorInfo.getReticleGroupRrn(), equipment.getInstanceRrn(), false);
                for (Relation relation : reticles) {
                    String reticleCheckResult = reticleService
                            .checkIfReticleIsAvailable(relation.getInstanceRrn(), lot.getQty1());
                    if (StringUtils.isEmpty(reticleCheckResult)) {
                        reticleIdList.add(getInstanceId(relation.getInstanceRrn()));
                    }
                }
            }

            // 校验recipe
            String recipeId = lotMonitorInfo.getRecipeId();
            String recipeCheckResult = StringUtils.EMPTY;
            if (AutoMonitorUtils.checkStepIsMainProcessStep(lotMonitorInfo.getEqptType())) {
                recipeCheckResult = wipCheckService
                        .checkHasAvailableDispatchRecipeByAutoMonitor(lot, equipment.getInstanceRrn(), recipeId);
            } else {
                recipeCheckResult = wipCheckService
                        .checkHasAvailableDispatchRecipe(lot, equipment.getInstanceRrn(), recipeId,
                                                         lot.getInt_qty1().doubleValue());
            }
            Assert.state(StringUtils.isBlank(recipeCheckResult), Errors.create().content(recipeCheckResult).build());

            if (CheckRegexUtils.checkFlagOn(equipment.getIsChamberEquip())) {
                if(!wipCheckService.checkSingleChamberTypeRecipeChamberExsit(recipeId,equipment.getInstanceRrn())) {
                    Recipe recipe = recipeService.getRecipe(recipeId, LocalContext.getFacilityRrn());

                    RecipeVersion recipeVersion = recipeService
                            .getAvailableRecipeVersion(lot, equipment.getInstanceRrn(), recipe.getInstanceRrn());
                    if (Objects.nonNull(recipeVersion)) {
                        recipeId = recipeVersion.getInstanceId();
                    }
                }
            }

            lotMap.put("recipeId", recipeId);

            if (CollectionUtils.isNotEmpty(reticleIdList)) {
                request.setAttribute("reticleIdList", reticleIdList);
            }
        }

        request.setAttribute("lot", lotMap);
        request.setAttribute("eqptId", eqptId);
        request.setAttribute("jobStatus", lot.getLotStatus());
        request.setAttribute("transId", transId);

        return mapping.findForward("jobservice");
    }

    public ActionForward dispatchLot(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                                     HttpServletResponse response) {
        String eqptId = WebUtils.getParameter("eqptId", request);
        Equipment equipment = emsService.getEquipment(eqptId, LocalContext.getFacilityRrn());

        String lotId = WebUtils.getParameter("lotId", request);
        Lot lot = lotInqService.getLot(lotId);

        LotAutoMonitorInfo lotMonitorInfo = lotAutoMonitorInqService.getLotActiveAutoMonitorInfo(lot.getLotRrn());

        Assert.state(!(lotAutoMonitorInqService.checkAutoMonitorLotCanCreateSortJob(lotMonitorInfo) &&
                             lotMonitorInfo.getCarrierRrn().longValue() != lotMonitorInfo.getMonitorCarrierRrn().longValue()),
                     Errors.create().content("Lot need change to monitor cassette.").build());

        List<Lot> lotInfos = new ArrayList<>();
        List<LotInfoDto> dispatchLotTransDatas = new ArrayList<>();
        if (LotStatus.isMoveInCheckStatus(lot.getLotStatus())) {
            buildMoveInTransData(request, equipment, lot, lotMonitorInfo, lotInfos, dispatchLotTransDatas);
        } else if (LotStatus.isMoveOutCheckStatus(lot.getLotStatus())) {
            lot.setpLocation(lot.getLocation());
            lot.setpLocationRrn(lot.getLocationRrn());
            lot.setpLocationType(lot.getLocationType());
            lot.setLocation(StringUtils.EMPTY);
            lot.setLocationRrn(NumberUtils.LONG_ZERO);
            lot.setLocationType(StringUtils.EMPTY);
            lotInfos.add(lot);

            ParameterSetDto parameterSetDTO = null;
            if (StringUtils.isNotBlank(WebUtils.getParameter("edcOver", request))) {
                parameterSetDTO = buildParameterInfo(lot, lotMonitorInfo, request);
            } else {
                parameterSetDTO = buildParameterInfo(lot, lotMonitorInfo, null);

                if (Objects.nonNull(parameterSetDTO)) {
                    List<Map<String, Object>> edcInfos = new ArrayList<>();
                    Map<String, Object> edcInfo = MapUtils.newHashMap();
                    edcInfo.put("lot", lot);
                    edcInfo.put("parameterSetInfo", parameterSetDTO);
                    edcInfos.add(edcInfo);

                    request.setAttribute("lotId", lotId);
                    request.setAttribute("eqptId", eqptId);
                    request.setAttribute("edcInfos", edcInfos);
                    return mapping.findForward("edcPage");
                }
            }
            LotInfoDto transData = new LotInfoDto();
            LotBaseInfoDto lotBaseInfo = new LotBaseInfoDto();
            lotBaseInfo.setLotId(lot.getLotId());
            lotBaseInfo.setLotRrn(lot.getLotRrn());
            lotBaseInfo.setTrackFlag(ActionPointList.MOVEOUT_KEY);
            lotBaseInfo.setManualFlag(Boolean.TRUE);
            transData.setLotBaseInfo(lotBaseInfo);
            transData.setParameterSet(parameterSetDTO);
            dispatchLotTransDatas.add(transData);
        } else {
            // TODO: 2021/1/26
            throw new SystemIllegalArgumentException(
                    Errors.create().content("Lot Status:{}").args(lot.getLotStatus()).build());
        }


        List<String> lotRrns = new ArrayList<>();
        lotRrns.add(StringUtils.toString(lot.getLotRrn()));
        lotDispatchService.dispatchLot(lotInfos, equipment, dispatchLotTransDatas, lotRrns);

        return mapping.findForward("lotinfo");
    }

    private void buildMoveInTransData(HttpServletRequest request, Equipment equipment, Lot lot,
                                      LotAutoMonitorInfo lotMonitorInfo, List<Lot> lotInfos,
                                      List<LotInfoDto> dispatchLotTransDatas) {
        lot.setEqptRrn(equipment.getInstanceRrn());
        lot.setEqptID(equipment.getInstanceId());
        lot.setLocation(equipment.getInstanceId());
        lot.setLocationRrn(equipment.getInstanceRrn());
        lot.setLocationType(ObjectList.ENTITY_KEY);

        String recipeId = WebUtils.getParameterUpperCase("recipeId", request);

        if (StringUtils.isNotEmpty(StringUtils.trimToUpperCase(recipeId))) {
            Recipe recipe = recipeService.getRecipe(recipeId, LocalContext.getFacilityRrn());
            Assert.state(Objects.nonNull(recipe) && recipe.getInstanceRrn() > 0,
                         Errors.create().key(MessageIdList.RECIPE_INVALID_ID).content("Recipe not exist").build());

            lot.setPpid(recipe.getInstanceId());
            lot.setRecipeId(recipe.getInstanceId());
            lot.setRecipeRrn(recipe.getInstanceRrn());
            lot.setRecipePhysicalId(recipe.getInstanceId());
            lot.setRecipeLogicalRrn(recipe.getInstanceRrn());

            RecipeVersion recipeVersion = recipeService.getNowActiveRecipeVersion(recipe.getInstanceRrn());
            if (Objects.nonNull(recipeVersion)) {
                lot.setRecipeVersion(recipeVersion.getActiveVersion());
                lot.setChamberType(recipeVersion.getChamberTypes());
            }
        }

        String reticleId = StringUtils.EMPTY;
        if (StringUtils.isNotBlank(WebUtils.getParameter("needReticleFlag", request))) {
            String reticleIdSelect = StringUtils.trimToUpperCase(request.getParameter("reticleIdSelect"));
            String reticleIdInput = StringUtils.trimToUpperCase(request.getParameter("reticleIdInput"));
            Assert.state(StringUtils.isNotBlank(reticleIdSelect) && StringUtils.isNotBlank(reticleIdInput) &&
                                 StringUtils.equalsIgnoreCase(reticleIdSelect, reticleIdInput),
                         Errors.create().content("Input Reticle ID error,please check!").build());

            reticleId = reticleIdInput;

            long reticleRrn = baseService.getNamedObjectRrn(reticleId, baseService
                                                                    .getNamedSpace(LocalContext.getFacilityRrn(),
                                                                                   ObjectList.ENTITY_KEY),
                                                            ObjectList.ENTITY_KEY,
                                                            ObjectList.RETICLE_KEY);
            Assert.state(reticleRrn > 0, Errors.create().key(MessageIdList.RETICLE_RETICLEID_INVALID).build());

            lot.setReticleId(reticleId);
            lot.setReticleRrn(reticleRrn);
        }

        lotInfos.add(lot);

        LotInfoDto transData = new LotInfoDto();
        LotBaseInfoDto lotBaseInfo = new LotBaseInfoDto();
        lotBaseInfo.setLotId(lot.getLotId());
        lotBaseInfo.setLotRrn(lot.getLotRrn());
        lotBaseInfo.setPpid(recipeId);
        lotBaseInfo.setTrackFlag(ActionPointList.MOVEIN_KEY);
        lotBaseInfo.setManualFlag(Boolean.TRUE);
        if (StringUtils.isNotBlank(reticleId)) {
            lotBaseInfo.setReticleId(reticleId);
        }
        transData.setLotBaseInfo(lotBaseInfo);
        dispatchLotTransDatas.add(transData);
    }

    private ParameterSetDto buildParameterInfo(Lot lot, LotAutoMonitorInfo monitorInfo, HttpServletRequest request) {
        List<AutoMonitorItemStepEdcInfo> edcInfoList = autoMonitorItemInqService
                .getEdcInfoList(monitorInfo.getWorkflowRrn(), monitorInfo.getWorkflowVersion(),
                                monitorInfo.getWorkflowStepSequence());
        if (CollectionUtils.isEmpty(edcInfoList)) {
            return null;
        }

        if (lotAutoMonitorInqService.checkAutomonitorLotNeedSkipEdc(lot.getLotRrn(), lot.getStepSequence())) {
            return null;
        }

        List<Map> nonRTJobList = edcChartService.getMainEqpNonRTJobList(monitorInfo.getMainEqptRrn());
        if (CollectionUtils.isEmpty(nonRTJobList)) {
            return null;
        }

        String nonRTSlotType = monitorInfo.getNonRTSlotType();

        checkNonRtJobInSpc(edcInfoList, nonRTJobList, nonRTSlotType);

        ParameterSetDto parameterSetDto = new ParameterSetDto();
        parameterSetDto.setParameters(new ArrayList<>());

        List<Unit> unitList = getUnitList(lot.getLotRrn());

        if (StringUtils.equals(nonRTSlotType, AutoMonitorOperationConstants.STEP_SLOT_TYPE_WAFER)) {
            Map<String, List<Unit>> jobUnitMapping = MapUtils.newHashMap();

            for (AutoMonitorItemStepEdcInfo edcInfo : edcInfoList) {
                String[] jobNames = StringUtils.split(edcInfo.getNonRTJobNames(), StringUtils.COMMA_SIGN);
                for (String jobName : jobNames) {
                    if (Objects.isNull(MapUtils.getObject(jobUnitMapping, jobName))) {
                        jobUnitMapping.put(jobName, new ArrayList<>());
                    }
                    jobUnitMapping.get(jobName).add(unitList.get(edcInfo.getWaferSlot().intValue() - 1));
                }
            }

            for (String jobName : jobUnitMapping.keySet()) {
                Integer subGroupSize = getSubGroupSize(nonRTJobList, jobName);
                parameterSetDto.getParameters()
                               .add(buildParameterDto(jobName, subGroupSize, jobUnitMapping.get(jobName), request));
            }
        } else {
            AutoMonitorItemStepEdcInfo edcInfo = edcInfoList.iterator().next();
            String[] jobNames = StringUtils.split(edcInfo.getNonRTJobNames(), StringUtils.COMMA_SIGN);
            for (String jobName : jobNames) {
                Integer subGroupSize = getSubGroupSize(nonRTJobList, jobName);
                parameterSetDto.getParameters().add(buildParameterDto(jobName, subGroupSize, unitList, request));
            }
        }
        parameterSetDto.setParameterSize(parameterSetDto.getParameters().size());
        return parameterSetDto;
    }

    private Integer getSubGroupSize(List<Map> nonRTJobList, String jobName) {
        Integer subGroupSize = NumberUtils.INTEGER_ZERO;
        for (Map map : nonRTJobList) {
            if (StringUtils.equals(MapUtils.getString(map, "JobName"), jobName)) {
                subGroupSize = MapUtils.getInteger(map, "SubgroupSize");
                break;
            }
        }
        return subGroupSize;
    }

    private ParameterDto buildParameterDto(String jobName, Integer subGroupSize, List<Unit> unitList,
                                           HttpServletRequest request) {
        ParameterDto parameterDto = new ParameterDto();
        parameterDto.setParameterId(jobName);
        parameterDto.setSamplePrompts(new ArrayList<SampleDto>());

        for (int j = 0; j < unitList.size(); j++) {
            Unit unit = unitList.get(j);
            String unitId = unit.getUnitId();

            SampleDto samplePromptDTO = new SampleDto();
            samplePromptDTO.setUnitId(unitId);
            samplePromptDTO.setUnitRrn(unit.getUnitRrn());
            samplePromptDTO.setPosition(unit.getPositionInCarrier() + "");
            samplePromptDTO.setReadingPrompts(new ArrayList<ReadingDto>());
            samplePromptDTO.setSampleSequence(j + 1);

            for (int k = 0; k < subGroupSize; k++) {
                ReadingDto readingDto = new ReadingDto();
                String readingId = "Reading " + (k + 1);
                readingDto.setReadingId(readingId);
                readingDto.setReadingSequence(k + 1);
                if (request != null) {
                    String requestName = jobName + unitId;
                    Double dataValue = NumberUtils.toDouble(request.getParameterValues(requestName)[k]);
                    readingDto.setDataValue(dataValue);
                }
                samplePromptDTO.getReadingPrompts().add(readingDto);
                samplePromptDTO.setReadingPromptSize(samplePromptDTO.getReadingPrompts().size());
            }
            parameterDto.getSamplePrompts().add(samplePromptDTO);
            parameterDto.setSamplePromptSize(parameterDto.getSamplePrompts().size());
        }

        return parameterDto;
    }

    private void checkNonRtJobInSpc(List<AutoMonitorItemStepEdcInfo> edcInfoList, List<Map> nonRTJobList,
                                    String slotType) {

        List<String> notInSpcJobNameList = new ArrayList<>();
        if (StringUtils.equals(slotType, AutoMonitorOperationConstants.STEP_SLOT_TYPE_WAFER)) {
            for (AutoMonitorItemStepEdcInfo edcInfo : edcInfoList) {
                String[] jobNames = StringUtils.split(edcInfo.getNonRTJobNames(), StringUtils.COMMA_SIGN);

                for (String jobName : jobNames) {
                    boolean notInSpc = true;
                    for (Map map : nonRTJobList) {
                        if (StringUtils.equals(MapUtils.getString(map, "JobName"), jobName)) {
                            notInSpc = false;
                            break;
                        }
                    }
                    if (notInSpc && !notInSpcJobNameList.contains(jobName)) {
                        notInSpcJobNameList.add(jobName);
                    }
                }
            }
        } else {
            AutoMonitorItemStepEdcInfo edcInfo = edcInfoList.iterator().next();
            String[] jobNames = StringUtils.split(edcInfo.getNonRTJobNames(), StringUtils.COMMA_SIGN);
            for (String jobName : jobNames) {
                boolean notInSpc = true;
                for (Map map : nonRTJobList) {
                    if (StringUtils.equals(MapUtils.getString(map, "JobName"), jobName)) {
                        notInSpc = false;
                        break;
                    }
                }
                if (notInSpc && !notInSpcJobNameList.contains(jobName)) {
                    notInSpcJobNameList.add(jobName);
                }
            }
        }

        Assert.state(CollectionUtils.isEmpty(notInSpcJobNameList),
                     Errors.create().key(MessageIdList.AUTOMONITOR_NONRT_NOT_IN_SPC)
                           .args(notInSpcJobNameList.toString()).build());
    }

}