MergeLotAction.java

package com.mycim.webapp.actions.lot.merge;

import com.fa.sesa.exception.Assert;
import com.fa.sesa.exception.Errors;
import com.fa.sesa.threadlocal.LocalContext;
import com.mycim.framework.utils.MiscUtils;
import com.mycim.framework.utils.beans.BeanUtils;
import com.mycim.framework.utils.beans.PropertyUtils;
import com.mycim.framework.utils.lang.StringUtils;
import com.mycim.framework.utils.lang.collections.CollectionUtils;
import com.mycim.framework.utils.lang.collections.MapUtils;
import com.mycim.framework.utils.lang.math.NumberUtils;
import com.mycim.framework.utils.msg.JsonUtils;
import com.mycim.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.consts.ContextNames;
import com.mycim.valueobject.consts.SessionNames;
import com.mycim.valueobject.ems.Carrier;
import com.mycim.valueobject.wip.*;
import com.mycim.webapp.Constants;
import com.mycim.webapp.WebUtils;
import com.mycim.webapp.actions.lot.ManualAndSortCheckAction;
import com.mycim.webapp.forms.lot.LotInfoForm;
import com.mycim.webapp.forms.lot.SplitMergeInfoForm;
import org.apache.commons.compress.utils.Sets;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

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

/**
 * @author shijie.deng
 * @version 6.0.0
 * @date 2019/10/6
 **/
public class MergeLotAction extends ManualAndSortCheckAction {

    @Override
    public ActionForward init(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                              HttpServletResponse response) throws Exception {
        SplitMergeInfoForm theform = (SplitMergeInfoForm) form;

        if (StringUtils.isNotBlank((String) request.getAttribute("target"))) {
            theform.setCacheTarget((String) request.getAttribute("target"));
        }

        theform.setPages(1);

        // reset increment element

        Lot lot = initLotBaseInfoForJsp(request, true, null, null);

        /*if (!lot.getLotStatus().equalsIgnoreCase(LotStatus.HOLD)) {
            throw new WebException("lot.merge_not_hold", "lot status must be hold!");
        }*/

        //卡控post future hold被hold住的lot
        checkPostFutureHold(lot.getLotRrn());

        super.checkCstRemoved(Sets.newHashSet(lot.getLotRrn()));

        Assert.isTrue(LotStatus.isWaitingOrHold(lot.getLotStatus()),
                      Errors.create().content("This lot status must be in " + "WAITING、HOLD !").build());
        if (this.isTrackUnitFlag(lot)) {
            lot.setTrackUnitFlag(TRUE);
        } else {
            lot.setTrackUnitFlag(FALSE);
        } // end of if
        LotInfoForm lotInfoForm = new LotInfoForm();
        PropertyUtils.copyProperties(lotInfoForm, lot);
        Map conditionMap = BeanUtils.copyBeanToMap(lot);
        lotInfoForm.setRecipePhysicalId(getRecipePhysicalId(lot));
        Assert.isFalse(lot.getQty1() == null, Errors.create().content("This Lot's qty1 is null").build());
        wipQueryService.checkActiveInlineOcapId(lot.getLotRrn());

        //check sortJob
        checkWaitJobs(lot.getCarrierRrn(), 0L, 0L, null);

        theform.setSourceListValues(parseToJsonString(wipQueryService.getUnitListByLot(lot.getLotRrn())));

        Collection collection = parseToSimplifyCollection(theform.getSourceListValues());
        request.setAttribute(SessionNames.COLLECTION2_KEY, collection);
        theform.setCacheCollection2(WebUtils.getCacheObj2String(collection));

        lotInfoForm.setRemainQty(lot.getQty1());

        theform.setLotInfoForm(lotInfoForm);
        theform.setLotId(null);

        Carrier parentCarrier = carrierService.getCarrier(lot.getCarrierRrn());
        request.setAttribute("parentCSTslotCount", parentCarrier.getSlotCount());
        Boolean canDropTarget = parentCarrier.getSlotCount() == 13;// cst13 的晶周可以拖动
        request.setAttribute("canDropTarget", canDropTarget);

        theform.setTransId(Constants.MODIFY_KEY);

        List childLotView = buildChildLotMap(lotQueryService.getChildLotsForMerge(lot));

        request.setAttribute(SessionNames.LOT_KEY, lot);
        request.setAttribute(SessionNames.COLLECTION_KEY, childLotView);
        request.setAttribute(SessionNames.LOT_INFO_FORM_KEY, lotInfoForm);
        theform.setCacheLotInfo(WebUtils.getCacheObj2String(lotInfoForm));
        theform.setCacheLot(WebUtils.getCacheObj2String(lot));
        theform.setCacheChildLots(WebUtils.getCacheObj2String(new ArrayList()));
        theform.setCacheChildLotsView(WebUtils.getCacheObj2String(childLotView));
        return mapping.findForward(Constants.INIT_KEY);
    }

