LotQueryDAOImpl.java

package com.mycim.server.wip.dao.impl;

import com.fa.sesa.threadlocal.LocalContext;
import com.mycim.framework.jdbc.JdbcTemplate;
import com.mycim.framework.jdbc.Page;
import com.mycim.framework.jdbc.mapper.RowMapper;
import com.mycim.framework.utils.MiscUtils;
import com.mycim.framework.utils.lang.StringUtils;
import com.mycim.framework.utils.lang.collections.CollectionUtils;
import com.mycim.framework.utils.lang.collections.MapUtils;
import com.mycim.framework.utils.lang.math.NumberUtils;
import com.mycim.framework.utils.lang.time.DateUtils;
import com.mycim.server.wip.dao.LotQueryDAO;
import com.mycim.server.wip.dao.impl.threadtask.QueryLotHistoryExpRowSetTask;
import com.mycim.server.wip.dao.mapper.*;
import com.mycim.server.wip.manager.impl.LotQueryManagerImpl;
import com.mycim.utils.EmasUtil;
import com.mycim.utils.WipUtils;
import com.mycim.valueobject.Constants;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.bas.TransactionLog;
import com.mycim.valueobject.consts.*;
import com.mycim.valueobject.prp.LotRecycledInfo;
import com.mycim.valueobject.runcard.util.RunCardConstants;
import com.mycim.valueobject.wip.*;
import com.mycim.valueobject.wip.dto.LotQueryParameterDto;
import com.mycim.valueobject.wip.dto.ShipQueryConditionDto;
import org.apache.commons.collections.list.SynchronizedList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.stereotype.Repository;

import javax.management.Query;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @author Johnson W
 */
@Repository
public class LotQueryDAOImpl implements LotQueryDAO {

    private static final String UOM1_TYPE = "1";

    private static final String UOM2_TYPE = "2";

    private static final String DUMMY_FLAG = "dummyFlag";

    private static final long MAX_PAGE_SIZE=1000000;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public List<Lot> getLots(String sql) {
        String new_sql = getLotSql() + " " + sql;
        return jdbcTemplate.query(new_sql, new LotMapper());
    }

    @Override
    public List<Lot> getLotsByEqpt(String whereSql, long eqptRrn) {
        String new_sql = getLotSql() + " " + whereSql + eqptRrn;
        return jdbcTemplate.query(new_sql, new LotMapper());
    }

    @Override
    public Lot getLot(String lotSql, long lotRrn, String lotId) {
        List<Object> args = new ArrayList<>();
        if (lotRrn > 0) {
            args.add(lotRrn);
        } else {
            args.add(LocalContext.getFacilityRrn());
            args.add(lotId);
        }

        Lot lot = jdbcTemplate.queryForObjectWithNull(lotSql, args.toArray(), new LotMapper());
        if (null == lot) {
            return new Lot();
        }

        lot.setwaitTime(Long.toString(getQueueTime(lot.getLotId())));

        if (lot.getOperationRrn() != null) {
            lot.setUOM1(getUOM1(lot.getOperationRrn()));
            lot.setUOM2(getUOM2(lot.getOperationRrn()));
        }

        String lot_rrn = String.valueOf(lot.getLotRrn());
        Map lotord = getLotOrder(lot_rrn);
        if (MapUtils.isNotEmpty(lotord)) {
            if (lotord.get("order_type").toString().equalsIgnoreCase(ObjectList.ORDER_SUB_ACTUL)) {
                lot.setOrder_id_actul(lotord.get("order_id").toString());
            } else {
                lot.setOrder_id_actul("");
            }
            lot.setMarket_order_Id(lotord.get("market_order_id").toString());
            lot.setCustProdid(getCustId(MapUtils.getLongValue(lotord, "order_rrn")));
        } else {
            lot.setOrder_id_actul("");
            lot.setMarket_order_Id("");
        }
        return lot;
    }

    @Override
    public Map getLotStepHisotryInfoByOperationRrn(Map info) {
        String sql = "select LOT_RRN,STEP_SEQUENCE,FACILITY_RRN,LOT_ID,PRODUCT_RRN," + "PROCESS_RRN,PROCESS_VERSION," +
                "PROCESS_STEP_VERSION," + "PROCESS_STEP_ID_VERSION,OPERATION_RRN,OPERATION_VERSION," + "EQPT_RRN," +
                "RECIPE_STRING,RETICLE_RRN," + "BIN_RRN,MOVE_IN_DCOL_RRN,MOVE_OUT_DCOL_RRN,AD_HOC_DCOL_RRN," +
                "RECIPE_LOGICAL_RRN " + " from " + DataBaseNames.LOT_STEP_HISTORY + " where " + " lot_rrn = " +
                info.get("lotRrn") + " and  operation_rrn = " + info.get("operationRrn") + " order by STEP_SEQUENCE ";
        List<Map> lotStepInfos = jdbcTemplate.query(sql, new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                HashMap lotStepInfo = new HashMap();
                lotStepInfo.put("lotRrn", rs.getString("LOT_RRN"));
                lotStepInfo.put("stepSequence", rs.getString("STEP_SEQUENCE"));
                lotStepInfo.put("facilityRrn", rs.getString("FACILITY_RRN"));
                lotStepInfo.put("lotId", rs.getString("LOT_ID"));
                lotStepInfo.put("productRrn", rs.getString("PRODUCT_RRN"));
                lotStepInfo.put("processRrn", rs.getString("PROCESS_RRN"));
                lotStepInfo.put("processVersion", rs.getString("PROCESS_VERSION"));
                lotStepInfo.put("processStepVersion", rs.getString("PROCESS_STEP_VERSION"));
                lotStepInfo.put("processStepIdVersion", rs.getString("PROCESS_STEP_ID_VERSION"));
                lotStepInfo.put("operationRrn", rs.getString("OPERATION_RRN"));
                lotStepInfo.put("operationVersion", rs.getString("OPERATION_VERSION"));
                lotStepInfo.put("equipmentRrn", rs.getString("EQPT_RRN"));
                lotStepInfo.put("recipeString", rs.getString("RECIPE_STRING"));
                lotStepInfo.put("reticleRrn", rs.getString("RETICLE_RRN"));
                lotStepInfo.put("binRrn", rs.getString("BIN_RRN"));
                lotStepInfo.put("moveInDcolRrn", rs.getString("MOVE_IN_DCOL_RRN"));
                lotStepInfo.put("moveOutDcolRrn", rs.getString("MOVE_OUT_DCOL_RRN"));
                lotStepInfo.put("adHocDcolRrn", rs.getString("AD_HOC_DCOL_RRN"));
                lotStepInfo.put("recipeLogicalRrn", rs.getString("RECIPE_LOGICAL_RRN"));

                return lotStepInfo;
            }

        });

        return CollectionUtils.isNotEmpty(lotStepInfos) ? lotStepInfos.get(0) : new HashMap();
    }

    @Override
    public long getQueueTime(String lotId) {
        long statusTime = 0;
        String sql = "select QUEUE_TIMESTAMP from lot where lot_id = ?";
        Timestamp queueTime = jdbcTemplate.queryForObjectWithNull(sql, new Object[]{lotId}, Timestamp.class);
        if (queueTime != null) {
            statusTime = (new java.util.Date().getTime() - queueTime.getTime()) / (60 * 1000);
        }
        return statusTime;
    }

    // todo 移到workorder
    @Override
    public Map getLotOrder(String lotRrn) {
        String sql = "select LINK_TYPE,FROM_RRN,TO_RRN, ATTRIBUTE_DATA_1, ATTRIBUTE_DATA_2, " + "ATTRIBUTE_DATA_3, " +
                "ATTRIBUTE_DATA_4, ATTRIBUTE_DATA_5, ATTRIBUTE_DATA_6," + "SEQUENCE_NUMBER  " +
                " from (select * from  " + "lot_relation_fmi l  where  l.FROM_RRN=" + lotRrn +
                " and link_type='ORDER' order by sys_dte_tm desc) " + "R_ORDER where rownum = 1";
        return jdbcTemplate.queryForObjectWithNull(sql, new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map map = new HashMap();
                map.put("lot_rrn", rs.getString("FROM_RRN"));
                map.put("order_rrn", rs.getString("TO_RRN"));
                map.put("lot_id", rs.getString("ATTRIBUTE_DATA_1"));
                map.put("order_id", rs.getString("ATTRIBUTE_DATA_2"));
                map.put("market_order_id", rs.getString("ATTRIBUTE_DATA_3"));
                map.put("order_type", rs.getString("ATTRIBUTE_DATA_4"));
                map.put("lot_qty", rs.getString("ATTRIBUTE_DATA_6"));
                map.put("STEP_SEQUENCE", rs.getString("SEQUENCE_NUMBER"));
                return map;
            }
        });
    }

    @Override
    public String getCustId(long orderRrn) {
        String sql = "select cust_prod_id from order_info b where b.order_rrn= ?";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{orderRrn}, String.class);
    }

    @Override
    public Map<String,Object> getLotStateAndStepSeq(long lotRrn){
        String sql = " SELECT LOT_STATUS AS CURRENT_STATUS,STEP_SEQUENCE AS STEP_SEQ FROM LOT WHERE LOT_RRN=? ";
        return  jdbcTemplate.queryForObjectWithNull(sql,Map.class,new Object[]{lotRrn});
    }

    @Override
    public List<Long> getRunLotRrnsByChamberId(Long eqptRrn ,String chamberId) {
        String sql =  "select lot.LOT_RRN from Lot lot left join JOB job on job.JOB_RRN = lot.JOB_RRN  where job.EQPT_RRN=?  and job.CHAMBER_EQPTS_ID is not null "
                + " and lot.JOB_RRN is not null and lot.LOT_STATUS in ('%s', '%s') and job.CHAMBER_EQPTS_ID like ? ";
        sql = String.format(sql,LotStatus.RUNNING,LotStatus.RUNNINGHOLD);
        //强制;结尾
        //判断是否存在
        return jdbcTemplate.query(sql, new Object[]{eqptRrn,"%"+chamberId+";%"},Long.class);
    }

    @Override
    public List<Map> getBatchAdjustLots(Map map) {
        List<Object> args=new ArrayList<>();
        StringBuilder sql = new StringBuilder("SELECT");
        sql.append(" lt.lot_rrn, lt.lot_id, lt.lot_owner, lt.qty1, lt.qty2, pro.OPERATION_DESCRIPTION, pro.route_id, pro.FLOW_SEQ,");
        sql.append(" lt.lot_status, pro.stage_id, lt.product_rrn, lt.process_rrn, lt.PROCESS_VERSION,lt.PRODUCT_VERSION, ");
        sql.append(" lt.process_step_version, lt.process_step_id_version, pro.operation_rrn, pro.recipe_id, ");
        sql.append(" pro.PRODUCT_ID, pro.PROCESS_ID, pro.OPERATION_ID, ");
        sql.append(" lt.facility_rrn, lt.eqpt_rrn, lt.product_layer, lt.route_seq, lt.product_version,lt.hot_flag,lt.priority, ");
        sql.append(" lt.operation_seq, pro.ATTRIBUTE_DATA2 BANK_FLAG, pro.route_Rrn FROM lot lt, PRO_CONTEXT_ACTIVE_DTL pro  ");
        sql.append(" WHERE lt.PROCESS_RRN = pro.PROCESS_RRN  AND lt.PROCESS_VERSION = pro.PROCESS_VERSION ");
        sql.append(" and lt.product_rrn = pro.product_rrn AND lt.product_version = pro.product_version AND");
        sql.append(" lt.operation_rrn = pro.operation_rrn AND");
        sql.append(" pro.ROUTE_RRN = TO_NUMBER ( REGEXP_SUBSTR ( lt.process_step_version, '[^,]+', INSTR( lt.process_step_version, '|', 1, 1 ) + 1, 1 ) )  ");

        sql.append(" AND lt.LOT_STATUS IN ('WAITING', 'HOLD', 'RUNNING') ");
        if (MapUtils.getLong(map, "productRrn") != null) {
            sql.append(" AND lt.product_rrn = ?");
            args.add(MapUtils.getLong(map, "productRrn"));
        }

        if (MapUtils.getLong(map, "processRrn") != null) {
            sql.append(" AND lt.process_rrn = ?");
            args.add(MapUtils.getLong(map, "processRrn"));
        }
        if (MapUtils.getInteger(map, "processVersion") != null){
            sql.append(" AND lt.PROCESS_VERSION = ?");
            args.add(MapUtils.getInteger(map, "processVersion"));
        }
        sql.append(" ORDER BY lt.lot_id ");
        return jdbcTemplate.query(sql.toString(), args.toArray(), new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map m = new HashMap();
                m.put("seq", new Integer(rowNum));
                m.put("lotRrn", new Long(rs.getLong("lot_rrn")));
                m.put("lotId", rs.getString("lot_id"));
                m.put("lotOwner", rs.getString("lot_owner"));
                m.put("qty1", new Double(rs.getDouble("qty1")));
                m.put("qty2", new Double(rs.getDouble("qty2")));
                m.put("lotStatus", rs.getString("lot_status"));
                String processStepIdString = rs.getString("process_step_id_version");
                m.put("processStepIdVersion", processStepIdString);
                m.put("routeId", rs.getString("route_id"));
                m.put("operationRrn", rs.getLong("operation_rrn"));
                m.put("stageId", rs.getString("stage_id"));
                m.put("productRrn", rs.getLong("product_rrn"));
                m.put("processStepVersion", rs.getString("process_step_version"));
                m.put("processRrn", new Long(rs.getLong("process_rrn")));
                m.put("lotRrn", new Long(rs.getLong("lot_rrn")));
                m.put("lotId", rs.getString("lot_id"));
                m.put("facilityRrn", new Long(rs.getLong("facility_rrn")));
                m.put("productLayer", rs.getString("product_layer"));
                m.put("routeSeq", rs.getString("route_seq"));
                m.put("operationSeq", rs.getString("operation_seq"));
                m.put("processVersion", rs.getInt("PROCESS_VERSION"));
                m.put("entityRrn", rs.getLong("eqpt_rrn"));
                m.put("bankFlag", rs.getString("BANK_FLAG"));
                m.put("routeRrn", rs.getString("route_Rrn"));
                m.put("recipeId", rs.getString("recipe_id"));
                String operationDescription = rs.getString("OPERATION_DESCRIPTION");
                m.put("operationDesc", StringUtils.isNotBlank(operationDescription) ? operationDescription:StringUtils.EMPTY);
                m.put("productVersion", rs.getString("PRODUCT_VERSION"));
                m.put("flowSeq", rs.getString("FLOW_SEQ"));
                m.put("hotFlag", rs.getString("hot_flag"));
                m.put("priority", rs.getString("priority"));
                m.put("processId", rs.getString("process_id"));
                m.put("productId", rs.getString("product_id"));
                m.put("operationId", rs.getString("operation_id"));
                return m;
            }
        });
    }

    @Override
    public List<Map> getBatchCancelFutureHoldLots(Map map, long refRrn) {
        List<Object> args=new ArrayList<>();
        StringBuilder sql = new StringBuilder("SELECT");
        sql.append(" lt.lot_rrn, lt.lot_id, pro.FLOW_SEQ, V.status, V.SEQUENCE_NUMBER ,V.RESULT_VALUE2 ,V.RESULT_VALUE3 , ");
        sql.append(" V.RESULT_VALUE4 , V.RESULT_VALUE5 ,V.RESULT_VALUE6 , V.RESULT_VALUE1 , V.EFFECTIVE_DATE_FROM, E.ACTION_TYPE , ");
        sql.append(" lt.lot_owner, lt.qty1, lt.qty2, pro.OPERATION_DESCRIPTION, pro.route_id, lt.lot_status, pro.stage_id, lt.product_rrn, ");
        sql.append(" lt.process_rrn, lt.PROCESS_VERSION, lt.PRODUCT_VERSION,lt.process_step_version, lt.process_step_id_version, ");
        sql.append(" pro.operation_rrn, pro.recipe_id, lt.facility_rrn, lt.eqpt_rrn, lt.product_layer, lt.route_seq, lt.product_version,  ");
        sql.append(" pro.PRODUCT_ID, pro.PROCESS_ID, pro.OPERATION_ID, ");
        sql.append(" lt.hot_flag, lt.priority, lt.operation_seq, pro.ATTRIBUTE_DATA2 BANK_FLAG, pro.route_Rrn FROM lot lt, PRO_CONTEXT_ACTIVE_DTL pro, ");
        sql.append(" CONTEXT_VALUE V, EEN_ACTION E WHERE lt.PROCESS_RRN = pro.PROCESS_RRN AND lt.product_rrn = pro.product_rrn");
        sql.append(" AND lt.PROCESS_VERSION = pro.PROCESS_VERSION  AND lt.product_version = pro.product_version ");
        if (MapUtils.getLong(map, "productRrn") != null) {
            sql.append(" AND lt.product_rrn = ?");
            args.add(MapUtils.getLong(map, "productRrn"));
        }
        if (MapUtils.getLong(map, "processRrn") != null) {
            sql.append(" AND lt.process_rrn = ?");
            args.add(MapUtils.getLong(map, "processRrn"));
        }
        if (MapUtils.getInteger(map, "processVersion") != null){
            sql.append(" AND lt.PROCESS_VERSION = ?");
            args.add(MapUtils.getInteger(map, "processVersion"));
        }
        if (MapUtils.getLong(map, "routeRrn") != null){
            sql.append(" AND pro.ROUTE_RRN = ?");
            args.add(MapUtils.getInteger(map, "routeRrn"));
        }
        if (MapUtils.getLong(map, "operationRrn") != null){
            sql.append(" AND pro.OPERATION_RRN = ?");
            args.add(MapUtils.getInteger(map, "operationRrn"));
        }
        sql.append("  AND V.CONTEXT_KEY3 = LT.LOT_RRN  AND V.RESULT_VALUE1 = E.ACTION_RRN AND V.CONTEXT_KEY2 = pro.OPERATION_RRN");
        sql.append("  AND V.CONTEXT_KEY1 = pro.ROUTE_RRN AND V.CONTEXT_RRN = ? ORDER BY lt.lot_id  ");
        args.add(refRrn);
        return jdbcTemplate.query(sql.toString(), args.toArray(), new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map m = new HashMap();
                m.put("seq", new Integer(rowNum));
                m.put("lotRrn", new Long(rs.getLong("lot_rrn")));
                m.put("lotId", rs.getString("lot_id"));
                m.put("lotOwner", rs.getString("lot_owner"));
                m.put("qty1", new Double(rs.getDouble("qty1")));
                m.put("qty2", new Double(rs.getDouble("qty2")));
                m.put("lotStatus", rs.getString("lot_status"));
                String processStepIdString = rs.getString("process_step_id_version");
                m.put("processStepIdVersion", processStepIdString);
                m.put("routeId", rs.getString("route_id"));
                m.put("operationRrn", rs.getLong("operation_rrn"));
                m.put("stageId", rs.getString("stage_id"));
                m.put("productRrn", rs.getLong("product_rrn"));
                m.put("processStepVersion", rs.getString("process_step_version"));
                m.put("processRrn", new Long(rs.getLong("process_rrn")));
                m.put("lotRrn", new Long(rs.getLong("lot_rrn")));
                m.put("lotId", rs.getString("lot_id"));
                m.put("facilityRrn", new Long(rs.getLong("facility_rrn")));
                m.put("productLayer", rs.getString("product_layer"));
                m.put("routeSeq", rs.getString("route_seq"));
                m.put("operationSeq", rs.getString("operation_seq"));
                m.put("processVersion", rs.getInt("PROCESS_VERSION"));
                m.put("entityRrn", rs.getLong("eqpt_rrn"));
                m.put("bankFlag", rs.getString("BANK_FLAG"));
                m.put("routeRrn", rs.getString("route_Rrn"));
                m.put("recipeId", rs.getString("recipe_id"));
                String operationDescription = rs.getString("OPERATION_DESCRIPTION");
                m.put("operationDesc", StringUtils.isNotBlank(operationDescription) ? operationDescription:StringUtils.EMPTY);
                m.put("productVersion", rs.getString("PRODUCT_VERSION"));
                m.put("flowSeq", rs.getString("FLOW_SEQ"));
                String transByName = getTransByName(rs.getString("RESULT_VALUE2"));
                if (transByName != null) {
                    m.put("userNamed", rs.getString("RESULT_VALUE2") + " " + transByName);
                } else {
                    m.put("userNamed", rs.getString("RESULT_VALUE2"));
                }
                m.put("holdGroup", rs.getString("RESULT_VALUE3"));
                m.put("holdCode", rs.getString("RESULT_VALUE4"));
                m.put("holdReason", rs.getString("RESULT_VALUE5"));
                m.put("effectCount", rs.getString("RESULT_VALUE6"));
                m.put("actionRrn", rs.getString("RESULT_VALUE1"));
                java.sql.Date db_Date = rs.getDate("EFFECTIVE_DATE_FROM");
                String dbDate = DateUtils.formatDate(db_Date, DateUtils.DATE_FORMAT4DAY);
                m.put("futureholdsetupdate", dbDate);
                m.put("seqNum", new Long(rs.getLong("SEQUENCE_NUMBER")));
                m.put("flag", rs.getString("ACTION_TYPE"));
                m.put("status", rs.getString("status"));
                m.put("processId", rs.getString("process_id"));
                m.put("productId", rs.getString("product_id"));
                m.put("operationId", rs.getString("operation_id"));
                return m;
            }
        });
    }

    @Override
    public List<Map> getLotList4Ship(ShipQueryConditionDto sqcd) {
        String sql = "SELECT LOT.*, LE.ATTRIBUTE_DATA5, TLL.TRANS_END_TIMESTAMP FROM (" + getLotSql() +") LOT LEFT JOIN (" +
                " SELECT LTH.LOT_RRN,TL.* FROM LOT_TRANS_HISTORY LTH,TRANSACTION_LOG TL "
                + " WHERE LTH.TRANS_RRN=TL.TRANS_RRN AND LTH.TRANS_ID = ? "
                + " ) TLL  ON LOT.LOT_RRN = TLL.LOT_RRN , LOT_EXT LE  ";
        List<Object> args = new ArrayList<>();
        args.add(TransactionNames.COMPLETE_LOT);
        String whereSql = buildParameter(sqcd, args, "LOT.");
        sql += whereSql + "  AND LOT.LOT_RRN = LE.LOT_RRN ORDER BY TLL.TRANS_END_TIMESTAMP ASC ";

        return jdbcTemplate.query(sql, args.toArray(), (RowMapper<Map>) (rs, rowNum) -> {
            Map m = new HashMap();
            m.put("seq", rowNum+1);
            m.put("lotRrn", rs.getLong("LOT_RRN"));
            m.put("lotId", rs.getString("LOT_ID"));
            m.put("lotOwner", rs.getString("LOT_OWNER"));
            m.put("qty1", rs.getDouble("QTY1"));
            m.put("qty2", rs.getDouble("QTY2"));
            m.put("lotStatus", rs.getString("LOT_STATUS"));
            String processStepString = rs.getString("PROCESS_STEP_VERSION");
            int firstSep = processStepString.indexOf("|");
            int secondSep = processStepString.indexOf("|", firstSep + 1);
            String routeRrn = "";
            if (secondSep >= 0) {
                routeRrn = processStepString.substring(firstSep + 1, processStepString.indexOf(",", firstSep));
            } else {
                routeRrn = processStepString.substring(0, processStepString.indexOf(","));
            }
            m.put("routeRrn", NumberUtils.toLong(routeRrn, 0L));
            m.put("operationRrn", rs.getLong("OPERATION_RRN"));
            m.put("stageId", rs.getString("STAGE_ID"));
            m.put("productRrn", rs.getLong("PRODUCT_RRN"));
            m.put("processRrn", rs.getLong("PROCESS_RRN"));
            m.put("processVersion", rs.getInt("PROCESS_VERSION"));
            m.put("processStepVersion", rs.getString("PROCESS_STEP_VERSION"));
            m.put("operationSeq", rs.getString("OPERATION_SEQ"));
            m.put("recipeRrn", null);
            m.put("facilityRrn", rs.getLong("FACILITY_RRN"));
            m.put("productLayer", rs.getString("PRODUCT_LAYER"));
            m.put("routeSeq", rs.getString("ROUTE_SEQ"));
            m.put("eqptRrn", rs.getLong("EQPT_RRN"));
            m.put("endTimestamp", DateUtils.formatDate(rs.getTimestamp("TRANS_END_TIMESTAMP")));
            m.put("attributeData5", rs.getString("ATTRIBUTE_DATA5"));
            return m;
        });
    }

    @Override
    public Map<Long, String> getInstanceIdsInLotByRrn(ShipQueryConditionDto sqcd) {
        Map<Long, String> idMap = new HashMap<>();
        List<Object> args = new ArrayList<>();
        String idSql4Lot = getInstanceIdSql(sqcd, args);

        jdbcTemplate.query(idSql4Lot, args.toArray(), (RowMapper<Map<Long, String>>) (rs, rowNum) -> {
            long instanceRrn = rs.getLong("INSTANCE_RRN");
            String instanceId = rs.getString("INSTANCE_ID");
            idMap.put(instanceRrn, instanceId);
            return idMap;
        });
        return idMap;
    }


    private String buildParameter(ShipQueryConditionDto sqcd, List<Object> args, String alis) {
        String whereSql = " WHERE 1=1 ";
        Object parameter = sqcd.getLotStatus();
        if (!Objects.isNull(parameter)){
            whereSql +=  " AND " + alis + "LOT_STATUS = ? ";
            args.add(parameter);
        }
        parameter = sqcd.getLotId();
        if (!Objects.isNull(parameter)){
            whereSql += " AND " + alis + "LOT_ID = ? ";
            args.add(parameter);
        }
        parameter = sqcd.getLotType();
        if (!Objects.isNull(parameter)){
            whereSql += " AND " + alis + "LOT_TYPE = ? ";
            args.add(parameter);
        }
        parameter = sqcd.getProductRrn();
        if (!Objects.isNull(parameter)){
            whereSql += " AND " + alis + "PRODUCT_RRN = ? ";
            args.add(parameter);
        }
        return whereSql;
    }


    @Override
    public Lot getLot(long lotRrn) {
        String sql = getLotSql() + " WHERE LOT_RRN = ?";

        return getLot(sql, lotRrn, 0, null);
    }

    @Override
    public Lot getLot(long facilityRrn, String lotId) {
        String sql = getLotSql() + " WHERE FACILITY_RRN = ? AND LOT_ID = ?";

        return getLot(sql, 0, facilityRrn, lotId);
    }

    @Override
    public List<Map<String, Object>> getLotInfoByStatus(long facilityRrn, String lotType, String... status) {
        List args = new ArrayList();
        String placeholder = StringUtils.strToCommaDelimitedDuplicateString("?", status.length);
        StringBuffer sql = new StringBuffer();
        sql.append("SELECT LOT.LOT_RRN, LOT.LOT_ID, LOT.LOT_STATUS, LOT.QTY1, LOT.LOT_TYPE, ");
        sql.append("LOT.QUEUE_TIMESTAMP, operating.work_area,temp.LABEL AS work_area_label, ");
        sql.append("operating.oper_name, OPERATING.OPER_DESC,PRODUCT_INFO.INSTANCE_ID AS PRODUCT_NAME, ");
        sql.append("EQUIP.INSTANCE_ID AS EQUIPMENT_NAME,rownum AS ROW_NUM ");
        sql.append("FROM LOT left join (SELECT * FROM named_object WHERE object = 'ENTITY') EQUIP ");
        sql.append("on LOT.EQPT_RRN = EQUIP.INSTANCE_RRN,  ");
        sql.append("(SELECT o.OPERATION_RRN, e.attribute_data5 AS work_area, ");
        sql.append("oper.instance_id AS oper_name, OPER.INSTANCE_DESC AS OPER_DESC ");
        sql.append("FROM OPERATION O LEFT JOIN operation_ext e ");
        sql.append("ON O.OPERATION_RRN = e.OPERATION_RRN ");
        sql.append("LEFT JOIN named_object_ext n ");
        sql.append("ON e.OPERATION_RRN = n.INSTANCE_RRN, ");
        sql.append("(SELECT * FROM named_object WHERE object = 'OPERATION') oper ");
        sql.append("WHERE O.OPERATION_RRN = oper.instance_rrn ");
        sql.append(") operating left join ");
        sql.append("(SELECT DISTINCT key_1_value AS VALUE, data_1_value AS label ");
        sql.append("FROM NAMED_OBJECT N, REFERENCE_FILE_DETAIL D ");
        sql.append("WHERE N.INSTANCE_RRN = D.REFERENCE_FILE_RRN and N.INSTANCE_ID = '$$WORK_AREA' ");
        sql.append(") temp on operating.work_area = temp.VALUE, ");
        sql.append("(SELECT * FROM named_object WHERE NAMED_OBJECT.OBJECT = 'PRODUCT') PRODUCT_INFO ");
        sql.append("WHERE LOT.OPERATION_RRN = operating.OPERATION_RRN ");
        sql.append("AND LOT.PRODUCT_RRN = PRODUCT_INFO.INSTANCE_RRN ");
        sql.append("AND lot_status IN (" + placeholder + ")");
        String[] list = status;
        for (String statu : list) {
            args.add(statu);
        }
        if (!StringUtils.isEmpty(lotType)) {
            sql.append(" AND PRODUCT_INFO.OBJECT_TYPE = ? ");
            args.add(lotType);
        }


        sql.append(" AND LOT.FACILITY_RRN = ? ");
        args.add(facilityRrn);

        return jdbcTemplate.query(sql.toString(), args.toArray(), new LotInfoMapper());
    }

    @Override
    public Lot getLotExt(Lot lot) {
        String sql = " SELECT LOT_RRN,ATTRIBUTE_DATA2," + " ATTRIBUTE_DATA1,WIFER_ID, WIFER_TYPE, " + "FLOW_LEVEL, " +
                "CUSTOMER_ID," + " CUSTOMER_LOT_ID, CUSTOMER_WAFER_ID," + " " + "OUTER_ORDER_NO, INNER_ORDER_NO, " +
                "SHIPPING_CODE, IS_OUT_SOURCE, IS_RECREATE_LOT, " + " " +
                "PROJECT_CATEGORY,NVL(RETICLE_GROUP_RRN,0) AS " + "RETICLE_GROUP_RRN," + "SPLIT_MERGE_FLAG, " +
                " RUNNING_HOLD_FLAG,OUT_ORDER_TYPE, LOCATION, PLOCATION," + "PLAN_START_DATE,START_HOLD," +
                "AUTO_SPLIT_MERG_FLAG,FLIP_TYPE " + " FROM " + DataBaseNames.LOT_EXT + " WHERE " + "LOT_RRN=?";


        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{lot.getLotRrn()}, new RowMapper<Lot>() {

            @Override
            public Lot mapRow(ResultSet rs, int rowNum) throws SQLException {
                lot.setPollutionLevel(rs.getString("ATTRIBUTE_DATA1"));
                lot.setWiferId(rs.getString("WIFER_ID"));
                lot.setFlowLevel(rs.getString("FLOW_LEVEL"));
                lot.setCustomerId(rs.getString("CUSTOMER_ID"));
                lot.setCustomerLotId(rs.getString("CUSTOMER_LOT_ID"));
                lot.setOuterOrderNO(rs.getString("OUTER_ORDER_NO"));
                lot.setInnerOrderNO(rs.getString("INNER_ORDER_NO"));
                lot.setShippingCode(rs.getString("SHIPPING_CODE"));
                lot.setIsOutSource(rs.getString("IS_OUT_SOURCE"));
                lot.setIsReCreateLot(rs.getString("IS_RECREATE_LOT"));
                lot.setProjectCategory(rs.getString("PROJECT_CATEGORY"));
                lot.setReticleGroupRrn(rs.getLong("RETICLE_GROUP_RRN"));
                lot.setSplitMergeFlag(rs.getString("SPLIT_MERGE_FLAG"));
                lot.setRunningHoldFlag(rs.getString("RUNNING_HOLD_FLAG"));
                lot.setOutOrderType(rs.getString("OUT_ORDER_TYPE"));
                lot.setLocationRrn(rs.getLong("LOCATION"));
                lot.setpLocationRrn(rs.getLong("PLOCATION"));
                lot.setLocation(buildLocationId(rs.getLong("LOCATION")));
                lot.setpLocation(buildLocationId(rs.getLong("PLOCATION")));
                if (StringUtils.isNotBlank(rs.getString("PLAN_START_DATE"))) {
                    lot.setPlanStartDate(new Timestamp(
                            DateUtils.parse(rs.getString("PLAN_START_DATE"), DateUtils.DATE_FORMAT4D).getTime()));
                }
                lot.setStartHold(rs.getString("START_HOLD"));
                lot.setAutoSplitMergFlag(rs.getInt("AUTO_SPLIT_MERG_FLAG"));
                lot.setFlipType(rs.getString("FLIP_TYPE"));
                return lot;
            }
        });
    }

    @Override
    public List<Map> getAvailableLotListWithExt(String wheresql, int limit) {
        StringBuffer new_sql = new StringBuffer();
        new_sql.append("select * from (").append(getLotExtSql()).append(wheresql)
               .append(") al order by TIME_REMAINING, PRIORITY, QUEUE_TIMESTAMP, HOT_FLAG DESC");

        String sql = new_sql.toString();
        if (limit > 0) {
            sql = " select * from (" + sql + " ) where rownum <=? ";
        }
        return jdbcTemplate.query(sql, new Object[]{limit}, (RowMapper<Map>) (rs, rowNum) -> {
            Map<String, Object> lot = new HashMap<>();
            lot.put("lotRrn", rs.getString("LOT_RRN"));
            lot.put("lotId", rs.getString("LOT_ID"));
            lot.put("lotStatus", rs.getString("LOT_STATUS"));
            lot.put("lotType", rs.getString("LOT_TYPE"));
            lot.put("hotFlag", "1".equals(rs.getString("HOT_FLAG")) ? "Y" : "N");
            lot.put("hotFlagCode", rs.getString("HOT_FLAG"));
            lot.put("priority", rs.getString("PRIORITY"));
            lot.put("carrierRrn", rs.getString("CARRIER_RRN"));
            lot.put("qty1", rs.getString("QTY1"));
            lot.put("qty2", rs.getString("QTY2"));
            lot.put("dummyQty1", rs.getInt("dummy_qty1"));
            lot.put("dummyFlag", rs.getString("DUMMY_FLAG"));
            if (rs.getString("EQPT_RRN") == null) {
                lot.put("equipmentRrn", "");
            } else {
                lot.put("equipmentRrn", rs.getString("EQPT_RRN"));
            }
            lot.put("operationRrn", new Long(rs.getString("OPERATION_RRN")));
            lot.put("operationVersion", rs.getString("OPERATION_VERSION"));
            lot.put("reticleRrn", rs.getString("reticle_rrn"));
            lot.put("routeRrn", WipUtils.getRouteByProcessStepVersion(rs.getString("PROCESS_STEP_VERSION"))[0]);
            lot.put("routeId", WipUtils.getRouteByProcessStepVersion(rs.getString("PROCESS_STEP_ID_VERSION"))[0]);
            lot.put("recipeRrn", rs.getString("TEMP_RECIPE_STRING"));
            lot.put("productRrn", rs.getLong("PRODUCT_RRN"));
            lot.put("processRrn", rs.getLong("PROCESS_RRN"));
            lot.put("facilityRrn", rs.getLong("FACILITY_RRN"));
            long spent = System.currentTimeMillis() / 1000 - (rs.getTimestamp("QUEUE_TIMESTAMP")).getTime() / 1000;
            lot.put("queueTimestamp", spent / 60);
            lot.put("jobRrn", rs.getString("JOB_RRN"));
            lot.put("createdTimestamp",
                    (rs.getTimestamp("CREATED_TIMESTAMP") == null) ? 0 : rs.getTimestamp("CREATED_TIMESTAMP")
                                                                           .getTime());
            lot.put("dueDate", (rs.getTimestamp("DUE_DATE") == null) ? 0 : rs.getTimestamp("DUE_DATE").getTime());
            lot.put("estimatedRemainTime", rs.getLong("ESTIMATED_REMAIN_TIME"));
            lot.put("pollutionLevel", rs.getString("ATTRIBUTE_DATA1"));// 污染等级
            lot.put("timeLimit", rs.getString("TIME_REMAINING") == null ? "" : rs.getString("TIME_REMAINING"));
            lot.put("productLayer", rs.getString("product_layer"));
            lot.put("routeSeq", rs.getString("ROUTE_SEQ"));
            lot.put("operationSeq", rs.getString("OPERATION_SEQ"));
            lot.put("processVersion", rs.getString("PROCESS_VERSION"));
            return lot;
        });
    }

    @Override
    public Lot getLotByCarrierId(Long carrierRrn) {
        String sql = getLotSql() + " WHERE CARRIER_RRN = ?";
        return getLot(sql, carrierRrn, LocalContext.getFacilityRrn(), null);
    }

    @Override
    public List<Lot> getLotListByCarrierRrn(Long carrierRrn) {
        String sql = getLotSql() + " WHERE CARRIER_RRN = ?";
        return jdbcTemplate.query(sql, new LotMapper(), carrierRrn);
    }

    @Override
    public Map<String, Object> getLotCountInfo(Map lotPortalFormMap) {
        lotPortalFormMap = buildLotPortalConditionMap(lotPortalFormMap);
        Map<String, Object> sqlMap = this.getLotCountSql(lotPortalFormMap);
        String sql = MapUtils.getString(sqlMap, "sql");
        List<Object> argList = (List<Object>) MapUtils.getObject(sqlMap, "argList");

        return jdbcTemplate.queryForObject(sql, new RowMapper<Map<String, Object>>() {
            @Override
            public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map<String, Object> map = new HashMap();
                map.put("lotCount", rs.getInt("LOT_COUNT"));
                String qtyCountStr = rs.getString("QTY_COUNT");
                if (StringUtils.isBlank(qtyCountStr)) {
                    qtyCountStr = "0";
                }
                map.put("qtyCount", Integer.valueOf(qtyCountStr));
                return map;
            }
        }, argList.toArray());
    }

    @Override
    public Lot getLot(String lotSql, long lotRrn, long facilityRrn, String lotId) {
        List<Object> args = new ArrayList<>();
        if (lotRrn > 0) {
            args.add(lotRrn);
        } else {
            if (lotId == null) {
                return new Lot();
            }
            args.add(facilityRrn);
            args.add(lotId);
        }

        Lot lot = jdbcTemplate.queryForObjectWithNull(lotSql, args.toArray(), new LotMapper());
        if (null == lot) {
            return new Lot();
        }
        lot.setwaitTime(Long.toString(getQueueTime(lot.getLotId())));
        if (lot.getOperationRrn() != null) {
            lot.setUOM1(getUOM1(lot.getOperationRrn()));
            lot.setUOM2(getUOM2(lot.getOperationRrn()));
        }

        String lot_rrn = String.valueOf(lot.getLotRrn());
        Map lotord = getLotOrder(lot_rrn);
        if (MapUtils.isNotEmpty(lotord)) {
            if (lotord.get("order_type").toString().equalsIgnoreCase(ObjectList.ORDER_SUB_ACTUL)) {
                lot.setOrder_id_actul(lotord.get("order_id").toString());
            } else {
                lot.setOrder_id_actul("");
            }
            lot.setMarket_order_Id(lotord.get("market_order_id").toString());
            lot.setCustProdid(getCustId(MapUtils.getLongValue(lotord, "order_rrn")));
        } else {
            lot.setOrder_id_actul("");
            lot.setMarket_order_Id("");
        }
        return lot;
    }

    @Override
    public List getChildLotsForMerge(Lot lot) {
        String sql = " SELECT L.*, '' AS Q_TIME FROM LOT L WHERE LOT_ID like ? AND LOT_ID != ? AND LOT_ID != ? " +
                "AND LOT_STATUS in ('HOLD','WAITING') ORDER BY LOT_ID";

        String lotId = lot.getLotId();
        lotId = lotId.indexOf(".") > 0 ? lotId.substring(0, lotId.indexOf(".")) : lotId;
        List<Object> args = new ArrayList<>();
        args.add(lotId + "%");
        args.add(lotId);
        args.add(lot.getLotId());
        return jdbcTemplate.query(sql, args.toArray(), new LotMapper());
    }

    @Override
    public Long getLotRrn(String lotId, long facilityRrn) {
        String sql = "SELECT LOT_RRN FROM LOT WHERE LOT_ID = ? AND FACILITY_RRN = ?";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{lotId, facilityRrn}, long.class);
    }

    @Override
    public List<Lot> getLotsByEqpWithStatus(long eqpRrn, String... lotStatus) {
        List<Object> args = new ArrayList<>(Arrays.asList(lotStatus));
        String placeholder = StringUtils.strToCommaDelimitedDuplicateString("?", lotStatus.length);
        String sql = getLotSql() + " WHERE LOT_STATUS in (" + placeholder + ") AND EQPT_RRN = ? AND" +
                " (IS_DUMMY_LOT IS NULL OR IS_DUMMY_LOT = '0')";
        args.add(eqpRrn);
        return jdbcTemplate.query(sql, args.toArray(), new LotMapper());
    }

    @Override
    public PlanLot getPlanLot(PlanLot planLot) {
        String sql = null;

        if ((planLot.getLotRrn() != null) && (planLot.getLotRrn().longValue() > 0)) {
            sql = " SELECT plan_lot_rrn,facility_rrn,plan_lot_id,product_rrn," + "default_Process_Rrn," + "hot_flag," +
                    "priority," + "plan_lot_owner,plan_lot_type,due_date,plan_qty1,plan_qty2," + "allocated_qty1," +
                    "allocated_qty2,created_lot_qty1,created_lot_qty2," + "scraped_qty1," + "scraped_qty2,comments" +
                    " " + "FROM PLAN_LOT " + " WHERE plan_lot_rrn =" + planLot.getLotRrn().longValue();
        } else {
            sql = " SELECT plan_lot_rrn,facility_rrn,plan_lot_id,product_rrn," + "default_Process_Rrn," + "hot_flag," +
                    "priority," + "plan_lot_owner,plan_lot_type,due_date,plan_qty1,plan_qty2," + "allocated_qty1," +
                    "allocated_qty2,created_lot_qty1,created_lot_qty2," + "scraped_qty1," + "scraped_qty2,comments" +
                    " " + "FROM PLAN_LOT " + " WHERE facility_rrn =" + planLot.getFacilityRrn() +
                    " AND plan_lot_id ='" + planLot.getLotId() + "'";
        }

        PlanLot lot = jdbcTemplate.queryForObject(sql, new Object[]{}, new RowMapper<PlanLot>() {

            @Override
            public PlanLot mapRow(ResultSet rs, int rowNum) throws SQLException {
                PlanLot planLot = new PlanLot();
                planLot.setLotRrn(new Long(rs.getLong("plan_lot_rrn")));
                planLot.setFacilityRrn(new Long(rs.getLong("facility_rrn")));
                planLot.setLotId(rs.getString("plan_lot_id"));
                planLot.setProductRrn(new Long(rs.getLong("product_rrn")));
                planLot.setDefaultProcessRrn(new Long(rs.getLong("default_Process_Rrn")));
                planLot.setHotFlag(rs.getString("hot_flag"));
                planLot.setPriority(new Short(rs.getShort("priority")));
                planLot.setLotOwner(rs.getString("plan_lot_owner"));
                planLot.setLotType(rs.getString("plan_lot_type"));
                planLot.setQty1(new Double(rs.getDouble("plan_qty1")));
                planLot.setQty2(new Double(rs.getDouble("plan_qty2")));
                planLot.setAllocatedQty1(new Double(rs.getDouble("allocated_qty1")));
                planLot.setAllocatedQty2(new Double(rs.getDouble("allocated_qty2")));
                planLot.setCreatedLotQty1(new Double(rs.getDouble("created_lot_qty1")));
                planLot.setCreatedLotQty2(new Double(rs.getDouble("created_lot_qty2")));
                planLot.setScrapedQty1(new Double(rs.getDouble("scraped_qty1")));
                planLot.setScrapedQty2(new Double(rs.getDouble("scraped_qty2")));

                if (rs.getTimestamp("due_date") != null) {
                    planLot.setDate(DateUtils.formatDate(rs.getTimestamp("due_date")));
                }

                planLot.setComments(rs.getString("comments"));
                return planLot;
            }
        });
        return lot;
    }

    @Override
    public Lot getLotPlan(String lotId) {
        String lotSql = "SELECT LOT_RRN,FACILITY_RRN,LOT_ID,BASED_LOT_RRN,HOT_FLAG,PRIORITY,STARTED_FLAG," +
                "STARTED_TIMESTAMP,CREATE_CATEGORY," + "CREATED_TIMESTAMP,END_TIMESTAMP,DUE_DATE," +
                "SCHEDULE_DUE_DATE," + "ESTIMATED_REMAIN_TIME,DUMMY_FLAG,LOT_TYPE,LOT_OWNER,QTY1,QTY2," +
                "DUMMY_QTY1,INPUT_QTY1,INPUT_QTY2," + "SUBCONTRACTOR_RRN,LOT_COMMENTS," + "STEP_SEQUENCE," +
                "STEP_NUMBER_IN_PROCESS,HOLD_TIMESTAMP," + "REWORK_TRANS_RRN," + "REWORK_CATEGORY,CARRIER_RRN," +
                "BEFORE_STATUS,LOT_STATUS,PROCESSING_STATUS," +
                "QUEUE_TIMESTAMP,PRODUCT_RRN, PRODUCT_VERSION,PROCESS_RRN," + "PROCESS_VERSION,PROCESS_STEP_VERSION," +
                "PROCESS_STEP_ID_VERSION,PREV_OPERATION_RRN," + "PREV_OPERATION_VERSION," + "OPERATION_RRN," +
                "OPERATION_VERSION,NEXT_STEP_VERSION1," + "NEXT_STEP_ID_VERSION1," + "NEXT_OPERATION_RRN1," +
                "NEXT_STEP_VERSION2," + "NEXT_STEP_ID_VERSION2,NEXT_OPERATION_RRN2,STAGE_ID,LAYER_ID," + "BOR_RRN," +
                "EQPT_RRN," + "RECIPE_STRING,NEXT_RECIPE_STRING1,NEXT_RECIPE_STRING2," + "JOB_RRN,NEXT_JOB_RRN1," +
                "NEXT_JOB_RRN2,WFL_STEP_PATH,EXECUTION_RRN,RETICLE_RRN," + "SHIPPED_QTY1,SHIPPED_QTY2," + "WIFER_ID," +
                "WIFER_TYPE,FLOW_LEVEL,CUSTOMER_ID,CUSTOMER_LOT_ID,CUSTOMER_WAFER_ID," + "WAFERSTARTTIME," +
                "OUTERORDERNO,INNERORDERNO,SHIPPINGCODE,ISOUTSOURCE,ISRECREATELOT, " + "PROJECT_CATEGORY,NVL" +
                "(RETICLE_GROUP_RRN,0) AS RETICLE_GROUP_RRN,LOT_PLAN_TYPE," + "MATERIALINFO," + "OUT_ORDER_TYPE," +
                " " + "START_HOLD, PLAN_START_DATE FROM LOT_PLAN WHERE " + "LOT_ID=?";

        return jdbcTemplate.queryForObjectWithNull(lotSql, new Object[]{lotId}, new RowMapper<Lot>() {

            @Override
            public Lot mapRow(ResultSet rs, int rowNum) throws SQLException {

                Lot lot = new Lot();
                lot.setLotRrn(rs.getLong("LOT_RRN"));
                lot.setFacilityRrn(rs.getLong("FACILITY_RRN"));
                lot.setLotId(rs.getString("LOT_ID"));
                lot.setHotFlag(rs.getString("HOT_FLAG"));
                lot.setPriority(rs.getInt("PRIORITY"));
                lot.setStartedFlag(rs.getString("STARTED_FLAG"));
                lot.setStartedTimestamp(rs.getTimestamp("STARTED_TIMESTAMP"));
                lot.setCreateCategory(rs.getString("CREATE_CATEGORY"));
                lot.setEndTimestamp(rs.getTimestamp("END_TIMESTAMP"));
                lot.setDueDate(DateUtils.stringToTimestamp(rs.getString("DUE_DATE")));
                lot.setScheduleDueDate(rs.getTimestamp("SCHEDULE_DUE_DATE"));
                lot.setEstimatedRemainTime(rs.getLong("ESTIMATED_REMAIN_TIME"));
                lot.setDummyFlag(rs.getString("DUMMY_FLAG"));
                lot.setLotType(rs.getString("LOT_TYPE"));
                lot.setLotOwner(rs.getString("LOT_OWNER"));
                lot.setQty1(rs.getDouble("QTY1"));
                lot.setQty2(rs.getDouble("QTY2"));
                lot.setDummyQty1(rs.getInt("DUMMY_QTY1"));
                lot.setInputQty1(rs.getDouble("INPUT_QTY1"));
                lot.setInputQty2(rs.getDouble("INPUT_QTY2"));
                lot.setSubcontractorRrn(rs.getLong("SUBCONTRACTOR_RRN"));
                lot.setLotComments(rs.getString("LOT_COMMENTS"));
                lot.setStepSequence(rs.getLong("STEP_SEQUENCE"));
                lot.setStepNumberInProcess(rs.getLong("STEP_NUMBER_IN_PROCESS"));
                lot.setHoldTimestamp(rs.getTimestamp("HOLD_TIMESTAMP"));
                lot.setReworkCategory(rs.getString("REWORK_CATEGORY"));
                lot.setCarrierRrn(rs.getLong("CARRIER_RRN"));
                lot.setBeforeStatus(rs.getString("BEFORE_STATUS"));
                lot.setLotStatus(rs.getString("LOT_STATUS"));
                lot.setProcessingStatus(rs.getString("PROCESSING_STATUS"));

                lot.setQueueTimestamp(DateUtils.stringToTimestamp(rs.getString("QUEUE_TIMESTAMP")));
                long v_queue_time = getqueueTime(rs.getString("LOT_ID"));
                lot.setWaitTime(Long.toString(v_queue_time));
                lot.setProductRrn(rs.getLong("PRODUCT_RRN"));
                lot.setProductVersion(rs.getInt("PRODUCT_VERSION"));
                lot.setProcessRrn(rs.getLong("PROCESS_RRN"));
                lot.setProcessVersion(rs.getInt("PROCESS_VERSION"));
                lot.setProcessStepVersion(rs.getString("PROCESS_STEP_VERSION"));
                lot.setProcessStepIdVersion(rs.getString("PROCESS_STEP_ID_VERSION"));
                lot.setWflStepPath(rs.getString("WFL_STEP_PATH"));
                lot.setOperationRrn(rs.getLong("OPERATION_RRN"));

                if (lot.getOperationRrn() != null) {
                    lot.setUOM1(getUOM1(lot.getOperationRrn()));
                    lot.setUOM2(getUOM2(lot.getOperationRrn()));
                }

                lot.setOperationVersion(rs.getInt("OPERATION_VERSION"));
                lot.setNextStepVersion1(rs.getString("NEXT_STEP_VERSION1"));
                lot.setNextStepIdVersion1(rs.getString("NEXT_STEP_ID_VERSION1"));
                lot.setNextOperationRrn1(rs.getLong("NEXT_OPERATION_RRN1"));

                lot.setNextStepVersion2(rs.getString("NEXT_STEP_VERSION2"));
                lot.setNextStepIdVersion2(rs.getString("NEXT_STEP_ID_VERSION2"));
                lot.setNextOperationRrn2(rs.getLong("NEXT_OPERATION_RRN2"));
                lot.setStageId(rs.getString("STAGE_ID"));
                lot.setLayerId(rs.getString("LAYER_ID"));
                lot.setBorRrn(rs.getLong("BOR_RRN"));
                lot.setEqptRrn(rs.getLong("EQPT_RRN"));
                lot.setReticleRrn(rs.getLong("reticle_rrn"));
                lot.setRecipeString(rs.getString("RECIPE_STRING"));
                lot.setNextRecipeString1(rs.getString("NEXT_RECIPE_STRING1"));
                lot.setNextRecipeString2(rs.getString("NEXT_RECIPE_STRING2"));
                lot.setJobRrn(rs.getLong("JOB_RRN"));
                lot.setNextJobRrn1(rs.getLong("NEXT_JOB_RRN1"));
                lot.setNextJobRrn2(rs.getLong("NEXT_JOB_RRN2"));
                lot.setExecutionRrn(rs.getLong("EXECUTION_RRN"));
                lot.setLotRrn(rs.getLong("LOT_RRN"));
                lot.setShippedQty1(rs.getDouble("SHIPPED_QTY1"));
                lot.setShippedQty2(rs.getDouble("SHIPPED_QTY2"));

                lot.setWiferId(rs.getString("WIFER_ID"));
                lot.setWaferType(rs.getString("WIFER_TYPE"));
                lot.setFlowLevel(rs.getString("FLOW_LEVEL"));
                lot.setCustomerId(rs.getString("CUSTOMER_ID"));
                lot.setCustomerLotId(rs.getString("CUSTOMER_LOT_ID"));
                lot.setCustomerWaferId(rs.getString("CUSTOMER_WAFER_ID"));
                lot.setWaferStartTime(rs.getString("WAFERSTARTTIME"));
                lot.setOuterOrderNO(rs.getString("OUTERORDERNO"));
                lot.setInnerOrderNO(rs.getString("INNERORDERNO"));
                lot.setShippingCode(rs.getString("SHIPPINGCODE"));
                lot.setIsOutSource(rs.getString("ISOUTSOURCE"));
                lot.setIsReCreateLot(rs.getString("ISRECREATELOT"));
                lot.setProjectCategory(rs.getString("PROJECT_CATEGORY"));
                lot.setLotPlanType(
                        rs.getString("LOT_PLAN_TYPE") == null ? StringUtils.EMPTY : rs.getString("lot_plan_type"));
                lot.setReticleGroupRrn(rs.getLong("RETICLE_GROUP_RRN"));
                lot.setMaterialinfo(rs.getString("materialinfo"));
                lot.setOutOrderType(rs.getString("OUT_ORDER_TYPE"));
                lot.setStartHold(rs.getString("START_HOLD"));
                lot.setPlanStartDate(StringUtils.isEmpty(rs.getString("PLAN_START_DATE")) ? null : DateUtils
                        .stringToTimestamp(rs.getString("PLAN_START_DATE")));
                return lot;
            }
        });
    }

    @Override
    public Long getlotRrnByExecutionRrn(Long executionRrn) {
        String sql = "SELECT L.LOT_RRN FROM LOT L,WORKFLOW_EXECUTION T WHERE L.EXECUTION_RRN=T" + ".EXECUTION_RRN AND" +
                " L.EXECUTION_RRN = ?";
        return jdbcTemplate.queryForObjectWithNull(sql, Long.class, executionRrn);
    }

    @Override
    public Page queryLotStepHistory(Page page, Long lotRrn) {
        long thisPage = page.getPageNo();
        long pageSize = page.getPageSize();
        List<Object> args = new ArrayList<Object>();

        StringBuilder sql = new StringBuilder(" SELECT t.*, s.step_comment FROM ");
        sql.append("  (SELECT * FROM LOT_STEP_HISTORY WHERE lot_rrn = ? ORDER BY step_sequence DESC ) t,");
        sql.append(" (SELECT * FROM lot_step_history_comment c WHERE lot_rrn = ? AND c.comment_sequence = 1) s" + " ");
        sql.append(" WHERE  t.step_sequence = s.step_sequence(+) ORDER BY t.step_sequence DESC ");

        args.add(lotRrn);
        args.add(lotRrn);

        return jdbcTemplate.queryForPage(page, sql.toString(), args.toArray(), new RowMapper<Map<String, Object>>() {
            @Override
            public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map<String, Object> map = new HashMap<>();

                map.put("seq", pageSize * (thisPage - 1) + rowNum + 1);
                map.put("lot_Id", rs.getString("LOT_ID"));
                map.put("lot_rrn", rs.getString("LOT_RRN"));
                map.put("facility_rrn", rs.getString("FACILITY_RRN"));
                map.put("eqpt_rrn", rs.getLong("EQPT_RRN"));
                map.put("step_sequence", rs.getString("STEP_SEQUENCE"));
                map.put("recipe_string", rs.getString("RECIPE_STRING"));
                map.put("route_id", parseRoute(rs.getString("PROCESS_STEP_ID_VERSION")));
                map.put("route_rrn", parseRouteRrn(rs.getString("PROCESS_STEP_VERSION")));
                map.put("product_rrn", rs.getLong("PRODUCT_RRN"));
                map.put("operation_rrn", rs.getLong("OPERATION_RRN"));
                map.put("stage_id", rs.getString("STAGE_ID"));
                map.put("layer_id", rs.getString("LAYER_ID"));
                map.put("run_rrn", rs.getLong("RUN_RRN"));
                map.put("rework_flag", rs.getString("REWORK_FLAG"));
                map.put("in_qty1", rs.getString("IN_QTY1"));
                map.put("out_qty1", rs.getString("OUT_QTY1"));
                map.put("bin_rrn", rs.getLong("BIN_RRN"));
                map.put("move_in_dcol_rrn", rs.getString("MOVE_IN_DCOL_RRN"));
                map.put("move_out_dcol_rrn", rs.getString("MOVE_OUT_DCOL_RRN"));
                map.put("ad_hoc_dcol_rrn", rs.getString("AD_HOC_DCOL_RRN"));
                map.put("chamber_type", rs.getString("CHAMBER_TYPE"));
                map.put("step_comment", rs.getString("STEP_COMMENT"));
                //step_comment2这个key是给导出数据时使用的。本来逻辑存在于前台显示
                //但是导出数据不走前台,故在后台做了这个逻辑
                String step_comment2 = rs.getString("STEP_COMMENT");
                map.put("step_comment2", StringUtils.isEmpty(step_comment2) ? "Add" : "Edit");

                map.put("process_rrn", rs.getLong("PROCESS_RRN"));


                return map;
            }
        });
    }

    @Override
    public String getLotId(long lotRrn) {
        String sql = "select lot_id from lot where lot_rrn = ?";
        return jdbcTemplate.queryForObjectWithNull(sql, String.class, lotRrn);
    }

    @Override
    public Page getLotPlanPage(Long facilityRrn, Page page, Map<String, Object> condition) {
        StringBuilder sql = new StringBuilder("SELECT rownum AS RN1, a.* FROM (");

        sql.append(" SELECT al.*, ltl.CREATED_QTY, ltl.TRANS_PERFORMED_BY, ltl.TRANS_START_TIMESTAMP ");
        sql.append(" FROM ");
        sql.append(" (SELECT l.LOT_RRN, l.FACILITY_RRN, l.LOT_ID, l.BASED_LOT_RRN, l.HOT_FLAG, l.PRIORITY, l" +
                           ".STARTED_FLAG, ");
        sql.append(" l.STARTED_TIMESTAMP, l.CREATE_CATEGORY, l.CREATED_TIMESTAMP, l.END_TIMESTAMP, l.DUE_DATE," + " ");
        sql.append(" l.SCHEDULE_DUE_DATE, l.ESTIMATED_REMAIN_TIME, l.DUMMY_FLAG, l.LOT_TYPE, l.LOT_OWNER, ");
        sql.append(
                " l.QTY1, l.QTY2, l.DUMMY_QTY1, l.INPUT_QTY1, l.INPUT_QTY2, l.SUBCONTRACTOR_RRN, l" + ".LOT_COMMENTS," +
                        " ");
        sql.append(" l.STEP_SEQUENCE, l.STEP_NUMBER_IN_PROCESS, l.HOLD_TIMESTAMP, l.REWORK_TRANS_RRN, l" +
                           ".REWORK_CATEGORY, ");
        sql.append(" l.CARRIER_RRN, l.BEFORE_STATUS, l.LOT_STATUS, l.PROCESSING_STATUS, l.QUEUE_TIMESTAMP, l" +
                           ".PRODUCT_RRN, ");
        sql.append(" l.PROCESS_RRN, l.PROCESS_VERSION, l.PROCESS_STEP_VERSION, l.PROCESS_STEP_ID_VERSION, ");
        sql.append(" l.PREV_OPERATION_RRN, l.PREV_OPERATION_VERSION, l.OPERATION_RRN, l.OPERATION_VERSION, ");
        sql.append(
                " l.NEXT_STEP_VERSION1, l.NEXT_STEP_ID_VERSION1, l.NEXT_OPERATION_RRN1, l" + ".NEXT_STEP_VERSION2, ");
        sql.append(
                " l.NEXT_STEP_ID_VERSION2, l.NEXT_OPERATION_RRN2, l.STAGE_ID, l.LAYER_ID, l.BOR_RRN, l" + ".EQPT_RRN," +
                        " ");
        sql.append(" l.RECIPE_STRING, l.NEXT_RECIPE_STRING1, l.NEXT_RECIPE_STRING2, l.JOB_RRN, l" + ".NEXT_JOB_RRN1, ");
        sql.append(" l.NEXT_JOB_RRN2, l.WFL_STEP_PATH, l.EXECUTION_RRN, l.RETICLE_RRN, l.SHIPPED_QTY1, l" +
                           ".SHIPPED_QTY2, ");
        sql.append(
                " l.WIFER_ID, l.WIFER_TYPE, l.FLOW_LEVEL, l.CUSTOMER_ID, l.CUSTOMER_LOT_ID,  l" + ".WAFERSTARTTIME, ");
        sql.append(" l.OUTERORDERNO, l.INNERORDERNO WORK_ORDER_ID, l.SHIPPINGCODE, ");
        sql.append(
                " l.ATTRIBUTE_DATA1, l.ATTRIBUTE_DATA2, l.ATTRIBUTE_DATA3, l.ATTRIBUTE_DATA4, l" + ".ATTRIBUTE_DATA5," +
                        " ");
        sql.append(" l.PROJECT_CATEGORY, l.RETICLE_GROUP_RRN, l.LOT_PLAN_TYPE, l.OUT_ORDER_TYPE, l.START_HOLD," + " l" +
                           ".PLAN_START_DATE, ");
        sql.append(" (SELECT INSTANCE_ID FROM NAMED_OBJECT WHERE INSTANCE_RRN = l.PRODUCT_RRN) AS PRODUCT_ID, ");
        sql.append(" (SELECT INSTANCE_ID FROM NAMED_OBJECT WHERE INSTANCE_RRN = l.PROCESS_RRN) AS PROCESS_ID, ");
        sql.append(" '0' AS WAFER_START_FLAG,l.MATERIALINFO ");
        sql.append(" FROM ").append(DataBaseNames.LOT_PLAN).append(" l ");
        sql.append(" UNION ALL ");
        sql.append(" SELECT l.LOT_RRN, l.FACILITY_RRN, l.LOT_ID, l.BASED_LOT_RRN, l.HOT_FLAG, l.PRIORITY, l" +
                           ".STARTED_FLAG, ");
        sql.append(" TO_CHAR(l.STARTED_TIMESTAMP, '" + DateUtils.DATE_FORMAT24 + "'), l.CREATE_CATEGORY, TO_CHAR(l" +
                           ".CREATED_TIMESTAMP, '" + DateUtils.DATE_FORMAT24 + "'), ");
        sql.append(" TO_CHAR(l.END_TIMESTAMP, '" + DateUtils.DATE_FORMAT24 + "'), TO_CHAR(l.DUE_DATE, '" +
                           DateUtils.DATE_FORMAT4D + "'), ");
        sql.append(" TO_CHAR(l.SCHEDULE_DUE_DATE, '" + DateUtils.DATE_FORMAT24 + "'), l.ESTIMATED_REMAIN_TIME, l" +
                           ".DUMMY_FLAG, l.LOT_TYPE, l.LOT_OWNER, ");
        sql.append(
                " l.QTY1, l.QTY2, l.DUMMY_QTY1, l.INPUT_QTY1, l.INPUT_QTY2, l.SUBCONTRACTOR_RRN, l" + ".LOT_COMMENTS," +
                        " ");
        sql.append(" l.STEP_SEQUENCE, l.STEP_NUMBER_IN_PROCESS, TO_CHAR(l.HOLD_TIMESTAMP, '" + DateUtils.DATE_FORMAT24 +
                           "'), l.REWORK_TRANS_RRN, l.REWORK_CATEGORY, ");
        sql.append(
                " l.CARRIER_RRN, l.BEFORE_STATUS, l.LOT_STATUS, l.PROCESSING_STATUS, TO_CHAR(l" + ".QUEUE_TIMESTAMP, " +
                        "'" + DateUtils.DATE_FORMAT24 + "'), l.PRODUCT_RRN, ");
        sql.append(" l.PROCESS_RRN, l.PROCESS_VERSION, l.PROCESS_STEP_VERSION, l.PROCESS_STEP_ID_VERSION, ");
        sql.append(" l.PREV_OPERATION_RRN, l.PREV_OPERATION_VERSION, l.OPERATION_RRN, l.OPERATION_VERSION, ");
        sql.append(
                " l.NEXT_STEP_VERSION1, l.NEXT_STEP_ID_VERSION1, l.NEXT_OPERATION_RRN1, l" + ".NEXT_STEP_VERSION2, ");
        sql.append(
                " l.NEXT_STEP_ID_VERSION2, l.NEXT_OPERATION_RRN2, l.STAGE_ID, l.LAYER_ID, l.BOR_RRN, l" + ".EQPT_RRN," +
                        " ");
        sql.append(" l.RECIPE_STRING, l.NEXT_RECIPE_STRING1, l.NEXT_RECIPE_STRING2, l.JOB_RRN, l" + ".NEXT_JOB_RRN1, ");
        sql.append(" l.NEXT_JOB_RRN2, l.WFL_STEP_PATH, l.EXECUTION_RRN, l.RETICLE_RRN, l.SHIPPED_QTY1, l" +
                           ".SHIPPED_QTY2, ");
        sql.append(" le.WIFER_ID, le.WIFER_TYPE, le.FLOW_LEVEL, le.CUSTOMER_ID, le.CUSTOMER_LOT_ID, TO_CHAR(le" +
                           ".WAFER_START_TIME, '" + DateUtils.DATE_FORMAT24 + "'), ");
        sql.append(" le.OUTER_ORDER_NO, le.INNER_ORDER_NO WORK_ORDER_ID, le.SHIPPING_CODE, ");
        sql.append(" le.ATTRIBUTE_DATA1, le.ATTRIBUTE_DATA2, le.ATTRIBUTE_DATA3, le.ATTRIBUTE_DATA4, le" +
                           ".ATTRIBUTE_DATA5, ");
        sql.append(
                " le.PROJECT_CATEGORY, le.RETICLE_GROUP_RRN, l.LOT_PLAN_TYPE, le.OUT_ORDER_TYPE, le" + ".START_HOLD, " +
                        "le.PLAN_START_DATE,");
        sql.append(" (SELECT INSTANCE_ID FROM NAMED_OBJECT WHERE INSTANCE_RRN = l.PRODUCT_RRN) AS PRODUCT_ID, ");
        sql.append(" (SELECT INSTANCE_ID FROM NAMED_OBJECT WHERE INSTANCE_RRN = l.PROCESS_RRN) AS PROCESS_ID, ");
        sql.append(" '1' AS WAFER_START_FLAG,lph.MATERIALINFO ");
        sql.append(" FROM ").append(DataBaseNames.LOT).append(" l ");
        sql.append(" LEFT JOIN ").append(DataBaseNames.LOT_EXT).append(" le ON l.LOT_RRN = le.LOT_RRN");
        sql.append(
                " LEFT JOIN (SELECT LPH.MATERIALINFO,LPH.LOT_RRN FROM LOT_PLAN_H LPH, TRANSACTION_LOG TL " + "WHERE " +
                        "LPH.TRANS_RRN = TL.TRANS_RRN AND TL.TRANS_ID = ? )  LPH ");
        sql.append(" ON L.LOT_RRN = LPH.LOT_RRN ");
        sql.append(") al ");
        sql.append(" LEFT JOIN ");
        sql.append(" (SELECT LPH.MATERIALINFO,lph.LOT_RRN, lph.QTY1 AS CREATED_QTY, tl.TRANS_START_TIMESTAMP, tl" +
                           ".TRANS_PERFORMED_BY ");
        sql.append(" FROM ").append(DataBaseNames.LOT_PLAN_H).append(" lph, ").append(DataBaseNames.TRANSACTION_LOG)
           .append(" tl ");
        sql.append(" WHERE lph.TRANS_RRN = tl.TRANS_RRN AND tl.TRANS_ID = ?) ltl ");
        sql.append(" ON al.LOT_RRN = ltl.LOT_RRN ");
        sql.append(" WHERE FACILITY_RRN = ? ");

        List<Object> args = new ArrayList<>();
        args.add(TransactionNames.CREATELOT_KEY);
        args.add(TransactionNames.LOT_PLAN);
        args.add(facilityRrn);

        if (condition != null) {
            String temp = MapUtils.getString(condition, "lotId");
            if (StringUtils.isNotEmpty(temp)) {
                sql.append(" AND LOT_ID LIKE ? ");
                args.add(temp.replace("*", "%"));
            }
            temp = MapUtils.getString(condition, "lotType");
            if (StringUtils.isNotEmpty(temp)) {
                sql.append(" AND LOT_TYPE = ? ");
                args.add(temp);
            }
            temp = MapUtils.getString(condition, "productId");
            if (StringUtils.isNotEmpty(temp)) {
                sql.append(" AND PRODUCT_ID LIKE ? ");
                args.add(temp.replace("*", "%"));
            }
            temp = MapUtils.getString(condition, "processId");
            if (StringUtils.isNotEmpty(temp)) {
                sql.append(" AND PROCESS_ID LIKE ? ");
                args.add(temp.replace("*", "%"));
            }
            temp = MapUtils.getString(condition, "priority");
            if (StringUtils.isNotEmpty(temp) && temp.indexOf('-') != -1) {
                String[] pris = temp.split("-");
                if (pris != null && pris.length == 2) {
                    sql.append(" AND HOT_FLAG = ? ");
                    if (StringUtils.equals("0", pris[1])) {
                        sql.append(" AND (PRIORITY = ? or PRIORITY is null) ");
                    } else {
                        sql.append(" AND PRIORITY = ?  ");
                    }
                    args.add(pris[0]);
                    args.add(NumberUtils.toInt(pris[1]));
                }
            }
            temp = MapUtils.getString(condition, "outerOrderNo");
            if (StringUtils.isNotEmpty(temp)) {
                sql.append(" AND OUTERORDERNO = ? ");
                args.add(temp);
            }
            temp = MapUtils.getString(condition, "outOrderType");
            if (StringUtils.isNotEmpty(temp)) {
                sql.append(" AND OUT_ORDER_TYPE = ? ");
                args.add(temp);
            }
            temp = MapUtils.getString(condition, "workOrderId");
            if (StringUtils.isNotEmpty(temp)) {
                sql.append(" AND WORK_ORDER_ID LIKE ? ");
                args.add(temp.replace("*", "%"));
            }
            temp = MapUtils.getString(condition, "shippingCode");
            if (StringUtils.isNotEmpty(temp)) {
                sql.append(" AND SHIPPINGCODE = ? ");
                args.add(temp);
            }
            temp = MapUtils.getString(condition, "customerId");
            if (StringUtils.isNotEmpty(temp)) {
                sql.append(" AND CUSTOMER_ID = ? ");
                args.add(temp);
            }
            temp = MapUtils.getString(condition, "waferQty");
            if (StringUtils.isNotEmpty(temp)) {
                sql.append(" AND QTY1 = ? ");
                args.add(NumberUtils.toInt(temp));
            }
            temp = MapUtils.getString(condition, "startDueDate");
            if (StringUtils.isNotEmpty(temp)) {
                sql.append(" AND TRANS_START_TIMESTAMP >= ? ");
                args.add(DateUtils.stringToTimestamp(temp));
            }
            temp = MapUtils.getString(condition, "endDueDate");
            if (StringUtils.isNotEmpty(temp)) {
                sql.append(" AND TRANS_START_TIMESTAMP <= ? ");
                args.add(DateUtils.stringToTimestamp(temp + " 23:59:59"));
            }
            temp = MapUtils.getString(condition, "lotOwner");
            if (StringUtils.isNotEmpty(temp)) {
                sql.append(" AND LOT_OWNER = ? ");
                args.add(temp);
            }
            temp = MapUtils.getString(condition, "lotCategory");
            if (StringUtils.isNotEmpty(temp)) {
                sql.append(" AND CREATE_CATEGORY = ? ");
                args.add(temp);
            }
            temp = MapUtils.getString(condition, "waferStartFlag");
            if (StringUtils.isNotEmpty(temp)) {
                sql.append(" AND WAFER_START_FLAG = ? ");
                args.add(temp);
            }

            temp = MapUtils.getString(condition, "materialinfo");
            if (StringUtils.isNotEmpty(temp)) {
                sql.append(" AND AL.materialinfo like ? ");
                args.add(temp.replace("*", "%"));
            }

            temp = MapUtils.getString(condition, "lotStatus");
            if (StringUtils.isNotEmpty(temp)) {
                if (temp.equalsIgnoreCase("HOLD")) {
                    sql.append(" AND LOT_STATUS IN ('" + LotStatus.RUNNINGHOLD + "','" + LotStatus.HOLD + "') ");
                } else {
                    sql.append(" AND LOT_STATUS = ? ");
                    args.add(temp);
                }

            }
        }

        //sql.append(" ORDER BY LOT_TYPE, TRANS_START_TIMESTAMP DESC) a ");
        sql.append(" ORDER BY PLAN_START_DATE,AL.LOT_RRN ) a");

        return jdbcTemplate.queryForPage(page, sql.toString(), args.toArray(), new RowMapper<Map<String, Object>>() {

            Map<String, Object> map;

            long tempLong;

            @Override
            public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
                map = new HashMap<>();

                map.put("lotRrn", rs.getLong("LOT_RRN"));
                map.put("facilityRrn", rs.getLong("FACILITY_RRN"));
                map.put("lotId", rs.getString("LOT_ID"));

                map.put("createCategory", rs.getString("CREATE_CATEGORY"));
                map.put("lotType", rs.getString("LOT_TYPE"));
                map.put("lotOwner", rs.getString("LOT_OWNER"));
                map.put("lotStatus", rs.getString("LOT_STATUS"));
                String dueTime = "";
                if (StringUtils.isNotBlank(rs.getString("DUE_DATE"))) {
                    int lastIndex = rs.getString("DUE_DATE").lastIndexOf("/");
                    dueTime = rs.getString("DUE_DATE").substring(0, lastIndex + 3);

                }
                map.put("dueDate", dueTime);
                map.put("hotFlag", rs.getString("HOT_FLAG"));
                map.put("priority", StringUtils.isEmpty(rs.getString("PRIORITY")) ? 0 : rs.getString("PRIORITY"));
                map.put("qty1", rs.getString("QTY1"));
                map.put("outerOrderNo", rs.getString("OUTERORDERNO"));
                map.put("workOrderId", rs.getString("WORK_ORDER_ID"));
                map.put("outOrderType", rs.getString("OUT_ORDER_TYPE"));
                map.put("shippingCode", rs.getString("SHIPPINGCODE"));
                map.put("customerId", rs.getString("CUSTOMER_ID"));

                map.put("productRrn", rs.getLong("PRODUCT_RRN"));
                map.put("productId", rs.getString("PRODUCT_ID"));
                map.put("processRrn", rs.getLong("PROCESS_RRN"));
                map.put("processId", rs.getString("PROCESS_ID"));
                map.put("processVersion", rs.getInt("PROCESS_VERSION"));
                map.put("processStepVersion", rs.getString("PROCESS_STEP_VERSION"));
                map.put("operationRrn", rs.getLong("OPERATION_RRN"));
                map.put("stageId", rs.getString("STAGE_ID"));
                map.put("waferStartFlag", rs.getString("WAFER_START_FLAG"));

                map.put("createdQty", rs.getDouble("CREATED_QTY"));
                map.put("createdTime", DateUtils.formatDate(rs.getTimestamp("TRANS_START_TIMESTAMP")));
                map.put("createdUserId", rs.getString("TRANS_PERFORMED_BY"));
                map.put("startHold", rs.getString("START_HOLD"));
                String planStartTime = "";
                if (StringUtils.isNotBlank(rs.getString("PLAN_START_DATE"))) {
                    int lastIndex = rs.getString("PLAN_START_DATE").lastIndexOf("/");
                    planStartTime = rs.getString("PLAN_START_DATE").substring(0, lastIndex + 3);

                }
                map.put("planStartDate", planStartTime);
                map.put("materialinfo", rs.getString("materialinfo"));
                map.put("materialNO", rs.getString("materialinfo"));
                return map;
            }
        });
    }

    @Override
    public boolean checkLotStatus(Long recipeRrn, long entityRrn) {
        String countSql = " SELECT COUNT(L.LOT_ID) FROM LOT L WHERE L.RECIPE_LOGICAL_RRN=? AND L.EQPT_RRN=?" + " AND " +
                "L.LOT_STATUS IN(?,?,?,?)";
        int resultCount = jdbcTemplate.queryForObject(countSql, new Object[]{recipeRrn, entityRrn, LotStatus.RUNNING,
                                                                             LotStatus.DISPATCH, LotStatus.PROCESSED,
                                                                             LotStatus.RUNNINGHOLD}, int.class);
        return resultCount > 0;
    }

    @Override
    public Map getLotInfoasMap(long facilityRrn, String lotId, Long carrierRrn) {

        String sql = " SELECT t1.lot_rrn,facility_rrn,lot_id,hot_flag,dummy_qty1,t1.rework_category," + " priority," +
                "created_timestamp,due_date,qty1,qty2,carrier_rrn," +
                " lot_type,lot_owner,eqpt_rrn,stage_id,recipe_string," + "eqpt_rrn,layer_id," +
                " product_rrn,process_rrn,operation_rrn,process_step_id_version,lot_status," +
                "PROCESS_STEP_VERSION,queue_timestamp" + " ,based_lot_rrn,carrier_rrn,product_layer,route_seq," +
                "operation_seq,process_version," + "t2.outer_order_no,t2.inner_order_no " + " ,recipe_logical_rrn," +
                "recipe_physical_id,chamber_type, t1.operation_seq, t2" + ".split_merge_flag, t1.WFL_STEP_PATH" +
                " ,t1" + ".prev_operation_rrn " + " FROM lot t1,lot_ext t2 " +
                " WHERE t1.lot_rrn=t2.lot_rrn and facility_rrn =" + facilityRrn;
        if (lotId != null && !lotId.equals("")) {
            sql += " AND lot_id ='" + lotId + "'";
        }
        if (carrierRrn != null && carrierRrn.longValue() > 0) {
            sql += " AND carrier_rrn ='" + carrierRrn + "'";
        }
        if (StringUtils.isEmpty(lotId) && carrierRrn.longValue() <= 0) {
            return null;
        }

        List lotInfo = jdbcTemplate.query(sql, new Object[]{}, new RowMapper<Map<String, Object>>() {

            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map lot = new HashMap();
                long queueTime = 0;

                String lotId = rs.getString("lot_id");

                queueTime = getqueueTime(lotId);

                lot.put("WaitTime", new Long(queueTime).toString());
                lot.put("waitTime", new Long(queueTime).toString());

                lot.put("lotId", lotId);
                lot.put("lotRrn", rs.getLong("lot_rrn"));
                lot.put("carrier_rrn", rs.getLong("carrier_rrn"));
                lot.put("layerId", rs.getString("layer_id"));

                if (rs.getLong("product_rrn") > 0) {
                    lot.put("productRrn", rs.getLong("product_rrn") + "");
                }

                if (rs.getLong("process_rrn") > 0) {
                    lot.put("processRrn", rs.getLong("process_rrn") + "");
                    lot.put("processVersion", rs.getString("process_version"));
                }

                if (rs.getLong("operation_rrn") > 0) {
                    lot.put("operation_rrn", rs.getLong("operation_rrn"));
                }

                if (rs.getString("process_step_id_version") != null) {
                    String processStepIdVer = rs.getString("process_step_id_version");
                    lot.put("route_id", parseRoute(processStepIdVer));
                    lot.put("routeId", parseRoute(processStepIdVer));
                } else {
                    lot.put("route_id", "");
                    lot.put("routeId", "");
                }

                if (rs.getLong("eqpt_rrn") > 0) {
                    lot.put("equipmentRrn", new Long(rs.getLong("eqpt_rrn")));
                } else {
                    lot.put("equipmentId", "");
                }

                // to do: add unit of measurement cotrol
                lot.put("lot_type", rs.getString("lot_type"));
                lot.put("lotType", rs.getString("lot_type"));
                lot.put("lot_owner", rs.getString("lot_owner"));
                lot.put("lotOwner", rs.getString("lot_owner"));
                lot.put("qty", new Double(rs.getDouble("qty1")));

                // avoid to mix original code
                lot.put("qty1", new Double(rs.getDouble("qty1")));
                lot.put("qty2", new Double(rs.getDouble("qty2")));
                lot.put("intQty1", new Double(rs.getDouble("qty1")));
                lot.put("intQty2", new Double(rs.getDouble("qty2")));
                lot.put("dummyQty1", new Integer(rs.getInt("dummy_qty1")));
                lot.put("hotflag", rs.getString("hot_flag"));
                lot.put("priority", new Short(rs.getShort("priority")));
                lot.put("duedate", rs.getDate("due_date"));
                lot.put("dueDate", rs.getTimestamp("due_date"));
                lot.put("createddate", rs.getTimestamp("created_timestamp"));
                lot.put("lot_status", rs.getString("lot_status"));
                String lotStatus = rs.getString("lot_status");
                lot.put("lotStatus", lotStatus);
                lot.put("parseOperation", parseOperation(rs.getString("PROCESS_STEP_ID_VERSION")));
                lot.put("stageId", rs.getString("stage_id"));
                lot.put("operationSeq", rs.getString("operation_seq"));
                lot.put("splitMergeFlag", rs.getString("split_merge_flag"));
                lot.put("wflStepPath", rs.getString("WFL_STEP_PATH"));

                String processStepString = rs.getString("PROCESS_STEP_VERSION");

                Lot lot1 = new Lot();
                lot1.setLotStatus(lotStatus);
                lot1.setOperationRrn(rs.getLong("prev_operation_rrn"));
                if (StringUtils.equalsIgnoreCase(LotStatus.BANKED, lotStatus) ||
                        StringUtils.equalsIgnoreCase(LotStatus.OUTSOURCING, lotStatus)) {
                    lot1.setOperationRrn(rs.getLong("operation_rrn"));
                    lot1.setPrevOperationRrn(rs.getLong("prev_operation_rrn"));
                }
                lot1.setProductRrn(rs.getLong("product_rrn"));
                lot1.setProcessRrn(rs.getLong("process_rrn"));
                lot1.setLotRrn(rs.getLong("lot_rrn"));
                lot1.setLotId(lotId);
                lot1.setEqptRrn(rs.getLong("eqpt_rrn"));
                lot1.setFacilityRrn(rs.getLong("facility_rrn"));
                lot1.setRouteRrn(parseRouteRrn(processStepString));
                lot1.setRouteSeq(rs.getString("route_seq"));
                lot1.setProductLayer(rs.getString("product_layer"));
                lot1.setOperationSeq(rs.getString("operation_seq"));
                lot1.setProcessVersion(rs.getInt("PROCESS_VERSION"));
                lot.put("tempLot", lot1);

                long recipeLogicalRrn = rs.getLong("recipe_logical_rrn");
                lot.put("recipeLogicalRrn", recipeLogicalRrn);
                lot.put("facilityRrn", rs.getLong("facility_rrn"));
                lot.put("basedLotRrn", rs.getLong("based_lot_rrn"));
                lot.put("carrierRrn", rs.getLong("carrier_rrn"));
                lot.put("outerOrderNO", StringUtils.trimToEmpty(rs.getString("outer_order_no")));
                lot.put("innerOrderNO", StringUtils.trimToEmpty(rs.getString("inner_order_no")));
                lot.put("reworkFlag", StringUtils.isNotBlank(rs.getString("rework_category")));

                return lot;
            }
        });
        return (lotInfo.size() > 0 ? (Map) lotInfo.get(0) : null);

    }

    @Override
    public Map getLotInfoasMap(long facilityRrn, String lotId) {
        String sql = " SELECT t1.lot_rrn,facility_rrn,lot_id,hot_flag,dummy_qty1," + " priority,created_timestamp," +
                "due_date,qty1,qty2,carrier_rrn," +
                " lot_type,lot_owner,eqpt_rrn,stage_id,recipe_string,eqpt_rrn,layer_id," +
                " product_rrn,process_rrn,operation_rrn,process_step_id_version,lot_status," +
                "PROCESS_STEP_VERSION,queue_timestamp" +
                " ,based_lot_rrn,carrier_rrn,product_layer,process_version,t2.outer_order_no,t2" + ".inner_order_no " +
                " ,recipe_logical_rrn,recipe_physical_id,chamber_type, t1.operation_seq,t1" +
                ".route_seq, t2.split_merge_flag, t1.WFL_STEP_PATH " + " FROM lot t1,lot_ext t2 " +
                " WHERE t1.lot_rrn=t2.lot_rrn and facility_rrn =?" + " AND lot_id =?";

        Map map = jdbcTemplate
                .queryForObjectWithNull(sql, new Object[]{facilityRrn, lotId}, new RowMapper<Map<String, Object>>() {
                    @Override
                    public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
                        Map lot = new HashMap();
                        long v_queue_time = 0;

                        v_queue_time = getqueueTime(lotId);

                        lot.put("WaitTime", new Long(v_queue_time).toString());
                        lot.put("waitTime", new Long(v_queue_time).toString());

                        lot.put("lotId", lotId);
                        lot.put("lotRrn", new Long(rs.getLong("lot_rrn")));


                        lot.put("carrier_rrn", rs.getLong("carrier_rrn"));

                        lot.put("layerId", rs.getString("layer_id"));

                        if (rs.getLong("product_rrn") > 0) {
                            lot.put("productRrn", rs.getLong("product_rrn") + "");
                        }

                        if (rs.getLong("process_rrn") > 0) {
                            lot.put("processRrn", rs.getLong("process_rrn") + "");
                            lot.put("processVersion", rs.getString("process_version"));
                        }

                        if (rs.getLong("operation_rrn") > 0) {
                            lot.put("operation_rrn", rs.getLong("operation_rrn"));
                        }
                        if (rs.getString("process_step_id_version") != null) {
                            String processStepIdVer = rs.getString("process_step_id_version");
                            lot.put("route_id", parseRoute(processStepIdVer));
                            lot.put("routeId", parseRoute(processStepIdVer));
                        } else {
                            lot.put("route_id", "");
                            lot.put("routeId", "");
                        }
                        if (rs.getLong("eqpt_rrn") > 0) {
                            lot.put("equipmentRrn", new Long(rs.getLong("eqpt_rrn")));
                        } else {
                            lot.put("equipmentId", "");
                        }
                        lot.put("lot_type", rs.getString("lot_type"));
                        lot.put("lotType", rs.getString("lot_type"));
                        lot.put("lot_owner", rs.getString("lot_owner"));
                        lot.put("lotOwner", rs.getString("lot_owner"));
                        lot.put("qty", new Double(rs.getDouble("qty1")));

                        lot.put("qty1", new Double(rs.getDouble("qty1")));
                        lot.put("qty2", new Double(rs.getDouble("qty2")));
                        lot.put("intQty1", new Double(rs.getDouble("qty1")));
                        lot.put("intQty2", new Double(rs.getDouble("qty2")));
                        lot.put("dummyQty1", new Integer(rs.getInt("dummy_qty1")));
                        lot.put("hotflag", rs.getString("hot_flag"));
                        lot.put("priority", new Short(rs.getShort("priority")));
                        lot.put("duedate", rs.getDate("due_date"));
                        lot.put("dueDate", rs.getTimestamp("due_date"));
                        lot.put("createddate", rs.getTimestamp("created_timestamp"));
                        lot.put("lot_status", rs.getString("lot_status"));
                        lot.put("lotStatus", rs.getString("lot_status"));
                        lot.put("parseOperation", parseOperation(rs.getString("PROCESS_STEP_ID_VERSION")));
                        lot.put("stageId", rs.getString("stage_id"));
                        lot.put("operationSeq", rs.getString("operation_seq"));
                        lot.put("routeSeq", rs.getString("route_seq"));
                        lot.put("splitMergeFlag", rs.getString("split_merge_flag"));
                        lot.put("wflStepPath", rs.getString("WFL_STEP_PATH"));

                        String processStepString = rs.getString("PROCESS_STEP_VERSION");
                        int firstSep = 0;
                        int secondSep = 0;
                        String routeRrn = "";
                        firstSep = processStepString.indexOf("|");

                        secondSep = processStepString.indexOf("|", firstSep + 1);
                        if (secondSep >= 0) {
                            routeRrn = processStepString
                                    .substring(firstSep + 1, processStepString.indexOf(",", firstSep));
                        } else {
                            routeRrn = processStepString.substring(0, processStepString.indexOf(","));
                        }
                        if (routeRrn.indexOf(",") > 0) {
                            routeRrn = processStepString.substring(0, routeRrn.indexOf(","));
                        }
                        if (StringUtils.isNotBlank(routeRrn)) {
                            lot.put("routeRrn", routeRrn);
                        } else {
                            lot.put("routeRrn", "");
                        }

                        Lot lot1 = new Lot();
                        lot1.setOperationRrn(rs.getLong("operation_rrn"));
                        lot1.setProductRrn(rs.getLong("product_rrn"));
                        lot1.setProcessRrn(rs.getLong("process_rrn"));
                        lot1.setLotRrn(rs.getLong("lot_rrn"));
                        lot1.setLotId(lotId);
                        lot1.setEqptRrn(rs.getLong("eqpt_rrn"));
                        lot1.setFacilityRrn(rs.getLong("facility_rrn"));
                        lot1.setRouteRrn(parseRouteRrn(processStepString));
                        lot1.setProductLayer(rs.getString("product_layer"));
                        lot1.setRouteSeq(rs.getString("route_seq"));
                        lot1.setOperationSeq(rs.getString("operation_seq"));
                        lot1.setProcessVersion(rs.getInt("PROCESS_VERSION"));
                        lot.put("tempLot", lot1);
                        lot.put("recipeLogicalRrn", rs.getLong("recipe_logical_rrn"));
                        lot.put("facilityRrn", new Long(rs.getLong("facility_rrn")));
                        lot.put("basedLotRrn", new Long(rs.getLong("based_lot_rrn")));
                        lot.put("carrierRrn", new Long(rs.getLong("carrier_rrn")));
                        lot.put("outerOrderNO", StringUtils.trimToEmpty(rs.getString("outer_order_no")));
                        lot.put("innerOrderNO", StringUtils.trimToEmpty(rs.getString("inner_order_no")));
                        return lot;
                    }
                });
        return map;
    }

    @Override
    public Long getCount(String tblName, Map condition) {
        String tblName1 = "";

        StringBuilder where = new StringBuilder(" WHERE 1=1 ");

        if (tblName.equals(DataBaseNames.LOT) && (condition != null) && (condition.size() != 0)) {
            if (condition.get("productRrn") != null) {
                where.append(" AND product_rrn = ?");
            }

            if (condition.get("processRrn") != null) {
                where.append(" AND process_rrn = ?");
            }

            if (condition.get("operationRrn") != null) {
                where.append(" AND operation_rrn = ?");
            }

            if (condition.get("lotStatus") != null) {
                if ("ACTIVE".equals(condition.get("lotStatus").toString())) {
                    where.append(" AND lot_status NOT IN ('" + LotStatus.SCRAPPED + "','" + LotStatus.BANKED + "','" +
                                         LotStatus.TERMINATED + "') ");
                } else if ("UNACTIVE".equals(condition.get("lotStatus").toString())) {
                    where.append(" AND lot_status IN ('" + LotStatus.SCRAPPED + "','" + LotStatus.BANKED + "','" +
                                         LotStatus.TERMINATED + "') ");
                } else if ("REWORK".equals(condition.get("lotStatus").toString())) {
                    where.append(" AND rework_category IS NOT NULL ");
                } else {
                    where.append(" AND lot_status = ?");
                }
            }

            if (condition.get("facility") != null) {
                where.append(" AND facility_rrn = ?");
            }

        }

        if (tblName.equals(DataBaseNames.LOT_STEP_HISTORY) && (condition != null) &&
                (condition.size() != 0 && condition.get("lotRrn") != null)) {
            where.append(" AND lot_rrn = ?");
        }

        if (tblName.equals(DataBaseNames.RUN) && (condition != null) && (condition.size() != 0) &&
                (condition.get("runRrn") != null)) {
            where.append(" AND run_rrn = ?");
        }


        if (tblName.equals(DataBaseNames.INVENTORY_TRANS_HISTORY) && (condition != null) && (condition.size() != 0) &&
                (condition.get("lotRrn") != null)) {
            where.append(" AND lot_Rrn = ?");
        }

        if (tblName.equals(DataBaseNames.LOT_PLAN_H) && (condition != null) && (condition.size() != 0)) {
            if (condition.get("lotRrn") != null) {
                where.append(" AND lot_rrn = ? ");
            }
        }

        if (tblName.equals(DataBaseNames.LOT_TRANS_HISTORY) && (condition != null) && (condition.size() != 0)) {
            if (condition.get("lotRrn") != null) {
                where.append(" AND lot_rrn = ? AND trans_id not in (?, ?, ?, ?) ");
            }

            if (condition.get("lotTransId") != null) {
                String transId = (String) condition.get("lotTransId");

                if ("lotholdreleasehistory".equals(transId)) {
                    where.append(" AND (trans_id ='HOLD' OR trans_id='RELEASE') ");
                } else if ("lotsplitmergehistory".equals(transId)) {
                    where.append(" AND (trans_id ='SPLIT' OR trans_id='MERGE') ");
                } else if ("lotlbrdhistory".equals(transId)) {
                    where.append(" AND TRANS_ID='LBRD' ");
                } else {
                    where.append(" AND trans_id ='");
                    where.append(transId);
                    where.append("' ");
                }
            }
        }

        String sql = " SELECT COUNT(*) FROM " + tblName + tblName1 + where.toString();

        Long count = new Long(0);

        List list = new ArrayList();
        if (tblName.equals(DataBaseNames.LOT) && (condition != null) && (condition.size() != 0)) {
            if (condition.get("productRrn") != null) {
                list.add(condition.get("productRrn"));
            }

            if (condition.get("processRrn") != null) {
                list.add(condition.get("processRrn"));
            }

            if (condition.get("operationRrn") != null) {
                list.add(condition.get("operationRrn"));
            }

            if ((condition.get("lotStatus") != null) && !("REWORK").equals(condition.get("lotStatus").toString()) &&
                    !("ACTIVE".equals(condition.get("lotStatus").toString())) &&
                    !("UNACTIVE".equals(condition.get("lotStatus").toString()))) {
                list.add(condition.get("lotStatus"));
            }

            if (condition.get("facility") != null) {
                list.add(condition.get("facility"));
            }

        }

        // qry lot step history
        if (tblName.equals(DataBaseNames.LOT_STEP_HISTORY) && (condition != null) && (condition.size() != 0) &&
                (condition.get("lotRrn") != null)) {
            list.add(condition.get("lotRrn"));
        }

        // qry run history
        if (tblName.equals(DataBaseNames.RUN) && (condition != null) && (condition.size() != 0) &&
                (condition.get("runRrn") != null)) {
            long run = (new Long((String) condition.get("runRrn"))).longValue();

            list.add(run);
        }


        if (tblName.equals(DataBaseNames.INVENTORY_TRANS_HISTORY) && (condition != null) && (condition.size() != 0) &&
                (condition.get("lotRrn") != null)) {
            list.add(condition.get("lotRrn"));
        }

        // qry lot trans history
        if (tblName.equals(DataBaseNames.LOT_PLAN_H) && (condition != null) && (condition.size() != 0) &&
                (condition.get("lotRrn") != null)) {
            list.add(condition.get("lotRrn"));
        }

        if (tblName.equals(DataBaseNames.LOT_TRANS_HISTORY) && (condition != null) && (condition.size() != 0) &&
                (condition.get("lotRrn") != null)) {
            list.add(condition.get("lotRrn"));
            list.add(TransactionNames.LBRD_KEY);
            list.add(TransactionNames.MOVENEXT_KEY);
            list.add(TransactionNames.WS_MOVENEXT_KEY);
            list.add(TransactionNames.CREATE_KEY);
        }

        count = jdbcTemplate.queryForObject(sql, list.toArray(), long.class);
        return count;
    }

    @Override
    public List<Map<String, Object>> getSameEqptTrackInLotListByEqptRrn(Long eqptRrn) {
        String sql = "SELECT LOT_RRN, LOT_ID, JOB_RRN, RECIPE_LOGICAL_RRN, QTY1, QTY2 " + " FROM LOT " + " WHERE " +
                "EQPT_RRN = ? AND (JOB_RRN IS NOT NULL OR JOB_RRN <> 0) " +
                " AND LOT_STATUS IN ('DISPATCH', 'PROCESSED', " + "'RUNNING') ";

        return jdbcTemplate.query(sql, new Object[]{eqptRrn}, new RowMapper<Map<String, Object>>() {

            @Override
            public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map<String, Object> result = new HashMap<>();

                result.put("lotRrn", new Long(rs.getLong("LOT_RRN")));
                result.put("lotId", rs.getString("LOT_ID"));
                result.put("jobRrn", new Long(rs.getLong("JOB_RRN")));
                result.put("recipeRrn", new Long(rs.getLong("RECIPE_LOGICAL_RRN")));
                result.put("qty1", new Double(rs.getDouble("QTY1")));
                result.put("qty2", new Double(rs.getDouble("QTY2")));

                return result;
            }
        });
    }

    @Override
    public List qryLotTransHistory(Map condition, int thisPage, int pageSize) {
        List list = new ArrayList();
        list.add(TransactionNames.ADJUST_WAFER);
        int fixPagesize = 10;

        StringBuffer where = new StringBuffer(" WHERE 1=1 ");

        if ((condition != null) && (condition.size() != 0)) {
            if (MapUtils.getString(condition, "showAll") != null) {
                fixPagesize = pageSize;
            }
            if (condition.get("lotRrn") != null) {
                where.append(" AND lt.lot_rrn = ?");
            }

            if (condition.get("lotTransId") != null) {
                where.append(" AND lt.trans_id = ?");
            }
        }

        String filterTransIDParams = " AND lt.trans_id not in (?, ?, ?, ?) ";

        String sql = "SELECT * FROM (SELECT ROWNUM AS ROWNO, T.* FROM (SELECT lt.carrier_rrn, lt" + ".trans_rrn,lt" +
                ".trans_sequence,lt.trans_id,lt.hot_flag,lt.priority, lt.TRANS_MODULE, " +
                " tr.trans_start_timestamp,tr.trans_end_timestamp," + " tr.trans_performed_by," +
                " ls.process_step_version,ls.stage_id,ls.lot_rrn,ls.lot_id,ls.facility_rrn," +
                " ls.step_sequence,ls.in_qty1,lt.qty1, ls.out_qty1, ls.product_rrn,ls.process_rrn,ls.process_id," +
                " ls.operation_rrn,ls.operation_id,lt.eqpt_rrn,lt.trans_comments,ls.process_step_id_version," +
                " ls.route_seq,ls.operation_seq,ls" + ".PROCESS_VERSION,ls.product_layer,ls" + ".operation_desc,ls" +
                ".step_type,ls.work_area,ls.flow_seq, " +
                " lt.recipe_id, smh.target_lot_id, smh.target_unit_id, smh.source_lot_id, " +
                " lt.CUSTOMER_ID, lt.SHIPPING_CODE, lt.OUTER_ORDER_NO, lt.OUT_ORDER_TYPE,cn" +
                ".object_subtype as carrier_type, ls.PROCESS_LOCATION, ls.FLIP_TYPE," +
                " lt.location, lt.prev_location, lt.TAILCODE, lt.SAMPLINGRATE ,lt.DCOL_RRN,lt.batch_id " +
                " ,CASE WHEN TR.TRANS_ID = ? THEN TR.COMMENTS ELSE '' END CARRIER_MAPPING_HIS " +
                " FROM lot_trans_history lt, lot_step_history ls,named_object cn, " +
                " transaction_log tr left join split_merge_history smh " + " on tr.trans_rrn = smh.trans_rrn " +
                where.toString() + " AND lt.carrier_rrn=cn.instance_rrn" +
                " AND lt.lot_rrn = ls.lot_rrn AND lt.step_sequence = ls.step_sequence AND lt" +
                ".trans_rrn = tr.trans_rrn " + " AND (smh.source_lot_rrn <> smh.target_lot_rrn or " +
                "(smh.target_lot_rrn is null and " + " smh.source_lot_id is null)) " +
                " AND (lt.lot_rrn = smh.target_lot_rrn or lt.lot_rrn =" + " smh.source_lot_rrn or " + "(smh" +
                ".target_lot_rrn is null and smh.source_lot_id is " + "null)) " + filterTransIDParams +
                " ORDER BY trans_start_timestamp DESC,trans_sequence DESC,lt.TRANS_RRN DESC," +
                "TARGET_LOT_ID ) T WHERE ROWNUM <= ?) ROW_T WHERE ROW_T.ROWNO > ?";

        int i = 1;

        if (condition.get("lotRrn") != null) {
            list.add((condition.get("lotRrn")));
        }

        if (condition.get("lotTransId") != null) {
            list.add(condition.get("lotTransId"));
        }

        list.add(TransactionNames.LBRD_KEY);
        list.add(TransactionNames.MOVENEXT_KEY);
        list.add(TransactionNames.WS_MOVENEXT_KEY);
        list.add(TransactionNames.CREATE_KEY);

        //TODO 修改page方式
        list.add(thisPage * fixPagesize);
        list.add(fixPagesize * (thisPage - 1));

        List<Map> lotTransHistory = jdbcTemplate.query(sql, list.toArray(), new RowMapper<Map>() {
            @Override
            public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {

                Map m = new HashMap();

                m.put("seq", new Integer(rowNum + 1));
                String transId = rs.getString("trans_id");
                m.put("trans_id", transId);
                m.put("transRrn", rs.getLong("trans_rrn"));
                m.put("lotRrn", rs.getLong("lot_rrn"));
                m.put("trans_start_timestamp", DateUtils.formatDate(rs.getTimestamp("trans_start_timestamp")));
                m.put("trans_end_timestamp", DateUtils.formatDate(rs.getTimestamp("trans_end_timestamp")));
                String transByName = getTransByName(rs.getString("trans_performed_by"));
                if (transByName != null) {
                    m.put("trans_performed_by", rs.getString("trans_performed_by") + " " + transByName);
                } else {
                    m.put("trans_performed_by", rs.getString("trans_performed_by"));
                }
                m.put("hotFlag", rs.getString("hot_flag"));
                m.put("priority", rs.getString("priority"));

                m.put("qty_1", rs.getInt("qty1"));

                m.put("qty_2", rs.getInt("out_qty1"));
                String processStepIdVer = rs.getString("process_step_id_version");

                m.put("route_id", parseRoute(processStepIdVer));
                String transComments = rs.getString("trans_comments");
                if (rs.getString("trans_comments") != null) {
                    if (StringUtils.equalsIgnoreCase(transId, TransactionNames.HOLD_KEY) ||
                            StringUtils.equalsIgnoreCase(transId, TransactionNames.HOLD_RUNNING_LOT)) {
                        m.put("transComments", rs.getString("trans_comments"));
                    } else {
                        if (!(rs.getString("trans_comments")).equals(getTransReason(rs.getLong("trans_rrn"),
                                                                                    ((Long) condition.get("lotRrn"))
                                                                                            .longValue()))) {
                            if (StringUtils.contains(transComments, "[changed lot location]")) {
                                m.put("transComments", getTransReason(rs.getLong("trans_rrn"),
                                                                      ((Long) condition.get("lotRrn")).longValue()));
                            } else {
                                m.put("transComments", rs.getString("trans_comments") + " " +
                                        getTransReason(rs.getLong("trans_rrn"),
                                                       ((Long) condition.get("lotRrn")).longValue()));
                            }
                        } else {
                            m.put("transComments", getTransReason(rs.getLong("trans_rrn"),
                                                                  ((Long) condition.get("lotRrn")).longValue()));
                        }
                    }

                } else {
                    m.put("transComments",
                          getTransReason(rs.getLong("trans_rrn"), ((Long) condition.get("lotRrn")).longValue()));
                }

                if (StringUtils.equalsIgnoreCase(MapUtils.getString(m, "trans_id"), TransactionNames.T7CODE_KEY)) {
                    String t7CodeHist = getT7CodeHist(rs.getLong("trans_rrn"));

                    if (StringUtils.isNotBlank(t7CodeHist)) {
                        transComments = MapUtils.getString(m, "transComments", StringUtils.EMPTY);
                        transComments = StringUtils.isEmpty(transComments) ? "" : transComments + ",";
                        m.put("transComments", transComments + "laserMarkHist: " + t7CodeHist);
                    }
                }

                // m.put("operation_id", parseOperation(processStepIdVer));
                m.put("stageId", rs.getString("stage_id"));
                m.put("eqpt_rrn", rs.getLong("eqpt_rrn"));
                m.put("carrier_rrn", rs.getLong("carrier_rrn"));
                m.put("operationRrn", new Long(rs.getLong("operation_rrn")));
                m.put("operationId",rs.getString("operation_id"));
                m.put("productRrn", new Long(rs.getLong("product_rrn")));
                m.put("processRrn", new Long(rs.getLong("process_rrn")));
                m.put("processId",rs.getString("process_id"));

                String processStepString = rs.getString("process_step_version");

                m.put("productLayer", rs.getString("product_layer"));

                m.put("recipeId", rs.getString("recipe_id"));
                m.put("targetLotId", rs.getString("target_lot_id"));
                m.put("targetUnitId", rs.getString("target_unit_id"));
                m.put("sourceLotId", rs.getString("source_lot_id"));
                m.put("routeRrn", parseRouteRrn(processStepString));
                m.put("processVersion", rs.getInt("PROCESS_VERSION"));
                m.put("operationDesc", rs.getString("operation_desc"));
                m.put("operationType", rs.getString("step_type"));
                m.put("workArea", rs.getString("work_area"));
                m.put("flowSeq", rs.getString("flow_seq"));

                m.put("customerId", rs.getString("CUSTOMER_ID"));
                m.put("shippingCode", rs.getString("SHIPPING_CODE"));
                m.put("outerOrderNo", rs.getString("OUTER_ORDER_NO"));
                m.put("outOrderType", rs.getString("OUT_ORDER_TYPE"));
                m.put("carrierType", rs.getString("carrier_type"));
                m.put("stepSequence", rs.getLong("step_sequence"));
                m.put("location", rs.getString("location"));
                m.put("pLocation", rs.getString("prev_location"));
                m.put("tailCode", rs.getString("TAILCODE"));
                m.put("samplingRate", rs.getString("SAMPLINGRATE"));
                m.put("transSequence", rs.getString("trans_sequence"));
                m.put("dcolRrn", rs.getString("DCOL_RRN"));
                m.put("batchId",rs.getString("BATCH_ID"));
                m.put("transModule", rs.getString("TRANS_MODULE"));
                m.put("processLocation", rs.getString("PROCESS_LOCATION"));
                m.put("flipType", rs.getString("FLIP_TYPE"));
                m.put("carrieMappingHistory", StringUtils.defaultIfBlank(rs.getString("CARRIER_MAPPING_HIS"), StringUtils.EMPTY));
                return m;
            }
        });
        return lotTransHistory;
    }

    @Override
    public List<Map> qryAllLotAdjustDetail(Long lotRrn) {
        String sql = "select lt.lot_rrn,lh.lot_id,lh.product_rrn,getinstanceid(lh.product_rrn) as product_id,lh" +
                ".process_rrn,getinstanceid(lh.process_rrn) as process_id," + "lh.process_version,lh.operation_rrn," +
                "getinstanceid(lh.operation_rrn) as operation_id,lh" +
                ".qty1,lh.create_category,lh.lot_type,lh.hot_flag,lh" + ".priority," +
                "lh.lot_owner,lh.due_date,lh.customer_id,lh.shipping_code,lh.outer_order_no,lh" +
                ".out_order_type,lh.split_merge_flag," +
                "tr.trans_start_timestamp,tr.trans_end_timestamp,tr.comments,tr" + ".trans_performed_by,lh" +
                ".lot_comments," + "LT.TRANS_RRN,LT.TRANS_SEQUENCE,LT.TRANS_ID,LT.FACILITY_RRN," +
                "LT.STEP_SEQUENCE,LT" + ".CARRIER_RRN,LT.TRANS_COMMENTS " + " from lot_trans_history lt,lot_h lh," +
                "transaction_log tr left join split_merge_history SMH " + " on tr.trans_rrn = smh.trans_rrn WHERE LT" +
                ".LOT_RRN=LH.LOT_RRN AND LT.TRANS_RRN=LH" + ".TRANS_RRN " + " AND LT.TRANS_RRN=TR.TRANS_RRN AND (smh" +
                ".source_lot_rrn <> smh.target_lot_rrn or " + "(smh.target_lot_rrn is null and smh.source_lot_id is " +
                "null)) " + " AND (lt.lot_rrn = smh.target_lot_rrn or lt.lot_rrn = smh.source_lot_rrn or (smh" +
                ".target_lot_rrn is null and smh.source_lot_id is null))" + " AND LT.LOT_RRN = ? order by TR" +
                ".TRANS_RRN DESC";
        //todo:该sql用trans_rrn进行排序
        List<Map> list = jdbcTemplate.query(sql, new Object[]{lotRrn}, new RowMapper<Map>() {

            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map map = new HashMap();
                map.put("lotRrn", rs.getLong("lot_rrn"));
                map.put("lotId", rs.getString("lot_id"));
                map.put("productRrn", rs.getLong("product_rrn"));
                map.put("productId", rs.getString("product_id"));
                map.put("processRrn", rs.getLong("process_rrn"));
                map.put("processId", rs.getString("process_id"));
                map.put("processVersion", rs.getString("process_version"));
                map.put("operationRrn", rs.getLong("operation_rrn"));
                map.put("operationId", rs.getString("operation_id"));
                map.put("qty1", new Double(rs.getDouble("qty1")).longValue());
                map.put("createCategory", rs.getString("create_category"));
                map.put("lotType", rs.getString("lot_type"));
                map.put("hotFlag", rs.getString("hot_flag"));
                map.put("priority", rs.getString("priority"));
                map.put("lotOwner", rs.getString("lot_owner"));
                map.put("dueDate",
                        rs.getDate("due_date") == null ? "" : new SimpleDateFormat(DateUtils.DATE_FORMAT4DAYD)
                                .format(rs.getDate("due_date")));
                map.put("customerId", rs.getString("customer_id"));
                map.put("shippingCode", rs.getString("shipping_code"));
                map.put("outerOrderNO", rs.getString("OUTER_ORDER_NO"));
                map.put("outOrderType", rs.getString("OUT_ORDER_TYPE"));
                map.put("transStartTime", rs.getString("trans_start_timestamp"));
                map.put("transEndTime", rs.getString("trans_end_timestamp"));
                map.put("comments", rs.getString("comments"));
                map.put("transPerformedBy", rs.getString("trans_performed_by"));
                map.put("transRrn", rs.getLong("TRANS_RRN"));
                map.put("transSequence", rs.getString("TRANS_SEQUENCE"));
                map.put("transId", rs.getString("TRANS_ID"));
                map.put("facilityRrn", rs.getLong("FACILITY_RRN"));
                map.put("stepSequence", rs.getString("STEP_SEQUENCE"));
                map.put("carrierRrn", rs.getLong("CARRIER_RRN"));
                map.put("transComments", rs.getString("TRANS_COMMENTS"));
                map.put("lotComments", rs.getString("lot_comments"));
                return map;
            }
        });
        return list;
    }

    @Override
    public Page queryLotPlanHistory(Page page, Map condition) {
        StringBuilder sql = new StringBuilder("SELECT ");

        sql.append(" lph.TRANS_RRN, lph.TRANS_SEQUENCE, LOT_RRN, FACILITY_RRN, LOT_ID, BASED_LOT_RRN, ");
        sql.append(" HOT_FLAG, PRIORITY, STARTED_FLAG, STARTED_TIMESTAMP, CREATE_CATEGORY, ");
        sql.append(" CREATED_TIMESTAMP, END_TIMESTAMP, DUE_DATE, SCHEDULE_DUE_DATE, ");
        sql.append(" ESTIMATED_REMAIN_TIME, DUMMY_FLAG, LOT_TYPE, LOT_OWNER, QTY1, QTY2, ");
        sql.append(" DUMMY_QTY1, INPUT_QTY1, INPUT_QTY2, SUBCONTRACTOR_RRN, LOT_COMMENTS, ");
        sql.append(" STEP_SEQUENCE, STEP_NUMBER_IN_PROCESS, HOLD_TIMESTAMP, REWORK_TRANS_RRN, ");
        sql.append(" REWORK_CATEGORY, CARRIER_RRN, BEFORE_STATUS, LOT_STATUS, PROCESSING_STATUS,");
        sql.append(" QUEUE_TIMESTAMP, PRODUCT_RRN, PROCESS_RRN, PROCESS_VERSION, ");
        sql.append(" PROCESS_STEP_VERSION, PROCESS_STEP_ID_VERSION, PREV_OPERATION_RRN, ");
        sql.append(" PREV_OPERATION_VERSION, OPERATION_RRN, OPERATION_VERSION, ");
        sql.append(" NEXT_STEP_VERSION1, NEXT_STEP_ID_VERSION1, NEXT_OPERATION_RRN1, ");
        sql.append(" NEXT_STEP_VERSION2, NEXT_STEP_ID_VERSION2, NEXT_OPERATION_RRN2, ");
        sql.append(" STAGE_ID, LAYER_ID, BOR_RRN, EQPT_RRN, RECIPE_STRING, ");
        sql.append(" NEXT_RECIPE_STRING1, NEXT_RECIPE_STRING2, JOB_RRN, NEXT_JOB_RRN1, ");
        sql.append(" NEXT_JOB_RRN2, WFL_STEP_PATH, EXECUTION_RRN, RETICLE_RRN, SHIPPED_QTY1, ");
        sql.append(" SHIPPED_QTY2, WIFER_ID, WIFER_TYPE, FLOW_LEVEL, CUSTOMER_ID, ");
        sql.append(" CUSTOMER_LOT_ID, CUSTOMER_WAFER_ID, WAFERSTARTTIME, ");
        sql.append(" OUTERORDERNO, INNERORDERNO, SHIPPINGCODE, ISOUTSOURCE, ISRECREATELOT, ");
        sql.append(" PROJECT_CATEGORY, RETICLE_GROUP_RRN, ATTRIBUTE_DATA3, LOT_PLAN_TYPE, MATERIALINFO, " +
                           "OUT_ORDER_TYPE, ");
        sql.append(" tl.TRANS_ID, tl.TRANS_START_TIMESTAMP, tl.TRANS_END_TIMESTAMP, tl.TRANS_PERFORMED_BY, tl" +
                           ".COMMENTS ");
        sql.append(" FROM ").append(DataBaseNames.LOT_PLAN_H).append(" lph ");
        sql.append(" LEFT JOIN ").append(DataBaseNames.TRANSACTION_LOG).append(" tl ");
        sql.append(" ON lph.TRANS_RRN = tl.TRANS_RRN ");
        sql.append(" WHERE 1 = 1");

        List<Object> args = new ArrayList<>();

        if ((condition != null) && (condition.size() != 0)) {
            if (condition.get("lotRrn") != null) {
                sql.append(" AND lph.LOT_RRN = ?");
                args.add(MapUtils.getLong(condition, "lotRrn"));
            }

            if (condition.get("lotId") != null) {
                sql.append(" AND lph.LOT_ID = ?");
                args.add(MapUtils.getString(condition, "lotId"));
            }

            if (condition.get("lotTransId") != null) {
                sql.append(" AND tl.TRANS_ID = ?");
                args.add(MapUtils.getString(condition, "lotTransId"));
            }
        }

        sql.append(" ORDER BY tl.TRANS_START_TIMESTAMP DESC, lph.TRANS_SEQUENCE DESC ");

        return jdbcTemplate.queryForPage(page, sql.toString(), args.toArray(), new RowMapper<Map<String, Object>>() {

            @Override
            public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map<String, Object> map = new HashMap<>();

                map.put("seq", rowNum + 1);
                map.put("transId", rs.getString("TRANS_ID"));
                map.put("transStartTimestamp", DateUtils.formatDate(rs.getTimestamp("TRANS_START_TIMESTAMP")));
                map.put("transEndTimestamp", DateUtils.formatDate(rs.getTimestamp("TRANS_END_TIMESTAMP")));
                String transByName = getTransByName(rs.getString("TRANS_PERFORMED_BY"));
                map.put("transPerformedBy", rs.getString("TRANS_PERFORMED_BY"));
                map.put("transPerformedByName", transByName);
                map.put("qty1", rs.getString("QTY1"));
                map.put("lotId", rs.getString("LOT_ID"));

                map.put("product_rrn", rs.getLong("product_rrn"));
                map.put("process_rrn", rs.getLong("process_rrn"));

                map.put("lotComments", rs.getString("LOT_COMMENTS"));
                map.put("createCategory", rs.getString("CREATE_CATEGORY"));
                map.put("lotType", rs.getString("LOT_TYPE"));
                map.put("priority", rs.getString("PRIORITY"));
                map.put("dueDate", rs.getString("DUE_DATE"));
                map.put("customerId", rs.getString("CUSTOMER_ID"));
                map.put("shippingCode", rs.getString("SHIPPINGCODE"));
                map.put("outerOrderNo", rs.getString("OUTERORDERNO"));
                map.put("outOrderType", rs.getString("OUT_ORDER_TYPE"));
                map.put("lotOwner", rs.getString("LOT_OWNER"));
                map.put("hotFlag", rs.getString("HOT_FLAG"));

                long transRrn = rs.getLong("TRANS_RRN");
                String comments = rs.getString("COMMENTS");
                long lotRrn = rs.getLong("LOT_RRN");
                if (comments != null) {
                    if (!comments.equals(getTransReason(transRrn, lotRrn))) {
                        map.put("transComments", comments + " " + getTransReason(transRrn, lotRrn));
                    } else {
                        map.put("transComments", getTransReason(transRrn, lotRrn));
                    }
                } else {
                    map.put("transComments", getTransReason(transRrn, lotRrn));
                }

                return map;
            }
        });
    }

    @Override
    public Map qryAdjustTransHistory(Long transRrn, Long lotRrn) {
        String sql = "SELECT TRANS_RRN,LOT_RRN,adjust_before,adjust_after FROM ADJUST_LOT_H WHERE TRANS_RRN" + " = ? " +
                "AND LOT_RRN = ?";
        Object[] args = new Object[]{transRrn, lotRrn};
        List<Map> list = jdbcTemplate.query(sql, args, new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map map = new HashMap<String, Object>();
                map.put("transRrn", rs.getLong("TRANS_RRN"));
                map.put("lotRrn", rs.getLong("LOT_RRN"));
                map.put("adjustBefore", rs.getString("adjust_before"));
                map.put("adjustAfter", rs.getString("adjust_after"));
                return map;
            }
        });
        if (list.size() > 0) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public Map qryTransHistoryDetail(Long transRrn, Long lotRrn) {
        String sql = "select lt.lot_rrn,lh.lot_id,lh.product_rrn,getinstanceid(lh.product_rrn) as product_id,lh" +
                ".process_rrn,getinstanceid(lh.process_rrn) as process_id," + "lh.process_version,lh.operation_rrn," +
                "getinstanceid(lh.operation_rrn) as operation_id,lh" +
                ".qty1,lh.create_category,lh.lot_type,lh.hot_flag,lh" + ".priority," +
                "lh.lot_owner,lh.due_date,lh.customer_id,lh.shipping_code,lh.outer_order_no,lh" +
                ".out_order_type,lh.split_merge_flag," +
                "tr.trans_start_timestamp,tr.trans_end_timestamp,tr.comments,tr" + ".trans_performed_by,lh" +
                ".lot_comments," + "LT.TRANS_RRN,LT.TRANS_SEQUENCE,LT.TRANS_ID,LT.FACILITY_RRN," +
                "LT.STEP_SEQUENCE,LT" + ".CARRIER_RRN,LT.TRANS_COMMENTS " + " from lot_trans_history lt,lot_h lh," +
                "transaction_log tr left join split_merge_history smh" + " ON  tr.trans_rrn = smh.trans_rrn " +
                " WHERE " + "LT.LOT_RRN=LH.LOT_RRN AND LT.TRANS_RRN=LH.TRANS_RRN AND LT.TRANS_RRN=TR.TRANS_RRN " +
                " AND (smh" + ".source_lot_rrn <> smh.target_lot_rrn or (smh.target_lot_rrn is null and " +
                "smh.source_lot_id is " + "null)) " +
                " AND (lt.lot_rrn = smh.target_lot_rrn or lt.lot_rrn = smh.source_lot_rrn or (smh" +
                ".target_lot_rrn is null and smh.source_lot_id is null))" + " AND TR.TRANS_RRN = ? AND LT.LOT_RRN = ?";
        List<Map> list = jdbcTemplate.query(sql, new Object[]{transRrn, lotRrn}, new RowMapper<Map>() {

            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map map = new HashMap<>();
                map.put("lotRrn", rs.getLong("lot_rrn"));
                map.put("lotId", rs.getString("lot_id"));
                map.put("productRrn", rs.getLong("product_rrn"));
                map.put("productId", rs.getString("product_id"));
                map.put("processRrn", rs.getLong("process_rrn"));
                map.put("processId", rs.getString("process_id"));
                map.put("processVersion", rs.getString("process_version"));
                map.put("operationRrn", rs.getLong("operation_rrn"));
                map.put("operationId", rs.getString("operation_id"));
                map.put("qty1", new Double(rs.getDouble("qty1")).longValue());
                map.put("createCategory", rs.getString("create_category"));
                map.put("lotType", rs.getString("lot_type"));
                map.put("hotFlag", rs.getString("hot_flag"));
                map.put("priority", rs.getString("priority"));
                map.put("lotOwner", rs.getString("lot_owner"));
                map.put("dueDate",
                        rs.getDate("due_date") == null ? "" : new SimpleDateFormat(DateUtils.DATE_FORMAT4DAYD)
                                .format(rs.getDate("due_date")));
                map.put("customerId", rs.getString("customer_id"));
                map.put("shippingCode", rs.getString("shipping_code"));
                map.put("outerOrderNO", rs.getString("OUTER_ORDER_NO"));
                map.put("outOrderType", rs.getString("OUT_ORDER_TYPE"));
                map.put("transStartTime", rs.getString("trans_start_timestamp"));
                map.put("transEndTime", rs.getString("trans_end_timestamp"));
                map.put("comments", rs.getString("comments"));
                map.put("transPerformedBy", rs.getString("trans_performed_by"));
                map.put("transRrn", rs.getLong("TRANS_RRN"));
                map.put("transSequence", rs.getString("TRANS_SEQUENCE"));
                map.put("transId", rs.getString("TRANS_ID"));
                map.put("facilityRrn", rs.getLong("FACILITY_RRN"));
                map.put("stepSequence", rs.getString("STEP_SEQUENCE"));
                map.put("carrierRrn", rs.getLong("CARRIER_RRN"));
                map.put("transComments", rs.getString("TRANS_COMMENTS"));
                map.put("splitMergeFlag", rs.getString("split_merge_flag"));
                map.put("lotComments", rs.getString("lot_comments"));
                return map;
            }
        });

        if (list != null && list.size() > 0) {
            return list.get(0);
        } else {
            return null;
        }
    }

    @Override
    public List<Map> queryAllLotTrans(Long lotRrn) {
        String sql =
                "SELECT lt.carrier_rrn, lt.trans_rrn,lt.trans_sequence,lt.trans_id,tr.trans_start_timestamp, " + " tr" +
                        ".trans_end_timestamp, tr.trans_performed_by,ls.process_step_version,ls.stage_id,ls" +
                        ".lot_rrn,ls.lot_id," + "ls.facility_rrn,ls.STEP_SEQUENCE," +
                        " ls.in_qty1,lt.qty1, ls.out_qty1, ls.product_rrn,ls.process_rrn,ls" + ".operation_rrn,ls" +
                        ".eqpt_rrn,lt.trans_comments,ls.process_step_id_version," + " ls.route_seq,ls" +
                        ".operation_seq,ls.PROCESS_VERSION,ls.product_layer,ls.operation_desc,ls" +
                        ".step_type,ls.work_area,ls" + ".flow_seq, " +
                        " ls.recipe_physical_id, smh.target_lot_id, smh.target_unit_id, smh.source_lot_id, " +
                        " lt.CUSTOMER_ID, lt.SHIPPING_CODE, lt.OUTER_ORDER_NO, lt.OUT_ORDER_TYPE,lt.HOT_FLAG,lt" +
                        ".priority," + "lt.split_merge_flag," + " CN.OBJECT_SUBTYPE AS CARRIER_TYPE " +
                        " FROM lot_trans_history lt, " + "lot_step_history ls, NAMED_OBJECT CN, transaction_log tr " +
                        " left join split_merge_history smh on " + "tr.trans_rrn = smh.trans_rrn " +
                        " WHERE lt.lot_rrn = ? AND LT.CARRIER_RRN = CN.INSTANCE_RRN" + " " +
                        "AND lt.lot_rrn = ls.lot_rrn AND lt.step_sequence = ls.step_sequence AND lt.trans_rrn = " +
                        " tr" + ".trans_rrn " +
                        " AND (smh.source_lot_rrn <> smh.target_lot_rrn or (smh.target_lot_rrn is null and" + " " +
                        "smh.source_lot_id is null)) " + " AND (lt.lot_rrn = smh.target_lot_rrn or lt.lot_rrn = smh" +
                        ".source_lot_rrn or (smh" + ".target_lot_rrn is null and smh.source_lot_id is null)) " +
                        " ORDER" + " BY TR.trans_start_timestamp DESC,TR.trans_rrn DESC,LT.trans_sequence DESC";

        Object[] args = new Object[]{lotRrn};

        List<Map> lotTransHistory = jdbcTemplate.query(sql, args, new RowMapper<Map>() {

            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map m = new HashMap<String, Object>();
                Long lotRrn = rs.getLong("lot_rrn");

                m.put("transId", rs.getString("trans_id"));
                m.put("transRrn", rs.getLong("trans_rrn"));
                m.put("transStartTime", DateUtils.formatDate(rs.getTimestamp("trans_start_timestamp")));
                m.put("transEndTime", DateUtils.formatDate(rs.getTimestamp("trans_end_timestamp")));
                m.put("transPerformedBy", rs.getString("trans_performed_by"));
                m.put("qty1", new Double(rs.getDouble("qty1")));

                String processStepIdVer = rs.getString("process_step_id_version");

                m.put("routeId", parseRoute(processStepIdVer));
                if (rs.getString("trans_comments") != null) {
                    if (!(rs.getString("trans_comments")).equals(getTransReason(rs.getLong("trans_rrn"), lotRrn))) {
                        m.put("transComments",
                              rs.getString("trans_comments") + " " + getTransReason(rs.getLong("trans_rrn"), lotRrn));
                    } else {
                        m.put("transComments", getTransReason(rs.getLong("trans_rrn"), lotRrn));
                    }
                } else {
                    m.put("transComments", getTransReason(rs.getLong("trans_rrn"), lotRrn));
                }

                if (StringUtils.equalsIgnoreCase(MapUtils.getString(m, "transId"), TransactionNames.T7CODE_KEY)) {
                    String t7CodeHist = getT7CodeHist(rs.getLong("trans_rrn"));

                    if (StringUtils.isNotBlank(t7CodeHist)) {
                        String transComments = MapUtils.getString(m, "transComments", StringUtils.EMPTY);
                        transComments = StringUtils.isEmpty(transComments) ? "" : transComments + ",";
                        m.put("transComments", transComments + "laserMarkHist: " + t7CodeHist);
                    }
                }

                m.put("stepSequence", rs.getString("STEP_SEQUENCE"));
                m.put("stageId", rs.getString("stage_id"));
                m.put("eqpt_rrn", rs.getLong("eqpt_rrn"));
                m.put("carrier_rrn", rs.getLong("carrier_rrn"));
                m.put("operationRrn", rs.getLong("operation_rrn"));
                m.put("productRrn", rs.getLong("product_rrn"));
                m.put("processRrn", rs.getLong("process_rrn"));

                String processStepString = "";
                int firstSep = 0;
                int secondSep = 0;
                String routeRrn = "";
                processStepString = rs.getString("process_step_version");
                firstSep = processStepString.indexOf("|");
                secondSep = processStepString.indexOf("|", firstSep + 1);
                if (secondSep >= 0) {
                    routeRrn = processStepString.substring(firstSep + 1, processStepString.indexOf(",", firstSep));
                } else {
                    routeRrn = processStepString.substring(0, processStepString.indexOf(","));
                }
                m.put("productLayer", rs.getString("product_layer"));

                m.put("recipeId", rs.getString("recipe_physical_id"));
                m.put("targetLotId", rs.getString("target_lot_id"));
                m.put("targetUnitId", rs.getString("target_unit_id"));
                m.put("sourceLotId", rs.getString("source_lot_id"));
                m.put("routeRrn", Long.parseLong(routeRrn));
                m.put("processVersion", rs.getInt("PROCESS_VERSION"));
                m.put("operationDesc", rs.getString("operation_desc"));
                m.put("operationType", rs.getString("step_type"));
                m.put("workArea", rs.getString("work_area"));
                m.put("flowSeq", rs.getString("flow_seq"));

                m.put("customerId", rs.getString("CUSTOMER_ID"));
                m.put("shippingCode", rs.getString("SHIPPING_CODE"));
                m.put("outerOrderNO", rs.getString("OUTER_ORDER_NO"));
                m.put("outOrderType", rs.getString("OUT_ORDER_TYPE"));

                m.put("splitMergeFlag", rs.getString("split_merge_flag"));
                m.put("hotFlag", rs.getString("HOT_FLAG"));
                m.put("priority", rs.getString("priority"));
                m.put("carrierType", rs.getString("CARRIER_TYPE"));

                return m;
            }
        });
        return lotTransHistory;
    }

    @Override
    public String queryLotPurposeByLotRrn(Long lotRrn) {
        String sql = "SELECT LTH.TRANS_COMMENTS FROM LOT_TRANS_HISTORY LTH " + "WHERE TRANS_ID = 'LOTPLAN'  AND " +
                "LOT_RRN = ?";
        String purpose = jdbcTemplate.queryForObjectWithNull(sql, new Object[]{lotRrn}, String.class);
        return purpose == null ? "" : purpose;
    }

    @Override
    public Map qryLotAfterTransDetail(Long transRrn, Long lotRrn) {
        String sql = "select lt.lot_rrn,lh.lot_id,lh.product_rrn,getinstanceid(lh.product_rrn) as product_id,lh" +
                ".process_rrn,getinstanceid(lh.process_rrn) as process_id," + "lh.process_version,lh.operation_rrn," +
                "getinstanceid(lh.operation_rrn) as operation_id,lh" +
                ".qty1,lh.create_category,lh.lot_type,lh.hot_flag,lh" + ".priority," +
                "lh.lot_owner,lh.due_date,lh.customer_id,lh.shipping_code,lh.outer_order_no,lh" +
                ".out_order_type,lh.split_merge_flag," +
                "tr.trans_start_timestamp,tr.trans_end_timestamp,tr.comments,tr" + ".trans_performed_by,lh" +
                ".lot_comments," + "LT.TRANS_RRN,LT.TRANS_SEQUENCE,LT.TRANS_ID,LT.FACILITY_RRN," +
                "LT.STEP_SEQUENCE,LT" + ".CARRIER_RRN,LT.TRANS_COMMENTS " + " from lot_trans_history lt,lot_h lh," +
                "transaction_log tr" +
                " WHERE LT.LOT_RRN=LH.LOT_RRN AND LT.TRANS_RRN=LH.TRANS_RRN AND LT.TRANS_RRN=TR" + ".TRANS_RRN " +
                " AND TR.TRANS_RRN = (SELECT MIN(trans_rrn) FROM (select trans_rrn from lot_h where " +
                "trans_rrn > ? AND LOT_RRN = ? )t) AND LT.LOT_RRN = ?";
        List<Map> list = jdbcTemplate.query(sql, new Object[]{transRrn, lotRrn, lotRrn}, new RowMapper<Map>() {

            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map map = new HashMap<>();
                map.put("lotRrn", rs.getLong("lot_rrn"));
                map.put("lotId", rs.getString("lot_id"));
                map.put("productRrn", rs.getLong("product_rrn"));
                map.put("productId", rs.getString("product_id"));
                map.put("processRrn", rs.getLong("process_rrn"));
                map.put("processId", rs.getString("process_id"));
                map.put("processVersion", rs.getString("process_version"));
                map.put("operationRrn", rs.getLong("operation_rrn"));
                map.put("operationId", rs.getString("operation_id"));
                map.put("qty1", new Double(rs.getDouble("qty1")).longValue());
                map.put("createCategory", rs.getString("create_category"));
                map.put("lotType", rs.getString("lot_type"));
                map.put("hotFlag", rs.getString("hot_flag"));
                map.put("priority", rs.getString("priority"));
                map.put("lotOwner", rs.getString("lot_owner"));
                map.put("dueDate",
                        rs.getDate("due_date") == null ? "" : new SimpleDateFormat(DateUtils.DATE_FORMAT4DAYD)
                                .format(rs.getDate("due_date")));
                map.put("customerId", rs.getString("customer_id"));
                map.put("shippingCode", rs.getString("shipping_code"));
                map.put("transStartTime", rs.getString("trans_start_timestamp"));
                map.put("transEndTime", rs.getString("trans_end_timestamp"));
                map.put("comments", rs.getString("comments"));
                map.put("transPerformedBy", rs.getString("trans_performed_by"));
                map.put("transRrn", rs.getLong("TRANS_RRN"));
                map.put("transSequence", rs.getString("TRANS_SEQUENCE"));
                map.put("transId", rs.getString("TRANS_ID"));
                map.put("facilityRrn", rs.getLong("FACILITY_RRN"));
                map.put("stepSequence", rs.getString("STEP_SEQUENCE"));
                map.put("carrierRrn", rs.getLong("CARRIER_RRN"));
                map.put("transComments", rs.getString("TRANS_COMMENTS"));
                map.put("splitMergeFlag", rs.getString("split_merge_flag"));

                map.put("lotComments", rs.getString("lot_comments"));
                map.put("outerOrderNO", rs.getString("OUTER_ORDER_NO"));
                map.put("outOrderType", rs.getString("OUT_ORDER_TYPE"));

                return map;
            }
        });

        if (list != null && list.size() > 0) {
            return list.get(0);
        } else {
            return null;
        }
    }

    @Override
    public String getParamCon(Long lotRrn, String stepSequence) {
        String parameterCollection = "";
        String sql = "SELECT LOT_RRN, PARAMETER_SET_RRN, SAMPLE_SEQUENCE, INSTANCE_ID || '(' || NVL" +
                "(INSTANCE_DESC, '')" +
                " || ')' INSTANCE_ID, PARAMETER_RRN, MAX(DATA_VALUE) DATA_VALUE, SAMPLE_ID FROM " +
                " (SELECT DSI.LOT_RRN, DC.PARAMETER_SET_RRN, RD.SAMPLE_SEQUENCE, N.INSTANCE_ID, N" +
                ".INSTANCE_DESC, " + " " +
                "DC.PARAMETER_RRN, SD.SAMPLE_ID, DC.DCOL_RRN, RD.DATA_VALUE AS DATA_VALUE FROM ((" + "(NAMED_OBJECT N" +
                " " + "left join DATA_COLLECTION DC on N.INSTANCE_RRN = DC.PARAMETER_RRN) INNER JOIN " + "RAW_DATA RD" +
                " on RD" + ".DCOL_SEQUENCE = DC.DCOL_SEQUENCE and RD.DCOL_RRN = DC.DCOL_RRN) inner join " +
                "SAMPLE_DATA SD" + " on " +
                "SD.DCOL_RRN = RD.DCOL_RRN  and SD.DCOL_SEQUENCE = RD.DCOL_SEQUENCE and SD" + ".SAMPLE_SEQUENCE =" +
                " RD" + ".SAMPLE_SEQUENCE) inner join DCOL_STEP_INFO DSI on DC.DCOL_RRN = DSI.DCOL_RRN and " +
                " DSI.LOT_RRN = ?" + " and DSI.metrological_step_sequence = ? ) t0 " +
                " GROUP BY LOT_RRN, PARAMETER_SET_RRN, " + "SAMPLE_SEQUENCE, " +
                "INSTANCE_ID || '(' || NVL(INSTANCE_DESC, '') || ')', PARAMETER_RRN, SAMPLE_ID, " + "DCOL_RRN " +
                " ORDER BY DCOL_RRN, SAMPLE_SEQUENCE ";
        List<Map> list = jdbcTemplate.query(sql, new Object[]{lotRrn, stepSequence}, Map.class);
        for (Map map : list) {
            parameterCollection +=
                    MapUtils.getString(map, "INSTANCE_ID") + "[" + MapUtils.getString(map, "SAMPLE_ID") + "] :";
            parameterCollection += MapUtils.getString(map, "DATA_VALUE");
            parameterCollection += "<br>";
        }

        return parameterCollection;
    }

    @Override
    public List<Map> getHoldReasons(long lotRrn) {
        String sql = "SELECT REASON_CATEGORY,REASON_CODE,REASON," + "SEQUENCE_NUMBER,HOLD_PASSWORD,INSTANCE_ID," +
                "HOLD_TIMESTAMP,C.INSTANCE_RRN,A" + ".responsibility,A.TRANS_RRN as TRANS_RRN," + " B.HOLD_BY,A" +
                ".REASON_CODE_SEQUENCE FROM TRANS_REASON A, (MULTIPLE_HOLD B left join  " +
                "NAMED_OBJECT C on B.HOLD_BY = " + "C.INSTANCE_RRN) " + " WHERE A.INSTANCE_RRN = B.INSTANCE_RRN" +
                " AND A.TRANS_RRN = B.TRANS_RRN" + " AND A" + ".INSTANCE_RRN = ?" + " ORDER BY SEQUENCE_NUMBER DESC";

        List<Map> list = jdbcTemplate.query(sql, new Object[]{lotRrn}, new RowMapper<Map>() {

            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map map = new HashMap<>();
                map.put("lotRrn", lotRrn);
                map.put("reasonCategory", rs.getString("REASON_CATEGORY"));
                map.put("reasonCode", rs.getString("REASON_CODE"));

                String reason = rs.getString("REASON");
                if (StringUtils.isNotEmptyTrim(reason)) {
                    reason = StringUtils.replace(reason, "\'", "&#39;").toString();
                    reason = StringUtils.replace(reason, "\"", "&#34;").toString();
                }
                map.put("reason", reason);
                map.put("sequenceNumber", rs.getString("SEQUENCE_NUMBER"));
                map.put("holdPassword", rs.getString("HOLD_PASSWORD"));
                String holdName = getTransByName(rs.getString("INSTANCE_ID"));
                if (StringUtils.isNotEmpty(holdName)) {
                    map.put("holdBy", rs.getString("INSTANCE_ID") + " " + holdName);
                } else {
                    map.put("holdBy", rs.getString("INSTANCE_ID") == null ? "SYSTEM" : rs.getString("INSTANCE_ID"));
                }
                map.put("holdDate", DateUtils.formatDate(rs.getTimestamp("HOLD_TIMESTAMP")));
                map.put("holdRrn", new Long(rs.getLong("INSTANCE_RRN")));
                map.put("responsibility", rs.getString("responsibility"));
                map.put("transRrn", rs.getString("TRANS_RRN"));
                map.put("holdByRrn", rs.getLong("HOLD_BY"));
                map.put("reasonCodeSequence", rs.getLong("REASON_CODE_SEQUENCE"));

                return map;
            }
        });
        return list;
    }

    @Override
    public List<Map> getReleaseReasonCodes(String releaseReasonGroupID, List<Object> releaseRoles,
                                           String referenceFileId) {

        StringBuilder sql = new StringBuilder("select rfd.key_1_value, rfd.data_1_value,rfd.data_3_value " +
                                                      " from reference_file_detail rfd, named_object no " +
                                                      " where rfd.reference_file_rrn = no.instance_rrn and no" +
                                                      ".instance_id=? " +
                                                      " and (instr(',' || rfd.data_2_value || ',' , ? )>0 or rfd" +
                                                      ".data_2_value like '%ALL%' )  and rfd.data_5_value='1' ");

        List args = new ArrayList();
        args.add(referenceFileId);
        args.add(StringUtils.COMMA_SIGN + releaseReasonGroupID + StringUtils.COMMA_SIGN);

        if (CollectionUtils.isNotEmpty(releaseRoles)) {

            sql.append(" AND (");

            for (Iterator iterator = releaseRoles.iterator(); iterator.hasNext(); ) {
                String holdRole = (String) iterator.next();
                sql.append(" rfd.data_3_value LIKE ? ");
                args.add("%" + holdRole + "%");
                if (iterator.hasNext()) {
                    sql.append(" OR ");
                }
            }
            sql.append(" )");
        }

        sql.append(" order by rfd.data_2_value ");

        List<Map> list = jdbcTemplate.query(sql.toString(), args.toArray(), new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map releaseReason = new HashMap();

                releaseReason.put("releaseCode", rs.getString("key_1_value"));
                releaseReason.put("releaseDesc", rs.getString("data_1_value"));

                return releaseReason;
            }
        });

        return list;

    }

    @Override
    public List<Map> getHoldReasonCodes(String holdReasonGroupID, List<String> holdRoles, String referenceFileId) {
        StringBuffer sql = new StringBuffer(
                "select rfd.key_1_value, rfd.data_1_value,rfd.data_3_value from reference_file_detail rfd, " +
                        "named_object no " + "where rfd.reference_file_rrn=no.instance_rrn and no.instance_id=? and (" +
                        "instr(',' || rfd.data_2_value || ',' , ? )>0 OR rfd.data_2_value LIKE '%ALL%' )" +
                        " and rfd.data_5_value = '1' ");

        List args = new ArrayList();
        args.add(referenceFileId);
        args.add(StringUtils.COMMA_SIGN + holdReasonGroupID + StringUtils.COMMA_SIGN);
        if (CollectionUtils.isNotEmpty(holdRoles)) {
            sql.append(" AND (");
            for (Iterator iterator = holdRoles.iterator(); iterator.hasNext(); ) {
                String holdRole = (String) iterator.next();
                sql.append(" rfd.data_3_value LIKE ? ");
                args.add("%" + holdRole + "%");
                if (iterator.hasNext()) {
                    sql.append(" OR ");
                }
            }
            sql.append(" )");
        }
        sql.append(" order by rfd.data_1_value ");
        List<Map> holdReasons = jdbcTemplate.query(sql.toString(), args.toArray(), (rs, rowNum) -> {
            Map holdReason = new HashMap();
            holdReason.put("holdCode", rs.getString("key_1_value"));
            holdReason.put("holdDesc", rs.getString("data_1_value"));
            holdReason.put("holdUsersGroup", rs.getString("data_3_value"));
            return holdReason;
        });
        return holdReasons;
    }

    @Override
    public List<Map> getHoldReasonCodes4HoldCodeGroupAll(String referenceFileId) {

        List args = new ArrayList();
        args.add(referenceFileId);

        String sql = "select rfd.key_1_value, rfd.data_1_value,rfd.data_3_value from reference_file_detail rfd, " +
                "named_object no " + "where rfd.reference_file_rrn=no.instance_rrn and no.instance_id=? and " + " rfd" +
                ".data_3_value LIKE '%ALL%' and rfd.data_5_value = '1' order by rfd.data_1_value ";
        List<Map> holdReasons = jdbcTemplate.query(sql, args.toArray(), new RowMapper<Map>() {

            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map holdReason = new HashMap();
                holdReason.put("holdCode", rs.getString("key_1_value"));
                holdReason.put("holdDesc", rs.getString("data_1_value"));
                holdReason.put("holdUsersGroup", rs.getString("data_3_value"));
                return holdReason;
            }
        });

        return holdReasons;
    }

    @Override
    public List<Map> getReleaseGroup(String holdCode, String classTableValue) {
        String sql = "select rfd.data_4_value from reference_file_detail rfd, named_object no " + "where rfd" +
                ".reference_file_rrn=no.instance_rrn and no.instance_id=? and rfd" + ".key_1_value=?";
        List args = new ArrayList();
        args.add(classTableValue);
        args.add(holdCode);
        List<Map> releaseGroups = jdbcTemplate.query(sql, args.toArray(), new RowMapper<Map>() {

            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map map = new HashMap();
                map.put("releaseGroup", rs.getString("data_4_value"));
                return map;
            }
        });
        return releaseGroups;
    }

    @Override
    public Lot qryLotExtInfo(long lotRrn) {
        String sql = " SELECT LOT_RRN,ATTRIBUTE_DATA2," + " ATTRIBUTE_DATA1,WIFER_ID, WIFER_TYPE, FLOW_LEVEL, " +
                "CUSTOMER_ID," + " CUSTOMER_LOT_ID, CUSTOMER_WAFER_ID," +
                " OUTER_ORDER_NO, INNER_ORDER_NO, SHIPPING_CODE, " + "IS_OUT_SOURCE, IS_RECREATE_LOT, " +
                " PROJECT_CATEGORY,NVL(RETICLE_GROUP_RRN,0) AS RETICLE_GROUP_RRN," + "SPLIT_MERGE_FLAG, " +
                " RUNNING_HOLD_FLAG,OUT_ORDER_TYPE, LOCATION, PLOCATION FROM " + DataBaseNames.LOT_EXT +
                " WHERE LOT_RRN=?";
        return jdbcTemplate.queryForObject(sql, new Object[]{lotRrn}, new RowMapper<Lot>() {
            @Override
            public Lot mapRow(ResultSet rs, int rowNum) throws SQLException {
                Lot lotExt = new Lot();
                lotExt.setPollutionLevel(rs.getString("ATTRIBUTE_DATA1"));
                lotExt.setWiferId(rs.getString("WIFER_ID"));
                lotExt.setFlowLevel(rs.getString("FLOW_LEVEL"));
                lotExt.setCustomerId(rs.getString("CUSTOMER_ID"));
                lotExt.setCustomerLotId(rs.getString("CUSTOMER_LOT_ID"));
                lotExt.setOuterOrderNO(rs.getString("OUTER_ORDER_NO"));
                lotExt.setInnerOrderNO(rs.getString("INNER_ORDER_NO"));
                lotExt.setShippingCode(rs.getString("SHIPPING_CODE"));
                lotExt.setIsOutSource(rs.getString("IS_OUT_SOURCE"));
                lotExt.setIsReCreateLot(rs.getString("IS_RECREATE_LOT"));
                lotExt.setProjectCategory(rs.getString("PROJECT_CATEGORY"));
                lotExt.setReticleGroupRrn(rs.getLong("RETICLE_GROUP_RRN"));
                lotExt.setSplitMergeFlag(rs.getString("SPLIT_MERGE_FLAG"));
                lotExt.setRunningHoldFlag(rs.getString("RUNNING_HOLD_FLAG"));
                lotExt.setOutOrderType(rs.getString("OUT_ORDER_TYPE"));
                lotExt.setLocationRrn(rs.getLong("LOCATION"));
                lotExt.setpLocationRrn(rs.getLong("PLOCATION"));
                lotExt.setLocation(buildLocationId(rs.getLong("LOCATION")));
                lotExt.setpLocation(buildLocationId(rs.getLong("PLOCATION")));
                return lotExt;
            }
        });
    }

    @Override
    public boolean isMultipleHoldExisted(long lotRrn) {
        String sql = "SELECT count(*) FROM " + DataBaseNames.MULTIPLE_HOLD + " WHERE INSTANCE_RRN = ?";
        int result = jdbcTemplate.queryForObject(sql, new Object[]{lotRrn}, int.class);

        boolean flag = true;
        if (result == 0) {
            flag = false;
        }
        return flag;
    }

    @Override
    public List qryLotCreateHistory(long lotRrn, int current, int pageSize) {

        int fixPagesize = 10;
        //todo:该sql用trans_rrn进行排序
        String sql = " SELECT * FROM ( SELECT * FROM ( SELECT * FROM (SELECT TH.TRANS_RRN,TH.MATERIAL_LOT_NUMBER," +
                " TH.WAREHOUSE_ID,TH.ITEM_RRN,HE.LOT_BOX,TH.TRANS_QTY, " +
                " TL.TRANS_START_TIMESTAMP,TL.TRANS_END_TIMESTAMP," + "TL.TRANS_PERFORMED_BY ,IE.CUSTOMER_ID," +
                " IE.OFF_ORIENTATION,IE.TYPE_DOPANT,IE.THICKNESS,IE" + ".PRODUCTION_DATE,IE.VALID_TERM " +
                " FROM INVENTORY_TRANS_HISTORY TH,INVENTORY_TRANS_HISTORY_EXT HE," + "TRANSACTION_LOG TL, " +
                " LOT_INVENTORY_EXT IE " + " WHERE TH.TRANS_RRN = HE.TRANS_RRN AND TH" +
                ".TRANS_SEQUENCE = HE.TRANS_SEQUENCE AND " +
                " TH.TRANS_RRN = TL.TRANS_RRN AND TH.ITEM_RRN = IE.ITEM_RRN" + "(+) AND TH.WAREHOUSE_RRN = " +
                " IE.WAREHOUSE_RRN(+) AND TH.MATERIAL_LOT_NUMBER = IE.LOT_NUMBER(+) AND " +
                " TH.LOT_RRN = ? ORDER BY TH.TRANS_RRN DESC)" + " WHERE ROWNUM<=?)" + " ORDER BY TRANS_RRN) WHERE " +
                "ROWNUM<=?" + " ORDER BY TRANS_RRN DESC";
        List lotTransHistory = jdbcTemplate
                .query(sql, new Object[]{lotRrn, current * fixPagesize, pageSize}, new RowMapper<Map>() {
                    int j = ((current - 1) * fixPagesize) + 1;

                    @Override
                    public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                        Map m = new HashMap();

                        m.put("seq", new Integer(j++));
                        m.put("lotNumber", rs.getString("MATERIAL_LOT_NUMBER"));
                        m.put("transStartTimestamp", DateUtils
                                .formatDate(rs.getTimestamp("TRANS_START_TIMESTAMP"), DateUtils.DATE_FORMAT4DATE));
                        m.put("transEndTimestamp",
                              DateUtils.formatDate(rs.getTimestamp("TRANS_END_TIMESTAMP"), DateUtils.DATE_FORMAT4DATE));
                        String transByName = getTransByName(rs.getString("trans_performed_by"));
                        if (transByName != null) {
                            m.put("transPerformedBy", rs.getString("TRANS_PERFORMED_BY") + " " + transByName);
                        } else {
                            m.put("transPerformedBy", rs.getString("TRANS_PERFORMED_BY"));
                        }

                        m.put("productId", translateRrn(rs.getLong("ITEM_RRN")));

                        m.put("wareHouseId", rs.getString("WAREHOUSE_ID"));
                        m.put("lotBox", rs.getString("LOT_BOX"));

                        m.put("transQty", new Long(rs.getLong("TRANS_QTY")));

                        m.put("customerId",
                              StringUtils.isEmpty(rs.getString("CUSTOMER_ID")) ? "" : rs.getString("CUSTOMER_ID"));
                        m.put("offOrientation", StringUtils.isEmpty(rs.getString("OFF_ORIENTATION")) ? "" : rs
                                .getString("OFF_ORIENTATION"));
                        m.put("typeDopant",
                              StringUtils.isEmpty(rs.getString("TYPE_DOPANT")) ? "" : rs.getString("TYPE_DOPANT"));
                        m.put("thickness",
                              StringUtils.isEmpty(rs.getString("THICKNESS")) ? "" : rs.getString("THICKNESS"));
                        m.put("validTerm",
                              StringUtils.isEmpty(rs.getString("VALID_TERM")) ? "" : rs.getString("VALID_TERM"));
                        m.put("productionDate",
                              DateUtils.formatDate(rs.getTimestamp("PRODUCTION_DATE"), DateUtils.DATE_FORMAT4DATE));
                        return m;
                    }
                });

        return lotTransHistory;
    }

    @Override
    public String getConsumedMaterial(Long lotRrn) {
        String sql = "SELECT LISTAGG(INSTANCE_ID, ',') WITHIN GROUP (ORDER BY INSTANCE_ID) AS MATERIALS " + "FROM " +
                "(SELECT " + "DISTINCT NB.INSTANCE_ID AS INSTANCE_ID FROM UNIT U, " + "UNIT_INVENTORY " +
                "UI, NAMED_OBJECT NB WHERE U" + ".UNIT_RRN = UI.UNIT_RRN AND UI.ITEM_RRN = NB" +
                ".INSTANCE_RRN AND U.LOT_RRN = ?) T";

        return jdbcTemplate.queryForObject(sql, new Object[]{lotRrn}, String.class);
    }

    @Override
    public int countPilotLotInfo(long lotRrn) {
        String sql = "select count(d.instance_rrn) instanceRrn FROM multiple_hold d,lot t,trans_reason n," +
                "pilot_info_history y " + " where d.instance_rrn=t.lot_rrn and n.trans_rrn=d.trans_rrn " +
                " and t.lot_rrn=? " + "and n.reason_code='PILOTHOLD' " +
                " and y.lot_rrn=t.lot_rrn and y.step_sequence=t.step_sequence " + " and y" + ".status='WAITING'";
        Object[] args = new Object[]{lotRrn};
        int count = jdbcTemplate.queryForObject(sql, args, int.class);

        return count;
    }

    @Override
    public PilotLotInfo getPilotLotInfo(long lotRrn) {
        final String sql = "Select t1.lot_rrn, t2.* from (select t.trans_rrn,t.lot_rrn,t.step_sequence,\n" + " " +
                "END_PRODUCT_RRN,END_PROCESS_RRN,END_ROUTE_RRN,o2.INSTANCE_ID END_ROUTE_ID,\n" + " END_WFL_STEP_PATH," +
                "END_OPERATION_RRN,o3.INSTANCE_ID END_OPERATION_ID,\n" + " t.QTY,MIN_PARENT_QTY,END_STEP_SEQUENCE," +
                "SKIP_USER_GROUP_RRN,\n" + " o1.INSTANCE_ID SKIP_USER_GROUP_ID,STATUS,ATTRIBUTE_DATA1,\n" + " " +
                "ATTRIBUTE_DATA2,ATTRIBUTE_DATA4,ATTRIBUTE_DATA3,ATTRIBUTE_DATA5," + " t.PILOT_TIMES,t.PILOT_RULES,t" +
                ".PILOT_LOT_TYPE,t.MEASURE_OPERATIONS, " + " t.AUTO_RELEASE_SPC_HOLD,t.AUTO_RELEASE_PILOT_HOLD,t" +
                ".AUTO_MERGE_PILOT " + " From pilot_info_history t, named_object o1, named_object o2, named_object " +
                "o3\n" + " Where o1.instance_rrn = t.SKIP_USER_GROUP_RRN\n" + " and o2.instance_rrn = END_ROUTE_RRN\n" +
                " and o3.instance_rrn = END_OPERATION_RRN and t.status='WAITING' ) t2,lot t1\n" +
                " where t2.LOT_RRN(+) = t1.LOT_RRN and t2.STEP_SEQUENCE(+) = t1.STEP_SEQUENCE\n" +
                " and T1.LOT_RRN = ? ";
        PilotLotInfo pilotLotInfo = jdbcTemplate.queryForObject(sql, new Object[]{lotRrn}, new PilotLotInfoMapper());
        return pilotLotInfo;
    }

    @Override
    public List<Map> getLotsByReticle(long reticleRrn) {

        String sql = "SELECT L.LOT_ID,L.LOT_RRN,N.INSTANCE_ID AS EQPT_ID,L.EQPT_RRN " + " FROM LOT  L, NAMED_OBJECT  " +
                "N  WHERE L.EQPT_RRN = N.INSTANCE_RRN " + " AND  L.RETICLE_RRN = ?";

        List list = jdbcTemplate.query(sql, new Object[]{reticleRrn}, new RowMapper() {

            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map map = new HashMap();
                map.put("lotId", rs.getString("LOT_ID"));
                map.put("lotRrn", rs.getLong("LOT_RRN"));
                map.put("eqptId", rs.getString("EQPT_ID"));
                map.put("eqptRrn", rs.getLong("EQPT_RRN"));
                return map;
            }
        });

        return list;
    }

    @Override
    public List qryLotHoldReleaseHistory(long lotRrn) {

        List<Object> args = new ArrayList<>();
        StringBuilder where = new StringBuilder(" WHERE lt.lot_rrn = ?");
        args.add(lotRrn);
        where.append(" AND lt.trans_id IN ('HOLD','RELEASE','SUPERRELEASE','CHANGE_HOLD') ");

        StringBuilder sql = new StringBuilder(" SELECT ");
        sql.append(" lt.trans_rrn,lt.trans_id,tr.trans_start_timestamp, ls.eqpt_rrn,  ");
        sql.append(" tr.trans_end_timestamp, tr.trans_performed_by,ls.stage_id,ls.process_step_version, ");
        sql.append(" ls.process_rrn,ls.lot_rrn,ls.lot_id,ls.facility_rrn, ls.in_qty1, ls.out_qty1, ");
        sql.append(" NVL(te.reason_code,' ') as reason_code,NVL(te.reason,' ') as reason, ");
        sql.append(" ls.product_rrn,ls.operation_rrn,lt.trans_comments,ls.process_step_id_version, ");
        sql.append(" ls.product_layer, ls.route_seq,ls.operation_seq,ls.PROCESS_VERSION,ls.recipe_physical_id, ");
        sql.append(" Ls.flow_seq  FROM ((lot_trans_history lt INNER JOIN lot_step_history ls on lt.lot_rrn = ls.lot_rrn");
        sql.append(" and lt.step_sequence = ls.step_sequence) INNER JOIN transaction_log tr on lt.trans_rrn = tr.trans_rrn) ");
        sql.append(" LEFT JOIN trans_reason te on lt.lot_rrn = te.instance_rrn and lt.trans_rrn = te.trans_rrn ");
        sql.append(where);
        sql.append(" ORDER BY trans_start_timestamp DESC ");

        return jdbcTemplate.query(sql.toString(), args.toArray(), new RowMapper<Map<String, Object>>() {

            @Override
            public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {

                Map<String, Object> m = new HashMap<>();
                m.put("seq", rowNum + 1);
                m.put("trans_rrn", rs.getLong("trans_rrn") + "");
                m.put("trans_id", rs.getString("trans_id"));
                m.put("trans_start_timestamp",
                      DateUtils.formatDate(rs.getTimestamp("trans_start_timestamp"), DateUtils.DATE_FORMAT4DATE));
                m.put("trans_end_timestamp",
                      DateUtils.formatDate(rs.getTimestamp("trans_end_timestamp"), DateUtils.DATE_FORMAT4DATE));
                String transByName = getTransByName(rs.getString("trans_performed_by"));
                if (transByName != null) {
                    m.put("trans_performed_by", rs.getString("trans_performed_by") + " " + transByName);
                } else {
                    m.put("trans_performed_by", rs.getString("trans_performed_by"));
                }
                m.put("qty_1", rs.getLong("in_qty1"));
                m.put("qty_2", rs.getLong("out_qty1"));
                m.put("reason_code", rs.getString("reason_code"));
                m.put("reason", rs.getString("reason"));

                String processStepIdVer = rs.getString("process_step_id_version");

                m.put("product_rrn", rs.getLong("product_rrn"));
                m.put("process_rrn", rs.getLong("process_rrn"));
                m.put("operation_rrn", rs.getLong("operation_rrn"));

                m.put("route_id", parseRoute(processStepIdVer));
                m.put("comments", rs.getString("trans_comments"));
                m.put("stageId", rs.getString("stage_id"));
                m.put("recipeId", rs.getString("recipe_physical_id"));

                // TODO: 2020/9/29 梳理结构 整理key/value
                //                m.put("operationId", MapUtils.getString(m, "operation_id"));
                m.put("routeId", MapUtils.getString(m, "route_id"));
                //                m.put("processId", MapUtils.getString(m, "technology_id"));
                //                m.put("productId", MapUtils.getString(m, "product_id"));

                String processStepString = rs.getString("process_step_version");

                Lot lot = getLot(rs.getLong("lot_rrn"));
                lot.setOperationRrn(rs.getLong("operation_rrn"));
                lot.setProductRrn(rs.getLong("product_rrn"));
                lot.setProcessRrn(rs.getLong("process_rrn"));
                lot.setLotRrn(rs.getLong("lot_rrn"));
                lot.setLotId(rs.getString("lot_id"));
                lot.setProcessStepVersion(rs.getString("process_step_version"));
                long eqptRrn = rs.getLong("eqpt_rrn");
                if (eqptRrn > 0) {
                    lot.setEqptRrn(rs.getLong("eqpt_rrn"));
                } else {
                    lot.setEqptRrn(null);
                }

                lot.setFacilityRrn(rs.getLong("facility_rrn"));
                lot.setRouteRrn(parseRouteRrn(processStepString));
                lot.setRouteSeq(rs.getString("route_seq"));
                lot.setProductLayer(rs.getString("product_layer"));
                lot.setOperationSeq(rs.getString("operation_seq"));
                lot.setProcessVersion(rs.getInt("PROCESS_VERSION"));
                m.put("tempLot", lot);
                return m;
            }
        });
    }

    @Override
    public Page qryLotHoldReleaseHistory(Page page, long lotRrn, String lotTransId, String type) {
        List<Object> args = new ArrayList<>();
        StringBuilder where = new StringBuilder(" WHERE lt.lot_rrn = ?");
        args.add(lotRrn);
        if (StringUtils.isNotEmpty(lotTransId)) {
            if ("query".equals(type)) {
                where.append(" AND lt.trans_id IN ('HOLD','RELEASE','SUPERRELEASE','CHANGE_HOLD','HOLD_RUNNING_LOT','RELEASE_RUNNING_LOT','CREATE_FH','CHANGE_RUNNING_HOLD','CREATE_POSTFH') ");
            } else if ("export".equals(type)) {
                where.append(" AND lt.trans_id IN ('HOLD','RELEASE') ");
            }
        }

        String sql = " SELECT LT.TRANS_RRN,LT.TRANS_ID,TR.TRANS_START_TIMESTAMP, LS.EQPT_RRN," +
                " TR.TRANS_END_TIMESTAMP, TR.TRANS_PERFORMED_BY,LS.STAGE_ID,LS.PROCESS_STEP_VERSION," +
                " LS.PROCESS_RRN,LS.LOT_RRN,LS.LOT_ID,LS.FACILITY_RRN, LS.IN_QTY1, LS.OUT_QTY1," +
                " NVL(TE.REASON_CODE,' ') AS REASON_CODE,NVL(TE.REASON,' ') AS REASON,LS.PRODUCT_RRN," +
                " LS.OPERATION_RRN,LT.TRANS_COMMENTS,LS.PROCESS_STEP_ID_VERSION,LS.PRODUCT_LAYER, " +
                " LS.ROUTE_SEQ,LS.OPERATION_SEQ,LS.PROCESS_VERSION,LS.RECIPE_PHYSICAL_ID,LS.FLOW_SEQ " +
                " FROM ((LOT_TRANS_HISTORY LT INNER JOIN LOT_STEP_HISTORY LS ON LT.LOT_RRN = LS.LOT_RRN" +
                " AND LT.STEP_SEQUENCE = LS.STEP_SEQUENCE) " +
                " INNER JOIN TRANSACTION_LOG TR ON LT.TRANS_RRN = TR.TRANS_RRN) " +
                " LEFT JOIN TRANS_REASON TE ON LT.LOT_RRN = TE.INSTANCE_RRN AND LT.TRANS_RRN = TE.TRANS_RRN " +
                where.toString() + " ORDER BY TRANS_START_TIMESTAMP DESC ";

        return jdbcTemplate.queryForPage(page, sql, args.toArray(), (RowMapper<Map<String, Object>>) (rs, rowNum) -> {
            Map<String, Object> m = new HashMap<>();
            m.put("seq", rowNum + 1);
            m.put("trans_rrn", rs.getLong("trans_rrn") + "");
            m.put("trans_id", rs.getString("trans_id"));
            m.put("trans_start_timestamp",
                  DateUtils.formatDate(rs.getTimestamp("trans_start_timestamp"), DateUtils.DATE_FORMAT4DATE));
            m.put("trans_end_timestamp",
                  DateUtils.formatDate(rs.getTimestamp("trans_end_timestamp"), DateUtils.DATE_FORMAT4DATE));
            String transByName = getTransByName(rs.getString("trans_performed_by"));
            if (transByName != null) {
                m.put("trans_performed_by", rs.getString("trans_performed_by") + " " + transByName);
            } else {
                m.put("trans_performed_by", rs.getString("trans_performed_by"));
            }
            m.put("qty_1", rs.getLong("in_qty1"));
            m.put("qty_2", rs.getLong("out_qty1"));
            m.put("reason_code", rs.getString("reason_code"));
            m.put("reason", rs.getString("reason"));
            if (StringUtils.equalsIgnoreCase(rs.getString("trans_id"), TransactionNames.HOLD_RUNNING_LOT)) {
                m.put("reason", rs.getString("trans_comments"));
            } else if (StringUtils.equalsIgnoreCase(rs.getString("trans_id"), TransactionNames.CHANGE_RUNNING_HOLD_REASON)) {
                m.put("reason", rs.getString("trans_comments"));
            } else if (StringUtils.equalsIgnoreCase(rs.getString("trans_id"), TransactionNames.RELEASE_KEY)) {
                m.put("reason", rs.getString("trans_comments") + " " +
                        getTransReason(rs.getLong("trans_rrn"), rs.getLong("lot_rrn")));
            }
            String processStepIdVer = rs.getString("process_step_id_version");

            m.put("product_rrn", rs.getLong("product_rrn"));
            m.put("process_rrn", rs.getLong("process_rrn"));
            m.put("operation_rrn", rs.getLong("operation_rrn"));

            m.put("route_id", parseRoute(processStepIdVer));
            m.put("comments", rs.getString("trans_comments"));
            m.put("stageId", rs.getString("stage_id"));
            m.put("recipeId", rs.getString("recipe_physical_id"));

            // TODO: 2020/9/29 梳理结构 整理key/value
            //                m.put("operationId", MapUtils.getString(m, "operation_id"));
            m.put("routeId", MapUtils.getString(m, "route_id"));
            String processStepString = rs.getString("process_step_version");
            Lot lot = getLot(rs.getLong("lot_rrn"));
            lot.setOperationRrn(rs.getLong("operation_rrn"));
            lot.setProductRrn(rs.getLong("product_rrn"));
            lot.setProcessRrn(rs.getLong("process_rrn"));
            lot.setLotRrn(rs.getLong("lot_rrn"));
            lot.setLotId(rs.getString("lot_id"));
            lot.setProcessStepVersion(rs.getString("process_step_version"));
            long eqptRrn = rs.getLong("eqpt_rrn");
            if (eqptRrn > 0) {
                lot.setEqptRrn(rs.getLong("eqpt_rrn"));
            } else {
                lot.setEqptRrn(null);
            }

            lot.setFacilityRrn(rs.getLong("facility_rrn"));
            lot.setRouteRrn(parseRouteRrn(processStepString));
            lot.setRouteSeq(rs.getString("route_seq"));
            lot.setProductLayer(rs.getString("product_layer"));
            lot.setOperationSeq(rs.getString("operation_seq"));
            lot.setProcessVersion(rs.getInt("PROCESS_VERSION"));
            m.put("tempLot", lot);
            m.put("flowSeq", rs.getString("FLOW_SEQ"));
            return m;
        });
    }

    @Override
    public Page qryLotHoldInfoForRelease(Page page, long lotRrn, long transRrn) {
        String sql = "SELECT LT.TRANS_RRN,LT.TRANS_ID,TR.TRANS_START_TIMESTAMP, LS.EQPT_RRN," +
                " TR.TRANS_END_TIMESTAMP, TR.TRANS_PERFORMED_BY,LS.STAGE_ID,LS.PROCESS_STEP_VERSION," +
                " LS.PROCESS_RRN,LS.LOT_RRN,LS.LOT_ID,LS.FACILITY_RRN,LS.IN_QTY1, LS.OUT_QTY1, " +
                " NVL(TE.REASON_CODE,' ') AS REASON_CODE,NVL(TE.REASON,' ') AS REASON, " +
                " LS.PRODUCT_RRN,LS.OPERATION_RRN,LT.TRANS_COMMENTS,LS.PROCESS_STEP_ID_VERSION," +
                " LS.PRODUCT_LAYER, LS.ROUTE_SEQ,LS.OPERATION_SEQ,LS.PROCESS_VERSION,LS.FLOW_SEQ " +
                " FROM ((LOT_TRANS_HISTORY LT INNER JOIN LOT_STEP_HISTORY LS ON LT.LOT_RRN = LS.LOT_RRN " +
                " AND LT.STEP_SEQUENCE = LS.STEP_SEQUENCE) INNER JOIN TRANSACTION_LOG TR ON  LT.TRANS_RRN = TR" +
                ".TRANS_RRN)" +
                " LEFT JOIN TRANS_REASON TE ON LT.LOT_RRN = TE.INSTANCE_RRN AND LT.TRANS_RRN = TE.TRANS_RRN " +
                " WHERE  LT.LOT_RRN = ? AND LT.TRANS_RRN IN (SELECT TRANS_RRN FROM MULTIPLE_HOLD_H " +
                " WHERE RELEASE_TRANS_RRN=?) ORDER BY TR.TRANS_END_TIMESTAMP DESC ";

        page = jdbcTemplate.queryForPage(page, sql, new Object[]{lotRrn, transRrn}, (RowMapper<Map>) (rs, rowNum) -> {
            Map<String, Object> m = new HashMap<>();
            m.put("seq", rowNum + 1);
            m.put("trans_id", rs.getString("trans_id"));
            m.put("trans_start_timestamp", rs.getTimestamp("trans_start_timestamp"));
            m.put("trans_end_timestamp", DateUtils.formatDate(rs.getTimestamp("trans_end_timestamp")));
            String transByName = getTransByName(rs.getString("trans_performed_by"));
            if (transByName != null) {
                m.put("trans_performed_by", rs.getString("trans_performed_by") + " " + transByName);
            } else {
                m.put("trans_performed_by", rs.getString("trans_performed_by"));
            }
            m.put("qty_1", rs.getLong("in_qty1"));
            m.put("qty_2", rs.getLong("out_qty1"));
            m.put("reason_code", rs.getString("reason_code"));
            m.put("reason", rs.getString("reason"));
            String processStepIdVer = rs.getString("process_step_id_version");
            m.put("product_rrn", rs.getLong("product_rrn"));
            m.put("process_rrn", rs.getLong("process_rrn"));
            m.put("operation_rrn", rs.getLong("operation_rrn"));
            m.put("route_id", parseRoute(processStepIdVer));
            m.put("comments", rs.getString("trans_comments"));
            m.put("stageId", rs.getString("stage_id"));
            String processStepString = rs.getString("process_step_version");
            Lot lot = getLot(rs.getLong("lot_rrn"));
            lot.setOperationRrn(rs.getLong("operation_rrn"));
            lot.setProductRrn(rs.getLong("product_rrn"));
            lot.setProcessRrn(rs.getLong("process_rrn"));
            lot.setLotRrn(rs.getLong("lot_rrn"));
            lot.setLotId(rs.getString("lot_id"));
            lot.setProcessStepVersion(rs.getString("process_step_version"));
            long eqptRrn = rs.getLong("eqpt_rrn");
            if (eqptRrn > 0) {
                lot.setEqptRrn(rs.getLong("eqpt_rrn"));
            } else {
                lot.setEqptRrn(null);
            }

            lot.setFacilityRrn(rs.getLong("facility_rrn"));
            lot.setRouteRrn(parseRouteRrn(processStepString));
            lot.setRouteSeq(rs.getString("route_seq"));
            lot.setProductLayer(rs.getString("product_layer"));
            lot.setOperationSeq(rs.getString("operation_seq"));
            lot.setProcessVersion(rs.getInt("PROCESS_VERSION"));
            m.put("tempLot", lot);
            m.put("productLayer", rs.getString("product_layer"));
            m.put("flowSeq", rs.getString("FLOW_SEQ"));

            return m;
        });

        return page;
    }

    @Override
    public List qryLotSplitMergeHistory(long lotRrn, String startDate, String endDate, Integer thisPage,
                                        Integer pageSize, String type, String sourceLotId) {
        List args = new LinkedList();
        int fixPageSize = 10;
        //AND sm.source_lot_rrn = ?
        StringBuffer where = new StringBuffer(" where 1=1 and lt.lot_rrn = ?  ");
        args.add(lotRrn);

        if (StringUtils.isNotEmpty(sourceLotId)) {
            where.append(" and (sm.source_lot_id = ? or sm.target_lot_id = ?) and ls.facility_rrn = ?");

            args.add(sourceLotId);
            args.add(sourceLotId);
            args.add(LocalContext.getFacilityRrn());
        }

        StringBuffer timeRange = new StringBuffer();
        if (StringUtils.isNotEmpty(startDate)) {
            timeRange.append(" AND trans_end_timestamp >= to_timestamp(?,'" + DateUtils.DATE_FORMAT24 + "')");
            args.add(startDate + " 00:00:00");
        }

        if (StringUtils.isNotEmpty(endDate)) {
            timeRange.append(" AND trans_end_timestamp <= to_timestamp(?,'" + DateUtils.DATE_FORMAT24 + "')");
            args.add(endDate + " 00:00:00");
        }


        String sql = "SELECT * FROM ( SELECT * FROM (SELECT lt.trans_rrn,lt.trans_id,sm.source_lot_id, " +
                "target_lot_id, tr" + ".trans_performed_by, tr.trans_end_timestamp, sm.trans_qty1, ls.in_qty2," +
                " ls" + ".product_rrn,ls.process_rrn,ls.operation_rrn,ls.stage_id,ls.eqpt_rrn," +
                " NVL(sm.target_unit_id,' ') as " + "unitIds," +
                " NVL(lt.trans_comments,' ') as trans_comments,ls.process_step_id_version," + " ls.lot_rrn,ls" +
                ".lot_id,ls.facility_rrn,ls.process_step_version, ls.product_layer," +
                " ls.route_seq,ls.operation_seq,ls" + ".PROCESS_VERSION,ls.recipe_physical_id " +
                " FROM ((lot_step_history ls inner join lot_trans_history lt " + "on " +
                " lt.lot_rrn = ls.lot_rrn and lt.step_sequence = ls.step_sequence) inner join " + " " +
                "transaction_log tr on lt.trans_rrn = tr.trans_rrn) left join split_merge_history " + "sm " + " on lt" +
                ".trans_rrn = sm.trans_rrn" + where.toString() + " and (lt.trans_id ='SPLIT' OR lt.trans_id='MERGE' " +
                " ) AND sm.source_lot_rrn != sm.target_lot_rrn " + timeRange +
                " ORDER BY trans_end_timestamp DESC ) WHERE ROWNUM > ?) WHERE ROWNUM <=?";

        int j = 0;
        if ("query".equals(type)) {
            args.add((thisPage - 1) * fixPageSize);
            args.add(pageSize);
            j = ((thisPage - 1) * fixPageSize) + 1;
        } else if ("export".equals(type)) {
            args.add(0);
            args.add(9999999);
            j = 1;
        }

        int finalJ = j;
        List lotTransHistory = jdbcTemplate.query(sql, args.toArray(), new RowMapper<Map>() {

            int i = finalJ;

            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map m = new HashMap();

                m.put("seq", new Integer(i++));
                m.put("trans_id", rs.getString("trans_id"));
                m.put("from_lot_id", rs.getString("source_lot_id"));
                m.put("to_lot_id", rs.getString("target_lot_id"));

                String transByName = getTransByName(rs.getString("trans_performed_by"));
                if (transByName != null) {
                    m.put("trans_performed_by", rs.getString("trans_performed_by") + " " + transByName);
                } else {
                    m.put("trans_performed_by", rs.getString("trans_performed_by"));
                }
                m.put("qty_1", new Long(rs.getLong("trans_qty1")));
                m.put("qty_2", new Long(rs.getLong("in_qty2")));

                String processStepIdVer = rs.getString("process_step_id_version");
                m.put("route_id", parseRoute(processStepIdVer));
                m.put("trans_end_timestamp", DateUtils.formatDate(rs.getTimestamp("trans_end_timestamp")));
                m.put("comments", rs.getString("trans_comments"));
                m.put("unitIds", rs.getString("unitIds"));
                // 获取母批Id
                String par_lot_id = StringUtils.EMPTY;
                Lot tmp = getLot(rs.getLong("facility_rrn"), rs.getString("target_lot_id"));
                if (tmp != null && tmp.getLotRrn() > 0 && tmp.getBasedLotRrn() != null) {
                    Lot parLot = getLot(tmp.getBasedLotRrn());
                    par_lot_id = parLot.getLotId();
                }
                m.put("par_lot_id", par_lot_id);

                m.put("facilityRrn", new Long(rs.getLong("facility_rrn")));
                m.put("productLayer", rs.getString("product_layer"));
                m.put("eqpt_rrn", rs.getLong("eqpt_rrn"));
                m.put("product_rrn", rs.getLong("product_rrn"));
                m.put("operation_rrn", rs.getLong("operation_rrn"));
                m.put("process_rrn", rs.getLong("process_rrn"));
                m.put("recipeId", rs.getString("recipe_physical_id"));
                m.put("stageId", rs.getString("stage_id"));
                m.put("routeId", MapUtils.getString(m, "route_id"));
                return m;
            }

        });

        return lotTransHistory;
    }

    @Override
    public Page qryLotSplitMergeHistory(Page page, long lotRrn, String startDate, String endDate, String sourceLotId) {
        StringBuilder where = new StringBuilder(" WHERE 1=1 AND lt.lot_rrn = ?  ");

        StringBuilder timeRange = new StringBuilder();
        if (StringUtils.isNotEmpty(startDate)) {
            timeRange.append(" AND trans_end_timestamp >=to_timestamp('");
            timeRange.append(startDate);
            timeRange.append(" 00:00:00','" + DateUtils.DATE_FORMAT24 + "')");
        }

        if (StringUtils.isNotEmpty(endDate)) {
            timeRange.append(" AND trans_end_timestamp <=to_timestamp('");
            timeRange.append(endDate);
            timeRange.append(" 00:00:00','" + DateUtils.DATE_FORMAT24 + "')");
        }

        if (StringUtils.isNotEmpty(sourceLotId)) {
            where.append(
                    " AND (SM.SOURCE_LOT_ID = '" + sourceLotId + "' OR SM.TARGET_LOT_ID = '" + sourceLotId + "') AND " +
                            "LS.FACILITY_RRN = " + LocalContext.getFacilityRrn());
        }


        String sql = "select * from (SELECT lt.trans_rrn,lt.trans_id,sm.source_lot_id," + " target_lot_id," + " tr" +
                ".trans_performed_by, tr.trans_end_timestamp, sm.trans_qty1, ls.in_qty2," +
                " ls.product_rrn,ls.process_rrn," + "ls.operation_rrn,ls.stage_id,ls.eqpt_rrn," +
                " NVL(sm.target_unit_id,' ') as unitIds," + " NVL(lt" +
                ".trans_comments,' ') as trans_comments,ls.process_step_id_version," + " ls.lot_rrn,ls.lot_id,ls" +
                ".facility_rrn,ls.process_step_version, ls.product_layer," + " ls.route_seq,ls.operation_seq,ls" +
                ".PROCESS_VERSION,ls.recipe_physical_id,ls.flow_seq " +
                " FROM ((lot_step_history ls inner join lot_trans_history lt" + " on " +
                " lt.lot_rrn = ls.lot_rrn and lt.step_sequence = ls.step_sequence) inner join " + " " +
                "transaction_log tr on lt.trans_rrn = tr.trans_rrn) left join split_merge_history sm " + " on lt" +
                ".trans_rrn = sm.trans_rrn" + where.toString() + " and (lt.trans_id ='SPLIT' OR lt.trans_id='MERGE' " +
                " ) AND sm.source_lot_rrn != sm.target_lot_rrn " + timeRange +
                " ORDER BY trans_end_timestamp DESC) result";

        Object[] args = new Object[]{lotRrn};
        return jdbcTemplate.queryForPage(page, sql, args, (RowMapper<Map>) (rs, rowNum) -> {
            Map m = new HashMap();

            m.put("seq", rs.getLong("rn"));
            m.put("trans_id", rs.getString("trans_id"));
            m.put("from_lot_id", rs.getString("source_lot_id"));
            m.put("to_lot_id", rs.getString("target_lot_id"));

            String transByName = getTransByName(rs.getString("trans_performed_by"));
            if (transByName != null) {
                m.put("trans_performed_by", rs.getString("trans_performed_by") + " " + transByName);
            } else {
                m.put("trans_performed_by", rs.getString("trans_performed_by"));
            }
            m.put("qty_1", new Long(rs.getLong("trans_qty1")));
            m.put("qty_2", new Long(rs.getLong("in_qty2")));

            String processStepIdVer = rs.getString("process_step_id_version");
            m.put("route_id", parseRoute(processStepIdVer));
            m.put("trans_end_timestamp", DateUtils.formatDate(rs.getTimestamp("trans_end_timestamp")));
            m.put("comments", rs.getString("trans_comments"));
            m.put("unitIds", rs.getString("unitIds"));
            // 获取母批Id
            String par_lot_id = StringUtils.EMPTY;
            Lot tmp = getLot(rs.getLong("facility_rrn"), rs.getString("target_lot_id"));
            if (tmp != null && tmp.getLotRrn() > 0 && tmp.getBasedLotRrn() != null) {
                Lot parLot = getLot(tmp.getBasedLotRrn());
                par_lot_id = parLot.getLotId();
            }
            m.put("par_lot_id", par_lot_id);

            m.put("facilityRrn", rs.getLong("facility_rrn"));
            m.put("productLayer", rs.getString("product_layer"));
            m.put("eqpt_rrn", rs.getLong("eqpt_rrn"));
            m.put("product_rrn", rs.getLong("product_rrn"));
            m.put("operation_rrn", rs.getLong("operation_rrn"));
            m.put("process_rrn", rs.getLong("process_rrn"));
            m.put("recipeId", rs.getString("recipe_physical_id"));
            m.put("stageId", rs.getString("stage_id"));
            m.put("routeId", MapUtils.getString(m, "route_id"));
            m.put("flowSeq", rs.getString("flow_seq"));
            return m;
        });
    }

    @Override
    public Long qryLotSplitMergeHistoryCount(long lotRrn, String startDate, String endDate) {
        StringBuffer where = new StringBuffer(" WHERE 1=1 AND lt.lot_rrn = ? ");

        StringBuffer timeRange = new StringBuffer();
        if (StringUtils.isNotEmpty(startDate)) {
            timeRange.append(" and trans_end_timestamp >=TO_DATE('");
            timeRange.append(startDate);
            timeRange.append(" 00:00:00','" + DateUtils.DATE_FORMAT24 + "')");
        }
        if (StringUtils.isNotEmpty(endDate)) {
            timeRange.append(" and trans_end_timestamp <=TO_DATE('");
            timeRange.append(endDate);
            timeRange.append(" 00:00:00','" + DateUtils.DATE_FORMAT24 + "')");
        }
        String sql = "SELECT count(*) FROM  (SELECT lt.trans_rrn,lt.trans_id,sm.source_lot_id," + " target_lot_id, tr" +
                ".trans_performed_by, tr.trans_end_timestamp, sm.trans_qty1, ls" +
                ".in_qty2, ls.product_rrn,ls.process_rrn," + "ls.operation_rrn,ls.stage_id,ls.eqpt_rrn," +
                " NVL(sm.target_unit_id,' ') as unitIds,NVL(lt" + ".trans_comments,' ') " +
                " as trans_comments,ls.process_step_id_version,ls.lot_rrn,ls.lot_id,ls" + ".facility_rrn," +
                "ls.process_step_version,ls.product_layer " + " FROM lot_trans_history lt, " +
                "lot_step_history ls, transaction_log tr, " + "split_merge_history sm " + where.toString() + " AND lt" +
                ".lot_rrn = ls.lot_rrn AND lt.step_sequence = ls.step_sequence AND sm" +
                ".trans_rrn(+) = lt.trans_rrn " + " AND lt.trans_rrn = " +
                " tr.trans_rrn AND (lt.trans_id ='SPLIT' OR lt.trans_id='MERGE'  " + " ) AND " +
                "sm.source_lot_rrn != sm.target_lot_rrn " + timeRange.toString() + ")";

        Long count = jdbcTemplate.queryForObject(sql, new Object[]{lotRrn}, long.class);

        return count;
    }

    @Override
    public List<Map> getScrapReasons(long lotRrn) {
        String sql = "select tr.reason,tr.trans_qty1,tr.responsibility,lo.trans_start_timestamp from" + " " +
                "trans_reason tr, transaction_log lo  where tr.instance_rrn =?" + " and" +
                " tr.reason_category='SCRAP' and " + "tr.trans_rrn=lo.trans_rrn and tr.trans_rrn >" +
                " NVL((select max(tr.trans_rrn) from trans_reason tr  " + "where tr.instance_rrn =?" +
                " and tr.reason_category='UNSCRAP'),0)";
        return jdbcTemplate.query(sql, new Object[]{lotRrn, lotRrn}, new RowMapper() {
            @Override
            public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map holdReason = new HashMap();
                holdReason.put("reason", rs.getString("reason"));
                holdReason.put("holdDate", rs.getTimestamp("trans_start_timestamp"));
                holdReason.put("responsibility", rs.getString("responsibility"));
                holdReason.put("transQty1", new Long(rs.getLong("trans_qty1")));
                return holdReason;
            }
        });
    }

    @Override
    public List<TimelimitStatus> getLotTimelimitStatusByLotRrn(Long lotRrn, String targetStatus) {
        List args = new ArrayList();
        args.add(lotRrn);
        StringBuilder sb = new StringBuilder();
        sb.append("SELECT ");
        sb.append("LOT_RRN, TIMELIMIT_ID, TIMELIMIT_TYPE, ");
        sb.append("START_PRODUCT_RRN, START_PROCESS_RRN, START_PROCESS_VERSION, START_PROCESS_VERSION ," +
                          "START_ROUTE_RRN, START_OPERATION_RRN, ");
        sb.append("END_PRODUCT_RRN, END_PROCESS_RRN, END_ROUTE_RRN, END_OPERATION_RRN, ");
        sb.append("TIMELIMIT, START_TIME, STATUS, MODULE, ADDITIONAL_TIMELIMIT, TIMELIMIT_RRN, TIME_TYPE, " +
                          "LIMIT_TYPE," + " ");
        sb.append("START_ROUTE_SEQ, START_OPERATION_SEQ, END_ROUTE_SEQ, END_OPERATION_SEQ, STEP_SEQUENCE ");
        sb.append("FROM " + DataBaseNames.TIMELIMIT_STATUS + " WHERE LOT_RRN = ? ");
        if (StringUtils.equalsIgnoreCase(targetStatus, "NO_CLOSE")) {
            sb.append(" AND STATUS <> 'CLOSE' ");
        } else if (StringUtils.isNotBlank(targetStatus)) {
            sb.append(" AND STATUS=? ");
            args.add(targetStatus);
        }

        sb.append(" ORDER BY STATUS,TIME_TYPE, START_TIME ");

        return jdbcTemplate.query(sb.toString(), args.toArray(), new TimeLimitStatusRowMapper());
    }

    @Override
    public Page qryLotStatus(Page page, Map condition) {
        List qryConditions = new ArrayList();

        String where = "";
        String orderBy = "LOT_ID";
        String orderBy1 = orderBy;
        String orderBy2 = orderBy + " DESC ";

        if (MapUtils.isNotEmpty(condition) && condition.size() != 0) {
            if (condition.get("facility") != null) {
                where += " AND FACILITY_RRN = ? ";
                qryConditions.add(((Long) condition.get("facility")).longValue());
            }

            if (StringUtils.isNotEmpty(StringUtils.toString(condition.get("productRrn")))) {
                where += " AND PRODUCT_RRN = ? ";
                qryConditions.add(((Long) condition.get("productRrn")).longValue());
            }

            if (StringUtils.isNotEmpty(StringUtils.toString(condition.get("processRrn")))) {
                where += " AND PROCESS_RRN = ? ";
                qryConditions.add(((Long) condition.get("processRrn")).longValue());
            }

            if (StringUtils.isNotEmpty(StringUtils.toString(condition.get("operationRrn")))) {
                where += " AND OPERATION_RRN = ? ";
                qryConditions.add(((Long) condition.get("operationRrn")).longValue());
            }

            if (StringUtils.isNotEmpty(StringUtils.toString(condition.get("objectType")))) {
                if ("NONPROD".equals(condition.get("objectType").toString())) {
                    where += " AND OBJECT_TYPE IN ('DUMMY'," + MiscUtils.parseSQL(ObjectList.SAPPHIRE) + ") ";
                } else if ("PROD".equals(condition.get("objectType").toString())) {
                    where += " AND OBJECT_TYPE  NOT IN ('DUMMY'," + MiscUtils.parseSQL(ObjectList.SAPPHIRE) + ") ";
                } else {
                    where += " AND OBJECT_TYPE = ?";
                    qryConditions.add(condition.get("objectType"));
                }
            }

            if (StringUtils.isNotEmpty((String) condition.get("lotStatus"))) {
                if (!LotStatus.ALL.equals(condition.get("lotStatus").toString())) {
                    if (LotStatus.ACTIVE.equals(condition.get("lotStatus").toString())) {
                        where += " AND LOT_STATUS IN ('" + LotStatus.RUNNING + "','" + LotStatus.WAITING + "') ";
                    } else if ("UNACTIVE".equals(condition.get("lotStatus").toString())) {
                        where += " AND LOT_STATUS IN ('" + LotStatus.BONDED + "','" + LotStatus.FINISH + "','" +
                                LotStatus.TERMINATED + "', '" + LotStatus.SCRAPPED + "') ";
                    } else if ("REWORK".equals(condition.get("lotStatus").toString())) {
                        where += " AND REWORK_CATEGORY IS NOT NULL ";
                    } else if ("HOLD".equals(condition.get("lotStatus").toString())) {
                        where += " AND LOT_STATUS IN ('" + LotStatus.HOLD + "','" + LotStatus.RUNNINGHOLD + "') ";
                    } else if ("ACTIVE_HOLD".equals(condition.get("lotStatus").toString())) {
                        where += " AND LOT_STATUS IN ('" + LotStatus.RUNNING + "','" + LotStatus.WAITING + "','" +
                                LotStatus.HOLD + "','" + LotStatus.RUNNINGHOLD + "') ";
                    } else {
                        where += " AND LOT_STATUS = ?";
                        qryConditions.add(condition.get("lotStatus"));
                    }
                }
            }

            if (StringUtils.isNotEmpty((String) condition.get("sortCondition"))) {
                orderBy = (String) condition.get("sortCondition");
                if ("DESC".equalsIgnoreCase((String) condition.get("sequence"))) {
                    String sequence = " " + condition.get("sequence");
                    orderBy1 = orderBy + sequence;
                    orderBy2 = orderBy;
                } else {
                    orderBy1 = orderBy;
                    orderBy2 = orderBy + " DESC ";
                }
            }
        }

        String sql = "SELECT * FROM " + "(SELECT * FROM " + " (SELECT a.LOT_RRN, a.LOT_ID, a.LOT_OWNER, a.PRIORITY, a" +
                ".HOT_FLAG,a.LOT_STATUS, a" + ".QTY1, " +
                "a.PRODUCT_RRN,a.PRODUCT_VERSION,a.PROCESS_RRN,a.PROCESS_VERSION, " + "a" +
                ".PROCESS_STEP_ID_VERSION, a" + ".STAGE_ID, a.OPERATION_RRN, " + "a.NEXT_OPERATION_RRN1, a" +
                ".CARRIER_RRN, a.PRODUCT_LAYER,a.route_seq,a.operation_seq, " + "a.PROCESS_STEP_VERSION, a.EQPT_RRN, " +
                "a.FACILITY_RRN,a.REWORK_CATEGORY,a.CREATED_TIMESTAMP,b.OBJECT_TYPE,b.INSTANCE_ID AS" + " PRODUCT_ID," +
                "c.INSTANCE_ID AS CARRIER_ID " + "FROM " + DataBaseNames.LOT + " a " + "LEFT JOIN " +
                DataBaseNames.NAMEDOBJECT + " b " + "ON a.PRODUCT_RRN=b.INSTANCE_RRN " + "LEFT JOIN " +
                DataBaseNames.NAMEDOBJECT + " c " + "ON a.CARRIER_RRN=c.INSTANCE_RRN" + " ORDER BY  " + orderBy1 +
                " ) t0 " + "WHERE 1=1 " + where + " ORDER BY " + orderBy2 + " ) t1 " + " ORDER BY " + orderBy1;

        Object[] args = qryConditions.toArray();

        page = jdbcTemplate.queryForPage(page, sql, args, new RowMapper() {

            @Override
            public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map m = new HashMap();
                m.put("lot_rrn", new Long(rs.getLong("lot_rrn")));
                m.put("lot_id", rs.getString("lot_id"));
                m.put("carrier_id", rs.getString("carrier_id"));
                m.put("lot_owner", rs.getString("lot_owner"));
                m.put("priority", rs.getString("priority"));
                m.put("hotFlag", rs.getString("hot_flag"));
                m.put("lot_status", rs.getString("lot_status"));
                m.put("qty1", new Double(rs.getDouble("qty1")));
                m.put("product_id", rs.getString("product_id"));
                m.put("product_version", rs.getInt("product_version"));
                m.put("product_rrn", rs.getLong("product_rrn"));
                m.put("process_rrn", rs.getLong("process_rrn"));
                m.put("process_version", rs.getInt("process_version"));
                m.put("route_id", parseRoute(rs.getString("process_step_id_version")));
                m.put("route_rrn", parseRouteRrn(rs.getString("process_step_version")));
                m.put("stageId", rs.getString("stage_id"));
                m.put("operation_rrn", rs.getLong("operation_rrn"));
                m.put("next_operation_rrn1", rs.getLong("next_operation_rrn1"));
                m.put("operationId", MapUtils.getString(m, "operation_id"));
                m.put("routeId", MapUtils.getString(m, "route_id"));
                m.put("processId", MapUtils.getString(m, "process_id"));
                m.put("productId", MapUtils.getString(m, "product_id"));
                m.put("facilityRrn", new Long(rs.getLong("facility_rrn")));

                m.put("eqpt_rrn", rs.getLong("eqpt_rrn"));
                return m;
            }
        });

        return page;
    }

    @Override
    public List<Map> getLotInfo4Transaction(Long jobRrn, Long lotRrn) {

        List<Map> lotsInfo = new ArrayList();

        if ((jobRrn == null) && (lotRrn == null)) {
            return lotsInfo;
        }
        Object[] args;
        StringBuilder sql = new StringBuilder();
        sql.append(" SELECT L.OPERATION_RRN,L.PROCESS_STEP_VERSION, L.lot_status,L.STEP_SEQUENCE,L" + ".CARRIER_RRN,L" +
                           ".LOT_RRN,L.FACILITY_RRN,L.Lot_id,L.QTY1,L.QTY2,L.PRODUCT_RRN,L" + ".REWORK_TRANS_RRN,L" +
                           ".EXECUTION_RRN EXECUTION_RRN_IN_LOT,");
        sql.append(
                "R.EXECUTION_RRN  EXECUTION_RRN_IN_REWORK,R.RETURN_PROCESS_STEP_VERSION,R" + ".RETURN_WFL_STEP_PATH,L" +
                        ".PROCESS_RRN,L.PRODUCT_LAYER,L.ROUTE_SEQ,L.OPERATION_SEQ,L" + ".PROCESS_VERSION FROM ");
        sql.append(DataBaseNames.LOT);
        sql.append(" L LEFT JOIN ");
        sql.append(DataBaseNames.REWORK_INFO_HISTORY);
        sql.append(" R ON L.REWORK_TRANS_RRN = R.TRANS_RRN AND L.LOT_RRN = R.LOT_RRN");

        if (jobRrn != null) {
            sql.append(" WHERE job_rrn = ? ");
            args = new Object[]{jobRrn};
        } else {
            sql.append(" WHERE L.LOT_RRN = ? ");
            args = new Object[]{lotRrn};
        }


        lotsInfo = jdbcTemplate.query(sql.toString(), args, new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                //TODO:fix me
                Map _temp = new HashMap();
                String[] routeVer = WipUtils.getRouteByProcessStepVersion(rs.getString("PROCESS_STEP_VERSION"));
                String route = routeVer[0];
                _temp.put("route", route);
                _temp.put("operationRrn", rs.getString("operation_Rrn"));
                _temp.put("lotRrn", rs.getString("LOT_RRN"));
                _temp.put("lotId", rs.getString("LOT_ID"));
                _temp.put("facilityRrn", rs.getString("FACILITY_RRN"));
                _temp.put("qty", rs.getDouble("QTY1") + "");
                _temp.put("qty2", rs.getDouble("QTY2") + "");
                _temp.put("productRrn", rs.getString("PRODUCT_RRN"));
                _temp.put("technologyRrn", rs.getString("PROCESS_RRN"));
                _temp.put("stepSequence", new Long(rs.getLong("STEP_SEQUENCE")));
                _temp.put("carrierRrn", new Long(rs.getLong("CARRIER_RRN")));
                _temp.put("lotStatus", rs.getString("lot_status"));
                _temp.put("productLayer", rs.getString("product_layer"));
                _temp.put("routeSeq", rs.getString("ROUTE_SEQ"));
                _temp.put("operationSeq", rs.getString("OPERATION_SEQ"));
                _temp.put("processVersion", rs.getString("PROCESS_VERSION"));
                if (rs.getLong("REWORK_TRANS_RRN") > 0) {
                    _temp.put("isReworkFlag", "1");
                    _temp.put("executionRrn", rs.getString("EXECUTION_RRN_IN_REWORK"));
                    _temp.put("lotExecutionRrn", rs.getString("EXECUTION_RRN_IN_LOT"));
                    _temp.put("returnProcessStepVersion", rs.getString("RETURN_PROCESS_STEP_VERSION"));
                    _temp.put("returnProcessStepVersion4Wfl", rs.getString("RETURN_WFL_STEP_PATH"));
                    _temp.put("reworkTransRrn", new Long(rs.getLong("REWORK_TRANS_RRN")));
                } else {
                    _temp.put("isReworkFlag", "0");
                    _temp.put("executionRrn", rs.getString("EXECUTION_RRN_IN_LOT"));
                }
                return _temp;
            }
        });

        return lotsInfo;
    }

    @Override
    public String getLayerId(long executeRrn) {
        String sql = "SELECT l.layer_id " + " FROM " + DataBaseNames.LOT + " L" + " WHERE l.execution_rrn = ? ";

        Object[] args = new Object[]{executeRrn};

        return jdbcTemplate.queryForObject(sql, args, String.class);
    }

    @Override
    public List<Bonding> getBondingsByLotRrn(long targetLotRrn, String sourceLotPlanType) {
        StringBuilder sql = new StringBuilder(
                "SELECT BL.TARGET_LOT_RRN,TL.LOT_ID AS TARGETLOTID,BL.SOURCE_LOT_RRN,SL.LOT_ID AS " + "SOURCELOTID,BL" +
                        ".TARGET_PLAN_TYPE,BL.SOURCE_PLAN_TYPE, ");
        sql.append(" SL.PRODUCT_RRN AS SOURCE_PRODUCT_RRN, TL.PRODUCT_RRN  AS TARGET_PRODUCT_RRN ");
        sql.append(" FROM BONDING_LOT BL,LOT TL,LOT SL ");

        sql.append(" WHERE BL.TARGET_LOT_RRN =TL.LOT_RRN AND BL.SOURCE_LOT_RRN=SL.LOT_RRN ");
        sql.append(" AND TARGET_LOT_RRN=? ");

        ArrayList args = new ArrayList();
        args.add(targetLotRrn);
        if (StringUtils.isNotBlank(sourceLotPlanType)) {
            sql.append(" AND (SOURCE_PLAN_TYPE = ? OR SOURCE_PLAN_TYPE IS NULL) ");
            args.add(sourceLotPlanType);
        }
        sql.append(" ORDER BY SL.LOT_RRN ASC ");

        return jdbcTemplate.query(sql.toString(), args.toArray(), new RowMapper<Bonding>() {

            @Override
            public Bonding mapRow(ResultSet rs, int rowNum) throws SQLException {
                Bonding bonding = new Bonding();

                bonding.setTargetLotRrn(rs.getLong("TARGET_LOT_RRN"));
                bonding.setTargetLotId(rs.getString("TARGETLOTID"));
                bonding.setSourceLotRrn(rs.getLong("SOURCE_LOT_RRN"));
                bonding.setSourceLotId(rs.getString("SOURCELOTID"));
                bonding.setTargetPlanType(rs.getString("TARGET_PLAN_TYPE"));
                bonding.setSourcePlanType(rs.getString("SOURCE_PLAN_TYPE"));
                bonding.setSourceProductRrn(rs.getLong("SOURCE_PRODUCT_RRN"));
                bonding.setTargetProductRrn(rs.getLong("TARGET_PRODUCT_RRN"));

                return bonding;
            }
        });
    }

    @Override
    public int getInuseWaferQtyForReticle(long reticleRrn) {
        String sql = "SELECT NVL(SUM(QTY1),0) FROM LOT  L WHERE L.RETICLE_RRN=?";

        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{reticleRrn}, int.class);
    }

    @Override
    public List<LotRecycledInfo> queryLotRecycledInfoByLotNoVersion(LotRecycledInfo lotRecycledInfo) {
        String sql = "SELECT sum(loop_count) loop_count,lot_rrn, process_rrn,start_route_rrn," +
                "start_operation_rrn,end_route_rrn,end_operation_rrn,process_version" +
                " FROM lot_recycled h where lot_rrn =" + " ? and process_rrn=? group by lot_rrn, " + "process_rrn, " +
                "start_route_rrn, start_operation_rrn," + " " + "end_route_rrn,end_operation_rrn,process_version";

        List<LotRecycledInfo> lotRecycledInfos = jdbcTemplate.query(sql,
                                                                    new Object[]{new Long(lotRecycledInfo.getLotRrn()),
                                                                                 new Long(lotRecycledInfo
                                                                                                  .getProcessRrn())},
                                                                    new RowMapper<LotRecycledInfo>() {

                                                                        @Override
                                                                        public LotRecycledInfo mapRow(ResultSet rs,
                                                                                                      int rowNum) throws SQLException {
                                                                            LotRecycledInfo lotRecycledInfo =
                                                                                    new LotRecycledInfo();

                                                                            lotRecycledInfo
                                                                                    .setLotRrn(rs.getLong("lot_rrn"));
                                                                            lotRecycledInfo.setProcessRrn(
                                                                                    rs.getLong("process_rrn"));
                                                                            lotRecycledInfo.setStartRouteRrn(
                                                                                    rs.getLong("start_route_rrn"));
                                                                            lotRecycledInfo.setStartOperationRrn(
                                                                                    rs.getLong("start_operation_rrn"));
                                                                            lotRecycledInfo.setEndRouteRrn(
                                                                                    rs.getLong("end_route_rrn"));
                                                                            lotRecycledInfo.setEndOperationRrn(
                                                                                    rs.getLong("end_operation_rrn"));
                                                                            lotRecycledInfo.setLoopCount(
                                                                                    rs.getInt("loop_count"));
                                                                            lotRecycledInfo.setProcessVersion(
                                                                                    rs.getInt("process_version"));

                                                                            return lotRecycledInfo;
                                                                        }
                                                                    });

        return lotRecycledInfos;
    }

    @Override
    public LotStepHistory getLotStepHistory(long lotRrn, long stepSequence) {
        String sql = "SELECT LOT_RRN,STEP_SEQUENCE,FACILITY_RRN,LOT_ID,PRODUCT_RRN,PRODUCT_VERSION,PROCESS_RRN," +
                "PROCESS_VERSION," + "PROCESS_STEP_VERSION,PROCESS_STEP_ID_VERSION,OPERATION_RRN,OPERATION_VERSION," +
                "SUBCONTRACTOR_RRN,STAGE_ID,LAYER_ID,CARRIER_RRN,CARRIER_MAP_RRN,RUN_RRN,EQPT_RRN," + "RECIPE_STRING," +
                "RETICLE_RRN,BIN_RRN,MOVE_IN_DCOL_RRN,MOVE_OUT_DCOL_RRN,AD_HOC_DCOL_RRN," + "REWORK_FLAG,SPLIT_QTY1," +
                "SPLIT_QTY2,MERGE_QTY1,MERGE_QTY2,LOSS_QTY1,LOSS_QTY2,BONUS_QTY1," +
                "BONUS_QTY2,SCRAP_QTY1,SCRAP_QTY2," + "DEFECTIVE_QTY1,DEFECTIVE_QTY2,INTERNAL_REWORK_QTY1," +
                "INTERNAL_REWORK_QTY2,TRACK_UNIT_FLAG,IN_QTY1," + "IN_QTY2,OUT_QTY1,OUT_QTY2,MOVE_IN_QTY1," +
                "MOVE_IN_QTY2,MOVE_OUT_QTY1,MOVE_OUT_QTY2," + "EXTERNAL_REWORK_QTY1,EXTERNAL_REWORK_QTY2," +
                "LOAD_POSITION,STEP_TRANS_RRN,CHAMBER_TYPE,OPERATION_SEQ," + "POLLUTION_LEVEL,ROUTE_SEQ," +
                "PRODUCT_LAYER,HOT_FLAG,PRIORITY,CREATE_CATEGORY,RECIPE_GROUP_RRN," + "RECIPE_LOGICAL_RRN," +
                "RECIPE_GROUP_VERSION,RECIPE_LOGICAL_VERSION,RECIPE_PHYSICAL_ID," +
                "PARAMETER,PARAMETER_VALUE,OPERATION_DESC,STEP_TYPE,WORK_AREA,FLOW_SEQ,EQPT_GROUP," +
                "EQPT_GROUP_RRN," + "PROCESS_LOCATION," +
                "CUSTOMER_ID,SHIPPING_CODE,OUTER_ORDER_NO,OUT_ORDER_TYPE,RECYCLE_STEP_INFO," + "RECYCLE_STEP_ID_INFO";
        sql += " FROM LOT_STEP_HISTORY";
        sql += " WHERE LOT_RRN=? AND STEP_SEQUENCE = ?";
        Object[] args = new Object[]{lotRrn, stepSequence};
        return jdbcTemplate.queryForObjectWithNull(sql, args, new LotStepHistoryMapper());
    }

    @Override
    public String getLotExtPL(long lotRrn) {
        String pollutionLevel = "0";
        String sql = "select t.attribute_data1 AS pollution_level  from lot_ext t WHERE t.lot_rrn=" + lotRrn;
        List<String> list = jdbcTemplate.query(sql, String.class);
        if (list != null && list.size() > 0) {
            pollutionLevel = list.get(0);
        }
        return pollutionLevel;
    }

    @Override
    public Map getQtyForUnscrap(long lotRrn) {
        String sql = "select SUM(tr.trans_qty1) trans_qty1,SUM(tr.trans_qty2) trans_qty2 from trans_reason tr," + " " +
                "transaction_log lo  where tr.instance_rrn =? and tr.reason_category='SCRAP'" + " and tr.trans_rrn=lo" +
                ".trans_rrn and lo.trans_start_timestamp >" +
                "NVL((select max(tl.trans_start_timestamp) from trans_reason " + "tr,transaction_log tl " +
                "where tr.instance_rrn =?" + " and tr.reason_category='UNSCRAP' and tr" +
                ".trans_rrn = tl.trans_rrn),to_timestamp" + "('1970-01-01 00:00:00','YYYY/MM/DD HH24:MI:SS'))";
        return jdbcTemplate.queryForObject(sql, new Object[]{lotRrn, lotRrn}, Map.class);
    }

    @Override
    public List<Map<String,Object>> qryLotHistoryExp(Long lotRrn, int startRow, int pageSize) {
        String sql = "SELECT ls.step_sequence, ls.reticle_rrn, ls.recipe_string, ls.operation_rrn," + "ls" +
                ".process_step_version,ls.stage_id,ls.lot_rrn,ls.lot_id,ls.facility_rrn," +
                "ls.in_qty1,ls.out_qty1,ls" + ".product_rrn,ls.process_rrn,ls.eqpt_rrn,ls" +
                ".process_step_id_version," + "ls.recipe_logical_rrn,ls" + ".recipe_physical_id,ls.POLLUTION_LEVEL,ls" +
                ".POLLUTION_LEVEL_AFTER," + "ls.OPERATION_SEQ,ls.ROUTE_SEQ," +
                "ls.HOT_FLAG,ls.PRIORITY,ls.RUN_RRN,ls.CREATE_CATEGORY," + "ls.CARRIER_RRN,ls.operation_desc,ls" +
                ".step_type,ls.flow_seq,ls.work_area,l.* FROM" + "( SELECT * FROM lot_step_history WHERE lot_rrn = ? ";
        //pageSize=0 就是不分页。。显示是倒序,从最大开始往小找
        if (pageSize > 0) {
            String sql0 = "select max(step_sequence) from lot_trans_history WHERE lot_rrn = ?";
            int maxSeq = jdbcTemplate.queryForObjectWithNull(sql0, new Object[]{lotRrn}, int.class);
            sql += " AND step_sequence > " + (maxSeq - pageSize - startRow) + " AND step_sequence <= " +
                    (maxSeq - startRow);
        }
        sql += ") ls left join " + "(SELECT lt.lot_rrn, lt.step_sequence,lt.trans_rrn,lt.trans_sequence,lt.trans_id," +
                "tr.trans_start_timestamp,tr.trans_end_timestamp," +
                "tr.trans_performed_by || ' ' || up.user_name AS trans_performed_by,lt.trans_comments," +
                "te.reason_code,te.reason,te.responsibility,sm.target_unit_id,sm.source_lot_id," +
                "decode(lt.trans_id, 'SPLIT', sm.target_lot_id, 'MERGETO', sm.target_lot_id, sm" +
                ".source_lot_id ) target_lot_id," + "NVL ( lt.carrier_rrn, 0 ) target_carrier_rrn FROM" +
                "((((lot_trans_history lt INNER JOIN transaction_log tr on lt.trans_rrn = tr" + ".trans_rrn)" +
                "left join named_object NO on tr.trans_performed_by = NO.instance_id and NO.OBJECT =" + " 'USER' )" +
                "left join user_profile up on NO.instance_rrn = up.user_rrn)" +
                "left join trans_reason te on lt.lot_rrn = te.instance_rrn and lt.trans_rrn = te" + ".trans_rrn)" +
                "left join split_merge_history sm on  lt.trans_rrn = sm.trans_rrn " + "WHERE lt.lot_rrn = ? " +
                "AND ( sm.source_lot_rrn != sm.target_lot_rrn OR (sm.target_lot_rrn IS NULL AND " +
                "sm.source_lot_id IS NULL)) " +
                "AND (lt.lot_rrn = SM.TARGET_LOT_RRN OR lt.lot_rrn = sm.source_lot_rrn " +
                "OR ( sm.target_lot_rrn IS NULL AND sm.source_lot_id IS NULL))) l " + "on ls.lot_rrn = l.lot_rrn " +
                "AND ls.step_sequence = l.step_sequence ORDER BY " + "ls.step_sequence DESC, l.trans_start_timestamp";

        List<Map> rows =  jdbcTemplate.query(sql,new Object[]{lotRrn,lotRrn},Map.class);
        if(CollectionUtils.isEmpty(rows)){
            return new ArrayList();
        }
        Set<Long> transRrns = Collections.synchronizedSet(new HashSet<>());
        List<Map<String,Object>> preResult = Collections.synchronizedList(new ArrayList<>());
        List<QueryLotHistoryExpRowSetTask> tasks =new ArrayList<>();
        final int size = rows.size();
        for (int i = 0; i < size; i++) {
            tasks.add(new QueryLotHistoryExpRowSetTask(rows.get(i),i+1,preResult,lotRrn,transRrns));
        }
        //批量查询
        tasks.parallelStream().forEach(QueryLotHistoryExpRowSetTask::run);
        Map<Long,String> reasons = this.getTransReasonByTrans(transRrns,lotRrn);
        preResult.sort(Comparator.comparingLong((Map<String, Object> a) -> MapUtils.getInteger(a,"seq")));
        List<Map<String,Object>> lotHistory = new ArrayList();
        for(Map<String,Object>item:preResult){
            Object callback;
            if ((callback = item.get("transCommentsCallBack")) != null && callback instanceof Consumer)
                ((Consumer) callback).accept(reasons);
            Map<String,Object> operationMap=null;
            for(Map<String,Object> tempOperationMap:lotHistory){
                if (tempOperationMap.containsKey(MapUtils.getString(item,"operation_rrn")) &&
                        // tempOperationMap.containsKey(lotTransmap.get("technology_id")) && //sql中没有找到这个字段
                        tempOperationMap.containsKey(MapUtils.getString(item,"route_id")) &&
                        tempOperationMap.containsKey(MapUtils.getString(item,"step_sequence"))) {
                    operationMap = tempOperationMap;
                    break;
                }
            }
            if (operationMap!=null) {
                ((List) operationMap.get(MapUtils.getString(item,"operation_rrn"))).add(item);
            } else {
                operationMap = new HashMap();
                List<Map<String,Object>> operationList = new ArrayList();
                operationList.add(item);
                // operationMap.put(MapUtils.getString(lotTransmap,"technology_id"), "");//sql中没有找到这个字段
                operationMap.put(MapUtils.getString(item,"route_id"), "");
                operationMap.put(MapUtils.getString(item,"step_sequence"), "");
                operationMap.put(MapUtils.getString(item,"operation_rrn"), operationList);
                operationMap.put("operationRrn", MapUtils.getString(item,"operation_rrn"));
                operationMap.put("operationdesc", MapUtils.getString(item,"operationDesc"));
                operationMap.put("productRrn", MapUtils.getString(item,"productRrn"));
                operationMap.put("process_rrn",MapUtils.getString(item,"process_rrn"));
                operationMap.put("eqpt_rrn", MapUtils.getString(item,"eqpt_rrn"));
                lotHistory.add(operationMap);
            }
        }
        return lotHistory;
    }


    private Map<Long, List<Map<String, Object>>> queryLotStepHistoryComments(Long lotRrn, List<Long> stepSeq){
        if(lotRrn==null||CollectionUtils.isEmpty(stepSeq)){
            return new HashMap<>();
        }
        String sql = "SELECT t.lot_rrn, t.step_sequence, t.comment_sequence, t.comment_type,t.step_comment,t" +
                ".add_timestamp,t.add_user_id, n.instance_id step_Id " +
                " FROM lot_step_history_comment t, lot_step_history " + "h, NAMED_OBJECT n" +
                " WHERE t.lot_rrn = h.lot_rrn AND t.step_sequence = h.step_sequence AND h" +
                String.format(".operation_rrn = n.instance_rrn and t.lot_rrn=? and t.step_sequence in (%s)", stepSeq.stream().map(e->"?").collect(
                        Collectors.joining(",")));
        List<Long> args = new ArrayList();
        args.add(lotRrn);
        args.addAll(stepSeq);
        SqlRowSet rs =  jdbcTemplate.queryForRowSet(sql,args.toArray());
        Map<Long,List<Map<String,Object>>> result =new HashMap<>();
        while (rs.next()){
            Long key = rs.getLong("step_sequence");
            List<Map<String,Object>> items =  result.computeIfAbsent(key,(k)->new ArrayList<>());
            Map<String,Object>item = new HashMap();
            item.put("lotRrn", rs.getLong("lot_rrn"));
            item.put("stepSequence",key );
            item.put("commentSequence", rs.getLong("comment_sequence"));
            item.put("commentType", rs.getString("comment_type"));
            item.put("stepComment", rs.getString("step_comment"));
            item.put("stepId", rs.getString("step_Id"));
            item.put("userId", rs.getString("add_user_id"));
            item.put("timeStamp", DateUtils.formatDate(rs.getTimestamp("add_timestamp"), DateUtils.DATE_FORMAT4DATE));
            items.add(item);
        }
        return result;
    }

    @Override
    public Map<Long, List<Map<String, Object>>> queryLotStepHistoryComments(Long lotRrn, Set<Long> stepSeq) {
        if(lotRrn==null||CollectionUtils.isEmpty(stepSeq)){
            return new HashMap<>();
        }
        List<List<Long>> arrays=  splitList(new ArrayList<>(stepSeq),900);
        Map<Long, List<Map<String, Object>>> result =  new HashMap<>();
        for(List<Long> arr : arrays){
            result.putAll(this.queryLotStepHistoryComments(lotRrn,arr));
        }
        return result;
    }

    @Override
    public List<Map> getUnitBondingInfo(Long unitRrn) {
        String sql = "SELECT TARGET_UNIT_RRN,SOURCE_UNIT_RRN FROM "
                + DataBaseNames.BONDING_UNIT +" WHERE TARGET_UNIT_RRN = ? ";

        return jdbcTemplate.query(sql,new Object[]{unitRrn}, new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map m = new HashMap();
                m.put("targetUnitRrn", new Long(rs.getLong("TARGET_UNIT_RRN")));
                m.put("sourceUnitRrn", new Long(rs.getLong("SOURCE_UNIT_RRN")));
                return m;
            }
        });
    }


    @Override
    public List qryLotStepHistoryComment(long lotRrn, long stepSequence, int thisPage, int pageSize) {
        List<Map> comments = new ArrayList<Map>();
        List args = new ArrayList();
        String sql = "SELECT t.lot_rrn, t.step_sequence, t.comment_sequence, t.comment_type,t.step_comment,t" +
                ".add_timestamp,t.add_user_id, n.instance_id step_Id " +
                " FROM lot_step_history_comment t, lot_step_history " + "h, NAMED_OBJECT n" +
                " WHERE t.lot_rrn = h.lot_rrn AND t.step_sequence = h.step_sequence AND h" +
                ".operation_rrn = n.instance_rrn and t.lot_rrn=?";
        args.add(lotRrn);
        if (stepSequence > 0) {
            sql += " and t.step_sequence = ? ";
            args.add(stepSequence);
        }

        sql += " order by step_sequence desc,comment_sequence desc";

        String sqlCount = "select count(*) from (" + sql + ") T0";
        int count = jdbcTemplate.queryForObject(sqlCount, args.toArray(), int.class);

        sql = "SELECT * from (  SELECT ROWNUM AS rowno, s.* from (" + sql + ") s WHERE ROWNUM<=?)SS WHERE SS.rowno>?";

        //TODO 修改page方式
        int endRow = 0;
        if (thisPage > 1) {
            endRow = (thisPage - 1) * pageSize;
        }
        args.add(thisPage * pageSize);
        args.add(endRow);

        comments = jdbcTemplate.query(sql, args.toArray(), new RowMapper<Map>() {

            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map m = new HashMap();
                m.put("lotRrn", new Long(rs.getLong("lot_rrn")));
                m.put("stepSequence", new Long(rs.getLong("step_sequence")));
                m.put("commentSequence", new Long(rs.getLong("comment_sequence")));
                m.put("commentType", rs.getString("comment_type"));
                m.put("stepComment", rs.getString("step_comment"));
                m.put("stepId", rs.getString("step_Id"));
                m.put("userId", rs.getString("add_user_id"));
                m.put("timeStamp", DateUtils.formatDate(rs.getTimestamp("add_timestamp"), DateUtils.DATE_FORMAT4DATE));
                m.put("totalCount", count);
                return m;
            }
        });

        return comments;
    }

    @Override
    public String getMaxLotId(String lotId) {
        String sql = "SELECT MAX(TO_NUMBER(NVL(SUBSTRB(T.LOT_ID,INSTR(T.LOT_ID,'.')+1),0))) LOTID FROM LOT T " +
                "WHERE T.LOT_ID LIKE ? AND" + " ASCII(SUBSTRB(T.LOT_ID,INSTR(T.LOT_ID,'.')+1,1)) > 47 AND" +
                " ASCII(SUBSTRB(T.LOT_ID,INSTR(T.LOT_ID,'.')+1,1)) < 58 AND" +
                " NVL(ASCII(SUBSTRB(T.LOT_ID,INSTR(T.LOT_ID,'.')+2,1)),50) > 47 AND" +
                " NVL(ASCII(SUBSTRB(T.LOT_ID,INSTR(T.LOT_ID,'.')+2,1)),50) < 58 ";
        sql += " AND T.LOT_ID NOT LIKE '%DEL'";
        sql += " AND T.LOT_ID NOT LIKE '%" + RunCardConstants.MAINLOT_ID_IN_MES + "%'";
        sql += " AND T.LOT_ID NOT LIKE '%" + RunCardConstants.RECOVERY_RUN_CARD_LOT_IN_MES + "%'";
        sql += " AND T.LOT_ID NOT LIKE '%" + RunCardConstants.SPLIT_RUN_CARD_LOT_IN_MES + "%'";

        String maxLotId = jdbcTemplate.queryForObject(sql, new Object[]{lotId + "%"}, String.class);
        if (maxLotId == null) {
            maxLotId = lotId.substring(0, lotId.indexOf("."));
        } else {
            maxLotId = lotId + maxLotId;
        }
        return maxLotId;
    }

    @Override
    public String getLotStatus(long lotRrn) {
        String sql = "select t.lot_status st from lot t where t.lot_rrn = ?";
        String lotStatus = jdbcTemplate.queryForObjectWithNull(sql, new Object[]{lotRrn}, String.class);
        if (StringUtils.isEmpty(lotStatus)) {
            return "";
        } else {
            return lotStatus;
        }
    }

    @Override
    public List<Map> queryLotPortalCondition(String searchType, String selectColumn, String resultCodeColumnName,
                                             String resultDescColumnName, Map<String, Object> conditionMap) {
        List<Object> argList = new ArrayList<Object>();
        StringBuffer sql = new StringBuffer();
        sql.append("select distinct ").append(selectColumn);
        sql.append(" from (select l.lot_id, l.hot_flag, l.priority, l.carrier_rrn, l.product_rrn, l.eqpt_rrn, " +
                           "getinstanceid(l.carrier_rrn) as carrier_id, ");
        sql.append("(l.hot_flag || '-' || l.priority) as hot_flag_priority, lot_status_ref.data_2_value as " +
                           "status_sort, l.rework_category, ");
        sql.append("l.lot_status, lot_status_ref.data_1_value as lot_status_data, l.create_category, " +
                           "lot_category_ref.data_1_value as lot_category, l.lot_type, ");
        sql.append(
                "product_no.instance_id as product_id, product_no.object_type, product_type_ref" + ".data_1_value as " +
                        "product_type, ");
        sql.append("REGEXP_SUBSTR(l.process_step_id_version, '[^,]+', 1, 1) as process_id, ");
        sql.append(
                "REGEXP_SUBSTR(l.process_step_id_version, '[^,]+', instr(l.process_step_id_version, '|', 1," + " 1) +" +
                        " 1,1) as route_id, ");
        sql.append(
                "REGEXP_SUBSTR(l.process_step_id_version, '[^,]+', instr(l.process_step_id_version, '|', 1," + " 2) +" +
                        " 1,1) as step_id, ");
        sql.append(
                "REGEXP_SUBSTR(l.process_step_version, '[^,]+', instr(l.process_step_version, '|', 1, 2) + " + "1,1) " +
                        "as step_rrn ");
        sql.append("from lot l, named_object product_no, ");
        sql.append("(select rfd.key_1_value, rfd.data_1_value, rfd.data_2_value from reference_file_detail " + "rfd, " +
                           "named_object n ");
        sql.append("where n.instance_id = '$$LOT_STATUS' and n.named_space = ? and n.instance_rrn = rfd" +
                           ".reference_file_rrn) lot_status_ref, ");
        sql.append("(select rfd.key_1_value, rfd.data_1_value from reference_file_detail rfd, named_object n ");
        sql.append("where n.instance_id = '$LOT_CREATE_CATEGORY' and n.named_space = ? and n.instance_rrn = " + "rfd" +
                           ".reference_file_rrn) lot_category_ref, ");
        sql.append("(select rfd.key_1_value, rfd.data_1_value from reference_file_detail rfd, named_object n ");
        sql.append("where n.instance_id = '$PRODUCT_TYPE' and n.named_space = ? and n.instance_rrn = rfd" +
                           ".reference_file_rrn) product_type_ref ");
        sql.append("where l.facility_rrn = ? and l.product_rrn = product_no.instance_rrn(+) and product_no" +
                           ".object_type = product_type_ref.key_1_value(+) ");
        sql.append("and l.create_category = lot_category_ref.key_1_value(+) and l.lot_status = " + "lot_status_ref" +
                           ".key_1_value(+)) lot_base_t, operation_ext oe, operation o, ");
        sql.append("(select rfd.key_1_value, rfd.data_1_value from reference_file_detail rfd, named_object n ");
        sql.append("where n.instance_id = '$$WORK_AREA' and n.named_space = ? and n.instance_rrn = rfd" +
                           ".reference_file_rrn) work_area_ref, ");
        sql.append("(select operation_rrn, station_rrn, station_id from (select o.operation_rrn, " + "eqpt_group_t" +
                           ".station_rrn, eqpt_group_t.station_id from operation o, ");
        sql.append("(select eqpt_group_r.to_rrn as epqt_group_rrn, eqpt_station_t.station_rrn, " + "eqpt_station_t" +
                           ".station_id ");
        sql.append(
                "from relation eqpt_group_r, (select eqpt_station_r.to_rrn as eqpt_rrn, station_t.from_rrn " + "as " +
                        "station_rrn, station_id from relation eqpt_station_r, ");
        sql.append("(select station_r.from_rrn, getinstanceid(station_r.from_rrn) as station_id from relation " +
                           "user_group_r, relation station_r ");
        sql.append(
                "where user_group_r.link_type = 'USER_TO_USER_GROUP' and station_r.link_type = " + "'STATION_TO_USER'" +
                        " and user_group_r.from_rrn = ? ");
        sql.append("group by station_r.from_rrn, getinstanceid(station_r.from_rrn)) station_t ");
        sql.append("where eqpt_station_r.link_type = 'STATION_TO_EQUIPMENT' and eqpt_station_r.from_rrn in " +
                           "station_t.from_rrn) eqpt_station_t ");
        sql.append("where eqpt_group_r.link_type = 'ENTITY_TO_ENTITY_GROUP' and eqpt_group_r.from_rrn = " +
                           "eqpt_station_t.eqpt_rrn) eqpt_group_t ");
        sql.append(
                "where o.entity_group_rrn in eqpt_group_t.epqt_group_rrn union select oper_station_r.to_rrn" + " as " +
                        "operation_rrn, station_t.from_rrn as station_rrn, station_id ");
        sql.append(
                "from relation oper_station_r, (select station_r.from_rrn, getinstanceid(station_r" + ".from_rrn) as " +
                        "station_id from relation user_group_r, relation station_r ");
        sql.append(
                "where user_group_r.link_type = 'USER_TO_USER_GROUP' and station_r.link_type = " + "'STATION_TO_USER'" +
                        " and user_group_r.from_rrn = ? ");
        sql.append("group by station_r.from_rrn, getinstanceid(station_r.from_rrn)) station_t ");
        sql.append(
                "where oper_station_r.link_type = 'STATION_TO_OPERATION' and oper_station_r.from_rrn = " + "station_t" +
                        ".from_rrn) station_all_operation_t ");
        sql.append("group by operation_rrn, station_rrn, station_id) oper_station_t ");
        sql.append("where lot_base_t.step_rrn = oe.operation_rrn(+) and lot_base_t.step_rrn = o" + ".operation_rrn" +
                           "(+) and oe.attribute_data5 = work_area_ref.key_1_value(+) ");
        sql.append("and lot_base_t.step_rrn = oper_station_t.operation_rrn(+) ");

        argList.add(MapUtils.getString(conditionMap, "referenceNamedSpace"));
        argList.add(MapUtils.getString(conditionMap, "referenceNamedSpace"));
        argList.add(MapUtils.getString(conditionMap, "referenceNamedSpace"));
        argList.add(MapUtils.getLong(conditionMap, "facilityRrn"));
        argList.add(MapUtils.getString(conditionMap, "referenceNamedSpace"));
        argList.add(MapUtils.getLong(conditionMap, "loginUserRrn"));
        argList.add(MapUtils.getLong(conditionMap, "loginUserRrn"));

        if (StringUtils.isNotBlank(MapUtils.getString(conditionMap, "lotId"))) {
            sql.append("and lot_base_t.lot_id like ? ");
            argList.add(MapUtils.getString(conditionMap, "lotId"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(conditionMap, "lotCategory"))) {
            sql.append("and lot_base_t.create_category = ? ");
            argList.add(MapUtils.getString(conditionMap, "lotCategory"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(conditionMap, "lotType"))) {
            sql.append("and lot_base_t.lot_type = ? ");
            argList.add(MapUtils.getString(conditionMap, "lotType"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(conditionMap, "lotStatus"))) {
            String lotStatus = MapUtils.getString(conditionMap, "lotStatus");
            if (StringUtils.equalsIgnoreCase(lotStatus, "ALL")) {

            } else {
                if (StringUtils.equalsIgnoreCase(lotStatus, LotStatus.REWORK)) {
                    sql.append("and (lot_base_t.rework_category is not null) ");
                } else {
                    boolean isReworkFlag = false;
                    sql.append("and (lot_base_t.lot_status in  ");
                    String statusArgs = "(";
                    if (StringUtils.equalsIgnoreCase(lotStatus, LotStatus.ACTIVE)) {
                        statusArgs +=
                                "'" + LotStatus.RUNNING + "','" + LotStatus.WAITING + "', '" + LotStatus.PROCESSED +
                                        "', '" + LotStatus.DISPATCH + "'";
                    } else if (StringUtils.equalsIgnoreCase(lotStatus, LotStatus.UNACTIVE)) {
                        statusArgs += "'" + LotStatus.BONDED + "','" + LotStatus.FINISH + "','" + LotStatus.TERMINATED +
                                "', '" + LotStatus.SCRAPPED + "'";
                    } else if (StringUtils.contains(lotStatus, ",")) {
                        if (StringUtils.contains(lotStatus, LotStatus.REWORK)) {
                            isReworkFlag = true;
                        }
                        String[] statusArray = lotStatus.split(",");
                        for (int i = 0; i < statusArray.length; i++) {
                            statusArgs += "'" + statusArray[i] + "',";
                        }
                        if (StringUtils.contains(lotStatus, LotStatus.ACTIVE)) {
                            statusArgs +=
                                    "'" + LotStatus.RUNNING + "','" + LotStatus.WAITING + "', '" + LotStatus.PROCESSED +
                                            "', '" + LotStatus.DISPATCH + "',";
                        }
                        if (StringUtils.contains(lotStatus, LotStatus.UNACTIVE)) {
                            statusArgs +=
                                    "'" + LotStatus.BONDED + "','" + LotStatus.FINISH + "','" + LotStatus.TERMINATED +
                                            "', '" + LotStatus.SCRAPPED + "',";
                        }

                        // 去除最后一个逗号
                        statusArgs = statusArgs.substring(0, statusArgs.lastIndexOf(","));
                    } else {
                        statusArgs += "'" + lotStatus + "'";
                    }
                    statusArgs += ") ";
                    // argList.add(statusArgs);
                    sql.append(statusArgs);
                    if (isReworkFlag) {
                        sql.append("or lot_base_t.rework_category is not null ");
                    }
                    sql.append(") ");
                }
            }
        }
        if (StringUtils.isNotBlank(MapUtils.getString(conditionMap, "productType"))) {
            sql.append("and lot_base_t.product_type = ? ");
            argList.add(MapUtils.getString(conditionMap, "productType"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(conditionMap, "product"))) {
            sql.append("and lot_base_t.product_id like ? ");
            argList.add(MapUtils.getString(conditionMap, "product"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(conditionMap, "process"))) {
            sql.append("and lot_base_t.process_id like ? ");
            argList.add(MapUtils.getString(conditionMap, "process"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(conditionMap, "route"))) {
            sql.append("and lot_base_t.route_id like ? ");
            argList.add(MapUtils.getString(conditionMap, "route"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(conditionMap, "carrier"))) {
            sql.append("and lot_base_t.carrier_id like ? ");
            argList.add(MapUtils.getString(conditionMap, "carrier"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(conditionMap, "workArea"))) {
            sql.append("and work_area_ref.key_1_value = ? ");
            argList.add(MapUtils.getString(conditionMap, "workArea"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(conditionMap, "station"))) {
            sql.append("and oper_station_t.station_id like ? ");
            argList.add(MapUtils.getString(conditionMap, "station"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(conditionMap, "eqptGroup"))) {
            sql.append("and getinstanceid(o.entity_group_rrn) like ? ");
            argList.add(MapUtils.getString(conditionMap, "eqptGroup"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(conditionMap, "hotFlag"))) {
            sql.append("and lot_base_t.hot_flag = ? ");
            argList.add(MapUtils.getString(conditionMap, "hotFlag"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(conditionMap, "hotFlag")) &&
                StringUtils.isNotBlank(MapUtils.getString(conditionMap, "internalPriority"))) {
            sql.append("and lot_base_t.hot_flag = ? and lot_base_t.priority = ? ");
            argList.add(MapUtils.getString(conditionMap, "hotFlag"));
            argList.add(MapUtils.getString(conditionMap, "internalPriority"));
        }

        List<Map> result = new ArrayList<>();

        if (StringUtils.isNotBlank(searchType) && StringUtils.equalsIgnoreCase(searchType, "lotStatus")) {
            sql.append("order by cast(lot_base_t.status_sort as int) asc ");
            Map<String, Object> data = new HashMap<>(2);
            data.put("key", LotStatus.ACTIVE);
            data.put("value", LotStatus.ACTIVE);
            result.add(data);
        }

        if(StringUtils.isNotBlank(searchType) && StringUtils.equalsIgnoreCase(searchType,"priority")){
            sql.append("order by lot_base_t.hot_flag_priority asc");
        }

        SqlRowSet rs = jdbcTemplate.queryForRowSet(sql.toString(), argList.toArray());
        boolean reworkStatusFlag = false;
        while (rs.next()) {
            Map<String, Object> data = new HashMap<>(2);
            data.put("key", rs.getString(resultDescColumnName));
            data.put("value", rs.getString(resultCodeColumnName));

            if (StringUtils.isNotBlank(searchType) && StringUtils.equalsIgnoreCase(searchType, "lotStatus")) {
                String reworkStatus = rs.getString("rework_category");
                if (StringUtils.isNotBlank(reworkStatus)) {
                    reworkStatusFlag = true;
                    continue;
                }
            }
            result.add(data);
        }

        if (StringUtils.isNotBlank(searchType) && StringUtils.equalsIgnoreCase(searchType, "lotStatus")) {
            if (reworkStatusFlag) {
                Map<String, Object> data = new HashMap<>(2);
                data.put("key", LotStatus.REWORK);
                data.put("value", LotStatus.REWORK);
                result.add(data);
            }
            Map<String, Object> data = new HashMap<>(2);
            data.put("key", LotStatus.UNACTIVE);
            data.put("value", LotStatus.UNACTIVE);
            result.add(data);
            data = new HashMap<>(2);
            data.put("key", LotStatus.ALL);
            data.put("value", LotStatus.ALL);
            result.add(data);
        }

        return result;
    }

    @Override
    public List<Map> qryWorkAreaAndEqptGroupAndStationComboData(String selectColumn, String resultCodeColumnName,
                                                                String resultDescColumnName,
                                                                Map<String, Object> conditionMap) {

        List<Object> argList = new ArrayList<Object>();
        StringBuffer sql = new StringBuffer();
        sql.append("select distinct ");
        sql.append(selectColumn);
        sql.append(
                " from (select rfd.key_1_value, rfd.data_1_value from reference_file_detail rfd, " + "named_object n ");
        sql.append("where n.instance_id = '$$WORK_AREA' and n.named_space = ? and n.instance_rrn = rfd" +
                           ".reference_file_rrn) work_area_ref left join operation_ext oe on oe.attribute_data5 =" +
                           " " + "work_area_ref.key_1_value, ");
        argList.add(MapUtils.getString(conditionMap, "refrenceNamedSpace"));
        sql.append("(select operation_rrn, station_rrn, station_id from (select o.operation_rrn, eqpt_group_t" +
                           ".station_rrn, eqpt_group_t.station_id ");
        sql.append(
                "from operation o, (select eqpt_group_r.to_rrn as epqt_group_rrn, eqpt_station_t" + ".station_rrn, " +
                        "eqpt_station_t.station_id ");
        sql.append(
                "from relation eqpt_group_r, (select eqpt_station_r.to_rrn as eqpt_rrn, station_t.from_rrn " + "   as" +
                        " station_rrn, station_id ");
        sql.append(
                "from relation eqpt_station_r, (select station_r.from_rrn, getinstanceid(station_r" + ".from_rrn) as " +
                        "station_id from relation user_group_r, relation station_r ");
        sql.append(
                "where user_group_r.link_type = 'USER_TO_USER_GROUP' and station_r.link_type = " + "'STATION_TO_USER'" +
                        " and user_group_r.from_rrn = ? ");
        argList.add(MapUtils.getLong(conditionMap, "loginUserRrn"));
        sql.append("group by station_r.from_rrn, getinstanceid(station_r.from_rrn)) station_t ");
        sql.append(
                "where eqpt_station_r.link_type = 'STATION_TO_EQUIPMENT' and eqpt_station_r.from_rrn = " + "station_t" +
                        ".from_rrn) eqpt_station_t ");
        sql.append("where eqpt_group_r.link_type = 'ENTITY_TO_ENTITY_GROUP' and eqpt_group_r.from_rrn = " +
                           "eqpt_station_t.eqpt_rrn) eqpt_group_t ");
        sql.append("where o.entity_group_rrn = eqpt_group_t.epqt_group_rrn ");
        sql.append("union ");
        sql.append(
                "select oper_station_r.to_rrn as operation_rrn, station_t.from_rrn    as station_rrn, " + "station_id" +
                        " ");
        sql.append(
                "from relation oper_station_r, (select station_r.from_rrn, getinstanceid(station_r" + ".from_rrn) as " +
                        "station_id ");
        sql.append("from relation user_group_r, relation station_r where user_group_r.link_type = " +
                           "'USER_TO_USER_GROUP' ");
        sql.append("and station_r.link_type = 'STATION_TO_USER' and user_group_r.from_rrn = ? group by " + "station_r" +
                           ".from_rrn, getinstanceid(station_r.from_rrn)) station_t ");
        argList.add(MapUtils.getLong(conditionMap, "loginUserRrn"));
        sql.append(
                "where oper_station_r.link_type = 'STATION_TO_OPERATION' and oper_station_r.from_rrn = " + "station_t" +
                        ".from_rrn) station_all_operation_t ");
        sql.append(
                "group by operation_rrn, station_rrn, station_id) oper_station_t left join named_object n " + "on n" +
                        ".instance_rrn = oper_station_t.operation_rrn left join operation" +
                        " o on n.instance_rrn = o" + ".operation_rrn ");
        sql.append("where n.object = 'OPERATION' and  o.operation_rrn = oe.operation_rrn ");

        if (conditionMap.get("operationRrnList") != null) {
            List<Long> operationLongList = (List<Long>) conditionMap.get("operationRrnList");
            if (operationLongList.size() > 0) {
                sql.append("and n.instance_rrn in (");
                for (int i = 0; i < operationLongList.size(); i++) {
                    sql.append(operationLongList.get(i));
                    if (i != (operationLongList.size() - 1)) {
                        sql.append(",");
                    }
                }
                sql.append(") ");
            }
        }

        if (StringUtils.isNotBlank(MapUtils.getString(conditionMap, "stationId"))) {
            sql.append("and oper_station_t.station_id like ? ");
            argList.add(MapUtils.getString(conditionMap, "stationId"));
        }

        if (StringUtils.isNotBlank(MapUtils.getString(conditionMap, "eqptGroupId"))) {
            sql.append("and getinstanceid(o.entity_group_rrn) like ? ");
            argList.add(MapUtils.getString(conditionMap, "eqptGroupId"));
        }

        return jdbcTemplate.query(sql.toString(), argList.toArray(), new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                String result = rs.getString(resultCodeColumnName);
                if (StringUtils.isNotEmpty(result)) {
                    Map<String, Object> data = new HashMap<>(2);
                    data.put("key", rs.getString(resultDescColumnName));
                    data.put("value", rs.getString(resultCodeColumnName));
                    return data;
                }
                return null;
            }
        });
    }

    @Override
    public List<Map<String, Object>> qryLotInfo(Map param, int startRow, int currentTotalRow) {
        Map<String, Object> sqlMap = this.getLotPortalListSql(param, startRow, currentTotalRow);
        String sql = MapUtils.getString(sqlMap, "sql");
        List<Object> argList = (List<Object>) MapUtils.getObject(sqlMap, "argList");

        Map<String, Object> countMap = queryLotCount(param);

        return jdbcTemplate.query(sql, argList.toArray(), new RowMapper<Map<String, Object>>() {
            @Override
            public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map<String, Object> dataMap = new HashMap<String, Object>();
                dataMap.put("batchId", rs.getString("BATCH_ID"));
                dataMap.put("lotID", rs.getString("LOTID"));
                dataMap.put("lotRRN", rs.getLong("LOTRRN"));
                dataMap.put("lotStatus", rs.getString("LOTSTATUS"));
                dataMap.put("lotType", rs.getString("LOTTYPE"));
                dataMap.put("lotPiority", rs.getString("PRIORITY")); // 已拼接
                dataMap.put("lotInteriorPiority", rs.getString("INTERIOR_PRIORITY"));
                dataMap.put("qty1", rs.getString("QTY1")); // 数量
                dataMap.put("carrierId", rs.getString("CARRIERID"));
                dataMap.put("productID", rs.getString("PRODUCTID"));
                dataMap.put("productRrn", rs.getLong("PRODUCT_RRN"));
                dataMap.put("routeSeq", rs.getString("ROUTESEQ"));
                dataMap.put("stepSeq", rs.getString("STEPSEQ"));
                dataMap.put("recipeRrn", rs.getString("CONTEXT_RECIPE_RRN")); // 情境值上的 recipe rrn
                dataMap.put("recipeID", rs.getString("CONTEXT_RECIPE")); // 情境值上的 recipe
                dataMap.put("processRrn", rs.getLong("PROCESS_RRN"));
                dataMap.put("routeRrn", rs.getLong("ROUTE_RRN"));
                dataMap.put("stepRrn", rs.getLong("STEP_RRN"));
                dataMap.put("processId", rs.getString("PROCESS_ID"));
                dataMap.put("routeID", rs.getString("ROUTE_ID"));
                dataMap.put("stepID", rs.getString("STEP_ID"));
                dataMap.put("runningEqpt", rs.getString("RUNNING_EQPT"));
                dataMap.put("eqptList", rs.getString("EQPT_LIST"));

                if (rs.getTimestamp("LOT_RUN_TIME") != null) {
                    long runSpent = DateUtils.getDistanceTime4Now(rs.getTimestamp("LOT_RUN_TIME"));
                    //                    String runTimeHr = DateUtils.formatDateForSeconds(runSpent);
                    String runTimeHr = (new java.text.DecimalFormat("#0.00")).format(runSpent / 60f / 60f);
                    // running状态批次才显示runTime
                    if (StringUtils.equalsIgnoreCase(LotStatus.RUNNING, rs.getString("lotStatus"))) {
                        dataMap.put("runTime", runTimeHr);
                    } else {
                        dataMap.put("runTime", "");
                    }
                } else {
                    dataMap.put("runTime", "");
                }

                long spent = DateUtils.getDistanceTime4Now(rs.getTimestamp("QUEUE_TIMESTAMP"));
                //                String waitTimeHr = DateUtils.formatDateForSeconds(spent);
                String waitTimeHr = (new java.text.DecimalFormat("#0.00")).format(spent / 60f / 60f);
                dataMap.put("queueTime", waitTimeHr);

                if (rs.getTimestamp("HOLD_TIMESTAMP") != null) {
                    long holdSpent = DateUtils.getDistanceTime4Now(rs.getTimestamp("HOLD_TIMESTAMP"));
                    //                    String holdTimeHr = DateUtils.formatDateForSeconds(holdSpent);
                    String holdTimeHr = (new java.text.DecimalFormat("#0.00")).format(holdSpent / 60f / 60f);
                    // hold状态批次才显示holdTime
                    if (StringUtils.equalsIgnoreCase(LotStatus.HOLD, rs.getString("lotStatus")) ||
                            StringUtils.equalsIgnoreCase(LotStatus.RUNNINGHOLD, rs.getString("lotStatus"))) {
                        dataMap.put("holdTime", holdTimeHr);
                    } else {
                        dataMap.put("holdTime", "");
                    }
                } else {
                    dataMap.put("holdTime", "");
                }
                dataMap.put("stageID", rs.getString("STAGE_ID"));
                dataMap.put("pollutionLevel", rs.getString("POLLUTION_LEVEL"));
                dataMap.put("recipePara", rs.getString("RECIPE_STRING"));// 工艺规格
                dataMap.put("workArea", rs.getString("WORK_AREA"));
                dataMap.put("eqptGroupId", rs.getString("ENTITY_GROUP_ID"));
                dataMap.put("eqptId", rs.getString("EQPTID")); // 没有设备就显示工步上设备组的所有设备
                dataMap.put("holdDept", rs.getString("HOLD_DEPT"));
                dataMap.put("holdComment", rs.getString("HOLD_REASON"));
                dataMap.put("isRework", rs.getString("REWORK_CATEGORY"));
                dataMap.put("lotCategory", rs.getString("LOTCATEGORY"));
                dataMap.put("processVersion", rs.getString("PROCESS_VERSION"));
                dataMap.put("podID", rs.getString("PODID"));
                dataMap.put("doorId", rs.getString("DOORID"));
                dataMap.put("shippingCode", rs.getString("SHIPPING_CODE"));
                dataMap.put("customerId", rs.getString("CUSTOMER_ID"));
                dataMap.put("outerOrderNO", rs.getString("OUTER_ORDER_NO"));
                dataMap.put("outOrderType", rs.getString("OUT_ORDER_TYPE"));
                dataMap.put("customerLotId", rs.getString("CUSTOMER_LOT_ID"));
                dataMap.put("wflSeq", rs.getString("CONTEXT_FLOW_SEQ"));
                dataMap.put("stepDesc", rs.getString("CONTEXT_STEP_DESC"));
                dataMap.put("timeLimit", rs.getString("Q_TIME"));
                dataMap.put("lotComment", rs.getString("LOT_COMMENT"));

                Long locationRrn = rs.getLong("LOCATION");
                Long pLocationRrn = rs.getLong("PLOCATION");
                dataMap.put("location", buildLocationId(locationRrn));
                dataMap.put("pLocation", buildLocationId(pLocationRrn));

                dataMap.put("lotCount", MapUtils.getIntValue(countMap, "lotCount"));
                dataMap.put("qtyCount", MapUtils.getIntValue(countMap, "qtyCount"));
                return dataMap;
            }
        });
    }

    @Override
    public List<Map<String, Object>> ryAllLotInfoForLotPortal(Map param) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Page qryBondedMappingInfos(String targetLotId, String targetUnitId, String productId, String StartDate,
                                      String endDate, Page page) {
        String cWhere = "";
        List args = new ArrayList();
        if (StringUtils.isBlank(targetLotId) && StringUtils.isBlank(targetUnitId) && StringUtils.isBlank(productId)) {
            return new Page();
        }
        if (StringUtils.isNotBlank(targetLotId)) {
            if (targetLotId.contains("*")) {
                cWhere += "AND (TLOT.LOT_ID like ? OR SLOT.LOT_ID like ?) ";
                args.add(targetLotId.replaceAll("\\*", "%"));
                args.add(targetLotId.replaceAll("\\*", "%"));
            } else {
                cWhere += "AND (TLOT.LOT_ID = ? OR SLOT.LOT_ID = ?)";
                args.add(targetLotId);
                args.add(targetLotId);
            }

        }
        if (StringUtils.isNotEmpty(targetUnitId)) {
            if (targetUnitId.contains("*")) {
                cWhere += "AND ( L.TARGET_UNIT_ID like ? OR L.SOURCE_UNIT_ID like ? )";
                args.add(targetUnitId.replaceAll("\\*", "%"));
                args.add(targetUnitId.replaceAll("\\*", "%"));
            } else {
                cWhere += "AND ( L.TARGET_UNIT_ID = ? OR L.SOURCE_UNIT_ID = ? )";
                args.add(targetUnitId);
                args.add(targetUnitId);
            }
        }

        if (StringUtils.isNotEmpty(productId)) {
            if (productId.contains("*")) {
                cWhere += "AND ( TPRODUCT.INSTANCE_ID LIKE ? OR SPRODUCT.INSTANCE_ID LIKE ? )";
                args.add(productId.replaceAll("\\*", "%"));
                args.add(productId.replaceAll("\\*", "%"));
            } else {
                cWhere += "AND ( TPRODUCT.INSTANCE_ID = ? OR SPRODUCT.INSTANCE_ID = ? )";
                args.add(productId);
                args.add(productId);
            }
        }

        cWhere += " AND TR.TRANS_START_TIMESTAMP >=to_timestamp(?,'" + DateUtils.DATE_FORMAT24 + "') ";
        args.add(StartDate + " 00:00:00");
        cWhere += " AND TR.TRANS_START_TIMESTAMP <=to_timestamp(?,'" + DateUtils.DATE_FORMAT24 + "') ";
        args.add(endDate + " 00:00:00");

        String sql =
                "SELECT DISTINCT L.TRANS_RRN,TR.TRANS_ID, L.TARGET_UNIT_RRN,L.TARGET_UNIT_ID,L" + ".TARGET_LOT_RRN," +
                        "TLOT.LOT_ID AS TARGET_LOT_ID,L.SOURCE_UNIT_RRN, L.SOURCE_UNIT_ID,L.SOURCE_LOT_RRN," +
                        "SLOT.LOT_ID AS SOURCE_LOT_ID,L.BOND_TYPE,LS.EQPT_RRN,TPRODUCT.INSTANCE_ID AS " +
                        "TARGET_PRODUCT," +
                        "SPRODUCT.INSTANCE_ID AS SOURCE_PRODUCT,GETINSTANCEID(LS.EQPT_RRN) AS EQPT_ID," +
                        "TR.TRANS_START_TIMESTAMP, " + "TR.TRANS_END_TIMESTAMP,TR.TRANS_PERFORMED_BY, LS.STAGE_ID," +
                        "LS.PRODUCT_RRN,LS.PROCESS_RRN, LS" + ".OPERATION_RRN,LS.PROCESS_VERSION,LS.OPERATION_DESC," +
                        "LS.STEP_TYPE,GETINSTANCEID(LS.OPERATION_RRN) AS " + "OPERATION_ID, " +
                        "GETINSTANCEID(LS.PROCESS_RRN) AS PROCESS_ID,T_UNIT_ALIAS_1, S_UNIT_ALIAS_1," +
                        " L.TARGET_BONDING_TAG, L.SOURCE_BONDING_TAG " + "FROM (" +
                        "((((SELECT DISTINCT UC.TRANS_RRN, UC.TARGET_UNIT_RRN,UCT.UNIT_ID AS " + "TARGET_UNIT_ID," +
                        "UCT.LOT_RRN" + " AS TARGET_LOT_RRN, UC.COUSUME_UNIT_RRN AS SOURCE_UNIT_RRN, UCS.UNIT_ID " +
                        "AS " + "SOURCE_UNIT_ID, " +
                        "UCS.LOT_RRN AS SOURCE_LOT_RRN,'ATTACH' AS BOND_TYPE, UC.STEP_SEQUENCE, UCT" +
                        ".UNIT_ALIAS_1 " + "AS T_UNIT_ALIAS_1, " +
                        "UCS.UNIT_ALIAS_1 AS S_UNIT_ALIAS_1,UC.TARGET_BONDING_TAG," +
                        " UC.CONSUME_BONDING_TAG AS SOURCE_BONDING_TAG FROM ( UNIT_CONSUME_RELATION UC LEFT JOIN " +
                        "UNIT UCT ON UC.TARGET_UNIT_RRN = UCT.UNIT_RRN and UC.TRANS_RRN > 0) LEFT JOIN " +
                        "UNIT UCS ON UC.COUSUME_UNIT_RRN = UCS.UNIT_RRN UNION SELECT DISTINCT BH.TRANS_RRN, " +
                        "BH.TARGET_UNIT_RRN, BUT.UNIT_ID AS TARGET_UNIT_ID," +
                        "BUT.LOT_RRN AS TARGET_LOT_RRN,BH.SOURCE_UNIT_RRN, BUS.UNIT_ID AS SOURCE_UNIT_ID," +
                        "BUS.LOT_RRN AS SOURCE_LOT_RRN,BH.TRANS_ID AS BOND_TYPE,BH.STEP_SEQUENCE," +
                        "BUT.UNIT_ALIAS_1 AS T_UNIT_ALIAS_1,BUS.UNIT_ALIAS_1 AS S_UNIT_ALIAS_1, " +
                        "BH.ATTRIBUTE_DATA5 AS TARGET_BONDING_TAG, BH.ATTRIBUTE_DATA4 AS SOURCE_BONDING_TAG FROM " +
                        "(BONDING_HISTORY BH LEFT JOIN UNIT BUT on BH.TARGET_UNIT_RRN = BUT.UNIT_RRN and BH" +
                        ".TRANS_RRN > 0)" + "left join UNIT BUS on BH.SOURCE_UNIT_RRN = BUS.UNIT_RRN) L left join " +
                        "TRANSACTION_LOG TR on L.TRANS_RRN = TR.TRANS_RRN) left join (SELECT DISTINCT " +
                        "LH.TRANS_RRN,LT.EQPT_RRN,LT.STAGE_ID,LT.LOT_RRN,LT.LOT_ID,LT.FACILITY_RRN," +
                        "LT.OUT_QTY1,LT.PRODUCT_RRN,LT.PROCESS_RRN,LT.OPERATION_RRN,LT.ROUTE_SEQ," +
                        "LT.OPERATION_SEQ,LT.PROCESS_VERSION,LT.OPERATION_DESC,LT.STEP_TYPE,LH.STEP_SEQUENCE " +
                        "FROM LOT_TRANS_HISTORY LH left join LOT_STEP_HISTORY LT on LH.LOT_RRN = LT.LOT_RRN " +
                        "AND LH.STEP_SEQUENCE = LT.STEP_SEQUENCE ) LS on L.TRANS_RRN = LS.TRANS_RRN " +
                        "and L.STEP_SEQUENCE = LS.STEP_SEQUENCE) left join (LOT TLOT INNER JOIN " +
                        "NAMED_OBJECT TPRODUCT on TLOT.PRODUCT_RRN = TPRODUCT.INSTANCE_RRN) on " +
                        "L.TARGET_LOT_RRN = TLOT.LOT_RRN) left join (LOT SLOT inner join NAMED_OBJECT SPRODUCT" +
                        " on SLOT.PRODUCT_RRN = SPRODUCT.INSTANCE_RRN)on L.SOURCE_LOT_RRN = SLOT.LOT_RRN)" +
                        "WHERE 1 = 1 " + cWhere + "ORDER BY TARGET_UNIT_ID,TR.TRANS_START_TIMESTAMP ";
        page = jdbcTemplate.queryForPage(page, sql, args.toArray(), new RowMapper<BondingMapping>() {

            @Override
            public BondingMapping mapRow(ResultSet rs, int rowNum) throws SQLException {
                BondingMapping bondingMapping = new BondingMapping();
                bondingMapping.setTargetLotRrn(rs.getLong("target_lot_rrn"));
                bondingMapping.setTargetLotId(rs.getString("target_lot_id"));
                bondingMapping.setTargeteUnitId(rs.getString("target_unit_id"));
                bondingMapping.setTargetUnitRrn(rs.getLong("target_unit_rrn"));
                bondingMapping.setSourceLotRrn(rs.getLong("source_lot_rrn"));
                bondingMapping.setSosurceLotId(rs.getString("source_lot_id"));
                bondingMapping.setSourceUnitRrn(rs.getLong("source_unit_rrn"));
                bondingMapping.setSourceUnitId(rs.getString("source_unit_id"));
                bondingMapping.setTargetHandleFlag(rs.getString("bond_type"));
                bondingMapping.setEqptId(rs.getString("eqpt_id"));
                bondingMapping.setTransStartTime(rs.getTimestamp("trans_start_timestamp"));
                bondingMapping.setTargetProductId(rs.getString("target_product"));
                bondingMapping.setSourceProductId(rs.getString("source_product"));
                bondingMapping.setProcessId(rs.getString("process_id"));
                bondingMapping.setOperationId(rs.getString("operation_id"));
                bondingMapping.setOperationUser(rs.getString("trans_performed_by"));
                bondingMapping.setTargetUnitAlias1(rs.getString("t_unit_alias_1"));
                bondingMapping.setSourceUnitAlias1(rs.getString("s_unit_alias_1"));
                bondingMapping.setTargetBondingTag(rs.getString("TARGET_BONDING_TAG"));
                bondingMapping.setSourceBondingTag(rs.getString("SOURCE_BONDING_TAG"));
                return bondingMapping;
            }
        });
        return page;
    }

    @Override
    public long getMaxOfLotByProduct(Long productRrn) {


        String sql = "select MAX(t.attribute_value) AS maxNum from object_attribute_value t, " + "named_object n " +
                "where t.field_rrn = n.instance_rrn and n.instance_id='FLD_PRODUCT_SERIAL_NUMBER' " +
                "and t.instance_rrn in" + "(select l.lot_rrn from lot l where l.product_rrn=?)";
        Long num = jdbcTemplate.queryForObjectWithNull(sql, new Object[]{productRrn}, Long.class);
        if (num == null) {
            num = 0L;
        }
        return num;
    }

    @Override
    public boolean isLotHaveMovein(long lotRrn) {
        String sql = "select count(*) from LOT_TRANS_HISTORY WHERE LOT_RRN=? AND ( TRANS_ID='MOVEIN' OR " + "TRANS_ID" +
                "=? OR TRANS_ID=? )";
        int count = jdbcTemplate
                .queryForObject(sql, new Object[]{lotRrn, TransactionNames.SPLITFROM_KEY, TransactionNames.SPLIT_KEY},
                                Integer.class);
        return count > 0;
    }

    @Override
    public Long getMinReworkInfo(Long transRrn, Long lotRrn) {
        String sql = "SELECT R.REWORK_LAYER_SEQ FROM REWORK_INFO_EXT_HISTORY  R WHERE " + " R.TRANS_RRN = ? AND R" +
                ".FLAG = '0' AND R.LOT_RRN = ?";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{transRrn, lotRrn}, Long.class);
    }

    @Override
    public Long getReutrnExe(long reworkTransRrn) {
        String sql = "select attribute_data5 from rework_info_ext_history where trans_rrn = '" + reworkTransRrn + "'";
        return jdbcTemplate.queryForObjectWithNull(sql, Long.class);
    }

    @Override
    public Map getReworkExecutionInfo(Long transRrn, Long lotRrn) {
        String sql = "SELECT T.TRANS_RRN,T.EXECUTION_RRN,T.return_wfl_step_path,E.ATTRIBUTE_DATA5 FROM " +
                "REWORK_INFO_HISTORY T, " + " REWORK_INFO_EXT_HISTORY E WHERE T.LOT_RRN = E.LOT_RRN AND " +
                " E.FLAG = '0' " + "and t.trans_rrn=e.trans_rrn AND T.LOT_RRN = ? AND T.TRANS_RRN = ? " +
                " ORDER BY T.TRANS_RRN DESC";

        List<Map> maps = jdbcTemplate.query(sql, new Object[]{lotRrn, transRrn}, new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map map = new HashMap(2);
                Long returnExecutionRrn = new Long(rs.getString("attribute_data5"));
                String returnWflStepPath = rs.getString("return_wfl_step_path");
                map.put("executionRrn", returnExecutionRrn);
                map.put("returnWflStepPath", returnWflStepPath);
                return map;
            }
        });
        if (maps != null && maps.size() > 0) {
            return maps.get(0);
        }
        return null;
    }

    @Override
    public Map getReturnProcessInfo(Long reworkTransRrn, Long lotRrn) {
        String sql = "SELECT R.RETURN_WFL_STEP_PATH,R.TRANS_RRN,E.REWORK_LAYER_SEQ " + " FROM REWORK_INFO_HISTORY R," +
                "REWORK_INFO_EXT_HISTORY E WHERE R.LOT_RRN = E.LOT_RRN " + "AND " +
                " R.TRANS_RRN = E.TRANS_RRN AND E.FLAG =" + " '0' AND R.RETURN_WFL_STEP_PATH IS NOT NULL " +
                " AND R.LOT_RRN = ? AND R.TRANS_RRN < ? ORDER BY R" + ".TRANS_RRN DESC";
        List<Map> maps = jdbcTemplate.query(sql, new Object[]{lotRrn, reworkTransRrn}, new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map map = new HashMap(3);
                map.put("transRrn", rs.getLong("TRANS_RRN"));
                map.put("reworkLayerSeq", rs.getLong("REWORK_LAYER_SEQ"));
                map.put("returnWflStepPath", rs.getString("RETURN_WFL_STEP_PATH"));
                return map;
            }
        });
        if (maps != null && maps.size() > 0) {
            return maps.get(0);
        }
        return null;
    }

    @Override
    public Map getReworkInfo(Long transRrn, Long lotRrn) {
        String sql = "SELECT LOT_RRN,STEP_SEQUENCE,PROCESS_RRN," + "PROCESS_VERSION,PROCESS_STEP_VERSION," +
                "CURRENT_PROCESS_STEP_VERSION,REWORK_WFL_RRN," + "RETURN_PROCESS_STEP_VERSION,RETURNED_FLAG," +
                "CURRENT_HIST_STEP_SEQUENCE,RETURN_STEP_SEQUENCE," + "NEXT_REWORK_TRANS_RRN,EXECUTION_RRN" + "," +
                "REWORK_PROCESS_STEP_VERSION,REWORK_PROCESS_STEP_ID_VERSION,REWORK_OPERATION_RRN," +
                "REWORK_WFL_STEP_PATH,REWORK_COUNT,SUM_REWORK_COUNT FROM " + DataBaseNames.REWORK_INFO_HISTORY +
                " WHERE TRANS_RRN = ? and LOT_RRN=?";
        List<Map> reworkInfos = jdbcTemplate.query(sql, new Object[]{transRrn, lotRrn}, new RowMapper<Map>() {

            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map reworkInfo = new HashMap();
                reworkInfo.put("lotRrn", rs.getString("LOT_RRN"));
                reworkInfo.put("stepSequence", rs.getString("STEP_SEQUENCE"));
                reworkInfo.put("processRrn", rs.getString("PROCESS_RRN"));
                reworkInfo.put("processVersion", rs.getString("PROCESS_VERSION"));
                reworkInfo.put("processStepVersion", rs.getString("PROCESS_STEP_VERSION"));
                reworkInfo.put("currentProcessStepVersion", rs.getString("CURRENT_PROCESS_STEP_VERSION"));
                reworkInfo.put("reworkWflRrn", rs.getString("REWORK_WFL_RRN"));
                reworkInfo.put("returnProcessStepVersion", rs.getString("RETURN_PROCESS_STEP_VERSION"));
                reworkInfo.put("returnedFlag", rs.getString("RETURNED_FLAG"));
                reworkInfo.put("currentHistStepSequence", rs.getString("CURRENT_HIST_STEP_SEQUENCE"));
                reworkInfo.put("returnStepSequence", rs.getString("RETURN_STEP_SEQUENCE"));
                reworkInfo.put("nextReworkTransRrn", rs.getString("NEXT_REWORK_TRANS_RRN"));
                reworkInfo.put("executionRrn", rs.getString("EXECUTION_RRN"));
                reworkInfo.put("reworkProcessStepVersion", rs.getString("REWORK_PROCESS_STEP_VERSION"));
                reworkInfo.put("reworkProcessStepIdVersion", rs.getString("REWORK_PROCESS_STEP_ID_VERSION"));
                reworkInfo.put("reworkOperationRrn", rs.getString("REWORK_OPERATION_RRN"));
                reworkInfo.put("reworkWflStepPath", rs.getString("REWORK_WFL_STEP_PATH"));
                reworkInfo.put("reworkCount", rs.getString("REWORK_COUNT"));
                reworkInfo.put("sumReworkCount", rs.getString("SUM_REWORK_COUNT"));
                return reworkInfo;
            }
        });
        if (reworkInfos != null && reworkInfos.size() > 0) {
            return reworkInfos.get(0);
        }
        return null;
    }

    @Override
    public int getTotalQtyForUnscrap(long lotRrn) {
        String sql = "select count(t.unit_rrn) as CuntUnitScrap from unit t where lot_rrn= ? ";
        return jdbcTemplate.queryForObject(sql, new Object[]{lotRrn}, Integer.class);
    }

    @Override
    public Lot getCompletedssLotInfo(String lotId) {
        String sql = "SELECT l.QTY1,l.LOT_ID,l.LOT_RRN,l.LOT_TYPE,l.LOT_OWNER,l.PROCESS_RRN," + "l.PRODUCT_RRN,le" +
                ".COMPLETEDSS_LEVEL,le.COMPLETEDSS_TYPE,le.STORAGE,l.LOT_STATUS,le" + ".IS_DIVIDE_BOX FROM LOT l" +
                " JOIN " + "LOT_EXT le ON l.lot_rrn = le.LOT_RRN" + " WHERE l.LOT_ID ='" + lotId + "'";
        List<Map<String, Object>> results = jdbcTemplate
                .query(sql, new Object[]{}, (RowMapper<Map<String, Object>>) (rs, rowNum) -> {
                    Map<String, Object> m = new HashMap<>();
                    m.put("LOT_RRN", rs.getLong("LOT_RRN"));
                    m.put("COMPLETEDSS_LEVEL", rs.getString("COMPLETEDSS_LEVEL"));
                    m.put("COMPLETEDSS_TYPE", rs.getString("COMPLETEDSS_TYPE"));
                    m.put("STORAGE", rs.getString("STORAGE"));
                    m.put("PRODUCT_RRN", rs.getLong("PRODUCT_RRN"));
                    m.put("PROCESS_RRN", rs.getLong("PROCESS_RRN"));
                    m.put("LOT_OWNER", rs.getString("LOT_OWNER"));
                    m.put("LOT_TYPE", rs.getString("LOT_TYPE"));
                    m.put("LOT_STATUS", rs.getString("LOT_STATUS"));
                    m.put("IS_DIVIDE_BOX", rs.getString("IS_DIVIDE_BOX"));
                    m.put("QTY1", rs.getDouble("QTY1"));
                    return m;
                });

        if (results != null && results.size() > 0) {
            Map<String, Object> lotInfo = results.get(0);
            Lot lot = new Lot();
            lot.setLotId(lotId);
            lot.setLotRrn(MapUtils.getLong(lotInfo, "LOT_RRN"));
            lot.setCompletedssLevel(MapUtils.getString(lotInfo, "COMPLETEDSS_LEVEL"));
            lot.setCompletedssType(MapUtils.getString(lotInfo, "COMPLETEDSS_TYPE"));
            lot.setStorage(MapUtils.getString(lotInfo, "STORAGE"));
            lot.setProductRrn(MapUtils.getLong(lotInfo, "PRODUCT_RRN"));
            lot.setProcessRrn(MapUtils.getLong(lotInfo, "PROCESS_RRN"));
            lot.setLotOwner(MapUtils.getString(lotInfo, "LOT_OWNER"));
            lot.setLotType(MapUtils.getString(lotInfo, "LOT_TYPE"));
            lot.setLotStatus(MapUtils.getString(lotInfo, "LOT_STATUS"));
            lot.setIsDivideBox(MapUtils.getInteger(lotInfo, "IS_DIVIDE_BOX"));
            lot.setQty1(MapUtils.getDouble(lotInfo, "QTY1"));
            return lot;
        }
        return null;

    }

    @Override
    public List<Lot> getLotsForReassign(Long facilityRrn, Map<String, Object> condition) {
        StringBuilder sql = new StringBuilder(getLotSql());
        List<Object> args = new ArrayList<>();

        sql.append(" WHERE FACILITY_RRN = ? ");
        args.add(facilityRrn);

        String tempString = MapUtils.getString(condition, "lotId");
        if (StringUtils.isNotEmpty(tempString)) {
            sql.append(" AND LOT_ID = ? ");
            args.add(tempString);
        }

        Long tempLong = MapUtils.getLong(condition, "productRrn");
        if (tempLong != null && tempLong >= 0) {
            sql.append(" AND PRODUCT_RRN = ? ");
            args.add(tempLong);
        }

        tempLong = MapUtils.getLong(condition, "processRrn");
        if (tempLong != null && tempLong >= 0) {
            sql.append(" AND PROCESS_RRN = ? ");
            args.add(tempLong);
        }

        Integer tempInteger = MapUtils.getInteger(condition, "processVersion");
        if (tempInteger != null && tempInteger >= 0) {
            // if (MapUtils.getBooleanValue(condition, "isExactQueryProcessVersion")) {
                sql.append(" AND PROCESS_VERSION = ? ");
                args.add(tempInteger);
            // }
            // else {
            //     sql.append(" AND PROCESS_VERSION <= ? ");
            //     args.add(tempInteger);
            // }
        }

        tempInteger = MapUtils.getInteger(condition, "productVersion");
        if (tempInteger != null && tempInteger >= 0) {
            if (MapUtils.getBooleanValue(condition, "isExactQueryProcessVersion")) {
                sql.append(" AND PRODUCT_VERSION = ? ");
                args.add(tempInteger);
            } else {
                sql.append(" AND PRODUCT_VERSION <= ? ");
                args.add(tempInteger);
            }
        }
        // #40629 dummy lot reassign 点击query,查询不到lot的信息
        // 函数调用链 结合根据git 历史 发现isDummy字段已经删除 修改成了dummyFlag
        // 确保兼容 增加dummyFlag
        if (MapUtils.getBooleanValue(condition, "isDummy")||
                MapUtils.getBooleanValue(condition, "dummyFlag")) {
            sql.append(" AND CREATE_CATEGORY IN (?) ");
            args.addAll(Arrays.asList("C"));
        } else {
            sql.append(" AND CREATE_CATEGORY NOT IN (?) ");
            args.addAll(Arrays.asList("C"));
        }

        if (MapUtils.getBooleanValue(condition, "isHoldLot")) {
            sql.append(" AND (LOT_STATUS = ? OR LOT_STATUS = ?) ");
            args.add(LotStatus.HOLD);
            args.add(LotStatus.WAITING);
        } else {
            sql.append(" AND LOT_STATUS NOT IN (?, ?, ?, ?, ?, ?) ");
            args.addAll(Arrays.asList(LotStatus.getEndedStatus()));
        }

        sql.append(" ORDER BY LOT_ID ");

        return jdbcTemplate.query(sql.toString(), args.toArray(), new LotMapper());
    }

    @Override
    public String getUserName(String instanceId) {
        return getTransByName(instanceId);
    }

    @Override
    public List<Map<String, Object>> qryOperationParameters(Long lotRrn, Long stepSequence) {
        List parameterValues = new ArrayList();

        String sql = "SELECT t.operation_rrn, t.lot_rrn, t.parameter_seq, t.parameter_id, t.parameter_value," + " t" +
                ".attribute_data1, t.attribute_data2, t.attribute_data3 " +
                "  FROM operation_parameter_collection t WHERE T" + ".STEP_SEQUENCE = ? AND T.LOT_RRN = ?" +
                " order by parameter_seq";
        Object[] args = new Object[]{stepSequence, lotRrn};
        parameterValues = jdbcTemplate.query(sql, args, new RowMapper() {

            @Override
            public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map operationParameter = new HashMap();
                operationParameter.put("operationParameterId", rs.getString("parameter_id"));
                operationParameter.put("operationParameterValue", rs.getString("parameter_value"));
                return operationParameter;
            }
        });
        return parameterValues;
    }

    @Override
    public int getMaxFlagFromLotId(String lotId) {

        String sql = "select max(regexp_substr(regexp_substr(t.split_merge_flag,'#\\$#[0-9]+'),'[0-9]+' )) as " +
                "flagMax " + "from lot_ext t,lot l where t.lot_rrn=l.lot_rrn and l.lot_id LIKE ?";
        List fields = jdbcTemplate.query(sql, new Object[]{StringUtils.split(lotId, ".")[0] + "%"}, new RowMapper() {

            @Override
            public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                return rs.getObject("flagMax");
            }
        });
        if (fields.get(0) == null) {
            return 0;
        }
        return Integer.parseInt(fields.get(0).toString());

    }

    @Override
    public long getStepSequence(long lotRrn, long operationRrn) {

        StringBuffer sb = new StringBuffer();
        sb.append(" SELECT MAX(STEP_SEQUENCE) FROM ");
        sb.append(DataBaseNames.LOT_STEP_HISTORY);
        sb.append(" WHERE ");

        List<Long> args = new ArrayList<>();

        if (lotRrn > 0) {
            sb.append(" LOT_RRN = ?");
            args.add(lotRrn);

            if (operationRrn > 0) {
                sb.append(" AND OPERATION_RRN = ?");
                args.add(operationRrn);
            }
        } else {
            return -1L;
        }

        Long seq = jdbcTemplate.queryForObjectWithNull(sb.toString(), args.toArray(), Long.class);

        if (seq == null) {
            return -1L;
        }

        return seq;
    }

    @Override
    public List<Map> getLotReworkInfo(long lotRrn) {
        String sql = "SELECT IH.TRANS_RRN,IH.LOT_RRN,IH.STEP_SEQUENCE,IH.PROCESS_RRN,IH.PROCESS_VERSION, " + " IH" +
                ".PROCESS_STEP_VERSION,IH.CURRENT_PROCESS_STEP_VERSION,IH.REWORK_WFL_RRN, " +
                " IH.RETURN_WFL_STEP_PATH,IH" + ".RETURN_PROCESS_STEP_VERSION,IH.RETURNED_FLAG,IH" +
                ".CURRENT_HIST_STEP_SEQUENCE, " + " IH" +
                ".RETURN_STEP_SEQUENCE,IH.NEXT_REWORK_TRANS_RRN,IH.EXECUTION_RRN,EH.FLAG,EH" + ".BASE_TRANS_RRN, " +
                " EH" + ".ATTRIBUTE_DATA1,EH.ATTRIBUTE_DATA3,EH.ATTRIBUTE_DATA4,EH.ATTRIBUTE_DATA5,EH" +
                ".REWORK_LAYER_SEQ,EH" + ".END_TRANS_RRN FROM REWORK_INFO_HISTORY IH, " +
                " REWORK_INFO_EXT_HISTORY EH WHERE IH.TRANS_RRN=EH" + ".TRANS_RRN AND IH.LOT_RRN=EH" +
                ".LOT_RRN AND IH.LOT_RRN=? " + " AND EH.BASE_TRANS_RRN IN (SELECT EH" +
                ".TRANS_RRN FROM REWORK_INFO_EXT_HISTORY EH " + "WHERE EH.FLAG = '0')" +
                " ORDER BY EH.REWORK_LAYER_SEQ";

        //TODO: rebuild
        return jdbcTemplate.query(sql, new Object[]{lotRrn}, new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map m = new HashMap();
                m.put("transRrn", new Long(rs.getLong("TRANS_RRN")));
                m.put("lotRrn", new Long(rs.getLong("LOT_RRN")));
                m.put("stepSeq", new Long(rs.getLong("STEP_SEQUENCE")));
                m.put("processRrn", new Long(rs.getLong("PROCESS_RRN")));
                m.put("processVersion", new Long(rs.getLong("PROCESS_VERSION")));
                m.put("processStepVersion", rs.getString("PROCESS_STEP_VERSION"));
                m.put("currentProcessStepVersion", rs.getString("CURRENT_PROCESS_STEP_VERSION"));
                m.put("reworkWflRrn", new Long(rs.getLong("REWORK_WFL_RRN")));
                m.put("returnWflStepPath", rs.getString("RETURN_WFL_STEP_PATH"));
                m.put("returnProcessStepVersion", rs.getString("RETURN_PROCESS_STEP_VERSION"));
                m.put("returnedFlag", rs.getString("RETURNED_FLAG"));
                m.put("currentHistStepSeq", new Long(rs.getLong("CURRENT_HIST_STEP_SEQUENCE")));
                m.put("returnStepSeq", new Long(rs.getLong("RETURN_STEP_SEQUENCE")));
                m.put("nextReworkTransRrn", new Long(rs.getLong("NEXT_REWORK_TRANS_RRN")));
                m.put("executionRrn", new Long(rs.getLong("EXECUTION_RRN")));
                m.put("flag", rs.getString("FLAG"));
                m.put("baseTransRrn", String.valueOf(rs.getLong("BASE_TRANS_RRN")));
                m.put("attributeData1", rs.getString("ATTRIBUTE_DATA1"));
                m.put("attributeData3", rs.getString("ATTRIBUTE_DATA3"));
                m.put("attributeData4", rs.getString("ATTRIBUTE_DATA4"));
                m.put("attributeData5", rs.getString("ATTRIBUTE_DATA5"));
                m.put("reworkLayerSeq", new Long(rs.getLong("REWORK_LAYER_SEQ")));
                m.put("endTransRrn", new Long(rs.getLong("END_TRANS_RRN")));
                return m;
            }
        });
    }

    @Override
    public Long getNewLotTransRrn(long lotRrn) {

        long transRrn = 0;
        String sql = " SELECT MAX(R.TRANS_RRN) TRANS_RRN FROM REWORK_INFO_EXT_HISTORY R " + " WHERE R.LOT_RRN = ? AND" +
                " R.FLAG='0'";
        Long maxTransRrn = jdbcTemplate.queryForObjectWithNull(sql, new Object[]{lotRrn}, Long.class);
        return maxTransRrn != null ? maxTransRrn : transRrn;

    }

    @Override
    public Long getHoldBy(Long transRrn, Long parentLotRrn) {
        String sql = "SELECT HOLD_BY FROM  MULTIPLE_HOLD WHERE  TRANS_RRN=? AND " + "INSTANCE_RRN=?";
        Long result = jdbcTemplate.queryForObjectWithNull(sql, new Object[]{transRrn, parentLotRrn}, Long.class);
        return result;
    }

    @Override
    public Map getParentLotBankInfo(long lotRrn) {

        Map parentLotInfo = new HashMap();
        String sql = "select lh.reference_document,tl.trans_performed_by, " + " lh.trans_comments from " +
                "lot_trans_history lh,transaction_log tl " +
                " where lh.trans_rrn = tl.trans_rrn and lh.trans_id='BANKIN' " + "and lh.lot_rrn=? " +
                " and lh.trans_rrn=NVL((select max(lh.trans_rrn) from lot_trans_history lh," + "transaction_log tl " +
                " where lh.trans_rrn = tl.trans_rrn and lh.trans_id='BANKIN' and lh.lot_rrn=?),0)";

        List<Map> maps = jdbcTemplate.query(sql, new Object[]{lotRrn, lotRrn}, new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map map = new HashMap();
                map.put("referenceDocument", rs.getString("reference_document"));
                map.put("user", rs.getString("trans_performed_by"));
                map.put("transComments", rs.getString("trans_comments"));
                return map;
            }
        });

        if (maps != null && maps.size() > 0) {
            parentLotInfo = maps.get(0);
        }
        return parentLotInfo;
    }

    @Override
    public List<Map> getSplitLotInfo(long lotRrn, long facilityRrn) {
        String sql = "select t.target_lot_id,t.trans_qty1, h.trans_comments,l.trans_start_timestamp,l" +
                ".trans_END_timestamp," + " l.trans_performed_by,o.product_rrn,o.process_rrn,o.process_step_version, " +
                " o" + ".process_step_id_version,o.operation_rrn,o.lot_status " +
                " from split_merge_history t,lot_trans_history h " + ",transaction_log l,lot o " +
                " where t.source_lot_rrn=? and t.target_lot_rrn !=? " + " and t.trans_rrn = h" +
                ".trans_rrn and t.target_lot_rrn= h.lot_rrn and h" + ".trans_id='CREATE' " +
                " and t.trans_rrn=l.trans_rrn" + " and t.target_lot_rrn=o.lot_rrn";

        List<Map> lotsInfo = jdbcTemplate.query(sql, new Object[]{lotRrn, lotRrn}, new RowMapper<Map>() {
            int j = 1;

            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map m = new HashMap();
                m.put("seq", new Long(j++));
                m.put("splitLotId", rs.getString("target_lot_id"));
                m.put("transQty1", new Long(rs.getLong("trans_qty1")));
                m.put("transComments", rs.getString("trans_comments"));
                m.put("transStartTimestamp",
                      DateUtils.formatDate(rs.getDate("trans_start_timestamp"), DateUtils.DATE_FORMAT4DAY));
                String transByName = getTransByName(rs.getString("trans_performed_by"));
                if (transByName != null) {
                    m.put("transPerformedBy", rs.getString("trans_performed_by") + " " + transByName);
                } else {
                    m.put("transPerformedBy", rs.getString("trans_performed_by"));
                }
                m.put("product_rrn", rs.getLong("product_rrn"));
                m.put("process_rrn", rs.getLong("process_rrn"));
                m.put("operation_rrn", rs.getLong("operation_rrn"));
                m.put("routeId", parseRoute(rs.getString("process_step_id_version")));
                m.put("lotStatus", rs.getString("lot_status"));
                return m;
            }
        });

        return lotsInfo;
    }

    @Override
    public long getReworkSeq(Long lotRrn, String reworkRouteRrn) {
        String sql = " SELECT COUNT(T.TRANS_RRN) AS NUM FROM " + " REWORK_INFO_EXT_HISTORY T WHERE T.LOT_RRN = ? " +
                " AND T.ATTRIBUTE_DATA3 = ?";

        return jdbcTemplate.queryForObjectWithNull(sql, long.class, lotRrn, reworkRouteRrn);
    }

    @Override
    public List<LotFutureReassign> getLotFutureReassigns(long lotRrn, String curWflStepPath) {

        List args = new ArrayList();
        args.add(lotRrn);
        StringBuilder sql = new StringBuilder("SELECT ");

        sql.append(" TRANS_RRN, TRANS_SEQUENCE, TRANS_TIMESTAMP, LOT_RRN, STEP_SEQUENCE, FACILITY_RRN, ");
        sql.append(" PRODUCT_RRN, PROCESS_RRN, PROCESS_VERSION, WFL_STEP_PATH, ");
        sql.append(
                " REASON_CATEGORY, REASON_CODE, REASON, RESPONSIBILITY, DELETE_FUTURE_ACTION_FLAG," + "REASSIGN_TYPE," +
                        "CURRENT_WFL_STEP_PATH,PRODUCT_VERSION ");
        sql.append(" FROM ");
        sql.append(DataBaseNames.LOT_FUTURE_REASSIGN);
        sql.append(" WHERE LOT_RRN = ? ");

        if (StringUtils.isNotBlank(curWflStepPath)) {
            sql.append("AND CURRENT_WFL_STEP_PATH = ? ");
            args.add(curWflStepPath);

        }
        sql.append(" ORDER BY TRANS_TIMESTAMP, TRANS_SEQUENCE ");

        return jdbcTemplate.query(sql.toString(), new LotFutureReassignMapper(), args.toArray());
    }

    @Override
    public List<Map> getFutureholdLotList(Map lotMap) {
        List<Map> futureHoldList = new ArrayList();
        Long refRrn = MapUtils.getLong(lotMap, "refRrn");
        final String routeRrn = MapUtils.getString(lotMap, "routeRrn");
        final String operationRrn = MapUtils.getString(lotMap, "operationRrn");
        final String lotRrn = MapUtils.getString(lotMap, "lotRrn");
        String routeSeq = MapUtils.getString(lotMap, "routeSeq");// 获取路径序号
        String operationSeq = MapUtils.getString(lotMap, "operationSeq");// 获取步骤序号

        String sql =
                "SELECT V.STATUS,V.CONTEXT_KEY1,V.CONTEXT_KEY2,V.CONTEXT_KEY3,V.CONTEXT_KEY4,V.CONTEXT_KEY5, " + " V" +
                        ".RESULT_VALUE2,V.RESULT_VALUE3,V.RESULT_VALUE4,V.RESULT_VALUE5,V.RESULT_VALUE6," +
                        " V.SEQUENCE_NUMBER,V" + ".RESULT_VALUE1, " +
                        " V.EFFECTIVE_DATE_FROM,E.ACTION_TYPE FROM CONTEXT_VALUE V,EEN_ACTION E WHERE V" +
                        ".CONTEXT_RRN = ? AND " + " V.CONTEXT_KEY1=? AND V.CONTEXT_KEY2=? AND V.CONTEXT_KEY3=? AND V" +
                        ".CONTEXT_KEY4=? AND V" + ".CONTEXT_KEY5=? AND V.STATUS=?" +
                        " AND V.RESULT_VALUE1 = E.ACTION_RRN ";

        Object[] args = new Object[]{refRrn, routeRrn, operationRrn, lotRrn, routeSeq, operationSeq,
                                     VersionStatus.ACTIVE_KEY};

        futureHoldList = jdbcTemplate.query(sql, args, new RowMapper() {

            @Override
            public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map futureHoldMap = new HashMap();
                futureHoldMap.put("routeRrn", Long.parseLong(StringUtils.trimToEmpty(rs.getString("CONTEXT_KEY1"))));
                futureHoldMap
                        .put("operationRrn", Long.parseLong(StringUtils.trimToEmpty(rs.getString("CONTEXT_KEY2"))));
                futureHoldMap.put("routeSeq", rs.getString("CONTEXT_KEY4"));
                futureHoldMap.put("operationSeq", rs.getString("CONTEXT_KEY5"));
                futureHoldMap.put("userNamed", rs.getString("RESULT_VALUE2"));
                futureHoldMap.put("holdGroup", rs.getString("RESULT_VALUE3"));
                futureHoldMap.put("holdCode", rs.getString("RESULT_VALUE4"));
                futureHoldMap.put("holdReason", rs.getString("RESULT_VALUE5"));
                futureHoldMap.put("effectCount", rs.getString("RESULT_VALUE6"));
                futureHoldMap.put("sequenceNumber", rs.getInt("SEQUENCE_NUMBER"));
                futureHoldMap.put("status", rs.getString("STATUS"));
                futureHoldMap.put("actionRrn", rs.getString("RESULT_VALUE1"));
                java.sql.Date db_Date = rs.getDate("EFFECTIVE_DATE_FROM");
                String dbDate = DateUtils.formatDate(db_Date);
                futureHoldMap.put("futureholdsetupdate", dbDate);
                futureHoldMap.put("flag", rs.getString("ACTION_TYPE"));
                if (hasExecuted(NumberUtils.toLong(lotRrn), NumberUtils.toLong(routeRrn),
                                NumberUtils.toLong(operationRrn))) {
                    futureHoldMap.put("executedFlag", "EXECUTED");
                } else {
                    futureHoldMap.put("executedFlag", "");
                }

                return futureHoldMap;
            }
        });
        List<Map> oldFutureHoldList = getFutureholdLotListByOldData(lotMap);
        if (oldFutureHoldList != null) {
            futureHoldList = oldFutureHoldList;
        }
        return futureHoldList;
    }

    @Override
    public List<Map> getFutureholdProductList(Map productMap) {
        Long refRrn = MapUtils.getLong(productMap, "refRrn");
        String productRrn = MapUtils.getString(productMap, "productRrn");
        String processRrn = MapUtils.getString(productMap, "processRrn");
        String routeRrn = MapUtils.getString(productMap, "routeRrn");
        String operationRrn = MapUtils.getString(productMap, "operationRrn");
        String sql = "SELECT V.CONTEXT_KEY1,V.CONTEXT_KEY2,V.CONTEXT_KEY3, V.CONTEXT_KEY4, " + " V.RESULT_VALUE2,V" +
                ".RESULT_VALUE3,V.RESULT_VALUE4,V.RESULT_VALUE5,V.RESULT_VALUE1, " + " V.EFFECTIVE_DATE_FROM FROM " +
                "CONTEXT_VALUE V WHERE V.CONTEXT_RRN = ? AND V" + ".CONTEXT_KEY1=? " + " AND V.CONTEXT_KEY2=? AND V" +
                ".CONTEXT_KEY3=? AND V.CONTEXT_KEY4=? ";

        return jdbcTemplate
                .query(sql, new Object[]{refRrn, productRrn, processRrn, routeRrn, operationRrn}, new RowMapper<Map>() {
                    @Override
                    public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                        Map futureHoldMap = new HashMap();
                        futureHoldMap.put("processRrn",
                                          Long.parseLong(StringUtils.trimToEmpty(rs.getString("CONTEXT_KEY2"))));
                        futureHoldMap
                                .put("routeRrn", Long.parseLong(StringUtils.trimToEmpty(rs.getString("CONTEXT_KEY3"))));
                        futureHoldMap.put("operationRrn",
                                          Long.parseLong(StringUtils.trimToEmpty(rs.getString("CONTEXT_KEY4"))));

                        futureHoldMap.put("userNamed", rs.getString("RESULT_VALUE2"));
                        futureHoldMap.put("holdGroup", rs.getString("RESULT_VALUE3"));
                        futureHoldMap.put("holdCode", rs.getString("RESULT_VALUE4"));
                        futureHoldMap.put("holdReason", rs.getString("RESULT_VALUE5"));
                        futureHoldMap.put("actionRrn", rs.getString("RESULT_VALUE1"));
                        java.sql.Date db_Date = rs.getDate("EFFECTIVE_DATE_FROM");
                        String dbDate = DateUtils.formatDate(db_Date);
                        futureHoldMap.put("futureholdsetupdate", dbDate);
                        futureHoldMap.put("flag", "FUTURE HOLD BY PRODUCT");
                        if ((rs.getString("CONTEXT_KEY3") != null) && (rs.getString("CONTEXT_KEY4") != null) &&
                                (productRrn != null) && (productMap.get("lotRrn") != null)) {
                            List<Long> executedLotList = getLotExecuted(Long.parseLong(productRrn), Long.parseLong(
                                    StringUtils.trimToEmpty(rs.getString("CONTEXT_KEY2"))), Long.parseLong(
                                    StringUtils.trimToEmpty(rs.getString("CONTEXT_KEY3"))), Long.parseLong(
                                    StringUtils.trimToEmpty(rs.getString("CONTEXT_KEY4"))),
                                                                        MapUtils.getLongValue(productMap, "lotRrn"));
                            if (CollectionUtils.isNotEmpty(executedLotList)) {
                                futureHoldMap.put("executedFlag", "EXECUTED");
                            } else {
                                futureHoldMap.put("executedFlag", "");
                            }
                        } else {
                            futureHoldMap.put("executedFlag", "");
                        }
                        return futureHoldMap;
                    }
                });

    }

    @Override
    public List<Map> getFutureholdOperationList(long refRrn, long operationRrn) {
        String sql = "SELECT V.CONTEXT_KEY1,V.CONTEXT_KEY2,V.CONTEXT_KEY3, V.CONTEXT_KEY4, " + " V.RESULT_VALUE2,V" +
                ".RESULT_VALUE3,V.RESULT_VALUE4,V.RESULT_VALUE5,V.RESULT_VALUE1, " + " V.EFFECTIVE_DATE_FROM FROM " +
                "CONTEXT_VALUE V WHERE V.CONTEXT_RRN = ? AND V" + ".CONTEXT_KEY1=? ";

        return jdbcTemplate.query(sql, new Object[]{refRrn, String.valueOf(operationRrn)}, new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map futureHoldMap = new HashMap();
                futureHoldMap
                        .put("operationRrn", Long.parseLong(StringUtils.trimToEmpty(rs.getString("CONTEXT_KEY1"))));

                futureHoldMap.put("userNamed", rs.getString("RESULT_VALUE2"));
                futureHoldMap.put("holdGroup", rs.getString("RESULT_VALUE3"));
                futureHoldMap.put("holdCode", rs.getString("RESULT_VALUE4"));
                futureHoldMap.put("holdReason", rs.getString("RESULT_VALUE5"));
                futureHoldMap.put("actionRrn", rs.getString("RESULT_VALUE1"));
                java.sql.Date db_Date = rs.getDate("EFFECTIVE_DATE_FROM");
                String dbDate = DateUtils.formatDate(db_Date);
                futureHoldMap.put("futureholdsetupdate", dbDate);

                return futureHoldMap;
            }
        });
    }

    @Override
    public boolean isLotsInSameJobPrepared(Long jobRrn) {
        String sql = "SELECT LOT_RRN" + " FROM " + DataBaseNames.LOT + " WHERE NEXT_JOB_RRN1 = ? OR NEXT_JOB_RRN2 = ?";

        return CollectionUtils.isEmpty(jdbcTemplate.query(sql, long.class, jobRrn, jobRrn));
    }

    @Override
    public String getPreviousStationStep(Lot lot) {
        String sql = " SELECT CT.INSTANCE_ID FROM LOT_STEP_HISTORY YY,NAMED_OBJECT CT WHERE YY.LOT_RRN=? AND YY" +
                ".STEP_SEQUENCE=? " + " AND CT.INSTANCE_RRN=YY.OPERATION_RRN ";

        return jdbcTemplate
                .queryForObjectWithNull(sql, new Object[]{lot.getLotRrn(), lot.getStepSequence() - 1}, String.class);
    }

    @Override
    public boolean isMaterialMapping(Lot lot) {
        String sql = "SELECT count(from_rrn) FROM relation where link_type='PRODUCT_TO_MATERIAL_MAPPING' and " +
                "from_rrn=? and to_rrn=?" + " and attribute_data_1=? and attribute_data_2=? and attribute_data_3='Y'";

        int count = jdbcTemplate.queryForObjectWithNull(sql, new Object[]{lot.getProductRrn(), lot.getOperationRrn(),
                                                                          String.valueOf(lot.getRouteRrn()),
                                                                          String.valueOf(lot.getProcessRrn())},
                                                        int.class);

        return count > 0;
    }

    @Override
    public int queryLotExtCount(long lotRrn) {
        String querySql = "SELECT COUNT(*) LOTEXTCOUNT FROM LOT_EXT O " + " WHERE O.LOT_RRN= ?";
        return jdbcTemplate.queryForObjectWithNull(querySql, new Object[]{lotRrn}, int.class);
    }

    @Override
    public List<Map> getLotList4Ext(Map condition) {
        String filed = "LOT.FACILITY_RRN, LOT.LOT_ID, LOT.BASED_LOT_RRN,LOT.CREATED_PLAN_LOT_RRN,LOT.HOT_FLAG,LOT" +
                ".PRIORITY,LOT.LAYER_ID,LOT.STARTED_FLAG," + "LOT.STARTED_TIMESTAMP,LOT.CREATE_CATEGORY,LOT" +
                ".CREATED_TIMESTAMP,LOT.END_TIMESTAMP,LOT" + ".DUE_DATE,LOT.SCHEDULE_DUE_DATE," +
                "LOT.LATE_SCHEDULED_FLAG," + "LOT.ESTIMATED_REMAIN_TIME,LOT.DUMMY_FLAG,LOT.LOT_TYPE,LOT" +
                ".LOT_OWNER,LOT.QTY1,LOT.QTY2," + "LOT" +
                ".DUMMY_QTY1,LOT.INPUT_QTY1,LOT.INPUT_QTY2,LOT.SUBCONTRACTOR_RRN,LOT.LOT_COMMENTS,LOT" +
                ".STEP_SEQUENCE," + "LOT.STEP_NUMBER_IN_PROCESS," +
                "LOT.HOLD_TIMESTAMP,LOT.REWORK_TRANS_RRN,LOT.REWORK_CATEGORY,LOT" + ".CARRIER_RRN,LOT" +
                ".BEFORE_STATUS,LOT.LOT_STATUS,LOT.PROCESSING_STATUS," + "LOT.QUEUE_TIMESTAMP,LOT" +
                ".PRODUCT_RRN,LOT.PROCESS_RRN,LOT.PROCESS_VERSION,LOT" + ".PROCESS_STEP_VERSION,LOT" +
                ".PROCESS_STEP_ID_VERSION," + "LOT.OPERATION_RRN,LOT.OPERATION_VERSION,LOT.NEXT_STEP_VERSION1,LOT" +
                ".NEXT_STEP_ID_VERSION1,LOT.NEXT_OPERATION_RRN1,LOT.NEXT_STEP_VERSION2," +
                "LOT.NEXT_STEP_ID_VERSION2," + "LOT.NEXT_OPERATION_RRN2,LOT.STAGE_ID,LOT.LAYER_ID,LOT" +
                ".ROUTE_SEQ,LOT.OPERATION_SEQ,LOT.BOR_RRN," + "LOT.EQPT_RRN," +
                "LOT.RECIPE_LOGICAL_RRN,LOT.RECIPE_PHYSICAL_ID,LOT.RECIPE_STRING,LOT_EXT" + ".TEMP_RECIPE_STRING," +
                "LOT_EXT.ATTRIBUTE_DATA1,LOT.NEXT_RECIPE_STRING1,LOT.NEXT_RECIPE_STRING2," + "LOT.JOB_RRN,LOT" +
                ".NEXT_JOB_RRN1,LOT.NEXT_JOB_RRN2," + "LOT.EXECUTION_RRN,LOT.LOT_RRN,LOT" +
                ".WFL_STEP_PATH,LOT.RETICLE_RRN,TIME_REMAINING,LOT" + ".SHIPPED_QTY1,LOT.SHIPPED_QTY2,LOT" +
                ".PRODUCT_LAYER,LOT.LOT_PLAN_TYPE";

        String tableTime = "SELECT LOT_RRN, DECODE(SIGN(TIME_REMAINING), -1, 0, TIME_REMAINING) AS TIME_REMAINING " +
                " FROM (select " + "lot_rrn,min((ROUND(TO_NUMBER(TO_DATE(TO_CHAR(T0.START_TIME, 'YYYY-MM-DD " +
                "HH24:MI:SS'), 'YYYY-MM-DD " + "HH24:MI:SS') - sysdate) * 86400)) + T0.TIMELIMIT) " +
                " AS TIME_REMAINING from TIMELIMIT_STATUS t0 where " + "t0.timelimit >= 0 and t0.status = " +
                "'NORMAL' group by lot_rrn)";

        String sql = "SELECT " + filed + " FROM LOT,LOT_EXT,(" + tableTime + ") T";

        StringBuffer whereSql = new StringBuffer(" WHERE LOT.LOT_RRN = LOT_EXT.LOT_RRN(+) ");

        String objectRrn = MapUtils.getString(condition, "objectRrn");
        if (objectRrn != null) {
            objectRrn = objectRrn.replace('_', ',');

            String tableLot = "(select l.lot_rrn from lot L,(select context_key4  as operation_rrn,context_key5  as " +
                    "lot_rrn," + "result_value1 as entity_rrn" +
                    "  from context_value c where status = 'ACTIVE' AND context_rrn in " +
                    "     (select instance_rrn from named_object where instance_id = " +
                    "'LOT_SPECIAL_EQUIP_CONTEXT')) T " +
                    "      WHERE L.LOT_RRN = T.lot_rrn(+) AND L.OPERATION_RRN = T.OPERATION_RRN AND T" +
                    ".ENTITY_RRN in ('" + objectRrn.replace(",", "','") + "') " + " union " +
                    " select distinct lot_rrn  from (" + " SELECT lot.lot_rrn from Lot " +
                    "WHERE lot.operation_rrn IN  " + "  (SELECT o.operation_rrn  FROM operation o WHERE o" +
                    ".entity_group_rrn in" + "     (SELECT distinct to_rrn FROM relation t WHERE t.link_type = " +
                    "'ENTITY_TO_ENTITY_GROUP' AND t.from_rrn IN (" + objectRrn + ")))" + " union SELECT lot.lot_rrn" +
                    " from Lot WHERE lot.operation_rrn in" + " (select r.from_rrn from relation r where r.to_rrn " +
                    "IN (" + objectRrn + ") and r.link_type='OPERATION_TO_EQUIPMENT'))" + " where to_Char" +
                    "(LOT_RRN) NOT IN" + "    (select to_char(l.LOT_RRN) from lot l, (select context_key4 as " +
                    "operation_rrn, " + "context_key5 as lot_rrn " + "       from context_value c where status " +
                    "= 'ACTIVE' AND context_rrn in " + "        (select instance_rrn from named_object where " +
                    "instance_id = " + "'LOT_SPECIAL_EQUIP_CONTEXT')) T " + "    WHERE to_char(L.LOT_RRN) = T" +
                    ".lot_rrn(+) AND to_char(L.OPERATION_RRN) = T" + ".OPERATION_RRN)" + ") talot";

            sql = sql + "," + tableLot;
            whereSql.append(" AND LOT.LOT_RRN = talot.lot_rrn");
        }

        if (MapUtils.getObject(condition, "lotStatus") != null) {
            ArrayList statusList = (ArrayList) condition.get("lotStatus");
            whereSql.append(" AND (LOT.LOT_STATUS='" + statusList.remove(0) + "'");
            for (Iterator iterator = statusList.iterator(); iterator.hasNext(); ) {
                String status = (String) iterator.next();
                whereSql.append(" OR LOT.LOT_STATUS='" + status + "'");
            }
            whereSql.append(" ) ");
        }

        if (MapUtils.getInteger(condition, "PAGESIZE") != null) {
            whereSql.append(" AND ROWNUM<=" + MapUtils.getInteger(condition, "PAGESIZE").intValue());
            whereSql.append(" AND LOT.LOT_RRN = T.LOT_RRN(+)");
        }

        if (condition.get(DUMMY_FLAG) != null) {
            whereSql.append(" AND  DUMMY_FLAG = '" + condition.get(DUMMY_FLAG) + "'");
        }

        Object stationRrn = MapUtils.getObject(condition, "stationRrn");
        if (stationRrn != null) {
            whereSql.append(
                    " AND ((lot.operation_rrn IN (SELECT distinct to_rrn FROM relation t WHERE t" + ".link_type" +
                            "='STATION_TO_OPERATION' AND t.from_rrn=" + stationRrn + "))) ");
        }

        if (MapUtils.getBoolean(condition, "jobGridFlag") != null &&
                MapUtils.getBooleanValue(condition, "jobGridFlag") && objectRrn != null) {
            whereSql.append(" AND LOT.JOB_RRN=JOB.JOB_RRN AND JOB.EQPT_RRN in (" + objectRrn + ")");
            sql = sql + "," + DataBaseNames.JOB;
        }

        String sapphire = MapUtils.getString(condition, "Sapphire");
        // 查询Bonding批次
        if (sapphire != null && sapphire.equalsIgnoreCase("isSapphire")) {
            // whereSql.append(" AND LOT.PRODUCT_RRN IN (SELECT INSTANCE_RRN FROM NAMED_OBJECT WHERE
            // OBJECT_TYPE="+MiscUtils.parseSQL(ObjectList.SAPPHIRE)+")");
            whereSql.append(" AND LOT.OPERATION_RRN IN (SELECT OO.OPERATION_RRN FROM OPERATION OO,NAMED_OBJECT N1," +
                                    "NAMED_OBJECT N2 " +
                                    " WHERE OO.MVIN_WFL_RRN=N1.INSTANCE_RRN AND OO.MVOU_WFL_RRN=N2.INSTANCE_RRN " +
                                    " AND N1.INSTANCE_ID='MOVEIN_BONDED_STD' AND N2" +
                                    ".INSTANCE_ID='MOVEOUT_AUTOBONDED_STD')");
        }
        // 查询非Bonding批次
        if (sapphire != null && sapphire.equalsIgnoreCase("notSapphire")) {
            // whereSql.append(" AND LOT.PRODUCT_RRN NOT IN (SELECT INSTANCE_RRN FROM NAMED_OBJECT WHERE
            // OBJECT_TYPE="+MiscUtils.parseSQL(ObjectList.SAPPHIRE)+")");
        }
        String lotId = MapUtils.getString(condition, "lotId");
        // 派工页面查询条件
        if (StringUtils.isNotBlank(lotId)) {
            whereSql.append(" AND LOT_ID LIKE UPPER (" + "'" + '%' + lotId + '%' + "'" + ")");
        }
        String proId = MapUtils.getString(condition, "proId");
        if (StringUtils.isNotBlank(proId)) {
            whereSql.append(
                    " AND PRODUCT_RRN IN ( SELECT INSTANCE_RRN FROM NAMED_OBJECT WHERE INSTANCE_ID IN " + "(SELECT " +
                            "INSTANCE_ID FROM NAMED_OBJECT where INSTANCE_ID LIKE UPPER (" + "'" + '%' + proId + '%' +
                            "'" + ")))");
        }
        //todo NPW_BANK 先不要
        //whereSql.append(" AND LOT.LOT_ID NOT IN (SELECT LOT_ID FROM NPW_BANK) ");
        sql = sql + whereSql.toString() + " order by " + " create_category desc, lot_status,lot_id,TIME_REMAINING, " +
                "PRIORITY, QUEUE_TIMESTAMP, " + "HOT_FLAG DESC";
        List<Map> lots = new ArrayList();
        List<Map> list = jdbcTemplate.query(sql, Map.class);
        for (Map map : list) {
            HashMap lot = new HashMap();
            lot.put("lotRrn", MapUtils.getString(map, "LOT_RRN"));
            lot.put("lotId", MapUtils.getString(map, "LOT_ID"));
            lot.put("lotStatus", MapUtils.getString(map, "LOT_STATUS"));
            lot.put("lotType", MapUtils.getString(map, "LOT_TYPE"));
            lot.put("hotFlag", "1".equals(MapUtils.getString(map, "HOT_FLAG")) ? "Y" : "N");
            lot.put("hotFlagCode", MapUtils.getString(map, "HOT_FLAG"));
            lot.put("priority", MapUtils.getString(map, "PRIORITY"));
            lot.put("layerId", MapUtils.getString(map, "LAYER_ID"));
            lot.put("carrierRrn", MapUtils.getString(map, "CARRIER_RRN"));
            lot.put("qty1", MapUtils.getString(map, "QTY1"));
            lot.put("qty2", MapUtils.getString(map, "QTY2"));
            lot.put("dummyQty1", new Integer(MapUtils.getInteger(map, "DUMMY_QTY1")));
            lot.put("dummyFlag", MapUtils.getString(map, "DUMMY_FLAG"));
            if (MapUtils.getString(map, "EQPT_RRN") == null) {
                lot.put("equipmentRrn", "");
            } else {
                lot.put("equipmentRrn", MapUtils.getString(map, "EQPT_RRN"));
            }
            lot.put("operationRrn", MapUtils.getString(map, "OPERATION_RRN"));
            lot.put("operationVersion", MapUtils.getString(map, "OPERATION_VERSION"));
            lot.put("reticleRrn", MapUtils.getString(map, "RETICLE_RRN"));

            lot.put("routeRrn", Long.toString(
                    (WipUtils.getRouteRrnByProcessStep(MapUtils.getString(map, "PROCESS_STEP_VERSION")).longValue())));
            lot.put("routeId", WipUtils.getRouteIdByProcessStep(MapUtils.getString(map, "PROCESS_STEP_ID_VERSION")));

            lot.put("productRrn", new Long(MapUtils.getLong(map, "PRODUCT_RRN")));
            lot.put("processRrn", new Long(MapUtils.getLong(map, "PROCESS_RRN")));
            lot.put("facilityRrn", new Long(MapUtils.getLong(map, "FACILITY_RRN")));
            long spent = System.currentTimeMillis() / 1000 - ((Timestamp) map.get("QUEUE_TIMESTAMP")).getTime() / 1000;
            lot.put("queueTimestamp", new Long(spent / 60));
            lot.put("jobRrn", MapUtils.getString(map, "JOB_RRN"));
            lot.put("createdTimestamp", new Long(
                    ((Timestamp) map.get("CREATED_TIMESTAMP") == null) ? 0 : ((Timestamp) map.get("CREATED_TIMESTAMP"))
                            .getTime()));
            lot.put("dueDate", new Long(
                    ((Timestamp) map.get("DUE_DATE") == null) ? 0 : ((Timestamp) map.get("DUE_DATE")).getTime()));
            lot.put("estimatedRemainTime", new Long(MapUtils.getLong(map, "ESTIMATED_REMAIN_TIME")));
            lot.put("pollutionLevel", MapUtils.getString(map, "ATTRIBUTE_DATA1"));// 污染等级
            lot.put("timeLimit",
                    MapUtils.getString(map, "TIME_REMAINING") == null ? "" : MapUtils.getString(map, "TIME_REMAINING"));
            lot.put("productLayer", MapUtils.getString(map, "PRODUCT_LAYER"));
            lot.put("routeSeq", MapUtils.getString(map, "ROUTE_SEQ"));
            lot.put("operationSeq", MapUtils.getString(map, "OPERATION_SEQ"));
            lot.put("processVersion", MapUtils.getInteger(map, "PROCESS_VERSION"));
            lot.put("processStepVersion", MapUtils.getString(map, "PROCESS_STEP_VERSION"));

            lot.put("recipeLogicalRrn", MapUtils.getLong(map, "RECIPE_LOGICAL_RRN"));
            lot.put("recipePhysicalId", MapUtils.getString(map, "RECIPE_PHYSICAL_ID"));
            lot.put("recipeRrn", MapUtils.getLong(map, "RECIPE_LOGICAL_RRN"));

            lot.put("recipeParam", MapUtils.getString(map, "RECIPE_STRING"));
            lot.put("lotPlanType", MapUtils.getString(map, "LOT_PLAN_TYPE"));
            lots.add(lot);
        }
        return lots;

    }

    @Override
    public LotExt getLotExt(LotExt lotExt) {
        String sql = " select xt.lot_rrn,xt.temp_recipe_string,xt.attribute_data1,xt.attribute_data2 " + " ,xt" +
                ".attribute_data3,xt.attribute_data4,xt.attribute_data5 " +
                " ,xt.wifer_id,xt.wifer_type,xt.flow_level,xt" + ".customer_id,xt.customer_lot_id," +
                "xt.customer_wafer_id " + " ,xt.wafer_start_time,xt.inner_order_no,xt" +
                ".shipping_code,xt.is_out_source " +
                " ,xt.is_recreate_lot,xt.project_category from lot_ext xt where xt" + ".lot_rrn=? ";
        return (LotExt) jdbcTemplate
                .queryForObject(sql, new Object[]{new Long(lotExt.getLotRrn())}, new LotExtMapper());
    }

    @Override
    public List<Map<String, Object>> getProcessAllReworkStepInfoByLot(long lotRrn, Long productRrn, String flowSeq,
                                                                      long pageSize, int processVersion,
                                                                      Integer productVersion) {
        List args = new ArrayList();
        if (productRrn == null) {
            productRrn = 0L;
        }
        args.add(productRrn);
        args.add(productRrn);
        args.add(productVersion);
        args.add(productRrn);
        args.add(productRrn);
        args.add(lotRrn);

        StringBuilder sql = new StringBuilder("SELECT ");
        sql.append(
                "RECIPE_NO.INSTANCE_ID AS RECIPE_ID, RECIPE_NO.INSTANCE_DESC AS RECIPE_DECS, GETINSTANCEID" + "(TTT" +
                        ".PROCESS_RRN) AS PROCESS_ID, GETINSTANCEID(TTT.ROUTE_RRN) AS ROUTE_ID, ");
        sql.append(" PRO.ATTRIBUTE_DATA3 AS WORK_AREA, PRO.ATTRIBUTE_DATA4 AS OPERATION_TYPE, ");
        sql.append("TTT.* ");
        sql.append("FROM (SELECT GETCONTEXTSTAGEID(?, TT.PROCESS_RRN, TT.ROUTE_RRN, TT.OPERATION_RRN, TT" +
                           ".PROCESS_VERSION) AS STAGE_ID, ");
        sql.append("GETFLOWSEQ(TT.PROCESS_RRN, TT.ROUTE_RRN, TT.OPERATION_RRN, TT.PROCESS_VERSION) AS " + "FLOW_SEQ, ");
        sql.append(" GETINSTANCEID(O.ENTITY_GROUP_RRN) AS EQPT_GROUP_ID, O" +
                           ".ENTITY_GROUP_RRN AS ENTIT_GROUP_RRN, ");
        sql.append(
                "GETCONTEXTRECIPERRN(?, TT.PROCESS_RRN, TT.ROUTE_RRN, TT.OPERATION_RRN, TT.PROCESS_VERSION," + " ?)" +
                        " AS RECIPE_RRN, ");
        sql.append("GETFLOWSTEPDESC(?, TT.PROCESS_RRN, TT.ROUTE_RRN, TT.OPERATION_RRN, TT.PROCESS_VERSION) AS " +
                           "STEP_DESC, ");
        sql.append("GETCONTEXTPROCESSLOCATION(?, TT.PROCESS_RRN, TT.ROUTE_RRN, TT.OPERATION_RRN, TT" +
                           ".PROCESS_VERSION) AS PROCESS_LOCATION, O.RETICLE_REQUIRED, ");
        sql.append(" OPERATION_PARAM_T.OPERATION_PARAMETER_GROUP, O.PLANNED_CYCLE_TIME, STEP_NO.INSTANCE_ID AS OPERATION_ID, TT.* ");
        sql.append("FROM ( ");
        if (pageSize <= 0 || pageSize==MAX_PAGE_SIZE) {// 负数查询before,包括进入rework的主flow
            sql.append("SELECT START_REWORK_T.*, 'IN' AS FLAG, -1 AS SORT_SEQ ");
            sql.append("FROM (SELECT TO_NUMBER(REGEXP_SUBSTR(H.PROCESS_STEP_VERSION, '[^,]+', 1, 1)) AS " +
                               "PROCESS_RRN, ");
            sql.append(
                    "TO_NUMBER(REGEXP_SUBSTR(H.PROCESS_STEP_VERSION, '[^|]+', INSTR(H.PROCESS_STEP_VERSION," + " ','," +
                            " 1, 1) + 1, 1)) AS PROCESS_VERSION, ");
            sql.append(
                    "TO_NUMBER(REGEXP_SUBSTR(H.PROCESS_STEP_VERSION, '[^,]+', INSTR(H.PROCESS_STEP_VERSION," + " '|'," +
                            " 1, 1) + 1, 1)) AS ROUTE_RRN, ");
            sql.append(
                    "TO_NUMBER(REGEXP_SUBSTR(H.PROCESS_STEP_VERSION, '[^|]+', INSTR(H.PROCESS_STEP_VERSION," + " ','," +
                            " 1, 2) + 1, 1)) AS ROUTE_VERSION, ");
            sql.append(
                    "TO_NUMBER(REGEXP_SUBSTR(H.PROCESS_STEP_VERSION, '[^,]+', INSTR(H.PROCESS_STEP_VERSION," + " '|'," +
                            " 1, 2) + 1, 1)) AS OPERATION_RRN, ");
            sql.append(
                    "TO_NUMBER(REGEXP_SUBSTR(H.PROCESS_STEP_VERSION, '[^,]+', INSTR(H.PROCESS_STEP_VERSION," + " ','," +
                            " 1, 3) + 1)) AS OPERATION_VERSION ");
            sql.append(
                    "FROM REWORK_INFO_HISTORY H WHERE H.LOT_RRN = ? ORDER BY H.TRANS_RRN DESC, H" + ".STEP_SEQUENCE " +
                            "DESC) START_REWORK_T ");
            sql.append("WHERE ROWNUM = 1 ");
            sql.append("UNION ALL ");

            args.add(lotRrn);
        }
        sql.append(" SELECT T.PROCESS_RRN, T.PROCESS_VERSION, T.ROUTE_RRN, T.ROUTE_VERSION, T.OPERATION_RRN, T" +
                           ".OPERATION_VERSION, T.FLAG, T.SORT_SEQ FROM ( ");
        sql.append("SELECT T.PROCESS_RRN, T.PROCESS_VERSION, T.REWORK_ROUTE_RRN AS ROUTE_RRN, T" +
                           ".REWORK_ROUTE_VERSION AS ROUTE_VERSION, ");
        sql.append("T.REWORK_OPERATION_RRN AS OPERATION_RRN, T.REWORK_OPERATION_VERSION AS OPERATION_VERSION, " + "T" +
                           ".FLAG, ROWNUM AS SORT_SEQ, ");
        sql.append("GETFLOWSEQ(T.PROCESS_RRN, T.REWORK_ROUTE_RRN, T.REWORK_OPERATION_RRN, T.PROCESS_VERSION) " + "AS " +
                           "REWORK_FLOW_SEQ ");
        sql.append(
                "FROM (SELECT RT.PROCESS_RRN, RT.PROCESS_VERSION, RT.REWORK_ROUTE_RRN, RT" + ".REWORK_ROUTE_VERSION, ");
        sql.append("TO_NUMBER(SUBSTR(WFL_ROUTE_T.PARAMETER_VALUE_1, 7)) AS REWORK_OPERATION_RRN, 0 AS " +
                           "REWORK_OPERATION_VERSION, RT.FLAG ");
        sql.append("FROM WORKFLOW_TEMPLATE_DETAIL WFL_ROUTE_T, (SELECT WFL_REWORK_T.*, 'REWORK' AS FLAG FROM " +
                           "(SELECT H.PROCESS_RRN, H.PROCESS_VERSION, ");
        sql.append(
                "TO_NUMBER(REGEXP_SUBSTR(H.CURRENT_PROCESS_STEP_VERSION, '[^,]+', 1, 1)) AS " + "REWORK_ROUTE_RRN, ");
        sql.append("TO_NUMBER(REGEXP_SUBSTR(H.CURRENT_PROCESS_STEP_VERSION, '[^|]+', INSTR(H" +
                           ".CURRENT_PROCESS_STEP_VERSION, ',', 1, 1) + 1, 1)) AS REWORK_ROUTE_VERSION ");
        sql.append(
                "FROM REWORK_INFO_HISTORY H WHERE H.LOT_RRN = ? ORDER BY H.TRANS_RRN DESC, H.STEP_SEQUENCE " + "DESC)" +
                        " WFL_REWORK_T ");
        sql.append(
                "WHERE ROWNUM = 1 AND WFL_REWORK_T.PROCESS_VERSION = ?) RT WHERE WFL_ROUTE_T" + ".WFL_OR_TASK_RRN <> " +
                        "110 AND WFL_ROUTE_T.WFL_OR_TASK_RRN <> 120 ");
        args.add(processVersion);
        sql.append("AND WFL_ROUTE_T.WFL_VERSION = RT.REWORK_ROUTE_VERSION START WITH WFL_ROUTE_T.WFL_RRN = RT" +
                           ".REWORK_ROUTE_RRN ");
        sql.append("CONNECT BY WFL_ROUTE_T.WFL_RRN = PRIOR WFL_ROUTE_T.WFL_OR_TASK_RRN ORDER BY TO_NUMBER" + "(SUBSTR" +
                           "(WFL_ROUTE_T.PARAMETER_VALUE_4, 8)) ASC) T ");
        sql.append(") T WHERE 1=1 ");
        if (pageSize > 0 && pageSize != MAX_PAGE_SIZE) {
            sql.append("AND TO_NUMBER(T.REWORK_FLOW_SEQ) >= ?");
            args.add(Integer.parseInt(flowSeq));
        } else if (pageSize < 0){
            sql.append("AND TO_NUMBER(T.REWORK_FLOW_SEQ) <= ?");
            args.add(Integer.parseInt(flowSeq));
        }
        if (pageSize > 0 || pageSize==MAX_PAGE_SIZE) {// 正数查询after,包括return到的主flow
            sql.append("UNION ALL ");
            sql.append("SELECT REWORK_RETURN_T.* , 'RETURN' AS FLAG, 100000 AS SORT_SEQ ");
            sql.append("FROM (SELECT TO_NUMBER(REGEXP_SUBSTR(H.RETURN_PROCESS_STEP_VERSION, '[^,]+', 1, 1)) AS" + " " +
                               "PROCESS_RRN, ");
            sql.append("TO_NUMBER(REGEXP_SUBSTR(H.RETURN_PROCESS_STEP_VERSION, '[^|]+', INSTR(H" +
                               ".RETURN_PROCESS_STEP_VERSION, ',', 1, 1) + 1, 1)) AS PROCESS_VERSION, ");
            sql.append("TO_NUMBER(REGEXP_SUBSTR(H.RETURN_PROCESS_STEP_VERSION, '[^,]+', INSTR(H" +
                               ".RETURN_PROCESS_STEP_VERSION, '|', 1, 1) + 1, 1)) AS ROUTE_RRN, ");
            sql.append("TO_NUMBER(REGEXP_SUBSTR(H.RETURN_PROCESS_STEP_VERSION, '[^|]+', INSTR(H" +
                               ".RETURN_PROCESS_STEP_VERSION, ',', 1, 2) + 1, 1)) AS ROUTE_VERSION, ");
            sql.append("TO_NUMBER(REGEXP_SUBSTR(H.RETURN_PROCESS_STEP_VERSION, '[^,]+', INSTR(H" +
                               ".RETURN_PROCESS_STEP_VERSION, '|', 1, 2) + 1, 1)) AS OPERATION_RRN, ");
            sql.append("TO_NUMBER(REGEXP_SUBSTR(H.RETURN_PROCESS_STEP_VERSION, '[^,]+', INSTR(H" +
                               ".RETURN_PROCESS_STEP_VERSION, ',', 1, 3) + 1)) AS OPERATION_VERSION ");
            sql.append(
                    "FROM REWORK_INFO_HISTORY H WHERE H.LOT_RRN = ? ORDER BY H.TRANS_RRN DESC, H" + ".STEP_SEQUENCE " +
                            "DESC) REWORK_RETURN_T WHERE ROWNUM = 1 ");

            args.add(lotRrn);
        }
        sql.append(") TT, ");
        sql.append("OPERATION_EXT OE, OPERATION O, NAMED_OBJECT STEP_NO, ");
        sql.append("(SELECT LISTAGG(OP.PARAMETER_ID, ',') WITHIN GROUP (ORDER BY OP.OPERATION_RRN) AS " +
                           "OPERATION_PARAMETER_GROUP, OP.OPERATION_RRN ");
        sql.append("FROM OPERATION_PARAMETER_RELATION OP GROUP BY OP.OPERATION_RRN) OPERATION_PARAM_T ");
        sql.append("WHERE TT.OPERATION_RRN = OE.OPERATION_RRN AND TT.OPERATION_RRN = O.OPERATION_RRN AND TT" +
                           ".OPERATION_RRN = STEP_NO.INSTANCE_RRN ");
        sql.append("AND TT.OPERATION_RRN = OPERATION_PARAM_T.OPERATION_RRN(+)) TTT, NAMED_OBJECT RECIPE_NO ");
        sql.append(", PRO_CONTEXT_ACTIVE_DTL PRO WHERE TTT.RECIPE_RRN = RECIPE_NO.INSTANCE_RRN(+) ");
        sql.append(" AND TTT.PROCESS_RRN = PRO.PROCESS_RRN AND TTT.OPERATION_RRN = PRO.OPERATION_RRN ");
        sql.append(" AND TTT.ROUTE_RRN = PRO.ROUTE_RRN AND TTT.PROCESS_VERSION = PRO.PROCESS_VERSION ");
        sql.append(" AND PRO.PRODUCT_RRN = ? AND PRO.PRODUCT_VERSION =?");
        args.add(productRrn);
        args.add(productVersion);
        if (pageSize > 0) {
            sql.append("ORDER BY SORT_SEQ ASC ");
        } else {
            sql.append("ORDER BY SORT_SEQ DESC ");
        }

        return jdbcTemplate.query(sql.toString(), args.toArray(), new RowMapper<Map<String, Object>>() {

            @Override
            public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map<String, Object> map = new HashMap<String, Object>();
                map.put("stageId", rs.getString("STAGE_ID"));
                map.put("flowSeq", rs.getString("FLOW_SEQ"));
                map.put("workArea", rs.getString("WORK_AREA"));
                map.put("recipePhysicalId", rs.getString("RECIPE_ID"));
                map.put("entityGroupId", rs.getString("EQPT_GROUP_ID"));
                map.put("operationDesc", rs.getString("STEP_DESC"));
                map.put("processLocation", rs.getString("PROCESS_LOCATION"));
                map.put("operationType", rs.getString("OPERATION_TYPE"));
                map.put("parameterGroup", rs.getString("OPERATION_PARAMETER_GROUP"));
                map.put("recipeDesc", rs.getString("RECIPE_DECS"));
                map.put("plannedCycleTime", rs.getString("PLANNED_CYCLE_TIME"));
                map.put("operationRrn", rs.getString("OPERATION_RRN"));
                map.put("operationId", rs.getString("OPERATION_ID"));
                map.put("processRrn", rs.getString("PROCESS_RRN"));
                map.put("processId", rs.getString("PROCESS_ID"));
                map.put("processVersion", rs.getString("PROCESS_VERSION"));
                map.put("routeRrn", rs.getString("ROUTE_RRN"));
                map.put("routeId", rs.getString("ROUTE_ID"));
                map.put("routeVersion", rs.getString("ROUTE_VERSION"));
                map.put("operationVersion", rs.getString("OPERATION_VERSION"));
                map.put("isRework", rs.getString("FLAG")); // IN 表示进入rework的工步,REWORK 表示rework流程信息,RETURN
                // 表示rework结束后返回的目标工步
                map.put("entityGroupRrn", rs.getString("ENTIT_GROUP_RRN"));
                map.put("reticle_required", rs.getString("RETICLE_REQUIRED"));

                return map;
            }
        });
    }

    @Override
    public List<TimelimitStatus> getLotTimeLimitStatusForNormal() {
        String sql = "SELECT " + "tl.LOT_RRN, tl.TIMELIMIT_ID, tl.TIMELIMIT_TYPE, " + "tl.START_PRODUCT_RRN, tl" +
                ".START_PROCESS_RRN, tl.START_PROCESS_VERSION,tl" + ".START_PROCESS_VERSION, tl.START_ROUTE_RRN, tl" +
                ".START_OPERATION_RRN, " +
                "tl.END_PRODUCT_RRN, tl.END_PROCESS_RRN, tl.END_ROUTE_RRN, tl.END_OPERATION_RRN," + " " +
                "tl.TIMELIMIT, tl.START_TIME, tl.STATUS, tl.ADDITIONAL_TIMELIMIT, tl.TIMELIMIT_RRN, " + "tl" +
                ".TIME_TYPE, tl.LIMIT_TYPE, tl.MODULE, " +
                "tl.START_ROUTE_SEQ, tl.START_OPERATION_SEQ, tl.END_ROUTE_SEQ," + " tl.END_OPERATION_SEQ," +
                " tl.STEP_SEQUENCE " + "FROM " + DataBaseNames.TIMELIMIT_STATUS + " tl, " + DataBaseNames.LOT + " l " +
                "WHERE tl.LOT_RRN = l.LOT_RRN AND l.LOT_STATUS IN ('WAITING', 'HOLD') " +
                "AND tl.STATUS = 'NORMAL' ORDER BY tl.START_TIME ";

        return jdbcTemplate.query(sql, new TimeLimitStatusRowMapper());
    }

    @Override
    public List<String> getInstanceIdsInLotAndLotPlan(String field) {
        StringBuilder sql = new StringBuilder("SELECT DISTINCT INSTANCE_ID FROM (");

        sql.append(" SELECT DISTINCT ").append(field).append(" FROM ").append(DataBaseNames.LOT_PLAN);
        sql.append(" UNION ALL ");
        sql.append(" SELECT DISTINCT ").append(field).append(" FROM ").append(DataBaseNames.LOT).append(" ) l, ");
        sql.append(DataBaseNames.NAMEDOBJECT).append(" no ");
        sql.append(" WHERE l.").append(field).append(" = no.INSTANCE_RRN ");
        sql.append(" ORDER BY INSTANCE_ID ");

        return jdbcTemplate.query(sql.toString(), String.class);
    }

    @Override
    public List<String> getProductOrProcessByRelationInLotAndLotPlan(String targetfield, String likeField,
                                                                     String likeValue) {
        StringBuilder sql = new StringBuilder("SELECT ");

        sql.append(" DISTINCT ").append(targetfield);
        sql.append(" FROM (SELECT ");
        sql.append(" (SELECT INSTANCE_ID FROM ").append(DataBaseNames.NAMEDOBJECT)
           .append(" WHERE INSTANCE_RRN = lp.PRODUCT_RRN) AS PRODUCT_ID, ");
        sql.append(" (SELECT INSTANCE_ID FROM ").append(DataBaseNames.NAMEDOBJECT)
           .append(" WHERE INSTANCE_RRN = lp.PROCESS_RRN) AS PROCESS_ID ");
        sql.append(" FROM (");
        sql.append(" SELECT PRODUCT_RRN, PROCESS_RRN FROM ").append(DataBaseNames.LOT_PLAN);
        sql.append(" UNION ALL ");
        sql.append(" SELECT PRODUCT_RRN, PROCESS_RRN FROM ").append(DataBaseNames.LOT).append(" ) lp ) ");
        sql.append(" WHERE ").append(likeField).append(" like ? ");
        sql.append(" ORDER BY ").append(targetfield);

        return jdbcTemplate.query(sql.toString(), String.class, MiscUtils.parseToFuzzySQL(likeValue));
    }

    @Override
    public List<Map> getLotsByEquipment4Ext(long equipmentRrn, String operationStep, List<Map> operationMap) {
        List<Map> tempLots = new ArrayList();
        String sql = "";
        for (Map o : operationMap) {
            Long operationRrn = (Long) o.get("operationRrn");
            sql = buildFuture(operationStep, operationRrn);
            sql = getLotSql() + " " + sql;

            List<Map> data = jdbcTemplate.query(sql, new RowMapper<Map>() {

                @Override
                public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                    String processStepString = rs.getString("PROCESS_STEP_VERSION");
                    int firstSep = processStepString.indexOf("|");
                    int secondSep = processStepString.indexOf("|", firstSep + 1);
                    Map lot = new HashMap();
                    String routeRrn;
                    if (secondSep >= 0) {
                        routeRrn = processStepString.substring(firstSep + 1, processStepString.indexOf(",", firstSep));
                    } else {
                        routeRrn = processStepString.substring(0, processStepString.indexOf(","));
                    }
                    long futureStep = getFutureStep(rs.getLong("product_rrn"), rs.getLong("process_rrn"),
                                                    rs.getLong("process_version"), new Long(routeRrn),
                                                    rs.getLong("operation_rrn"), operationRrn);
                    String lot_status = rs.getString("LOT_STATUS");
                    long eqpt_rrn = rs.getLong("eqpt_rrn");
                    if ((lot_status.equalsIgnoreCase("DISPATCH") && eqpt_rrn != equipmentRrn)) {

                    } else if ((futureStep <= 0) || (futureStep > Long.parseLong(operationStep))) {

                    } else {
                        lot.put("lotRrn", rs.getString("LOT_RRN"));
                        lot.put("lotId", rs.getString("LOT_ID"));
                        lot.put("operationprrn", String.valueOf(operationRrn));
                        lot.put("futureStepSeq", futureStep);
                        lot.put("productrrn", rs.getString("product_rrn"));
                        lot.put("processrrn", rs.getString("process_rrn"));
                    }

                    return lot;
                }
            });
            tempLots.addAll(data);
        }
        return tempLots;
    }

    @Override
    public long getFutureStep(long productRrn, long processRrn, long processVersionId, Long routeRrn, long operationRrn,
                              long selectOperationRrn) {
        long futureStep = 999L;
        String sql = "SELECT step_seq FROM (select a.product_rrn, b.step_seq - a" + ".step_seq step_seq " + " from " +
                "(select t.product_rrn, t.step_seq from process_workflow_hist t " + " where t.process_rrn = ? and t" +
                ".operation_rrn = ?) a, " + " (select t.product_rrn, t.step_seq from process_workflow_hist t " +
                " where t" + ".process_rrn = ? and t.operation_rrn = ?) b " +
                " where a.product_rrn = b.product_rrn and (a" + ".product_rrn=-1 or a.product_rrn=?)" +
                " and b.step_seq - a.step_seq >= 0 order by a.product_rrn desc) " + "t1 WHERE ROWNUM = 1";

        List<Long> data = jdbcTemplate
                .query(sql, Long.class, processRrn, operationRrn, processRrn, selectOperationRrn, productRrn);

        if (CollectionUtils.isNotEmpty(data)) {
            futureStep = data.get(0);
        }

        return futureStep;
    }

    @Override
    public List<Map> queryFutureLotDetail4Extjs(long equipmentRrn, String operationStep, List<Map> operationMap) {
        List<Map> lots = new ArrayList<>();

        String sql = "";
        for (Map m : operationMap) {
            Long operationRrn = (Long) m.get("operationRrn");
            sql = buildFuture(operationStep, operationRrn);

            sql = "SELECT FACILITY_RRN,LOT_ID,BASED_LOT_RRN,CREATED_PLAN_LOT_RRN," + "HOT_FLAG, (SELECT max" +
                    "(DATA_1_VALUE) FROM REFERENCE_FILE_DETAIL a " + "WHERE  a.KEY_1_VALUE=LOT.PRIORITY and a" +
                    ".reference_file_rrn=" + "(SELECT b.instance_rrn FROM NAMED_OBJECT b" + " WHERE b" +
                    ".instance_id='$$LOT_PRIORITY')) as PRIORITY,STARTED_FLAG,STARTED_TIMESTAMP," + "CREATE_CATEGORY," +
                    "CREATED_TIMESTAMP,END_TIMESTAMP,DUE_DATE,SCHEDULE_DUE_DATE," + "LATE_SCHEDULED_FLAG," +
                    "ESTIMATED_REMAIN_TIME,DUMMY_FLAG,LOT_TYPE," +
                    "LOT_OWNER,QTY1,QTY2,DUMMY_QTY1,INPUT_QTY1,INPUT_QTY2," + "SUBCONTRACTOR_RRN," +
                    "LOT_COMMENTS,STEP_SEQUENCE,STEP_NUMBER_IN_PROCESS,HOLD_TIMESTAMP," +
                    "REWORK_TRANS_RRN,REWORK_CATEGORY,CARRIER_RRN,BEFORE_STATUS," + "LOT_STATUS,PROCESSING_STATUS, " +
                    "QUEUE_TIMESTAMP,PRODUCT_RRN," + "PROCESS_RRN,PROCESS_VERSION,PROCESS_STEP_VERSION," +
                    "PROCESS_STEP_ID_VERSION,OPERATION_RRN,OPERATION_VERSION," + "NEXT_STEP_VERSION1," +
                    "NEXT_STEP_ID_VERSION1,NEXT_OPERATION_RRN1," + "NEXT_STEP_VERSION2,NEXT_STEP_ID_VERSION2," +
                    "NEXT_OPERATION_RRN2," + "STAGE_ID,LAYER_ID,BOR_RRN,EQPT_RRN,RECIPE_STRING," +
                    "NEXT_RECIPE_STRING1,NEXT_RECIPE_STRING2,JOB_RRN," + "NEXT_JOB_RRN1,NEXT_JOB_RRN2,EXECUTION_RRN," +
                    "LOT_RRN,WFL_STEP_PATH,reticle_rrn," + "SHIPPED_QTY1,SHIPPED_QTY2,PRODUCT_LAYER,ROUTE_SEQ," +
                    "OPERATION_SEQ,RECIPE_LOGICAL_RRN," + "RECIPE_PHYSICAL_ID,CHAMBER_TYPE,IS_SAPPHIRE FROM " +
                    DataBaseNames.LOT + " " + sql;

            List<Map> data = jdbcTemplate.query(sql, new RowMapper<Map>() {

                @Override
                public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                    Map lot = new TreeMap();
                    String processStepString = rs.getString("PROCESS_STEP_VERSION");
                    int firstSep = processStepString.indexOf("|");
                    int secondSep = processStepString.indexOf("|", firstSep + 1);
                    String routeRrn;
                    String processStepIdString;
                    String routeId;
                    if (secondSep >= 0) {
                        routeRrn = processStepString.substring(firstSep + 1, processStepString.indexOf(",", firstSep));
                    } else {
                        routeRrn = processStepString.substring(0, processStepString.indexOf(","));
                    }
                    long futureStep = getFutureStep(rs.getLong("product_rrn"), rs.getLong("process_rrn"),
                                                    rs.getLong("process_version"), new Long(routeRrn),
                                                    rs.getLong("operation_rrn"), operationRrn);
                    String lot_status = rs.getString("LOT_STATUS");
                    long eqpt_rrn = rs.getLong("eqpt_rrn");
                    if ((lot_status.equalsIgnoreCase("DISPATCH") && eqpt_rrn != equipmentRrn)) {
                    } else if ((futureStep <= 0) || (futureStep > Long.parseLong(operationStep))) {
                    } else {
                        lot.put("lotRrn", rs.getString("LOT_RRN"));
                        lot.put("lotId", rs.getString("LOT_ID"));
                        lot.put("lotStatus", rs.getString("LOT_STATUS"));
                        lot.put("lotType", rs.getString("LOT_TYPE"));
                        lot.put("hotFlag", "1".equals(rs.getString("HOT_FLAG")) ? "Y" : "N");
                        lot.put("priority", rs.getString("PRIORITY"));
                        //                        lot.put("carrierId", getInstanceId(rs.getLong
                        //                        ("CARRIER_RRN")));
                        lot.put("carrierRrn", rs.getString("CARRIER_RRN"));
                        lot.put("qty1", rs.getString("QTY1"));
                        lot.put("qty2", rs.getString("QTY2"));
                        lot.put("dummyQty1", rs.getInt("dummy_qty1"));
                        lot.put("dummyFlag", rs.getString("DUMMY_FLAG"));
                        lot.put("equipmentRrn", rs.getString("EQPT_RRN"));
                        lot.put("operationRrn", rs.getString("OPERATION_RRN"));
                        lot.put("operationVersion", rs.getString("OPERATION_VERSION"));
                        //                        lot.put("operationId", getInstanceId(rs.getLong
                        //                        ("OPERATION_RRN")));
                        lot.put("reticleRrn", rs.getString("reticle_rrn"));
                        //                        lot.put("reticleId", getInstanceId(rs.getLong
                        //                        ("reticle_rrn")));
                        lot.put("productrrn", rs.getString("product_rrn"));
                        lot.put("processrrn", rs.getString("process_rrn"));
                        processStepString = rs.getString("PROCESS_STEP_VERSION");
                        firstSep = processStepString.indexOf("|");
                        secondSep = processStepString.indexOf("|", firstSep + 1);
                        if (secondSep >= 0) {
                            routeRrn = processStepString
                                    .substring(firstSep + 1, processStepString.indexOf(",", firstSep));
                        } else {
                            routeRrn = processStepString.substring(0, processStepString.indexOf(","));
                        }
                        // get route_id from processStepIdString
                        processStepIdString = rs.getString("PROCESS_STEP_ID_VERSION");
                        firstSep = processStepIdString.indexOf("|");
                        secondSep = processStepIdString.indexOf("|", firstSep + 1);
                        if (secondSep >= 0) {
                            routeId = processStepIdString
                                    .substring(firstSep + 1, processStepIdString.indexOf(",", firstSep));
                        } else {
                            routeId = processStepIdString.substring(0, processStepIdString.indexOf(","));
                        }
                        lot.put("routeRrn", routeRrn);
                        lot.put("routeId", routeId);
                        lot.put("recipeRrn", rs.getString("RECIPE_STRING"));

                        //                        lot.put("productId", getInstanceId(rs.getLong
                        //                        ("PRODUCT_RRN")));
                        lot.put("productRrn", rs.getLong("PRODUCT_RRN"));
                        lot.put("processRrn", rs.getLong("PROCESS_RRN"));
                        //                        lot.put("processId", getInstanceId(rs.getLong
                        //                        ("PROCESS_RRN")));
                        lot.put("facilityRrn", rs.getLong("FACILITY_RRN"));
                        long spent = DateUtils.getDistanceTime4Now(rs.getTimestamp("QUEUE_TIMESTAMP"));
                        lot.put("queueTimestamp", spent / 60);
                        lot.put("jobRrn", rs.getString("JOB_RRN"));
                        lot.put("createdTimestamp", (rs.getTimestamp("CREATED_TIMESTAMP") == null) ? 0 : rs
                                .getTimestamp("CREATED_TIMESTAMP").getTime());
                        lot.put("dueDate",
                                (rs.getTimestamp("DUE_DATE") == null) ? 0 : rs.getTimestamp("DUE_DATE").getTime());
                        lot.put("estimatedRemainTime", rs.getLong("ESTIMATED_REMAIN_TIME"));
                        lot.put("stageId", rs.getString("stage_id"));
                        lot.put("processVersion", rs.getInt("PROCESS_VERSION"));
                        //                        lot.put("operationDesc", this.getInstanceDesc(rs.getLong
                        //                        ("operation_rrn")));
                        HashMap tempInfo = new HashMap();
                        tempInfo.put("operationRrn", rs.getLong("operation_rrn"));
                        tempInfo.put("productRrn", rs.getLong("product_rrn"));
                        tempInfo.put("routeRrn", routeRrn);
                        tempInfo.put("processRrn", rs.getLong("process_rrn"));
                        tempInfo.put("recipeRrn", null);
                        tempInfo.put("lotRrn", rs.getLong("lot_rrn"));
                        tempInfo.put("equipmentModel", null);
                        tempInfo.put("lotId", rs.getString("lot_id"));
                        tempInfo.put("facilityRrn", rs.getLong("facility_rrn"));
                        tempInfo.put("productLayer", rs.getString("product_layer"));
                        tempInfo.put("routeSeq", rs.getString("route_seq"));
                        tempInfo.put("operationSeq", rs.getString("operation_seq"));
                        tempInfo.put("processVersion", rs.getString("PROCESS_VERSION"));
                        long eqptRrn = rs.getLong("eqpt_rrn");
                        if (eqptRrn > 0) {
                            tempInfo.put("entityRrn", rs.getLong("eqpt_rrn"));
                        } else {
                            tempInfo.put("entityRrn", null);
                        }
                        lot.put("tempInfo", tempInfo);

                        //                        String recipeString = getRecipeString(tempInfo);
                        //                        String recipeId     = parseRecipeId(recipeString);
                        //                        lot.put("recipeId", recipeId);
                        //                        lot.put("recipeParam", this.parseRecipeParam(recipeString));
                        lot.put("futureStepSeq", new Long(futureStep));
                        lot.put("operationprrn", String.valueOf(operationRrn));
                        //                        lots.add(lot);
                    }
                    return lot;
                }
            });

            lots.addAll(data);
        }


        return lots;
    }

    @Override
    public List<String> getFieldValueInLotAndLotPlan(String field) {
        StringBuilder sql = new StringBuilder("SELECT ");

        sql.append(" DISTINCT ").append(field);
        sql.append(" FROM (");
        sql.append(" SELECT LOT_OWNER, OUTERORDERNO, OUT_ORDER_TYPE, SHIPPINGCODE, CUSTOMER_ID ");
        sql.append(" FROM ").append(DataBaseNames.LOT_PLAN);
        sql.append(" UNION ALL ");
        sql.append(" SELECT l.LOT_OWNER, le.OUTER_ORDER_NO AS OUTERORDERNO, le.OUT_ORDER_TYPE, ");
        sql.append(" le.SHIPPING_CODE AS SHIPPINGCODE, le.CUSTOMER_ID ");
        sql.append(" FROM ").append(DataBaseNames.LOT).append(" l left join ").append(DataBaseNames.LOT_EXT)
           .append(" le ");
        sql.append(" on l.LOT_RRN = le.LOT_RRN ) lot_plan ");
        sql.append(" WHERE ").append(field).append(" IS NOT NULL ");
        sql.append(" ORDER BY ").append(field);

        return jdbcTemplate.query(sql.toString(), String.class);
    }

    @Override
    public List<String[]> getPriorityInLotAndLotPlan() {
        StringBuilder sql = new StringBuilder(" SELECT DISTINCT HOT_FLAG, PRIORITY FROM (");

        sql.append(" SELECT HOT_FLAG, PRIORITY FROM ").append(DataBaseNames.LOT_PLAN);
        sql.append(" UNION ALL ");
        sql.append(" SELECT HOT_FLAG, PRIORITY FROM ").append(DataBaseNames.LOT).append(" ) hot_flag ");
        sql.append(" ORDER BY HOT_FLAG, PRIORITY ");

        return jdbcTemplate.query(sql.toString(), new RowMapper<String[]>() {

            @Override
            public String[] mapRow(ResultSet rs, int rowNum) throws SQLException {
                String[] strings = new String[2];

                strings[0] = rs.getString("HOT_FLAG");
                strings[1] = StringUtils.isEmpty(rs.getString("PRIORITY")) ? "0" : "1";

                return strings;
            }
        });
    }

    @Override
    public long getParentLotRrn(long lotRrn) {
        String sql = "select based_lot_rrn from lot where lot_rrn = ?";
        return jdbcTemplate.queryForObject(sql, new Object[]{lotRrn}, long.class);
    }

    @Override
    public List<LotProcessInfo> getLotProcessInfo(long lotRrn, String stepType) {
        String sql = "SELECT LOT_RRN,STEP_SEQUENCE,STEP_TYPE,FLOW_SEQ,WAFER_ROUTE,MOVE_IN_TIME," + "MOVE_IN_USER," +
                "MOVE_OUT_TIME,MOVE_OUT_USER,CREATED_TIME,UPDATED_TIME";
        sql += " FROM LOT_PROCESS_INFO";
        sql += " WHERE STEP_SEQUENCE IN (SELECT MAX(STEP_SEQUENCE) FROM LOT_PROCESS_INFO" + " WHERE LOT_RRN = ? AND " +
                "STEP_TYPE = ? GROUP BY FLOW_SEQ)" + " AND LOT_RRN=? AND STEP_TYPE = ?";
        sql += " ORDER BY STEP_SEQUENCE DESC";
        Object[] args = new Object[]{lotRrn, stepType, lotRrn, stepType};
        return jdbcTemplate.query(sql, args, new RowMapper<LotProcessInfo>() {
            @Override
            public LotProcessInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
                LotProcessInfo lotProcessInfo = new LotProcessInfo();
                lotProcessInfo.setLotRrn(rs.getLong("LOT_RRN"));
                lotProcessInfo.setStepSequence(rs.getLong("STEP_SEQUENCE"));
                lotProcessInfo.setStepType(rs.getString("STEP_TYPE"));
                lotProcessInfo.setFlowSeq(rs.getString("FLOW_SEQ"));
                lotProcessInfo.setWaferRoute(rs.getString("WAFER_ROUTE"));
                lotProcessInfo.setMoveInTime(rs.getDate("MOVE_IN_TIME"));
                lotProcessInfo.setMoveInUser(rs.getString("MOVE_IN_USER"));
                lotProcessInfo.setMoveOutTime(rs.getDate("MOVE_OUT_TIME"));
                lotProcessInfo.setMoveOutUser(rs.getString("MOVE_OUT_USER"));
                lotProcessInfo.setCreatedTime(rs.getDate("CREATED_TIME"));
                lotProcessInfo.setUpdatedTime(rs.getDate("UPDATED_TIME"));

                return lotProcessInfo;
            }
        });
    }

    @Override
    public String getMaxLotIdByProductType(String productType) {
        String temp = "";
        String sql = " SELECT NVL(substr(MAX(MAX_LOT_ID),4),'0') AS MAX_LOT_ID \n" + "FROM ((SELECT MAX(L.LOT_ID) AS " +
                "MAX_LOT_ID FROM LOT L\n" + "WHERE L.LOT_RRN = L.BASED_LOT_RRN AND L.LOT_ID like '" + productType +
                "%' AND " + "LOT_ID NOT LIKE '%_DEL') UNION (SELECT MAX(LP.LOT_ID) AS MAX_LOT_ID\n" +
                " FROM LOT_PLAN LP WHERE LP" + ".LOT_RRN = LP.BASED_LOT_RRN AND LP.LOT_ID like '" + productType +
                "%')UNION(SELECT MAX(SUBSTR(LOT_ID, 0," + "INSTR (LOT_ID, '_') - 1  )) AS MAX_LOT_ID FROM" +
                " LOT L WHERE " + "  L.LOT_RRN = L.BASED_LOT_RRN AND L" + ".LOT_ID LIKE '" + productType +
                "%' AND LOT_ID LIKE '%_DEL'))";

        temp = jdbcTemplate.queryForObjectWithNull(sql, new Object[]{}, String.class);
        return temp;
    }

    @Override
    public List<Map> getLotsList(Map actionMap) {
        List obj = new ArrayList<>();
        StringBuffer where = new StringBuffer(" WHERE ");
        where.append(" L.PROCESS_RRN = PRO.PROCESS_RRN  AND L.product_rrn = PRO.product_rrn  ");
        where.append(" AND L.PROCESS_VERSION = PRO.PROCESS_VERSION AND L.product_version = PRO.product_version");
        where.append(" AND L.operation_rrn = PRO.operation_rrn ");
        where.append(" AND PRO.ROUTE_RRN = TO_NUMBER ( REGEXP_SUBSTR ( L.process_step_version, '[^,]+', INSTR( L.process_step_version, '|', 1, 1 ) + 1, 1 ) ) ");

        if (MapUtils.getLong(actionMap, "productRrn") != null) {
            where.append(" AND L.product_rrn = ? ");
            obj.add(MapUtils.getLong(actionMap, "productRrn"));
        }

        if (MapUtils.getLong(actionMap, "processRrn") != null) {
            where.append(" AND L.process_rrn = ? ");
            obj.add(MapUtils.getLong(actionMap, "processRrn"));
        }

        if (MapUtils.getLong(actionMap, "routeRrn") != null) {
            where.append(" AND L.process_step_version like ? ");
            String routeRrn = "%"+MapUtils.getLong(actionMap, "routeRrn")+"%";
            obj.add(routeRrn);
        }

        if (MapUtils.getLong(actionMap, "operationRrn") != null) {
            where.append(" AND L.operation_rrn = ? ");
            obj.add(MapUtils.getLong(actionMap, "operationRrn"));
        }

        StringBuffer _where = new StringBuffer(" WHERE 1=1 ");
        if (MapUtils.getString(actionMap, "equipmentId") != null) {
            _where.append(" AND equipment_id = ? ");
            obj.add(MapUtils.getString(actionMap, "equipmentId"));
        }

        if (MapUtils.getString(actionMap, "dueDateS") != null) {
            _where.append(" AND equipment_run_time >= to_timestamp(?,'"+ DateUtils.DATE_FORMAT24 + "')");
            obj.add(MapUtils.getString(actionMap, "dueDateS"));
        }

        if (MapUtils.getString(actionMap, "dueDateE") != null) {
            _where.append(" AND equipment_run_time <= to_timestamp(?,'"+ DateUtils.DATE_FORMAT24 + "')");
            obj.add(MapUtils.getString(actionMap, "dueDateE"));
        }

        String sql = " select * from(select a.*,ROW_NUMBER() over(partition by lot_rrn order by equipment_run_time desc) as new_index  " +
                " from (select lots.*,eqpt.equipment_id,eqpt.equipment_run_time from (select L.lot_rrn,L.lot_id,L.lot_owner,L.qty1,L.qty2, " +
                " L.lot_status,L.stage_id,L.product_rrn,L.process_rrn,L.PROCESS_VERSION,L.process_step_version,L.process_step_id_version, " +
                " PRO.ROUTE_RRN, PRO.OPERATION_DESCRIPTION, PRO.RECIPE_ID, PRO.PROCESS_ID, PRO.PRODUCT_ID, PRO.OPERATION_ID,PRO.FLOW_SEQ, "+
                " L.operation_rrn,L.facility_rrn,L.eqpt_rrn,L.product_layer,L.route_seq,L.operation_seq from "+DataBaseNames.LOT+" L " +
                " ,PRO_CONTEXT_ACTIVE_DTL PRO  "+
                where.toString() + " AND l.lot_status = '"+LotStatus.WAITING+"' order by lot_id) lots " +
                " left join "+DataBaseNames.EQUIPMENT_RUN_HISTORY+" eqpt on lots.lot_id = eqpt.lot_id " +
                _where.toString() + " ) a ) b where b.new_index = 1 ";

        return jdbcTemplate.query(sql,obj.toArray(), new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map m = new HashMap();
                m.put("seq", new Integer(rowNum));
                m.put("lotRrn", new Long(rs.getLong("lot_rrn")));
                m.put("lotId", rs.getString("lot_id"));
                m.put("lotOwner", rs.getString("lot_owner"));
                m.put("qty1", new Double(rs.getDouble("qty1")));
                m.put("qty2", new Double(rs.getDouble("qty2")));
                m.put("lotStatus", rs.getString("lot_status"));
                String processStepIdString = rs.getString("process_step_id_version");
                int firstSep = processStepIdString.indexOf("|");
                int secondSep = processStepIdString.indexOf("|", firstSep + 1);
                String routeId = "";
                if (secondSep >= 0) {
                    routeId = processStepIdString.substring(firstSep + 1, processStepIdString.indexOf(",", firstSep));
                } else {
                    routeId = processStepIdString.substring(0, processStepIdString.indexOf(","));
                }
                m.put("processStepIdVersion", processStepIdString);
                m.put("routeId", routeId);
                m.put("operationRrn", rs.getLong("operation_rrn"));
                m.put("stageId", rs.getString("stage_id"));
                m.put("productRrn", rs.getLong("product_rrn"));
                m.put("processStepVersion", rs.getString("process_step_version"));
                m.put("processRrn", new Long(rs.getLong("process_rrn")));
                m.put("recipeRrn", null);
                m.put("lotRrn", new Long(rs.getLong("lot_rrn")));

                m.put("equipmentModel", null);
                m.put("lotId", rs.getString("lot_id"));
                m.put("facilityRrn", new Long(rs.getLong("facility_rrn")));
                m.put("productLayer", rs.getString("product_layer"));
                m.put("routeSeq", rs.getString("route_seq"));
                m.put("operationSeq", rs.getString("operation_seq"));
                m.put("processVersion", rs.getInt("PROCESS_VERSION"));
                m.put("entityRrn", rs.getLong("eqpt_rrn"));

                m.put("equipmentId",rs.getString("equipment_id"));
                m.put("equipmentRunTime",rs.getString("equipment_run_time"));
                m.put("routeRrn", rs.getString("ROUTE_RRN"));
                String operationDescription = rs.getString("OPERATION_DESCRIPTION");
                m.put("operationDesc", StringUtils.isNotBlank(operationDescription) ? operationDescription:StringUtils.EMPTY);
                m.put("recipeId", rs.getString("RECIPE_ID"));
                m.put("processId", rs.getString("PROCESS_ID"));
                m.put("productId", rs.getString("PRODUCT_ID"));
                m.put("operationId", rs.getString("OPERATION_ID"));
                m.put("flowSeq", rs.getString("FLOW_SEQ"));
                return m;
            }
        });
    }

    @Override
    public Map getLotTransInfo(String lotrrn) {
        String sql = "select trans_rrn,TRANS_SEQUENCE,TRANS_ID,LOT_RRN,QTY1,STEP_SEQUENCE from " + "(select " +
                "trans_rrn,TRANS_SEQUENCE,TRANS_ID,LOT_RRN,QTY1,STEP_SEQUENCE  " +
                "from lot_trans_history where lot_rrn=" + lotrrn +
                " order by trans_rrn desc, trans_sequence desc ) where rownum<=1";
        return jdbcTemplate.queryForObject(sql, new Object[]{}, Map.class);
    }

    @Override
    public long getBatchRrn() {
        String sql = "SELECT OBJECT_SEQ.NEXTVAL FROM DUAL";
        return jdbcTemplate.queryForObjectWithNull(sql, Long.class);
    }

    @Override
    public List<Map> getLotPriorityList(long productRrn) {
        StringBuffer sql = new StringBuffer(" SELECT ");
        sql.append(" L.LOT_RRN,L.LOT_ID,L.LOT_OWNER,L.CREATE_CATEGORY,L.LOT_TYPE,L.DUE_DATE,L.HOT_FLAG,L.PRIORITY,L.QTY1, ");
        sql.append(" L.QTY2,L.LOT_STATUS,L.STAGE_ID,L.PRODUCT_RRN,L.PROCESS_RRN,L.PROCESS_VERSION,L.PROCESS_STEP_VERSION, ");
        sql.append(" L.PROCESS_STEP_ID_VERSION,L.OPERATION_RRN,L.FACILITY_RRN,L.EQPT_RRN,L.PRODUCT_LAYER,L.route_seq, ");
        sql.append(" L.operation_seq, PRO.PROCESS_ID, PRO.PRODUCT_ID, PRO.OPERATION_ID,PRO.FLOW_SEQ, ");
        sql.append(" PRO.ROUTE_RRN, PRO.RECIPE_ID, PRO.OPERATION_DESCRIPTION FROM LOT L,PRO_CONTEXT_ACTIVE_DTL PRO WHERE");
        sql.append(" L.PROCESS_RRN = PRO.PROCESS_RRN AND L.product_rrn = PRO.product_rrn AND L.PROCESS_VERSION = PRO.PROCESS_VERSION ");
        sql.append(" AND L.product_version = PRO.product_version  AND L.operation_rrn = PRO.operation_rrn ");
        sql.append(" AND PRO.ROUTE_RRN = TO_NUMBER ( REGEXP_SUBSTR ( L.process_step_version, '[^,]+', INSTR( L.process_step_version, '|', 1, 1 ) + 1, 1 ) ) ");
        sql.append(" AND L.PRODUCT_RRN = ? AND LOT_STATUS NOT IN ('FINISH', 'SCRAPPED', 'TERMINATED')");
        sql.append(" ORDER BY PRIORITY,LOT_STATUS ");
        List args = new ArrayList();
        args.add(productRrn);
        return jdbcTemplate.query(sql.toString(), args.toArray(), new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map m = new HashMap();
                m.put("seq", new Integer(rowNum + 1));
                m.put("lotRrn", rs.getLong("lot_rrn"));
                m.put("lotId", rs.getString("lot_id"));
                m.put("lotOwner", rs.getString("lot_owner"));
                m.put("qty1", rs.getDouble("qty1"));
                m.put("qty2", rs.getDouble("qty2"));
                m.put("lotStatus", rs.getString("lot_status"));
                m.put("hotFlag", rs.getString("HOT_FLAG"));
                m.put("priority", new Integer(rs.getInt("PRIORITY")));

                m.put("processVer", rs.getString("process_version"));
                String processStepIdString = rs.getString("process_step_id_version");
                int firstSep = processStepIdString.indexOf("|");
                int secondSep = processStepIdString.indexOf("|", firstSep + 1);
                String routeId = "";
                if (secondSep >= 0) {
                    routeId = processStepIdString.substring(firstSep + 1, processStepIdString.indexOf(",", firstSep));
                } else {
                    routeId = processStepIdString.substring(0, processStepIdString.indexOf(","));
                }
                m.put("processStepIdVersion", processStepIdString);
                m.put("routeId", routeId);
                m.put("stageId", rs.getString("stage_id"));
                m.put("dueDate", rs.getString("due_date"));

                m.put("createCategory", rs.getString("create_category"));
                m.put("lotType", rs.getString("lot_type"));
                m.put("operationRrn", rs.getLong("operation_rrn"));
                m.put("productRrn", rs.getLong("product_rrn"));
                m.put("productLayer", rs.getString("product_layer"));
                m.put("processStepVersion", rs.getString("process_step_version"));

                m.put("processRrn", rs.getLong("process_rrn"));
                m.put("lotRrn", rs.getLong("lot_rrn"));

                m.put("lotId", rs.getString("lot_id"));
                m.put("facilityRrn", rs.getLong("facility_rrn"));
                m.put("routeSeq", rs.getString("route_seq"));
                m.put("operationSeq", rs.getString("operation_seq"));
                m.put("processVersion", rs.getInt("PROCESS_VERSION"));
                m.put("entityRrn", rs.getLong("eqpt_rrn"));
                m.put("recipeId", rs.getString("recipe_id"));
                String operationDesc = rs.getString("OPERATION_DESCRIPTION");
                m.put("operationDesc", StringUtils.isNotBlank(operationDesc) ? operationDesc:StringUtils.EMPTY);
                m.put("routeRrn", rs.getString("ROUTE_RRN"));
                m.put("processId", rs.getString("process_id"));
                m.put("productId", rs.getString("product_id"));
                m.put("operationId", rs.getString("operation_id"));
                m.put("flowSeq", rs.getString("FLOW_SEQ"));
                return m;
            }
        });
    }

    @Override
    public List<Map> getHoldLotsList(Map actionMap) {
        List args = new ArrayList();
        StringBuilder sql = new StringBuilder(" SELECT ");
        sql.append(" l.lot_rrn, l.lot_id, l.lot_owner, l.qty1, l.qty2, l.lot_status, l.stage_id, ");
        sql.append(" l.product_rrn, l.process_rrn, l.PROCESS_VERSION, l.PRODUCT_VERSION, l.process_step_version, ");
        sql.append(" l.process_step_id_version, l.operation_rrn, l.facility_rrn, l.eqpt_rrn, ");
        sql.append(" l.product_layer, l.route_seq, l.operation_seq, t.BATCH_ID, pro.RECIPE_ID,pro.flow_seq, ");
        sql.append(" pro.OPERATION_ID, pro.PROCESS_ID, pro.PRODUCT_ID, pro.ROUTE_RRN, pro.OPERATION_DESCRIPTION ");
        sql.append(" FROM lot l, batch_hold_release_ext t, PRO_CONTEXT_ACTIVE_DTL PRO WHERE L.PROCESS_RRN = PRO.PROCESS_RRN");
        sql.append(" AND L.product_rrn = PRO.product_rrn AND L.PROCESS_VERSION = PRO.PROCESS_VERSION  ");
        sql.append(" AND L.product_version = PRO.product_version  AND L.operation_rrn = PRO.operation_rrn ");
        sql.append(" AND PRO.ROUTE_RRN = TO_NUMBER ( REGEXP_SUBSTR ( L.process_step_version, '[^,]+', INSTR( L.process_step_version, '|', 1,1) + 1,1)) ");
        sql.append(" AND l.lot_status = 'HOLD'  AND l.lot_id = t.lot_id  AND t.attribute_data1 = '0' ");

        if (MapUtils.getLong(actionMap, "productRrn") != null) {
            sql.append(" AND l.product_rrn = ?");
            args.add(MapUtils.getLong(actionMap, "productRrn"));
        }

        if (MapUtils.getLong(actionMap, "processRrn") != null) {
            sql.append(" AND l.process_rrn = ?");
            args.add(MapUtils.getLong(actionMap, "processRrn"));
        }

        if (MapUtils.getLong(actionMap, "routeRrn") != null) {
            sql.append(" AND PRO.ROUTE_RRN = ?");
            args.add(MapUtils.getLong(actionMap, "routeRrn"));
        }

        if (MapUtils.getLong(actionMap, "operationRrn") != null) {
            sql.append(" AND l.operation_rrn = ?");
            args.add(MapUtils.getLong(actionMap, "operationRrn"));
        }

        return jdbcTemplate.query(sql.toString(), args.toArray(), new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map m = new HashMap();
                m.put("seq", new Integer(rowNum + 1));
                m.put("lotRrn", rs.getLong("lot_rrn"));
                m.put("lotId", rs.getString("lot_id"));
                m.put("lotOwner", rs.getString("lot_owner"));
                m.put("qty1", rs.getDouble("qty1"));
                m.put("qty2", rs.getDouble("qty2"));
                m.put("lotStatus", rs.getString("lot_status"));
                m.put("processVer", rs.getString("process_version"));
                String processStepIdString = rs.getString("process_step_id_version");
                int firstSep = processStepIdString.indexOf("|");
                int secondSep = processStepIdString.indexOf("|", firstSep + 1);
                String routeId = "";
                if (secondSep >= 0) {
                    routeId = processStepIdString.substring(firstSep + 1, processStepIdString.indexOf(",", firstSep));
                } else {
                    routeId = processStepIdString.substring(0, processStepIdString.indexOf(","));
                }
                m.put("processStepIdVersion", processStepIdString);
                m.put("routeId", routeId);
                m.put("stageId", rs.getString("stage_id"));

                m.put("operationRrn", rs.getLong("operation_rrn"));
                m.put("productRrn", rs.getLong("product_rrn"));
                m.put("productLayer", rs.getString("product_layer"));
                m.put("processStepVersion", rs.getString("process_step_version"));

                m.put("processRrn", rs.getLong("process_rrn"));
                m.put("lotRrn", rs.getLong("lot_rrn"));

                m.put("lotId", rs.getString("lot_id"));
                m.put("facilityRrn", rs.getLong("facility_rrn"));
                m.put("routeSeq", rs.getString("route_seq"));
                m.put("operationSeq", rs.getString("operation_seq"));
                m.put("processVersion", rs.getInt("PROCESS_VERSION"));
                m.put("entityRrn", rs.getLong("eqpt_rrn"));
                m.put("recipeId", rs.getString("RECIPE_ID"));
                String operationDescription = rs.getString("OPERATION_DESCRIPTION");
                m.put("operationDesc", StringUtils.isNotBlank(operationDescription) ? operationDescription:StringUtils.EMPTY);
                m.put("routeRrn", rs.getLong("ROUTE_RRN"));
                m.put("processId", rs.getString("PROCESS_ID"));
                m.put("productId", rs.getString("PRODUCT_ID"));
                m.put("operationId", rs.getString("OPERATION_ID"));
                m.put("batchId", rs.getString("BATCH_ID"));
                m.put("flowSeq", rs.getString("flow_seq"));
                return m;
            }
        });
    }

    @Override
    public String getBatchId(String lotId) {
        String sql = "SELECT L.BATCH_ID FROM BATCH_HOLD_RELEASE_EXT L WHERE L.LOT_ID = ? AND L" + ".ATTRIBUTE_DATA1 =" +
                " ? and rownum = 1";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{lotId, "0"}, String.class);
    }

    @Override
    public String getBatchId(Long lotRrn) {
        String sql = "select t.batch_id from batch_lot_store t where t.lot_rrn = ?";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{lotRrn}, String.class);
    }

    @Override
    public List<NpwBank> getNPWBankLot(Map<String, String> queryInfo) {

        String lotId = MapUtils.getString(queryInfo, "lotId");
        String carrierId = MapUtils.getString(queryInfo, "carrierId");
        String startDate = MapUtils.getString(queryInfo, "startDate");
        String endDate = MapUtils.getString(queryInfo, "endDate");
        List args = new ArrayList();

        StringBuilder sb = new StringBuilder(" SELECT ");
        sb.append(" LOT_RRN, A.LOT_ID, EQUIPMENT_RRN, EQUIPMENT_ID, STATUS, A.CREATED_TIMESTAMP, A" +
                          ".CREATED_USER_RRN,");
        sb.append(" LOT_TYPE_IN_BANK, SUB_STATUS, CARRIER_RRN, CARRIER_ID, COMMENTS,");
        sb.append(" BANK_IN_OPERATION_ID, BANK_IN_OPERATION_RRN, INSTANCE_ID || ' ' || USER_NAME AS " +
                          "CREATED_USER_NAME, D.SOURCELOT ");
        sb.append(" FROM NAMED_OBJECT B, USER_PROFILE C, NPW_BANK A left join ");
        sb.append(" (SELECT LISTAGG (SOURCE_LOT_ID,',') WITHIN GROUP (ORDER BY SOURCE_LOT_ID) AS SOURCELOT, " +
                          "TARGET_LOT_ID AS LOT_ID FROM LOT_BUILD_HISTORY GROUP BY TARGET_LOT_ID) D " +
                          "on A.LOT_ID = D.LOT_ID");
        sb.append(" WHERE A.CREATED_USER_RRN = INSTANCE_RRN AND INSTANCE_RRN = " + "USER_RRN AND A.SUB_STATUS " +
                          "!='TERMINATED'");
        if (StringUtils.isNotEmpty(lotId)) {
            sb.append(" AND A.LOT_ID = ?");
            args.add(lotId);
        }
        if (StringUtils.isNotEmpty(carrierId)) {
            sb.append(" AND CARRIER_ID = ? ");
            args.add(carrierId);
        }
        if (StringUtils.isNotEmpty(startDate)) {
            sb.append(" AND A.CREATED_TIMESTAMP > TO_DATE (?,'dd/MM/yyyy')");
            args.add(startDate);
        }
        if (StringUtils.isNotEmpty(endDate)) {
            sb.append(" AND A.CREATED_TIMESTAMP <= TO_DATE (?,'dd/MM/yyyy')");
            args.add(endDate);
        }
        sb.append(" ORDER BY A.LOT_ID DESC");

        return jdbcTemplate.query(sb.toString(), args.toArray(), new RowMapper<NpwBank>() {

            @Override
            public NpwBank mapRow(ResultSet rs, int rowNum) throws SQLException {
                NpwBank bankLot = new NpwBank();
                bankLot.setLotRrn(rs.getLong("lot_rrn"));
                bankLot.setLotId(rs.getString("lot_id"));
                bankLot.setEquipmentRrn(rs.getLong("equipment_rrn"));
                bankLot.setEquipmentId(rs.getString("equipment_id"));
                bankLot.setStatus(rs.getString("status"));
                bankLot.setCreatedDate(rs.getTimestamp("created_timestamp"));
                bankLot.setCreatedUserRrn(rs.getLong("created_user_rrn"));
                bankLot.setCreatedUserName(rs.getString("created_user_name"));
                bankLot.setLotTypeInBank(rs.getString("lot_type_in_bank"));
                bankLot.setSubStatus(rs.getString("sub_status"));
                bankLot.setCarrierRrn(rs.getLong("carrier_rrn"));
                bankLot.setCarrierId(rs.getString("carrier_id"));
                bankLot.setComments(rs.getString("comments"));
                bankLot.setBankInOperationId(rs.getString("bank_in_operation_id"));
                bankLot.setBankInOperationRrn(rs.getLong("bank_in_operation_rrn"));
                bankLot.setSourceLotId(rs.getString("sourcelot"));

                return bankLot;
            }

        });


    }

    @Override
    public Map getMaxLotIdByLotType(String lotType) {
        String sql = "SELECT NVL(SUBSTR(MAX_LOT_ID,length(MAX_LOT_ID)-2,3), '0') AS MAX_SUFFIX, MAX_LOT_ID \n" +
                "FROM (SELECT MAX(MAX_LOT_ID) AS MAX_LOT_ID \n" +
                "FROM ((SELECT MAX(L.LOT_ID) AS MAX_LOT_ID FROM LOT L\n" +
                "WHERE L.LOT_RRN = L.BASED_LOT_RRN AND L.LOT_ID like '" + lotType +
                "%' AND LOT_ID NOT LIKE '%_DEL') UNION " + "(SELECT MAX(LP.LOT_ID) AS MAX_LOT_ID\n" +
                " FROM LOT_PLAN LP WHERE LP.LOT_RRN = LP.BASED_LOT_RRN AND LP" + ".LOT_ID like '" + lotType +
                "%')UNION(SELECT MAX(SUBSTR(LOT_ID, 0,INSTR (LOT_ID, '_') - 1  )) AS " + "MAX_LOT_ID FROM" +
                " LOT L WHERE " + "  L.LOT_RRN = L.BASED_LOT_RRN AND L.LOT_ID LIKE '" + lotType + "%' " +
                "AND LOT_ID LIKE '%_DEL')))";

        Map map = jdbcTemplate.queryForObjectWithNull(sql, new Object[]{}, Map.class);
        return map;
    }

    @Override
    public Map getMaxLotIdByLotType4NPW(String lotType) {
        String sql = "SELECT NVL(SUBSTR(MAX_LOT_ID,length(MAX_LOT_ID)-2,3), '0') AS \"MAX_SUFFIX\", " + "MAX_LOT_ID " +
                "AS \"MAX_LOT_ID\" FROM (SELECT MAX(MAX_LOT_ID) AS MAX_LOT_ID  " + "FROM ((SELECT MAX(L.LOT_ID) AS " +
                "MAX_LOT_ID  FROM LOT L " + "WHERE L.LOT_RRN = L.BASED_LOT_RRN AND L.LOT_ID like '" + lotType +
                "%' AND " + "LOT_ID NOT LIKE '%_DEL') UNION (SELECT MAX(LP.LOT_ID) AS  MAX_LOT_ID  " +
                " FROM LOT_PLAN LP WHERE LP" + ".LOT_RRN = LP.BASED_LOT_RRN AND LP.LOT_ID like '" + lotType +
                "%')UNION(SELECT MAX(SUBSTR(LOT_ID, 0," + "instr (LOT_ID,'_'  ) - 1  )) AS " +
                "MAX_LOT_ID FROM LOT L WHERE " + "  L.LOT_RRN = L.BASED_LOT_RRN AND" + " L.LOT_ID LIKE '" + lotType +
                "%' AND LOT_ID LIKE '%_DEL')) maxlotid ) result ";

        Map map = jdbcTemplate.queryForObjectWithNull(sql, new Object[]{}, Map.class);
        return map;
    }

    @Override
    public boolean generateLotIdIsExisted(String generateLotId) {
        String sql = "SELECT COUNT(*) FROM (SELECT L.LOT_ID FROM LOT L WHERE L.LOT_ID = ? OR L.LOT_ID = ? " + "UNION " +
                "ALL SELECT LP.LOT_ID FROM LOT_PLAN LP WHERE LP.LOT_ID = ? ) RESULT ";
        return jdbcTemplate
                .queryForObjectWithNull(sql, new Object[]{generateLotId, generateLotId + "_DEL", generateLotId},
                                        int.class) > 0;
    }

    @Override
    public Map<String, Object> getComsumeLotsByEqpt(Lot lot, Integer lotSize) {

        StringBuilder sb = new StringBuilder(
                " SELECT NVL(LISTAGG(LOT_ID, ',') WITHIN GROUP(ORDER BY LOT_ID),'') AS LOTIDS, " + "NVL(LISTAGG" +
                        "(LOT_RRN, ',') WITHIN GROUP(ORDER BY LOT_ID),'') AS LOTRRNS ");

        sb.append(" FROM (SELECT LOT_ID,LOT_RRN FROM ");

        sb.append(
                " (SELECT E.LOT_ID, E.LOT_RRN, MAX(TRANS_TIME) AS MAX_TRANS FROM EQPT_LOTS_INFO E, RELATION" + " R,  " +
                        "LOT TL, LOT SL");
        sb.append(" WHERE E.EQPT_RRN = TL.EQPT_RRN AND E.OPERATION_RRN = TL.OPERATION_RRN ");
        sb.append(" AND TL.PRODUCT_RRN = R.FROM_RRN AND SL.PRODUCT_RRN = R.TO_RRN ");
        sb.append(" AND TL.OPERATION_RRN = R.ATTRIBUTE_DATA_1 AND TL.PROCESS_RRN = R.ATTRIBUTE_DATA_2 ");
        sb.append(" AND SL.LOT_RRN = E.LOT_RRN AND TL.LOT_ID=? ");
        sb.append(" AND R.LINK_TYPE = ? AND R.ATTRIBUTE_DATA_3 = ? ");
        sb.append(" GROUP BY E.LOT_ID, E.LOT_RRN ORDER BY MAX_TRANS DESC ) WHERE ROWNUM <= ?)");

        List<Map> list = jdbcTemplate.query(sb.toString(),
                                            new Object[]{lot.getLotId(), LinkTypeList.PRODUCT_TO_SAPPHIRES,
                                                         BondAndConsumeEnum.COSUME.getValue(), lotSize}, Map.class);
        return list != null && !list.isEmpty() ? list.iterator().next() : new HashMap<String, Object>();

    }

    @Override
    public LotSapphreInfo getLotSapphreInfo(Long lotRrn) {
        String sql = "SELECT " + "a.LOT_RRN TEMP_LOT_RRN ,b.LOT_RRN, EXPIRED_DATE, UNIT_DATE, TARGET_COUNT, " +
                "WARNING_COUNT, ACTUAL_COUNT, " +
                "ATTRIBUTE_DATA1, ATTRIBUTE_DATA2, ATTRIBUTE_DATA3, ATTRIBUTE_DATA4, " + "ATTRIBUTE_DATA5 " + "FROM " +
                DataBaseNames.LOT + " a LEFT JOIN " + DataBaseNames.LOT_SAPPHIRE_INFO + " b " +
                "ON a.LOT_RRN = b.LOT_RRN " + " WHERE a.LOT_RRN = ?";

        Object[] args = new Object[]{lotRrn};
        LotSapphreInfo lotSapphireInfo = jdbcTemplate.queryForObjectWithNull(sql, args, LotSapphreInfo.class);
        return lotSapphireInfo;
    }

    @Override
    public List<Map> qryBondedLotInfos(Unit unit) {
        StringBuffer sql = new StringBuffer();
        sql.append("SELECT  u2.unit_id AS source_unit_id," + "  l.lot_id, l.PROCESS_RRN,l.OPERATION_RRN, " +
                           "  u1.unit_id AS target_unit_id, " + "  nb.instance_id AS product_id," +
                           "  lsh.process_step_id_version," + "  tl.trans_performed_by," +
                           "  tl.trans_start_timestamp," + "  tl.trans_end_timestamp," + "  lt.trans_comments," +
                           "  nb.instance_rrn AS product_rrn," + "  bh.source_unit_rrn AS carrier_rrn " + " FROM " +
                           "  bonding_history bh" + "  JOIN unit u1 ON bh.target_unit_rrn = u1.unit_rrn " +
                           "  JOIN unit u2 ON bh.source_unit_rrn = u2.unit_rrn " +
                           "  LEFT JOIN lot l ON bh.target_lot_rrn = l.lot_rrn " +
                           "  LEFT JOIN named_object nb ON nb.instance_rrn = l.product_rrn " +
                           "  JOIN lot_step_history lsh ON lsh.step_sequence = bh.step_sequence " +
                           "  AND l.lot_rrn = lsh.lot_rrn " +
                           "  JOIN lot_trans_history lt ON bh.trans_rrn = lt.trans_rrn " +
                           "  AND l.lot_rrn = lt.lot_rrn " + "  AND lt.trans_sequence = 1 " +
                           "  JOIN transaction_log tl ON tl.trans_rrn = bh.trans_rrn " + " WHERE " +
                           "  u1.unit_id = ? ");

        System.out.println("sql=["+sql.toString()+"]");
        List<Map> bondedlotListInfo = jdbcTemplate.query(sql.toString(), new Object[]{new String(unit.getUnitId())},

                                                         new RowMapper() {

                                                             @Override
                                                             public Object mapRow(ResultSet rs,
                                                                                  int rowNum) throws SQLException {
                                                                 Map bondedTrans = new HashMap();
                                                                 bondedTrans.put("seq", new Integer(rowNum + 1));
                                                                 bondedTrans.put("unitId", rs.getString("source_unit_id"));
                                                                 bondedTrans.put("bondedlotId",
                                                                                 rs.getString("lot_id"));
                                                                 bondedTrans.put("transStartTimestamp", DateUtils
                                                                         .formatDate(rs.getTimestamp(
                                                                                 "trans_start_timestamp")));
                                                                 bondedTrans.put("trans_end_timestamp", DateUtils
                                                                         .formatDate(rs.getTimestamp(
                                                                                 "trans_end_timestamp")));
                                                                 String transByName = getTransByName(
                                                                         rs.getString("trans_performed_by"));
                                                                 if (transByName != null) {
                                                                     bondedTrans.put("transPerformedBy", rs.getString(
                                                                             "trans_performed_by") + " " + transByName);
                                                                 } else {
                                                                     bondedTrans.put("transPerformedBy", rs.getString(
                                                                             "trans_performed_by"));
                                                                 }
                                                                 bondedTrans
                                                                         .put("productRrn", rs.getLong("product_rrn"));
                                                                 String processStepIdVer = rs
                                                                         .getString("process_step_id_version");
                                                                 bondedTrans
                                                                         .put("routeId", parseRoute(processStepIdVer));
                                                                 bondedTrans.put("operationRrn",
                                                                                 rs.getLong("operation_rrn"));
                                                                 bondedTrans
                                                                         .put("processRrn", rs.getLong("process_rrn"));
                                                                 bondedTrans.put("transComments",
                                                                                 rs.getString("trans_comments"));
                                                                 // bondedTrans.put("unitType", rs.getString("unittype"));
                                                                 bondedTrans.put("bondedlotiId", rs.getString("lot_id"));
                                                                 bondedTrans
                                                                         .put("carrierRrn", rs.getLong("carrier_rrn"));
                                                                 bondedTrans.put("targetUnitId",
                                                                                 rs.getString("target_unit_id"));
                                                                 return bondedTrans;
                                                             }

                                                         });
        return bondedlotListInfo;

    }

    @Override
    public List<Map> qryBondedLotInfos(Lot lot) {
        StringBuffer sql = new StringBuffer();

        sql.append(" SELECT u2.unit_id AS source_unit_id, l.lot_id, l.PROCESS_RRN, l.OPERATION_RRN,u1.unit_id AS target_unit_id, " );
        sql.append(" nb.instance_id AS product_id,lsh.process_step_id_version,tl.trans_performed_by, ");
        sql.append(" tl.trans_start_timestamp,tl.trans_end_timestamp,lt.trans_comments,nb.instance_rrn AS product_rrn, ");
        sql.append(" bh.source_unit_rrn AS carrier_rrn FROM bonding_history bh ");
        sql.append(" JOIN unit u1 ON bh.target_unit_rrn = u1.unit_rrn ");
        sql.append(" JOIN unit u2 ON bh.source_unit_rrn = u2.unit_rrn ");
        sql.append(" LEFT JOIN lot l ON bh.target_lot_rrn = l.lot_rrn ");
        sql.append(" LEFT JOIN named_object nb ON nb.instance_rrn = l.product_rrn ");
        sql.append(" JOIN lot_step_history lsh ON lsh.step_sequence = bh.step_sequence ");
        sql.append(" AND l.lot_rrn = lsh.lot_rrn ");
        sql.append(" JOIN lot_trans_history lt ON bh.trans_rrn = lt.trans_rrn ");
        sql.append(" AND l.lot_rrn = lt.lot_rrn AND lt.trans_sequence = 1 ");
        sql.append(" JOIN transaction_log tl ON tl.trans_rrn = bh.trans_rrn WHERE l.lot_id = ? ");

        List<Map> bondedlotListInfo = jdbcTemplate.query(sql.toString(), new Object[]{new String(lot.getLotId())},

                                                         new RowMapper() {

                                                             @Override
                                                             public Object mapRow(ResultSet rs,
                                                                                  int rowNum) throws SQLException {
                                                                 Map bondedTrans = new HashMap();
                                                                 bondedTrans.put("seq", new Integer(rowNum + 1));
                                                                 bondedTrans.put("unitId", rs.getString("source_unit_id"));
                                                                 bondedTrans.put("bondedlotId",
                                                                                 rs.getString("lot_id"));
                                                                 bondedTrans.put("transStartTimestamp", DateUtils
                                                                         .formatDate(rs.getTimestamp(
                                                                                 "trans_start_timestamp")));
                                                                 bondedTrans.put("trans_end_timestamp", DateUtils
                                                                         .formatDate(rs.getTimestamp(
                                                                                 "trans_end_timestamp")));
                                                                 String transByName = getTransByName(
                                                                         rs.getString("trans_performed_by"));
                                                                 if (transByName != null) {
                                                                     bondedTrans.put("transPerformedBy", rs.getString(
                                                                             "trans_performed_by") + " " + transByName);
                                                                 } else {
                                                                     bondedTrans.put("transPerformedBy", rs.getString(
                                                                             "trans_performed_by"));
                                                                 }
                                                                 bondedTrans
                                                                         .put("productRrn", rs.getLong("product_rrn"));
                                                                 String processStepIdVer = rs
                                                                         .getString("process_step_id_version");
                                                                 bondedTrans
                                                                         .put("routeId", parseRoute(processStepIdVer));
                                                                 bondedTrans.put("operationRrn",
                                                                                 rs.getLong("operation_rrn"));
                                                                 bondedTrans
                                                                         .put("processRrn", rs.getLong("process_rrn"));
                                                                 bondedTrans.put("transComments",
                                                                                 rs.getString("trans_comments"));
                                                                 // bondedTrans.put("unitType", rs.getString("unittype"));
                                                                 bondedTrans.put("bondedlotiId", rs.getString("lot_id"));
                                                                 bondedTrans
                                                                         .put("carrierRrn", rs.getLong("carrier_rrn"));
                                                                 bondedTrans.put("targetUnitId",
                                                                                 rs.getString("target_unit_id"));
                                                                 return bondedTrans;
                                                             }

                                                         });
        return bondedlotListInfo;

    }

    @Override
    public List<Map> qryByBondedLotInfos(Unit unit) {
        StringBuffer sql = new StringBuffer();
        sql.append("SELECT *" + "  FROM (SELECT *" + "          FROM (SELECT *" + "                  FROM (SELECT lt" +
                           ".trans_rrn," + "                               It.UNIT_ID SOURCE_UNIT_ID," +
                           "                     " + "          lt.trans_sequence," +
                           "                               lt.trans_id," + "                 " +
                           "              tr.trans_start_timestamp," + "                               tr" +
                           ".trans_end_timestamp," + "                               tr.trans_performed_by," +
                           "            " + "                   ls.process_step_version," +
                           "                               ls.stage_id," +
                           "                               ls.lot_rrn," + "                               ls.lot_id," +
                           "  " + "                             ls.facility_rrn," +
                           "                               ls.in_qty1," + "                               lt.qty1," +
                           "                               ls.out_qty1," +
                           "                               ls.product_rrn," +
                           "                               ls.process_rrn," +
                           "                               ls.operation_rrn," +
                           "                               ls.eqpt_rrn," +
                           "                               lt.trans_comments," +
                           "                               ls.process_step_id_version," +
                           "                               ls.product_layer," +
                           "                               It3.unit_id as unit_id, " +
                           "                               ed.source_unit_type  as unittype, " +
                           "                               t2.lot_id as bondedlotid, " +
                           "                               t2.carrier_rrn " +
                           "                          FROM lot_trans_history lt," +
                           "                               lot_step_history  ls," +
                           "                               transaction_log   tr," +
                           "                               unit_bonded_h     ed," +
                           "                               unit              It,"
                           // + "                               unit              It2,"
                           + "                               unit              It3,"
                           // + "                               lot              t1,"
                           + "                               lot              t2 " +
                           "                         WHERE 1 =" + " 1 " +
                           "                           AND lt.lot_rrn = ls.lot_rrn " + "                       " +
                           "    AND lt.trans_rrn =ed.trans_rrn"
                           // + "                           AND t1.lot_rrn =ed.source_lot_rrn  "
                           + "                           AND t2.lot_rrn =ed.target_lot_rrn  " +
                           "                       " + "    AND lt.step_sequence = ls.step_sequence " +
                           "                           AND lt" + ".trans_rrn = tr.trans_rrn " +
                           "                           AND it.unit_rrn=?   " + "       " +
                           "                    AND It.Unit_Rrn = ed.source_unit_rrn and ed" + ".source_lot_rrn=ls" +
                           ".lot_rrn "
                           // + "                           AND It2.Unit_Rrn=ed.source_unit_rrn "
                           + "                           AND It3.Unit_Rrn=ed.target_unit_rrn " +
                           "                      " + "   ORDER BY trans_start_timestamp DESC, trans_sequence DESC)" +
                           "                         ORDER BY " +
                           "trans_start_timestamp) ORDER BY trans_start_timestamp DESC, trans_sequence)");
        List<Map> bondedlotListInfo = jdbcTemplate.query(sql.toString(), new Object[]{new Long(unit.getUnitRrn())},

                                                         new RowMapper() {

                                                             @Override
                                                             public Object mapRow(ResultSet rs,
                                                                                  int rowNum) throws SQLException {
                                                                 Map bondedTrans = new HashMap();
                                                                 bondedTrans.put("seq", new Integer(rowNum + 1));
                                                                 bondedTrans.put("unitId", rs.getString("unit_id"));
                                                                 bondedTrans.put("bondedlotId",
                                                                                 rs.getString("bondedlotid"));
                                                                 bondedTrans.put("transStartTimestamp", DateUtils
                                                                         .formatDate(rs.getTimestamp(
                                                                                 "trans_start_timestamp")));
                                                                 bondedTrans.put("trans_end_timestamp", DateUtils
                                                                         .formatDate(rs.getTimestamp(
                                                                                 "trans_end_timestamp")));
                                                                 String transByName = getTransByName(
                                                                         rs.getString("trans_performed_by"));
                                                                 if (transByName != null) {
                                                                     bondedTrans.put("transPerformedBy", rs.getString(
                                                                             "trans_performed_by") + " " + transByName);
                                                                 } else {
                                                                     bondedTrans.put("transPerformedBy", rs.getString(
                                                                             "trans_performed_by"));
                                                                 }
                                                                 String processStepIdVer = rs
                                                                         .getString("process_step_id_version");
                                                                 bondedTrans
                                                                         .put("routeId", parseRoute(processStepIdVer));
                                                                 bondedTrans.put("transComments",
                                                                                 rs.getString("trans_comments"));
                                                                 bondedTrans.put("unitType", rs.getString("unittype"));
                                                                 bondedTrans.put("bondedlotiId",
                                                                                 rs.getString("bondedlotid"));
                                                                 bondedTrans.put("sourceUnitId",
                                                                                 rs.getString("SOURCE_UNIT_ID"));
                                                                 bondedTrans.put("operationRrn",
                                                                                 rs.getLong("operation_rrn"));
                                                                 bondedTrans
                                                                         .put("processRrn", rs.getLong("process_rrn"));
                                                                 bondedTrans
                                                                         .put("productRrn", rs.getLong("product_rrn"));
                                                                 bondedTrans
                                                                         .put("carrierRrn", rs.getLong("carrier_rrn"));
                                                                 return bondedTrans;
                                                             }
                                                         });
        return bondedlotListInfo;
    }

    @Override
    public long queryLotStepEquipmentHistoryByLot(long lotRrn) {
        String sql = "SELECT T1.*  FROM (SELECT LS.EQPT_RRN FROM (SELECT * FROM LOT_STEP_HISTORY WHERE " + "LOT_RRN =" +
                " ? ) LS left join " +
                " (SELECT LT.LOT_RRN AS LOT_RRN2,LT.STEP_SEQUENCE,LT.TRANS_RRN,LT.TRANS_SEQUENCE,LT" +
                ".TRANS_ID FROM LOT_TRANS_HISTORY LT " +
                " WHERE LT.LOT_RRN = ? ) L  on LS.LOT_RRN = L.LOT_RRN2  AND LS.STEP_SEQUENCE = L" + ".STEP_SEQUENCE " +
                " where L.TRANS_ID = 'MOVEOUT' ORDER BY L.TRANS_RRN DESC) T1 where rownum =  1";
        Object[] args = {lotRrn, lotRrn};
        return jdbcTemplate.queryForObjectWithNull(sql, args, long.class);
    }

    @Override
    public int qryLotTransHistoryCount(long lotRrn) {
        List list = new ArrayList();
        String filterTransIDParams = " AND lt.trans_id not in (?, ?, ?, ?) ";
        String sql = "SELECT COUNT(ls.lot_rrn)" + " FROM lot_trans_history lt, lot_step_history ls, named_object cn, " +
                " transaction_log tr left join split_merge_history smh " +
                " on tr.trans_rrn = smh.trans_rrn  WHERE 1 = 1" +
                " AND lt.lot_rrn=? AND lt.carrier_rrn=cn.instance_rrn" +
                " AND lt.lot_rrn = ls.lot_rrn AND lt.step_sequence = ls.step_sequence " +
                " AND lt.trans_rrn = tr.trans_rrn " +
                " AND (smh.source_lot_rrn <> smh.target_lot_rrn or (smh.target_lot_rrn is null and smh" +
                ".source_lot_id is null)) " +
                " AND (lt.lot_rrn = smh.target_lot_rrn or lt.lot_rrn = smh.source_lot_rrn or (smh" +
                ".target_lot_rrn is null and smh.source_lot_id is null)) " + filterTransIDParams;

        list.add(lotRrn);
        list.add(TransactionNames.LBRD_KEY);
        list.add(TransactionNames.MOVENEXT_KEY);
        list.add(TransactionNames.WS_MOVENEXT_KEY);
        list.add(TransactionNames.CREATE_KEY);
        return jdbcTemplate.queryForObjectWithNull(sql, list.toArray(), int.class);
    }

    @Override
    public List<LotRecycledInfo> qryLotRecycledInfos(LotRecycledInfo lotRecycledInfo, String filterFlag) {
        StringBuffer sql = new StringBuffer(
                "select * from lot_recycled_h where lot_rrn=?" + " and process_rrn=? AND PROCESS_VERSION = ? ");

        List<Object> args = new ArrayList<Object>();
        args.add(lotRecycledInfo.getLotRrn());
        args.add(lotRecycledInfo.getProcessRrn());
        args.add(lotRecycledInfo.getProcessVersion());
        if (lotRecycledInfo.getStartRouteRrn() > 0 && lotRecycledInfo.getStartOperationRrn() > 0) {
            sql.append(" and start_route_rrn=? and start_operation_rrn=?");
            args.add(lotRecycledInfo.getStartRouteRrn());
            args.add(lotRecycledInfo.getStartOperationRrn());
        }
        if (lotRecycledInfo.getEndRouteRrn() > 0 && lotRecycledInfo.getEndOperationRrn() > 0) {
            sql.append(" and end_route_rrn=? and end_operation_rrn=?");
            args.add(lotRecycledInfo.getEndRouteRrn());
            args.add(lotRecycledInfo.getEndOperationRrn());
        }
        if (StringUtils.equals("Y", filterFlag)) {
            sql.append(" and loop_count<sum_loop_count");
        }
        List<LotRecycledInfo> lotRecycledInfos = jdbcTemplate
                .query(sql.toString(), args.toArray(), new LotRecycledInfoRowMapper());
        return lotRecycledInfos;
    }

    @Override
    public Map selectMatchingRulesFromReworkLot(long executionRrn) {
        String sql =
                "select t.return_wfl_step_path||'#0' as exepath,l.product_rrn||','||l.process_rrn||','||' " + "'||'," +
                        "'||' '||','||l.lot_rrn as matchingRules" + " from lot l,rework_info_history t where l" +
                        ".lot_rrn" + "=t.lot_rrn " + " and l.rework_trans_rrn=t.trans_rrn and l.execution_rrn = ?";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{executionRrn}, new RowMapper<Map>() {

            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map map = new HashMap();
                map.put("exepath", rs.getString("exepath"));
                map.put("matchingRules", rs.getString("matchingRules"));
                return map;
            }
        });
    }

    @Override
    public Map selectMatchingRulesFromLot(long executionRrn) {
        String sql = "select l.wfl_step_path||'#0'as exepath,l.product_rrn||','||l.process_rrn||','||' '||','||'" +
                " '||','||l" + ".lot_rrn as matchingRules  from lot l where l.execution_rrn = ?";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{executionRrn}, new RowMapper<Map>() {

            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map map = new HashMap();
                map.put("exepath", rs.getString("exepath"));
                map.put("matchingRules", rs.getString("matchingRules"));
                return map;
            }
        });
    }

    @Override
    public Map selectMatchingRulesFromExecution(long executionRrn) {
        String sql =
                "select t.current_step as exepath,l.product_rrn||','||l.process_rrn||','||' '||','||' '||'," + "'||l" +
                        ".lot_rrn as matchingRules from lot l,workflow_execution t where l" + ".execution_rrn=t" +
                        ".execution_rrn And l.execution_rrn = ?";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{executionRrn}, new RowMapper<Map>() {

            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map map = new HashMap();
                map.put("exepath", rs.getString("exepath"));
                map.put("matchingRules", rs.getString("matchingRules"));
                return map;
            }
        });
    }

    @Override
    public long getReworkLotCountByExecutionRrn(long executionRrn) {
        String sql = "select count(*)  from lot l,rework_info_history t where l.lot_rrn=t" + ".lot_rrn" + " and l" +
                ".rework_trans_rrn=t.trans_rrn and l.execution_rrn = ?";
        return jdbcTemplate.queryForObject(sql, new Object[]{executionRrn}, long.class);
    }

    @Override
    public long getLotCountByExecutionRrn(long executionRrn) {
        String sql = "select count(*) from lot l where l.execution_rrn = ?";
        return jdbcTemplate.queryForObject(sql, new Object[]{executionRrn}, long.class);
    }

    @Override
    public Map<String, Object> getProContextActiveDtl(long productRrn, long routeRrn, long processRrn,
                                                      int processVersion, long stepRrn, long productVersion) {
        String sql =
                "select T.RETICLE_GROUP_RRN,t.recipe_rrn,t.operation_description from " + "pro_context_active_dtl t " +
                        " where t.operation_rrn = ? and t.route_rrn = ? " + " and t.process_rrn = ? and" +
                        " t.process_version = ? and t.product_rrn = ? and t.product_version = ?  and rownum " + "=  1";

        return jdbcTemplate
                .queryForObjectWithNull(sql, new Object[]{stepRrn, routeRrn, processRrn, processVersion, productRrn,
                                                          productVersion},
                                        new RowMapper<Map<String, Object>>() {

                                            @Override
                                            public Map<String, Object> mapRow(ResultSet rs,
                                                                              int rowNum) throws SQLException {
                                                Map<String, Object> result = new HashMap<>();
                                                result.put("RETICLE_GROUP_RRN", rs.getLong("RETICLE_GROUP_RRN"));
                                                result.put("recipe_rrn", rs.getLong("recipe_rrn"));
                                                result.put("operation_description",
                                                           rs.getString("operation_description"));

                                                return result;
                                            }
                                        });
    }

    @Override
    public String getStepDesc(long contextRrn, String productRrn, String routeRrn, String processRrn,
                              String processVersion, String stepRrn) {
        String sql = "select t.result_value1 STEP_DESC from context_value t where t.context_key1 = ? and t" +
                ".context_key2 = ? " + "and t.context_key3 = ? and t.context_key4 = ? and t.context_key5 = ? and t" +
                ".context_rrn =" + " ?";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{productRrn, processRrn, processVersion, routeRrn,
                                                                     stepRrn, contextRrn}, String.class);
    }

    @Override
    public Long getRecipeByLot(long contextRrn, String productRrn, String routeRrn, String processRrn,
                               String processVersion, String stepRrn) {
        String sql = "select result_value1 from context_value t where t.context_key1 = ? and t.context_key2 = ? " +
                " and t.context_key3 = ? and t.context_key11 = ? and t.context_key4 = ? and t.context_rrn" +
                " = ? and rownum" + " = 1";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{stepRrn, routeRrn, processRrn, processVersion,
                                                                     productRrn, contextRrn}, Long.class);
    }

    @Override
    public Long getReticleByLot(long contextRrn, String productRrn, String routeRrn, String processRrn,
                                String processVersion, String stepRrn) {
        String sql = "select result_value1 from context_value t where t.context_key4 = ? and t.context_key3 = ? " +
                "and t.context_key2 = ?" +
                " and t.context_key7 = ? and t.context_key1 = ? and t.context_rrn = ? and rownum =" + " 1";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{stepRrn, routeRrn, processRrn, processVersion,
                                                                     productRrn, contextRrn}, Long.class);
    }

    @Override
    public List<Long> getReticleByFamily(long toRrn) {
        StringBuilder sql = new StringBuilder("SELECT ");
        sql.append(" FROM_RRN ");
        sql.append(" FROM ").append(DataBaseNames.RELATION);
        sql.append(" WHERE LINK_TYPE = '").append(LinkTypeList.RETICLE_TO_RETICLEFAMILY_KEY);
        sql.append("' AND TO_RRN = ?");
        sql.append(" ORDER BY SEQUENCE_NUMBER,  FROM_RRN");

        return jdbcTemplate.query(sql.toString(), Long.class, toRrn);
    }

    @Override
    public Map<String, Object> queryCarrierInfo(long carrierRrn) {
        String sql = "SELECT PA.POD_RRN,PA.DOOR_RRN FROM PCD_ASSEMBLY PA WHERE PA.CARRIER_RRN = ?";
        List result = jdbcTemplate.query(sql, new Object[]{carrierRrn}, Map.class);
        return CollectionUtils.isEmpty(result) ? null : (Map<String, Object>) result.get(0);
    }

    @Override
    public String getAreaByStep(long stepRrn) {
        String sql = "select t.attribute_data5 from OPERATION_EXT t where t.operation_rrn = ?";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{stepRrn}, String.class);
    }

    @Override
    public long getEqpGroupByStep(long stepRrn) {
        String sql = "select t.entity_group_rrn from operation t where t.operation_rrn = ?";

        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{stepRrn}, Long.class);
    }

    @Override
    public String getEqpIds(long eqpGroup) {
        String sql = "select listagg(A.INSTANCE_ID, ',') WITHIN GROUP ( ORDER BY A" + ".INSTANCE_ID ) AS eqp_ids from" +
                " " + " (select r.from_rrn,n.instance_id from relation r ,named_object n " + "  where r.from_rrn = n" +
                ".instance_rrn and r.link_type = 'ENTITY_TO_ENTITY_GROUP' " + "    and r.to_rrn = ? ) a ";

        Object[] args = new Object[]{eqpGroup};
        return jdbcTemplate.queryForObjectWithNull(sql, args, String.class);
    }

    @Override
    public String getLocationId(long locationRrn) {
        String sql = " SELECT location_id  FROM Location WHERE location_rrn=?";
        String locationId = jdbcTemplate.queryForObjectWithNull(sql, new Object[]{locationRrn}, String.class);
        return StringUtils.trimToEmpty(locationId);
    }

    @Override
    public long getHoldTransRrn(long lotRrn) {
        String sql = "select trans_rrn from MULTIPLE_HOLD t where t.instance_rrn = ? order by t" + ".hold_timestamp " +
                "desc";

        List<Long> transRrns = jdbcTemplate.query(sql, Long.class, lotRrn);

        if (CollectionUtils.isNotEmpty(transRrns)) {
            return transRrns.get(0);
        } else {
            return 0L;
        }
    }

    /**
     * 当前框架 ListUtils 没有提供partition 操作。这里自己添加
     * 如果后续加上 partition 可以删除此函数
     * @param list
     * @param subNum
     * @param <T>
     * @return
     */
    private <T> List<List<T>> splitList(List<T> list, int subNum) {
        List<List<T>> tNewList = new ArrayList<List<T>>();
        int priIndex = 0;
        int lastPriIndex = 0;
        int insertTimes = list.size() / subNum;
        List<T> subList;
        for (int i = 0; i <= insertTimes; i++) {
            priIndex = subNum * i;
            lastPriIndex = priIndex + subNum;
            if (i == insertTimes) {
                subList = list.subList(priIndex, list.size());
            } else {
                subList = list.subList(priIndex, lastPriIndex);
            }
            if (subList.size() > 0) {
                tNewList.add(subList);
            }
        }
        return tNewList;
    }

    public Map<Long,String> getTransReasonByTrans(Set<Long>trans,Long lotRrrn){
        trans =  Optional.ofNullable(trans).orElse(new HashSet<>());
        trans.remove(null);
        trans.remove(0L);
        if(trans.isEmpty()||lotRrrn==null||lotRrrn<=0){
            return new HashMap<>();
        }
        Map<Long,String> result = new HashMap<>();
        //暂时不知道trans 一次查多少,因为oracle 限制 in 1000
        List<List<Long>> transList= splitList (new ArrayList<Long>(trans),900);
        for(List<Long>item:transList){
            String sql = String.format(
                    "select t.trans_rrn,t.reason from TRANS_REASON t WHERE t.instance_rrn = ? and t.trans_rrn in(%s) order by t" +
                            ".reason_code_sequence desc", StringUtils.join(item,","));
            SqlRowSet sqlRowSet =  jdbcTemplate.queryForRowSet(sql, lotRrrn);
            while (sqlRowSet.next()){
                result.put(sqlRowSet.getLong(1),sqlRowSet.getString(2));
            }
        }


        return result;
    }

    @Override
    public String getTransReasonByTrans(long transRrn, long lotRrn) {
        String sql = "select t.reason from TRANS_REASON t WHERE t.trans_rrn = ? and t.instance_rrn = ? " + "order by " +
                "t.trans_rrn desc";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{transRrn, lotRrn}, String.class);
    }

    @Override
    public List<Long> getLotTransRrnByLot(long lotRrn, int stepSeq) {
        String sql = "select t.trans_rrn from LOT_TRANS_HISTORY t where t.lot_rrn = ? and t.step_sequence =" + " ? " +
                "and t.trans_id = 'MOVEIN' order by t.trans_rrn desc";
        return jdbcTemplate.query(sql, new Object[]{lotRrn, stepSeq}, new RowMapper<Long>() {

            @Override
            public Long mapRow(ResultSet rs, int rowNum) throws SQLException {
                // TODO Auto-generated method stub
                return rs.getLong("trans_rrn");
            }

        });
    }

    @Override
    public TransactionLog getTransactionLogByRrn(long transRrn) {
        String sql = "select * from transaction_log l where l.trans_rrn = ?";
        return jdbcTemplate.queryForObject(sql, new Object[]{transRrn}, new RowMapper<TransactionLog>() {

            @Override
            public TransactionLog mapRow(ResultSet rs, int rowNum) throws SQLException {
                // TODO Auto-generated method stub
                TransactionLog transactionLog = new TransactionLog();
                transactionLog.setTransRrn(rs.getLong("TRANS_RRN"));
                transactionLog.setTransId(rs.getString("TRANS_ID"));
                transactionLog.setTransEndTimestamp(rs.getTimestamp("TRANS_END_TIMESTAMP"));
                return transactionLog;
            }

        });
    }

    @Override
    public Integer getLotWaferCount(Long lotRrn) {
        String sql = "SELECT COUNT(L.UNIT_RRN) FROM UNIT L WHERE L.LOT_RRN=?";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{lotRrn}, Integer.class);
    }

    @Override
    public List<Map<String, Object>> queryLotInfoByPage(StringBuffer sqlBuffer, List<Object> args,
                                                        LotQueryParameterDto lotQueryParameterDto) {
        String countSql =
                "select COUNT(LOT_RRN) AS LOT_COUNT,SUM(QTY1) AS QTY_COUNT from (" + sqlBuffer.toString() + ") tt";


        Map count = jdbcTemplate.queryForObject(countSql, args.toArray(), (rs, rowNum) -> {
            Map _map = new HashMap();
            _map.put("LOT_COUNT", rs.getLong("LOT_COUNT"));
            _map.put("QTY_COUNT", rs.getLong("QTY_COUNT"));
            return _map;
        });

        sqlBuffer.append(" ORDER BY ");
        sqlBuffer.append(" case when Q_TIME=-10000 then 100000 else Q_TIME end ASC, l.hot_flag" +
                                 " ASC," + " l.PRIORITY ASC, TOTAL_WAITING_TIME DESC ");

        //        String pageSql = "SELECT * FROM ( SELECT t_0.* FROM (" + sqlBuffer.toString() + ") t_0 )
        //        t_1  where rownum > " + lotQueryParameterDto.getStartRow()+ " and rownum <= " +
        //        lotQueryParameterDto.getPageSize();
        //        return jdbcTemplate.query(pageSql, args.toArray(), new LotQueryInfoMapper(MapUtils
        //        .getIntValue(count, "LOT_COUNT"), MapUtils.getIntValue(count, "QTY_COUNT")));

        long startRow = NumberUtils.toLong(lotQueryParameterDto.getStartRow(), 0);
        long pageSize = NumberUtils.toLong(lotQueryParameterDto.getPageSize(), 20);
        Page page = new Page((startRow / pageSize) + 1, pageSize);
        page = jdbcTemplate.queryForPage(page, sqlBuffer.toString(), args.toArray(),
                                         new LotQueryInfoMapper(MapUtils.getIntValue(count, "LOT_COUNT"),
                                                                MapUtils.getIntValue(count, "QTY_COUNT")));
        return (List<Map<String, Object>>) page.getResults();
    }

    @Override
    public List<Map<String, Object>> queryLotInfoByNoPage(StringBuffer sqlBuffer, List<Object> args,
                                                          LotQueryParameterDto lotQueryParameterDto) {

        sqlBuffer.append(" ORDER BY ");
        sqlBuffer.append(" case when Q_TIME=-10000 then 100000 else Q_TIME end ASC, l.hot_flag " +
                                 "ASC," + " l.PRIORITY ASC, TOTAL_WAITING_TIME DESC ");

        //        String pageSql = " SELECT t_0.* FROM (" + sqlBuffer.toString() + ") t_0 ";
        Page page = new Page(1, Integer.MAX_VALUE);
        page = jdbcTemplate.queryForPage(page, sqlBuffer.toString(), args.toArray(), new LotQueryInfoMapper(0, 0));
        return (List<Map<String, Object>>) page.getResults();
        //        return jdbcTemplate.query(pageSql, args.toArray(), new LotQueryInfoMapper(0, 0));
    }

    @Override
    public List getChildLotsForMergeWithActiveHold(Lot lot) {
        String sql = " SELECT * FROM (SELECT L.*, '' AS Q_TIME FROM LOT L WHERE LOT_ID like ? AND LOT_ID != ? AND " +
                "LOT_ID" + " != ? " +
                "AND LOT.LOT_STATUS in ('HOLD','WAITING','RUNNING','RUNNINGHOLD')) result  ORDER BY " + "LOT_ID";

        String lotId = lot.getLotId();
        lotId = lotId.indexOf(".") > 0 ? lotId.substring(0, lotId.indexOf(".")) : lotId;
        List<Object> args = new ArrayList<>();
        args.add(lotId + "%");
        args.add(lotId);
        args.add(lot.getLotId());
        return jdbcTemplate.query(sql, args.toArray(), new LotMapper());
    }

    @Override
    public List<Long> getStepByStation(Long stationRrn) {
        String sql = "SELECT R.TO_RRN STEP_RRN FROM RELATION R WHERE R.LINK_TYPE = 'STATION_TO_OPERATION' " + "AND R" +
                ".FROM_RRN = ?";
        List<Long> stepRrns1 = jdbcTemplate
                .query(sql, new Object[]{stationRrn}, (RowMapper<Long>) (rs, rowNum) -> rs.getLong("STEP_RRN"));

        String sql2 = "select  STEP_RRN from( SELECT STEP_RRN, STATION_RRN, STATION_ID FROM (SELECT O" +
                ".OPERATION_RRN AS STEP_RRN, " +
                "N1.INSTANCE_RRN STATION_RRN, N1.INSTANCE_ID STATION_ID, ROW_NUMBER() OVER" + "(PARTITION BY O" +
                ".OPERATION_RRN ORDER BY N1.INSTANCE_ID desc)" +
                " ROW_NUM FROM OPERATION O, RELATION R1, RELATION R2, NAMED_OBJECT N1 WHERE O" +
                ".ENTITY_GROUP_RRN = R1.TO_RRN AND R1.LINK_TYPE = 'ENTITY_TO_ENTITY_GROUP' " +
                "AND R1.FROM_RRN = R2.TO_RRN AND R2.LINK_TYPE = 'STATION_TO_EQUIPMENT' AND R2" + ".FROM_RRN = " +
                "N1.INSTANCE_RRN AND N1.OBJECT = 'STATION' AND NOT EXISTS (SELECT 1 FROM RELATION RS " +
                "WHERE RS.LINK_TYPE = 'STATION_TO_OPERATION' AND O.OPERATION_RRN = RS.TO_RRN)) t0 " + "WHERE " +
                "ROW_NUM = 1) t1  where STATION_RRN = ?";
        List<Long> stepRrns2 = jdbcTemplate.query(sql2, new Object[]{stationRrn}, new RowMapper<Long>() {
            @Override
            public Long mapRow(ResultSet rs, int rowNum) throws SQLException {
                return rs.getLong("STEP_RRN");
            }
        });

        if (CollectionUtils.isEmpty(stepRrns1) && CollectionUtils.isEmpty(stepRrns2)) {
            return null;
        }
        List<Long> steps = CollectionUtils.isNotEmpty(stepRrns1) ? stepRrns1 : new ArrayList<Long>();
        if (CollectionUtils.isNotEmpty(stepRrns2)) {
            steps.addAll(stepRrns2);
        }
        return steps;
    }

    @Override
    public List qryLotHistoryCommentByTime(long lotRrn) {

        StringBuffer sql = new StringBuffer();
        sql.append(" SELECT t.lot_rrn,                                                          ");
        sql.append("        t.step_sequence,                                                    ");
        sql.append("        t.comment_sequence,                                                 ");
        sql.append("        t.comment_type,                                                     ");
        sql.append("        t.step_comment,                                                     ");
        sql.append("        t.add_timestamp,                                                    ");
        sql.append("        t.add_user_id,                                                      ");
        sql.append("        n.instance_id step_Id                                               ");
        sql.append("   FROM lot_step_history_comment t, lot_step_history h, NAMED_OBJECT n      ");
        sql.append("  WHERE t.lot_rrn = h.lot_rrn                                               ");
        sql.append("    AND t.step_sequence = h.step_sequence                                   ");
        sql.append("    AND h.operation_rrn = n.instance_rrn                                    ");
        sql.append("    and t.lot_rrn = ?                                                       ");
        sql.append("  order by t.add_timestamp desc												    ");

        return jdbcTemplate.query(sql.toString(), new Object[]{lotRrn}, (rs, rowNum) -> {

            Map m = new HashMap();
            m.put("lotRrn", new Long(rs.getLong("lot_rrn")));
            m.put("stepSequence", new Long(rs.getLong("step_sequence")));
            m.put("commentSequence", new Long(rs.getLong("comment_sequence")));
            m.put("commentType", rs.getString("comment_type"));
            m.put("stepComment", rs.getString("step_comment"));
            m.put("stepId", rs.getString("step_Id"));
            m.put("userId", rs.getString("add_user_id"));
            m.put("timeStamp", DateUtils.formatDate(rs.getTimestamp("add_timestamp"), DateUtils.DATE_FORMAT4DATE));
            return m;
        });
    }

    @Override
    public Map<String, Object> queryPriorityBeforeLastAdjust(long lotRrn, long transRrn) {
        String countsql =
                "SELECT COUNT(*) FROM lot_trans_history where lot_rrn = ? and trans_rrn < ? AND " + "trans_id='ADJUST'";
        int count = jdbcTemplate.queryForObject(countsql, new Object[]{lotRrn, transRrn}, int.class);
        String sql = "";
        if (count == 0) {
            sql = "select hot_flag,priority from lot_trans_history where lot_rrn = ? and trans_rrn < " + "? AND " +
                    "hot_flag IS NOT NULL and rownum = 1";
        } else {
            sql = "select * from (select hot_flag,priority from lot_trans_history where lot_rrn = ? and " +
                    "trans_rrn < ? AND " + "trans_id='ADJUST'  ORDER BY TRANS_RRN DESC ) t where rownum = 1";
        }
        return jdbcTemplate
                .queryForObjectWithNull(sql, new Object[]{lotRrn, transRrn}, new RowMapper<Map<String, Object>>() {

                    @Override
                    public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
                        Map map = new HashMap();
                        map.put("hotFlag", new Long(rs.getInt("hot_flag")));
                        map.put("priority", new Long(rs.getInt("priority")));
                        return map;
                    }
                });

    }

    @Override
    public int qryLotTransHisCountByStepseq(long lotRrn) {
        String sql = "SELECT count(*) from (SELECT DISTINCT step_sequence  FROM lot_trans_history WHERE " + "lot_rrn " +
                "= ? ) t";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{lotRrn}, int.class);
    }

    @Override
    public void getParamSetMapByLotRrn(Long lotRrn, Map<Long, String> paramSetMap) {
        String sql = "SELECT DISTINCT DSI.LOT_RRN, DC.PARAMETER_SET_RRN ,N.INSTANCE_ID, N.INSTANCE_DESC," + " DSI" +
                ".METROLOGICAL_STEP_SEQUENCE STEP_SEQUENCE " +
                " FROM DATA_COLLECTION DC, DCOL_STEP_INFO DSI, NAMED_OBJECT N" + " " +
                " WHERE DC.DCOL_RRN = DSI.DCOL_RRN " + " AND DC.PARAMETER_SET_RRN = N.INSTANCE_RRN " + " AND DSI" +
                ".LOT_RRN = ? ";
        jdbcTemplate.query(sql, new Object[]{lotRrn}, (RowMapper<Map>) (rs, rowNum) -> {
            Long rrn = rs.getLong("LOT_RRN") + rs.getLong("STEP_SEQUENCE");
            String paramSetStr = rs.getString("INSTANCE_ID");
            paramSetMap.put(rrn, paramSetStr);
            return paramSetMap;
        });

    }

    @Override
    public TimelimitStatus getLotTimeLimitStatusByLotRrnAndQtimeId(long lotRrn, String timeLimitId,
                                                                   String targetStatus) {
        List args = new ArrayList();
        args.add(lotRrn);
        args.add(timeLimitId);
        StringBuilder sb = new StringBuilder();
        sb.append("SELECT ");
        sb.append("LOT_RRN, TIMELIMIT_ID, TIMELIMIT_TYPE, ");
        sb.append("START_PRODUCT_RRN, START_PROCESS_RRN, START_PROCESS_VERSION, START_PROCESS_VERSION ," +
                          "START_ROUTE_RRN, START_OPERATION_RRN, ");
        sb.append("END_PRODUCT_RRN, END_PROCESS_RRN, END_ROUTE_RRN, END_OPERATION_RRN, ");
        sb.append("TIMELIMIT, START_TIME, STATUS, MODULE, ADDITIONAL_TIMELIMIT, TIMELIMIT_RRN, TIME_TYPE, " +
                          "LIMIT_TYPE," + " ");
        sb.append("START_ROUTE_SEQ, START_OPERATION_SEQ, END_ROUTE_SEQ, END_OPERATION_SEQ, STEP_SEQUENCE ");
        sb.append("FROM " + DataBaseNames.TIMELIMIT_STATUS + " WHERE LOT_RRN = ? AND TIMELIMIT_ID = ? ");
        if (StringUtils.equalsIgnoreCase(targetStatus, "NO_CLOSE")) {
            sb.append(" AND STATUS <> 'CLOSE' ");
        } else if (StringUtils.isNotBlank(targetStatus)) {
            sb.append(" AND STATUS=? ");
            args.add(targetStatus);
        }

        sb.append(" ORDER BY STATUS,TIME_TYPE, START_TIME ");

        return jdbcTemplate.queryForObject(sb.toString(), args.toArray(), new TimeLimitStatusRowMapper());
    }

    @Override
    public List<Map<String, String>> getLotPlanAdjustDataWithSimilarTime(Long lotRrn, Timestamp transStartTimestamp) {
        StringBuilder sql = new StringBuilder("SELECT * FROM ");

        sql.append(" (SELECT tl.TRANS_RRN, tl.TRANS_START_TIMESTAMP, tl.TRANS_PERFORMED_BY, ");
        sql.append(" lph.TRANS_SEQUENCE, LOT_RRN, FACILITY_RRN, LOT_ID, BASED_LOT_RRN, ");
        sql.append(" HOT_FLAG, PRIORITY, STARTED_FLAG, STARTED_TIMESTAMP, CREATE_CATEGORY, ");
        sql.append(" CREATED_TIMESTAMP, END_TIMESTAMP, DUE_DATE, SCHEDULE_DUE_DATE, ");
        sql.append(" ESTIMATED_REMAIN_TIME, DUMMY_FLAG, LOT_TYPE, LOT_OWNER, QTY1, QTY2, ");
        sql.append(" DUMMY_QTY1, INPUT_QTY1, INPUT_QTY2, SUBCONTRACTOR_RRN, LOT_COMMENTS, ");
        sql.append(" STEP_SEQUENCE, STEP_NUMBER_IN_PROCESS, HOLD_TIMESTAMP, REWORK_TRANS_RRN, ");
        sql.append(" REWORK_CATEGORY, CARRIER_RRN, BEFORE_STATUS, LOT_STATUS, PROCESSING_STATUS,");
        sql.append(" QUEUE_TIMESTAMP, PRODUCT_RRN, PROCESS_RRN, PROCESS_VERSION, ");
        sql.append(" PROCESS_STEP_VERSION, PROCESS_STEP_ID_VERSION, PREV_OPERATION_RRN, ");
        sql.append(" PREV_OPERATION_VERSION, OPERATION_RRN, OPERATION_VERSION, ");
        sql.append(" NEXT_STEP_VERSION1, NEXT_STEP_ID_VERSION1, NEXT_OPERATION_RRN1, ");
        sql.append(" NEXT_STEP_VERSION2, NEXT_STEP_ID_VERSION2, NEXT_OPERATION_RRN2, ");
        sql.append(" STAGE_ID, LAYER_ID, BOR_RRN, EQPT_RRN, RECIPE_STRING, ");
        sql.append(" NEXT_RECIPE_STRING1, NEXT_RECIPE_STRING2, JOB_RRN, NEXT_JOB_RRN1, ");
        sql.append(" NEXT_JOB_RRN2, WFL_STEP_PATH, EXECUTION_RRN, RETICLE_RRN, SHIPPED_QTY1, ");
        sql.append(" SHIPPED_QTY2, WIFER_ID, WIFER_TYPE, FLOW_LEVEL, CUSTOMER_ID, ");
        sql.append(" CUSTOMER_LOT_ID, CUSTOMER_WAFER_ID, WAFERSTARTTIME, ");
        sql.append(" OUTERORDERNO, INNERORDERNO, SHIPPINGCODE, ISOUTSOURCE, ISRECREATELOT, ");
        sql.append(
                " PROJECT_CATEGORY, RETICLE_GROUP_RRN, ATTRIBUTE_DATA3, LOT_PLAN_TYPE, MATERIALINFO, OUT_ORDER_TYPE ");
        sql.append(" FROM ").append(DataBaseNames.LOT_PLAN_H).append(" lph, ").append(DataBaseNames.TRANSACTION_LOG)
           .append(" tl ");
        sql.append(" WHERE lph.TRANS_RRN = tl.TRANS_RRN AND lph.LOT_RRN = ? ");
        sql.append(" ORDER BY tl.TRANS_START_TIMESTAMP DESC) ");
        sql.append(" WHERE TRANS_START_TIMESTAMP <= ? AND ROWNUM <= 2 ");

        return jdbcTemplate.query(sql.toString(), new Object[]{lotRrn, transStartTimestamp}, (rs, rowNum) -> {
            Map<String, String> map = new HashMap<>();
            SimpleDateFormat formatter = new SimpleDateFormat(DateUtils.DATE_FORMAT);

            map.put("transRrn", rs.getString("TRANS_RRN"));
            map.put("transStartTimestamp", formatter.format(rs.getTimestamp("TRANS_START_TIMESTAMP")));
            map.put("transPerformedBy", rs.getString("TRANS_PERFORMED_BY"));
            map.put("lotId", rs.getString("LOT_ID"));
            map.put("hotFlag", rs.getString("HOT_FLAG"));
            map.put("priority", rs.getString("PRIORITY"));
            map.put("dueDate", rs.getString("DUE_DATE"));
            map.put("lotType", rs.getString("LOT_TYPE"));
            map.put("lotOwner", rs.getString("LOT_OWNER"));
            map.put("startedFlag", rs.getString("STARTED_FLAG"));
            map.put("startedTimestamp", rs.getString("STARTED_TIMESTAMP"));
            map.put("createCategory", rs.getString("CREATE_CATEGORY"));
            map.put("createdTimestamp", rs.getString("CREATED_TIMESTAMP"));
            map.put("endTimestamp", rs.getString("END_TIMESTAMP"));
            map.put("scheduleDueDate", rs.getString("SCHEDULE_DUE_DATE"));
            map.put("estimatedRemainTime", rs.getString("ESTIMATED_REMAIN_TIME"));
            map.put("dummyFlag", rs.getString("DUMMY_FLAG"));
            map.put("qty1", rs.getString("QTY1"));
            map.put("qty2", rs.getString("QTY2"));
            map.put("dummyQty1", rs.getString("DUMMY_QTY1"));
            map.put("inputQty1", rs.getString("INPUT_QTY1"));
            map.put("inputQty2", rs.getString("INPUT_QTY2"));
            map.put("subcontractorRrn", rs.getString("SUBCONTRACTOR_RRN"));
            map.put("lotComments", rs.getString("LOT_COMMENTS"));
            map.put("stepSequence", rs.getString("STEP_SEQUENCE"));
            map.put("stepNumberInProcess", rs.getString("STEP_NUMBER_IN_PROCESS"));
            map.put("holdTimestamp", rs.getString("HOLD_TIMESTAMP"));
            map.put("reworkTransRrn", rs.getString("REWORK_TRANS_RRN"));
            map.put("reworkCategory", rs.getString("REWORK_CATEGORY"));
            map.put("carrierRrn", rs.getString("CARRIER_RRN"));
            map.put("beforeStatus", rs.getString("BEFORE_STATUS"));
            map.put("lotStatus", rs.getString("LOT_STATUS"));
            map.put("processingStatus", rs.getString("PROCESSING_STATUS"));
            map.put("queueTimestamp", rs.getString("QUEUE_TIMESTAMP"));
            map.put("productRrn", rs.getString("PRODUCT_RRN"));
            map.put("processRrn", rs.getString("PROCESS_RRN"));
            map.put("processVersion", rs.getString("PROCESS_VERSION"));
            map.put("processStepVersion", rs.getString("PROCESS_STEP_VERSION"));
            map.put("processStepIdVersion", rs.getString("PROCESS_STEP_ID_VERSION"));
            map.put("prevOperationRrn", rs.getString("PREV_OPERATION_RRN"));
            map.put("prevOperationVersion", rs.getString("PREV_OPERATION_VERSION"));
            map.put("operationRrn", rs.getString("OPERATION_RRN"));
            map.put("operationVersion", rs.getString("OPERATION_VERSION"));
            map.put("nextStepVersion1", rs.getString("NEXT_STEP_VERSION1"));
            map.put("nextStepIdVersion1", rs.getString("NEXT_STEP_ID_VERSION1"));
            map.put("nextOperationRrn1", rs.getString("NEXT_OPERATION_RRN1"));
            map.put("nextStepVersion2", rs.getString("NEXT_STEP_VERSION2"));
            map.put("nextStepIdVersion2", rs.getString("NEXT_STEP_ID_VERSION2"));
            map.put("nextOperationRrn2", rs.getString("NEXT_OPERATION_RRN2"));
            map.put("stageId", rs.getString("STAGE_ID"));
            map.put("layerId", rs.getString("LAYER_ID"));
            map.put("borRrn", rs.getString("BOR_RRN"));
            map.put("eqptRrn", rs.getString("EQPT_RRN"));
            map.put("customerId", rs.getString("CUSTOMER_ID"));
            map.put("outerOrderNo", rs.getString("OUTERORDERNO"));
            map.put("outOrderType", rs.getString("OUT_ORDER_TYPE"));
            map.put("shippingCode", rs.getString("SHIPPINGCODE"));
            map.put("lotPlanType", rs.getString("LOT_PLAN_TYPE"));

            return map;
        });
    }

    @Override
    public Map<String, Object> getTransRrnAndSequenceForDataCollectionTrans(Long dcolRrn) {
        String sql =
                "SELECT TRANS_RRN, TRANS_SEQUENCE FROM " + DataBaseNames.LOT_TRANS_HISTORY + " WHERE DCOL_RRN = ? ";
        return jdbcTemplate.queryForObject(sql, (RowMapper<Map<String, Object>>) (rs, rowNum) -> {
            Map<String, Object> map = new HashMap<>();
            map.put("transRrn", rs.getLong("TRANS_RRN"));
            map.put("transSequence", rs.getInt("TRANS_SEQUENCE"));
            return map;
        }, dcolRrn);
    }

    @Override
    public String getDataCollectionUrlForDataCollectionTrans(long transRrn, Integer transSequence) {
        String sql =
                "SELECT SPC_URLS FROM LOT_DATA_COLLECTION_HISTORY " + " WHERE TRANS_RRN = ? AND TRANS_SEQUENCE = ? ";
        List<String> list = jdbcTemplate
                .query(sql, (RowMapper<String>) (rs, rowNum) -> rs.getString("SPC_URLS"), transRrn, transSequence);
        return list.size() > 0 ? list.get(0) : null;
    }

    @Override
    public int getLotReworkCountBySubplan(Long lotRrn, String processStepVersion, String time) {
        String sql = "select count(*) from rework_info_history rh, transaction_log t " +
                " where t.trans_rrn = rh.trans_rrn and lot_rrn = ? and process_step_version like ? ";
        List args = new ArrayList();
        args.add(lotRrn);
        args.add(processStepVersion + "%");
        if (StringUtils.isNotBlank(time)) {
            sql += " AND t.trans_start_timestamp <= to_date( ?, 'yyyy/mm/dd hh24:mi:ss')";
            args.add(time);
        }
        return jdbcTemplate.queryForObject(sql, args.toArray(), Integer.class);
    }

    @Override
    public Page getLotReworkHistoryInfoList(Page page, Map condition) {
        String sql = "SELECT T.TRANS_START_TIMESTAMP,R.TRANS_RRN,R.LOT_RRN,L.LOT_ID,R.STEP_SEQUENCE,R.PROCESS_RRN," +
                "R.PROCESS_STEP_VERSION,R.PROCESS_VERSION,R.REWORK_COUNT,R.SUM_REWORK_COUNT," +
                "R.REWORK_PROCESS_STEP_VERSION,R.RETURN_PROCESS_STEP_VERSION,E.ATTRIBUTE_DATA3," +
                "E.FLAG FROM REWORK_INFO_HISTORY R,rework_info_ext_history E, TRANSACTION_LOG T, LOT L " +
                " WHERE T.TRANS_RRN = R.TRANS_RRN AND L.LOT_RRN = E.LOT_RRN " +
                " AND R.LOT_RRN = E.LOT_RRN AND R.TRANS_RRN = E.TRANS_RRN ";

        List<Object> args = new ArrayList<Object>();

        if (MapUtils.getLong(condition, "lotRrn") != null) {
            sql += " AND R.LOT_RRN IN (SELECT LOT_RRN FROM LOT WHERE BASED_LOT_RRN = ? OR LOT_RRN = ?) ";
            args.add(MapUtils.getLong(condition, "lotRrn"));
            args.add(MapUtils.getLong(condition, "lotRrn"));
        }

        if (MapUtils.getLong(condition, "reworkRouteRrn") != null) {
            sql += " AND to_number(E.ATTRIBUTE_DATA3) = ?";
            args.add(MapUtils.getLong(condition, "reworkRouteRrn"));
        }

        if (MapUtils.getLong(condition, "transRrn") != null) {
            sql += " AND R.TRANS_RRN = ?";
            args.add(MapUtils.getLong(condition, "transRrn"));
        }

        sql += " ORDER BY T.TRANS_START_TIMESTAMP DESC";

        return jdbcTemplate.queryForPage(page, sql, args.toArray(), new RowMapper<Map<String, Object>>() {

            @Override
            public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map<String, Object> map = new HashMap<String, Object>();
                map.put("transRrn", rs.getLong("TRANS_RRN"));
                map.put("transStartTimestamp", rs.getTimestamp("TRANS_START_TIMESTAMP"));
                map.put("lotRrn", rs.getLong("LOT_RRN"));
                map.put("lotId", rs.getString("LOT_ID"));
                map.put("stepSequence", rs.getLong("STEP_SEQUENCE"));
                map.put("processRrn", rs.getLong("PROCESS_RRN"));
                map.put("processVersion", rs.getInt("PROCESS_VERSION"));
                map.put("processStepVersion", rs.getString("PROCESS_STEP_VERSION"));
                map.put("reworkCount", rs.getInt("REWORK_COUNT"));
                map.put("reworkProcessStepVersion", rs.getString("REWORK_PROCESS_STEP_VERSION"));
                map.put("returnProcessStepVersion", rs.getString("RETURN_PROCESS_STEP_VERSION"));
                map.put("sumReworkCount", rs.getInt("SUM_REWORK_COUNT"));
                map.put("reworkRouteRrn", NumberUtils.toLong(rs.getString("ATTRIBUTE_DATA3")));
                map.put("flag", rs.getString("FLAG"));
                return map;
            }
        });
    }

    @Override
    public long getReworkCount(Long lotRrn, String processStepVersion) {
        String sql = "SELECT MAX(T.REWORK_COUNT) AS NUM FROM  REWORK_INFO_HISTORY T " +
                " WHERE T.LOT_RRN = ? AND T.PROCESS_STEP_VERSION LIKE ? ";

        return jdbcTemplate.queryForObjectWithNull(sql, long.class, lotRrn, processStepVersion + "%");
    }

    @Override
    public LotProcessStepInfo getLotProcessStepInfo(long lotRrn, String stepType) {
        String sql = "SELECT LOT_RRN, LOT_ID, STEP_TYPE, PROCESS_LOT_RRN, PROCESS_LOT_ID, " +
                "PROCESS_EQP_RRN, PROCESS_EQP_ID, PROCESS_RECIPE, " +
                "FLOW_SEQ, STEP_RRN, STAGE_ID, TRACK_OUT_TIME, PROCESS_STEP_VERSION, PROCESS_STEP_ID_VERSION " +
                "FROM LOT_PROCESS_STEP_INFO WHERE LOT_RRN = ? AND STEP_TYPE = ? ";

        RowMapper<LotProcessStepInfo> rowMapper = new RowMapper<LotProcessStepInfo>() {
            private LotProcessStepInfo lotProcessStepInfo;

            @Override
            public LotProcessStepInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
                lotProcessStepInfo = new LotProcessStepInfo();
                lotProcessStepInfo.setLotRrn(rs.getLong("LOT_RRN"));
                lotProcessStepInfo.setLotId(rs.getString("LOT_ID"));
                lotProcessStepInfo.setStepType(rs.getString("STEP_TYPE"));
                lotProcessStepInfo.setProcessLotRrn(rs.getLong("PROCESS_LOT_RRN"));
                lotProcessStepInfo.setProcessLotId(rs.getString("PROCESS_LOT_ID"));
                lotProcessStepInfo.setProcessEqpRrn(rs.getLong("PROCESS_EQP_RRN"));
                lotProcessStepInfo.setProcessEqpId(rs.getString("PROCESS_EQP_ID"));
                lotProcessStepInfo.setProcessRecipe(rs.getString("PROCESS_RECIPE"));
                lotProcessStepInfo.setFlowSeq(rs.getString("FLOW_SEQ"));
                lotProcessStepInfo.setStepRrn(rs.getLong("STEP_RRN"));
                lotProcessStepInfo.setStageId(rs.getString("STAGE_ID"));
                lotProcessStepInfo.setTrackOutTime(rs.getTimestamp("TRACK_OUT_TIME"));
                lotProcessStepInfo.setProcessStepVersion(rs.getString("PROCESS_STEP_VERSION"));
                lotProcessStepInfo.setProcessStepIdVersion(rs.getString("PROCESS_STEP_ID_VERSION"));
                return lotProcessStepInfo;
            }
        };
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{lotRrn, stepType}, rowMapper);
    }

    @Override
    public Double getParameterValueForLot(Lot lot) {
        String sql = "SELECT ROUND(AVG(SD.AVERAGE_VALUE),4) FROM SAMPLE_DATA SD" +
                " WHERE SD.DCOL_RRN = (SELECT AD_HOC_DCOL_RRN FROM" +
                " (SELECT LSH.AD_HOC_DCOL_RRN FROM LOT_STEP_HISTORY LSH" +
                " WHERE LSH.LOT_RRN = ? ORDER BY LSH.STEP_SEQUENCE DESC) WHERE ROWNUM = 1)";

        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{lot.getLotRrn()}, Double.class);
    }

    @Override
    public List<Map<String, String>> isMultipathRunningHoldStep(Lot lot) {
        String sql = "SELECT REASON_CODE, TRANS_ID FROM" +
                " (SELECT TR.REASON_CODE, TL.TRANS_ID FROM TRANS_REASON TR, LOT_TRANS_HISTORY LTH, TRANSACTION_LOG TL" +
                " WHERE LTH.TRANS_RRN = TR.TRANS_RRN AND TL.TRANS_RRN = LTH.TRANS_RRN AND LTH.LOT_RRN = ?" +
                " AND LTH.STEP_SEQUENCE = ? AND TL.TRANS_ID IN ('CANCELMOVEIN', 'HOLD_RUNNING_LOT')" +
                " ORDER BY TL.TRANS_END_TIMESTAMP DESC)";

        return jdbcTemplate
                .query(sql, new Object[]{lot.getLotRrn(), lot.getStepSequence()}, new RowMapper<Map<String, String>>() {

                    @Override
                    public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                        Map<String, String> map = new HashMap<String, String>();
                        map.put("reasonCode", rs.getString("REASON_CODE"));
                        map.put("transId", rs.getString("TRANS_ID"));
                        return map;
                    }
                });
    }

    @Override
    public List<LotRecycledInfo> queryUnitRecycledInfoByLotNoVersion(LotRecycledInfo lotRecycledInfo) {
        String sql = "SELECT max(loop_count) loop_count, ? as lot_rrn, process_rrn,start_route_rrn," +
                " start_operation_rrn,end_route_rrn,end_operation_rrn,process_version FROM unit_recycled h " +
                " where unit_rrn in (select unit_rrn from unit where lot_rrn = ?) and " +
                " process_rrn=? group by process_rrn, start_route_rrn, start_operation_rrn," +
                " end_route_rrn,end_operation_rrn,process_version";

        List<LotRecycledInfo> lotRecycledInfos = jdbcTemplate.query(sql,
                                                                    new Object[]{new Long(lotRecycledInfo.getLotRrn()),
                                                                                 new Long(lotRecycledInfo.getLotRrn()),
                                                                                 new Long(lotRecycledInfo
                                                                                                  .getProcessRrn())},
                                                                    new RowMapper<LotRecycledInfo>() {

                                                                        @Override
                                                                        public LotRecycledInfo mapRow(ResultSet rs,
                                                                                                      int rowNum) throws SQLException {
                                                                            LotRecycledInfo lotRecycledInfo =
                                                                             new LotRecycledInfo();

                                                                            lotRecycledInfo
                                                                                    .setLotRrn(rs.getLong("lot_rrn"));
                                                                            lotRecycledInfo.setProcessRrn(
                                                                                    rs.getLong("process_rrn"));
                                                                            lotRecycledInfo.setStartRouteRrn(
                                                                                    rs.getLong("start_route_rrn"));
                                                                            lotRecycledInfo.setStartOperationRrn(
                                                                                    rs.getLong("start_operation_rrn"));
                                                                            lotRecycledInfo.setEndRouteRrn(
                                                                                    rs.getLong("end_route_rrn"));
                                                                            lotRecycledInfo.setEndOperationRrn(
                                                                                    rs.getLong("end_operation_rrn"));
                                                                            lotRecycledInfo.setLoopCount(
                                                                                    rs.getInt("loop_count"));
                                                                            lotRecycledInfo.setProcessVersion(
                                                                                    rs.getInt("process_version"));

                                                                            return lotRecycledInfo;
                                                                        }
                                                                    });

        return lotRecycledInfos;
    }

    @Override
    public List<Map> queryLotLoopInfo(long lotRrn, long processRrn, int processVersion) {
        StringBuilder sb = new StringBuilder();
        sb.append("SELECT T.*, (SUM_LOOP_COUNT - LOOP_COUNT) AS REMAINDER_LOOP_COUNT,");
        sb.append(" GETINSTANCEID(PROCESS_RRN) PROCESS_ID,GETINSTANCEID(START_ROUTE_RRN) START_ROUTE_ID,");
        sb.append(" GETINSTANCEID(START_OPERATION_RRN) START_OPERATION_ID,GETINSTANCEID(END_ROUTE_RRN) END_ROUTE_ID, ");
        sb.append(" GETINSTANCEID(END_OPERATION_RRN) END_OPERATION_ID, ");
        sb.append(" GETFLOWSEQ(PROCESS_RRN, START_ROUTE_RRN, START_OPERATION_RRN, PROCESS_VERSION) START_SEQ, ");
        sb.append(" GETFLOWSEQ(PROCESS_RRN, END_ROUTE_RRN, END_OPERATION_RRN, PROCESS_VERSION) END_SEQ FROM ");
        sb.append(" (SELECT PROCESS_RRN,PROCESS_VERSION, START_ROUTE_RRN, START_OPERATION_RRN, END_ROUTE_RRN, ");
        sb.append(" END_OPERATION_RRN, SUM_LOOP_COUNT, MAX(LOOP_COUNT) LOOP_COUNT FROM UNIT_RECYCLED WHERE ");
        sb.append(" UNIT_RRN IN (SELECT UNIT_RRN FROM UNIT WHERE LOT_RRN = ? ) AND PROCESS_RRN = ? ");
        sb.append(" AND PROCESS_VERSION = ? GROUP BY PROCESS_RRN,PROCESS_VERSION, START_ROUTE_RRN, ");
        sb.append(" START_OPERATION_RRN, END_ROUTE_RRN, END_OPERATION_RRN, SUM_LOOP_COUNT) T");
        return jdbcTemplate.query(sb.toString(), new Object[]{lotRrn, processRrn, processVersion}, (rs, rowNum) -> {
            Map result = new HashMap();
            result.put("processRrn", rs.getLong("PROCESS_RRN"));
            result.put("processVersion", rs.getLong("PROCESS_VERSION"));
            result.put("startRouteRrn", rs.getLong("START_ROUTE_RRN"));
            result.put("startOperationRrn", rs.getLong("START_OPERATION_RRN"));
            result.put("endRouteRrn", rs.getLong("END_ROUTE_RRN"));
            result.put("endOperationRrn", rs.getLong("END_OPERATION_RRN"));
            result.put("loopCount", rs.getLong("LOOP_COUNT"));
            result.put("remainderLoopCount", rs.getLong("REMAINDER_LOOP_COUNT"));
            result.put("sumLoopCount", rs.getLong("SUM_LOOP_COUNT"));
            result.put("processId", rs.getString("PROCESS_ID"));
            result.put("startRouteId", rs.getString("START_ROUTE_ID"));
            result.put("startOperationId", rs.getString("START_OPERATION_ID"));
            result.put("endRouteId", rs.getString("END_ROUTE_ID"));
            result.put("endOperationId", rs.getString("END_OPERATION_ID"));
            result.put("startSeq", rs.getString("START_SEQ"));
            result.put("endSeq", rs.getString("END_SEQ"));
            return result;
        });
    }

    @Override
    public Page queryLotLoopHistoryInfo(Page page, long lotRrn, long processRrn) {
        StringBuilder sb = new StringBuilder("SELECT * FROM (SELECT L.LOT_ID, T.TRANS_END_TIMESTAMP, H.*,");
        sb.append(" (H.SUM_LOOP_COUNT - H.LOOP_COUNT) AS REMAINDER_LOOP_COUNT, ");
        sb.append(" GETINSTANCEID(H.PROCESS_RRN ) PROCESS_ID,GETINSTANCEID(H.START_OPERATION_RRN) START_OPERATION_ID,");
        sb.append(" GETINSTANCEID(H.START_ROUTE_RRN) START_ROUTE_ID, GETINSTANCEID(H.END_ROUTE_RRN) END_ROUTE_ID,");
        sb.append(" GETINSTANCEID(H.END_OPERATION_RRN) END_OPERATION_ID,");
        sb.append(" GETFLOWSEQ(H.PROCESS_RRN, H.START_ROUTE_RRN, H.START_OPERATION_RRN, H.PROCESS_VERSION) START_SEQ,");
        sb.append(" GETFLOWSEQ(H.PROCESS_RRN, H.END_ROUTE_RRN, H.END_OPERATION_RRN, H.PROCESS_VERSION ) END_SEQ");
        sb.append(" FROM(SELECT PROCESS_RRN,PROCESS_VERSION, START_ROUTE_RRN, START_OPERATION_RRN, END_ROUTE_RRN, ");
        sb.append(" END_OPERATION_RRN, SUM_LOOP_COUNT, MAX(LOOP_COUNT) LOOP_COUNT, TRANS_RRN, LOT_RRN, STEP_SEQUENCE ");
        sb.append(" FROM UNIT_RECYCLED_H WHERE LOT_RRN IN(SELECT LOT_RRN FROM LOT WHERE BASED_LOT_RRN=? OR LOT_RRN=?)");
        sb.append(" AND PROCESS_RRN = ? GROUP BY PROCESS_RRN,PROCESS_VERSION, START_ROUTE_RRN, START_OPERATION_RRN, ");
        sb.append(" END_ROUTE_RRN, END_OPERATION_RRN, SUM_LOOP_COUNT, TRANS_RRN, LOT_RRN, STEP_SEQUENCE)");
        sb.append(" H, TRANSACTION_LOG T, LOT L WHERE H.LOT_RRN = L.LOT_RRN AND H.TRANS_RRN = T.TRANS_RRN");
        sb.append(" AND LOOP_COUNT > 0)ORDER BY TRANS_END_TIMESTAMP DESC");

        return jdbcTemplate
                .queryForPage(page, sb.toString(), new Object[]{lotRrn, lotRrn, processRrn}, (rs, rowNum) -> {
                    Map result = new HashMap();
                    result.put("lotId", rs.getString("lot_ID"));
                    result.put("transTimestamp", rs.getTimestamp("TRANS_END_TIMESTAMP"));
                    result.put("stepSeq", rs.getString("STEP_SEQUENCE"));
                    result.put("processRrn", rs.getLong("PROCESS_RRN"));
                    result.put("processVersion", rs.getLong("PROCESS_VERSION"));
                    result.put("startRouteRrn", rs.getLong("START_ROUTE_RRN"));
                    result.put("startOperationRrn", rs.getLong("START_OPERATION_RRN"));
                    result.put("endRouteRrn", rs.getLong("END_ROUTE_RRN"));
                    result.put("endOperationRrn", rs.getLong("END_OPERATION_RRN"));
                    result.put("loopCount", rs.getLong("LOOP_COUNT"));
                    result.put("sumLoopCount", rs.getLong("SUM_LOOP_COUNT"));
                    result.put("remainderLoopCount", rs.getLong("REMAINDER_LOOP_COUNT"));
                    result.put("processId", rs.getString("PROCESS_ID"));
                    result.put("startRouteId", rs.getString("START_ROUTE_ID"));
                    result.put("startOperationId", rs.getString("START_OPERATION_ID"));
                    result.put("endRouteId", rs.getString("END_ROUTE_ID"));
                    result.put("endOperationId", rs.getString("END_OPERATION_ID"));
                    result.put("startSeq", rs.getString("START_SEQ"));
                    result.put("endSeq", rs.getString("END_SEQ"));
                    return result;
                });
    }

    @Override
    public List<Map> queryUnitLoopInfo(LotRecycledInfo LotRecycledInfo) {
        StringBuilder sql = new StringBuilder();
        sql.append("select L.LOT_ID, U.UNIT_ID, U.POSITION_IN_CARRIER, T.* FROM LOT L, UNIT U LEFT JOIN(");
        sql.append(" SELECT UR.*, (UR.SUM_LOOP_COUNT - UR.LOOP_COUNT ) AS REMAINDER_LOOP_COUNT, ");
        sql.append(" GETINSTANCEID( ur.PROCESS_RRN ) PROCESS_ID, ");
        sql.append(" GETINSTANCEID( ur.START_OPERATION_RRN ) START_OPERATION_ID, ");
        sql.append(" GETINSTANCEID( ur.START_ROUTE_RRN ) START_ROUTE_ID, ");
        sql.append(" GETINSTANCEID( ur.END_ROUTE_RRN ) END_ROUTE_ID, ");
        sql.append(" GETINSTANCEID( ur.END_OPERATION_RRN ) END_OPERATION_ID, ");
        sql.append(
                " GETFLOWSEQ(ur.PROCESS_RRN,ur.START_ROUTE_RRN,ur.START_OPERATION_RRN,ur.PROCESS_VERSION) START_SEQ,");
        sql.append(" GETFLOWSEQ(ur.PROCESS_RRN,ur.END_ROUTE_RRN, ur.END_OPERATION_RRN, ur.PROCESS_VERSION) END_SEQ ");
        sql.append(" FROM UNIT_RECYCLED UR WHERE UR.LOT_RRN IN (SELECT LOT_RRN FROM ");
        sql.append(" LOT WHERE BASED_LOT_RRN = ? OR LOT_RRN = ?) AND UR.PROCESS_RRN = ? AND UR.PROCESS_VERSION = ? ");
        sql.append(" AND START_ROUTE_RRN = ? AND START_OPERATION_RRN = ? AND END_ROUTE_RRN = ?  ");
        sql.append(" AND END_OPERATION_RRN = ?) T ON U.UNIT_RRN = T.UNIT_RRN WHERE U.lot_RRN = L.LOT_RRN");
        sql.append(" AND U.LOT_RRN in (SELECT LOT_RRN FROM LOT WHERE BASED_LOT_RRN = ? OR LOT_RRN = ?)  ");
        sql.append(" ORDER BY U.POSITION_IN_CARRIER");

        return jdbcTemplate.query(sql.toString(), new Object[]{LotRecycledInfo.getLotRrn(), LotRecycledInfo.getLotRrn(),
                                                               LotRecycledInfo.getProcessRrn(),
                                                               LotRecycledInfo.getProcessVersion(),
                                                               LotRecycledInfo.getStartRouteRrn(),
                                                               LotRecycledInfo.getStartOperationRrn(),
                                                               LotRecycledInfo.getEndRouteRrn(),
                                                               LotRecycledInfo.getEndOperationRrn(),
                                                               LotRecycledInfo.getLotRrn(),
                                                               LotRecycledInfo.getLotRrn()}, (rs, rowNum) -> {
            Map result = new HashMap();
            result.put("lotId", rs.getString("LOT_ID"));
            result.put("unitId", rs.getString("UNIT_ID"));
            result.put("position", rs.getLong("POSITION_IN_CARRIER"));
            result.put("processRrn", rs.getLong("PROCESS_RRN"));
            result.put("processVersion", rs.getLong("PROCESS_VERSION"));
            result.put("startRouteRrn", rs.getLong("START_ROUTE_RRN"));
            result.put("startOperationRrn", rs.getLong("START_OPERATION_RRN"));
            result.put("endRouteRrn", rs.getLong("END_ROUTE_RRN"));
            result.put("endOperationRrn", rs.getLong("END_OPERATION_RRN"));
            result.put("loopCount", rs.getString("LOOP_COUNT"));
            result.put("remainderLoopCount", rs.getString("REMAINDER_LOOP_COUNT"));
            result.put("sumLoopCount", rs.getString("SUM_LOOP_COUNT"));
            result.put("processId", rs.getString("PROCESS_ID"));
            result.put("startRouteId", rs.getString("START_ROUTE_ID"));
            result.put("startOperationId", rs.getString("START_OPERATION_ID"));
            result.put("endRouteId", rs.getString("END_ROUTE_ID"));
            result.put("endOperationId", rs.getString("END_OPERATION_ID"));
            result.put("startSeq", rs.getString("START_SEQ"));
            result.put("endSeq", rs.getString("END_SEQ"));
            return result;
        });
    }

    @Override
    public List<Map> queryUnitReworkInfo(long lotRrn, String processStepVersion) {
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT L.LOT_ID, U.UNIT_ID, U.POSITION_IN_CARRIER, H.* FROM LOT L, UNIT U LEFT JOIN ( ");
        sql.append(" SELECT RH.UNIT_RRN, RH.SUM_REWORK_COUNT, MAX( RH.REWORK_COUNT ) REWORK_COUNT FROM ");
        sql.append(" REWORK_UNIT_INFO_HISTORY RH WHERE RH.UNIT_RRN IN ( SELECT UNIT_RRN FROM UNIT WHERE LOT_RRN IN ");
        sql.append(" ((SELECT LOT_RRN FROM LOT WHERE BASED_LOT_RRN = ? OR LOT_RRN = ?))) AND RH.PROCESS_STEP_VERSION ");
        sql.append(" LIKE ? GROUP BY RH.UNIT_RRN, RH.SUM_REWORK_COUNT) H ON U.UNIT_RRN = H.UNIT_RRN ");
        sql.append(" WHERE U.LOT_RRN = L.LOT_RRN AND U.LOT_RRN IN (SELECT LOT_RRN FROM LOT WHERE BASED_LOT_RRN = ? ");
        sql.append(" OR LOT_RRN = ?) ORDER BY U.POSITION_IN_CARRIER");

        return jdbcTemplate
                .query(sql.toString(), new Object[]{lotRrn, lotRrn, processStepVersion + "%", lotRrn, lotRrn},
                       (rs, rowNum) -> {
                           Map result = new HashMap();
                           result.put("lotId", rs.getString("LOT_ID"));
                           result.put("unitId", rs.getString("UNIT_ID"));
                           result.put("position", rs.getLong("POSITION_IN_CARRIER"));
                           result.put("sumReworkCount", rs.getLong("SUM_REWORK_COUNT"));
                           result.put("reworkCount", rs.getLong("REWORK_COUNT"));
                           return result;
                       });
    }
    @Override
    public List<Map> getBatchBankLots(Map map) {
        List<Object> args=new ArrayList<>();
        StringBuilder sql = new StringBuilder("SELECT");
        sql.append(" lt.lot_rrn, lt.lot_id, lt.lot_owner, lt.qty1, lt.qty2, pro.OPERATION_DESCRIPTION, pro.route_id, ");
        sql.append(" lt.lot_status, pro.stage_id, lt.product_rrn, lt.process_rrn, lt.PROCESS_VERSION,lt.PRODUCT_VERSION, ");
        sql.append(" lt.process_step_version, lt.process_step_id_version, pro.operation_rrn, pro.recipe_id, ");
        sql.append(" pro.PRODUCT_ID, pro.PROCESS_ID, pro.OPERATION_ID, pro.flow_seq, ");
        sql.append(" lt.facility_rrn, lt.eqpt_rrn, lt.product_layer, lt.route_seq, lt.product_version, ");
        sql.append(" lt.operation_seq, pro.ATTRIBUTE_DATA2 BANK_FLAG, pro.route_Rrn FROM lot lt, PRO_CONTEXT_ACTIVE_DTL pro  ");
        sql.append(" WHERE lt.PROCESS_RRN = pro.PROCESS_RRN  AND lt.PROCESS_VERSION = pro.PROCESS_VERSION ");
        sql.append(" AND pro.FLOW_SEQ = LT.FLOW_SEQ ");
        sql.append(" AND PRO.ATTRIBUTE_DATA2 = 'Y' AND lt.PRODUCT_RRN = pro.PRODUCT_RRN");
        sql.append(" AND lt.product_version = pro.product_version ");
        if (StringUtils.isNotEmptyTrim(MapUtils.getString(map, "lotStatus"))) {
            sql.append(" AND lt.LOT_STATUS = ? ");
            args.add(MapUtils.getString(map,"lotStatus"));
        }

        if (MapUtils.getLong(map, "productRrn") != null) {
            sql.append(" AND lt.product_rrn = ?");
            args.add(MapUtils.getLong(map, "productRrn"));
        }

        if (MapUtils.getLong(map, "processRrn") != null) {
            sql.append(" AND lt.process_rrn = ?");
            args.add(MapUtils.getLong(map, "processRrn"));
        }

        if (MapUtils.getInteger(map, "processVersion") != null){
            sql.append(" AND lt.PROCESS_VERSION = ?");
            args.add(MapUtils.getInteger(map, "processVersion"));
        }

        if (MapUtils.getInteger(map, "productVersion") != null){
            sql.append(" AND lt.PRODUCT_VERSION = ?");
            args.add(MapUtils.getInteger(map, "productVersion"));
        }

        if (StringUtils.isNotEmptyTrim(MapUtils.getString(map, "lotId"))) {
            sql.append(" AND lt.LOT_ID LIKE ?");
            args.add(MapUtils.getString(map, "lotId"));
        }

        if (MapUtils.getLong(map, "operationRrn") != null) {
            sql.append(" AND pro.operation_rrn = ?");
            args.add(MapUtils.getLong(map, "operationRrn"));
        }
        sql.append(" ORDER BY lt.lot_id ");
        return jdbcTemplate.query(sql.toString(), args.toArray(), new RowMapper<Map>() {
            @Override
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map m = new HashMap();
                m.put("seq", new Integer(rowNum));
                m.put("lotRrn", new Long(rs.getLong("lot_rrn")));
                m.put("lotId", rs.getString("lot_id"));
                m.put("lotOwner", rs.getString("lot_owner"));
                m.put("qty1", new Double(rs.getDouble("qty1")));
                m.put("qty2", new Double(rs.getDouble("qty2")));
                m.put("lotStatus", rs.getString("lot_status"));
                String processStepIdString = rs.getString("process_step_id_version");
                m.put("processStepIdVersion", processStepIdString);
                m.put("routeId", rs.getString("route_id"));
                m.put("operationRrn", rs.getLong("operation_rrn"));
                m.put("stageId", rs.getString("stage_id"));
                m.put("productRrn", rs.getLong("product_rrn"));
                m.put("processStepVersion", rs.getString("process_step_version"));
                m.put("processRrn", new Long(rs.getLong("process_rrn")));
                m.put("lotRrn", new Long(rs.getLong("lot_rrn")));
                m.put("lotId", rs.getString("lot_id"));
                m.put("facilityRrn", new Long(rs.getLong("facility_rrn")));
                m.put("productLayer", rs.getString("product_layer"));
                m.put("routeSeq", rs.getString("route_seq"));
                m.put("operationSeq", rs.getString("operation_seq"));
                m.put("processVersion", rs.getInt("PROCESS_VERSION"));
                m.put("entityRrn", rs.getLong("eqpt_rrn"));
                m.put("bankFlag", rs.getString("BANK_FLAG"));
                m.put("routeRrn", rs.getString("route_Rrn"));
                m.put("recipeId", rs.getString("recipe_id"));
                String operationDescription = rs.getString("OPERATION_DESCRIPTION");
                m.put("operationDesc", StringUtils.isNotBlank(operationDescription) ? operationDescription:StringUtils.EMPTY);
                m.put("productVersion", rs.getString("PRODUCT_VERSION"));
                m.put("productId", rs.getString("product_id"));
                m.put("processId", rs.getString("process_id"));
                m.put("operationId", rs.getString("operation_id"));
                m.put("flowSeq", rs.getString("flow_seq"));
                return m;
            }
        });
    }

    @Override
    public MultiLot getMultiLotByCarrierRrn(long carrierRrn) {
        String sql = getLotSql() + " WHERE CARRIER_RRN = ?";
        List<Lot> lotList = jdbcTemplate.query(sql, new Object[]{carrierRrn}, new LotMapper());
        return new MultiLot(lotList);
    }

    @Override
    public String getLotMoveInTime(String lotId, String equipmentId) {
        String sql = "select TO_CHAR(max(equipment_run_time),?) from equipment_run_history " +
                "where run_type in (?,?) and equipment_id = ? AND LOT_ID = ? ";
        Object[] args = {DateUtils.DATE_FORMAT24, EmasUtil.RUN_TYPE_MOVEIN, EmasUtil.RUN_TYPE_RUNCARDMOVEIN, equipmentId, lotId};
        return jdbcTemplate.queryForObjectWithNull(sql, args, String.class);
    }

    @Override
    public List<Map<String, Object>> getEqpRunLotRecipeMES(long eqpRrn, Date timePoint) {
        StringBuilder sql = new StringBuilder("select lsh.recipe_physical_id from ( ");
        sql.append("select tl.trans_start_timestamp,lth.lot_rrn,lth.step_sequence,lth.trans_id, ");
        sql.append("rank()over(partition by lth.lot_rrn,lth.step_sequence order by tl.trans_start_timestamp desc) ");
        sql.append("as row_num from transaction_log tl, lot_trans_history lth ");
        sql.append("where tl.trans_start_timestamp > ? and tl.trans_rrn = lth.trans_rrn ) a, ");
        sql.append("lot_step_history lsh where row_num = 1 and (trans_id = 'MOVEIN' or trans_id = 'MOVEOUT') ");
        sql.append("and lsh.eqpt_rrn = ? and a.lot_rrn = lsh.lot_rrn and a.step_sequence = lsh.step_sequence ");

        Object[] args = new Object[]{timePoint, eqpRrn};
        return jdbcTemplate.query(sql.toString(), args, (RowMapper<Map<String, Object>>) (rs, rowNum) -> {
            Map<String, Object> map = new HashMap<>();
            map.put("recipeId", rs.getString("recipe_physical_id"));
            return map;
        });
    }

    @Override
    public List<Map<String, Object>> getEqpRunWaferRecipeMES(long eqpRrn, Date timePoint) {
        StringBuilder sql = new StringBuilder("select lsh.recipe_physical_id from ( ");
        sql.append("select tl.trans_start_timestamp,lth.lot_rrn,lth.step_sequence,lth.trans_id, ");
        sql.append("rank()over(partition by lth.lot_rrn,lth.step_sequence order by tl.trans_start_timestamp desc) ");
        sql.append("as row_num from transaction_log tl, lot_trans_history lth ");
        sql.append("where tl.trans_start_timestamp > ? and tl.trans_rrn = lth.trans_rrn ) a, ");
        sql.append("lot_step_history lsh, carrier_mapping cm where row_num = 1 ");
        sql.append("and (trans_id = 'MOVEIN' or trans_id = 'MOVEOUT') ");
        sql.append("and lsh.eqpt_rrn = ? and a.lot_rrn = lsh.lot_rrn ");
        sql.append("and a.step_sequence = lsh.step_sequence and lsh.carrier_map_rrn = cm.carrier_map_rrn ");

        Object[] args = new Object[]{timePoint, eqpRrn};
        return jdbcTemplate.query(sql.toString(), args, (RowMapper<Map<String, Object>>) (rs, rowNum) -> {
            Map<String, Object> map = new HashMap<>();
            map.put("recipeId", rs.getString("recipe_physical_id"));
            return map;
        });
    }

    @Override
    public List<Map<String, Object>> getEqpRunLotRecipeMESByEqpRunHist(String eqpId, Date timePoint) {
        StringBuilder sql = new StringBuilder("select t.physical_recipe_id from equipment_run_history t ");
        sql.append("where t.equipment_run_time > ? and t.run_type in (?,?) and t.equipment_id = ? ");

        Object[] args = new Object[]{timePoint, EmasUtil.RUN_TYPE_MOVEIN, EmasUtil.RUN_TYPE_RUNCARDMOVEIN, eqpId};
        return jdbcTemplate.query(sql.toString(), args, (RowMapper<Map<String, Object>>) (rs, rowNum) -> {
            Map<String, Object> map = new HashMap<>();
            map.put("recipeId", rs.getString("physical_recipe_id"));
            return map;
        });
    }

    @Override
    public List<Map<String, Object>> getEqpRunWaferRecipeMESByEqpRunHist(String eqpId, Date timePoint) {
        StringBuilder sql = new StringBuilder("select t.physical_recipe_id from equipment_run_history t, ");
        sql.append("carrier_mapping cm where t.carrier_map_rrn = cm.carrier_map_rrn and ");
        sql.append("t.equipment_run_time > ? and t.run_type in (?,?) and t.equipment_id = ? ");

        Object[] args = new Object[]{timePoint, EmasUtil.RUN_TYPE_MOVEIN, EmasUtil.RUN_TYPE_RUNCARDMOVEIN, eqpId};
        return jdbcTemplate.query(sql.toString(), args, (RowMapper<Map<String, Object>>) (rs, rowNum) -> {
            Map<String, Object> map = new HashMap<>();
            map.put("recipeId", rs.getString("physical_recipe_id"));
            return map;
        });
    }

    @Override
    public List<Map<String, Object>> getEqpRunLotRecipeEAP(String eqpId, String chamberType, Date timePoint) {
        StringBuilder sql = new StringBuilder();
        List<Object> args = new ArrayList<>();
        args.add(eqpId);
        args.add(timePoint);
        if (StringUtils.isNotBlank(chamberType)) {
            sql.append("select recipe_id from elog_sheet_chamber ");
            sql.append("where equipment_id = ? and process_start_time > ? and chamber_type = ? ");
            args.add(chamberType);
        } else {
            sql.append("select recipe_id from elog_sheet where equipment_id = ? and process_start_time > ? ");
        }

        return jdbcTemplate.query(sql.toString(), args.toArray(), (RowMapper<Map<String, Object>>) (rs, rowNum) -> {

            Map<String, Object> map = new HashMap<>();
            map.put("recipeId", rs.getString("recipe_id"));
            return map;
        });
    }

    @Override
    public List<Map<String, Object>> getEqpRunWaferRecipeEAP(String eqpId, String chamberType, Date timePoint) {
        StringBuilder sql = new StringBuilder();
        List<Object> args = new ArrayList<>();
        args.add(eqpId);
        args.add(timePoint);
        if (StringUtils.isNotBlank(chamberType)) {
            sql.append("select recipe_id,qty wafer_qty from elog_sheet_chamber ");
            sql.append("where equipment_id = ? and process_start_time > ? and chamber_type = ? ");
            args.add(chamberType);
        } else {
            sql.append("select recipe_id,chamber_qty wafer_qty from elog_sheet ");
            sql.append("where equipment_id = ? and process_start_time > ? ");
        }

        return jdbcTemplate.query(sql.toString(), args.toArray(), (RowMapper<Map<String, Object>>) (rs, rowNum) -> {

            Map<String, Object> map = new HashMap<>();
            map.put("recipeId", rs.getString("recipe_id"));
            map.put("qty", rs.getString("wafer_qty"));
            return map;
        });
    }

    @Override
    public Long getLotCountFormHistoryByCondition(String sql, List<Object> args) {
        Long count = jdbcTemplate.queryForObjectWithNull(sql, args.toArray(), Long.class);
        return count == null ? 0L : count;
    }

    public List getProcessRrn4FutureLots(long operationRrn) {
        String sql = "SELECT P.STEP_SEQ, P.PROCESS_RRN FROM process_workflow_hist P WHERE P" + ".OPERATION_RRN = ? " +
                "ORDER BY P.STEP_SEQ";
        return jdbcTemplate.query(sql, new RowMapper() {

            @Override
            public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map eqptInfo = new HashMap();
                eqptInfo.put("STEP_SEQ", new Long(rs.getInt("STEP_SEQ")));
                eqptInfo.put("PROCESS_RRN", new Long(rs.getInt("PROCESS_RRN")));
                return eqptInfo;
            }

        }, operationRrn);
    }

    public String getOperationFutureLots(long operationRrn, long operationSeq) {
        final Set rrnSet = new HashSet();
        rrnSet.add("0");
        List processFlowHistList = getProcessRrn4FutureLots(operationRrn);

        for (Iterator iterator = processFlowHistList.iterator(); iterator.hasNext(); ) {
            Map eqptInfo = (HashMap) iterator.next();
            String sql = "SELECT DISTINCT OPERATION_RRN OPERATION_RRN FROM " + "(SELECT P.OPERATION_RRN FROM " +
                    "PROCESS_WORKFLOW_HIST P " + "WHERE P.STEP_SEQ >= ? AND P.STEP_SEQ <= ? AND P.PROCESS_RRN = ? " +
                    "AND " + "instr(P.OPERATION_RRN,?) < 1 ORDER BY P.STEP_SEQ) T";

            Long stepSeq = MapUtils.getLong(eqptInfo, "STEP_SEQ");
            Long minStepSeq = new Long(stepSeq.longValue() - operationSeq);

            Object[] args = new Object[]{minStepSeq, stepSeq, MapUtils.getLong(eqptInfo, "PROCESS_RRN"),
                                         rrnSet.toString().replaceAll("\\[", "").replaceAll("\\]", "")};

            jdbcTemplate.query(sql, args, new RowMapper() {

                @Override
                public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                    rrnSet.add(rs.getString(1));
                    return null;
                }
            });
        }
        return rrnSet.toString().replaceAll("\\[", "").replaceAll("\\]", "");
    }

    public long getqueueTime(String lotId) {
        long statusTime = 0;
        String sql = "select QUEUE_TIMESTAMP from lot where lot_id = ?";
        Timestamp queueTime = jdbcTemplate.queryForObjectWithNull(sql, new Object[]{lotId}, Timestamp.class);
        if (queueTime != null) {
            statusTime = (new java.util.Date().getTime() - queueTime.getTime()) / (60 * 1000);
        }
        return statusTime;
    }

    public String getLotSql() {
        String sql = "SELECT FACILITY_RRN,LOT_ID,BASED_LOT_RRN,CREATED_PLAN_LOT_RRN," + "HOT_FLAG,PRIORITY," +
                "STARTED_FLAG,STARTED_TIMESTAMP,CREATE_CATEGORY," + "CREATED_TIMESTAMP," +
                "END_TIMESTAMP,DUE_DATE,SCHEDULE_DUE_DATE," + "LATE_SCHEDULED_FLAG," +
                "ESTIMATED_REMAIN_TIME,DUMMY_FLAG,LOT_TYPE," + "LOT_OWNER,QTY1,QTY2,DUMMY_QTY1," +
                "INPUT_QTY1,INPUT_QTY2,SUBCONTRACTOR_RRN," + "LOT_COMMENTS,STEP_SEQUENCE," +
                "STEP_NUMBER_IN_PROCESS,HOLD_TIMESTAMP," + "REWORK_TRANS_RRN,REWORK_CATEGORY," +
                "CARRIER_RRN,BEFORE_STATUS," + "LOT_STATUS,PROCESSING_STATUS, QUEUE_TIMESTAMP," +
                "PRODUCT_RRN, PRODUCT_VERSION," + "PROCESS_RRN,PROCESS_VERSION,PROCESS_STEP_VERSION," +
                "PROCESS_STEP_ID_VERSION,PREV_OPERATION_RRN,PREV_OPERATION_VERSION,OPERATION_RRN," +
                "OPERATION_VERSION," + "NEXT_STEP_VERSION1,NEXT_STEP_ID_VERSION1,NEXT_OPERATION_RRN1," +
                "NEXT_STEP_VERSION2,NEXT_STEP_ID_VERSION2,NEXT_OPERATION_RRN2," +
                "STAGE_ID,LAYER_ID,BOR_RRN,EQPT_RRN,RECIPE_STRING," +
                "NEXT_RECIPE_STRING1,NEXT_RECIPE_STRING2,JOB_RRN," +
                "NEXT_JOB_RRN1,NEXT_JOB_RRN2,EXECUTION_RRN,LOT_RRN,WFL_STEP_PATH,RETICLE_RRN,ROUND(" +
                "(GETMINREMAINTIMEBYLOTRRN(LOT_RRN, '" + Constants.TIME_LIMIT.TIME_TYPE_MAX +
                "') / 3600), 2) AS Q_TIME," +
                "SHIPPED_QTY1,SHIPPED_QTY2,PRODUCT_LAYER,ROUTE_SEQ,OPERATION_SEQ,RECIPE_LOGICAL_RRN," +
                "RECIPE_PHYSICAL_ID,CHAMBER_TYPE,IS_SAPPHIRE,LOT_PLAN_TYPE,FLOW_SEQ,OPERATION_DESC," +
                "PROCESS_LOCATION,IS_DUMMY_LOT FROM " + DataBaseNames.LOT;

        return sql;
    }

    private String getInstanceIdSql(ShipQueryConditionDto sqcd, List<Object> args) {
        return "SELECT INSTANCE_RRN,INSTANCE_ID FROM NAMED_OBJECT WHERE INSTANCE_RRN IN ("
                + " SELECT CARRIER_RRN FROM " + DataBaseNames.LOT + buildParameter(sqcd, args, StringUtils.EMPTY)
                + " UNION SELECT PRODUCT_RRN FROM " + DataBaseNames.LOT + buildParameter(sqcd, args, StringUtils.EMPTY)
                + " UNION SELECT PROCESS_RRN FROM " + DataBaseNames.LOT + buildParameter(sqcd, args, StringUtils.EMPTY)
                + " UNION SELECT OPERATION_RRN FROM " + DataBaseNames.LOT + buildParameter(sqcd, args, StringUtils.EMPTY)
                + " UNION SELECT NEXT_OPERATION_RRN1 FROM " + DataBaseNames.LOT + buildParameter(sqcd, args, StringUtils.EMPTY)
                + " UNION SELECT NEXT_OPERATION_RRN2 FROM " + DataBaseNames.LOT + buildParameter(sqcd, args, StringUtils.EMPTY)
                + " UNION SELECT EQPT_RRN FROM " + DataBaseNames.LOT + buildParameter(sqcd, args, StringUtils.EMPTY)
                + " UNION SELECT RETICLE_RRN FROM " + DataBaseNames.LOT + buildParameter(sqcd, args, StringUtils.EMPTY)
                + " UNION SELECT RECIPE_LOGICAL_RRN FROM " + DataBaseNames.LOT + buildParameter(sqcd, args, StringUtils.EMPTY)
                + " UNION SELECT DISTINCT CASE WHEN PROCESS_STEP_VERSION IS NULL THEN 0 "
                + " WHEN INSTR(PROCESS_STEP_VERSION,'|',1,2) > 0 THEN TO_NUMBER(SUBSTR(PROCESS_STEP_VERSION,"
                + " INSTR(PROCESS_STEP_VERSION,'|',1,1)+1, INSTR(PROCESS_STEP_VERSION,',',1,1)-1)) "
                + " WHEN INSTR(PROCESS_STEP_VERSION,'|',1,1) > 0 THEN TO_NUMBER(SUBSTR(PROCESS_STEP_VERSION,"
                + " 1, INSTR(PROCESS_STEP_VERSION,',',1,1)-1)) ELSE 0 END FROM " + DataBaseNames.LOT + buildParameter(sqcd, args, StringUtils.EMPTY)
                + " )";
    }

    private String buildFuture(String operationStep, Long operationRrn) {
        String sql;
        String operationRrns = "";
        if (!"0".equals(operationStep)) {
            String sqlString = this.getOperationFutureLots(operationRrn.longValue(), Long.parseLong(operationStep));
            operationRrns += sqlString + ",";
            sql = " where operation_rrn in (" + sqlString + ") and lot_status <> '" + LotStatus.TERMINATED + "' and " +
                    "lot_status<>'" + LotStatus.SCRAPPED + "' and lot_status<>'" + LotStatus.LOSSED +
                    "' and lot_status<>'" + LotStatus.FINISH + "' ORDER BY OPERATION_RRN";
        } else {
            sql = " where operation_rrn in (" + operationRrn.longValue() + ") and lot_status <> '" +
                    LotStatus.TERMINATED + "' and lot_status<>'" + LotStatus.SCRAPPED + "' and lot_status<>'" +
                    LotStatus.LOSSED + "' and lot_status<>'" + LotStatus.FINISH + "'  ORDER BY OPERATION_RRN";
        }
        return sql;
    }

    private List<Long> getLotExecuted(long productRrn, long processRrn, long routeRrn, long operationRrn, long lotRrn) {
        String sql = "SELECT L.LOT_RRN FROM LOT_TRANS_HISTORY L, LOT_STEP_HISTORY H, TRANS_REASON R," + "(SELECT V" +
                ".CONTEXT_KEY1 AS PRODUCT_RRN, V.CONTEXT_KEY2 AS PROCESS_RRN,V.CONTEXT_KEY3" + " AS ROUTE_RRN, " + "V" +
                ".CONTEXT_KEY4 AS OPERATION_RRN, V.SEQUENCE_NUMBER, V.RESULT_VALUE2, V" +
                ".RESULT_VALUE3 AS HOLDGROUP," +
                " V.RESULT_VALUE4 AS HOLDCODE, V.RESULT_VALUE5 AS HOLDREASON, V.RESULT_VALUE1 AS " + "ACTIONRRN  " +
                "FROM " + "CONTEXT_VALUE V WHERE V.CONTEXT_RRN = (SELECT L.INSTANCE_RRN FROM NAMED_OBJECT" + " L " +
                "WHERE L" + ".INSTANCE_ID='EEN_CONTEXT_HOLDPRODUCT' AND L.NAMED_SPACE='MYCIM2') AND V" +
                ".CONTEXT_KEY1 = ?)C " + "WHERE L.LOT_RRN = H.LOT_RRN AND L.TRANS_ID = 'HOLD' AND H.STEP_SEQUENCE = L" +
                ".STEP_SEQUENCE " + "AND " +
                "L.TRANS_RRN = R.TRANS_RRN AND R.REASON LIKE '%(FH)%' AND H.PRODUCT_RRN = C" + ".PRODUCT_RRN " +
                "AND H" + ".PROCESS_RRN = C.PROCESS_RRN AND H.OPERATION_RRN = C.OPERATION_RRN "
                //+ "AND R.REASON_CODE = C.HOLDCODE AND R.REASON='(FH)'||C.HOLDREASON "
                + "AND H.PRODUCT_RRN = ? " + "AND H.PROCESS_RRN = ? AND H.OPERATION_RRN = ? AND L.LOT_RRN = ?";

        return jdbcTemplate
                .query(sql, new Object[]{productRrn, productRrn, processRrn, operationRrn, lotRrn}, long.class);
    }

    private boolean hasExecuted(long lotRrn, long routeRrn, long operationRrn) {

        String sql = "select count(l.lot_rrn)  from lot_trans_history l,lot_step_history h where l.lot_rrn = h" +
                ".lot_rrn " + " and l.trans_id = 'HOLD' and h.step_sequence = l.step_sequence and l.lot_rrn =? " +
                "and h" + ".operation_rrn=? and h.process_step_version like ?";

        return jdbcTemplate
                .queryForObjectWithNull(sql, new Object[]{lotRrn, operationRrn, "%" + routeRrn + "%"}, int.class) > 0;
    }

    private List<Map> getFutureholdLotListByOldData(Map lotMap) {
        List<Map> oldFutureHoldList = new ArrayList<>();
        Long refRrn = MapUtils.getLong(lotMap, "refRrn");
        final String routeRrn = MapUtils.getString(lotMap, "routeRrn");
        final String operationRrn = MapUtils.getString(lotMap, "operationRrn");
        final String lotRrn = MapUtils.getString(lotMap, "lotRrn");
        String routeSeq = " ";
        String operationSeq = " ";

        String sql =
                "SELECT V.STATUS,V.CONTEXT_KEY1,V.CONTEXT_KEY2,V.CONTEXT_KEY3,V.CONTEXT_KEY4,V.CONTEXT_KEY5, " + " V" +
                        ".RESULT_VALUE2,V.RESULT_VALUE3,V.RESULT_VALUE4,V.RESULT_VALUE5,V.RESULT_VALUE6," +
                        " V.SEQUENCE_NUMBER,V" + ".RESULT_VALUE1, " +
                        " V.EFFECTIVE_DATE_FROM,E.ACTION_TYPE FROM CONTEXT_VALUE V,EEN_ACTION E WHERE V" +
                        ".CONTEXT_RRN = ? AND " + " V.CONTEXT_KEY1=? AND V.CONTEXT_KEY2=? AND V.CONTEXT_KEY3=? AND V" +
                        ".CONTEXT_KEY4=? AND V" + ".CONTEXT_KEY5=? AND V.STATUS=?" +
                        " AND V.RESULT_VALUE1 = E.ACTION_RRN";

        Object[] args = new Object[]{refRrn, routeRrn, operationRrn, lotRrn, routeSeq, operationSeq,
                                     VersionStatus.ACTIVE_KEY};

        oldFutureHoldList = jdbcTemplate.query(sql, args, new RowMapper() {

            @Override
            public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map futureHoldMap = new HashMap();
                futureHoldMap.put("routeRrn", Long.parseLong(StringUtils.trimToEmpty(rs.getString("CONTEXT_KEY1"))));
                futureHoldMap
                        .put("operationRrn", Long.parseLong(StringUtils.trimToEmpty(rs.getString("CONTEXT_KEY2"))));
                futureHoldMap.put("routeSeq", rs.getString("CONTEXT_KEY4"));
                futureHoldMap.put("operationSeq", rs.getString("CONTEXT_KEY5"));
                futureHoldMap.put("userNamed", rs.getString("RESULT_VALUE2"));
                futureHoldMap.put("holdGroup", rs.getString("RESULT_VALUE3"));
                futureHoldMap.put("holdCode", rs.getString("RESULT_VALUE4"));
                futureHoldMap.put("holdReason", rs.getString("RESULT_VALUE5"));
                futureHoldMap.put("effectCount", rs.getString("RESULT_VALUE6"));
                futureHoldMap.put("sequenceNumber", rs.getInt("SEQUENCE_NUMBER"));
                futureHoldMap.put("status", rs.getString("STATUS"));
                futureHoldMap.put("actionRrn", rs.getString("RESULT_VALUE1"));
                java.sql.Date db_Date = rs.getDate("EFFECTIVE_DATE_FROM");
                String dbDate = DateUtils.formatDate(db_Date);
                futureHoldMap.put("futureholdsetupdate", dbDate);
                futureHoldMap.put("flag", rs.getString("ACTION_TYPE"));
                if (hasExecuted(NumberUtils.toLong(lotRrn), NumberUtils.toLong(routeRrn),
                                NumberUtils.toLong(operationRrn))) {
                    futureHoldMap.put("executedFlag", "EXECUTED");
                } else {
                    futureHoldMap.put("executedFlag", "");
                }

                return futureHoldMap;
            }
        });
        if (oldFutureHoldList.size() == 0) {
            return null;
        } else {
            return oldFutureHoldList;
        }
    }

    private Map<String, Object> queryLotCount(Map param) {

        Map<String, Object> sqlMap = this.getLotCountSql(param);
        String sql = MapUtils.getString(sqlMap, "sql");
        List<Object> argList = (List<Object>) MapUtils.getObject(sqlMap, "argList");

        return jdbcTemplate.queryForObject(sql, new RowMapper<Map<String, Object>>() {
            @Override
            public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map<String, Object> map = new HashMap();
                map.put("lotCount", rs.getInt("LOT_COUNT"));
                String qtyCountStr = rs.getString("QTY_COUNT");
                if (StringUtils.isBlank(qtyCountStr)) {
                    qtyCountStr = "0";
                }
                map.put("qtyCount", Integer.valueOf(qtyCountStr));
                return map;
            }
        }, argList.toArray());
    }

    private Map<String, Object> getLotPortalListSql(Map param, int startRow, int currentTotalRow) {
        List<Object> argList = new ArrayList<Object>();
        StringBuffer sql = new StringBuffer("SELECT * FROM (SELECT ROW_T.*, ROWNUM AS ROW_NO FROM (SELECT * ");
        sql.append("FROM (SELECT RN.*, ROW_NUMBER() OVER(PARTITION BY RN.LOTRRN ORDER BY LOTRRN DESC) AS " + "RN_NUM ");
        sql.append("FROM (SELECT HOTFLAG AS PRIORITY , OE.ATTRIBUTE_DATA5 AS " + "WORK_AREA, ");
        sql.append("PRIORITY AS INTERIOR_PRIORITY , ");
        sql.append("getinstanceid(getcontextreciperrn(PRODUCT_RRN, PROCESS_RRN, ROUTE_RRN, L.STEP_RRN, " +
                           "PROCESS_VERSION,L.PRODUCT_VERSION)) AS CONTEXT_RECIPE, ");
        sql.append("getcontextreciperrn(PRODUCT_RRN, PROCESS_RRN, ROUTE_RRN, L.STEP_RRN, PROCESS_VERSION,L" +
                           ".PRODUCT_VERSION) AS " + "CONTEXT_RECIPE_RRN, ");
        sql.append("CONTEXT_FLOW_SEQ, ");
        sql.append("CONTEXT_STEP_DESC, ");
        sql.append("ROUND((GETMINREMAINTIMEBYLOTRRN(LOTRRN, ?) / 3600), 2) AS Q_TIME, ");
        argList.add(Constants.TIME_LIMIT.TIME_TYPE_MAX);
        sql.append("(CASE WHEN LENGTH(EQPTID) > 0 THEN EQPTID WHEN EQPTID = '' OR EQPTID IS NULL THEN " + "EPT_GROUP " +
                           "END) EQPTID, ");
        sql.append("EQPTID AS RUNNING_EQPT, EPT_GROUP AS EQPT_LIST, BATCH_ID, ");
        sql.append("PODID, DOORID, LOT_RUNTIME.LOT_RUN_TIME, LOTID, REWORK_CATEGORY, LOTRRN, LOT_STATUS_REF" +
                           ".DATA_1_VALUE AS LOTSTATUS, LOT_CATEGORY_REF.DATA_1_VALUE AS LOTCATEGORY, ");
        sql.append("LOTTYPE, QTY1, CARRIERID, PRODUCTID, PRODUCT_RRN, ROUTESEQ, STEPSEQ, RECIPEID, " + "PROCESS_RRN, " +
                           "PROCESS_VERSION, ROUTE_RRN, ROUTE_VERSION, L.STEP_RRN, STEP_VERSION, ");
        sql.append("PROCESS_ID, ROUTE_ID, L.STEP_ID, L.EQPT_RRN, QUEUE_TIMESTAMP, STAGE_ID, POLLUTION_LEVEL, " +
                           "RECIPE_STRING, REA.HOLD_DEPT, REA.HOLD_REASON, O.ENTITY_GROUP_RRN, ");
        sql.append("GETINSTANCEID(O.ENTITY_GROUP_RRN) AS ENTITY_GROUP_ID, HOLD_TIMESTAMP, CUSTOMER_ID, " +
                           "SHIPPING_CODE, OUTER_ORDER_NO, OUT_ORDER_TYPE, CUSTOMER_LOT_ID, ");
        sql.append("LOCATION, PLOCATION,LOT_COMMENT ");
        sql.append("FROM (SELECT ");
        sql.append(
                "GETINSTANCEID(PA.POD_RRN) AS PODID, GETINSTANCEID(PA.DOOR_RRN) AS DOORID, T.LOT_RRN AS " + "LOTRRN," +
                        "LSGC.STEP_COMMENT AS LOT_COMMENT, T.REWORK_CATEGORY, T.LOT_STATUS AS " +
                        "LOTSTATUS, BATCH_STORE" + ".BATCH_ID, ");
        sql.append(
                "T.CREATE_CATEGORY AS LOTCATEGORY, T.LOT_TYPE AS LOTTYPE, T.PRIORITY AS PRIORITY, T" + ".HOT_FLAG AS " +
                        "HOTFLAG, getlotqty1(T.LOT_RRN) AS QTY1, GETINSTANCEID(T.CARRIER_RRN) AS " + "CARRIERID, ");
        sql.append(
                "GETINSTANCEID(T.PRODUCT_RRN) PRODUCTID, T.ROUTE_SEQ AS ROUTESEQ, T.OPERATION_SEQ AS " + "STEPSEQ, " +
                        "GETINSTANCEID(T.RECIPE_LOGICAL_RRN) AS RECIPEID, T.LOT_ID AS LOTID, ");
        sql.append("T.PRODUCT_RRN, T.EQPT_RRN, GETINSTANCEID(T.EQPT_RRN) AS EQPTID, LX.ATTRIBUTE_DATA1 AS " +
                           "POLLUTION_LEVEL, RECIPE_STRING, T.HOLD_TIMESTAMP, LX.CUSTOMER_ID, LX.SHIPPING_CODE, ");
        sql.append("LX.OUT_ORDER_TYPE, LX.CUSTOMER_LOT_ID, QUEUE_TIMESTAMP, STAGE_ID, T.PROCESS_RRN, T" +
                           ".PROCESS_VERSION, getinstanceid(T.PROCESS_RRN) AS PROCESS_ID, LX.OUTER_ORDER_NO, ");
        sql.append("LX.LOCATION, LX.PLOCATION, ");
        sql.append("CASE WHEN REWORK_CATEGORY IS NULL OR REWORK_CATEGORY = '' ");
        sql.append(
                "THEN REGEXP_SUBSTR(T.PROCESS_STEP_VERSION, '[^,]+', INSTR(T.PROCESS_STEP_VERSION, '|', 1, " + "1) + " +
                        "1, 1) ");
        sql.append(
                "ELSE REGEXP_SUBSTR(T.PROCESS_STEP_VERSION, '[^,]+', INSTR(T.PROCESS_STEP_VERSION, '|', 1, " + "2) + " +
                        "1, 1) ");
        sql.append("END AS ROUTE_RRN, ");
        sql.append("CASE WHEN REWORK_CATEGORY IS NULL OR REWORK_CATEGORY = '' ");
        sql.append(
                "THEN REGEXP_SUBSTR(T.PROCESS_STEP_ID_VERSION, '[^,]+', INSTR(T.PROCESS_STEP_ID_VERSION, " + "'|', 1," +
                        " 1) + 1, 1) ");
        sql.append(
                "ELSE REGEXP_SUBSTR(T.PROCESS_STEP_ID_VERSION, '[^,]+', INSTR(T.PROCESS_STEP_ID_VERSION, " + "'|', 1," +
                        " 2) + 1, 1) ");
        sql.append("END AS ROUTE_ID, ");
        sql.append("CASE  WHEN REWORK_CATEGORY IS NULL OR REWORK_CATEGORY = '' ");
        sql.append(
                "THEN REGEXP_SUBSTR(T.PROCESS_STEP_VERSION, '[^|]+', INSTR(T.PROCESS_STEP_VERSION, ',', 1, " + "2) + " +
                        "1, 1) ");
        sql.append("ELSE SUBSTR(PROCESS_STEP_VERSION, INSTR(PROCESS_STEP_VERSION, ',', 1, 3) + 1) ");
        sql.append("END AS ROUTE_VERSION, ");
        sql.append("CASE WHEN REWORK_CATEGORY IS NULL OR REWORK_CATEGORY = '' ");
        sql.append(
                "THEN REGEXP_SUBSTR(T.PROCESS_STEP_VERSION, '[^,]+', INSTR(T.PROCESS_STEP_VERSION, '|', 1, " + "2) + " +
                        "1, 1) ");
        sql.append(
                "ELSE REGEXP_SUBSTR(T.PROCESS_STEP_VERSION, '[^,]+', INSTR(T.PROCESS_STEP_VERSION, '|', 1, " + "1) + " +
                        "1, 1) ");
        sql.append("END AS STEP_RRN, ");
        sql.append("CASE WHEN REWORK_CATEGORY IS NULL OR REWORK_CATEGORY = '' ");
        sql.append(
                "THEN REGEXP_SUBSTR(T.PROCESS_STEP_ID_VERSION, '[^,]+', INSTR(T.PROCESS_STEP_ID_VERSION, " + "'|', 1," +
                        " 2) + 1, 1) ");
        sql.append(
                "ELSE REGEXP_SUBSTR(T.PROCESS_STEP_ID_VERSION, '[^,]+', INSTR(T.PROCESS_STEP_ID_VERSION, " + "'|', 1," +
                        " 1) + 1, 1) ");
        sql.append("END AS STEP_ID, ");
        sql.append("CASE WHEN REWORK_CATEGORY IS NULL OR REWORK_CATEGORY = '' ");
        sql.append("THEN SUBSTR(PROCESS_STEP_VERSION, INSTR(PROCESS_STEP_VERSION, ',', 1, 3) + 1) ");
        sql.append(
                "ELSE REGEXP_SUBSTR(T.PROCESS_STEP_VERSION, '[^|]+', INSTR(T.PROCESS_STEP_VERSION, ',', 1, " + "2) + " +
                        "1, 1) ");
        sql.append("END AS STEP_VERSION, ");
        sql.append("T.FLOW_SEQ AS CONTEXT_FLOW_SEQ, ");
        sql.append("T.OPERATION_DESC AS CONTEXT_STEP_DESC ");

        if (StringUtils.isNotBlank(MapUtils.getString(param, "subTechnologyId")) ||
                StringUtils.isNotBlank(MapUtils.getString(param, "technologyId"))) {
            sql.append(",RE.FROM_RRN, RE.TO_RRN ");
        }

        sql.append(
                "FROM LOT T, LOT_EXT LX, PCD_ASSEMBLY PA, NAMED_OBJECT PRODUCT_N,BATCH_LOT_STORE " + "BATCH_STORE, " +
                        "LOT_STEP_HISTORY_COMMENT LSGC, ");
        sql.append(" (SELECT T.LOT_RRN, MAX(COMMENT_SEQUENCE) COMMENT_SEQUENCE FROM LOT_STEP_HISTORY_COMMENT T" + " " +
                           "GROUP BY T.LOT_RRN) MAXCOMMENTSEQ ");

        if (StringUtils.isNotBlank(MapUtils.getString(param, "subTechnologyId")) ||
                StringUtils.isNotBlank(MapUtils.getString(param, "technologyId"))) {
            sql.append(", RELATION RE  ");
        }

        sql.append("WHERE T.LOT_RRN = LX.LOT_RRN(+) ");
        sql.append("AND T.LOT_RRN = MAXCOMMENTSEQ.LOT_RRN(+) ");
        sql.append("AND MAXCOMMENTSEQ.LOT_RRN = LSGC.LOT_RRN(+) ");
        sql.append("AND MAXCOMMENTSEQ.COMMENT_SEQUENCE = LSGC.COMMENT_SEQUENCE(+) ");
        sql.append("AND T.CARRIER_RRN = PA.CARRIER_RRN(+) AND T.PRODUCT_RRN = PRODUCT_N.INSTANCE_RRN(+) AND T" +
                           ".FACILITY_RRN = ? AND T.LOT_RRN=BATCH_STORE.LOT_RRN(+) ");
        argList.add(MapUtils.getIntValue(param, "facilityRrn", 0));
        sql.append("AND (T.IS_DUMMY_LOT IS NULL OR T.IS_DUMMY_LOT = '0')");

        if (StringUtils.isNotBlank(MapUtils.getString(param, "lotId"))) {
            sql.append("AND T.LOT_ID LIKE ? ");
            argList.add(MapUtils.getString(param, "lotId"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "stageId"))) {
            sql.append("AND T.STAGE_ID = ? ");
            argList.add(MapUtils.getString(param, "stageId"));
        }

        if (MapUtils.getObject(param, "lotCategoryArray") != null) {
            String[] lotCategoryArray = (String[]) MapUtils.getObject(param, "lotCategoryArray");
            String categoryCondition = "AND (";
            for (int i = 0; i < lotCategoryArray.length; i++) {
                if (StringUtils.isNotBlank(lotCategoryArray[i])) {
                    if (i == 0) {
                        categoryCondition += "T.CREATE_CATEGORY = ? ";
                    } else {
                        categoryCondition += "OR T.CREATE_CATEGORY = ? ";
                    }
                    argList.add(lotCategoryArray[i]);
                }
            }
            categoryCondition += ") ";
            if (StringUtils.contains(categoryCondition, "CREATE_CATEGORY")) {
                sql.append(categoryCondition);
            }
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "lotType"))) {
            sql.append("AND T.LOT_TYPE = ? ");
            argList.add(MapUtils.getString(param, "lotType"));
        }

        String[] filterStatus = LotStatus.getFilterStatus();
        for (String filter : filterStatus) {
            sql.append("AND T.LOT_STATUS <> ? ");
            argList.add(filter);
        }
        if (MapUtils.getObject(param, "lotStatusArray") != null) {
            String[] lotStatusArray = (String[]) MapUtils.getObject(param, "lotStatusArray");
            String statusCondition = "AND (";
            boolean reworkFlag = false;
            for (int i = 0; i < lotStatusArray.length; i++) {
                if (StringUtils.equals(LotStatus.ALL, lotStatusArray[i])) {
                    continue;
                }
                if (!reworkFlag && StringUtils.equals(lotStatusArray[i], LotStatus.REWORK)) {
                    reworkFlag = true;
                }

                if (i == 0) {
                    statusCondition += "T.LOT_STATUS = ? ";
                } else {
                    statusCondition += "OR T.LOT_STATUS = ? ";
                }
                argList.add(lotStatusArray[i]);

                if (StringUtils.equals(LotStatus.ACTIVE, lotStatusArray[i])) {
                    statusCondition +=
                            "OR T.LOT_STATUS = ? OR T.LOT_STATUS = ? OR T.LOT_STATUS = ? OR T" + ".LOT_STATUS = ? ";
                    argList.add(LotStatus.RUNNING);
                    argList.add(LotStatus.WAITING);
                    argList.add(LotStatus.PROCESSED);
                    argList.add(LotStatus.DISPATCH);
                } else if (StringUtils.equals(LotStatus.UNACTIVE, lotStatusArray[i])) {
                    statusCondition +=
                            "OR T.LOT_STATUS = ? OR T.LOT_STATUS = ? OR T.LOT_STATUS = ? OR T" + ".LOT_STATUS = ? ";
                    argList.add(LotStatus.BONDED);
                    argList.add(LotStatus.FINISH);
                    argList.add(LotStatus.TERMINATED);
                    argList.add(LotStatus.SCRAPPED);
                } else if (StringUtils.equals(LotStatus.HOLD, lotStatusArray[i])) {
                    statusCondition += "OR T.LOT_STATUS = ?";
                    argList.add(LotStatus.RUNNINGHOLD);
                }
            }
            if (reworkFlag) {
                statusCondition += "OR REWORK_CATEGORY IS NOT NULL ";
            }
            statusCondition += ") ";
            if (StringUtils.contains(statusCondition, "LOT_STATUS")) {
                sql.append(statusCondition);
            }
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "priority"))) {
            if (MapUtils.getString(param, "priority").indexOf("-") > 0) {
                String[] pris = MapUtils.getString(param, "priority").split("-");
                if (pris != null && pris.length == 2) {
                    sql.append("AND T.HOT_FLAG = ? AND T.PRIORITY = ? ");
                    argList.add(pris[0]);
                    argList.add(Long.parseLong(pris[1]));
                }
            }
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "productType"))) {
            sql.append("AND PRODUCT_N.OBJECT_TYPE = ? ");
            argList.add(MapUtils.getString(param, "productType"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "productId"))) {
            sql.append("AND getinstanceid(T.PRODUCT_RRN) LIKE ? ");
            argList.add(MapUtils.getString(param, "productId"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "processId"))) {
            sql.append("AND getinstanceid(T.PROCESS_RRN) LIKE ? ");
            argList.add(MapUtils.getString(param, "processId"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "subTechnologyId"))) {
            sql.append("AND RE.LINK_TYPE='SUBTECHNOLOGY_PRODUCT' AND RE.TO_RRN = T.PRODUCT_RRN  ");
            sql.append("AND getinstanceid(FROM_RRN) = ? ");
            argList.add(MapUtils.getString(param, "subTechnologyId"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "technologyId"))) {
            sql.append(
                    "AND RE.LINK_TYPE='TECHNOLOGY_SUBTECHNOLOGY' AND RE.TO_RRN = (select from_rrn from " + "relation " +
                            "where LINK_TYPE='SUBTECHNOLOGY_PRODUCT' AND TO_RRN = T.PRODUCT_RRN) ");
            sql.append("AND getinstanceid(FROM_RRN) = ? ");
            argList.add(MapUtils.getString(param, "technologyId"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "carrierId"))) {
            sql.append("AND getinstanceid(T.CARRIER_RRN) LIKE ? ");
            argList.add(MapUtils.getString(param, "carrierId"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "routeId"))) {
            sql.append(
                    "AND REGEXP_SUBSTR(T.PROCESS_STEP_ID_VERSION, '[^,]+', instr(T.PROCESS_STEP_ID_VERSION," + " '|'," +
                            " 1, 1) + 1, 1) LIKE ? ");
            argList.add(MapUtils.getString(param, "routeId"));
        }

        sql.append(") L, (SELECT DISTINCT RS.TO_RRN AS STEP_RRN, RS.FROM_RRN AS STATION_RRN, GETINSTANCEID(RS" +
                           ".FROM_RRN) AS STATION_ID ");
        sql.append("FROM RELATION RS WHERE RS.LINK_TYPE = 'STATION_TO_OPERATION' ");
        sql.append("UNION ");
        sql.append(
                "SELECT DISTINCT O.OPERATION_RRN AS STEP_RRN, EQPT_GROUP_T.STATION_RRN, EQPT_GROUP_T" + ".STATION_ID ");
        sql.append(
                "FROM OPERATION O, (SELECT EQPT_GROUP_R.TO_RRN AS EPQT_GROUP_RRN, EQPT_STATION_T" + ".STATION_RRN, " +
                        "EQPT_STATION_T.STATION_ID ");
        sql.append(
                "FROM RELATION EQPT_GROUP_R, (SELECT EQPT_STATION_R.TO_RRN AS EQPT_RRN, STATION_T.FROM_RRN " + "AS " +
                        "STATION_RRN, STATION_ID ");
        sql.append(
                "FROM RELATION EQPT_STATION_R, (SELECT N.INSTANCE_RRN AS FROM_RRN, N.INSTANCE_ID  AS " + "STATION_ID ");
        sql.append("FROM NAMED_OBJECT N WHERE N.OBJECT = 'STATION') STATION_T WHERE EQPT_STATION_R.LINK_TYPE =" + " " +
                           "'STATION_TO_EQUIPMENT' ");
        sql.append("AND EQPT_STATION_R.FROM_RRN IN STATION_T.FROM_RRN) EQPT_STATION_T ");
        sql.append("WHERE EQPT_GROUP_R.LINK_TYPE = 'ENTITY_TO_ENTITY_GROUP' AND EQPT_GROUP_R.FROM_RRN = " +
                           "EQPT_STATION_T.EQPT_RRN) EQPT_GROUP_T ");
        sql.append("WHERE O.ENTITY_GROUP_RRN IN EQPT_GROUP_T.EPQT_GROUP_RRN) STATION_T, ");
        sql.append("(SELECT TR.TRANS_RRN AS HOLD_RRN, TR.INSTANCE_RRN AS LOT_RRN, MAXMH.HOLD_USER_RRN, TR" +
                           ".RESPONSIBILITY AS HOLD_USER_ID, ");
        sql.append(
                "CASE WHEN LENGTH(SUBSTR(TR.REASON, 1, INSTR(TR.REASON, 'Reason:', 1, 1)-1)) > 0 THEN " + "SUBSTR(TR" +
                        ".REASON, 1, INSTR(TR.REASON, 'Reason:', 1, 1)-1) ");
        sql.append(
                "ELSE 'SYSTEM' END AS HOLD_DEPT, SUBSTR(TR.REASON, INSTR(TR.REASON, 'Reason:', 1, 1)+7, " + "LENGTH" +
                        "(TR.REASON)) AS HOLD_REASON ");
        sql.append("FROM TRANS_REASON TR, (SELECT M.TRANS_RRN, M.HOLD_BY AS HOLD_USER_RRN, M.INSTANCE_RRN AS " +
                           "LOT_RRN FROM MULTIPLE_HOLD M, ");
        sql.append("(SELECT MAX(MH.HOLD_TIMESTAMP) AS HOLD_DATE, MAX(MH.SEQUENCE_NUMBER) AS HOLD_SEQ, MH" +
                           ".INSTANCE_RRN AS LOT_RRN ");
        sql.append("FROM MULTIPLE_HOLD MH WHERE MH.OBJECT = 'LOT' GROUP BY MH.INSTANCE_RRN) MAXM ");
        sql.append("WHERE M.HOLD_TIMESTAMP = MAXM.HOLD_DATE AND M.SEQUENCE_NUMBER = MAXM.HOLD_SEQ AND M" +
                           ".INSTANCE_RRN = MAXM.LOT_RRN) MAXMH ");
        sql.append("WHERE TR.TRANS_RRN = MAXMH.TRANS_RRN AND TR.INSTANCE_RRN = MAXMH.LOT_RRN) REA, ");
        sql.append(
                "(SELECT LISTAGG(GETINSTANCEID(R.FROM_RRN), ',') WITHIN GROUP(ORDER BY R.TO_RRN) AS " + "EPT_GROUP, R" +
                        ".TO_RRN AS ENTITY_GROUP_RRN ");
        sql.append("FROM RELATION R WHERE R.LINK_TYPE = 'ENTITY_TO_ENTITY_GROUP' OR R.LINK_TYPE = " +
                           "'ENTITY_TO_ENTITY_GROUP_INACTIVE' GROUP BY R.TO_RRN) EGR, ");
        sql.append(
                "(SELECT MAX(TLOG.TRANS_START_TIMESTAMP) AS LOT_RUN_TIME, LOT_TRANS.LOT_RRN FROM " + "TRANSACTION_LOG" +
                        " TLOG, ");
        sql.append("(SELECT TRANS_RRN, LOT_RRN FROM LOT_TRANS_HISTORY WHERE TRANS_ID = 'MOVEIN') LOT_TRANS ");
        sql.append("WHERE TLOG.TRANS_RRN IN (LOT_TRANS.TRANS_RRN) GROUP BY LOT_TRANS.LOT_RRN) LOT_RUNTIME, ");
        sql.append("(SELECT RF.KEY_1_VALUE, RF.DATA_1_VALUE FROM NAMED_OBJECT N, REFERENCE_FILE_DETAIL RF ");
        sql.append("WHERE N.INSTANCE_ID = '$LOT_CREATE_CATEGORY' AND N.NAMED_SPACE = ? AND N.OBJECT = " +
                           "'REFERENCEFILE' ");
        argList.add(MapUtils.getString(param, "referenceNamedSpace"));

        sql.append("AND N.INSTANCE_RRN = RF.REFERENCE_FILE_RRN) LOT_CATEGORY_REF, ");
        sql.append("(SELECT RF.KEY_1_VALUE, RF.DATA_1_VALUE FROM NAMED_OBJECT N, REFERENCE_FILE_DETAIL RF ");
        sql.append("WHERE N.INSTANCE_ID = '$$LOT_STATUS' AND N.NAMED_SPACE = ? AND N.OBJECT = 'REFERENCEFILE' ");
        argList.add(MapUtils.getString(param, "referenceNamedSpace"));

        sql.append("AND N.INSTANCE_RRN = RF.REFERENCE_FILE_RRN) LOT_STATUS_REF, OPERATION_EXT OE, OPERATION O ");

        sql.append("WHERE L.STEP_RRN = OE.OPERATION_RRN(+) AND L.STEP_RRN = O.OPERATION_RRN(+) AND L.STEP_RRN " + "= " +
                           "STATION_T.STEP_RRN(+) AND L.LOTRRN = REA.LOT_RRN(+) ");
        sql.append("AND O.ENTITY_GROUP_RRN = EGR.ENTITY_GROUP_RRN(+) AND L.LOTRRN = LOT_RUNTIME.LOT_RRN(+) AND" + " L" +
                           ".LOTCATEGORY = LOT_CATEGORY_REF.KEY_1_VALUE ");
        sql.append("AND L.LOTSTATUS = LOT_STATUS_REF.KEY_1_VALUE ");

        if (StringUtils.isNotBlank(MapUtils.getString(param, "stationId"))) {
            sql.append("AND STATION_T.STATION_ID LIKE ? ");
            argList.add(MapUtils.getString(param, "stationId"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "eqptGroupId"))) {
            sql.append("AND getinstanceid(O.ENTITY_GROUP_RRN) LIKE ? ");
            argList.add(MapUtils.getString(param, "eqptGroupId"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "workArea"))) {
            sql.append("AND OE.ATTRIBUTE_DATA5 = ? ");
            argList.add(MapUtils.getString(param, "workArea"));
        }

        sql.append(") RN) RN_T WHERE RN_T.RN_NUM = 1 ORDER BY LOTID ASC) ROW_T WHERE ROWNUM <= ? ) PAGE_T " + "WHERE " +
                           "PAGE_T.ROW_NO > ? ");
        argList.add(currentTotalRow);
        argList.add(startRow);

        Map<String, Object> sqlMap = new HashMap<String, Object>();
        sqlMap.put("sql", sql.toString());
        sqlMap.put("argList", argList);
        return sqlMap;
    }

    private String translateRrn(long rrn) {
        String instanceId = null;

        String sql = "SELECT instance_id " + " FROM " + DataBaseNames.NAMEDOBJECT + " WHERE instance_rrn=? ";
        Object[] args = new Object[]{rrn};
        instanceId = jdbcTemplate.queryForObjectWithNull(sql, args, String.class);

        if (instanceId == null) {
            instanceId = "N/A";
        }
        return instanceId;
    }

    private String getTransReason(long transRrn, long lotRrn) {
        String sql = "select  listagg(tr.reason,',') WITHIN GROUP (ORDER BY tr.reason_code_sequence)  as reason " +
                "from trans_reason tr where tr.trans_rrn=? " + "and tr.instance_rrn=?";

        String reason = jdbcTemplate.queryForObjectWithNull(sql, new Object[]{transRrn, lotRrn}, String.class);
        return reason == null ? "" : reason;
    }

    private String getTransByName(String transBy) {
        String sql = "select t.user_name from user_profile t,named_object o " + " where t.user_rrn=o.instance_rrn " +
                " and o" + ".instance_id=? and o.object='USER'";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{transBy}, String.class);
    }

    private String getT7CodeHist(Long transRrn) {
        String sql = "SELECT LISTAGG(U.UNIT_ID || ':' || T7H.T7CODE, ',') WITHIN GROUP(ORDER BY T7H.TRANS_RRN) " +
                "FROM UNIT_T7CODE_MAPPING_H T7H,UNIT U WHERE U" + ".LOT_RRN=T7H.LOT_RRN " + "AND U.UNIT_RRN=T7H.UNIT_RRN  AND T7H" +
                ".TRANS_RRN =? GROUP BY T7H.TRANS_RRN ";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{transRrn}, String.class);
    }

    private String parseOperation(String processStepIdVersion) {
        String operationId = null;

        if (processStepIdVersion != null) {
            int start = processStepIdVersion.lastIndexOf("|");
            int end = processStepIdVersion.lastIndexOf(",");
            operationId = processStepIdVersion.substring(start + 1, end);
        }

        return operationId;
    }

    private String parseRoute(String processStepIdVersion) {
        String routeId = null;

        if (StringUtils.isNotEmpty(processStepIdVersion)) {
            int start = processStepIdVersion.indexOf("|");
            int _start = processStepIdVersion.lastIndexOf("|");

            // handle case "Route_120898,0|WAFER_CODE,0|1000,1"
            // and case "WAFER_CODE,0|1000,1"
            if (start == _start) {
                start = -1;
            }

            int end = processStepIdVersion.indexOf(",", start);

            routeId = processStepIdVersion.substring(start + 1, end);
        }

        return routeId;
    }

    private Long parseRouteRrn(String processStepString) {
        Long routeRrn = null;

        if (StringUtils.isNotEmpty(processStepString)) {
            int firstSep = processStepString.indexOf("|");
            int secondSep = processStepString.indexOf("|", firstSep + 1);

            if (secondSep >= 0) {
                routeRrn = Long
                        .valueOf(processStepString.substring(firstSep + 1, processStepString.indexOf(",", firstSep)));
            } else {
                routeRrn = Long.valueOf(processStepString.substring(0, processStepString.indexOf(",")));
            }
        }

        return routeRrn;
    }

    private Map<String, Object> buildLotPortalConditionMap(Map lotPortalFormMap) {
        if (StringUtils.isNotBlank(MapUtils.getString(lotPortalFormMap, "lotId"))) {
            lotPortalFormMap.put("lotId",
                                 StringUtils.replace(MapUtils.getString(lotPortalFormMap, "lotId"), "*", "%").toString()
                                            .toUpperCase());
        }
        if (MapUtils.getObject(lotPortalFormMap, "lotStatus") != null) {
            String[] lotStatusArray = (String[]) MapUtils.getObject(lotPortalFormMap, "lotStatus");
            if (lotStatusArray != null && lotStatusArray.length > 0) {
                if (lotStatusArray.length != 1 || StringUtils.isNotEmpty(lotStatusArray[0])) {
                    lotPortalFormMap.put("lotStatusArray", lotStatusArray);
                }
            } else {
                lotPortalFormMap.put("lotStatusArray", lotStatusArray);
            }
        }
        if (MapUtils.getObject(lotPortalFormMap, "lotCategory") != null) {
            String[] lotCategoryArray = (String[]) MapUtils.getObject(lotPortalFormMap, "lotCategory");
            lotPortalFormMap.put("lotCategoryArray", lotCategoryArray);
        } else {
            lotPortalFormMap.put("lotCategory", StringUtils.EMPTY);
        }
        if (StringUtils.isNotBlank(MapUtils.getString(lotPortalFormMap, "productId"))) {
            lotPortalFormMap.put("productId",
                                 MapUtils.getString(lotPortalFormMap, "productId").replace("*", "%").toUpperCase());
        }
        if (StringUtils.isNotBlank(MapUtils.getString(lotPortalFormMap, "processId"))) {
            lotPortalFormMap.put("processId",
                                 MapUtils.getString(lotPortalFormMap, "processId").replace("*", "%").toUpperCase());
        }
        if (StringUtils.isNotBlank(MapUtils.getString(lotPortalFormMap, "routeId"))) {
            lotPortalFormMap
                    .put("routeId", MapUtils.getString(lotPortalFormMap, "routeId").replace("*", "%").toUpperCase());
        }
        if (StringUtils.isNotBlank(MapUtils.getString(lotPortalFormMap, "carrierId"))) {
            lotPortalFormMap.put("carrierId",
                                 StringUtils.replace(MapUtils.getString(lotPortalFormMap, "carrierId"), "*", "%")
                                            .toString().toUpperCase());
        }
        if (StringUtils.isNotBlank(MapUtils.getString(lotPortalFormMap, "stationId"))) {
            lotPortalFormMap.put("stationId",
                                 MapUtils.getString(lotPortalFormMap, "stationId").replace("*", "%").toUpperCase());
        }
        if (StringUtils.isNotBlank(MapUtils.getString(lotPortalFormMap, "eqptGroupId"))) {
            lotPortalFormMap.put("eqptGroupId",
                                 MapUtils.getString(lotPortalFormMap, "eqptGroupId").replace("*", "%").toUpperCase());
        }

        return lotPortalFormMap;
    }

    private Map<String, Object> getLotCountSql(Map param) {
        List<Object> argList = new ArrayList<Object>();

        StringBuffer sql = new StringBuffer("SELECT COUNT(LOT_UNIT_T.LOT_RRN) AS LOT_COUNT, ");
        sql.append("SUM(LOT_UNIT_T.QTY) AS QTY_COUNT FROM ( SELECT L.LOT_RRN, COUNT(U.UNIT_RRN) AS QTY FROM ( ");
        sql.append("SELECT DISTINCT LOT_T.LOT_RRN, LOT_T.LOT_ID ");
        sql.append("FROM (SELECT L.LOT_RRN, L.LOT_ID, REGEXP_SUBSTR(L.PROCESS_STEP_VERSION, '[^,]+', INSTR(L" +
                           ".PROCESS_STEP_VERSION, '|', 1, 2) + 1, 1) AS STEP_RRN, ");
        sql.append("L.CREATE_CATEGORY, L.LOT_STATUS ");

        if (StringUtils.isNotBlank(MapUtils.getString(param, "subTechnologyId")) ||
                StringUtils.isNotBlank(MapUtils.getString(param, "technologyId"))) {
            sql.append(",RE.FROM_RRN, RE.TO_RRN ");
        }

        sql.append("FROM LOT L LEFT JOIN NAMED_OBJECT N ON L.PRODUCT_RRN = N.INSTANCE_RRN ");

        if (StringUtils.isNotBlank(MapUtils.getString(param, "subTechnologyId")) ||
                StringUtils.isNotBlank(MapUtils.getString(param, "technologyId"))) {
            sql.append(", RELATION RE  ");
        }

        sql.append(" WHERE L.FACILITY_RRN = ? ");
        argList.add(MapUtils.getIntValue(param, "facilityRrn", 0));
        sql.append(" AND (L.IS_DUMMY_LOT IS NULL OR L.IS_DUMMY_LOT = '0')");

        if (StringUtils.isNotBlank(MapUtils.getString(param, "lotId"))) {
            sql.append("AND L.LOT_ID LIKE ? ");
            argList.add(MapUtils.getString(param, "lotId"));
        }
        if (MapUtils.getObject(param, "lotCategoryArray") != null) {
            String[] lotCategoryArray = (String[]) MapUtils.getObject(param, "lotCategoryArray");
            StringBuilder categoryCondition = new StringBuilder("AND (");
            for (int i = 0; i < lotCategoryArray.length; i++) {
                if (StringUtils.isNotBlank(lotCategoryArray[i])) {
                    if (i == 0) {
                        categoryCondition.append("L.CREATE_CATEGORY = ? ");
                    } else {
                        categoryCondition.append("OR L.CREATE_CATEGORY = ? ");
                    }
                    argList.add(lotCategoryArray[i]);
                }
            }
            categoryCondition.append(") ");
            if (StringUtils.contains(categoryCondition.toString(), "CREATE_CATEGORY")) {
                sql.append(categoryCondition);
            }
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "lotType"))) {
            sql.append("AND L.LOT_TYPE = ? ");
            argList.add(MapUtils.getString(param, "lotType"));
        }
        String[] filterStatus = LotStatus.getFilterStatus();
        for (String filter : filterStatus) {
            sql.append("AND L.LOT_STATUS <> ? ");
            argList.add(filter);
        }
        if (MapUtils.getObject(param, "lotStatusArray") != null) {

            String[] lotStatusArray = (String[]) MapUtils.getObject(param, "lotStatusArray");
            StringBuilder statusCondition = new StringBuilder("AND (");
            boolean reworkFlag = false;

            for (int i = 0; i < lotStatusArray.length; i++) {
                if (StringUtils.equals(LotStatus.ALL, lotStatusArray[i])) {
                    continue;
                }
                if (!reworkFlag && StringUtils.equals(lotStatusArray[i], LotStatus.REWORK)) {
                    reworkFlag = true;
                }

                if (i == 0) {
                    statusCondition.append("L.LOT_STATUS = ? ");
                } else {
                    statusCondition.append("OR L.LOT_STATUS = ? ");
                }
                argList.add(lotStatusArray[i]);

                if (StringUtils.equals(LotStatus.ACTIVE, lotStatusArray[i])) {
                    statusCondition.append("OR L.LOT_STATUS = ? OR L.LOT_STATUS = ? OR L.LOT_STATUS = ? OR L" +
                                                   ".LOT_STATUS = ? ");
                    argList.add(LotStatus.RUNNING);
                    argList.add(LotStatus.WAITING);
                    argList.add(LotStatus.PROCESSED);
                    argList.add(LotStatus.DISPATCH);
                } else if (StringUtils.equals(LotStatus.UNACTIVE, lotStatusArray[i])) {
                    statusCondition.append("OR L.LOT_STATUS = ? OR L.LOT_STATUS = ? OR L.LOT_STATUS = ? OR L" +
                                                   ".LOT_STATUS = ? ");
                    argList.add(LotStatus.BONDED);
                    argList.add(LotStatus.FINISH);
                    argList.add(LotStatus.TERMINATED);
                    argList.add(LotStatus.SCRAPPED);
                } else if (StringUtils.equals(LotStatus.HOLD, lotStatusArray[i])) {
                    statusCondition.append("OR L.LOT_STATUS = ? ");
                    argList.add(LotStatus.RUNNINGHOLD);
                }
            }
            if (reworkFlag) {
                statusCondition.append("OR REWORK_CATEGORY IS NOT NULL ");
            }
            statusCondition.append(") ");
            if (StringUtils.contains(statusCondition.toString(), "LOT_STATUS")) {
                sql.append(statusCondition);
            }
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "priority"))) {
            if (MapUtils.getString(param, "priority").indexOf("-") > 0) {
                String[] pris = MapUtils.getString(param, "priority").split("-");
                if (pris.length == 2) {
                    sql.append("AND L.HOT_FLAG = ? AND L.PRIORITY = ? ");
                    argList.add(pris[0]);
                    argList.add(Long.parseLong(pris[1]));
                }
            }
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "productType"))) {
            sql.append("AND N.OBJECT_TYPE = ? ");
            argList.add(MapUtils.getString(param, "productType"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "productId"))) {
            sql.append("AND getinstanceid(L.PRODUCT_RRN) LIKE ? ");
            argList.add(MapUtils.getString(param, "productId"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "processId"))) {
            sql.append("AND getinstanceid(L.PROCESS_RRN) LIKE ? ");
            argList.add(MapUtils.getString(param, "processId"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "subTechnologyId"))) {
            sql.append("AND RE.LINK_TYPE='SUBTECHNOLOGY_PRODUCT' AND RE.TO_RRN = L.PRODUCT_RRN  ");
            sql.append("AND getinstanceid(FROM_RRN) = ? ");
            argList.add(MapUtils.getString(param, "subTechnologyId"));
        }

        if (StringUtils.isNotBlank(MapUtils.getString(param, "technologyId"))) {
            sql.append(
                    "AND RE.LINK_TYPE='TECHNOLOGY_SUBTECHNOLOGY' AND RE.TO_RRN = (select from_rrn from " + "relation " +
                            "where LINK_TYPE='SUBTECHNOLOGY_PRODUCT' AND TO_RRN = L.PRODUCT_RRN) ");
            sql.append("AND getinstanceid(FROM_RRN) = ? ");
            argList.add(MapUtils.getString(param, "technologyId"));
        }

        if (StringUtils.isNotBlank(MapUtils.getString(param, "carrierId"))) {
            sql.append("AND getinstanceid(L.CARRIER_RRN) LIKE ? ");
            argList.add(MapUtils.getString(param, "carrierId"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "routeId"))) {
            sql.append(
                    "AND REGEXP_SUBSTR(L.PROCESS_STEP_ID_VERSION, '[^,]+', instr(L.PROCESS_STEP_ID_VERSION," + " '|'," +
                            " 1, 1) + 1, 1) LIKE ? ");
            argList.add(MapUtils.getString(param, "routeId"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "recipeId"))) {
            sql.append("AND GETINSTANCEID(GETCONTEXTRECIPERRN(L.PRODUCT_RRN, L.PROCESS_RRN, ");
            sql.append(
                    "REGEXP_SUBSTR(L.PROCESS_STEP_VERSION, '[^,]+', INSTR(L.PROCESS_STEP_VERSION, '|', 1, " + "1) + " +
                            "1, 1), ");
            sql.append("L.OPERATION_RRN, L.PROCESS_VERSION,L.PRODUCT_VERSION)) = ? ");
            argList.add(MapUtils.getString(param, "recipeId"));
        }
        sql.append(") LOT_T ");
        sql.append(
                " LEFT JOIN OPERATION_EXT OE ON LOT_T.STEP_RRN = OE.OPERATION_RRN LEFT JOIN (SELECT" + " DISTINCT RS" +
                        ".TO_RRN AS STEP_RRN, RS.FROM_RRN AS STATION_RRN, getinstanceid(RS" + ".FROM_RRN) " +
                        "AS STATION_ID" + " FROM RELATION RS WHERE RS.LINK_TYPE = 'STATION_TO_OPERATION' UNION " +
                        "SELECT " + "DISTINCT O" +
                        ".OPERATION_RRN AS STEP_RRN, EQPT_GROUP_T.STATION_RRN, EQPT_GROUP_T" + ".STATION_ID " +
                        "FROM " + "OPERATION O,  (SELECT EQPT_GROUP_R.TO_RRN AS EPQT_GROUP_RRN, EQPT_STATION_T" +
                        ".STATION_RRN, " + "EQPT_STATION_T.STATION_ID FROM RELATION EQPT_GROUP_R, (SELECT " +
                        "EQPT_STATION_R.TO_RRN AS " + "EQPT_RRN, STATION_T.FROM_RRN    AS STATION_RRN, STATION_ID " +
                        "FROM" + " RELATION " +
                        "EQPT_STATION_R, (SELECT N.INSTANCE_RRN AS FROM_RRN, N.INSTANCE_ID AS " + "STATION_ID FROM " +
                        "NAMED_OBJECT N WHERE N.OBJECT = 'STATION') STATION_T WHERE " + "EQPT_STATION_R.LINK_TYPE = " +
                        "'STATION_TO_EQUIPMENT' AND EQPT_STATION_R.FROM_RRN IN " + "(STATION_T.FROM_RRN)) " +
                        "EQPT_STATION_T WHERE EQPT_GROUP_R.LINK_TYPE = " + "'ENTITY_TO_ENTITY_GROUP' AND " +
                        "EQPT_GROUP_R.FROM_RRN = EQPT_STATION_T.EQPT_RRN) " + "EQPT_GROUP_T WHERE O" +
                        ".ENTITY_GROUP_RRN IN (EQPT_GROUP_T.EPQT_GROUP_RRN)) STATION_T ON " + "LOT_T.STEP_RRN = " +
                        "STATION_T.STEP_RRN LEFT JOIN OPERATION O ON LOT_T" + ".STEP_RRN = O.OPERATION_RRN," +
                        "(SELECT RF.KEY_1_VALUE, RF.DATA_1_VALUE FROM " + "NAMED_OBJECT N, " +
                        "REFERENCE_FILE_DETAIL RF WHERE N.INSTANCE_ID = '$LOT_CREATE_CATEGORY' " + "AND N" +
                        ".NAMED_SPACE = 'MYCIM2' AND N.OBJECT = 'REFERENCEFILE' AND N.INSTANCE_RRN = RF" +
                        ".REFERENCE_FILE_RRN) LOT_CATEGORY_REF, (SELECT RF.KEY_1_VALUE, RF.DATA_1_VALUE FROM " +
                        "NAMED_OBJECT N, REFERENCE_FILE_DETAIL RF WHERE N.INSTANCE_ID = '$$LOT_STATUS' AND" + " N" +
                        ".NAMED_SPACE = 'MYCIM2' AND N.OBJECT = 'REFERENCEFILE' AND N.INSTANCE_RRN =" + " RF" +
                        ".REFERENCE_FILE_RRN) LOT_STATUS_REF WHERE LOT_T.LOT_STATUS = " + "LOT_STATUS_REF" +
                        ".KEY_1_VALUE " + "AND LOT_T.CREATE_CATEGORY = " + "LOT_CATEGORY_REF.KEY_1_VALUE  ");
        if (StringUtils.isNotBlank(MapUtils.getString(param, "stationId"))) {
            sql.append("AND STATION_T.STATION_ID LIKE ? ");
            argList.add(MapUtils.getString(param, "stationId"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "eqptGroupId"))) {
            sql.append("AND getinstanceid(O.ENTITY_GROUP_RRN) LIKE ? ");
            argList.add(MapUtils.getString(param, "eqptGroupId"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "workArea"))) {
            sql.append("AND OE.ATTRIBUTE_DATA5 = ? ");
            argList.add(MapUtils.getString(param, "workArea"));
        }
        sql.append(") L left join UNIT U ");
        sql.append("on L.LOT_RRN = U.LOT_RRN ");
        sql.append("GROUP BY L.LOT_RRN) LOT_UNIT_T ");

        Map<String, Object> sqlMap = new HashMap<String, Object>();
        sqlMap.put("sql", sql.toString());
        sqlMap.put("argList", argList);
        return sqlMap;
    }

    private String getLotExtSql() {
        String sql = " SELECT LOT.FACILITY_RRN,LOT.LOT_ID,LOT.BASED_LOT_RRN,LOT.CREATED_PLAN_LOT_RRN," + "LOT" +
                ".HOT_FLAG,LOT.PRIORITY,LOT.STARTED_FLAG,LOT.STARTED_TIMESTAMP,LOT" + ".CREATE_CATEGORY," + "LOT" +
                ".CREATED_TIMESTAMP,LOT.END_TIMESTAMP,LOT.DUE_DATE,LOT.SCHEDULE_DUE_DATE," + " " + "LOT" +
                ".LATE_SCHEDULED_FLAG,LOT.ESTIMATED_REMAIN_TIME,LOT.DUMMY_FLAG,LOT.LOT_TYPE," +
                "LOT.LOT_OWNER,LOT.QTY1," + "LOT.QTY2,LOT.DUMMY_QTY1,LOT.INPUT_QTY1,LOT.INPUT_QTY2," + "LOT" +
                ".SUBCONTRACTOR_RRN, LOT.LOT_COMMENTS," + "LOT.STEP_SEQUENCE," + "LOT" +
                ".STEP_NUMBER_IN_PROCESS,LOT.HOLD_TIMESTAMP,LOT.REWORK_TRANS_RRN,LOT" + ".REWORK_CATEGORY," +
                "LOT.CARRIER_RRN,LOT.BEFORE_STATUS,LOT.LOT_STATUS,LOT" + ".PROCESSING_STATUS, LOT" +
                ".QUEUE_TIMESTAMP," + "LOT.PRODUCT_RRN,LOT.PROCESS_RRN," +
                "LOT.PROCESS_VERSION,LOT.PROCESS_STEP_VERSION," + "LOT.PROCESS_STEP_ID_VERSION,LOT" +
                ".OPERATION_RRN,LOT.OPERATION_VERSION,LOT" + ".NEXT_STEP_VERSION1," + "LOT" +
                ".NEXT_STEP_ID_VERSION1,LOT.NEXT_OPERATION_RRN1,LOT.NEXT_STEP_VERSION2,LOT" +
                ".NEXT_STEP_ID_VERSION2," + "LOT.NEXT_OPERATION_RRN2, LOT.STAGE_ID,LOT.LAYER_ID,LOT" +
                ".BOR_RRN,LOT.EQPT_RRN," + "LOT_EXT.TEMP_RECIPE_STRING,LOT_EXT.ATTRIBUTE_DATA1,LOT" +
                ".NEXT_RECIPE_STRING1,LOT" + ".NEXT_RECIPE_STRING2," + "LOT.JOB_RRN,LOT" +
                ".NEXT_JOB_RRN1,LOT.NEXT_JOB_RRN2,LOT.EXECUTION_RRN,LOT.LOT_RRN,LOT" + ".WFL_STEP_PATH," +
                "LOT.reticle_rrn, TIME_REMAINING,LOT.SHIPPED_QTY1,LOT" + ".SHIPPED_QTY2,LOT.PRODUCT_LAYER," +
                "LOT.ROUTE_SEQ,LOT.OPERATION_SEQ FROM LOT , " + "LOT_EXT ,(SELECT LOT_RRN," +
                " DECODE(SIGN(TIME_REMAINING),-1,0,TIME_REMAINING) AS " + "TIME_REMAINING FROM (select " + "lot_rrn," +
                "min((ROUND(TO_NUMBER( TO_DATE(TO_CHAR" + "(T0.START_TIME,'YYYY-MM-DD HH24:MI:SS')," +
                "'YYYY-MM-DD HH24:MI:SS') " + "- " +
                "SYSDATE )* 86400))+T0.TIMELIMIT) AS TIME_REMAINING from TIMELIMIT_STATUS t0 where " +
                "t0.timelimit>=0 and t0.status='NORMAL' group by lot_rrn))  T  ";
        return sql;
    }

    private String buildLocationId(Long locationRrn) {
        if (locationRrn != null && locationRrn > 0) {
            String locationId = getObjectLocationId(locationRrn);
            locationId = StringUtils.isEmpty(locationId) ? getLocationId(locationRrn) : locationId;
            return locationId;
        } else if (locationRrn != null && locationRrn < 0) {
            return getLotLocationByRef(locationRrn);
        }
        return StringUtils.EMPTY;
    }

    private String getLotLocationByRef(long locationRrn) {
        String sql = "SELECT T.DATA_1_VALUE FROM ( SELECT D.KEY_1_VALUE AS KEY_1_VALUE,D.DATA_1_VALUE," +
                "REGEXP_REPLACE( D.KEY_1_VALUE, '^[0-9]+$' ) FROM REFERENCE_FILE_DETAIL D " +
                " WHERE D.REFERENCE_FILE_RRN IN" + " (SELECT INSTANCE_RRN FROM NAMED_OBJECT WHERE OBJECT = " +
                "'REFERENCEFILE' AND INSTANCE_ID = ?) ) T WHERE " + "T.KEY_1_VALUE = ? ";
        List<String> data1s = jdbcTemplate.query(sql, new Object[]{ReferenceDetailNames.LOT_LOCATION_REF,
                                                                   StringUtils.toString(Math.abs(locationRrn))},
                                                 (RowMapper<String>) (rs, rowNum) -> rs.getString("DATA_1_VALUE"));
        return CollectionUtils.isNotEmpty(data1s) ? data1s.get(0) : StringUtils.EMPTY;
    }

    private String getObjectLocationId(long locationRrn) {
        String sql = " SELECT instance_id FROM NAMED_OBJECT WHERE instance_rrn=? and  object = 'ENTITY'";
        return jdbcTemplate.queryForObjectWithNull(sql, new Object[]{locationRrn}, String.class);
    }

    private String getUOM1(Long operationRrn) {
        return getUOM(operationRrn, UOM1_TYPE);
    }

    private String getUOM(Long operationRrn, String type) {
        String uom = StringUtils.EMPTY;
        String sql = "SELECT UNIT_OF_MEASURE1,UNIT_OF_MEASURE2 FROM " + DataBaseNames.OPERATION + " " + "WHERE " +
                "OPERATION_RRN = ?";
        Map results = jdbcTemplate.queryForObjectWithNull(sql, new Object[]{operationRrn}, Map.class);
        if (MapUtils.isNotEmpty(results)) {
            if (type.equals("1")) {
                uom = MapUtils.getString(results, "UNIT_OF_MEASURE1");
            } else {
                uom = MapUtils.getString(results, "UNIT_OF_MEASURE2");
            }
        }
        return uom;
    }

    private String getUOM2(Long operationRrn) {
        return getUOM(operationRrn, UOM2_TYPE);
    }
}