SortJobManagementAction.java
package com.mycim.webapp.actions.sort;
import com.fa.sesa.exception.Assert;
import com.fa.sesa.exception.Errors;
import com.fa.sesa.exception.SystemIllegalArgumentException;
import com.fa.sesa.exception.TransformFunc;
import com.fa.sesa.threadlocal.LocalContext;
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.automonitor.entity.MonitorCarrierMapping;
import com.mycim.valueobject.consts.ReferenceDetailNames;
import com.mycim.valueobject.consts.SorterEnum;
import com.mycim.valueobject.ems.Carrier;
import com.mycim.valueobject.runcard.util.RunCardConstants;
import com.mycim.valueobject.runcard.util.RunCardStoreSubStatus;
import com.mycim.valueobject.runcard.util.RunCardUtils;
import com.mycim.valueobject.sorter.*;
import com.mycim.valueobject.sys.ReferenceFileDetail;
import com.mycim.valueobject.wip.*;
import com.mycim.webapp.WebUtils;
import com.mycim.webapp.actions.lot.ManualAndSortCheckAction;
import com.mycim.webapp.forms.SortJobForm;
import com.mycim.webapp.forms.lot.LotInfoForm;
import org.apache.struts.action.ActionMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.function.BiFunction;
/**
* @Author: yibing.liu
* @Date: 2021/6/30 15:25
*/
public class SortJobManagementAction extends ManualAndSortCheckAction {
public Map loadCarrierBySrc(Map paramMap) {
long facilityRrn = LocalContext.getFacilityRrn();
String type = MapUtils.getString(paramMap, "sortJobType");
Assert.isFalse(StringUtils.isBlank(type), Errors.create().key(MessageIdList.TYPE_CAN_NOT_EMPTY).build());
String sourceCarrierId = MapUtils.getString(paramMap, "sourceCarrierId_create");
Assert.isFalse(StringUtils.isBlank(sourceCarrierId),
Errors.create().key(MessageIdList.SOURCE_ID_CAN_NOT_EMPTY).build());
//目标晶舟ID可以为空,后续由EAP指定
String targetCarrierId = MapUtils.getString(paramMap, "targetCarrierId_create");
Integer splitSeq = MapUtils.getInteger(paramMap, "splitSeq");
Map<String, Object> data = new HashMap<>();
Carrier sourceCarrier = carrierService.getCarrier(facilityRrn, sourceCarrierId);
String sourceCarrierCategory = sourceCarrier.getFlagType();
Lot sourceLot = getLotByCarrierId(sourceCarrierId);
Assert.state(Objects.nonNull(sourceLot),
Errors.create().key(MessageIdList.SOURCE_IS_EMPTY).build());
if (StringUtils.equals(LotStatus.RUNCARD_HOLD, sourceLot.getLotStatus())) {
sourceLot = lotQueryService.getLot(sourceLot.getLotId() + RunCardConstants.MAINLOT_ID_IN_MES, facilityRrn);
long sourceCarrierRrn = sourceLot.getCarrierRrn();
sourceCarrier = carrierService.getCarrier(sourceCarrierRrn);
}
LotRunCardStore sourceRunCardStore = lotRunCardQueryService.getSplitRunCardLotStore(sourceLot.getLotRrn());
Assert.isFalse(sourceRunCardStore == null || sourceRunCardStore.getRuncardRrn() <= 0,
Errors.create().key(MessageIdList.SOURCE_LOT_NOT_RC)
.content("Source carrier lot is not runcard lot!").build());
Carrier targetCarrier = null;
if (SorterEnum.Constant.SRC_MERGE.equals(type)) {
// targetCarrier = carrierService.getCarrier(facilityRrn, targetCarrierId);
// Assert.isFalse(!StringUtils.equals(LotStatus.RUNCARD_FINISH, sourceLot.getLotStatus()),
// Errors.create().key("").content("Source carrier lot status must be WAITMERGE!").build());
//
// Lot targetLot = lotQueryService.getLotByCarrierId(targetCarrierId, facilityRrn);
// Assert.isFalse(targetLot == null || targetLot.getLotRrn() <= 0,
// Errors.create().key("").content("The targetCarrier has no lot, please check!").build());
//
//
// if (StringUtils.equals(LotStatus.RUNCARD_HOLD, targetLot.getLotStatus())) {
// targetLot = lotQueryService.getLot(targetLot.getLotId() + RunCardConstants.MAINLOT_ID_IN_MES,
// facilityRrn);
// }
// Assert.isFalse(!StringUtils.equals(LotStatus.RUNCARD_FINISH, targetLot.getLotStatus()),
// Errors.create().key("").content("Target carrier lot status must be WAITMERGE!").build());
//
// LotRunCardStore targetRunCardStore = lotRunCardQueryService.getSplitRunCardLotStore(targetLot
// .getLotRrn());
// Assert.isFalse(targetRunCardStore == null || targetRunCardStore.getRuncardRrn() <= 0,
// Errors.create().key("").content("Target carrier lot is not runcard lot!").build());
//
// targetCarrier = carrierService.getCarrier(targetLot.getCarrierRrn());
// Assert.isFalse(!StringUtils.equals(sourceCarrierCategory, targetCarrier.getFlagType()),
// Errors.create().key("").content("Source carrier category is not same as target carrier
// category!").build());
} else {
if (StringUtils.isNotBlank(targetCarrierId)) {
targetCarrier = carrierService.getCarrier(facilityRrn, targetCarrierId);
sorterService.checkCarrierStatus(targetCarrier);
Assert.isFalse(!StringUtils.equals(sourceCarrierCategory, targetCarrier.getFlagType()),
Errors.create().key(MessageIdList.CATEGORY_NOT_SAME).build());
Assert.state(!lotAutoMonitorInqService.checkMonitorCarrierUsed(targetCarrier.getInstanceRrn()),
Errors.create().key(MessageIdList.AUTOMONITOR_CARRIER_INUSED).build());
} else {
targetCarrier = new Carrier();
}
}
List<Map> sourceUnits = wipQueryService.getUnitListByCarrier(sourceCarrier.getInstanceRrn());
List<Map> targetUnits = wipQueryService.getUnitListByCarrier(targetCarrier.getInstanceRrn());
if (SorterEnum.Constant.SRC_SPLIT.equals(type)) {
Assert.isFalse(sourceUnits == null || sourceUnits.isEmpty(),
Errors.create().key(MessageIdList.SOURCE_IS_EMPTY).build());
Assert.isFalse(targetUnits != null && !targetUnits.isEmpty(),
Errors.create().key(MessageIdList.TARGET_CARRIER_NOT_EMPTY).build());
//StringUtils.equalsIgnoreCase(RunCardConstants.STATUS_BANK_IN, sourceRunCardStore.getSubStatus()) &&
Assert.isFalse(!(StringUtils.equals(LotStatus.RUNCARD_WAITSPLIT, sourceLot.getLotStatus())),
Errors.create().key(MessageIdList.SOURCE_LOT_NOT_WAIT_SPIT).build());
if (StringUtils.isNotBlank(targetCarrierId)) {
carrierService.compareRealCarrierAndCheckAvailabile(facilityRrn, sourceCarrierId, targetCarrierId);
}
Assert.isFalse(splitSeq == null || splitSeq <= 0,
Errors.create().key(MessageIdList.SPLIT_SEQ_ERROR).build());
buildUnitsInfoBySrcSplit(sourceLot, sourceUnits, targetUnits, sourceRunCardStore, splitSeq, facilityRrn);
addChooseFlag(sourceUnits, SorterEnum.HardCode.FALSE_LOW);
addChooseFlag(targetUnits, SorterEnum.HardCode.FALSE_LOW);
} else {
addChooseFlag(sourceUnits, SorterEnum.HardCode.FALSE_LOW);
addChooseFlag(targetUnits, SorterEnum.HardCode.FALSE_LOW);
}
String sourceDate;
int targetSlotCount =
targetCarrier.getSlotCount() == null ? 25 : targetCarrier.getSlotCount().intValue();// 默认槽位25片
String targetData = initEmptyCarrier(targetSlotCount);
sourceDate = sorterQueryService.parseToJsonT(sourceUnits, new FilterParam<>(String.class));
if (targetUnits != null && !targetUnits.isEmpty()) {
targetData = sorterQueryService.parseToJsonT(targetUnits, new FilterParam<>(String.class));
}
// SPLIT_3PORT 才需传递 targetCarrierId2 , 故此处可不传
checkTargetCarrier(type, targetCarrierId, StringUtils.EMPTY, sourceCarrier, targetCarrier);
data.put("sourceData", sourceDate);
data.put("targetData", targetData);
data.put("soruceMaxSlot", sourceCarrier.getSlotCount());
data.put("targetMaxSlot", targetSlotCount);
return data;
}
/**
* 加载 RunCard的分批集合
*
* @param mapping
* @param sortJobForm
* @param request
* @param response
* @return
*/
public Map loadSRCSplitList(ActionMapping mapping, SortJobForm sortJobForm, HttpServletRequest request,
HttpServletResponse response) {
long facilityRrn = LocalContext.getFacilityRrn();
String carrierId = sortJobForm.getSourceCarrierId();
List<Object> jsa = new ArrayList<>();
if (StringUtils.isBlank(carrierId)) {
return ajaxReturn(null, null);
}
carrierService.getCarrier(facilityRrn, carrierId = carrierId.trim());
Lot sourceLot = getLotByCarrierId(carrierId);
Assert.state(Objects.nonNull(sourceLot),
Errors.create().key(MessageIdList.SOURCE_IS_EMPTY).build());
long carrierRrn = sourceLot.getCarrierRrn();
if (StringUtils.equals(LotStatus.RUNCARD_HOLD, sourceLot.getLotStatus())) {
sourceLot = lotQueryService.getLot(sourceLot.getLotId() + RunCardConstants.MAINLOT_ID_IN_MES, facilityRrn);
}
LotRunCardStore lotRunCardStore = lotRunCardQueryService.getSplitRunCardLotStore(sourceLot.getLotRrn());
Assert.isFalse(lotRunCardStore == null || lotRunCardStore.getRuncardRrn() <= 0,
Errors.create().key(MessageIdList.SOURCE_LOT_NOT_RC).build()); //该晶舟中批次不是Runcard 批次!
List<LotRunCardSplit> splitSet = lotRunCardQueryService.getLotRunCardSplit(lotRunCardStore.getRuncardRrn());
List<Map<String, Object>> splitLots = lotRunCardQueryService.getSplitedRunCardLots(
lotRunCardStore.getRuncardRrn());
Map<Integer, Integer> splitRunCardSeqMap = new HashMap<>(splitLots.size());
if (CollectionUtils.isNotEmpty(splitLots)) {
splitLots.forEach(s -> {
int splitSeq = MapUtils.getInteger(s, "splitSeq", -1);
if (splitSeq > 0) {
splitRunCardSeqMap.put(splitSeq, splitSeq);
}
});
}
List<SorterBean> subJobs = sorterQueryService.getAllSortJobBySourceCarrierRrn(carrierRrn);
Map<Integer, Integer> sortSplitSeqMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(subJobs)) {
subJobs.forEach(s -> {
int splitSeq = NumberUtils.toInt(s.getJsonAttributeData2(), -1);
if (splitSeq > 0) {
sortSplitSeqMap.put(splitSeq, splitSeq);
}
});
}
for (LotRunCardSplit lrcs : splitSet) {
boolean notSplited = true;
if (splitRunCardSeqMap.containsKey(lrcs.getSplitSeq())) {
notSplited = false;
}
if (sortSplitSeqMap.containsKey(lrcs.getSplitSeq())) {
notSplited = false;
}
if (notSplited) {
Map<String, Object> js = new HashMap<>();
js.put("value", lrcs.getSplitSeq());
js.put("key", lrcs.getUnitIds());
jsa.add(js);
}
}
//RunCard剩余的需要拆分的晶圆将放在母批的晶舟中。
return ajaxReturn("", jsa.size() == 1 ? new ArrayList() : jsa);
}
public Map loadCarrierByAutoMonitor(Map paramMap) {
Long facilityRrn = LocalContext.getFacilityRrn();
String sourceCarrierId = MapUtils.getString(paramMap, "sourceCarrierId_create");
Assert.state(StringUtils.isNotBlank(sourceCarrierId),
Errors.create().key(MessageIdList.SOURCE_ID_CAN_NOT_EMPTY).build());
String targetCarrierId = MapUtils.getString(paramMap, "targetCarrierId_create");
Assert.state(StringUtils.isNotBlank(sourceCarrierId),
Errors.create().key(MessageIdList.TARGET_ID_CAN_NOT_EMPTY).build());
Carrier sourceCarrier = carrierService.getCarrier(facilityRrn, sourceCarrierId);
Carrier targetCarrier = carrierService.getCarrier(facilityRrn, targetCarrierId);
String sourceDate = initEmptyCarrier(sourceCarrier.getSlotCount().intValue());
String targetData = initEmptyCarrier(targetCarrier.getSlotCount().intValue());
List<MonitorCarrierMapping> monitorCarrierMappings = lotAutoMonitorInqService.getMonitorCarrierMappings(
targetCarrier.getInstanceRrn());
Assert.state(CollectionUtils.isNotEmpty(monitorCarrierMappings),
Errors.create().content("Target monitor cassette not have sort set").build());
// create target unit info
List<Map<String, Object>> targetUnitList = new ArrayList<Map<String, Object>>();
for (long i = 1; i <= targetCarrier.getSlotCount().longValue(); i++) {
Map<String, Object> unitMap = null;
for (MonitorCarrierMapping carrierMapping : monitorCarrierMappings) {
if (carrierMapping.getPosition().longValue() == i) {
unitMap = buildUnitMapByAutoMonitor(carrierMapping.getPosition().longValue(),
carrierMapping.getUnitId(), carrierMapping.getUnitRrn(),
carrierMapping.getLotId());
}
}
if (unitMap == null) {
unitMap = buildUnitMapByAutoMonitor(i, StringUtils.EMPTY, NumberUtils.LONG_ZERO, StringUtils.EMPTY);
}
targetUnitList.add(unitMap);
}
targetData = sorterQueryService.parseToJsonT(targetUnitList, new FilterParam<>(String.class));
// source unit list
List<Lot> carrierLotList = lotInqService.getLotListByCarrierId(sourceCarrierId);
List<Unit> sourceCarrierUnitList = new ArrayList<>();
List<Map<String, Object>> sourceUnitList = new ArrayList<Map<String, Object>>();
for (Lot sourceCarrierLot : carrierLotList) {
List<Unit> unitList = wipQueryService.getUnitList(sourceCarrierLot.getLotRrn());
unitList.stream().forEach(unit -> {
unit.setLotId(sourceCarrierLot.getLotId());
});
sourceCarrierUnitList.addAll(unitList);
}
for (long i = 1; i <= sourceCarrier.getSlotCount().longValue(); i++) {
Map<String, Object> unitMap = null;
for (Unit sourceUnit : sourceCarrierUnitList) {
if (sourceUnit.getPositionInCarrier().longValue() == i) {
boolean needSort = false;
for (MonitorCarrierMapping carrierMapping : monitorCarrierMappings) {
if (sourceUnit.getUnitRrn() == carrierMapping.getUnitRrn().longValue()) {
needSort = true;
}
}
if (!needSort) {
unitMap = buildUnitMapByAutoMonitor(sourceUnit.getPositionInCarrier().longValue(),
sourceUnit.getUnitId(), sourceUnit.getUnitRrn(),
sourceUnit.getLotId());
}
}
}
if (unitMap == null) {
unitMap = buildUnitMapByAutoMonitor(i, StringUtils.EMPTY, NumberUtils.LONG_ZERO, StringUtils.EMPTY);
}
sourceUnitList.add(unitMap);
}
sourceDate = sorterQueryService.parseToJsonT(sourceUnitList, new FilterParam<>(String.class));
Map<String, Object> data = new HashMap<String, Object>();
data.put("sourceData", sourceDate);
data.put("targetData", targetData);
data.put("soruceMaxSlot", sourceCarrier.getSlotCount());
data.put("targetMaxSlot", targetCarrier.getSlotCount());
return data;
}
/**
* 加载 晶舟 中的晶圆
*
* @param paramMap
* @return
* @throws Exception
*/
public Map loadCarrier(Map paramMap) throws Exception {
long facilityRrn = LocalContext.getFacilityRrn();
String type = MapUtils.getString(paramMap, "sortJobType");
Assert.isFalse(StringUtils.isBlank(type), Errors.create().key(MessageIdList.TYPE_CAN_NOT_EMPTY).build());
String sourceCarrierId = MapUtils.getString(paramMap, "sourceCarrierId_create");
Assert.isFalse(StringUtils.isBlank(sourceCarrierId),
Errors.create().key(MessageIdList.SOURCE_ID_CAN_NOT_EMPTY).build());
//目标晶舟ID可以为空,后续由EAP指定
String targetCarrierId = MapUtils.getString(paramMap, "targetCarrierId_create");
String targetCarrierId2 = MapUtils.getString(paramMap, "targetCarrierId2_create");
Map<String, Object> data = new HashMap<>();
Carrier sourceCarrier = carrierService.getCarrier(facilityRrn, sourceCarrierId);
Carrier targetCarrier = StringUtils.isNotBlank(targetCarrierId) ? carrierService.getCarrier(facilityRrn,
targetCarrierId)
: new Carrier();
Assert.isFalse((SortJob.ObjectType.DUMMY.toString().equals(sourceCarrier.getObjectSubtype()) ||
SortJob.ObjectType.DUMMY.toString().equals(targetCarrier.getObjectSubtype())),
Errors.create().key(MessageIdList.CANNOT_USE_DUMMY_CARRIER).build());
checkTargetCarrier(type, targetCarrierId, targetCarrierId2, sourceCarrier, targetCarrier);
long sourceCarrierRrn = sourceCarrier.getInstanceRrn();
long targetCarrierRrn = targetCarrier.getInstanceRrn();
List<Map> sourceUnits = wipQueryService.getUnitListByCarrier(sourceCarrierRrn);
List<Map> targetUnits =
targetCarrierRrn > 0 ? wipQueryService.getUnitListByCarrier(targetCarrierRrn) : new ArrayList<>();
Lot sourceLot = checkCarrierForLoad(sourceCarrier, targetCarrier, type, sourceUnits, targetUnits, facilityRrn);
if (SorterEnum.Check.isProdLotExchange(type)){
//RC不允许在此进行Exchange操作。
//先检查是不是RC的批次
Assert.state(!lotRunCardQueryService.checkLotInRunCard(sourceLot.getLotRrn()),
Errors.create().key(MessageIdList.IS_RC_LOT).content("{} is a RunCard Lot! Can't operate here!").args(sourceLot.getLotId()).build());
}
addChooseFlag(sourceUnits, SorterEnum.HardCode.TRUE_LOW);
addChooseFlag(targetUnits, SorterEnum.HardCode.FALSE_LOW);
String sourceDate;
int targetSlotCount =
targetCarrier.getSlotCount() == null ? 25 : targetCarrier.getSlotCount().intValue();// 默认槽位25片
String targetData = initEmptyCarrier(targetSlotCount);
FilterParam filterParam;
if (SorterEnum.Constant.SRC_MERGE.equals(type)) {
List<Unit> childUnitList = wipQueryService.getUnitList(sourceLot.getLotRrn());
List<Unit> parentUnitList = wipQueryService.getUnitList(sourceLot.getCreatedPlanLotRrn());
sourceUnits = parseUnits(childUnitList);
targetUnits = parseUnits(parentUnitList);
}
if (SorterEnum.Check.isFlip(type)) {
Assert.isFalse(StringUtils.isBlank(sourceLot.getFlipType()), Errors.create().key(MessageIdList.LOT_NOT_SET)
.content(
"Flip property is not set for " +
"Lot {}!")
.args(sourceLot.getLotId()).build());
filterParam = new FilterParam<>("lotId", String.class);
if (LotStatus.isRunCardHold(sourceLot.getLotStatus())) {
sourceLot = lotQueryService.getLot(RunCardUtils.buildMainRcLotId(sourceLot.getLotId()));
sourceUnits = parseUnits(wipQueryService.getUnitList(sourceLot.getLotRrn()));
}
filterParam.setMark(sourceLot.getFlipType());
filterParam.setCustomColumn("mark");
sourceDate = sorterQueryService.parseToJsonT(sourceUnits, filterParam);
filterParam.setMark(SorterEnum.Constant.getOpposite(sourceLot.getFlipType()));
targetData = sorterQueryService.parseToJsonT(sourceUnits, filterParam);
}else if (SorterEnum.Check.isOffLineCheckT7Code(type) || SorterEnum.Check.isOfflineReadMaterialId(type)) {
filterParam = new FilterParam<>(String.class);
if (LotStatus.isRunCardHold(sourceLot.getLotStatus())) {
sourceLot = lotQueryService.getLot(RunCardUtils.buildMainRcLotId(sourceLot.getLotId()));
sourceUnits = parseUnits(wipQueryService.getUnitList(sourceLot.getLotRrn()));
}
sourceDate = sorterQueryService.parseToJsonT(sourceUnits, filterParam);
targetData = sorterQueryService.parseToJsonT(sourceUnits, filterParam);
}else {
filterParam = new FilterParam<>(String.class);
sourceDate = sorterQueryService.parseToJsonT(sourceUnits, filterParam);
if (targetUnits != null && !targetUnits.isEmpty()) {
targetData = sorterQueryService.parseToJsonT(targetUnits, filterParam);
}
}
data.put("sourceData", sourceDate);
data.put("targetData", targetData);
data.put("soruceMaxSlot", sourceCarrier.getSlotCount());
data.put("targetMaxSlot", targetSlotCount);
return data;
}
private void checkTargetCarrier(String type, String targetCarrierId, String targetCarrierId2, Carrier sourceCarrier,
Carrier targetCarrier) {
if (SorterEnum.Check.targetCarrierMayBeEmpty(type)) {
//Target carrier 可能为空
if (targetCarrier.isNotEmpty()) {
//用户指定了Cassette 1 后,才检查
sorterService.checkCarrierStatus(targetCarrier);
Assert.isFalse(!StringUtils.equals(sourceCarrier.getFlagType(), targetCarrier.getFlagType()),
Errors.create().key(MessageIdList.CATEGORY_NOT_SAME).build());
// SPLIT_3PORT ignore type verify
Assert.isFalse(
!StringUtils.equals(sourceCarrier.getObjectSubtype(), targetCarrier.getObjectSubtype()) &&
!StringUtils.equals(SorterEnum.Constant.SPLIT_3PORT, type),
Errors.create().key(MessageIdList.CARRIER_TYPE_NOT_SAME).build());
}
}
if (SorterEnum.Check.needCheckTargetCarrier(type)) {
//需要检查目标晶舟的type
Assert.isFalse(StringUtils.isBlank(targetCarrierId),
Errors.create().key(MessageIdList.TARGET_ID_CAN_NOT_EMPTY).build());
if (StringUtils.equals(type, SorterEnum.Constant.SPLIT_3PORT)) {
Assert.isFalse(StringUtils.isBlank(targetCarrierId2),
Errors.create().key(MessageIdList.TARGET_ID_CAN_NOT_EMPTY).build());
Carrier targetCarrier2 = carrierService.getCarrier(LocalContext.getFacilityRrn(), targetCarrierId2);
sorterQueryService.checkPort2CstForLoad(sourceCarrier, targetCarrier, targetCarrier2);
}
}
}
public Map loadCarrierByExchange(Map paramMap) {
long facilityRrn = LocalContext.getFacilityRrn();
String type, sourceCarrierId, targetCarrierId;
Assert.isFalse(StringUtils.isBlank(type = MapUtils.getString(paramMap, "sortJobType")),
Errors.create().key(MessageIdList.TYPE_CAN_NOT_EMPTY).build());
Assert.isFalse(StringUtils.isBlank(sourceCarrierId = MapUtils.getString(paramMap, "sourceCarrierId_create")),
Errors.create().key(MessageIdList.SOURCE_ID_CAN_NOT_EMPTY).build());
Map<String, Object> data = new HashMap<>();
Carrier sourceCarrier = carrierService.getCarrier(facilityRrn, sourceCarrierId);
Carrier targetCarrier = StringUtils.isNotBlank(targetCarrierId = MapUtils.getString(paramMap, "targetCarrierId_create")) ?
carrierService.getCarrier(facilityRrn, targetCarrierId) : new Carrier(); //目标晶舟ID可以为空,后续由EAP指定
List<BiFunction<Carrier, Carrier, TransformFunc>> functionList = this.buildCarrierCheckFunction(type, facilityRrn);
TransformFunc transformFunc;
for (BiFunction<Carrier, Carrier, TransformFunc> bi:functionList){
if ((transformFunc = bi.apply(sourceCarrier, targetCarrier)) != null) throw new SystemIllegalArgumentException(transformFunc);
}
long sourceCarrierRrn = sourceCarrier.getInstanceRrn();
long targetCarrierRrn = targetCarrier.getInstanceRrn();
List<Map> sourceUnits = new ArrayList<>();
List<Map> targetUnits = targetCarrierRrn > 0 ? wipQueryService.getUnitListByCarrier(targetCarrierRrn) : new ArrayList<>();
// 获取LOT
Lot sourceLot = getLotByCarrierId(sourceCarrierId);
Assert.state(sourceLot != null, Errors.create().key(MessageIdList.SOURCE_IS_EMPTY).build());
if (SorterEnum.Check.isSrcExchange(type)){
//先检查是不是RC的批次
Assert.isFalse(!lotRunCardQueryService.checkLotInRunCard(sourceLot.getLotRrn()),
Errors.create().key(MessageIdList.NOT_RC_LOT).content("{} is not a RunCard Lot!").args(sourceLot.getLotId()).build());
if (LotStatus.isRunCardHold(sourceLot.getLotStatus())) {//MAINRC 不能用carrierRrn去查unit,因为它和原Lot是共用Cassette的。
sourceLot = lotQueryService.getLot(RunCardUtils.buildMainRcLotId(sourceLot.getLotId()));
List<Unit> sourceUnitList = wipQueryService.getUnitList(sourceLot.getLotRrn());
sourceUnits = parseUnits(sourceUnitList);
} else {
sourceUnits = wipQueryService.getUnitListByCarrier(sourceCarrierRrn);
}
} else {
//先检查是不是RC的批次
Assert.state(!lotRunCardQueryService.checkLotInRunCard(sourceLot.getLotRrn()),
Errors.create().key(MessageIdList.IS_RC_LOT).content("{} is a RunCard Lot! Can't operate here!").args(sourceLot.getLotId()).build());
sourceUnits = wipQueryService.getUnitListByCarrier(sourceCarrierRrn);
}
// 若为runcard 特殊状态 则不需要hold 就可建sortJob
if (!LotStatus.isRunCardSpecialStatus(sourceLot.getLotStatus())) {
Assert.isFalse(!LotStatus.HOLD.equals(sourceLot.getLotStatus()) && !LotStatus.isRunCardHold(sourceLot.getLotStatus()),
Errors.create().key(MessageIdList.LOT_MUST_HOLD).build());
}
//获取unitList ,原晶舟必须有晶圆
Assert.isFalse(sourceUnits == null || sourceUnits.isEmpty(), Errors.create().key(MessageIdList.CARRIER_NO_UNIT).build());
Assert.isFalse((targetUnits != null && !targetUnits.isEmpty()), Errors.create().key(MessageIdList.TARGET_CARRIER_NOT_EMPTY).build());
Assert.isFalse(targetCarrier.getInstanceRrn() > 0 && targetCarrier.getAvailableSlotCount() < sourceLot.getQty1(),
Errors.create().content("CST {}'s qty is {} > {}")
.args(sourceCarrier.getInstanceId(), sourceLot.getInt_qty1(), targetCarrier.getSlotCount()).build());
// 3、获取ProcessLocation
String processLocation = sourceLot.getProcessLocation();
addChooseFlag(sourceUnits, SorterEnum.HardCode.TRUE_LOW);
addChooseFlag(targetUnits, SorterEnum.HardCode.FALSE_LOW);
String sourceDate;
int targetSlotCount = targetCarrier.getSlotCount() == null ? 25 : targetCarrier.getSlotCount().intValue();// 默认槽位25片
String targetData = initEmptyCarrier(targetSlotCount);
FilterParam filterParam = new FilterParam<>(String.class);
sourceDate = sorterQueryService.parseToJsonT(sourceUnits, filterParam);
data.put("sourceData", sourceDate);
data.put("targetData", targetData);
data.put("soruceMaxSlot", sourceCarrier.getSlotCount());
data.put("targetMaxSlot", targetSlotCount);
data.put("processLocation", processLocation);
return data;
}
/**
* 保存 SortJob
*
* @param paramMap
* @return
*/
public Map saveSortJob(Map paramMap) {
String type = MapUtils.getString(paramMap, "sortJobType");
Assert.isFalse(StringUtils.isBlank(type), Errors.create().key(MessageIdList.TYPE_CAN_NOT_EMPTY).build());
String sourceCarrierId = MapUtils.getString(paramMap, "sourceCarrierId_create");
Assert.isFalse(StringUtils.isBlank(sourceCarrierId),
Errors.create().key(MessageIdList.SOURCE_ID_CAN_NOT_EMPTY).build());
//目标晶舟ID可以为空,后续由EAP指定
String targetCarrierId = MapUtils.getString(paramMap, "targetCarrierId_create");
String targetCarrierId2 = MapUtils.getString(paramMap, "targetCarrierId2_create");
String sourceUnitListStr = MapUtils.getString(paramMap, "sourceListValues");
String targetUnitListStr = MapUtils.getString(paramMap, "targetListValues");
Integer splitSeq = MapUtils.getInteger(paramMap, "splitSeq", -1);
SortJobForm sortJobForm = new SortJobForm(type, sourceCarrierId, targetCarrierId, targetCarrierId2,
sourceUnitListStr, targetUnitListStr);
//校验
sortJobForm.setSplitSeq(splitSeq);//runCard split need splitSeq
SortJobBean sortJobBean = this.buildSortJobBean(sortJobForm);
Assert.isFalse(sortJobBean == null, Errors.create().key(MessageIdList.TYPE_NOT_EXIST).build());
//创建SortJob
sortJobBean.setTransPerformedby(LocalContext.getUserId());
sorterService.addSortJob(sortJobBean);
return ajaxReturn("Save succeeded!", null);
}
// pilot sortjob 参数组装
public void pilotSplitSortJob(Map param) {
//需要判断是否
List<Map> childLots = (List<Map>) WebUtils.getCacheString2Obj(MapUtils.getString(param, "cacheChildLots"));
LotInfoForm lotInfoForm = (LotInfoForm) WebUtils.getCacheString2Obj(MapUtils.getString(param, "cacheLotInfo"));
Assert.state(CollectionUtils.isNotEmpty(childLots),
Errors.create().key(MessageIdList.PILOT_TARGET_CARRIER_EMPTY)
.content("The target carrier has not been selected!").build());
String targetListValues = MapUtils.getString(childLots.get(0), "unitList");
Map<String, String> map = new HashMap();
map.put("sortJobType", MapUtils.getString(param, "sortJobType"));
map.put("targetCarrierId_create", MapUtils.getString(childLots.get(0), "carrierId"));
map.put("sourceCarrierId_create", lotInfoForm.getCarrierId());
map.put("sourceListValues", buildCarrierList(lotInfoForm.getSourceListValues(), lotInfoForm.getLotRrn()));
map.put("targetListValues", buildCarrierList(targetListValues, lotInfoForm.getLotRrn()));
saveSortJob(map);
}
private Lot getLotByCarrierId(String carrierId) {
List<Lot> lotList = lotInqService.getLotListByCarrierId(carrierId);
Assert.state(lotList.size() <= 1, Errors.create().key(MessageIdList.REWORK_SAME_CARRIER_FOR_LOTS)
.content("More than one lot in the same Carrier.").build());
if (CollectionUtils.isNotEmpty(lotList)) {
return lotList.iterator().next();
}
return null;
}
private void buildUnitsInfoBySrcSplit(Lot sourceLot, List<Map> sourceUnits, List<Map> targetUnits,
LotRunCardStore sourceRunCardStore, Integer splitSeq, Long facilityRrn) {
List<LotRunCardSplit> splitSet = lotRunCardQueryService.getLotRunCardSplit(sourceRunCardStore.getRuncardRrn());
LotRunCardSplit splitInfo = null;
for (LotRunCardSplit set : splitSet) {
if (set.getSplitSeq().equals(splitSeq)) {
splitInfo = set;
break;
}
}
if (splitInfo != null) {
String[] units = StringUtils.split(splitInfo.getUnitRrns(), ",");
for (String unitRrnStr : units) {
Long unitRrn = RunCardUtils.patternUnitRrn(unitRrnStr);
String unitId = RunCardUtils.buildRunCardUnitId(wipQueryService.getUnitIdByRrn(unitRrn));
Unit unit = wipQueryService.getUnit(facilityRrn, unitId);
for (int i = 0; i < sourceUnits.size(); i++) {
Map sourceUnit = sourceUnits.get(i);
if (MapUtils.getLongValue(sourceUnit, "unitRrn") == unit.getUnitRrn()) {
targetUnits.add(sourceUnits.remove(i));
break;
}
}
}
}
Assert.isFalse(targetUnits.isEmpty(), Errors.create().key(MessageIdList.SPLIT_INFO_WAFER_NOT_EXIST).build());
}
private void addChooseFlag(List<Map> units, String chooseFlag) {
for (Map unit : units) {
unit.put("chooseFlag", chooseFlag);
}
}
private SortJobBean buildSortJobBean(SortJobForm sjf) {
long facilityRrn = LocalContext.getFacilityRrn();
Carrier sCarrier = carrierService.getCarrier(facilityRrn, sjf.getSourceCarrierId());
Assert.isTrue(sCarrier != null,
Errors.create().key(MessageIdList.SOURCE_ID_NOT_EXIST).build());
Assert.isTrue(sCarrier.getInstanceRrn() > 0,
Errors.create().key(MessageIdList.SOURCE_ID_NOT_EXIST).build());
Carrier tCarrier = StringUtils.isBlank(sjf.getTargetCarrierId()) ? new Carrier() : carrierService.getCarrier(
facilityRrn, sjf.getTargetCarrierId());
Carrier tCarrier2 = StringUtils.isBlank(sjf.getTargetCarrierId2()) ? null : carrierService.getCarrier(
facilityRrn, sjf.getTargetCarrierId2());
sjf.setSourceCarrierRrn(sCarrier.getInstanceRrn());
sjf.setTargetCarrierRrn(tCarrier.getInstanceRrn());
sjf.setTargetCarrierRrn2(tCarrier2 == null ? null : tCarrier2.getInstanceRrn());
ReferenceFileDetail referenceFileDetail = getReferenceFileDetail(ReferenceDetailNames.SORT_HOLD_CODE,
sjf.getJobType(),
LocalContext.getFacilityRrn());
Assert.isFalse(referenceFileDetail == null,
Errors.create().key(MessageIdList.REFERENCE_NOT_EXIST).args(ReferenceDetailNames.SORT_HOLD_CODE)
.build());
String sortHoldCode = referenceFileDetail.getData1Value();
Assert.isFalse(StringUtils.isBlank(sortHoldCode), Errors.create().key(MessageIdList.REFERENCE_NOT_EXIST_VALUE)
.args(sjf.getJobType(),
ReferenceDetailNames.SORT_HOLD_CODE).build());
sjf.setSortHoldCode(sortHoldCode);
switch (sjf.getJobType()) {
case SorterEnum.Constant.EXCHANGE:
return buildExchangeSortJob(sCarrier, tCarrier, sjf);
case SorterEnum.Constant.SPLIT:
return buildSplitSortJob(sCarrier, tCarrier, sjf);
case SorterEnum.Constant.MERGE:
return buildMergeSortJob(sCarrier, tCarrier, sjf);
case SorterEnum.Constant.SPLIT_3PORT:
return buildSplitMorePortSortJob(sCarrier, tCarrier, tCarrier2, sjf);
case SorterEnum.Constant.SRC_SPLIT:
return buildRunCardSplitSortJob(sCarrier, tCarrier, sjf);
case SorterEnum.Constant.SRC_MERGE:
return buildRunCardMergeSortJob(sCarrier, tCarrier, sjf);
case SorterEnum.Constant.AUTO_MONITOR:
return buildAutoMonitorSortInfo(sCarrier, tCarrier, sjf);
case SorterEnum.Constant.FLIP_SIDE:
return buildFlipSideSortInfo(sCarrier, sCarrier, sjf);
case SorterEnum.Constant.PILOT_SPLIT:
return buildPilotSplitSortJob(sCarrier, tCarrier, sjf);
case SorterEnum.Constant.OFFLINE_CHECK_T7CODE:
return buildCheckT7CodeSortInfo(sCarrier, sjf);
case SorterEnum.Constant.SPECIAL_EXCHANGE:
return buildExchangeSortJobBean(sCarrier, tCarrier, sjf, SorterEnum.Constant.SPECIAL_EXCHANGE);
case SorterEnum.Constant.SRC_EXCHANGE:
return buildExchangeSortJobBean(sCarrier, tCarrier, sjf, SorterEnum.Constant.SRC_EXCHANGE);
case SorterEnum.Constant.SRC_SPECIAL_EXCHANGE:
return buildExchangeSortJobBean(sCarrier, tCarrier, sjf, SorterEnum.Constant.SRC_SPECIAL_EXCHANGE);
case SorterEnum.Constant.OFFLINE_READ_MATERIALID:
return buildReadMaterialIdSortInfo(sCarrier, sjf);
default:
return null;
}
}
private SortJobBean buildExchangeSortJobBean(Carrier sc, Carrier tc, SortJobForm sjf, String type) {
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(sc.getObjectSubtype()), Errors.create().key(MessageIdList.SOURCE_CAN_NOT_DUMMY).build());
List<SorterDetailBean> sourceUnitList = parseSorterDetailBeanList(sjf.getSourceListValues());
Assert.isFalse(!sourceUnitList.isEmpty(), Errors.create().key(MessageIdList.SOURCE_CARRIER_HAVE_NO_WAFER).build());
List<SorterDetailBean> targetUnitList = parseSorterDetailBeanList(sjf.getTargetListValues());
Assert.isFalse(targetUnitList.isEmpty(), Errors.create().key(MessageIdList.TARGET_CARRIER_HAVE_NO_WAFER).build());
if (tc != null && tc.isNotEmpty()) {
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(tc.getObjectSubtype()), Errors.create().key(MessageIdList.TARGET_CAN_NOT_DUMMY).build());
sorterService.checkCarrierStatus(tc);
Assert.state(!lotAutoMonitorInqService.checkMonitorCarrierUsed(tc.getInstanceRrn()), Errors.create().key(MessageIdList.AUTOMONITOR_CARRIER_INUSED).build());
// 检查目标晶舟是否是空的
Assert.isFalse(!carrierIsEmpty(sjf.getTargetCarrierRrn()), Errors.create().key(MessageIdList.TARGET_BE_USED).build());
}
Assert.isFalse(sourceUnitList.size() > 0, Errors.create().key(MessageIdList.EXCHANGE_NEED_ALL).build());
checkSourceAndTargetInfo(sjf);
SorterBean sorterBean = buildSorterBean(SorterEnum.Constant.CREATE, type, sc, tc, targetUnitList);
SortJobBean sortJobBean = new SortJobBean();
sortJobBean.setSorterBeans(sorterBean);
return sortJobBean;
}
/**
* 检查需要加载的晶舟
*
* @param sourceCarrier sourceCarrier
* @param targetCarrier targetCarrier
* @param jobType jobType
* @param sourceUnits sourceUnits
* @param targetUnits targetUnits
* @param facilityRrn facilityRrn
*/
private Lot checkCarrierForLoad(Carrier sourceCarrier, Carrier targetCarrier, String jobType, List<Map> sourceUnits,
List<Map> targetUnits, Long facilityRrn) {
String sourceCarrierId = sourceCarrier.getInstanceId();
String targetCarrierId = targetCarrier.getInstanceId();
Assert.isFalse(StringUtils.equalsIgnoreCase(sourceCarrier.getInstanceId(), targetCarrier.getInstanceId()),
Errors.create().key(MessageIdList.CARRIER_CAN_NOT_SAME).build());
// 原晶舟必须有晶圆
Assert.isFalse(sourceUnits == null || sourceUnits.isEmpty(),
Errors.create().key(MessageIdList.CARRIER_NO_UNIT).build());
// 检查批次状态
Lot sourceLot = getLotByCarrierId(sourceCarrierId);
Assert.state(Objects.nonNull(sourceLot),
Errors.create().key(MessageIdList.SOURCE_IS_EMPTY).build());
if (!(SorterEnum.Constant.SRC_MERGE.equals(jobType) || SorterEnum.Check.isOffLineCheckT7Code(jobType)
|| SorterEnum.Check.isOfflineReadMaterialId(jobType))) {
checkWaitJobs(sourceCarrier.getInstanceRrn(), targetCarrier.getInstanceRrn(), 0L, null);
Assert.isFalse(!LotStatus.HOLD.equals(sourceLot.getLotStatus()) &&
!LotStatus.isRunCardHold(sourceLot.getLotStatus()),
Errors.create().key(MessageIdList.LOT_MUST_HOLD).build());
}
// 若jobType为OFFLINE_CHECK_T7CODE 时单独check
if (SorterEnum.Check.isOffLineCheckT7Code(jobType)) {
checkWaitJobs(sourceCarrier.getInstanceRrn(), targetCarrier.getInstanceRrn(), 0L, null);
Lot checkLot = sourceLot;
if (LotStatus.isRunCardHold(checkLot.getLotStatus())) {
checkLot = lotQueryService.getLot(RunCardUtils.buildMainRcLotId(checkLot.getLotId()));
}
if (!LotStatus.isRunCardSpecialStatus(checkLot.getLotStatus())) {
Assert.isFalse(!LotStatus.HOLD.equals(checkLot.getLotStatus()),
Errors.create().key(MessageIdList.LOT_MUST_HOLD).build());
}
}
if (SorterEnum.Constant.MERGE.equals(jobType)) {
// Lot targetLot = lotQueryService.getLotByCarrierId(targetCarrier.getInstanceId(), facilityRrn);
Lot targetLot = getLotByCarrierId(targetCarrierId);
Assert.state(CollectionUtils.isNotEmpty(targetUnits),
Errors.create().key(MessageIdList.TARGET_CARRIER_NO_WAFER).build());
Assert.state(LotStatus.isHold(targetLot.getLotStatus()),
Errors.create().key(MessageIdList.LOT_MUST_HOLD).build());
// Lot childLotId = lotQueryService.getLotByCarrierId(sourceCarrierId, facilityRrn);
// Lot parentLotId = lotQueryService.getLotByCarrierId(targetCarrierId, facilityRrn);
// 检查合批规则
lotService.canMergeLotCheck(sourceLot.getLotId(), targetLot.getLotId());
} else if (SorterEnum.Constant.SRC_MERGE.equals(jobType)) {
//先检查是不是RC的批次
Assert.isFalse(!lotRunCardQueryService.checkLotInRunCard(sourceLot.getLotRrn()),
Errors.create().key(MessageIdList.NOT_RC_LOT).content("{} is not a RunCard Lot!")
.args(sourceLot.getLotId()).build());
if (LotStatus.isRunCardHold(sourceLot.getLotStatus())) {
sourceLot = lotQueryService.getLot(RunCardUtils.buildMainRcLotId(sourceLot.getLotId()));
}
Lot targetLot = getLotByCarrierId(targetCarrierId);
Assert.state(targetLot != null,
Errors.create().key(MessageIdList.TARGET_CARRIER_NO_WAFER).build());
// Lot targetLot = lotQueryService.getLotByCarrierId(targetCarrier.getInstanceId(), facilityRrn);//Lot Id为母批的ID
//先检查是不是RC的批次
Assert.isFalse(!lotRunCardQueryService.checkLotInRunCard(targetLot.getLotRrn()),
Errors.create().key(MessageIdList.NOT_RC_LOT).content("{} is not a RunCard Lot!")
.args(targetLot.getLotId()).build());
if (LotStatus.isRunCardHold(targetLot.getLotStatus())) {
targetLot = lotQueryService.getLot(RunCardUtils.buildMainRcLotId(targetLot.getLotId()));
}
Assert.isFalse((targetUnits == null || targetUnits.isEmpty()),
Errors.create().key(MessageIdList.TARGET_CARRIER_NO_WAFER).build());
Assert.isFalse(!LotStatus.RUNCARD_FINISH.equals(targetLot.getLotStatus()),
Errors.create().content("Lot status must be WAITMERGE!")
.key(MessageIdList.LOT_MUST_WAIT_MERGE).build());
// Lot childLotId = lotQueryService.getLotByCarrierId(sourceCarrierId, facilityRrn);
// Lot parentLotId = lotQueryService.getLotByCarrierId(targetCarrierId, facilityRrn);
String[] lotIdArr = buildChildAndParentLotId4RunCard(sourceLot.getLotRrn(), sourceLot.getLotId());
String childLotId = lotIdArr[0];
String parentLotId = lotIdArr[1];
Assert.isFalse(!StringUtils.equalsIgnoreCase(sourceLot.getLotId(), childLotId),
Errors.create().key(MessageIdList.PARENT_IN_TARGET).content(
"The carrier where the parent Lot is located should be placed at the " +
"position of the Target Carrier!").build());
Assert.isFalse(!LotStatus.RUNCARD_FINISH.equals(sourceLot.getLotStatus()),
Errors.create().content("Lot status must be WAITMERGE!")
.key(MessageIdList.LOT_MUST_WAIT_MERGE).build());
//SRC的Merge需要母批放在Target的位置上,所以不需要check Target的SortJob,因为可能会存在多个
checkWaitJobs(sourceCarrier.getInstanceRrn(), 0L, 0L, null);
Map<String, Object> childLotMap = lotRunCardQueryService.getRCLotInfoMap(childLotId);
Map<String, Object> parentLotMap = lotRunCardQueryService.getRCLotInfoMap(parentLotId);
//check flip type
String childFlipType = MapUtils.getString(childLotMap, "flipType");
String parentFlipType = MapUtils.getString(parentLotMap, "flipType");
this.checkFlip4ChildAndParentLot(parentFlipType, childFlipType);
this.checkQTime(targetLot.getLotRrn(), sourceLot.getLotRrn());
sourceLot.setCreatedPlanLotRrn(MapUtils.getLong(parentLotMap, "lotRrn"));
} else {
Assert.isFalse((targetUnits != null && !targetUnits.isEmpty()),
Errors.create().key(MessageIdList.TARGET_CARRIER_NOT_EMPTY).build());
}
return sourceLot;
}
/**
* 校验源晶舟和目标晶舟以及晶舟中的批次的相关卡控
* 1 检查源晶舟与目标晶舟是否存在于同一个SortJob中。
* 2 检查晶舟中的批次是否为HOLD状态。
* 3 检查晶舟中的批次是否存在指定的HoldCode。
* 4 分别检查 源晶舟、目标晶舟、目标晶舟2是否存在SortJob。
*
* @param sortJobForm
*/
private Lot checkSourceAndTargetInfo(SortJobForm sortJobForm) {
SortJobBean sortJob = sorterQueryService.getSortJobByCarrier(sortJobForm.getSourceCarrierRrn(),
sortJobForm.getTargetCarrierRrn(),
sortJobForm.getTargetCarrierRrn2());
if (sortJobForm.isRcType()) {
Integer splitSeq = (splitSeq = sortJobForm.getSplitSeq()) != null ? splitSeq : -1;
if (sortJob.isEmpty() && CollectionUtils.isNotEmpty(sortJob.getSorterBeans())) {
List<SorterBean> subJobs = sortJob.getSorterBeans();
for (SorterBean sb : subJobs) {
Assert.isFalse(splitSeq == Integer.parseInt(sb.getJsonAttributeData2()),
Errors.create().key(MessageIdList.SRC_CHILD_LOT_IN_SORT).build());
}
}
} else {
Assert.isFalse(sortJob.isEmpty(), Errors.create().key(MessageIdList.CARRIER_HAVE_JOB).build());
}
// 检查批次状态
Lot sourceLot = getLotByCarrierId(sortJobForm.getSourceCarrierId());
Assert.state(Objects.nonNull(sourceLot),
Errors.create().key(MessageIdList.SOURCE_IS_EMPTY).build());
//1、先检查批次的状态是否为hold
if (sortJobForm.isRcType()) {
Assert.isFalse(!LotStatus.RUNCARD_HOLD.equals(sourceLot.getLotStatus()),
Errors.create().key(MessageIdList.LOT_MUST_HOLD).build());
} else {
if (LotStatus.isRunCardHold(sourceLot.getLotStatus())) {
sourceLot = lotQueryService.getLot(RunCardUtils.buildMainRcLotId(sourceLot.getLotId()));
}
if (!SorterEnum.Check.isSpecialStatusForRcSortJob(sortJobForm.getJobType(), sourceLot.getLotStatus())) {
Assert.isFalse(!LotStatus.HOLD.equals(sourceLot.getLotStatus()) &&
!LotStatus.isRunCardHold(sourceLot.getLotStatus()),
Errors.create().key(MessageIdList.LOT_MUST_HOLD).build());
}
}
if (SorterEnum.Check.isFlip(sortJobForm.getJobType()) || SorterEnum.Check.isSrcExchange(sortJobForm.getJobType())) {
if (LotStatus.isRunCardHold(sourceLot.getLotStatus())) {
sourceLot = lotQueryService.getLot(RunCardUtils.buildMainRcLotId(sourceLot.getLotId()));
}
}
// 若 jobType 为 OFFLINE_CHECK_T7CODE、SRC_EXCHANGE、SRC_SPECIAL_EXCHANGE 且 lot状态为runcard内特殊状态
// 则不需要校验hold code
if (!SorterEnum.Check.isSpecialStatusForRcSortJob(sortJobForm.getJobType(), sourceLot.getLotStatus())) {
//2、检查HoldCode
List<Map> holdInfos = wipQueryService.getHoldReasons(sourceLot.getLotRrn());
boolean holdCodeFlag = false;
for (Map map : holdInfos) {
String holdCold = MapUtils.getString(map, "reasonCode", StringUtils.EMPTY);
if (sortJobForm.isSortHoldCode(holdCold)) {
holdCodeFlag = true;
break;
}
}
Assert.isFalse(!holdCodeFlag, Errors.create().key(MessageIdList.HOLD_CODE_NOT_FOUND).build());
}
//3、是否存在未执行的Sort任务
if (sortJobForm.isRcType()) {
//SRC的类型不用检查源晶舟是否已经存在SortJob了
checkWaitJobs(-1, sortJobForm.getTargetCarrierRrn(), sortJobForm.getTargetCarrierRrn2(), null);
} else {
checkWaitJobs(sortJobForm.getSourceCarrierRrn(), sortJobForm.getTargetCarrierRrn(),
sortJobForm.getTargetCarrierRrn2(), null);
}
return sourceLot;
}
private SortJobBean buildAutoMonitorSortInfo(Carrier sourceCarrier, Carrier targetCarrier,
SortJobForm sortJobForm) {
if (targetCarrier != null && targetCarrier.isNotEmpty()) {
sorterService.checkCarrierStatus(targetCarrier);
}
// 检查目标晶舟是否是空的
Assert.state(carrierIsEmpty(sortJobForm.getTargetCarrierRrn()),
Errors.create().key(MessageIdList.TARGET_BE_USED).build());
checkWaitJobs(sortJobForm.getSourceCarrierRrn(), sortJobForm.getTargetCarrierRrn(),
sortJobForm.getTargetCarrierRrn2(), null);
List<MonitorCarrierMapping> carrierMappings = lotAutoMonitorInqService.getMonitorCarrierMappings(
targetCarrier.getInstanceRrn());
List<SorterDetailBean> targetUnitList = new ArrayList<>();
for (MonitorCarrierMapping carrierMapping : carrierMappings) {
targetUnitList.add(new SorterDetailBean(carrierMapping.getLotRrn(), carrierMapping.getLotId(),
carrierMapping.getUnitRrn(), carrierMapping.getUnitId(),
carrierMapping.getSourcePosition(), carrierMapping.getPosition()));
}
SorterBean sorterBean = buildSorterBean(SorterEnum.Constant.CREATE, SorterEnum.Constant.AUTO_MONITOR,
sourceCarrier, targetCarrier, targetUnitList);
SortJobBean sortJobBean = new SortJobBean();
sortJobBean.setSorterBeans(sorterBean);
return sortJobBean;
}
private Map<String, Object> buildUnitMapByAutoMonitor(long position, String unitId, Long unitRrn, String lotId) {
Map<String, Object> unitMap = new HashMap<>();
unitMap.put("position", position);
unitMap.put("unitId", unitId);
unitMap.put("unitRrn", unitRrn);
unitMap.put("lotId", lotId);
unitMap.put("chooseFlag", "");
return unitMap;
}
private Map ajaxReturn(String message, Collection data) {
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("message", message);
resultMap.put("data", data);
return resultMap;
}
private SortJobBean buildMergeSortJob(Carrier sourceCarrier, Carrier targetCarrier, SortJobForm sortJobForm) {
long facilityRrn = LocalContext.getFacilityRrn();
List<SorterDetailBean> sourceUnitList = parseSorterDetailBeanList(sortJobForm.getSourceListValues());
List<SorterDetailBean> targetUnitList = parseSorterDetailBeanList(sortJobForm.getTargetListValues());
Assert.isFalse(targetUnitList.isEmpty(),
Errors.create().key(MessageIdList.TARGET_CARRIER_HAVE_NO_WAFER).build());
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(sourceCarrier.getObjectSubtype()),
Errors.create().key(MessageIdList.SOURCE_CAN_NOT_DUMMY).build());
if (targetCarrier != null) {
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(targetCarrier.getObjectSubtype()),
Errors.create().key(MessageIdList.TARGET_CAN_NOT_DUMMY).build());
// sorterService.checkCarrierStatus(targetCarrier);
}
Assert.isFalse(StringUtils.isBlank(sortJobForm.getTargetCarrierId()),
Errors.create().key(MessageIdList.TARGET_ID_CAN_NOT_EMPTY).build());
Assert.isFalse(sourceUnitList.size() > 0, Errors.create().key(MessageIdList.MERGE_NEED_ALL).build());
// 检查批次是否可以合批(合批规则) 数字小的批次为母批
Lot childLot = getLotByCarrierId(sortJobForm.getSourceCarrierId());
Lot parentLot = getLotByCarrierId(sortJobForm.getTargetCarrierId());
// 检查合批规则
lotService.canMergeLotCheck(childLot.getLotId(), parentLot.getLotId());
//新增加的一系列列其他业务的卡控
//卡控post future hold被hold住的lot
this.checkPostFutureHold(parentLot.getLotRrn());
wipQueryService.checkActiveInlineOcapId(parentLot.getLotRrn());
this.checkChildLotStatusForMerge(childLot);
//child lot和lot必须都bond或都未bond才允许合批
this.checkBond(parentLot, childLot);
//check contamination level
this.checkContaminationLevel(parentLot, childLot);
//check Flip
this.checkFlip4ChildAndParentLot(parentLot, childLot);
checkSourceAndTargetInfo(sortJobForm);
//根据源晶舟中的子批的晶圆,来组装sourcePosition和targetPosition
List<Map> childLotUnitList = wipQueryService.getUnitListByCarrier(sourceCarrier.getInstanceRrn());
List<SorterDetailBean> exchangeUnitList = buildMergeUnitList(parseSorterDetailBeanList(childLotUnitList),
targetUnitList);
//Runcard的merge卡控
List<Map> masterLotRunCardCreatedTimeList = lotRunCardQueryService.getSumbitAndActiveRunCardCreateTime(
parentLot.getLotRrn());
List sourceListValues = wipQueryService.getUnitListByLot(parentLot.getLotRrn());
Map item = new HashMap();
item.put("units", childLotUnitList);
item.put("childLotId", childLot.getLotId());
this.sourceAndChidUnits(sourceListValues, item, masterLotRunCardCreatedTimeList);
// 判断是否可以合批
this.checkMergeAvailable(parentLot, childLot);
this.checkLotStepForMerge(parentLot, childLot);
// check product version
checkProductVersionForMerge(parentLot, childLot);
// check process version
checkProcessVersionForMerge(parentLot, childLot);
List childLots = new ArrayList();
Map childLotMap = new HashMap();
childLotMap.put("childLotId", childLot.getLotId());
childLots.add(childLotMap);
childLotsBeforeIntoServiceCheck(childLots);
lotBeforeIntoServiceCheck(parentLot, "SO");
SorterBean sorterBean = buildSorterBean(SorterEnum.Constant.CREATE, SorterEnum.Constant.MERGE, sourceCarrier,
targetCarrier, exchangeUnitList);
sorterBean.setJsonAttributeData4(parentLot.getLotId());
SortJobBean sortJobBean = new SortJobBean();
sortJobBean.setSorterBeans(sorterBean);
return sortJobBean;
}
private List<SorterDetailBean> buildMergeUnitList(List<SorterDetailBean> sourceUnitList,
List<SorterDetailBean> targetUnitList) {
Map<String, Integer> positionMap = new HashMap<>();
for (SorterDetailBean sdb : targetUnitList) {
positionMap.put(sdb.getUnitId(), sdb.getTargetPosition());
}
for (SorterDetailBean sdb : sourceUnitList) {
sdb.setTargetPosition(positionMap.getOrDefault(sdb.getUnitId(), sdb.getSourcePosition()));
}
return sourceUnitList;
}
private SortJobBean buildSplitSortJob(Carrier sourceCarrier, Carrier targetCarrier, SortJobForm sortJobForm) {
List<SorterDetailBean> sourceUnitList = parseSorterDetailBeanList(sortJobForm.getSourceListValues());
List<SorterDetailBean> targetUnitList = parseSorterDetailBeanList(sortJobForm.getTargetListValues());
Assert.isFalse(targetUnitList.isEmpty(),
Errors.create().key(MessageIdList.TARGET_CARRIER_HAVE_NO_WAFER).build());
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(sourceCarrier.getObjectSubtype()),
Errors.create().key(MessageIdList.SOURCE_CAN_NOT_DUMMY).build());
if (targetCarrier != null && targetCarrier.isNotEmpty()) {
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(targetCarrier.getObjectSubtype()),
Errors.create().key(MessageIdList.TARGET_CAN_NOT_DUMMY).build());
sorterService.checkCarrierStatus(targetCarrier);
}
Assert.state(!lotAutoMonitorInqService.checkMonitorCarrierUsed(targetCarrier.getInstanceRrn()),
Errors.create().key(MessageIdList.AUTOMONITOR_CARRIER_INUSED).build());
Assert.isFalse(sourceUnitList.isEmpty(), Errors.create().key(MessageIdList.PARENT_LOT_LEAST_ONE).build());
// 检查目标晶舟是否是空的
Assert.isFalse(!carrierIsEmpty(sortJobForm.getTargetCarrierRrn()),
Errors.create().key(MessageIdList.TARGET_BE_USED).build());
Lot sourceLot = getLotByCarrierId(sourceCarrier.getInstanceId());
checkLotForSplit(sourceLot, "");
checkSourceAndTargetInfo(sortJobForm);
SorterBean sorterBean = buildSorterBean(SorterEnum.Constant.CREATE, SorterEnum.Constant.SPLIT, sourceCarrier,
targetCarrier, targetUnitList);
SortJobBean sortJobBean = new SortJobBean();
sortJobBean.setSorterBeans(sorterBean);
return sortJobBean;
}
private SortJobBean buildPilotSplitSortJob(Carrier sourceCarrier, Carrier targetCarrier, SortJobForm sortJobForm) {
List<SorterDetailBean> sourceUnitList = parseSorterDetailBeanList(sortJobForm.getSourceListValues());
List<SorterDetailBean> targetUnitList = parseSorterDetailBeanList(sortJobForm.getTargetListValues());
Assert.isFalse(targetUnitList.isEmpty(),
Errors.create().key(MessageIdList.TARGET_CARRIER_HAVE_NO_WAFER).build());
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(sourceCarrier.getObjectSubtype()),
Errors.create().key(MessageIdList.SOURCE_CAN_NOT_DUMMY).build());
if (targetCarrier != null && targetCarrier.isNotEmpty()) {
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(targetCarrier.getObjectSubtype()),
Errors.create().key(MessageIdList.TARGET_CAN_NOT_DUMMY).build());
sorterService.checkCarrierStatus(targetCarrier);
}
Assert.isFalse(sourceUnitList.isEmpty(), Errors.create().key(MessageIdList.PARENT_LOT_LEAST_ONE).build());
// 检查目标晶舟是否是空的
Assert.isFalse(!carrierIsEmpty(sortJobForm.getTargetCarrierRrn()),
Errors.create().key(MessageIdList.TARGET_BE_USED).build());
Lot sourceLot = getLotByCarrierId(sourceCarrier.getInstanceId());
// 永久分批flag初始化提示
Assert.isFalse((sourceLot == null) || (sourceLot.getLotRrn() <= 0),
Errors.create().key(MessageIdList.SCRAPLOT_LOTID_ERROR).content("Lot id not find!").build());
// Bonding临时分批卡控
Assert.isFalse(isSapphireLot(sourceLot) && LocationNames.TEMPORARY.equalsIgnoreCase(""),
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(sourceLot.getLotStatus()),
Errors.create().key(MessageIdList.LOT_MUST_W_H).build());
Assert.isFalse(diffBatchQueryService.checkLotInBatch(sourceLot.getLotRrn()),
Errors.create().key(MessageIdList.LOT_IN_BATCH).content("Lot in batch!").build());
wipQueryService.checkActiveInlineOcapId(sourceLot.getLotRrn());
checkSourceAndTargetInfo(sortJobForm);
SorterBean sorterBean = buildSorterBean(SorterEnum.Constant.CREATE, SorterEnum.Constant.PILOT_SPLIT,
sourceCarrier, targetCarrier, targetUnitList);
SortJobBean sortJobBean = new SortJobBean();
sortJobBean.setSorterBeans(sorterBean);
return sortJobBean;
}
/**
* 组装 交换晶舟 的SortJob
*
* @param sourceCarrier 源晶舟
* @param targetCarrier 目标晶舟
* @param sortJobForm SortJobForm
* @return SortJobBean
*/
private SortJobBean buildExchangeSortJob(Carrier sourceCarrier, Carrier targetCarrier, SortJobForm sortJobForm) {
List<SorterDetailBean> sourceUnitList = parseSorterDetailBeanList(sortJobForm.getSourceListValues());
Assert.isFalse(!sourceUnitList.isEmpty(),
Errors.create().key(MessageIdList.SOURCE_CARRIER_HAVE_NO_WAFER).build());
List<SorterDetailBean> targetUnitList = parseSorterDetailBeanList(sortJobForm.getTargetListValues());
Assert.isFalse(targetUnitList.isEmpty(),
Errors.create().key(MessageIdList.TARGET_CARRIER_HAVE_NO_WAFER).build());
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(sourceCarrier.getObjectSubtype()),
Errors.create().key(MessageIdList.SOURCE_CAN_NOT_DUMMY).build());
if (targetCarrier != null && targetCarrier.isNotEmpty()) {
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(targetCarrier.getObjectSubtype()),
Errors.create().key(MessageIdList.TARGET_CAN_NOT_DUMMY).build());
sorterService.checkCarrierStatus(targetCarrier);
}
Assert.state(!lotAutoMonitorInqService.checkMonitorCarrierUsed(targetCarrier.getInstanceRrn()),
Errors.create().key(MessageIdList.AUTOMONITOR_CARRIER_INUSED).build());
Assert.isFalse(sourceUnitList.size() > 0, Errors.create().key(MessageIdList.EXCHANGE_NEED_ALL).build());
// 检查目标晶舟是否是空的
Assert.isFalse(!carrierIsEmpty(sortJobForm.getTargetCarrierRrn()),
Errors.create().key(MessageIdList.TARGET_BE_USED).build());
checkSourceAndTargetInfo(sortJobForm);
SorterBean sorterBean = buildSorterBean(SorterEnum.Constant.CREATE, SorterEnum.Constant.EXCHANGE, sourceCarrier,
targetCarrier, targetUnitList);
SortJobBean sortJobBean = new SortJobBean();
sortJobBean.setSorterBeans(sorterBean);
return sortJobBean;
}
/**
* 组装 多Port的交换晶舟 的SortJob
*
* @param sourceCarrier 源晶舟
* @param targetCarrier 目标晶舟
* @param targetCarrier2 第二个目标晶舟
* @param sortJobForm SortJobForm
* @return SortJobBean
*/
private SortJobBean buildExchange2PortSortJob(Carrier sourceCarrier, Carrier targetCarrier, Carrier targetCarrier2,
SortJobForm sortJobForm) {
//targetCarrier的rrn=0 并且 targetCarrier2==null 表示多Port且都不指定。targetCarrier的rrn>0 并且 targetCarrier2!=null
// 表示多Port且都指定。
Assert.isFalse((targetCarrier.getInstanceRrn() <= 0 && targetCarrier2 != null) ||
(targetCarrier.getInstanceRrn() > 0 && targetCarrier2 == null),
Errors.create().key(MessageIdList.MORE_PORT_NEED_SAME).build());
List<SorterDetailBean> sourceUnitList = parseSorterDetailBeanList(sortJobForm.getSourceListValues());
Assert.isFalse(!sourceUnitList.isEmpty(),
Errors.create().key(MessageIdList.SOURCE_CARRIER_HAVE_NO_WAFER).build());
List<SorterDetailBean> targetUnitList = parseSorterDetailBeanList(sortJobForm.getTargetListValues());
Assert.isFalse(targetUnitList.isEmpty(),
Errors.create().key(MessageIdList.TARGET_CARRIER_HAVE_NO_WAFER).build());
// List<SorterDetailBean> targetUnitList2 = parseSorterDetailBeanList(sortJobForm.getTargetListValues2());
// Assert.isFalse(targetUnitList2.isEmpty(), Errors.create().key(MessageIdList.TARGET_CARRIER_HAVE_NO_WAFER)
// .build());
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(sourceCarrier.getObjectSubtype()),
Errors.create().key(MessageIdList.SOURCE_CAN_NOT_DUMMY).build());
if (targetCarrier != null && targetCarrier.isNotEmpty()) {
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(targetCarrier.getObjectSubtype()),
Errors.create().key(MessageIdList.TARGET_CAN_NOT_DUMMY).build());
// sorterService.checkCarrierStatus(targetCarrier);
}
if (targetCarrier2 != null && targetCarrier2.isNotEmpty()) {
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(targetCarrier2.getObjectSubtype()),
Errors.create().key(MessageIdList.TARGET_CAN_NOT_DUMMY).build());
sorterService.checkCarrierStatus(targetCarrier2);
}
Assert.isFalse(sourceUnitList.size() > 0, Errors.create().key(MessageIdList.EXCHANGE_NEED_ALL).build());
// 检查目标晶舟是否是空的
Assert.isFalse(!carrierIsEmpty(sortJobForm.getTargetCarrierRrn()),
Errors.create().key(MessageIdList.TARGET_BE_USED).build());
Assert.isFalse(!carrierIsEmpty(sortJobForm.getTargetCarrierRrn2()),
Errors.create().key(MessageIdList.TARGET_BE_USED).build());
//TODO check
if (targetCarrier2 == null) {
sortJobForm.setTargetCarrierRrn2(0L);
}
checkSourceAndTargetInfo(sortJobForm);
SorterBean sorterBean = buildSorterBean(SorterEnum.Constant.CREATE, SorterEnum.Constant.NORMAL_EXCHANGE,
sourceCarrier, targetCarrier, targetUnitList);
// SorterBean sorterBean2 = buildSorterBean(SorterEnum.Constant.CREATE, SorterEnum.Constant.NORMAL_EXCHANGE,
// sourceCarrier, targetCarrier2, targetUnitList2);
SortJobBean sortJobBean = new SortJobBean();
// sortJobBean.setSorterBeans(sorterBean, sorterBean2);
return sortJobBean;
}
private SortJobBean buildRunCardSplitSortJob(Carrier sourceCarrier, Carrier targetCarrier,
SortJobForm sortJobForm) {
long facilityRrn = LocalContext.getFacilityRrn();
String realCarrierRrnOfSRC = null;
String splitSeq;
Lot sourceLot = getLotByCarrierId(sourceCarrier.getInstanceId());
if (StringUtils.equalsIgnoreCase(sourceLot.getLotStatus(), LotStatus.RUNCARD_HOLD)) {
sourceLot = lotQueryService.getLot(sourceLot.getLotId() + RunCardConstants.MAINLOT_ID_IN_MES, facilityRrn);
realCarrierRrnOfSRC =
sourceLot.getCarrierRrn() != null ? sourceLot.getCarrierRrn().toString() : StringUtils.EMPTY;
}
LotRunCardStore sourceRunCardStore = lotRunCardQueryService.getSplitRunCardLotStore(sourceLot.getLotRrn());
Assert.isFalse(!(StringUtils.equalsIgnoreCase(RunCardStoreSubStatus.BANKIN.toString(),
sourceRunCardStore.getSubStatus()) &&
StringUtils.equalsIgnoreCase(LotStatus.RUNCARD_WAITSPLIT, sourceLot.getLotStatus())),
Errors.create().key(MessageIdList.SOURCE_LOT_NOT_WAIT_SPIT).build());
Assert.isFalse(!carrierIsEmpty(sortJobForm.getTargetCarrierRrn()),
Errors.create().key(MessageIdList.TARGET_IS_IN_USE).build());
splitSeq = sourceRunCardStore.getSplitSeq() != null ? sourceRunCardStore.getSplitSeq()
.toString() : sortJobForm.getSplitSeq()
.toString();
List<SorterDetailBean> sourceUnitList = parseSorterDetailBeanList(sortJobForm.getSourceListValues());
Assert.isFalse(sourceUnitList.isEmpty(), Errors.create().key(MessageIdList.PARENT_LOT_LEAST_ONE).build());
List<SorterDetailBean> targetUnitList = parseSorterDetailBeanList(sortJobForm.getTargetListValues());
Assert.isFalse(targetUnitList.isEmpty(),
Errors.create().key(MessageIdList.TARGET_CARRIER_HAVE_NO_WAFER).build());
if (targetCarrier != null && targetCarrier.isNotEmpty()) {
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(targetCarrier.getObjectSubtype()),
Errors.create().key(MessageIdList.TARGET_CAN_NOT_DUMMY).build());
sorterService.checkCarrierStatus(targetCarrier);
Assert.state(!lotAutoMonitorInqService.checkMonitorCarrierUsed(targetCarrier.getInstanceRrn()),
Errors.create().key(MessageIdList.AUTOMONITOR_CARRIER_INUSED).build());
}
Assert.isFalse(sourceUnitList.isEmpty(), Errors.create().key(MessageIdList.PARENT_LOT_LEAST_ONE).build());
// 检查目标晶舟是否是空的
Assert.isFalse(!carrierIsEmpty(sortJobForm.getTargetCarrierRrn()),
Errors.create().key(MessageIdList.TARGET_BE_USED).build());
checkSourceAndTargetInfo(sortJobForm);
SorterBean sorterBean = buildSorterBean(SorterEnum.Constant.CREATE, SorterEnum.Constant.SRC_SPLIT,
sourceCarrier, targetCarrier, targetUnitList);
sorterBean.setJsonAttributeData1(realCarrierRrnOfSRC); //realCarrierRrnOfSRC 放在备用字段一
sorterBean.setJsonAttributeData2(splitSeq); //splitSeq 放在备用字段二
SortJobBean sortJobBean = new SortJobBean();
sortJobBean.setSorterBeans(sorterBean);
return sortJobBean;
}
private SortJobBean buildRunCardMergeSortJob(Carrier sourceCarrier, Carrier targetCarrier,
SortJobForm sortJobForm) {
long facilityRrn = LocalContext.getFacilityRrn();
Lot sourceLot = getLotByCarrierId(sourceCarrier.getInstanceId());
//先检查是不是RC的批次
Assert.isFalse(!lotRunCardQueryService.checkLotInRunCard(sourceLot.getLotRrn()),
Errors.create().key(MessageIdList.NOT_RC_LOT).content("{} is not a RunCard Lot!")
.args(sourceLot.getLotId()).build());
if (LotStatus.isRunCardHold(sourceLot.getLotStatus())) {
sourceLot = lotQueryService.getLot(RunCardUtils.buildMainRcLotId(sourceLot.getLotId()));
}
Lot targetLot = getLotByCarrierId(targetCarrier.getInstanceId());
//先检查是不是RC的批次
Assert.isFalse(!lotRunCardQueryService.checkLotInRunCard(targetLot.getLotRrn()),
Errors.create().key(MessageIdList.NOT_RC_LOT).content("{} is not a RunCard Lot!")
.args(targetLot.getLotId()).build());
if (LotStatus.isRunCardHold(targetLot.getLotStatus())) {
targetLot = lotQueryService.getLot(RunCardUtils.buildMainRcLotId(targetLot.getLotId()));
}
List<SorterDetailBean> sourceUnitList = parseSorterDetailBeanList(sortJobForm.getSourceListValues());
List<SorterDetailBean> targetUnitList = parseSorterDetailBeanList(sortJobForm.getTargetListValues());
Assert.isFalse(!LotStatus.RUNCARD_FINISH.equals(targetLot.getLotStatus()),
Errors.create().content("Lot status must be WAITMERGE!").key(MessageIdList.LOT_MUST_WAIT_MERGE)
.build());
Assert.isFalse(targetUnitList.isEmpty(), Errors.create().key(MessageIdList.TARGET_CARRIER_NO_WAFER).build());
Assert.isFalse(sourceUnitList.size() > 0, Errors.create().key(MessageIdList.SELECT_SOURCE_ALL_WAFER)
.content("Please select all source wafer!").key("").build());
String[] lotIdArr = buildChildAndParentLotId4RunCard(sourceLot.getLotRrn(), sourceLot.getLotId());
String childLotId = lotIdArr[0];
String parentLotId = lotIdArr[1];
Assert.isFalse(!StringUtils.equalsIgnoreCase(sourceLot.getLotId(), childLotId),
Errors.create().key(MessageIdList.PARENT_IN_TARGET).content(
"The carrier where the parent Lot is located should be placed at the position of" +
" the Target Carrier!").build());
Assert.isFalse(!LotStatus.RUNCARD_FINISH.equals(sourceLot.getLotStatus()),
Errors.create().content("Lot status must be WAITMERGE!").key(MessageIdList.LOT_MUST_WAIT_MERGE)
.build());
//SRC的Merge需要母批放在Target的位置上,所以不需要check Target的SortJob,因为可能会存在多个
checkWaitJobs(sourceCarrier.getInstanceRrn(), 0L, 0L, null);
Map<String, Object> childLotMap = lotRunCardQueryService.getRCLotInfoMap(childLotId);
Map<String, Object> parentLotMap = lotRunCardQueryService.getRCLotInfoMap(parentLotId);
//check flip type
String childFlipType = MapUtils.getString(childLotMap, "flipType");
String parentFlipType = MapUtils.getString(parentLotMap, "flipType");
this.checkFlip4ChildAndParentLot(parentFlipType, childFlipType);
this.checkQTime(targetLot.getLotRrn(), sourceLot.getLotRrn());
//根据源晶舟中的子批的晶圆,来组装sourcePosition和targetPosition
List<Map> childLotUnitList = wipQueryService.getUnitListByCarrier(sourceCarrier.getInstanceRrn());
List<SorterDetailBean> exchangeUnitList = buildMergeUnitList(parseSorterDetailBeanList(childLotUnitList),
targetUnitList);
SorterBean sorterBean = buildSorterBean(SorterEnum.Constant.CREATE, SorterEnum.Constant.SRC_MERGE,
sourceCarrier, targetCarrier, exchangeUnitList);
sorterBean.setJsonAttributeData1(MapUtils.getString(parentLotMap, "lotId"));
sorterBean.setJsonAttributeData2(MapUtils.getString(parentLotMap, "lotRrn"));
SortJobBean sortJobBean = new SortJobBean();
sortJobBean.setSorterBeans(sorterBean);
return sortJobBean;
}
private SortJobBean buildSplitMorePortSortJob(Carrier sourceCarrier, Carrier targetCarrier, Carrier targetCarrier2,
SortJobForm sortJobForm) {
long facilityRrn = LocalContext.getFacilityRrn();
//targetCarrier的rrn=0 并且 targetCarrier2==null 表示多Port且都不指定。targetCarrier的rrn>0 并且 targetCarrier2!=null
// 表示多Port且都指定。
Assert.isFalse((targetCarrier.getInstanceRrn() <= 0 && targetCarrier2 != null) ||
(targetCarrier.getInstanceRrn() > 0 && targetCarrier2 == null),
Errors.create().key(MessageIdList.MORE_PORT_NEED_SAME).build());
List<SorterDetailBean> sourceUnitList = parseSorterDetailBeanList(sortJobForm.getSourceListValues());
Assert.isFalse(sourceUnitList.isEmpty(), Errors.create().key(MessageIdList.PARENT_LOT_LEAST_ONE).build());
List<SorterDetailBean> targetUnitList = parseSorterDetailBeanList(sortJobForm.getTargetListValues());
Assert.isFalse(targetUnitList.isEmpty(),
Errors.create().key(MessageIdList.TARGET_CARRIER_HAVE_NO_WAFER).build());
//TargetCarrier2的晶圆来自于源晶舟中剩余的晶圆
List<SorterDetailBean> targetUnitList2 = recombinateTargetUnitList2(sourceUnitList);
Assert.isFalse(targetUnitList.size() != 12,
Errors.create().key(MessageIdList.TARGET_CARRIER_NEED_1_TO_12).build());
if (StringUtils.equalsIgnoreCase(sortJobForm.getJobType(), SorterEnum.Constant.SPLIT_3PORT)) {
if (targetCarrier.isNotEmpty() && targetCarrier2 != null && targetCarrier2.isNotEmpty()) {
sorterQueryService.checkPort2CstForLoad(sourceCarrier, targetCarrier, targetCarrier2);
}
}
if (targetCarrier2 == null) {
sortJobForm.setTargetCarrierRrn2(0L);
}
checkSourceAndTargetInfo(sortJobForm);
SorterBean sorterBean = buildSorterBean(SorterEnum.Constant.CREATE, SorterEnum.Constant.SPLIT_3PORT,
sourceCarrier, targetCarrier, targetUnitList);
SorterBean sorterBean2 = buildSorterBean(SorterEnum.Constant.CREATE, SorterEnum.Constant.SPLIT_3PORT,
sourceCarrier, targetCarrier2, targetUnitList2);
SortJobBean sortJobBean = new SortJobBean();
sortJobBean.setSorterBeans(sorterBean, sorterBean2);
return sortJobBean;
}
/**
* 组装翻面的SorterJob
*
* @param sCarrier
* @param targetCarrier 预留翻面并交换
* @param sjf
* @return
*/
private SortJobBean buildFlipSideSortInfo(Carrier sCarrier, Carrier targetCarrier, SortJobForm sjf) {
//TODO
List<SorterDetailBean> sourceUnitList = parseSorterDetailBeanList(sjf.getSourceListValues());
Assert.isFalse(sourceUnitList.isEmpty(),
Errors.create().key(MessageIdList.SOURCE_CARRIER_HAVE_NO_WAFER).build());
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(sCarrier.getObjectSubtype()),
Errors.create().key(MessageIdList.SOURCE_CAN_NOT_DUMMY).build());
Lot sourceLot = checkSourceAndTargetInfo(sjf);
String flipType = sourceLot.getFlipType();
SorterBean sorterBean = buildSorterBean(SorterEnum.Constant.CREATE, SorterEnum.Constant.FLIP_SIDE, sCarrier,
sCarrier, sourceUnitList);
sorterBean.setJsonAttributeData3(flipType + "|" + SorterEnum.Constant.getOpposite(flipType));
SortJobBean sortJobBean = new SortJobBean();
sortJobBean.setSorterBeans(sorterBean);
return sortJobBean;
}
/**
* 组装check t7code 的SorterJob
*
* @param sCarrier
* @param sjf
* @return
*/
private SortJobBean buildCheckT7CodeSortInfo(Carrier sCarrier, SortJobForm sjf) {
List<SorterDetailBean> sourceUnitList = parseSorterDetailBeanList(sjf.getSourceListValues());
Assert.isFalse(sourceUnitList.isEmpty(),
Errors.create().key(MessageIdList.SOURCE_CARRIER_HAVE_NO_WAFER).build());
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(sCarrier.getObjectSubtype()),
Errors.create().key(MessageIdList.SOURCE_CAN_NOT_DUMMY).build());
checkSourceAndTargetInfo(sjf);
SorterBean sorterBean = buildSorterBean(SorterEnum.Constant.CREATE, SorterEnum.Constant.OFFLINE_CHECK_T7CODE, sCarrier,
sCarrier, sourceUnitList);
SortJobBean sortJobBean = new SortJobBean();
sortJobBean.setSorterBeans(sorterBean);
return sortJobBean;
}
/**
* 组装read Material Id 的SorterJob
*
* @param sCarrier
* @param sjf
* @return
*/
private SortJobBean buildReadMaterialIdSortInfo(Carrier sCarrier, SortJobForm sjf) {
List<SorterDetailBean> sourceUnitList = parseSorterDetailBeanList(sjf.getSourceListValues());
Assert.isFalse(sourceUnitList.isEmpty(),
Errors.create().key(MessageIdList.SOURCE_CARRIER_HAVE_NO_WAFER).build());
Assert.isFalse(SorterEnum.Constant.DUMMY.equals(sCarrier.getObjectSubtype()),
Errors.create().key(MessageIdList.SOURCE_CAN_NOT_DUMMY).build());
checkSourceAndTargetInfo(sjf);
SorterBean sorterBean = buildSorterBean(SorterEnum.Constant.CREATE, SorterEnum.Constant.OFFLINE_READ_MATERIALID, sCarrier,
sCarrier, sourceUnitList);
SortJobBean sortJobBean = new SortJobBean();
sortJobBean.setSorterBeans(sorterBean);
return sortJobBean;
}
private List<SorterDetailBean> recombinateTargetUnitList2(List<SorterDetailBean> sourceUnitList) {
if (CollectionUtils.isEmpty(sourceUnitList)) {
return new ArrayList<>();
}
List<SorterDetailBean> sortJobDetailList = new ArrayList<>();
SorterDetailBean[] arr = new SorterDetailBean[26];
for (SorterDetailBean sdb : sourceUnitList) {
arr[sdb.getSourcePosition()] = sdb;
}
int position = 1;
for (SorterDetailBean sdb : arr) {
if (sdb != null) {
sortJobDetailList.add(
new SorterDetailBean(sdb.getLotRrn(), sdb.getLotId(), sdb.getUnitRrn(), sdb.getUnitId(),
sdb.getSourcePosition(), position++));
}
}
return sortJobDetailList;
}
private SorterBean buildSorterBean(String jobStatus, String jobType, Carrier sourceCarrier, Carrier targetCarrier,
List<SorterDetailBean> unitList) {
SorterBean sorterBean = new SorterBean();
sorterBean.setSourceCarrierId(sourceCarrier.getInstanceId());
sorterBean.setSourceCarrierRrn(sourceCarrier.getInstanceRrn());
sorterBean.setSourceCarrierMapRrn(sourceCarrier.getCarrierMapRrn());
sorterBean.setTargetCarrierId(targetCarrier == null ? StringUtils.EMPTY : targetCarrier.getInstanceId());
sorterBean.setTargetCarrierRrn(targetCarrier == null ? NumberUtils.LONG_ZERO : targetCarrier.getInstanceRrn());
sorterBean.setTargetCarrierMapRrn(targetCarrier==null?NumberUtils.LONG_ZERO:targetCarrier.getCarrierMapRrn());
sorterBean.setStatus(jobStatus);
sorterBean.setJobType(jobType);
sorterBean.setCreateUser(LocalContext.getUserId());
sorterBean.setExchangeTotalQty(unitList.size());
sorterBean.setSorterDetailBeanList(unitList);
sorterBean.setJsonAttributeData5(StringUtils.EMPTY + sourceCarrier.getCarrierMapRrn());
return sorterBean;
}
private List<UnitBean> parseUnitListAbsenceEmptySlot(String jsonStr) {
List<UnitBean> unitList = new ArrayList<>();
List list = JsonUtils.toObject(jsonStr, List.class);
for (Map<String, Object> unitMap : (List<Map<String, Object>>) list) {
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)) {
unitList.add(new UnitBean(lotRrn, lotId, unitRrn, unitId, position, position));
}
}
return unitList;
}
private String buildCarrierList(String carrierList, long lotRrn) {
List<Map> list = JsonUtils.toObject(carrierList, List.class);
List<Map> resultList = new ArrayList<>();
for (Map map : list) {
Map resultMap = new HashMap();
String lotId = MapUtils.getString(map, "lotid");
resultMap.put("unitId", MapUtils.getString(map, "unitId"));
resultMap.put("unitRrn", MapUtils.getString(map, "unitRrn"));
resultMap.put("position", MapUtils.getString(map, "position"));
if (StringUtils.isNotEmpty(lotId)) {
resultMap.put("lotId", lotId);
resultMap.put("lotRrn", lotRrn);
resultMap.put("chooseFlag", "true");
} else {
resultMap.put("lotRrn", "");
resultMap.put("chooseFlag", "");
resultMap.put("lotId", "");
}
resultList.add(resultMap);
}
return JsonUtils.toString(resultList);
}
}