    public ActionForward addChildLot(ActionMapping mapping, SplitMergeInfoForm theform, HttpServletRequest request) {
        long facilityRrn = LocalContext.getFacilityRrn();
        LotInfoForm lotInfoForm = (LotInfoForm) WebUtils.getCacheString2Obj(theform.getCacheLotInfo());
        List childLots = (List) WebUtils.getCacheString2Obj(theform.getCacheChildLots());
        List childLotsView = (List) WebUtils.getCacheString2Obj(theform.getCacheChildLotsView());
        Lot lot = (Lot) WebUtils.getCacheString2Obj(theform.getCacheLot());
        initLotBaseInfoForJsp(request, true, null, null);
        Carrier parentCarrier = carrierService.getCarrier(lot.getCarrierRrn());
        request.setAttribute("parentCSTslotCount", parentCarrier.getSlotCount());
        Boolean canDropTarget = parentCarrier.getSlotCount() == 13;// cst13 的晶周可以拖动
        request.setAttribute("canDropTarget", canDropTarget);
        List buildChildLots = new ArrayList();
        Boolean confirmFlag = WebUtils.getParameterBoolean("confirmFlag", request);

        // check if valid lot selected
        Assert.isFalse((theform.getChildLotId() == null) || theform.getChildLotId().equalsIgnoreCase(""),
                       Errors.create().key(MessageIdList.LOT_LOTID_OR_CASSETTEID_EMPTY)
                             .content("Lot Id and Cassette Id can't be Empty!").build());

        Assert.isFalse(theform.getChildLotId().equals(lot.getLotId()),
                       Errors.create().content("Please select different lot to merge!").build());


        Lot paLot = lotQueryService.getLot(lot.getLotId(), facilityRrn);
        theform.setChildLotId(StringUtils.trimToUpperCase(theform.getChildLotId()));
        Lot child_Lot = lotQueryService.getLot(theform.getChildLotId(), facilityRrn);
        Assert.isFalse(child_Lot.getLotRrn() <= 0, Errors.create().content("No such Lot!").build());
        //Check flip for childLot and parentLot
        this.checkFlip4ChildAndParentLot(paLot, child_Lot);

        //TODO :  merge lot really need it?
        //        String        qtimeErrorMsg = buidldQtimeErrorMsg(paLot, child_Lot);
        //        StringBuilder confirmMsg    = new StringBuilder();
        StringBuilder loopErrorMsg = new StringBuilder();
        //        this.buidldLoopErrorMsg(paLot, child_Lot, confirmMsg, loopErrorMsg);
        //        loopErrorMsg.append(qtimeErrorMsg);

        Assert.isFalse(loopErrorMsg.length() > 0, Errors.create().content(loopErrorMsg.toString()).build());

        Carrier childCarrier = carrierService.getCarrier(child_Lot.getCarrierRrn());

        Assert.isFalse(!StringUtils.equalsIgnoreCase(parentCarrier.getFlagType(), childCarrier.getFlagType()) ||
                               !StringUtils.equalsIgnoreCase(parentCarrier.getObjectSubtype(),
                                                             childCarrier.getObjectSubtype()),
                       Errors.create().content("Parent and child lot Cassette info not consistent!").build());

        //child lot若正被post future hold状态则无法合批
        checkPostFutureHold(child_Lot.getLotRrn());

        //child lot和lot必须都bond或都未bond才允许合批
        this.checkBond(lot, child_Lot);
        //check contamination level
        this.checkContaminationLevel(lot, child_Lot);

        HashMap item = null;

        for (Iterator it = childLots.iterator(); it.hasNext(); ) {
            item = (HashMap) it.next();

            Assert.isFalse(item.get("childLotId").equals(theform.getChildLotId()),
                           Errors.create().content("Please Select different lot to merge!").build());
        }

        // 判断是否可以合批
        checkMergeAvailable(paLot, child_Lot);

        HashMap childLot = getLotInfo(theform, lot);
        theform.setChildLotId(StringUtils.EMPTY);

        lotInfoForm.setMergedQty(MiscUtils.parseSQL(lotInfoForm.getMergedQty()) + MiscUtils.parseSQL((Double) childLot.get("qty1")));
        lotInfoForm.setMergedQty2(MiscUtils.parseSQL(lotInfoForm.getMergedQty2()) + MiscUtils.parseSQL((Double) childLot.get("qty2")));
        theform.setLotInfoForm(lotInfoForm);
        buildChildLots.add(childLot);
        childLots.add(childLot);

        buildChildLotMap(childLotsView, child_Lot, true);

        this.rebuildTheFormSourceList(theform, lot, buildChildLots,
                                      (List) WebUtils.getCacheString2Obj(theform.getCacheCollection2()), parentCarrier);
        request.setAttribute(SessionNames.LOT_KEY, lot);
        request.setAttribute(SessionNames.COLLECTION_KEY, childLotsView);
        request.setAttribute(SessionNames.LOT_INFO_FORM_KEY, lotInfoForm);
        theform.setCacheChildLots(WebUtils.getCacheObj2String(childLots));
        theform.setCacheChildLotsView(WebUtils.getCacheObj2String(childLotsView));
        theform.setCacheLotInfo(WebUtils.getCacheObj2String(lotInfoForm));
        theform.setCacheLot(WebUtils.getCacheObj2String(lot));
        return mapping.findForward(Constants.INIT_KEY);

    }


