ManualAndSortCheckAction.java
package com.mycim.webapp.actions.lot;
import com.fa.sesa.exception.Assert;
import com.fa.sesa.exception.Errors;
import com.fa.sesa.exception.TransformFunc;
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.valueobject.LocationNames;
import com.mycim.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.consts.SorterEnum;
import com.mycim.valueobject.ems.Carrier;
import com.mycim.valueobject.prp.Item;
import com.mycim.valueobject.runcard.util.RunCardStoreSubStatus;
import com.mycim.valueobject.sorter.SorterDetailBean;
import com.mycim.valueobject.wip.*;
import com.mycim.webapp.actions.WipSetupAction;
import java.util.*;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
/**
* Manual 和 Sort 的一些共用的校验
*
* @Author: yibing.liu
* @Date: 2021/8/2 11:45
*/
public class ManualAndSortCheckAction extends WipSetupAction {
protected void checkMergeAvailable(Lot sourceLot, Lot targetLot) {
Boolean checkResult = false;
checkResult = !StringUtils.equals(sourceLot.getLotType(), targetLot.getLotType());
Assert.isFalse(checkResult, Errors.create().key(MessageIdList.LOT_CANT_MERGE)
.content("The lot's {} are different,can't merge!").args("lotType").build());
}
protected boolean checkMergeBeforeUpdateDB(HashMap valueMap) {
Lot tempLot = (Lot) valueMap.get("lot");
Lot lot = lotQueryService.getLot(tempLot.getLotRrn());
List childLots = (List) valueMap.get("childLots");
List unitsOfParentLot = (List) valueMap.get("unitOfParent");
List newUnits = (List) valueMap.get("newUnits");
List pLotUnits = wipQueryService.getUnitListByLot(lot.getLotRrn());
// 检查母批qty1 与 unit的真实数量 是否一致
if (pLotUnits.size() != unitsOfParentLot.size() || lot.getQty1() != pLotUnits.size()) {
return true;
}
for (Object childLot : childLots) {
Map clot = (Map) childLot;
Lot tempChildLot = lotQueryService.getLot(MapUtils.getString(clot, "childLotId"), tempLot.getFacilityRrn());
List clotUnits = wipQueryService.getUnitListByLot(tempChildLot.getLotRrn());
if (clotUnits.size() < 1) {
return true;
}
// 检查子批qty1 与 unit的真实数量 是否一致
if (tempChildLot.getQty1() != clotUnits.size()) {
return true;
}
pLotUnits.addAll(clotUnits);
}
// 检查合批后的unit数量是否 等于母批+子批Unit数量之和
if (pLotUnits.size() != newUnits.size()) {
return true;
}
// 1.检查子批,母批片号是否与数据库一致 ;
// 2.检查合批位置是否正确
for (Object pLotUnit : pLotUnits) {
Map dbUnit = (Map) pLotUnit;
Long dbUnitRrn = MapUtils.getLong(dbUnit, "unitRrn");
String dbUnitId = MapUtils.getString(dbUnit, "unitId");
boolean isHasUnit = false;
for (Object unit : newUnits) {
Map newUnit = (Map) unit;
Long newUnitRrn = MapUtils.getLong(newUnit, "unitRrn");
String newUnitId = MapUtils.getString(newUnit, "unitId");
if (dbUnitRrn.longValue() == newUnitRrn.longValue() && StringUtils.equals(dbUnitId, newUnitId)) {
isHasUnit = true;
}
}
// 没有匹配到相应的unit
if (!isHasUnit) {
return true;
}
}
return false;
}
protected void lotBeforeIntoServiceCheck(Lot tempLot, String type) {
Lot lot = lotQueryService.getLot(tempLot.getLotRrn());
char[] options = type.trim().toUpperCase().toCharArray();
for (char option : options) {
if ('S' == option) {
Assert.isTrue(StringUtils.equalsIgnoreCase(tempLot.getLotStatus(), lot.getLotStatus()),
Errors.create().content("The status of LOT has changed! Please enter F5 refresh!")
.build());
} else if ('O' == option) {
Assert.isFalse(tempLot.getOperationRrn().longValue() != lot.getOperationRrn().longValue(),
Errors.create().content("The Step of LOT has changed! Please enter F5 refresh!")
.build());
} else if ('Q' == option) {
Assert.isFalse(tempLot.getQty1().doubleValue() != lot.getQty1().doubleValue(),
Errors.create().content("The QTY of LOT has changed! Please enter F5 refresh!").build());
}
}
}
protected void childLotsBeforeIntoServiceCheck(List childLots) {
String childLotId;
for (Object childLot : childLots) {
childLotId = MapUtils.getString((Map) childLot, "childLotId");
Lot childLotInfo = lotQueryService.getLot(childLotId);
checkChildLotStatusForMerge(childLotInfo);
}
}
protected void checkChildLotStatusForMerge(Lot childLot) {
Assert.isTrue(LotStatus.isHold(childLot.getLotStatus()),
Errors.create().key(MessageIdList.LOT_CANT_MERGE).content("The childLot status must be in HOLD! Please check!").build());
}
/**
* 校验流程版本是否修改
*
* @param lot 母批
* @param childLot 子批
*/
protected void checkProductVersionForMerge(Lot lot, Lot childLot) {
boolean productFlag = !StringUtils.equalsIgnoreCase(lot.getProductId(), childLot.getProductId());
boolean productVersionFlag = !lot.getProductVersion().equals(childLot.getProductVersion());
Assert.isFalse(productFlag || productVersionFlag,
Errors.create().content("ParentLot and ChildLot products or product versions are different!")
.build());
}
/**
* 校验产品版本是否修改
*
* @param lot 母批
* @param childLot 子批
*/
protected void checkProcessVersionForMerge(Lot lot, Lot childLot) {
boolean processFlag = !StringUtils.equalsIgnoreCase(lot.getProcessId(), childLot.getProcessId());
boolean processVersionFlag = !lot.getProcessVersion().equals(childLot.getProcessVersion());
Assert.isFalse(processFlag || processVersionFlag,
Errors.create().content("ParentLot and ChildLot processes or process versions are different!")
.build());
}
/**
* @param carrierRrn
* @return boolean
* @Description 判断carrier是否是空晶舟
* @author Aiden
*/
protected boolean carrierIsEmpty(Long carrierRrn) {
List<Map> units = wipQueryService.getUnitListByCarrier(carrierRrn);
return units == null || units.isEmpty();
}
protected String initEmptyCarrier(int slotCount) {
List<Map<String, Object>> emptyUnits = new ArrayList<>();
for (int i = 1; i <= slotCount; i++) {
Map<String, Object> unitMap = new HashMap<>();
unitMap.put("position", i + "");
unitMap.put("unitId", "");
unitMap.put("unitRrn", "");
unitMap.put("lotId", "");
emptyUnits.add(unitMap);
}
return JsonUtils.toString(emptyUnits);
}
protected void checkLotForSplit(Lot lot, String splitType) {
// 永久分批flag初始化提示
Assert.isFalse((lot == null) || (lot.getLotRrn() <= 0),
Errors.create().key(MessageIdList.SCRAPLOT_LOTID_ERROR).content("Lot id not find!").build());
// Bonding临时分批卡控
Assert.isFalse(isSapphireLot(lot) && LocationNames.TEMPORARY.equalsIgnoreCase(splitType),
Errors.create().key(MessageIdList.BOND_LOT_CAN_NOT_SPLIT).build());
// check the lot status by product typess
/*if (!lot.getLotStatus().equalsIgnoreCase(LotStatus.HOLD)) {
throw new WebException("lot.spilt_not_hold", "This lot is not in hold");
}*/
Assert.isTrue(LotStatus.isWaitingOrHold(lot.getLotStatus()),
Errors.create().key(MessageIdList.LOT_MUST_W_H).build());
Assert.isFalse(diffBatchQueryService.checkLotInBatch(lot.getLotRrn()),
Errors.create().key(MessageIdList.LOT_IN_BATCH).content("Lot in batch!").build());
wipQueryService.checkActiveInlineOcapId(lot.getLotRrn());
wipCheckService.checkPiLotNormalFunction(lot.getLotRrn(), lot.getBasedLotRrn());
}
protected boolean isSapphireLot(Lot lot) {
Item item = new Item(lot.getProductRrn());
item = prpService.getItem(item);
// 如果是Bonding类型
return StringUtils.equalsIgnoreCase(item.getObjectType(), ObjectList.SAPPHIRE);
}
/**
* child lot和lot必须都bond或都未bond才允许合批
*
* @param parentLot
* @param childLot
*/
protected void checkBond(Lot parentLot, Lot childLot) {
//#44487 将Check降到Wafer级别 卡控是否做了bond操作
Boolean parentLotBondingFlag = false;
Boolean childLotBondingFlag = false;
List<Map> parentLotUnitList = wipQueryService.getUnitListByCarrier(parentLot.getCarrierRrn());
List<Map> childLotLotUnitList = wipQueryService.getUnitListByCarrier(childLot.getCarrierRrn());
if(CollectionUtils.isNotEmpty(parentLotUnitList)){
parentLotBondingFlag = lotQueryService.getUnitBondingInfo(parentLotUnitList);
}
if(CollectionUtils.isNotEmpty(childLotLotUnitList)){
childLotBondingFlag = lotQueryService.getUnitBondingInfo(childLotLotUnitList);
}
Assert.isTrue((parentLotBondingFlag && childLotBondingFlag) ||
(!parentLotBondingFlag && !childLotBondingFlag),
Errors.create().key(MessageIdList.LOT_IS_BONDING).content("child lot is bonding Not allowed to merge!")
.build());
//如果是分批之后再bond的情况 此时的childLot有bond信息
List<Bonding> childBondInfo = lotQueryService.getBondingsByLotRrn(childLot.getLotRrn(), StringUtils.EMPTY);
if (CollectionUtils.isNotEmpty(childBondInfo) && parentLotBondingFlag && childLotBondingFlag) {
//母子批的bond辅产品必须同源
Assert.isTrue(wipCheckService.checkParentAndChildSourceMerge(parentLot, childLot),
Errors.create().key(MessageIdList.BOND_MERGE_SOURCE).content("DeBond steps exist and bond lots come from different sources!").build());
}
}
/**
* child and parent lot need the same contamination level
*
* @param parentLot
* @param childLot
*/
protected void checkContaminationLevel(Lot parentLot, Lot childLot) {
String parentContaminationLevelStr = parentLot.getPollutionLevel();
String childContaminationLevelStr = childLot.getPollutionLevel();
if (StringUtils.isNotBlank(parentContaminationLevelStr) && StringUtils.isNotBlank(childContaminationLevelStr)) {
int parentContaminationLevel = NumberUtils.toInt(parentContaminationLevelStr, -1);
int childContaminationLevel = NumberUtils.toInt(childContaminationLevelStr, -1);
if (parentContaminationLevel >= 0 && childContaminationLevel >= 0) {
Assert.state(parentContaminationLevel == childContaminationLevel,
Errors.create().key(MessageIdList.CONTAIMNATION_SHOULD_BE_CONSISTENT).content(
"The contamination level of the child lot and the parent lot must be " +
"consistent!").build());
}
}
}
/**
* Check flip for childLot and parentLot
* @param parentLot 父批
* @param childLot 子批
*/
protected void checkFlip4ChildAndParentLot(Lot parentLot, Lot childLot) {
Assert.isFalse(!StringUtils.equalsIgnoreCase(parentLot.getFlipType(), childLot.getFlipType()),
Errors.create().key(MessageIdList.CHILD_PARENT_NOT_SAME)
.content("The Flip Type of the child Lot is inconsistent with that of the parent Lot!").build());
}
protected void checkFlip4ChildAndParentLot(String parentFlipType, String childFlipType){
Assert.isFalse(!StringUtils.equalsIgnoreCase(parentFlipType, childFlipType),
Errors.create().key(MessageIdList.CHILD_PARENT_NOT_SAME)
.content("The Flip Type of the child Lot is inconsistent with that of the parent Lot!").build());
}
protected String[] buildChildAndParentLotId4RunCard(long lotRrn, String lotId){
String[] lotIds = new String[2];
LotRunCardStore lotStore = lotRunCardQueryService.getSplitRunCardLotStore(lotRrn);
List<Map<String, Object>> subList = lotRunCardQueryService.getRunCardLotsByRuncardRrn(lotStore.getRuncardRrn());
List<Map<String, Object>> finishLots = new ArrayList<>();
for (Map<String, Object> map : subList) {
if (StringUtils
.equalsIgnoreCase(RunCardStoreSubStatus.FINISH.toString(), MapUtils.getString(map, "subStatus"))) {
finishLots.add(map);
}
}
Assert.isFalse(CollectionUtils.isEmpty(finishLots), Errors.create().key(MessageIdList.CAN_NOT_MERGE).content("Can't merge lot").build());
String parentLotId = lotId;
String childLotId = null;
for (Map<String, Object> finishLot : finishLots) {
String finishLotId = MapUtils.getString(finishLot, "lotId");
if (StringUtils.equals(MapUtils.getString(finishLot, "lotId"), lotId)) {
continue;
}
if (MapUtils.getLongValue(finishLot, "lotRrn") == MapUtils.getLongValue(finishLot, "baseLotRrn")) {
childLotId = parentLotId;
parentLotId = finishLotId;
break;
} else {
if (!StringUtils.equals(MapUtils.getString(finishLot, "lotId"), lotId)) {
childLotId = finishLotId;
}
}
}
lotIds[0] = childLotId;
lotIds[1] = parentLotId;
return lotIds;
}
protected void checkQTime(long parentLotRrn, long childLotRrn) {
String qtimeErrorMsg = buidldQtimeErrorMsg(parentLotRrn, childLotRrn);
Assert.isFalse(qtimeErrorMsg.length() > 0, Errors.create().content(qtimeErrorMsg).build());
}
protected String buidldQtimeErrorMsg(Long paraLotRrn, Long childLotRrn) {
List<TimelimitStatus> paraQTimes = lotQueryService.getLotTimeLimitStatusByLotRrn(paraLotRrn, StringUtils.EMPTY);
List<TimelimitStatus> childQTimes = lotQueryService.getLotTimeLimitStatusByLotRrn(childLotRrn, StringUtils.EMPTY);
StringBuilder errorMsg = new StringBuilder();
Boolean existFlag;
for (TimelimitStatus paraQtime : paraQTimes) {
existFlag = false;
for (TimelimitStatus childQtime : childQTimes) {
if (StringUtils.equalsIgnoreCase(paraQtime.getUniqueKeyWithOutStatus(),
childQtime.getUniqueKeyWithOutStatus())) {
existFlag = true;
break;
}
}
if (!existFlag) {
errorMsg.append(paraQtime.getTimeLimitId()).append(",");
}
}
for (TimelimitStatus childQtime : childQTimes) {
existFlag = false;
for (TimelimitStatus paraQtime : paraQTimes) {
if (StringUtils.equalsIgnoreCase(paraQtime.getUniqueKeyWithOutStatus(),
childQtime.getUniqueKeyWithOutStatus())) {
existFlag = true;
break;
}
}
if (!existFlag) {
errorMsg.append(childQtime.getTimeLimitId()).append(",");
}
}
if (errorMsg.length() > 0) {
errorMsg.deleteCharAt(errorMsg.length() - 1);
errorMsg.insert(0, "Following timelimits not match:</br>");
}
if (errorMsg.length() > 0) {
errorMsg.append("</br>");
}
return errorMsg.toString();
}
protected List<SorterDetailBean> parseSorterDetailBeanList(String jsonStr) {
if (StringUtils.isBlank(jsonStr)){
return new ArrayList<>();
}
List list = JsonUtils.toObject(jsonStr, List.class);
return parseSorterDetailBeanList((List<Map>) list);
}
protected List<SorterDetailBean> parseSorterDetailBeanList(List<Map> unitMapList) {
if (CollectionUtils.isEmpty(unitMapList)){
return new ArrayList<>();
}
List<SorterDetailBean> sortJobDetailList = new ArrayList<>();
for (Map unitMap : unitMapList) {
String unitId = MapUtils.getString(unitMap, "unitId");
long unitRrn = MapUtils.getLong(unitMap, "unitRrn", 0L);
String lotId = MapUtils.getString(unitMap, "lotId");
long lotRrn = MapUtils.getLong(unitMap, "lotRrn", 0L);
int position = MapUtils.getIntValue(unitMap, "position", 0);
if (StringUtils.isNotBlank(unitId) && unitRrn > 0
&& StringUtils.isNotBlank(lotId) && (position > 0 && position < 26)) {
sortJobDetailList.add(new SorterDetailBean(lotRrn, lotId, unitRrn, unitId, position, position));
}
}
return sortJobDetailList;
}
protected List<Map> buildCarrierMapping(List<SorterDetailBean> sorterDetailBeans) {
return sorterDetailBeans.stream().map(m->{
Map map = new HashMap();
map.put("lotRrn", m.getLotRrn());
map.put("lotId", m.getLotId());
map.put("unitRrn", m.getUnitRrn());
map.put("unitId", m.getUnitId());
map.put("oldPosition", m.getSourcePosition());
map.put("position", m.getTargetPosition());
return map;
}).collect(Collectors.toList());
}
protected List<Map> parseUnits(List<Unit> unitList) {
List<Map> unitMapList = new ArrayList<>();
for (Unit u:unitList){
Map unit = new HashMap<>();
unit.put("lotRrn", u.getLotRrn());
unit.put("unitRrn", u.getUnitRrn());
unit.put("unitId", u.getUnitId());
unit.put("position", u.getPositionInCarrier());
unit.put("unitstatus", u.getUnitStatus());
unit.put("lotid", u.getLotId());
unit.put("lotId", u.getLotId());
unit.put("t7code", u.getT7code());
unit.put("ppid", u.getRecipeId());
unit.put("recipeId", u.getRecipeId());
unit.put("unitAlias1", u.getUnitAlias1());
unit.put("unitAlias2", u.getUnitAlias2());
unit.put("itemId", u.getItemId());
unitMapList.add(unit);
}
return unitMapList;
}
protected List<BiFunction<Carrier, Carrier, TransformFunc>> buildCarrierCheckFunction(String type, long facilityRrn) {
final List<BiFunction<Carrier, Carrier, TransformFunc>> functionList = new ArrayList<>();
//检查源晶舟和目标晶舟是否为DUMMY晶舟
BiFunction<Carrier, Carrier, TransformFunc> checkDummy = (sc, tc) -> {
if ((SortJob.ObjectType.DUMMY.toString().equals(sc.getObjectSubtype()) || SortJob.ObjectType.DUMMY.toString().equals(tc.getObjectSubtype())))
return Errors.create().key(MessageIdList.CANNOT_USE_DUMMY_CARRIER).build();
return null;
};
//检查源晶舟和目标的类型是否一致
final BiFunction<Carrier, Carrier, TransformFunc> checkCateGory = (sc, tc) -> {
if (tc.getInstanceRrn() > 0 && !StringUtils.equals(sc.getFlagType(), tc.getFlagType()))
return Errors.create().key(MessageIdList.CATEGORY_NOT_SAME).build();
return null;
};
//检查源晶舟和目标晶舟是否是同一类型
final BiFunction<Carrier, Carrier, TransformFunc> checkCarrierIsSameType = (sc, tc) -> {
if (tc.getInstanceRrn() > 0 && !StringUtils.equals(sc.getObjectSubtype(), tc.getObjectSubtype()))
return Errors.create().key(MessageIdList.CARRIER_TYPE_NOT_SAME).build();
return null;
};
//检查源晶舟和目标晶舟的是否需要组合
final BiFunction<Carrier, Carrier, TransformFunc> checkCarrierStatus = (sc, tc) -> {
// if (sc != null && sc.getInstanceRrn() > 0) sorterService.checkCarrierStatus(sc);
if (tc != null && tc.getInstanceRrn() > 0)
sorterService.checkCarrierStatus(tc);
return null;
};
//检查源晶舟和目标晶舟是否是同一个
final BiFunction<Carrier, Carrier, TransformFunc> checkCarrierIsSame = (sc, tc) -> {
if (StringUtils.equalsIgnoreCase(sc.getInstanceId(), tc.getInstanceId()))
return Errors.create().key(MessageIdList.CARRIER_CAN_NOT_SAME).build();
return null;
};
//检查源晶舟和目标晶舟是否被SortJob占用
final BiFunction<Carrier, Carrier, TransformFunc> checkWaitSortJob = (sc, tc) -> {
checkWaitJobs(sc.getInstanceRrn(), tc.getInstanceRrn(), 0L, null);
return null;
};
//检查目标晶舟是否需要清洗
final BiFunction<Carrier, Carrier, TransformFunc> checkTargetCarrierIsValid = (sc, tc) -> {
if (tc != null && tc.getInstanceRrn() > 0)
carrierService.checkPcdIsValid(tc.getInstanceRrn(), facilityRrn);
return null;
};
//检查目标晶舟是否被Monitor占用
final BiFunction<Carrier, Carrier, TransformFunc> checkMonitorCarrierUsed = (sc, tc) -> {
if (tc.getInstanceRrn() > 0 && lotAutoMonitorInqService.checkMonitorCarrierUsed(tc.getInstanceRrn()))
return Errors.create().key(MessageIdList.AUTOMONITOR_CARRIER_INUSED).build();
return null;
};
functionList.add(checkDummy);
functionList.add(checkCarrierIsSame);
functionList.add(checkCarrierStatus);
functionList.add(checkWaitSortJob);
functionList.add(checkTargetCarrierIsValid);
functionList.add(checkMonitorCarrierUsed);
if (SorterEnum.Constant.SRC_EXCHANGE.equalsIgnoreCase(type)){
functionList.add(checkCateGory);
functionList.add(checkCarrierIsSameType);
}
return functionList;
}
}