public List<CardCdr> findCardCdr(
     Account account,
     List<String> restrictedMerchants,
     String pin,
     String serial,
     String status,
     List<Integer> amounts,
     List<String> cardTypes,
     String searchMerchant,
     List<String> merchants,
     List<String> providers,
     Date fromTime,
     Date toTime,
     int offset,
     int limit) {
   Query query =
       getQuery(
           account,
           restrictedMerchants,
           pin,
           serial,
           status,
           amounts,
           cardTypes,
           searchMerchant,
           merchants,
           providers,
           fromTime,
           toTime);
   if (query == null) return null;
   Sort orderBy = new Sort(Sort.Direction.DESC, new String[] {"timestamp"});
   query.with(orderBy);
   if (offset > 0) query.skip(offset);
   if (limit > 0) {
     query.limit(limit);
   }
   List<CardCdr> cdrs = this.mongoTemplate.find(query, CardCdr.class);
   if ((cdrs != null) && (cdrs.size() > 0)) {
     for (CardCdr cardCdr : cdrs) {
       cardCdr.setTimestamp(Utils.mongoDbTimeToDisplayTime(cardCdr.getTimestamp()));
     }
   }
   return cdrs;
 }
  private Query getQuery(
      Account account,
      List<String> restrictedMerchants,
      String pin,
      String serial,
      String status,
      List<Integer> amounts,
      List<String> cardTypes,
      String searchMerchant,
      List<String> merchants,
      List<String> providers,
      Date fromTime,
      Date toTime) {
    if (account == null) return null;
    if (!account.isAdmin()) if (!account.isStaff()) ;
    boolean isAdmin = account.checkRoles(new String[] {"biz_supporter", "customer_care"});
    Query query = new Query();

    Criteria searchMerchantCriteria = null;
    if (StringUtils.isNotEmpty(searchMerchant)) {
      String[] arrayOfString = null;
      int j = 0;
      int i = 0;
      if ((isAdmin)
          && (SharedConstants.MBIZ)
          && (SharedConstants.MBIZ_MERCHANTS != null)
          && (SharedConstants.MBIZ_MERCHANTS.length > 0)) {
        j = (arrayOfString = SharedConstants.MBIZ_MERCHANTS).length;
        i = 0;
      }
      while (true) {
        String mbizMerchant = arrayOfString[i];
        if (mbizMerchant.indexOf(searchMerchant) != -1) {
          searchMerchantCriteria = Criteria.where("merchant").regex(searchMerchant, "i");
        } else {
          i++;
          if (i < j) continue;
          break;

          // searchMerchantCriteria = Criteria.where("merchant").regex(searchMerchant, "i");
        }
      }
    }
    if (!isAdmin) {
      if ((restrictedMerchants == null) || (restrictedMerchants.isEmpty())) return null;
      List filterMerchants = new ArrayList();
      if ((merchants != null) && (merchants.size() > 0)) {
        for (String merchant : merchants) {
          if (restrictedMerchants.contains(merchant)) filterMerchants.add(merchant);
        }
        if (filterMerchants.size() == 0) return null;
      }
      if (filterMerchants.size() > 0) {
        if (filterMerchants.size() > 1) {
          if (searchMerchantCriteria != null)
            searchMerchantCriteria =
                searchMerchantCriteria.andOperator(
                    new Criteria[] {Criteria.where("merchant").in(filterMerchants)});
          else searchMerchantCriteria = Criteria.where("merchant").in(filterMerchants);
        } else if (searchMerchantCriteria != null)
          searchMerchantCriteria =
              searchMerchantCriteria.andOperator(
                  new Criteria[] {Criteria.where("merchant").is(filterMerchants.get(0))});
        else {
          searchMerchantCriteria = Criteria.where("merchant").is(filterMerchants.get(0));
        }
      } else if (restrictedMerchants.size() > 1) {
        if (searchMerchantCriteria != null)
          searchMerchantCriteria =
              searchMerchantCriteria.andOperator(
                  new Criteria[] {Criteria.where("merchant").in(restrictedMerchants)});
        else searchMerchantCriteria = Criteria.where("merchant").in(restrictedMerchants);
      } else if (searchMerchantCriteria != null)
        searchMerchantCriteria =
            searchMerchantCriteria.andOperator(
                new Criteria[] {Criteria.where("merchant").is(restrictedMerchants.get(0))});
      else {
        searchMerchantCriteria = Criteria.where("merchant").is(restrictedMerchants.get(0));
      }

    } else if ((merchants != null) && (merchants.size() > 0)) {
      if (merchants.size() > 1) {
        if (searchMerchantCriteria != null)
          searchMerchantCriteria =
              searchMerchantCriteria.andOperator(
                  new Criteria[] {Criteria.where("merchant").in(merchants)});
        else searchMerchantCriteria = Criteria.where("merchant").in(merchants);
      } else if (searchMerchantCriteria != null)
        searchMerchantCriteria =
            searchMerchantCriteria.andOperator(
                new Criteria[] {Criteria.where("merchant").is(merchants.get(0))});
      else {
        searchMerchantCriteria = Criteria.where("merchant").is(merchants.get(0));
      }
    }

    if (searchMerchantCriteria != null) {
      if ((isAdmin)
          && (SharedConstants.MBIZ)
          && (SharedConstants.MBIZ_MERCHANTS != null)
          && (SharedConstants.MBIZ_MERCHANTS.length > 0)
          && (!account.checkRole("customer_care"))
          && (!account.checkRole("biz_supporter"))) {
        searchMerchantCriteria =
            new Criteria()
                .andOperator(
                    new Criteria[] {
                      searchMerchantCriteria,
                      Criteria.where("merchant").in(Arrays.asList(SharedConstants.MBIZ_MERCHANTS))
                    });
      }

      query.addCriteria(searchMerchantCriteria);
    }

    if (StringUtils.isNotEmpty(pin)) {
      query.addCriteria(Criteria.where("pin").regex(Pattern.compile(pin, 34)));
    }
    if (StringUtils.isNotEmpty(serial)) {
      query.addCriteria(Criteria.where("serial").regex(Pattern.compile(serial, 34)));
    }
    if (StringUtils.isNotEmpty(status)) {
      query.addCriteria(Criteria.where("status").is(status));
    }
    if ((amounts != null) && (amounts.size() > 0)) {
      if (amounts.size() > 1) query.addCriteria(Criteria.where("amount").in(amounts));
      else query.addCriteria(Criteria.where("amount").is(amounts.get(0)));
    }
    if ((cardTypes != null) && (cardTypes.size() > 0)) {
      if (cardTypes.size() > 1) query.addCriteria(Criteria.where("type").in(cardTypes));
      else query.addCriteria(Criteria.where("type").is(cardTypes.get(0)));
    }
    if ((providers != null) && (providers.size() > 0)) {
      if (providers.size() > 1) query.addCriteria(Criteria.where("paymentProvider").in(providers));
      else {
        query.addCriteria(Criteria.where("paymentProvider").is(providers.get(0)));
      }
    }
    if ((fromTime != null) || (toTime != null)) {
      if (fromTime == null) fromTime = new Date(0L);
      if (toTime == null) toTime = new Date();
      if (fromTime.getTime() <= toTime.getTime()) {
        Criteria dateCriteria =
            Criteria.where("timestamp")
                .gte(Utils.convertToMongoDBTime(fromTime))
                .andOperator(
                    new Criteria[] {
                      Criteria.where("timestamp").lte(Utils.convertToMongoDBTime(toTime))
                    });
        query.addCriteria(dateCriteria);
      }
    }

    System.out.println(query.toString());
    return query;
  }