    public Map checkFutureHold(Map map) {
        Map result = new HashMap();
        String lotId = MapUtils.getString(map, "lotId");
        /**
         * 是否有futureHold
         */
        Lot lot = lotQueryService.getLot(lotId, LocalContext.getFacilityRrn());
        long refRrn = getInstanceRrn(ContextNames.EEN_CONTEXT_HOLDLOT,
                                     getNamedSpace(ObjectList.CONTEXT_KEY, LocalContext.getFacilityRrn()),
                                     ObjectList.CONTEXT_KEY);
        List<Map> futureHoldInfoByLot = ctxExecService.getFutureHoldListByLot(refRrn, lot.getLotRrn());
        refRrn = getInstanceRrn(ContextNames.EEN_CONTEXT_HOLDPRODUCT, LocalContext.getFacilityRrn(),
                                ObjectList.CONTEXT_KEY);
        List<Map> futureHoldInfoByProduct = ctxExecService
                .getFutureHoldListByProduct(refRrn, lot.getProductRrn(), lot.getProcessRrn(), lot.getLotRrn());
        if (futureHoldInfoByLot != null && futureHoldInfoByLot.size() > 0) {
            result.put("futureHoldInfoByLot", futureHoldInfoByLot);
        }
        if (futureHoldInfoByProduct != null && futureHoldInfoByProduct.size() > 0) {
            result.put("futureHoldInfoByProduct", futureHoldInfoByProduct);
        }

        return result;
    }

    public ActionForward delChildLot(ActionMapping mapping, SplitMergeInfoForm theform, HttpServletRequest request) {

        initLotBaseInfoForJsp(request, true, null, null);
        LotInfoForm lotInfoForm = (LotInfoForm) WebUtils.getCacheString2Obj(theform.getCacheLotInfo());
        List childLots = (List) WebUtils.getCacheString2Obj(theform.getCacheChildLots());
        List childLotsView = (List) WebUtils.getCacheString2Obj(theform.getCacheChildLotsView());
        Lot lot = (Lot) WebUtils.getCacheString2Obj(theform.getCacheLot());
        Iterator it = childLots.iterator();
        String record = request.getParameter(Constants.ITEM_KEY);
        List source = JsonUtils.toObject(theform.getSourceListValues(), List.class);
        List buildSource = new ArrayList();
        while (it.hasNext()) {
            HashMap item = (HashMap) it.next();
            String childLotId = (String) item.get("childLotId");

            if (childLotId.equals(record)) {
                lotInfoForm.setMergedQty(new Double(MiscUtils.parseSQL(lotInfoForm.getMergedQty()) -
                                                            MiscUtils.parseSQL((Double) item.get("qty1"))));
                lotInfoForm.setMergedQty2(new Double(MiscUtils.parseSQL(lotInfoForm.getMergedQty2()) -
                                                             MiscUtils.parseSQL((Double) item.get("qty2"))));
                for (Iterator iterator = source.iterator(); iterator.hasNext(); ) {
                    boolean sourceB = true;
                    Map sourceMap = (Map) iterator.next();
                    String sourceUnitId = MapUtils.getString(sourceMap, "unitId");
                    List childUnits = (List) MapUtils.getObject(item, "units");
                    for (Iterator iterator2 = childUnits.iterator(); iterator2.hasNext(); ) {
                        Map childUnit = (Map) iterator2.next();
                        String childUnitId = MapUtils.getString(childUnit, "unitId");
                        if (StringUtils.equals(sourceUnitId, childUnitId)) {
                            sourceB = false;
                        }
                    }
                    if (sourceB) {
                        buildSource.add(sourceMap);
                    }
                }
                childLots.remove(item);

                break;
            }
        }

        Lot tempLot = new Lot();
        tempLot.setLotId(record);
        buildChildLotMap(childLotsView, tempLot, false);

        theform.setLotInfoForm(lotInfoForm);

        theform.setSourceListValues(this.parseToJsonString(buildSource));
        request.setAttribute(SessionNames.LOT_KEY, lot);
        request.setAttribute(SessionNames.COLLECTION_KEY, childLotsView);
        request.setAttribute(SessionNames.LOT_INFO_FORM_KEY, lotInfoForm);
        theform.setCacheChildLots(WebUtils.getCacheObj2String(childLots));
        theform.setCacheChildLotsView(WebUtils.getCacheObj2String(childLotsView));
        theform.setCacheLotInfo(WebUtils.getCacheObj2String(lotInfoForm));
        theform.setCacheLot(WebUtils.getCacheObj2String(lot));
        return mapping.findForward(Constants.INIT_KEY);
    }

