# 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);
        }
    }