MoveOutAction.java
package com.mycim.webapp.actions.operation.run;
import com.fa.sesa.exception.Assert;
import com.fa.sesa.exception.Errors;
import com.fa.sesa.threadlocal.LocalContext;
import com.mycim.framework.utils.beans.PropertyUtils;
import com.mycim.framework.utils.lang.ObjectUtils;
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.utils.WflLinkContextSetupAttributeUtil;
import com.mycim.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.consts.ReferenceDetailNames;
import com.mycim.valueobject.consts.SessionNames;
import com.mycim.valueobject.ems.Carrier;
import com.mycim.valueobject.prp.Operation;
import com.mycim.valueobject.prp.ProcessSpecFormDto;
import com.mycim.valueobject.prp.ProcessSpecItemDto;
import com.mycim.valueobject.prp.WflLinkContextValue;
import com.mycim.valueobject.sorter.SortJobCacheBean;
import com.mycim.valueobject.sys.ReferenceFileDetail;
import com.mycim.valueobject.wip.*;
import com.mycim.webapp.WebUtils;
import com.mycim.webapp.actions.WipSetupAction;
import com.mycim.webapp.actions.unit.LotUnitInfoAction;
import com.mycim.webapp.forms.JobInfoForm;
import com.mycim.webapp.forms.RootForm;
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.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Johnson.Wang
* @version 6.0.0
* @date 2019/10/5
**/
public class MoveOutAction extends WipSetupAction {
@Override
public ActionForward init(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
RootForm theform = (RootForm) form;
if (request.getAttribute(SessionNames.RUNCARD_LOT_ID) == null) {
String runcardLotId = request.getParameter(SessionNames.RUNCARD_LOT_ID);
request.setAttribute(SessionNames.RUNCARD_LOT_ID, runcardLotId);
}
if (request.getAttribute(SessionNames.PARAMETERSINFO_KEY) == null) {
request.setAttribute(SessionNames.PARAMETERSINFO_KEY,
WebUtils.getCacheString2Obj(theform.getCacheParametersInfo()));
}
if (request.getAttribute(SessionNames.JOB_KEY) == null) {
request.setAttribute(SessionNames.JOB_KEY, WebUtils.getCacheString2Obj(theform.getCacheJob()));
}
if (request.getAttribute(SessionNames.COLLECTION_KEY) == null) {
request.setAttribute(SessionNames.COLLECTION_KEY,
WebUtils.getCacheString2Obj(theform.getCacheCollection()));
}
SortJobCacheBean sjcb = (SortJobCacheBean) request.getAttribute(SessionNames.SORTER_JOB);
if (sjcb == null){
sjcb = (SortJobCacheBean) WebUtils.getCacheString2Obj(theform.getCacheSorterJob());
request.setAttribute(SessionNames.SORTER_JOB, sjcb);
}
Assert.isFalse(request.getAttribute(SessionNames.PARAMETERSINFO_KEY) == null ||
request.getAttribute(SessionNames.JOB_KEY) == null ||
request.getAttribute(SessionNames.COLLECTION_KEY) == null,
Errors.create().key(MessageIdList.SYSTEM_MISSING_PARAMETER)
.content("Required parameters do not exists!").build());
Map parameters = (Map) request.getAttribute(SessionNames.PARAMETERSINFO_KEY);
String comments = (String) parameters.get("comments");
Job job = (Job) request.getAttribute(SessionNames.JOB_KEY);
List<Map> lots = (List<Map>) request.getAttribute(SessionNames.COLLECTION_KEY);
JobInfoForm jobInfoForm = new JobInfoForm();
PropertyUtils.copyProperties(jobInfoForm, job);
for (Map lotInfo : lots) {
if (StringUtils.isBlank(MapUtils.getString(lotInfo, "recipePhysicalId")) &&
StringUtils.isNotBlank(MapUtils.getString(lotInfo, "recipeId"))) {
lotInfo.put("eqptID", MapUtils.getString(lotInfo, "equipmentId"));
String id = recipeService.buildRecipePhysicalId(MapUtils.getString(lotInfo, "recipeId"), lotInfo);
lotInfo.put("recipePhysicalId", id);
}
}
String automoveout = request.getParameter("automoveout");
if (StringUtils.isNotBlank(automoveout)) {
request.setAttribute("automoveout", automoveout);
}
request.setAttribute("jobInfoForm", jobInfoForm);
setCache4WFL(request, jobInfoForm);
return handleRunningHold(mapping, request, job);
}
@Override
public ActionForward cancel(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
request.removeAttribute(SessionNames.PARAMETERSINFO_KEY);
request.removeAttribute(SessionNames.JOB_KEY);
request.removeAttribute(SessionNames.ENTITY_KEY);
request.removeAttribute(SessionNames.OPERATION_KEY);
String lotId = WebUtils.getParameter("lotIdShow", request);
//批次作业出站,点击取消,删除lot lock
// Lot _lot = lotQueryService.getLot(lotId, LocalContext.getFacilityRrn());
// removeLotLock(LocalContext.getUserRrn(), _lot, TransactionNames.LOCK_MOVEOUT,
// "Cancel moveOut, in MoveOutAction by: " + LocalContext.getUserId());
if (StringUtils.isNotBlank(request.getParameter(SessionNames.RUNCARD_LOT_ID))) {
String runcardLotId = request.getParameter(SessionNames.RUNCARD_LOT_ID);
request.getRequestDispatcher("splitRunCardLotInfo.do?action=init&lotId=" + runcardLotId)
.forward(request, response);
} else {
request.getRequestDispatcher(mapping.findForward("jobmanagement4lot").getPath() + "&lotId=" + lotId)
.forward(request, response);
}
return null;
}
public ActionForward ok(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
RootForm theform = (RootForm) form;
Map parameters = (Map) request.getAttribute(SessionNames.PARAMETERSINFO_KEY);
if (parameters == null) {
parameters = (Map) WebUtils.getCacheString2Obj(theform.getCacheParametersInfo());
request.setAttribute(SessionNames.PARAMETERSINFO_KEY, parameters);
}
Job job = (Job) request.getAttribute("job");
if (job == null) {
job = (Job) WebUtils.getCacheString2Obj(theform.getCacheJob());
request.setAttribute("job", job);
}
SortJobCacheBean sjcb = (SortJobCacheBean) request.getAttribute(SessionNames.SORTER_JOB);
if (sjcb == null){
sjcb = (SortJobCacheBean) WebUtils.getCacheString2Obj(theform.getCacheSorterJob());
request.setAttribute(SessionNames.SORTER_JOB, sjcb);
}
Assert.isFalse(job != null && wipQueryService.getJob(job.getJobRrn()) == null,
Errors.create().key(MessageIdList.JOB_MISSING).content(
"Job does " + "not " + "exist! " + "Please " + "close " + "the " + "current" + " tab " +
"page " + "and " + "recreate " + "it!").build());
List lots = (List) request.getAttribute(SessionNames.COLLECTION_KEY);
if (lots == null) {
lots = (List) WebUtils.getCacheString2Obj(theform.getCacheCollection());
request.setAttribute(SessionNames.COLLECTION_KEY, lots);
request.setAttribute("currentlots", lots);
}
Map lotMap = (Map) lots.iterator().next();
Operation operation = prpService.getOperation(MapUtils.getLongValue(lotMap, "operationRrn"));
if (operation.isBondedOperation()) {
wipService.validAndBuildBondingAfterLock(lots, parameters);
} else if (operation.isDeBondOperation()) {
Assert.isFalse(lots.size() > 1, Errors.create().content("Only one lot is allowed in this step !").build());
}
Assert.isFalse(parameters == null || job == null || lots == null,
Errors.create().key(MessageIdList.SYSTEM_MISSING_PARAMETER).content("Parameters are not enough!")
.build());
request.setAttribute("runcardLotId", request.getParameter("runcardLotId"));
List<Lot> lotsByJobRrn = lotQueryService.getLotsByJobRrn(job.getJobRrn());
boolean byManualFlag = wipCheckService.checkMultipathByManual(lotsByJobRrn);
if (byManualFlag) {
Assert.isTrue(NumberUtils.INTEGER_ONE.equals(lots.size()),
Errors.create().key(MessageIdList.MULTIPATH_BY_MANUAL_CHECK_LOT)
.content("has a multipath set by manual.lot quantity can only be 1!").build());
String operationWflPath = request.getParameter("selectOperationWflPath");
String routeWflPath = request.getParameter("selectRouteWflPath");
Assert.isFalse(StringUtils.isBlank(operationWflPath) && StringUtils.isBlank(routeWflPath),
Errors.create()
.content("has a multipath set by manual.please choose wflPath!").build());
setMultipathByManual(lotsByJobRrn, operationWflPath, routeWflPath);
}
return lbrd(job, lots, parameters, request, response, mapping);
}
public ActionForward moveOut(HttpServletRequest request, ActionForm form, HttpServletResponse response,
ActionMapping mapping) throws Exception {
Map parameters = (Map) request.getAttribute(SessionNames.PARAMETERSINFO_KEY);
RootForm theform = (RootForm) form;
if (parameters == null) {
parameters = (Map) WebUtils.getCacheString2Obj(theform.getCacheParametersInfo());
request.setAttribute(SessionNames.PARAMETERSINFO_KEY, parameters);
}
Job job = (Job) request.getAttribute("job");
if (job == null) {
job = (Job) WebUtils.getCacheString2Obj(theform.getCacheJob());
request.setAttribute("job", job);
}
SortJobCacheBean sjcb = (SortJobCacheBean) request.getAttribute(SessionNames.SORTER_JOB);
if (sjcb == null){
sjcb = (SortJobCacheBean) WebUtils.getCacheString2Obj(theform.getCacheSorterJob());
}
String eqptRrn = "";
String outQty = request.getParameter("moveOutQty");
String[] moveOutQty = null;
String comments = (String) parameters.get("comments");
if (StringUtils.isNotEmpty(outQty) && !StringUtils.equals(outQty, "null")) {
moveOutQty = StringUtils.split(outQty, ",");
}
String outQty2 = request.getParameter("moveOutQty2");
String[] moveOutQty2 = null;
if (StringUtils.isNotEmpty(outQty2) && !StringUtils.equals(outQty2, "null")) {
moveOutQty2 = StringUtils.split(outQty2, ",");
}
Assert.isFalse(moveOutQty == null,
Errors.create().key(MessageIdList.SYSTEM_MISSING_PARAMETER).content("Parameters are not enough!")
.build());
List<Map> lotList = wipQueryService.getJobList(job.getJobRrn(), ObjectList.JOB_KEY);
List<String> lotRrns = new ArrayList<>();
for (Map jobItem : lotList) {
if (StringUtils.equals(LotStatus.PROCESSED, MapUtils.getString(jobItem, "lotStatus"))) {
parameters.put(SessionNames.RUNSTEP_FLAG, "0");
return mapping.findForward("workflow");
}
if(jobItem.containsKey("lotRrn")){
//不确定是 long 还是 stirng 统一进行转换 防止报错
lotRrns.add(StringUtils.toString(jobItem.get("lotRrn")));
}
}
HashMap transInfo = new HashMap();
transInfo.put("job", job);
transInfo.put(SessionNames.SORTER_JOB, sjcb);
wipService.moveOut(job, moveOutQty, moveOutQty2, null, comments,lotRrns,transInfo);
List<Lot> lots4job = lotQueryService.getLotsByJobRrn(job.getJobRrn());
// handle the move out max processing time
Operation o = getOperation(new Operation(job.getOperationRrn()));
// csec发生move in后job上run为0,且run中也没有该job的run,
// 添加补丁,发生这种情况,自动补上run, yunsong, 2011-12-14
if (job.getRunRrn() == null || job.getRunRrn() == 0) {
// 1.判断run中有没有该job的记录,如果有,将对应runRrn放回job中
Run newRun = wipQueryService.getRunByJob(job.getJobRrn());
if (newRun != null) {
wipService.updateRunRrn(newRun.getRunRrn(), job.getJobRrn());
} else {
// 2.如果run表中都没有,需要模拟move in的逻辑,完全新建一个run
long newRunRrn = wipService.createRun4Job(job);
job.setRunRrn(newRunRrn);
}
}
Run run = wipQueryService.getRun(job.getRunRrn());
Timestamp processStart = run.getProcessStartTime();
if (processStart != null) {
boolean triggered = false;
String alarmId = null;
String subject = "";
String content = "";
long jobRrn = job.getJobRrn();
long runRrn = job.getRunRrn().longValue();
long spent = DateUtils.getDistanceTime4Now(processStart);
for (Lot item : lots4job) {
eqptRrn = Long.toString(item.getEqptRrn());
if (spent > DateUtils.getSecondsTime(o.getMaxProcessingTime())) {
alarmId = o.getExceedPTimeAlarmId();
if (alarmId != null) {
triggered = true;
content = "lot " + item.getLotId() + " has exceed the max processing time in step " +
o.getInstanceId();
subject = "Process alarm ";
}
}
// todo alarm
// triggerProcessAlarm(item.getProductRrn().longValue(), alarmId, userRrn,
// subject, content,
// jobRrn, runRrn);
removeEqptlotCache(item);
}
}
// todo bom consume Material
// jobService.consumeMaterialFromBOM(facilityRrn, user, job.getRunRrn(),
// getConsumeMaterialLotListByBOR(lots4job));
return workflow(parameters, mapping, request, response);
}
public ActionForward lbrd(Job job, List<Map> lots, Map parameters, HttpServletRequest request,
HttpServletResponse response, ActionMapping mapping) throws Exception {
validateTask(parameters, "moveout");
// add by steven for fmi
request.removeAttribute("reticleRrns");
String[] reticleRrns = request.getParameterValues("reticleRrn");
if (reticleRrns != null) {
int m = 0;
String _reticleRrn = null;
for (Map lot : lots) {
_reticleRrn = reticleRrns[m];
m++;
}
request.setAttribute("reticleRrns", reticleRrns);
}
// parameter "moveOutQty" is needed
String[] moveOutQty = request.getParameterValues("moveOutQty");
String[] moveOutQty2 = request.getParameterValues("moveOutQty2");
Carrier carrier = null;
String UOM1 = null;
int i = 0;
List<Lot> lockLots = new ArrayList<Lot>();
for (Map item : lots) {
UOM1 = (String) item.get("UOM1");
if (UOM1 == null) {
// getUOM1
UOM1 = this.getUOM1((Long) item.get("operationRrn"));
}
if (UOM1 != null && UOM1.trim().equalsIgnoreCase(UOM_WAFER)) {
carrier = carrierService.getCarrier(
getInstanceRrn(MapUtils.getString(item, "carrierId"), LocalContext.getFacilityRrn(),
ObjectList.ENTITY_KEY));
Assert.isFalse(carrier != null && carrier.getSlotCount() != null &&
carrier.getSlotCount().compareTo(new Long(moveOutQty[i])) < 0,
Errors.create().key(MessageIdList.CARRIER_MUST_SMALLER_SLOT)
.content("Quantity should be smaller than carrier's slot count").build());
}
Lot lot = lotQueryService.getLot(MapUtils.getString(item, "lotId"), LocalContext.getFacilityRrn());
lockLots.add(lot);
i++;
}
//check lot lock
if (lockLots != null && lockLots.size() > 0) {
// checkAndCreateLotsTransLock(LocalContext.getUserRrn(), TransactionNames
// .LOCK_MOVEOUT, lockLots,
// "moveOut in MoveOutAction by:" + LocalContext
// .getUserId());
}
parameters.put("comments", request.getParameter("comments"));
String moveOutQtys = "";
StringJoiner stringJoiner = new StringJoiner(",");
if (moveOutQty != null && moveOutQty.length > 0) {
for (int j = 0; j < moveOutQty.length; j++) {
String temp = moveOutQty[j];
temp = StringUtils.isEmpty(temp) ? "0" : temp;
stringJoiner.add(temp);
}
moveOutQtys = stringJoiner.toString();
} else {
moveOutQtys = null;
}
String moveOutQtys2 = "";
if (moveOutQty2 != null && moveOutQty2.length > 0) {
for (int j = 0; j < moveOutQty2.length; j++) {
if (j == 0) {
moveOutQtys2 = moveOutQty2[j];
} else {
moveOutQtys2 += "," + moveOutQty2[j];
}
}
} else {
moveOutQtys2 = null;
}
request.setAttribute("moveOutQty", moveOutQtys);
request.setAttribute("moveOutQty2", moveOutQtys2);
String automoveout = request.getParameter("automoveout");
request.setAttribute("automoveout", automoveout);
request.getRequestDispatcher(mapping.findForward("lbrd").getPath()).forward(request, response);
return null;
}
public ActionForward workflow(Map parameters, ActionMapping mapping, HttpServletRequest request,
HttpServletResponse response) throws Exception {
parameters.put(SessionNames.RUNSTEP_FLAG, "0");
request.removeAttribute("workflowPara");
// todo future action split
request.getRequestDispatcher(mapping.findForward("workflow").getPath() + "?action=init")
.forward(request, response);
return null;
}
private ActionForward handleRunningHold(ActionMapping mapping, HttpServletRequest request, Job job) {
List holdInfos = new ArrayList<>();
Assert.isFalse(job != null && wipQueryService.getJob(job.getJobRrn()) == null,
Errors.create().key(MessageIdList.JOB_MISSING).content(
"Job does not exist! Please close the current tab page and recreate it").build());
List<Map> joblots = wipQueryService.getJobList(job.getJobRrn(), ObjectList.JOB_KEY);
for (Map lotMap : joblots) {
Lot lot = lotQueryService.getLot(MapUtils.getLongValue(lotMap, "lotRrn"));
if (StringUtils.equalsIgnoreCase(lot.getLotStatus(), LotStatus.RUNNINGHOLD)) {
holdInfos.addAll(wipQueryService.getHoldReasons(lot.getLotRrn()));
}
}
//打印出货标签
printShippingLabel(joblots, request);
if (holdInfos.isEmpty()) {
return showMoveOutPage(mapping, request);
} else {
request.setAttribute("holdInfo", holdInfos);
request.setAttribute(SessionNames.COLLECTION_KEY, joblots);
//批次作业出站,当批次状态为RUNNINGHOLD时,删除lot lock
return mapping.findForward("runningHold");
}
}
protected ActionForward showMoveOutPage(ActionMapping mapping, HttpServletRequest request) {
return mapping.findForward("moveout");
}
private void printShippingLabel(List<Map> joblots, HttpServletRequest request) {
// 查找flow中的第一个stage为INS-OQI的步骤
String stageId = sysService.getReferenceFileData1ValueByKey1Value(ReferenceDetailNames.PRINT_SHIPPING_LABEL,"STAGEID");
if (StringUtils.isEmpty(stageId)) {
stageId = "";
}
ProcessSpecFormDto processSpecForm = new ProcessSpecFormDto();
processSpecForm.setProcessId(MapUtils.getString(joblots.get(0), "processId"));
processSpecForm.setProcessRrn(MapUtils.getLongValue(joblots.get(0), "processRrn"));
processSpecForm.setProcessVersion(MapUtils.getInteger(joblots.get(0), "processVersion"));
processSpecForm.setProductId(MapUtils.getString(joblots.get(0), "productId"));
String finalStageId = StringUtils.trimToUpperCase(stageId);
ProcessSpecItemDto processSpecItemDto = processSpecService.queryProcessSpecItems(processSpecForm)
.stream().sorted(Comparator.comparing(ProcessSpecItemDto::getFlowSeq))
.filter(p-> StringUtils.equalsIgnoreCase(p.getStageId(), finalStageId))
.findFirst().orElse(null);
boolean printLabelFlag = false;
if (ObjectUtils.isNotEmpty(processSpecItemDto)) {
if (CollectionUtils.size(joblots) > 1 ) {
// 多个lot的stage为INS-OQI时 不能job out
Assert.isFalse(StringUtils.equalsIgnoreCase(MapUtils.getString(joblots.get(0), "stageId"), finalStageId)
&& StringUtils.equalsIgnoreCase(processSpecItemDto.getFlowSeq(), MapUtils.getString(joblots.get(0), "flowSeq")),
Errors.create().key(MessageIdList.LOT_JOBS_OUT_PRINT_LABEL_ERROR)
.content("The current stage is INS-OQI,cannot mutli lot print shipping label!").build());
} else {
if (StringUtils.equalsIgnoreCase(MapUtils.getString(joblots.get(0), "stageId"), finalStageId)
&& StringUtils.equalsIgnoreCase(processSpecItemDto.getFlowSeq(), MapUtils.getString(joblots.get(0), "flowSeq"))) {
printLabelFlag = true;
Lot lot = lotQueryService.getLot(MapUtils.getLongValue(joblots.get(0), "lotRrn"));
request.setAttribute("lotId", StringUtils.replace(lot.getLotId(), ".MAINRC", ""));
request.setAttribute("productId", lot.getProductId());
request.setAttribute("lotType",lot.getLotType());
request.setAttribute("qty1", lot.getQty1().intValue());
request.setAttribute("dueDate", DateUtils.getNowTime(DateUtils.DATE_FORMAT4DAYD));
List<Unit> units = wipQueryService.getUnitList(lot.getLotRrn());
String waferIdStr = units.stream().sorted(Comparator.comparing(Unit::getPositionInCarrier))
.map(unit -> {
if (StringUtils.isEmpty(unit.getUnitId())) {
return StringUtils.EMPTY;
} else {
return StringUtils
.substring(unit.getUnitId(), unit.getUnitId().length() - 3);
}
}).collect(Collectors.joining(","));
request.setAttribute("waferId", waferIdStr);
}
}
}
request.setAttribute("printLabelFlag", printLabelFlag);
// check 按钮权限
long userRrn = LocalContext.getUserRrn();
Collection<Long> roles = securityService.getUserRoleList(userRrn);
Map button = securityService.getButtonInfoWithRoles(roles, "BTN_JOBMANAGEMENT_PRINT_SHIPPING_LABEL");
if (MapUtils.isNotEmpty(button)) {
request.setAttribute("buttonPermissions", true);
}else {
request.setAttribute("buttonPermissions", false);
}
}
private void setMultipathByManual(List<Lot> lots, String operationWflPath, String routeWflPath) {
for (Lot lot : lots) {
List<WflLinkContextValue> wflLinkContextValueList = lotQueryService.getMultiPathForLot(lot);
for (WflLinkContextValue wflLinkContextValue : wflLinkContextValueList) {
if (WflLinkContextSetupAttributeUtil.isByManualOperationMultipath(wflLinkContextValue) &&
StringUtils.isNotBlank(operationWflPath) && lot.getOperationRrn().
equals(wflLinkContextValue.getOperationRrn())) {
wflLinkContextValue.setWflLinkId(operationWflPath);
ctxService.updateContextValueWithActivatedEcn(LocalContext.getFacilityRrn(),
LocalContext.getUserRrn(), wflLinkContextValue);
} else if (WflLinkContextSetupAttributeUtil.isByManualRouteMultipath(wflLinkContextValue) &&
StringUtils.isNotBlank(routeWflPath)) {
wflLinkContextValue.setWflLinkId(routeWflPath);
ctxService.updateContextValueWithActivatedEcn(LocalContext.getFacilityRrn(),
LocalContext.getUserRrn(), wflLinkContextValue);
}
}
}
}
}