    public ActionForward saveMergeLots(ActionMapping mapping, SplitMergeInfoForm theform, HttpServletRequest request) {

        String user = LocalContext.getUserId();
        LotInfoForm lotInfoForm = (LotInfoForm) WebUtils.getCacheString2Obj(theform.getCacheLotInfo());
        List childLots = (List) WebUtils.getCacheString2Obj(theform.getCacheChildLots());
        Lot lot = (Lot) WebUtils.getCacheString2Obj(theform.getCacheLot());

        lot.setTransPerformedby(user);
        List buildChildUnits = null;
        List buildChildLots = new ArrayList();
        List sourceListValues = this.parseJsonStrAndRemoveIdlePostion(theform.getSourceListValues());

        for (Iterator iterator2 = childLots.iterator(); iterator2.hasNext(); ) {
            Map childMap = (HashMap) iterator2.next();
            Map buildChildMap = childMap;
            Collection childUnits = (Collection) MapUtils.getObject(childMap, "units");
            buildChildUnits = new ArrayList();
            for (Iterator iterator3 = childUnits.iterator(); iterator3.hasNext(); ) {
                Map unitsMap = (HashMap) iterator3.next();
                Map buildUnitsMap = unitsMap;
                String childUnitRrn = MapUtils.getString(unitsMap, "unitRrn");
                for (Iterator iterator = sourceListValues.iterator(); iterator.hasNext(); ) {
                    Map sourceMap = (HashMap) iterator.next();
                    String sourceUnitRrn = MapUtils.getString(sourceMap, "unitRrn");
                    if (StringUtils.equals(childUnitRrn, sourceUnitRrn)) {
                        buildUnitsMap.put("position", MapUtils.getString(sourceMap, "position"));
                        buildChildUnits.add(buildUnitsMap);
                    }
                }
            }
            if (buildChildUnits.size() > 0) {
                buildChildMap.put("units", buildChildUnits);
                buildChildLots.add(buildChildMap);
            }
        }
        if (childLots.size() == buildChildLots.size()) {
            childLots = buildChildLots;
        }

        childLotsBeforeIntoServiceCheck(childLots);
        lotBeforeIntoServiceCheck(lot, "SO");

        //check sortJob
        checkWaitJobs(lot.getCarrierRrn(), 0L, 0L, null);
        
        mergeLot(lot, childLots, theform, user);


        //        if (StringUtils.equalsIgnoreCase("_merge", theform.getCacheTarget())) {
        //            request.getRequestDispatcher("/lotLocation4CSECAction.do?qry=lotlocation&lotId=" +
        //            String.valueOf(
        //                    lot.getLotId())).forward(request, response);
        //            return null;
        //        }

        //        request.setAttribute(SessionNames.LOT_KEY, lot);
        //        request.setAttribute(SessionNames.COLLECTION_KEY, childLots);
        //        request.setAttribute(SessionNames.LOT_INFO_FORM_KEY, lotInfoForm);
        //        theform.setCacheChildLots(WebUtils.getCacheObj2String(childLots));
        //        theform.setCacheLotInfo(WebUtils.getCacheObj2String(lotInfoForm));
        //        theform.setCacheLot(WebUtils.getCacheObj2String(lot));
        return mapping.findForward(Constants.LOTLOCATION_KEY);
    }

