JobManagementDispatchAction.java
package com.mycim.webapp.actions.operation;
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.StringUtils;
import com.mycim.framework.utils.lang.collections.CollectionUtils;
import com.mycim.framework.utils.lang.collections.MapUtils;
import com.mycim.framework.utils.lang.time.DateUtils;
import com.mycim.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.consts.*;
import com.mycim.valueobject.ems.Equipment;
import com.mycim.valueobject.prp.RecipeVersion;
import com.mycim.valueobject.wip.BatchLotStore;
import com.mycim.valueobject.wip.Job;
import com.mycim.valueobject.wip.Lot;
import com.mycim.valueobject.wip.LotStatus;
import com.mycim.webapp.Constants;
import com.mycim.webapp.actions.WipSetupAction;
import com.mycim.webapp.forms.EntityAttrEqptForm;
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.*;
/**
* @author Johnson.Wang
* @version 6.0.0
* @date 2019/9/25
**/
public class JobManagementDispatchAction extends WipSetupAction {
@Override
public ActionForward init(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
//以下代码作用为:当批次作业页面因为数据未刷新而报错时,就刷新此页面
if (StringUtils.equals("lotLocation", request.getParameter("currentPage"))) {
return mapping.findForward("init");
} else {
return jobManagementDispatch(mapping, form, request, response);
}
}
public ActionForward jobManagementDispatch(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
JobOfEquipmentInfoForm theform = (JobOfEquipmentInfoForm) form;
request.setAttribute("jobservice_flag", "true");
Equipment equipment = null;
if (request.getParameter("equipmentRrn") != null) {
equipment = emsService.getEquipment(Long.parseLong(request.getParameter("equipmentRrn")));
} else {
String id = theform.getEquipmentId().trim().toUpperCase();
equipment = new Equipment(id, getNamedSpace(ObjectList.ENTITY_KEY, LocalContext.getFacilityRrn()),
ObjectList.ENTITY_KEY);
equipment = emsService.getEquipment(equipment);
}
Assert.isFalse(equipment.getInstanceRrn() == 0,
Errors.create().key(MessageIdList.SYSTEM_INSTANCE_NOT_FOUND).content("{} 没有找到对象!")
.args("Equipment").build());
// todo equipment 和station需不需要校验
// 检查批次是否已经在batch中
String lotId = request.getParameter("lotId");
long lotRrn = lotQueryService.getLotRrn(lotId);
List<BatchLotStore> batchLotStores = diffBatchQueryService.getBatchStoreListByLot(lotRrn);
Assert.isFalse(CollectionUtils.isNotEmpty(batchLotStores), Errors.create().key(MessageIdList.BATCH_CONTAIN_LOT)
.content("The Lot in batch ,can not " +
"dispatch lot by manual " +
"mode!").build());
Lot lot = lotQueryService.getLot(lotRrn);
String recipePhysicalId = StringUtils.EMPTY;
RecipeVersion recipeVersion = recipeService.getLotRecipe(lot);
if (recipeVersion != null) {
recipePhysicalId = recipeVersion.getPpid();
}
if (request.getParameter("check_flag") != null) {
check(lot, equipment, recipePhysicalId, lot.getOperationRrn());
}
emsService.checkEquipmentRecipeInvalid(equipment.getInstanceRrn());
long physicalRecipeRrn = getInstanceRrn(recipePhysicalId, LocalContext.getFacilityRrn(), ObjectList.RECIPE_KEY);
Assert.isFalse(physicalRecipeRrn <= 0,
Errors.create().key(MessageIdList.RECIPE_MISSING).content("The Recipe {} does not exist!")
.args(recipePhysicalId).build());
if (LotStatus.isMoveInCheckStatus(lot.getLotStatus())) {
// todo check spc
// String checkEquipmentChartMsg = jobService.checkEquipmentChartInfo(lotTemp,
// equipment
// .getInstanceRrn(),
// recipePhysicalId);
String checkRecipeResultMsg = wipCheckService
.checkHasAvailableDispatchRecipe(lot, equipment.getInstanceRrn(), recipePhysicalId, lot.getQty1());
Assert.isFalse(StringUtils.isNotEmpty(checkRecipeResultMsg),
Errors.create().content(checkRecipeResultMsg).args(recipePhysicalId).build());
}
Map holdPMMap = wipCheckService.validateEquipPMStatus(equipment);
String msgPMInfo = wipCheckService.validateEquipPMStatusReturnMsg(holdPMMap);
// ------------操作工设备认证--------------
wipCheckService.checkEquipmentCertification(LocalContext.getUserId(), equipment.getInstanceRrn());
String msg = "";
if ("WAITING".equalsIgnoreCase(lot.getLotStatus()) || "DISPATCH".equalsIgnoreCase(lot.getLotStatus())) {
Assert.isFalse(Boolean.parseBoolean(((String) holdPMMap.get("pmHold"))),
Errors.create().key(MessageIdList.EQUIPMENT_PM_HOLD).content(
"The EQP has" + " " + "been " + "hold by " + "PM,Can't " + "machined " + "lot!{} ")
.args(StringUtils.replaceAll(MapUtils.getString(holdPMMap, "checklistJobIds"), "<br>",
"\n")).build());
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);
}
// Recipe超时提醒.
Map item = new HashMap();
item.put("lotRrn", lot.getLotRrn());
String recipeTimeOutMsg = checkRecipeTimeOutMsg(Collections.singletonList(item));
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);
}
List list = emsService.getEquipmentHoldInfo(equipment.getInstanceRrn());
Assert.isFalse(!list.isEmpty() && lot.getLotStatus().equals("WAITING"),
Errors.create().key(MessageIdList.EQUIPMENT_HOLD)
.content("EQP has been hold,Can't machined " + "lot {}").build());
} else {
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);
}
}
Map equipmentExt = emsService.getEquipmentExtMap(equipment.getInstanceRrn());
String pollutionLevel = (String) equipmentExt.get("pollutionLevel");
if ((!"0".equals(lot.getPollutionLevel())) && !("null".equals(pollutionLevel)) &&
StringUtils.isNotEmpty(pollutionLevel)) {
boolean flag = false;
String[] pollutionLevels = pollutionLevel.split(",");
for (String level : pollutionLevels) {
if (level.equals(lot.getPollutionLevel())) {
flag = true;
break;
}
}
Assert.isTrue(flag, Errors.create().key(MessageIdList.LOT_CONTAMINATION_NOT_MATCH_EQPT).content(
"The EQP and the lot Contamination don't match,Acceptable " +
"contamination of equipment: {} Lot contamination:{}")
.args(pollutionLevel, lot.getPollutionLevel()).build());
}
if (StringUtils.equalsIgnoreCase(Constants.SEMI_AUTO_KEY, equipment.getOperationMode()) &&
"DISPATCH".equalsIgnoreCase(lot.getLotStatus())) {
Job job = wipQueryService.getJob(lot.getJobRrn());
// todo 字段不存在
// if (job.getExecutionRrn() > 0) {
//
// String params = wipWorkflowQueryService.getSemiAutoParamsInExection(job
// .getExecutionRrn());
// if (!StringUtils.isBlank(params)) {
// Collection lots = getJobManager().getJobList(new Long(lotTemp.getJobRrn()
// ).longValue(),
// ObjectList.JOB_KEY);
// session.setAttribute(SessionNames.JOB_KEY, job);
// session.setAttribute(SessionNames.COLLECTION_KEY, lots);
// return (mapping.findForward("viewRecipeSet"));
// } else {
// if (StringUtils.equalsIgnoreCase("CN", language)) {
// request.setAttribute(ErrorDef.MYCIM_ERR_KEY, new
// ValidateFailureException("批次信息错误!"));
// } else {
// request.setAttribute(ErrorDef.MYCIM_ERR_KEY,
// new ValidateFailureException("Lot info error!"));
// }
// return (mapping.findForward("error"));
// }
// }
}
// Copy value object properties to form bean.
EntityAttrEqptForm entityAttrEqptForm = new EntityAttrEqptForm();
PropertyUtils.copyProperties(entityAttrEqptForm, equipment);
entityAttrEqptForm.setCurrentStatus(emsService.getEntityCurrentStatus(equipment.getInstanceRrn()));
request.setAttribute(SessionNames.EQUIPMELNT_INFO_FORM_KEY, entityAttrEqptForm);
List<Map> jobList = wipQueryService.getJobList(equipment.getInstanceRrn(), ObjectList.EQUIPMENT_KEY);
Map cur_job = null;
if (CollectionUtils.isEmpty(jobList)) {
List<Lot> jobLots = new ArrayList<>();
Job job = new Job();
job.setTransPerformedby(LocalContext.getUserId());
job.setEqptRrn(equipment.getInstanceRrn());
Long operationRrn = lot.getOperationRrn();
job.setOperationRrn(operationRrn);
job.setJobStatus(JobStatus.WAITING);
job.setEqptId(equipment.getInstanceId());
job.setExecutionRrn(0L);
job.setUOM1(lot.getUOM1());
job.setUOM2(lot.getUOM2());
long total_slots_qty = 0;
if (CollectionUtils.isNotEmpty(batchLotStores)) {
for (BatchLotStore batch : batchLotStores) {
Lot batchLot = lotQueryService.getLot(batch.getLotRrn());
Assert.isFalse(batchLot.getExecutionRrn() == null || batchLot.getExecutionRrn() == 0,
Errors.create().content("Lot's executionRrn is null, and can not be dispatched.")
.build());
// 检查下是否做过跳步跳出了跨境时间,如果超过了则不做hold的检查。
wipCheckService.validateLotOverQueueTime(lot);
validateLotStatusForHold(batchLot);
if (jobLots.stream().noneMatch(l -> l.getLotRrn() == batchLot.getLotRrn())) {
jobLots.add(batchLot);
}
long qty = batchLot.getQty1().longValue();
total_slots_qty = total_slots_qty + qty;
}
} else {
Assert.isFalse(lot.getExecutionRrn() == null || lot.getExecutionRrn() == 0,
Errors.create().content("Lot's executionRrn is null, and can not be dispatched.")
.build());
// 检查下是否做过跳步跳出了跨境时间,如果超过了则不做hold的检查。
wipCheckService.validateLotOverQueueTime(lot);
validateLotStatusForHold(lot);
jobLots.add(lot);
long qty = lot.getQty1().longValue();
total_slots_qty = total_slots_qty + qty;
}
Assert.isTrue(wipCheckService.isValidJobSize(equipment.getInstanceRrn(), 1, total_slots_qty),
Errors.create().key(MessageIdList.LOT_INVALID_JOB_SIZE).content("Invalid Job Size!").build());
boolean eqptBusyFlag = wipCheckService.validJobSize(job);
Assert.isTrue(eqptBusyFlag, Errors.create().key(MessageIdList.EQUIPMENT_CURRENTLY_BUSY)
.content("Equipment currently busy.").build());
validLotInEqp(equipment.getInstanceRrn(), jobLots);
// wipService.createJob(job, jobLots.stream().map(Lot::getLotRrn).collect(Collectors.toList()));
// request.getRequestDispatcher(mapping.findForward("jobmanagement").getPath()).forward(request, response);
// return null;
request.setAttribute(SessionNames.JOB_KEY, job);
lot.setEqptRrn(equipment.getInstanceRrn());
lot.setEqptID(equipment.getInstanceId());
jobList = getInfos(lot);
cur_job = BeanUtils.copyBeanToMap(job);
cur_job.put("equipmentRrn",job.getEqptRrn());
if (lot.getReworkTransRrn() == null || lot.getReworkTransRrn() <= 0){
cur_job.put("lotExecutionRrn",lot.getExecutionRrn());
} else {
Map reworkInfo = lotQueryService.getReworkInfo(lot.getReworkTransRrn(), lot.getLotRrn());
cur_job.put("lotExecutionRrn",MapUtils.getString(reworkInfo,"executionRrn"));
}
cur_job.put("operationVersion",lot.getOperationVersion());
} else {
List l = new ArrayList();
for (Map m : jobList) {
if (batchLotStores.size() > 0) {
for (BatchLotStore batch : batchLotStores) {
if (MapUtils.getLongValue(m, "lotRrn") == batch.getLotRrn()) {
l.add(m);
}
}
jobList = l;
} else {
if ((String.valueOf(lot.getLotRrn()).equals(m.get("lotRrn").toString()))) {
// 提取设备上当前批次信息
l.add(m);
jobList = l;
}
}
}
// 当前设备有作业信息但无当前批次的信息
if (l.size() == 0) {
List<Lot> jobLots = new ArrayList<>();
Job job = new Job();
job.setTransPerformedby(LocalContext.getUserId());
job.setEqptRrn(equipment.getInstanceRrn());
Long operationRrn = new Long(lot.getOperationRrn());
job.setOperationRrn(operationRrn);
job.setJobStatus(JobStatus.WAITING);
job.setEqptId(equipment.getInstanceId());
job.setExecutionRrn(0L);
job.setUOM1(lot.getUOM1());
job.setUOM2(lot.getUOM2());
long total_slots_qty = 0;
if (batchLotStores.size() > 0) {
for (BatchLotStore batch : batchLotStores) {
Lot batchLot = lotQueryService.getLot(batch.getLotRrn());
Assert.isFalse(batchLot.getExecutionRrn() == null || batchLot.getExecutionRrn() == 0,
Errors.create().content("Lot's executionRrn is null, and can not be dispatched.")
.build());
// 检查下是否做过跳步跳出了跨境时间,如果超过了则不做hold的检查。
wipCheckService.validateLotOverQueueTime(lot);
validateLotStatusForHold(batchLot);
if (jobLots.stream().noneMatch(temp -> temp.getLotRrn() == batchLot.getLotRrn())) {
jobLots.add(batchLot);
}
long qty = lot.getQty1().longValue();
total_slots_qty = total_slots_qty + qty;
}
} else {
Assert.isFalse(lot.getExecutionRrn() == null || lot.getExecutionRrn() == 0,
Errors.create().content("Lot's executionRrn is null, and can not be dispatched.")
.build());
// 检查下是否做过跳步跳出了跨境时间,如果超过了则不做hold的检查。
wipCheckService.validateLotOverQueueTime(lot);
validateLotStatusForHold(lot);
if (jobLots.stream().noneMatch(temp -> temp.getLotRrn() == lot.getLotRrn())) {
jobLots.add(lot);
}
long qty = lot.getQty1().longValue();
total_slots_qty = total_slots_qty + qty;
}
Assert.isTrue(wipCheckService.isValidJobSize(equipment.getInstanceRrn(), 1, total_slots_qty),
Errors.create().key(MessageIdList.LOT_INVALID_JOB_SIZE).content("Invalid Job Size!")
.build());
wipCheckService.validJobSize(job);
validLotInEqp(equipment.getInstanceRrn(), jobLots);
// wipService.createJob(job, jobLots.stream().map(Lot::getLotRrn).collect(Collectors.toList()));
// request.getRequestDispatcher(mapping.findForward("jobmanagement").getPath()).forward(request, response);
// return null;
request.setAttribute(SessionNames.JOB_KEY, job);
lot.setEqptRrn(equipment.getInstanceRrn());
lot.setEqptID(equipment.getInstanceId());
lot.setEqptRrn(equipment.getInstanceRrn());
lot.setEqptID(equipment.getInstanceId());
jobList = getInfos(lot);
cur_job = BeanUtils.copyBeanToMap(job);
cur_job.put("equipmentRrn",job.getEqptRrn());
if (lot.getReworkTransRrn() == null || lot.getReworkTransRrn() <= 0){
cur_job.put("lotExecutionRrn",lot.getExecutionRrn());
} else {
Map reworkInfo = lotQueryService.getReworkInfo(lot.getReworkTransRrn(), lot.getLotRrn());
cur_job.put("lotExecutionRrn",MapUtils.getString(reworkInfo,"executionRrn"));
}
cur_job.put("operationVersion",lot.getOperationVersion());
} else {
cur_job = jobList.iterator().next();
}
}
int i = 1;
String _JobNumber = null;
for (Map job : jobList) {
job.put("isUniqueJobFlag", "1");
if (i == 1) {
_JobNumber = (String) job.get("jobRrn");
} else {
if (job.get("jobRrn").equals(_JobNumber)) {
job.put("isUniqueJobFlag", "0");
} else {
_JobNumber = (String) job.get("jobRrn");
}
}
i++;
String hotflagSplicingPriority = wipQueryService
.getHotflagSplicingPriority(MapUtils.getInteger(job, "hotFlag"),
MapUtils.getInteger(job, "priority"), LocalContext.getFacilityRrn());
job.put("priority", hotflagSplicingPriority);
}
replaceJobListRecipeId(jobList);
request.setAttribute(SessionNames.COLLECTION_KEY, jobList);
// Map job = jobList.iterator().next();
request.setAttribute("cur_job", cur_job);
request.setAttribute("type", "equipment");
if (!"RUNNING".equals(cur_job.get("jobStatus").toString()) &&
!"COMPLETED".equals(cur_job.get("jobStatus").toString())) {
request.getRequestDispatcher(mapping.findForward("movein").getPath()).forward(request, response);
return null;
} else {
//审查设备状态 #41027 要求提前。这里的检查更为严格,检查设备运行状态(串并行 chamber的逻辑)
//根据##45514要求,出站不再卡控机台状态
// Job job = wipQueryService.getJob(lot.getJobRrn());
// wipCheckService.checkEqptStateByJobMove(job, ActionPointList.MOVEOUT_KEY);
request.getRequestDispatcher(mapping.findForward("moveout").getPath()).forward(request, response);
return null;
}
}
public void check(Lot lot, Equipment equipment, String recipePhysicalId, long operationRrn) {
String checkEqptAndRecipeResultMsg = wipCheckService
.checkEqptAndRecipeAndReticleAtJobIn(lot, equipment.getInstanceRrn(), recipePhysicalId,
LocalContext.getUserRrn());
Assert.isFalse(StringUtils.isNotEmpty(checkEqptAndRecipeResultMsg),
Errors.create().content(checkEqptAndRecipeResultMsg).build());
Assert.isTrue(emsService.checkPermission(equipment.getInstanceRrn(), LocalContext.getUserRrn()),
Errors.create().key(MessageIdList.EQPT_NO_PERMISSION).content("The current user {} has no permission to operate the EQP {}!")
.args(LocalContext.getUserId(), equipment.getInstanceId()).build());
Assert.isTrue(wipCheckService.checkEquipmentOperationPermission(operationRrn, equipment.getInstanceRrn()),
Errors.create().key(MessageIdList.EQUIPMENT_PERMISSION_OPERATION)
.content("The lot on the current step cant't run on the EQP.").build());
}
private String validateLotStatusForHold(Lot lot) {
if (LotStatus.HOLD.equalsIgnoreCase(lot.getLotStatus())) {
List<Map> holdReasons = wipQueryService.getHoldReasons(lot.getLotRrn());
if (!holdReasons.isEmpty()) {
for (Map hashMap : holdReasons) {
Assert.isFalse(
HoldCodeNames.QTIMEHOLD_KEY.equalsIgnoreCase(MapUtils.getString(hashMap, "reasonCode")),
Errors.create().key(MessageIdList.LOT_EXCEEDS_MAX)
.content("Lot exceeds the maximum waiting time, it was hold by the system!").build());
}
}
}
return null;
}
private void replaceJobListRecipeId(List<Map> jobList) {
for (Map map : jobList) {
// map.put("eqptID", MapUtils.getString(map, "equipmentId"));
map.put("eqptID", MapUtils.getString(map, "eqptID", MapUtils.getString(map, "equipmentId")));
map.put("facilityRrn", LocalContext.getFacilityRrn());
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 List<Map> getInfos(Lot lot){
List<Map> lotInfos = new ArrayList<>();
Map lotInfo = BeanUtils.copyBeanToMap(lot);
long spent = DateUtils.getDistanceTime4Now(lot.getQueueTimestamp());
lotInfo.put("queueTimestamp", String.valueOf(spent));
if (lot.getRecipeId() != null) {
lotInfo.put("recipeId", lot.getRecipeId());
} else {
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("isUniqueCarrierFlag", "1");
lotInfo.put("isUniqueJobFlag", "0");
lotInfo.put("equipmentRrn", lot.getEqptRrn());
lotInfo.put("lotExecutionRrn","0");
lotInfo.put("jobRrn","0");
String priority = sysService.referenceDetailExchange(ReferenceDetailNames.LOT_PRIORITY,
String.valueOf(lot.getPriority()), null,
"DATA_1_VALUE");
lotInfo.put("priority", priority);
lotInfo.put("jobStatus", "WAITING");
lotInfos.add(lotInfo);
return lotInfos;
}
}