    public Map checkMergeInfo(Map requestMap) {

        long facilityRrn = LocalContext.getFacilityRrn();
        List childLots = (List) WebUtils.getCacheString2Obj(MapUtils.getString(requestMap, "cacheChildLots"));
        Lot lot = (Lot) WebUtils.getCacheString2Obj(MapUtils.getString(requestMap, "cacheLot"));

        String childLotId = MapUtils.getStringCheckNull(requestMap, "childLotId");
        Double mergedQty = MapUtils.getDouble(requestMap, "mergedQty");
        Lot paLot = lotQueryService.getLot(lot.getLotId(), facilityRrn);
        Carrier parentCarrier = carrierService.getCarrier(lot.getCarrierRrn());
        Lot childLot = lotQueryService.getLot(childLotId, facilityRrn);

        Assert.isFalse(childLot == null || childLot.getLotRrn() <= 0, Errors.create().content("No such Lot!").build());

        //TODO:
        //        String        qtimeErrorMsg = buidldQtimeErrorMsg(paLot, childLot);
        StringBuilder confirmMsg = new StringBuilder();
        StringBuilder loopErrorMsg = new StringBuilder();
        //        this.buidldLoopErrorMsg(paLot, childLot, confirmMsg, loopErrorMsg);
        //        loopErrorMsg.append(qtimeErrorMsg);

        Map<String, String> result = new HashMap<String, String>();
        result.put("confirmMsg", confirmMsg.toString());
        result.put("loopErrorMsg", loopErrorMsg.toString());

        HashMap item = null;
        for (Iterator it = childLots.iterator(); it.hasNext(); ) {
            item = (HashMap) it.next();

            Assert.isFalse(item.get("childLotId").equals(childLotId),
                           Errors.create().content("Please Select different lot to merge!").build());
        }

        Carrier childCarrier = carrierService.getCarrier(childLot.getCarrierRrn());

        Assert.isFalse(!StringUtils.equalsIgnoreCase(parentCarrier.getFlagType(), childCarrier.getFlagType()) ||
                               !StringUtils.equalsIgnoreCase(parentCarrier.getObjectSubtype(),
                                                             childCarrier.getObjectSubtype()),
                       Errors.create().content("Parent and child " + "lot " + "Cassette " + "info not " + "consistent!")
                             .build());

        // 获取计算后的母批,比验证母批晶舟槽位数是否够用
        Lot tmpParentLot = this.rebuidMergeLotInfo(lot, childLots);
        Lot temChildLot = childLot;

        int index = StringUtils.indexOf(childLot.getLotId(), ".");
        int childLotnumber = NumberUtils.toInt(childLot.getLotId().substring(index + 1));

        index = StringUtils.indexOf(lot.getLotId(), ".");
        int parentLotnumber = NumberUtils.toInt(lot.getLotId().substring(index + 1));

        if (childLotnumber < parentLotnumber) {
            tmpParentLot = childLot;
            temChildLot = lot;
        }

        Long availableSlotCount = carrierService.getCarrier(tmpParentLot.getCarrierRrn()).getAvailableSlotCount();

        Assert.isFalse((MiscUtils.parseSQL(mergedQty) + MiscUtils.parseSQL(temChildLot.getQty1())) >
                               availableSlotCount.longValue(),
                       Errors.create().content("This Carrier available slot " + "is not enough!").build());
        return result;


    }

    public List<Map> buildChildLotMap(List<Lot> lots) {
        List list = new ArrayList();
        for (Lot lot : lots) {
            HashMap item = new HashMap();
            item.put("childLotId", lot.getLotId());
            item.put("carrierId", lot.getCarrierId());
            item.put("qty1", lot.getQty1());
            item.put("qty2", lot.getQty2());
            item.put("productId", getInstanceId(lot.getProductRrn()));
            item.put("processId", getInstanceId(lot.getProcessRrn()));
            item.put("operationId", getInstanceId(lot.getOperationRrn()));
            item.put("mergeSelectFlag", lot.getMergeSelectFlag());
            list.add(item);
        }
        return list;
    }

    public void buildChildLotMap(List<Map> lots, Lot lot, Boolean mergeSelectFlag) {
        for (Map map : lots) {
            if (StringUtils.equalsIgnoreCase(lot.getLotId(), (String) map.get("childLotId"))) {
                if (mergeSelectFlag) {
                    map.put("mergeSelectFlag", "true");
                } else {
                    map.put("mergeSelectFlag", null);
                }
            }
        }
    }



    private HashMap getLotInfo(SplitMergeInfoForm theform, Lot lot) {
        long facilityRrn = LocalContext.getFacilityRrn();
        // check if child lot valid
        Lot childLot = lotQueryService.getLot(theform.getChildLotId(), facilityRrn);

        Assert.isFalse(childLot.getLotRrn() <= 0, Errors.create().content("No such Lot!").build());

        Assert.isFalse((childLot.getLotStatus() != null) && (childLot.getLotStatus().equals(LotStatus.LOSSED) ||
                               childLot.getLotStatus().equals(LotStatus.SCRAPPED) ||
                               childLot.getLotStatus().equals(LotStatus.TERMINATED)),
                       Errors.create().content("Invalid child lot status!").build());

        // check if lots in same operation
        this.checkLotStepForMerge(lot, childLot);

        HashMap item = new HashMap();
        item.put("childLotId", theform.getChildLotId());
        item.put("carrierId", childLot.getCarrierId());
        item.put("qty1", childLot.getQty1());
        item.put("qty2", childLot.getQty2());
        item.put("productId", childLot.getProductId());
        item.put("processId", childLot.getProcessId());
        item.put("operationId", childLot.getOperationId());

        if (this.isTrackUnitFlag(lot)) {
            Assert.isTrue(this.isTrackUnitFlag(childLot),
                          Errors.create().content("Different track unit flag!").build());
            item.put("units", this.parseToSimplifyCollection(
                    this.parseToString(wipQueryService.getUnitListByLot(childLot.getLotRrn()))));
        }
        return item;
    }

    /**
     * @param theform
     * @param lot
     * @param childLots
     * @param parentLotUnits
     */
    private void rebuildTheFormSourceList(SplitMergeInfoForm theform, Lot lot, List childLots, List parentLotUnits,
                                          Carrier parentCarrier) {

        Boolean canDropTarget = parentCarrier.getSlotCount() == 13;// cst13 的晶周可以拖动

        double remainQty = lot.getQty1().doubleValue();

        List source = null;

        if ((lot.getTrackUnitFlag() != null) && lot.getTrackUnitFlag().equalsIgnoreCase(TRUE)) {
            source = JsonUtils.toObject(theform.getSourceListValues(), List.class);
        }

        for (Iterator it = childLots.iterator(); it.hasNext(); ) {
            Map item = (Map) it.next();


            if (lot.getTrackUnitFlag().equalsIgnoreCase(TRUE)) {
                List<Map> childUnits = (List<Map>) item.get("units");
                source = addUnitsInDifferenceFoupForMergeLot(source, childUnits, lot.getLotId());
            }
        } // end of while

        if (lot.getTrackUnitFlag().equalsIgnoreCase(TRUE)) {
            Collections.sort((List) source, new Comparator() {

                @Override
                public int compare(Object paramObject1, Object paramObject2) {
                    Map info1 = (Map) paramObject1;
                    Map info2 = (Map) paramObject2;
                    int seq1 = MapUtils.getIntValue(info1, "position");
                    int seq2 = MapUtils.getIntValue(info2, "position");
                    return (seq1 - seq2);
                }
            });

            theform.setSourceListValues(this.parseToJsonString(source));
        }
    }

    /**
     * @param foupUnits
     * @param childUnits
     * @return List<Map < String, Object>>
     * @Description 将其他foup的子批wafer添加到母批foup内, 并返回母批所在foup的wafer集合(包含空槽位position)
     */
    private List<Map> addUnitsInDifferenceFoupForMergeLot(List<Map> foupUnits, List<Map> childUnits,
                                                          String parentLotId) {
        List<Map> tempChildUnits = new ArrayList<Map>();
        tempChildUnits.addAll(childUnits);
        List<Map> alreadyAddUnits = new ArrayList<Map>();
        // 1.放入对应的空位
        for (Map lotUnitMap : tempChildUnits) {
            lotUnitMap.put("lotid", parentLotId);
            String lotUnitPosition = MapUtils.getString(lotUnitMap, "position");
            String lotUnitId = MapUtils.getString(lotUnitMap, "unitId");
            String lotUnitRrn = MapUtils.getString(lotUnitMap, "unitRrn");
            String lotUnitDummyflag = MapUtils.getString(lotUnitMap, "dummyflag");
            String lotUnitAvailable = MapUtils.getString(lotUnitMap, "available");
            String lotUnitLotid = MapUtils.getString(lotUnitMap, "lotid");
            for (Map carrierUnitMap : foupUnits) {
                String carrierUnitPosition = MapUtils.getString(carrierUnitMap, "position");
                String carrierUnitId = MapUtils.getString(carrierUnitMap, "unitId");
                String carrierUnitRrn = MapUtils.getString(carrierUnitMap, "unitRrn");
                if (lotUnitPosition.equals(carrierUnitPosition) && StringUtils.isBlank(carrierUnitId) &&
                        StringUtils.isBlank(carrierUnitRrn)) {// 同位置下是空位
                    carrierUnitMap.put("unitId", lotUnitId);
                    carrierUnitMap.put("unitRrn", lotUnitRrn);
                    carrierUnitMap.put("dummyflag", lotUnitDummyflag);
                    carrierUnitMap.put("available", lotUnitAvailable);
                    carrierUnitMap.put("lotid", lotUnitLotid);
                    alreadyAddUnits.add(lotUnitMap);
                    break;
                }
            }
        }
        tempChildUnits.removeAll(alreadyAddUnits);// 移除已添加到对应位置的unit
        // 2.有空位就放入
        for (Map lotUnitMap : tempChildUnits) {
            String lotUnitId = MapUtils.getString(lotUnitMap, "unitId");
            String lotUnitRrn = MapUtils.getString(lotUnitMap, "unitRrn");
            String lotUnitDummyflag = MapUtils.getString(lotUnitMap, "dummyflag");
            String lotUnitAvailable = MapUtils.getString(lotUnitMap, "available");
            String lotUnitLotid = MapUtils.getString(lotUnitMap, "lotid");
            for (Map carrierUnitMap : foupUnits) {
                String carrierUnitId = MapUtils.getString(carrierUnitMap, "unitId");
                String carrierUnitRrn = MapUtils.getString(carrierUnitMap, "unitRrn");
                if (StringUtils.isBlank(carrierUnitId) && StringUtils.isBlank(carrierUnitRrn)) {// 空位
                    carrierUnitMap.put("unitId", lotUnitId);
                    carrierUnitMap.put("unitRrn", lotUnitRrn);
                    carrierUnitMap.put("dummyflag", lotUnitDummyflag);
                    carrierUnitMap.put("available", lotUnitAvailable);
                    carrierUnitMap.put("lotid", lotUnitLotid);
                    break;
                }
            }
        }

        return foupUnits;
    }

    private Lot rebuidMergeLotInfo(Lot lot, Collection childLots) {
        long facilityRrn = LocalContext.getFacilityRrn();
        int parIndex = StringUtils.indexOf(lot.getLotId(), ".");
        int parLotnumber = NumberUtils.toInt(lot.getLotId().substring(parIndex + 1));

        String minestLotId = StringUtils.EMPTY;
        int minestLotnumber = parLotnumber;
        Map leftLot = new HashMap();
        Iterator it = childLots.iterator();
        while (it.hasNext()) {
            Map item = (HashMap) it.next();
            String childLotId = MapUtils.getString(item, "childLotId", StringUtils.EMPTY);
            int index = StringUtils.indexOf(childLotId, ".");
            int childLotnumber = NumberUtils.toInt(childLotId.substring(index + 1));
            if (minestLotnumber > childLotnumber) {
                minestLotnumber = childLotnumber;
                minestLotId = childLotId;
                leftLot = item;
            }
        }

        if (minestLotnumber != parLotnumber) {
            Lot realParentLot = lotQueryService.getLot(minestLotId, facilityRrn);
            childLots.remove(leftLot);

            HashMap item = new HashMap();
            item.put("childLotId", lot.getLotId());
            item.put("carrierId", lot.getCarrierId());
            item.put("qty1", lot.getQty1());
            item.put("qty2", lot.getQty2());
            item.put("productId", lot.getProductId());
            item.put("processId", lot.getProcessId());
            item.put("operationId", lot.getOperationId());

            if (this.isTrackUnitFlag(realParentLot)) {
                Assert.isTrue(this.isTrackUnitFlag(lot), Errors.create().content("Different track unit flag!").build());
                item.put("units", this.parseToSimplifyCollection(
                        this.parseToString(wipQueryService.getUnitListByLot(lot.getLotRrn()))));
            }
            childLots.add(item);
            lot = realParentLot;

        }
        return lot;
    }

    private void mergeLot(Lot lot, List childLots, SplitMergeInfoForm theform, String user) {
        long facilityRrn = LocalContext.getFacilityRrn();
        Assert.isFalse(childLots.size() <= 0, Errors.create().key(MessageIdList.MERGELOT_NO_LOT_SELECTED_FOR_MERGE)
                                                    .content("No lot selected for merge").build());

        lot = this.rebuidMergeLotInfo(lot, childLots);

        Carrier parentCarrier = carrierService.getCarrier(lot.getCarrierRrn());
        Boolean canDropTarget = parentCarrier.getSlotCount() == 13;// cst13 的晶周可以拖动

        List newUnits = null;

        List sourceListValues = wipQueryService.getUnitListByLot(lot.getLotRrn());

        //创建需要上锁的 rrn arry
        List<String> needLockLotRrns=new ArrayList<>();
        //添加 父 lot rrn
        needLockLotRrns.add(StringUtils.toString(lot.getLotRrn()));
        List<Map> masterLotRunCardCreatedTimeList = lotRunCardQueryService
                .getSumbitAndActiveRunCardCreateTime(lot.getLotRrn());

        for (Iterator it = childLots.iterator(); it.hasNext(); ) {
            Map item = (Map) it.next();
            Lot child_Lot = lotQueryService
                    .getLot(MapUtils.getString(item, "childLotId"), LocalContext.getFacilityRrn());
            // 再次判断是否可以合批
            checkMergeAvailable(lot, child_Lot);
            sourceAndChidUnits(sourceListValues, item, masterLotRunCardCreatedTimeList);
            //经过上述判断后 将子批次 加入上锁集合
            needLockLotRrns.add(StringUtils.toString(child_Lot.getLotRrn()));
            // check process version
            checkProcessVersionForMerge(lot, child_Lot);
            // check product version
            checkProductVersionForMerge(lot, child_Lot);
            // check Contamination
            this.checkContaminationLevel(lot, child_Lot);
            //Check flip for childLot and parentLot
            this.checkFlip4ChildAndParentLot(lot, child_Lot);
        }

        Collections.sort((List) sourceListValues, new Comparator() {

            @Override
            public int compare(Object paramObject1, Object paramObject2) {
                Map info1 = (Map) paramObject1;
                Map info2 = (Map) paramObject2;
                int seq1 = MapUtils.getIntValue(info1, "position");
                int seq2 = MapUtils.getIntValue(info2, "position");
                return (seq1 - seq2);
            }
        });

        List buildChildUnits = new ArrayList();
        for (Iterator iterator2 = sourceListValues.iterator(); iterator2.hasNext(); ) {
            Map childMap = (HashMap) iterator2.next();
            Map buildChildMap = childMap;
            String childUnitRrn = MapUtils.getString(childMap, "unitRrn");
            for (Iterator iterator = sourceListValues.iterator(); iterator.hasNext(); ) {
                Map sourceMap = (HashMap) iterator.next();
                String sourceUnitRrn = MapUtils.getString(sourceMap, "unitRrn");
                if (StringUtils.equals(childUnitRrn, sourceUnitRrn)) {
                    buildChildMap.put("position", MapUtils.getString(sourceMap, "position"));
                    buildChildUnits.add(buildChildMap);
                }
            }
        }
        if (buildChildUnits.size() == buildChildUnits.size()) {
            sourceListValues = buildChildUnits;
        }
        newUnits = this.parseJsonStrAndRemoveIdlePostion(theform.getSourceListValues());

        HashMap valueMap = new HashMap();
        valueMap.put("lot", lot);
        valueMap.put("childLots", childLots);
        valueMap.put("unitOfParent", wipQueryService.getUnitListByLot(lot.getLotRrn()));
        valueMap.put("comment", theform.getComment());
        valueMap.put("newUnits", newUnits);
        Assert.isFalse(checkMergeBeforeUpdateDB(valueMap), Errors.create().content("Merge Lot info is error!").build());

        // add for FMI reason Code
        TransReason transReason = new TransReason();
        String reason = theform.getReason();

        transReason.setReasonCode("");
        transReason.setResponsibility(user);
        transReason.setReason(reason);
        valueMap.put("transReason", transReason);

        checkLotPriority(valueMap, lot, childLots);

        // end
        // String childLotIds = "";
        // List<Lot> lockLots = new ArrayList<Lot>();
        // lockLots.add(lot);
        // for (Iterator iterator = childLots.iterator(); iterator.hasNext(); ) {
        //     Map map = (Map) iterator.next();
        //     Lot _lot = lotQueryService.getLot(MapUtils.getString(map, "childLotId"), facilityRrn);
        //     // lockLots.add(_lot);
        //     childLotIds += _lot.getLotId() + ",";
        // }
        // Long userRrn = LocalContext.getUserRrn();
        // checkAndCreateLotsTransLock(userRrn, TransactionNames.LOCK_MERGE, lockLots,
        //                             "The lot: " + lot.getLotId() + " merge: " + childLotIds + " in MergeLotAction
        //                             by:" +
        //                                     " " + user);
        lotService.mergeLot(valueMap,needLockLotRrns);
    }


    private void checkLotPriority(HashMap valueMap, Lot lot, Collection childLots) {
        // Check the priority size of sub-lot and lot
        Integer tempHotFlag = NumberUtils.toInt(lot.getHotFlag(), Integer.MAX_VALUE);
        Integer tempProirity = Optional.ofNullable(lot.getPriority()).orElse(Integer.MAX_VALUE);
        boolean changeFlag = false;
        for (Iterator it = childLots.iterator(); it.hasNext(); ) {
            HashMap subLotMap = (HashMap) it.next();
            Lot subLot = lotQueryService.getLot(MapUtils.getString(subLotMap, "childLotId"), lot.getFacilityRrn());
            Integer hotFlag = NumberUtils.toInt(subLot.getHotFlag(), Integer.MAX_VALUE);
            Integer priority = Optional.ofNullable(subLot.getPriority()).orElse(Integer.MAX_VALUE);
            if (hotFlag < tempHotFlag || (hotFlag.equals(tempHotFlag) && priority < tempProirity)) {
                changeFlag = true;
                tempHotFlag = hotFlag;
                tempProirity = priority;
            }
        }
        if (changeFlag) {
            valueMap.put("hotFlag", tempHotFlag);
            valueMap.put("priority", tempProirity);
        }
    }

}