This is an automated email from the ASF dual-hosted git repository.

adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new e20e71548 FINERACT-1943 Transaction and datatable GET queries
e20e71548 is described below

commit e20e7154881c02c3709e13d8ac719cb587d04b5e
Author: jmarta <[email protected]>
AuthorDate: Sun Aug 6 01:30:06 2023 +0200

    FINERACT-1943 Transaction and datatable GET queries
---
 .../infrastructure/core/data/RangeOperator.java    |  31 --
 .../infrastructure/core/service/PagedRequest.java  |  12 +-
 .../database/DatabaseSpecificSQLGenerator.java     |   9 +-
 .../dataqueries/data/ColumnFilter.java             |  19 +-
 .../savings/SavingsAccountTransactionType.java     |   4 +
 ...tityDatatableChecksReadPlatformServiceImpl.java |  11 +-
 .../service/ReadWriteNonCoreDataService.java       |   6 +-
 .../service/ReadWriteNonCoreDataServiceImpl.java   |   6 +-
 .../api/SavingsAccountTransactionsApiResource.java |  42 +-
 ...vingsAccountTransactionsApiResourceSwagger.java |   4 +-
 .../SavingsAccountTransactionSearchValidator.java  |  95 -----
 .../data/SavingsTransactionSearchResult.java       | 147 -------
 .../SavingsAccountTransactionRepository.java       |   5 +-
 .../domain/search/SavingsTransactionSearch.java    |  51 ---
 .../search/SavingsTransactionSearchParameters.java |  39 --
 .../SavingsTransactionsSearchRepository.java       |  27 --
 .../SavingsTransactionsSearchRepositoryImpl.java   | 186 ---------
 .../SavingsAccountReadPlatformServiceImpl.java     |  84 ++--
 .../SavingsAccountTransactionSearchService.java    |   9 +-
 ...avingsAccountTransactionsSearchServiceImpl.java | 168 ++++++--
 .../fineract/portfolio/search/SearchConstants.java |   7 +
 .../portfolio/search/data/ColumnFilterData.java    |  51 +++
 .../fineract/portfolio/search/data/FilterData.java |  54 +++
 .../search/data/TransactionSearchRequest.java      | 106 +++++
 .../portfolio/search/service/SearchUtil.java       |  77 +++-
 .../ReadWriteNonCoreDataServiceImplTest.java       |   5 +-
 ...AccountTransactionDatatableIntegrationTest.java |   4 +-
 ...gsAccountTransactionsSearchIntegrationTest.java | 428 ++++++++++++---------
 .../common/savings/SavingsAccountHelper.java       |  18 +-
 29 files changed, 794 insertions(+), 911 deletions(-)

diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/RangeOperator.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/RangeOperator.java
deleted file mode 100644
index 67977e4b2..000000000
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/RangeOperator.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.fineract.infrastructure.core.data;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-@AllArgsConstructor
-@Getter
-public enum RangeOperator {
-
-    GTE(">="), LTE("<="), GT(">"), LT("<");
-
-    private final String symbol;
-}
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/PagedRequest.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/PagedRequest.java
index fd9f7b56f..12c3ff881 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/PagedRequest.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/PagedRequest.java
@@ -25,7 +25,6 @@ import java.util.List;
 import java.util.Optional;
 import lombok.Data;
 import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
 import org.springframework.data.domain.Sort;
 
 @Data
@@ -44,7 +43,7 @@ public class PagedRequest<T> {
         return Optional.ofNullable(request);
     }
 
-    public Pageable toPageable() {
+    public PageRequest toPageable() {
         if (isEmpty(sorts)) {
             return PageRequest.of(page, size);
         } else {
@@ -57,16 +56,11 @@ public class PagedRequest<T> {
     @SuppressWarnings({ "unused" })
     private static class SortOrder {
 
-        private Direction direction;
+        private Sort.Direction direction;
         private String property;
 
-        private enum Direction {
-            ASC, DESC;
-        }
-
         private Sort.Order toOrder() {
-            Sort.Direction d = Sort.Direction.fromString(direction.name());
-            return new Sort.Order(d, property);
+            return new Sort.Order(direction, property);
         }
     }
 }
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/DatabaseSpecificSQLGenerator.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/DatabaseSpecificSQLGenerator.java
index cce2807b9..115af018c 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/DatabaseSpecificSQLGenerator.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/DatabaseSpecificSQLGenerator.java
@@ -41,11 +41,14 @@ public class DatabaseSpecificSQLGenerator {
         this.databaseTypeResolver = databaseTypeResolver;
     }
 
+    public DatabaseType getDialect() {
+        return databaseTypeResolver.databaseType();
+    }
+
     public String escape(String arg) {
-        DatabaseType dialect = databaseTypeResolver.databaseType();
-        if (dialect.isMySql()) {
+        if (databaseTypeResolver.isMySQL()) {
             return format("`%s`", arg);
-        } else if (dialect.isPostgres()) {
+        } else if (databaseTypeResolver.isPostgreSQL()) {
             return format("\"%s\"", arg);
         }
         return arg;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/search/BaseQueryParametersMapResult.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/ColumnFilter.java
similarity index 69%
rename from 
fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/search/BaseQueryParametersMapResult.java
rename to 
fineract-core/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/ColumnFilter.java
index 4522f0169..7b72f2085 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/search/BaseQueryParametersMapResult.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/ColumnFilter.java
@@ -16,14 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.portfolio.savings.domain.search;
+package org.apache.fineract.infrastructure.dataqueries.data;
 
-import java.util.Map;
+import java.io.Serializable;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
+/**
+ * Immutable data object representing datatable data.
+ */
 @Data
-public class BaseQueryParametersMapResult {
+@NoArgsConstructor
+public final class ColumnFilter implements Serializable {
+
+    private String columnName;
+
+    private String columnValue;
+
+    private String columnOperation;
 
-    private final String baseQueryString;
-    private final Map<String, Object> parametersMap;
 }
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java
 
b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java
index c9aa0e230..48f5e00e6 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java
@@ -99,6 +99,10 @@ public enum SavingsAccountTransactionType {
         return transactionType == null ? INVALID : transactionType;
     }
 
+    public boolean isValid() {
+        return this != INVALID;
+    }
+
     public boolean isDeposit() {
         return this == DEPOSIT;
     }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadPlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadPlatformServiceImpl.java
index 3e5afd9de..37e604931 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadPlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadPlatformServiceImpl.java
@@ -30,6 +30,8 @@ import 
org.apache.fineract.infrastructure.core.service.PaginationHelper;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import 
org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
 import 
org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver;
+import org.apache.fineract.infrastructure.core.service.database.JdbcJavaType;
+import org.apache.fineract.infrastructure.core.service.database.SqlOperator;
 import 
org.apache.fineract.infrastructure.dataqueries.data.DatatableCheckStatusData;
 import org.apache.fineract.infrastructure.dataqueries.data.DatatableChecksData;
 import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
@@ -172,11 +174,12 @@ public class EntityDatatableChecksReadPlatformServiceImpl 
implements EntityDatat
         return this.jdbcTemplate.query(sql, this.registerDataTableMapper); // 
NOSONAR
     }
 
-    protected static final class RegisterDataTableMapper implements 
RowMapper<DatatableChecksData> {
+    protected final class RegisterDataTableMapper implements 
RowMapper<DatatableChecksData> {
+
+        public static final String SELECT_FROM = " t.application_table_name as 
entity, t.registered_table_name as tableName FROM x_registered_table t WHERE ";
 
         @Override
         public DatatableChecksData mapRow(final ResultSet rs, 
@SuppressWarnings("unused") final int rowNum) throws SQLException {
-
             final String entity = rs.getString("entity");
             final String tableName = rs.getString("tableName");
 
@@ -184,8 +187,8 @@ public class EntityDatatableChecksReadPlatformServiceImpl 
implements EntityDatat
         }
 
         public String schema() {
-            return " t.application_table_name as entity, 
t.registered_table_name as tableName " + " from x_registered_table t "
-                    + " where application_table_name IN( 
'm_client','m_group','m_savings_account','m_loan')";
+            String[] values = 
EntityTables.getFiltered(EntityTables::hasCheck).stream().map(EntityTables::getName).toArray(String[]::new);
+            return SELECT_FROM + SqlOperator.IN.formatSql(sqlGenerator, 
JdbcJavaType.VARCHAR, "application_table_name", null, values);
         }
     }
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataService.java
index e95061c30..e10aa9a06 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataService.java
@@ -19,6 +19,7 @@
 package org.apache.fineract.infrastructure.dataqueries.service;
 
 import com.google.gson.JsonObject;
+import jakarta.validation.constraints.NotNull;
 import java.util.List;
 import org.apache.fineract.infrastructure.core.api.JsonCommand;
 import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
@@ -32,8 +33,6 @@ public interface ReadWriteNonCoreDataService {
 
     DatatableData retrieveDatatable(String datatable);
 
-    List<JsonObject> queryDataTable(String datatable, String columnFilter, 
String valueFilter, String resultColumns);
-
     @PreAuthorize(value = "hasAnyAuthority('ALL_FUNCTIONS', 
'REGISTER_DATATABLE')")
     void registerDatatable(JsonCommand command);
 
@@ -73,4 +72,7 @@ public interface ReadWriteNonCoreDataService {
     String getDataTableName(String Url);
 
     Long countDatatableEntries(String datatableName, Long appTableId, String 
foreignKeyColumn);
+
+    List<JsonObject> queryDataTable(@NotNull String datatable, @NotNull String 
columnName, String columnValue,
+            @NotNull String resultColumns);
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
index 000433a52..bf2a82db6 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
@@ -210,8 +210,7 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
             throw new PlatformApiDataValidationException(errors);
         }
 
-        DatabaseType dialect = databaseTypeResolver.databaseType();
-        Object columnValue = 
SearchUtil.parseAndValidateJdbcColumnValue(columnName, columnValueString, 
columnHeaders, dialect);
+        Object columnValue = 
SearchUtil.parseAndValidateJdbcColumnValue(columnName, columnValueString, 
columnHeaders, false, sqlGenerator);
         String sql = sqlGenerator.buildSelect(selectColumns, null, false) + " 
" + sqlGenerator.buildFrom(datatable, null, false) + " WHERE "
                 + EQ.formatPlaceholder(sqlGenerator, columnName, null);
         SqlRowSet rowSet = jdbcTemplate.queryForRowSet(sql, columnValue);
@@ -1812,7 +1811,6 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
         String queryParamColumnUnderscored;
         String columnHeaderUnderscored;
         boolean notFound;
-        DatabaseType dialect = databaseTypeResolver.databaseType();
 
         final Map<String, Object> affectedColumns = new HashMap<>();
         final Set<String> keys = queryParams.keySet();
@@ -1833,7 +1831,7 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
                         if 
(queryParamColumnUnderscored.equalsIgnoreCase(columnHeaderUnderscored)) {
                             pValue = queryParams.get(key);
                             validatedValue = 
SearchUtil.parseAndValidateColumnValue(columnHeader, pValue, dateFormat,
-                                    clientApplicationLocale, dialect);
+                                    clientApplicationLocale, true, 
sqlGenerator);
                             affectedColumns.put(columnHeader.getColumnName(), 
validatedValue);
                             notFound = false;
                         }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountTransactionsApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountTransactionsApiResource.java
index bbbc66218..a1ed7911d 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountTransactionsApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountTransactionsApiResource.java
@@ -37,7 +37,9 @@ import jakarta.ws.rs.QueryParam;
 import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.UriInfo;
+import java.math.BigDecimal;
 import java.util.Collection;
+import java.util.Locale;
 import lombok.RequiredArgsConstructor;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.fineract.commands.domain.CommandWrapper;
@@ -49,18 +51,19 @@ import 
org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityEx
 import 
org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException;
 import 
org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
 import 
org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
-import org.apache.fineract.infrastructure.core.service.Page;
-import org.apache.fineract.infrastructure.core.service.PagedRequest;
+import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
 import 
org.apache.fineract.portfolio.paymenttype.service.PaymentTypeReadPlatformService;
 import org.apache.fineract.portfolio.savings.DepositAccountType;
 import org.apache.fineract.portfolio.savings.SavingsApiConstants;
 import 
org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
-import 
org.apache.fineract.portfolio.savings.domain.search.SavingsTransactionSearch;
 import 
org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformService;
-import 
org.apache.fineract.portfolio.savings.service.search.SavingsAccountTransactionsSearchServiceImpl;
+import 
org.apache.fineract.portfolio.savings.service.search.SavingsAccountTransactionSearchService;
+import org.apache.fineract.portfolio.search.data.TransactionSearchRequest;
 import org.springframework.dao.CannotAcquireLockException;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Sort;
 import org.springframework.orm.ObjectOptimisticLockingFailureException;
 import org.springframework.stereotype.Component;
 
@@ -76,7 +79,7 @@ public class SavingsAccountTransactionsApiResource {
     private final ApiRequestParameterHelper apiRequestParameterHelper;
     private final SavingsAccountReadPlatformService 
savingsAccountReadPlatformService;
     private final PaymentTypeReadPlatformService 
paymentTypeReadPlatformService;
-    private final SavingsAccountTransactionsSearchServiceImpl 
transactionsSearchServiceImpl;
+    private final SavingsAccountTransactionSearchService 
transactionsSearchService;
 
     private boolean is(final String commandParam, final String commandValue) {
         return StringUtils.isNotBlank(commandParam) && 
commandParam.trim().equalsIgnoreCase(commandValue);
@@ -124,16 +127,35 @@ public class SavingsAccountTransactionsApiResource {
                 
SavingsApiSetConstants.SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS);
     }
 
-    @POST
+    @GET
     @Path("search")
-    @Consumes({ MediaType.APPLICATION_JSON })
     @Produces({ MediaType.APPLICATION_JSON })
     @Operation(summary = "Search Savings Account Transactions")
     @ApiResponses({
             @ApiResponse(responseCode = "200", description = "OK", content = 
@Content(schema = @Schema(implementation = 
SavingsAccountTransactionsApiResourceSwagger.SavingsAccountTransactionsSearchResponse.class)))
 })
-    public String searchTransactions(@PathParam("savingsId") 
@Parameter(description = "savingsId") final Long savingsId,
-            @Parameter PagedRequest<SavingsTransactionSearch> searchRequest) {
-        Page<SavingsAccountTransactionData> transactionsData = 
transactionsSearchServiceImpl.searchTransactions(savingsId, searchRequest);
+    public String searchTransactions(@PathParam("savingsId") 
@Parameter(description = "savings account id") final Long savingsId,
+            @QueryParam("fromDate") @Parameter(description = "minimum value 
date (inclusive)", example = "2023-08-08") final String fromDate,
+            @QueryParam("toDate") @Parameter(description = "maximum value date 
(inclusive)", example = "2023-08-15") final String toDate,
+            @QueryParam("fromSubmittedDate") @Parameter(description = "minimum 
booking date (inclusive)", example = "2023-08-08") final String 
fromSubmittedDate,
+            @QueryParam("toSubmittedDate") @Parameter(description = "maximum 
booking date (inclusive)", example = "2023-08-15") final String toSubmittedDate,
+            @QueryParam("fromAmount") @Parameter(description = "minimum 
transaction amount (inclusive)", example = "1000") final BigDecimal fromAmount,
+            @QueryParam("toAmount") @Parameter(description = "maximum 
transaction amount (inclusive)", example = "50000000") final BigDecimal 
toAmount,
+            @QueryParam("types") @Parameter(description = "transaction types", 
example = "1,2,4,20,21") final String types,
+            @QueryParam("credit") @Parameter(description = "credit") final 
Boolean credit,
+            @QueryParam("debit") @Parameter(description = "debit") final 
Boolean debit,
+            @QueryParam("offset") @Parameter(description = "offset") final 
Integer offset,
+            @QueryParam("limit") @Parameter(description = "limit") final 
Integer limit,
+            @QueryParam("orderBy") @Parameter(description = "sort properties", 
example = "createdDate,transactionDate,id") final String orderBy,
+            @QueryParam("sortOrder") @Parameter(description = "sort 
direction") final Sort.Direction sortOrder,
+            @QueryParam("locale") @Parameter(description = "locale") final 
String localeString,
+            @QueryParam("dateFormat") @Parameter(description = "date format", 
example = "yyyy-MM-dd") String dateFormat) {
+        final Locale locale = localeString == null ? null : 
JsonParserHelper.localeFromString(localeString);
+        TransactionSearchRequest searchParameters = new 
TransactionSearchRequest().accountId(savingsId)
+                .fromDate(fromDate, dateFormat, locale).toDate(toDate, 
dateFormat, locale)
+                .fromSubmittedDate(fromSubmittedDate, dateFormat, 
locale).toSubmittedDate(toSubmittedDate, dateFormat, locale)
+                
.fromAmount(fromAmount).toAmount(toAmount).types(types).credit(credit).debit(debit)
+                .pageable(offset, limit, orderBy, sortOrder);
+        Page<SavingsAccountTransactionData> transactionsData = 
transactionsSearchService.searchTransactions(savingsId, searchParameters);
         return toApiJsonSerializer.serialize(transactionsData);
     }
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountTransactionsApiResourceSwagger.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountTransactionsApiResourceSwagger.java
index 80bd34c9d..3e7f53239 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountTransactionsApiResourceSwagger.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountTransactionsApiResourceSwagger.java
@@ -185,8 +185,8 @@ final class SavingsAccountTransactionsApiResourceSwagger {
         }
 
         @Schema(example = "2")
-        public Long totalFilteredRecords;
-        public Set<GetSavingsAccountTransactionsPageItem> pageItems;
+        public Long total;
+        public Set<GetSavingsAccountTransactionsPageItem> content;
     }
 
     @Schema(description = "PostSavingsAccountTransactionsRequest")
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionSearchValidator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionSearchValidator.java
deleted file mode 100644
index 39a17334a..000000000
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionSearchValidator.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.fineract.portfolio.savings.data;
-
-import static 
org.apache.fineract.portfolio.savings.SavingsApiConstants.transactionAmountParamName;
-import static 
org.apache.fineract.portfolio.savings.SavingsApiConstants.transactionDateParamName;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.fineract.infrastructure.core.data.ApiParameterError;
-import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
-import org.apache.fineract.infrastructure.core.data.RangeOperator;
-import 
org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
-import org.apache.fineract.portfolio.savings.SavingsApiConstants;
-import 
org.apache.fineract.portfolio.savings.domain.search.SavingsTransactionSearch;
-import 
org.apache.fineract.portfolio.savings.domain.search.SavingsTransactionSearch.RangeFilter;
-import org.springframework.stereotype.Component;
-
-@Component
-public class SavingsAccountTransactionSearchValidator {
-
-    public void validateSearchFilters(SavingsTransactionSearch.Filters 
searchFilters) {
-        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
-        final DataValidatorBuilder baseDataValidator = new 
DataValidatorBuilder(dataValidationErrors)
-                
.resource(SavingsApiConstants.SAVINGS_ACCOUNT_TRANSACTION_RESOURCE_NAME);
-        if (searchFilters != null) {
-
-            List<RangeFilter<LocalDate>> dateFilters = 
searchFilters.getTransactionDate();
-            validateRangeFilters(baseDataValidator, dateFilters, 
transactionDateParamName);
-
-            List<RangeFilter<BigDecimal>> amountFilters = 
searchFilters.getTransactionAmount();
-            validateRangeFilters(baseDataValidator, amountFilters, 
transactionAmountParamName);
-        }
-        throwExceptionIfValidationWarningsExist(dataValidationErrors);
-    }
-
-    private <T> void validateRangeFilters(DataValidatorBuilder 
baseDataValidator, List<RangeFilter<T>> rangeFilters, String paramName) {
-        if (rangeFilters == null) {
-            return;
-        }
-
-        if (rangeFilters.size() > 2) {
-            
baseDataValidator.parameter(paramName).value(rangeFilters).notExceedingListLengthOf(2);
-        }
-
-        if (!rangeFilters.isEmpty()) {
-            RangeFilter<T> firstFilter = rangeFilters.get(0);
-            RangeOperator firstOperator = firstFilter.getOperator();
-
-            if (rangeFilters.size() == 2) {
-                RangeFilter<T> secondFilter = rangeFilters.get(1);
-                RangeOperator secondOperator = secondFilter.getOperator();
-
-                if (((firstOperator == RangeOperator.GT || firstOperator == 
RangeOperator.GTE)
-                        && !(secondOperator == RangeOperator.LT || 
secondOperator == RangeOperator.LTE))
-                        || ((firstOperator == RangeOperator.LT || 
firstOperator == RangeOperator.LTE)
-                                && !(secondOperator == RangeOperator.GT || 
secondOperator == RangeOperator.GTE))) {
-                    
baseDataValidator.parameter(paramName).failWithCode("invalid.range", 
firstOperator, secondOperator);
-                }
-            }
-        }
-
-        for (RangeFilter<T> filter : rangeFilters) {
-            T value = filter.getValue();
-            if (value instanceof BigDecimal) {
-                
baseDataValidator.parameter(paramName).value(value).zeroOrPositiveAmount();
-            }
-        }
-    }
-
-    private void throwExceptionIfValidationWarningsExist(final 
List<ApiParameterError> dataValidationErrors) {
-        if (!dataValidationErrors.isEmpty()) {
-            throw new 
PlatformApiDataValidationException("validation.msg.validation.errors.exist", 
"Validation errors exist.",
-                    dataValidationErrors);
-        }
-    }
-}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsTransactionSearchResult.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsTransactionSearchResult.java
deleted file mode 100644
index 4ab2ad47c..000000000
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsTransactionSearchResult.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.fineract.portfolio.savings.data;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.util.Objects;
-import java.util.Optional;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import org.apache.fineract.organisation.monetary.data.CurrencyData;
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
-import org.apache.fineract.portfolio.account.data.AccountTransferData;
-import org.apache.fineract.portfolio.account.domain.AccountTransferTransaction;
-import org.apache.fineract.portfolio.paymentdetail.data.PaymentDetailData;
-import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
-import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
-import org.apache.fineract.portfolio.savings.service.SavingsEnumerations;
-import org.apache.fineract.useradministration.domain.AppUser;
-
-@Getter
-@AllArgsConstructor
-public class SavingsTransactionSearchResult {
-
-    private Long transactionId;
-    private Integer transactionType;
-    private LocalDate transactionDate;
-    private BigDecimal transactionAmount;
-    private Long releaseIdOfHoldAmountTransaction;
-    private String reasonForBlock;
-    private LocalDateTime createdDate;
-    private AppUser appUser;
-    private String note;
-    private BigDecimal runningBalance;
-    private boolean reversed;
-    private boolean reversalTransaction;
-    private Long originalTxnId;
-    private Boolean lienTransaction;
-    private boolean isManualTransaction;
-    private AccountTransferTransaction fromSavingsTransaction;
-    private AccountTransferTransaction toSavingsTransaction;
-    private SavingsAccount savingsAccount;
-    private PaymentDetail paymentDetail;
-    private ApplicationCurrency currency;
-
-    public static final SavingsAccountTransactionData 
toSavingsAccountTransactionData(SavingsTransactionSearchResult dto) {
-        final Long id = dto.getTransactionId();
-        final int transactionTypeInt = dto.getTransactionType();
-
-        final SavingsAccountTransactionEnumData transactionType = 
SavingsEnumerations.transactionType(transactionTypeInt);
-
-        final LocalDate date = dto.getTransactionDate();
-        final LocalDate submittedOnDate = 
Optional.ofNullable(dto.getCreatedDate()).map(LocalDateTime::toLocalDate).orElse(null);
-        final BigDecimal amount = 
Optional.ofNullable(dto.getTransactionAmount()).orElse(BigDecimal.ZERO);
-        final Long releaseTransactionId = 
Optional.ofNullable(dto.getReleaseIdOfHoldAmountTransaction()).orElse(null);
-        final String reasonForBlock = 
Optional.ofNullable(dto.getReasonForBlock()).orElse(null);
-        final BigDecimal outstandingChargeAmount = null;
-        final BigDecimal runningBalance = 
Optional.ofNullable(dto.getRunningBalance()).orElse(BigDecimal.ZERO);
-        final boolean reversed = dto.isReversed();
-        final boolean isReversal = dto.isReversalTransaction();
-        final Long originalTransactionId = 
Optional.ofNullable(dto.getOriginalTxnId()).orElse(null);
-        final Boolean lienTransaction = dto.getLienTransaction();
-
-        final Long savingsId = 
Optional.ofNullable(dto.getSavingsAccount()).map(savingsAccount -> 
savingsAccount.getId()).orElse(null);
-        final String accountNo = 
Optional.ofNullable(dto.getSavingsAccount()).map(savingsAccount -> 
savingsAccount.getAccountNumber())
-                .orElse(null);
-        final boolean postInterestAsOn = dto.isManualTransaction();
-
-        PaymentDetailData paymentDetailData = null;
-        if (Objects.nonNull(transactionType) && 
transactionType.isDepositOrWithdrawal()) {
-            final PaymentDetail paymentDetail = dto.getPaymentDetail();
-            if (Objects.nonNull(paymentDetail)) {
-                final Long paymentTypeId = 
Optional.ofNullable(paymentDetail.getPaymentType()).map(paymentType -> 
paymentType.getId())
-                        .orElse(null);
-                if (Objects.nonNull(paymentTypeId)) {
-                    final String typeName = 
Optional.ofNullable(paymentDetail.getPaymentType()).map(paymentType -> 
paymentType.getName())
-                            .orElse(null);
-                    final PaymentTypeData paymentType = 
PaymentTypeData.instance(paymentTypeId, typeName);
-                    final String accountNumber = 
paymentDetail.getAccountNumber();
-                    final String checkNumber = paymentDetail.getCheckNumber();
-                    final String routingCode = paymentDetail.getRoutingCode();
-                    final String receiptNumber = 
paymentDetail.getReceiptNumber();
-                    final String bankNumber = paymentDetail.getBankNumber();
-                    paymentDetailData = new PaymentDetailData(id, paymentType, 
accountNumber, checkNumber, routingCode, receiptNumber,
-                            bankNumber);
-                }
-            }
-        }
-
-        final String currencyCode = 
dto.getSavingsAccount().getCurrency().getCode();
-        final String currencyName = dto.getCurrency().getName();
-        final String currencyNameCode = dto.getCurrency().getNameCode();
-        final String currencyDisplaySymbol = 
dto.getCurrency().getDisplaySymbol();
-        final Integer currencyDigits = 
dto.getSavingsAccount().getCurrency().getDigitsAfterDecimal();
-        final Integer inMultiplesOf = 
dto.getSavingsAccount().getCurrency().getCurrencyInMultiplesOf();
-        final CurrencyData currency = new CurrencyData(currencyCode, 
currencyName, currencyDigits, inMultiplesOf, currencyDisplaySymbol,
-                currencyNameCode);
-
-        AccountTransferData transfer = null;
-        AccountTransferTransaction transferFrom = 
dto.getFromSavingsTransaction();
-        AccountTransferTransaction transferTo = dto.getToSavingsTransaction();
-        if (Objects.nonNull(transferFrom)) {
-            final Long fromTransferId = transferFrom.getId();
-            final LocalDate fromTransferDate = transferFrom.getDate();
-            final BigDecimal fromTransferAmount = 
Optional.ofNullable(transferFrom.getAmount()).orElse(BigDecimal.ZERO);
-            final boolean fromTransferReversed = transferFrom.isReversed();
-            final String fromTransferDescription = 
transferFrom.getDescription();
-
-            transfer = 
AccountTransferData.transferBasicDetails(fromTransferId, currency, 
fromTransferAmount, fromTransferDate,
-                    fromTransferDescription, fromTransferReversed);
-        } else if (Objects.nonNull(transferTo)) {
-            final Long toTransferId = transferTo.getId();
-            final LocalDate toTransferDate = transferTo.getDate();
-            final BigDecimal toTransferAmount = 
Optional.ofNullable(transferTo.getAmount()).orElse(BigDecimal.ZERO);
-            final boolean toTransferReversed = transferTo.isReversed();
-            final String toTransferDescription = transferTo.getDescription();
-
-            transfer = AccountTransferData.transferBasicDetails(toTransferId, 
currency, toTransferAmount, toTransferDate,
-                    toTransferDescription, toTransferReversed);
-        }
-        final String submittedByUsername = 
Optional.ofNullable(dto.getAppUser()).map(user -> 
user.getUsername()).orElse(null);
-        final String note = Optional.ofNullable(dto.getNote()).orElse(null);
-        return SavingsAccountTransactionData.create(id, transactionType, 
paymentDetailData, savingsId, accountNo, date, currency, amount,
-                outstandingChargeAmount, runningBalance, reversed, transfer, 
submittedOnDate, postInterestAsOn, submittedByUsername, note,
-                isReversal, originalTransactionId, lienTransaction, 
releaseTransactionId, reasonForBlock);
-
-    }
-
-}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionRepository.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionRepository.java
index ae0709658..2eba64bb2 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionRepository.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionRepository.java
@@ -21,7 +21,6 @@ package org.apache.fineract.portfolio.savings.domain;
 import jakarta.persistence.LockModeType;
 import java.time.LocalDate;
 import java.util.List;
-import 
org.apache.fineract.portfolio.savings.domain.search.SavingsTransactionsSearchRepository;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@@ -29,8 +28,8 @@ import org.springframework.data.jpa.repository.Lock;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.repository.query.Param;
 
-public interface SavingsAccountTransactionRepository extends 
JpaRepository<SavingsAccountTransaction, Long>,
-        JpaSpecificationExecutor<SavingsAccountTransaction>, 
SavingsTransactionsSearchRepository {
+public interface SavingsAccountTransactionRepository
+        extends JpaRepository<SavingsAccountTransaction, Long>, 
JpaSpecificationExecutor<SavingsAccountTransaction> {
 
     @Query("select sat from SavingsAccountTransaction sat where sat.id = 
:transactionId and sat.savingsAccount.id = :savingsId")
     SavingsAccountTransaction 
findOneByIdAndSavingsAccountId(@Param("transactionId") Long transactionId,
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/search/SavingsTransactionSearch.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/search/SavingsTransactionSearch.java
deleted file mode 100644
index ef09050bb..000000000
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/search/SavingsTransactionSearch.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.fineract.portfolio.savings.domain.search;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.util.List;
-import lombok.Data;
-import org.apache.fineract.infrastructure.core.data.RangeOperator;
-import org.apache.fineract.portfolio.savings.SavingsAccountTransactionType;
-
-@Data
-public class SavingsTransactionSearch {
-
-    private Filters filters;
-
-    @Data
-    public static class Filters {
-
-        private List<RangeFilter<LocalDate>> transactionDate;
-
-        private List<RangeFilter<BigDecimal>> transactionAmount;
-
-        private List<SavingsAccountTransactionType> transactionType;
-    }
-
-    @Data
-    public static class RangeFilter<T> {
-
-        private RangeOperator operator;
-
-        private T value;
-    }
-
-}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/search/SavingsTransactionSearchParameters.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/search/SavingsTransactionSearchParameters.java
deleted file mode 100644
index 4ec2f4dd8..000000000
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/search/SavingsTransactionSearchParameters.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.fineract.portfolio.savings.domain.search;
-
-import lombok.Builder;
-import lombok.Getter;
-import org.apache.fineract.portfolio.savings.DepositAccountType;
-import 
org.apache.fineract.portfolio.savings.domain.search.SavingsTransactionSearch.Filters;
-import org.springframework.data.domain.Pageable;
-
-@Getter
-@Builder
-public class SavingsTransactionSearchParameters {
-
-    private Long savingsId;
-
-    private DepositAccountType depositAccountType;
-
-    private Filters filters;
-
-    private Pageable pageable;
-
-}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/search/SavingsTransactionsSearchRepository.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/search/SavingsTransactionsSearchRepository.java
deleted file mode 100644
index 8a881154e..000000000
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/search/SavingsTransactionsSearchRepository.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.fineract.portfolio.savings.domain.search;
-
-import 
org.apache.fineract.portfolio.savings.data.SavingsTransactionSearchResult;
-import org.springframework.data.domain.Page;
-
-public interface SavingsTransactionsSearchRepository {
-
-    Page<SavingsTransactionSearchResult> 
searchTransactions(SavingsTransactionSearchParameters searchParameters);
-}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/search/SavingsTransactionsSearchRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/search/SavingsTransactionsSearchRepositoryImpl.java
deleted file mode 100644
index 2a92fea05..000000000
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/search/SavingsTransactionsSearchRepositoryImpl.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.fineract.portfolio.savings.domain.search;
-
-import jakarta.persistence.EntityManager;
-import jakarta.persistence.TypedQuery;
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.StringJoiner;
-import java.util.stream.Collectors;
-import lombok.RequiredArgsConstructor;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.fineract.portfolio.savings.DepositAccountType;
-import org.apache.fineract.portfolio.savings.SavingsAccountTransactionType;
-import 
org.apache.fineract.portfolio.savings.data.SavingsTransactionSearchResult;
-import 
org.apache.fineract.portfolio.savings.domain.search.SavingsTransactionSearch.Filters;
-import 
org.apache.fineract.portfolio.savings.domain.search.SavingsTransactionSearch.RangeFilter;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
-import org.springframework.data.domain.Sort.Order;
-import org.springframework.data.support.PageableExecutionUtils;
-import org.springframework.stereotype.Repository;
-
-@Repository
-@RequiredArgsConstructor
-public class SavingsTransactionsSearchRepositoryImpl implements 
SavingsTransactionsSearchRepository {
-
-    private static final String AMOUNT_FIELD_NAME = "amount";
-    private static final String ID_FIELD_NAME = "id";
-    private static final String CREATED_DATE_FIELD_NAME = "createdDate";
-    private static final String TRANSACTION_DATE_FIELD_NAME = "dateOf";
-    private final EntityManager entityManager;
-
-    @Override
-    public Page<SavingsTransactionSearchResult> 
searchTransactions(SavingsTransactionSearchParameters searchParameters) {
-        // Build base query with filters but without the selection
-        BaseQueryParametersMapResult baseQueryParameterMapResult = 
buildBaseQueryWithFilters(searchParameters.getSavingsId(),
-                searchParameters.getDepositAccountType(), 
searchParameters.getFilters());
-
-        // Attach the selection
-        String jpqlQuery = 
attachSelection(baseQueryParameterMapResult.getBaseQueryString());
-
-        // Attach the ordering
-        String queryWithOrdering = attachOrdering(jpqlQuery, 
searchParameters.getPageable().getSort());
-
-        // Execute Query
-        TypedQuery<SavingsTransactionSearchResult> queryToExecute = 
entityManager.createQuery(queryWithOrdering,
-                SavingsTransactionSearchResult.class);
-        setQueryParameters(queryToExecute, 
baseQueryParameterMapResult.getParametersMap());
-        applyPagination(queryToExecute, searchParameters.getPageable());
-        List<SavingsTransactionSearchResult> resultList = 
queryToExecute.getResultList();
-
-        // Attach the count selection
-        String countQuery = 
attachCountSelection(baseQueryParameterMapResult.getBaseQueryString());
-
-        // Execute count query
-        TypedQuery<Long> countQueryToExecute = 
entityManager.createQuery(countQuery, Long.class);
-        setQueryParameters(countQueryToExecute, 
baseQueryParameterMapResult.getParametersMap());
-        Long totalElements = countQueryToExecute.getSingleResult();
-
-        return PageableExecutionUtils.getPage(resultList, 
searchParameters.getPageable(), () -> totalElements);
-    }
-
-    private <T> void setQueryParameters(TypedQuery<T> queryToExecute, 
Map<String, Object> parametersMap) {
-        for (Map.Entry<String, Object> entry : parametersMap.entrySet()) {
-            queryToExecute.setParameter(entry.getKey(), entry.getValue());
-        }
-    }
-
-    private BaseQueryParametersMapResult buildBaseQueryWithFilters(Long 
savingsId, DepositAccountType depositAccountType, Filters filters) {
-        String baseQuery = """
-                        SELECT tr
-                        FROM SavingsAccountTransaction tr
-                        JOIN ApplicationCurrency currency ON (currency.code = 
tr.savingsAccount.currency.code)
-                        LEFT JOIN AccountTransferTransaction fromtran ON 
(fromtran.fromSavingsTransaction = tr)
-                        LEFT JOIN AccountTransferTransaction totran ON 
(totran.toSavingsTransaction = tr)
-                        LEFT JOIN tr.notes nt ON (nt.savingsTransaction = tr)
-                        WHERE tr.savingsAccount.id = :savingsId
-                        AND tr.savingsAccount.depositType = :depositType
-                """;
-        StringBuilder baseQueryBuilder = new StringBuilder(baseQuery);
-
-        Map<String, Object> parameterMap = new HashMap<>();
-        parameterMap.put("savingsId", savingsId);
-        parameterMap.put("depositType", depositAccountType.getValue());
-
-        setFilterConditions(baseQueryBuilder, parameterMap, filters);
-        return new BaseQueryParametersMapResult(baseQueryBuilder.toString(), 
parameterMap);
-    }
-
-    private String attachSelection(String baseQuery) {
-        return baseQuery.replace("SELECT tr",
-                "SELECT NEW 
org.apache.fineract.portfolio.savings.data.SavingsTransactionSearchResult(tr.id,tr.typeOf,
 tr.dateOf, tr.amount, tr.releaseIdOfHoldAmountTransaction, 
tr.reasonForBlock,tr.createdDate, tr.appUser, nt.note, tr.runningBalance, 
tr.reversed,tr.reversalTransaction, tr.originalTxnId, tr.lienTransaction, 
tr.isManualTransaction,fromTran, toTran, tr.savingsAccount, tr.paymentDetail, 
currency) ");
-    }
-
-    private String attachOrdering(String jpqlQuery, Sort sort) {
-        StringJoiner orderByClauseBuilder = new StringJoiner(", ", " ORDER BY 
", "");
-
-        if (Objects.nonNull(sort) && sort.isSorted()) {
-            buildOrderByClause(sort.toList(), orderByClauseBuilder);
-        } else {
-            List<Order> defaultOrders = getDefaultOrders();
-            buildOrderByClause(defaultOrders, orderByClauseBuilder);
-        }
-        return new 
StringBuilder(jpqlQuery).append(orderByClauseBuilder.toString()).toString();
-    }
-
-    private void buildOrderByClause(List<Order> orders, StringJoiner 
orderByClauseBuilder) {
-        for (Order order : orders) {
-            String property = "tr." + order.getProperty();
-            String direction = order.getDirection().name();
-            String orderByExpression = new 
StringBuilder(property).append(StringUtils.SPACE).append(direction).toString();
-            orderByClauseBuilder.add(orderByExpression);
-        }
-    }
-
-    private List<Order> getDefaultOrders() {
-        return List.of(Order.desc(TRANSACTION_DATE_FIELD_NAME), 
Order.desc(CREATED_DATE_FIELD_NAME), Order.desc(ID_FIELD_NAME));
-    }
-
-    private void applyPagination(TypedQuery<?> query, Pageable pageable) {
-        if (pageable.isPaged()) {
-            query.setFirstResult((int) pageable.getOffset());
-            query.setMaxResults(pageable.getPageSize());
-        }
-    }
-
-    private String attachCountSelection(String baseQuery) {
-        return baseQuery.replace("SELECT tr", "SELECT COUNT(tr) ");
-    }
-
-    private void setFilterConditions(StringBuilder queryBuilder, Map<String, 
Object> parameterMap, Filters filters) {
-        if (Objects.nonNull(filters)) {
-            List<RangeFilter<LocalDate>> dateFilters = 
filters.getTransactionDate();
-            List<RangeFilter<BigDecimal>> amountFilters = 
filters.getTransactionAmount();
-            List<SavingsAccountTransactionType> transactionTypes = 
filters.getTransactionType();
-
-            if (Objects.nonNull(dateFilters)) {
-                processRangeFilters(queryBuilder, parameterMap, dateFilters, 
TRANSACTION_DATE_FIELD_NAME);
-            }
-
-            if (Objects.nonNull(amountFilters)) {
-                processRangeFilters(queryBuilder, parameterMap, amountFilters, 
AMOUNT_FIELD_NAME);
-            }
-
-            if (CollectionUtils.isNotEmpty(transactionTypes)) {
-                List<Integer> transactionTypeValues = 
transactionTypes.stream().map(SavingsAccountTransactionType::getValue)
-                        .collect(Collectors.toList());
-                queryBuilder.append(" AND tr.typeOf IN :transactionTypes ");
-                parameterMap.put("transactionTypes", transactionTypeValues);
-            }
-        }
-    }
-
-    private <T> void processRangeFilters(StringBuilder queryBuilder, 
Map<String, Object> parameterMap, List<RangeFilter<T>> filters,
-            String field) {
-        filters.forEach(filter -> {
-            String paramName = new 
StringBuilder(field).append(filter.getOperator()).toString();
-            queryBuilder.append(" AND 
tr.").append(field).append(StringUtils.SPACE).append(filter.getOperator().getSymbol()).append("
 :")
-                    .append(paramName);
-            parameterMap.put(paramName, filter.getValue());
-        });
-    }
-}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
index 9740bbec7..e3835b879 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
@@ -1313,52 +1313,54 @@ public class SavingsAccountReadPlatformServiceImpl 
implements SavingsAccountRead
      * return this.jdbcTemplate.query(sql, this.annualFeeMapper, new Object[] 
{}); }
      */
 
-    private static final class SavingsAccountTransactionsMapper implements 
RowMapper<SavingsAccountTransactionData> {
+    public static final class SavingsAccountTransactionsMapper implements 
RowMapper<SavingsAccountTransactionData> {
+
+        private static final String SELECT = buildSelect();
+        private static final String FROM = buildFrom();
+        private static final String SCHEMA = SELECT + FROM;
+
+        public SavingsAccountTransactionsMapper() {}
+
+        private static String buildSelect() {
+            return "tr.id as transactionId, tr.transaction_type_enum as 
transactionType, "
+                    + "tr.transaction_date as transactionDate, tr.amount as 
transactionAmount, "
+                    + "tr.release_id_of_hold_amount as releaseTransactionId, 
tr.reason_for_block as reasonForBlock, "
+                    + "tr.submitted_on_date as submittedOnDate, au.username as 
submittedByUsername, nt.note as transactionNote, "
+                    + "tr.running_balance_derived as runningBalance, 
tr.is_reversed as reversed, "
+                    + "tr.is_reversal as isReversal, 
tr.original_transaction_id as originalTransactionId, tr.is_lien_transaction as 
lienTransaction, "
+                    + "fromtran.id as fromTransferId, fromtran.is_reversed as 
fromTransferReversed, "
+                    + "fromtran.transaction_date as fromTransferDate, 
fromtran.amount as fromTransferAmount, "
+                    + "fromtran.description as fromTransferDescription, "
+                    + "totran.id as toTransferId, totran.is_reversed as 
toTransferReversed, "
+                    + "totran.transaction_date as toTransferDate, 
totran.amount as toTransferAmount, "
+                    + "totran.description as toTransferDescription, sa.id as 
savingsId, sa.account_no as accountNo, "
+                    + "pd.payment_type_id as paymentType,pd.account_number as 
accountNumber,pd.check_number as checkNumber, "
+                    + "pd.receipt_number as receiptNumber, pd.bank_number as 
bankNumber,pd.routing_code as routingCode, "
+                    + "sa.currency_code as currencyCode, sa.currency_digits as 
currencyDigits, sa.currency_multiplesof as inMultiplesOf, "
+                    + "curr.name as currencyName, 
curr.internationalized_name_code as currencyNameCode, "
+                    + "curr.display_symbol as currencyDisplaySymbol, pt.value 
as paymentTypeName, " + "tr.is_manual as postInterestAsOn ";
+        }
 
-        private final String schemaSql;
+        private static String buildFrom() {
+            return " FROM m_savings_account_transaction tr join 
m_savings_account sa on tr.savings_account_id = sa.id "
+                    + "join m_currency curr on curr.code = sa.currency_code "
+                    + "left join m_account_transfer_transaction fromtran on 
fromtran.from_savings_transaction_id = tr.id "
+                    + "left join m_account_transfer_transaction totran on 
totran.to_savings_transaction_id = tr.id "
+                    + "left join m_payment_detail pd on tr.payment_detail_id = 
pd.id "
+                    + "left join m_payment_type pt on pd.payment_type_id = 
pt.id left join m_appuser au on au.id=tr.appuser_id "
+                    + "left join m_note nt ON 
nt.savings_account_transaction_id=tr.id ";
+        }
 
-        SavingsAccountTransactionsMapper() {
+        public String schema() {
+            return SCHEMA;
+        }
 
-            final StringBuilder sqlBuilder = new StringBuilder(400);
-            sqlBuilder.append("tr.id as transactionId, 
tr.transaction_type_enum as transactionType, ");
-            sqlBuilder.append("tr.transaction_date as transactionDate, 
tr.amount as transactionAmount,");
-            sqlBuilder.append(" tr.release_id_of_hold_amount as 
releaseTransactionId,");
-            sqlBuilder.append(" tr.reason_for_block as reasonForBlock,");
-            sqlBuilder.append("tr.submitted_on_date as submittedOnDate,");
-            sqlBuilder.append(" au.username as submittedByUsername, ");
-            sqlBuilder.append(" nt.note as transactionNote, ");
-            sqlBuilder.append("tr.running_balance_derived as runningBalance, 
tr.is_reversed as reversed,");
-            sqlBuilder.append(
-                    "tr.is_reversal as isReversal, tr.original_transaction_id 
as originalTransactionId, tr.is_lien_transaction as lienTransaction, ");
-            sqlBuilder.append("fromtran.id as fromTransferId, 
fromtran.is_reversed as fromTransferReversed,");
-            sqlBuilder.append("fromtran.transaction_date as fromTransferDate, 
fromtran.amount as fromTransferAmount,");
-            sqlBuilder.append("fromtran.description as 
fromTransferDescription,");
-            sqlBuilder.append("totran.id as toTransferId, totran.is_reversed 
as toTransferReversed,");
-            sqlBuilder.append("totran.transaction_date as toTransferDate, 
totran.amount as toTransferAmount,");
-            sqlBuilder.append("totran.description as toTransferDescription,");
-            sqlBuilder.append("sa.id as savingsId, sa.account_no as 
accountNo,");
-            sqlBuilder.append("pd.payment_type_id as 
paymentType,pd.account_number as accountNumber,pd.check_number as checkNumber, 
");
-            sqlBuilder.append("pd.receipt_number as receiptNumber, 
pd.bank_number as bankNumber,pd.routing_code as routingCode, ");
-            sqlBuilder.append(
-                    "sa.currency_code as currencyCode, sa.currency_digits as 
currencyDigits, sa.currency_multiplesof as inMultiplesOf, ");
-            sqlBuilder.append("curr.name as currencyName, 
curr.internationalized_name_code as currencyNameCode, ");
-            sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, 
");
-            sqlBuilder.append("pt.value as paymentTypeName, ");
-            sqlBuilder.append("tr.is_manual as postInterestAsOn ");
-            sqlBuilder.append("from m_savings_account sa ");
-            sqlBuilder.append("join m_savings_account_transaction tr on 
tr.savings_account_id = sa.id ");
-            sqlBuilder.append("join m_currency curr on curr.code = 
sa.currency_code ");
-            sqlBuilder.append("left join m_account_transfer_transaction 
fromtran on fromtran.from_savings_transaction_id = tr.id ");
-            sqlBuilder.append("left join m_account_transfer_transaction totran 
on totran.to_savings_transaction_id = tr.id ");
-            sqlBuilder.append("left join m_payment_detail pd on 
tr.payment_detail_id = pd.id ");
-            sqlBuilder.append("left join m_payment_type pt on 
pd.payment_type_id = pt.id ");
-            sqlBuilder.append(" left join m_appuser au on au.id=tr.appuser_id 
");
-            sqlBuilder.append(" left join m_note nt ON 
nt.savings_account_transaction_id=tr.id ");
-            this.schemaSql = sqlBuilder.toString();
+        public String select() {
+            return SELECT;
         }
 
-        public String schema() {
-            return this.schemaSql;
+        public String from() {
+            return FROM;
         }
 
         @Override
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/search/SavingsAccountTransactionSearchService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/search/SavingsAccountTransactionSearchService.java
index e330aeaed..3bf5765cf 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/search/SavingsAccountTransactionSearchService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/search/SavingsAccountTransactionSearchService.java
@@ -18,13 +18,12 @@
  */
 package org.apache.fineract.portfolio.savings.service.search;
 
-import org.apache.fineract.infrastructure.core.service.Page;
-import org.apache.fineract.infrastructure.core.service.PagedRequest;
+import jakarta.validation.constraints.NotNull;
 import 
org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
-import 
org.apache.fineract.portfolio.savings.domain.search.SavingsTransactionSearch;
+import org.apache.fineract.portfolio.search.data.TransactionSearchRequest;
+import org.springframework.data.domain.Page;
 
 public interface SavingsAccountTransactionSearchService {
 
-    Page<SavingsAccountTransactionData> searchTransactions(Long savingsId, 
PagedRequest<SavingsTransactionSearch> searchRequest);
-
+    Page<SavingsAccountTransactionData> searchTransactions(@NotNull Long 
savingsId, @NotNull TransactionSearchRequest searchParameters);
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/search/SavingsAccountTransactionsSearchServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/search/SavingsAccountTransactionsSearchServiceImpl.java
index 0d477e00c..ba06548d8 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/search/SavingsAccountTransactionsSearchServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/search/SavingsAccountTransactionsSearchServiceImpl.java
@@ -18,21 +18,37 @@
  */
 package org.apache.fineract.portfolio.savings.service.search;
 
-import java.util.Objects;
-import java.util.Optional;
+import static 
org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
+
+import jakarta.validation.constraints.NotNull;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
 import lombok.RequiredArgsConstructor;
-import org.apache.fineract.infrastructure.core.service.Page;
-import org.apache.fineract.infrastructure.core.service.PagedRequest;
+import org.apache.fineract.infrastructure.core.data.ApiParameterError;
+import 
org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.core.service.MathUtil;
+import 
org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
+import org.apache.fineract.infrastructure.core.service.database.SqlOperator;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
+import 
org.apache.fineract.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
+import 
org.apache.fineract.infrastructure.dataqueries.service.GenericDataService;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
-import org.apache.fineract.portfolio.savings.DepositAccountType;
+import org.apache.fineract.portfolio.savings.SavingsAccountTransactionType;
 import 
org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
-import 
org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionSearchValidator;
-import 
org.apache.fineract.portfolio.savings.data.SavingsTransactionSearchResult;
-import 
org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository;
-import 
org.apache.fineract.portfolio.savings.domain.search.SavingsTransactionSearch;
-import 
org.apache.fineract.portfolio.savings.domain.search.SavingsTransactionSearch.Filters;
-import 
org.apache.fineract.portfolio.savings.domain.search.SavingsTransactionSearchParameters;
-import org.springframework.data.domain.Pageable;
+import 
org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformServiceImpl;
+import org.apache.fineract.portfolio.search.data.ColumnFilterData;
+import org.apache.fineract.portfolio.search.data.TransactionSearchRequest;
+import org.apache.fineract.portfolio.search.service.SearchUtil;
+import org.jetbrains.annotations.Nullable;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.support.PageableExecutionUtils;
+import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -42,35 +58,117 @@ import 
org.springframework.transaction.annotation.Transactional;
 public class SavingsAccountTransactionsSearchServiceImpl implements 
SavingsAccountTransactionSearchService {
 
     private final PlatformSecurityContext context;
+    private final GenericDataService genericDataService;
+    private final DatabaseSpecificSQLGenerator sqlGenerator;
+    private final JdbcTemplate jdbcTemplate;
 
-    private final SavingsAccountTransactionRepository 
savingsTransactionRepository;
+    @Override
+    public Page<SavingsAccountTransactionData> searchTransactions(@NotNull 
Long savingsId,
+            @NotNull TransactionSearchRequest searchParameters) {
+        
context.authenticatedUser().validateHasReadPermission(SAVINGS_ACCOUNT_RESOURCE_NAME);
 
-    private final SavingsAccountTransactionSearchValidator searchValidator;
+        String apptable = EntityTables.SAVINGS_TRANSACTION.getApptableName();
+        Map<String, ResultsetColumnHeaderData> columnHeaders = SearchUtil
+                
.mapHeadersToName(genericDataService.fillResultsetColumnHeaders(apptable));
 
-    @Override
-    public Page<SavingsAccountTransactionData> searchTransactions(Long 
savingsId, PagedRequest<SavingsTransactionSearch> searchRequest) {
-        validateSearchRequest(searchRequest);
-        return executeSearch(savingsId, DepositAccountType.SAVINGS_DEPOSIT, 
searchRequest);
-    }
+        PageRequest pageable = searchParameters.getPageable();
+        PageRequest sortPageable;
+        if (pageable.getSort().isSorted()) {
+            List<ApiParameterError> errors = new ArrayList<>();
+            List<Sort.Order> orders = pageable.getSort().toList();
+            sortPageable = pageable.withSort(Sort.by(orders.stream()
+                    .map(e -> 
e.withProperty(SearchUtil.validateToJdbcColumn(e.getProperty(), columnHeaders, 
errors, false))).toList()));
+            if (!errors.isEmpty()) {
+                throw new PlatformApiDataValidationException(errors);
+            }
+        } else {
+            pageable = pageable.withSort(Sort.Direction.DESC, 
"transaction_date", "created_date", "id");
+            sortPageable = pageable;
+        }
+
+        List<ColumnFilterData> columnFilters = new ArrayList<>();
+        columnFilters.add(ColumnFilterData.eq("savings_account_id", 
savingsId.toString()));
+        columnFilters.add(ColumnFilterData.eq("is_reversal", 
Boolean.FALSE.toString()));
+        addFromToFilter("transaction_date", 
DateUtils.format(searchParameters.getFromDate()),
+                DateUtils.format(searchParameters.getToDate()), columnFilters);
+        addFromToFilter("submitted_on_date", 
DateUtils.format(searchParameters.getFromSubmittedDate()),
+                DateUtils.format(searchParameters.getToSubmittedDate()), 
columnFilters);
+        addFromToFilter("amount", 
MathUtil.formatToSql(searchParameters.getFromAmount()),
+                MathUtil.formatToSql(searchParameters.getToAmount()), 
columnFilters);
+
+        Page<SavingsAccountTransactionData> emptyResult = 
PageableExecutionUtils.getPage(new ArrayList<>(0), pageable, () -> 0);
+        if (addTransactionTypesFilter(searchParameters, columnFilters) == 
null) {
+            return emptyResult;
+        }
 
-    private void validateSearchRequest(PagedRequest<SavingsTransactionSearch> 
searchRequest) {
-        Objects.requireNonNull(searchRequest, "searchRequest must not be 
null");
-        context.isAuthenticated();
-        Optional<SavingsTransactionSearch> request = 
searchRequest.getRequest();
-        Filters searchFilters = 
request.map(SavingsTransactionSearch::getFilters).orElse(null);
-        searchValidator.validateSearchFilters(searchFilters);
+        String alias = "tr";
+        StringBuilder where = new StringBuilder(" WHERE ");
+        ArrayList<Object> params = new ArrayList<>();
+        SearchUtil.buildQueryCondition(columnFilters, where, params, alias, 
columnHeaders, false, false, sqlGenerator);
+
+        SavingsAccountReadPlatformServiceImpl.SavingsAccountTransactionsMapper 
tm = new 
SavingsAccountReadPlatformServiceImpl.SavingsAccountTransactionsMapper();
+        Object[] args = params.toArray();
+
+        String countQuery = "SELECT COUNT(*) " + tm.from() + where;
+        Integer totalElements = jdbcTemplate.queryForObject(countQuery, 
Integer.class, args);
+        if (totalElements == null || totalElements == 0) {
+            return emptyResult;
+        }
+
+        StringBuilder query = new StringBuilder().append("SELECT 
").append(tm.schema()).append(where);
+        query.append(" 
").append(sqlGenerator.buildOrderBy(sortPageable.getSort().toList(), alias, 
false));
+        if (pageable.isPaged()) {
+            query.append(" 
").append(sqlGenerator.limit(pageable.getPageSize(), (int) 
pageable.getOffset()));
+        }
+
+        List<SavingsAccountTransactionData> results = 
this.jdbcTemplate.query(query.toString(), tm, args);
+        return PageableExecutionUtils.getPage(results, pageable, () -> 
totalElements);
     }
 
-    private Page<SavingsAccountTransactionData> executeSearch(Long savingsId, 
DepositAccountType depositType,
-            PagedRequest<SavingsTransactionSearch> searchRequest) {
-        Optional<SavingsTransactionSearch> request = 
searchRequest.getRequest();
-        Pageable pageable = searchRequest.toPageable();
-        Filters searchFilters = 
request.map(SavingsTransactionSearch::getFilters).orElse(null);
-        SavingsTransactionSearchParameters searchParameters = 
SavingsTransactionSearchParameters.builder().savingsId(savingsId)
-                
.depositAccountType(DepositAccountType.SAVINGS_DEPOSIT).filters(searchFilters).pageable(pageable).build();
-        org.springframework.data.domain.Page<SavingsAccountTransactionData> 
pageResult = savingsTransactionRepository
-                
.searchTransactions(searchParameters).map(SavingsTransactionSearchResult::toSavingsAccountTransactionData);
-        return new Page<>(pageResult.getContent(), 
Long.valueOf(pageResult.getTotalElements()).intValue());
+    private static void addFromToFilter(@NotNull String column, String 
fromValue, String toValue,
+            @NotNull List<ColumnFilterData> columnFilters) {
+        if (fromValue != null) {
+            columnFilters.add(toValue == null ? 
ColumnFilterData.create(column, SqlOperator.GTE, fromValue)
+                    : ColumnFilterData.btw(column, fromValue, toValue));
+        } else if (toValue != null) {
+            columnFilters.add(ColumnFilterData.create(column, SqlOperator.LTE, 
toValue));
+        }
     }
 
+    @Nullable
+    private static Boolean addTransactionTypesFilter(@NotNull 
TransactionSearchRequest searchParameters,
+            List<ColumnFilterData> columnFilters) {
+        Predicate<SavingsAccountTransactionType> filter = null;
+        Boolean credit = searchParameters.getCredit();
+        Boolean debit = searchParameters.getDebit();
+
+        if (credit != null) {
+            Predicate<SavingsAccountTransactionType> cf = 
SavingsAccountTransactionType::isCreditEntryType;
+            filter = credit ? cf : Predicate.not(cf);
+        }
+        if (debit != null) {
+            Predicate<SavingsAccountTransactionType> df = 
SavingsAccountTransactionType::isDebitEntryType;
+            if (!debit) {
+                df = Predicate.not(df);
+            }
+            filter = credit == null ? df : (credit && debit ? filter.or(df) : 
filter.and(df));
+        }
+        if (searchParameters.getTypes() != null) {
+            List<String> types = Arrays.asList(searchParameters.getTypes());
+            Predicate<SavingsAccountTransactionType> tf = t -> 
types.contains(String.valueOf(t.getId()));
+            filter = filter == null ? tf : filter.and(tf);
+        }
+        if (filter != null) {
+            filter = filter.and(SavingsAccountTransactionType::isValid);
+            List<SavingsAccountTransactionType> filteredTypes = 
SavingsAccountTransactionType.getFiltered(filter);
+            if (filteredTypes.isEmpty()) {
+                return null;
+            } else {
+                String[] values = filteredTypes.stream().map(t -> 
String.valueOf(t.getId())).toArray(String[]::new);
+                
columnFilters.add(ColumnFilterData.create("transaction_type_enum", 
SqlOperator.IN, values));
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/SearchConstants.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/SearchConstants.java
index 48a327c58..dbe099447 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/SearchConstants.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/SearchConstants.java
@@ -23,7 +23,14 @@ import java.util.Set;
 
 public final class SearchConstants {
 
+    public static final String API_PARAM_RESULTCOLUMNS = "resultColumns";
+    public static final String API_PARAM_COLUMN_FILTERS = "columnFilters";
     public static final String API_PARAM_COLUMN = "column";
+    public static final String API_PARAM_FILTERS = "filters";
+    public static final String API_PARAM_OPERATOR = "operator";
+    public static final String API_PARAM_VALUES = "values";
+    public static final String API_PARAM_TABLE = "table";
+    public static final String API_PARAM_QUERY = "query";
 
     private SearchConstants() {}
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/data/ColumnFilterData.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/data/ColumnFilterData.java
new file mode 100644
index 000000000..a4c7ba746
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/data/ColumnFilterData.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.search.data;
+
+import java.io.Serializable;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.fineract.infrastructure.core.service.database.SqlOperator;
+
+/**
+ * Immutable data object representing datatable data.
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public final class ColumnFilterData implements Serializable {
+
+    private String column;
+
+    private List<FilterData> filters;
+
+    public static ColumnFilterData eq(String column, String value) {
+        return new ColumnFilterData(column, List.of(FilterData.eq(value)));
+    }
+
+    public static ColumnFilterData btw(String column, String value1, String 
value2) {
+        return new ColumnFilterData(column, List.of(FilterData.btw(value1, 
value2)));
+    }
+
+    public static ColumnFilterData create(String column, SqlOperator op, 
String... values) {
+        return new ColumnFilterData(column, List.of(FilterData.create(op, 
values)));
+    }
+}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/data/FilterData.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/data/FilterData.java
new file mode 100644
index 000000000..58345f2bc
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/data/FilterData.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.search.data;
+
+import static 
org.apache.fineract.infrastructure.core.service.database.SqlOperator.BTW;
+import static 
org.apache.fineract.infrastructure.core.service.database.SqlOperator.EQ;
+
+import java.io.Serializable;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.fineract.infrastructure.core.service.database.SqlOperator;
+
+/**
+ * Immutable data object representing datatable data.
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public final class FilterData implements Serializable {
+
+    private SqlOperator operator;
+
+    private List<String> values;
+
+    static FilterData eq(String value) {
+        return new FilterData(EQ, List.of(value));
+    }
+
+    static FilterData btw(String value1, String value2) {
+        return new FilterData(BTW, List.of(value1, value2));
+    }
+
+    static FilterData create(SqlOperator op, String... values) {
+        return new FilterData(op, List.of(values));
+    }
+}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/data/TransactionSearchRequest.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/data/TransactionSearchRequest.java
new file mode 100644
index 000000000..5b4953507
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/data/TransactionSearchRequest.java
@@ -0,0 +1,106 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.search.data;
+
+import static 
org.apache.fineract.portfolio.search.service.SearchUtil.DEFAULT_PAGE_SIZE;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.Locale;
+import lombok.Getter;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.core.service.MathUtil;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
+
+@Getter
+public class TransactionSearchRequest {
+
+    private Long accountId;
+    private LocalDate fromDate;
+    private LocalDate toDate;
+    private LocalDate fromSubmittedDate;
+    private LocalDate toSubmittedDate;
+    private BigDecimal fromAmount;
+    private BigDecimal toAmount;
+    private String[] types;
+    private Boolean credit;
+    private Boolean debit;
+
+    private PageRequest pageable;
+
+    public TransactionSearchRequest accountId(Long accountId) {
+        this.accountId = accountId;
+        return this;
+    }
+
+    public TransactionSearchRequest fromDate(String fromDate, String 
dateFormat, Locale locale) {
+        this.fromDate = fromDate == null ? null : 
DateUtils.parseLocalDate(fromDate, dateFormat, locale);
+        return this;
+    }
+
+    public TransactionSearchRequest toDate(String toDate, String dateFormat, 
Locale locale) {
+        this.toDate = toDate == null ? null : DateUtils.parseLocalDate(toDate, 
dateFormat, locale);
+        return this;
+    }
+
+    public TransactionSearchRequest fromSubmittedDate(String 
fromSubmittedDate, String dateFormat, Locale locale) {
+        this.fromSubmittedDate = fromSubmittedDate == null ? null : 
DateUtils.parseLocalDate(fromSubmittedDate, dateFormat, locale);
+        return this;
+    }
+
+    public TransactionSearchRequest toSubmittedDate(String toSubmittedDate, 
String dateFormat, Locale locale) {
+        this.toSubmittedDate = toSubmittedDate == null ? null : 
DateUtils.parseLocalDate(toSubmittedDate, dateFormat, locale);
+        return this;
+    }
+
+    public TransactionSearchRequest fromAmount(BigDecimal fromAmount) {
+        this.fromAmount = fromAmount;
+        return this;
+    }
+
+    public TransactionSearchRequest toAmount(BigDecimal toAmount) {
+        this.toAmount = toAmount;
+        return this;
+    }
+
+    public TransactionSearchRequest types(String types) {
+        this.types = types == null ? null : types.split(",");
+        return this;
+    }
+
+    public TransactionSearchRequest credit(Boolean credit) {
+        this.credit = credit;
+        return this;
+    }
+
+    public TransactionSearchRequest debit(Boolean debit) {
+        this.debit = debit;
+        return this;
+    }
+
+    public TransactionSearchRequest pageable(Integer offset, Integer limit, 
String orderByProps, Sort.Direction direction) {
+        offset = MathUtil.nullToDefault(offset, 0);
+        limit = MathUtil.nullToDefault(limit, DEFAULT_PAGE_SIZE);
+        String[] properties = Strings.isEmpty(orderByProps) ? null : 
orderByProps.split(",");
+        this.pageable = properties == null ? PageRequest.of(offset, limit) : 
PageRequest.of(offset, limit, direction, properties);
+        return this;
+    }
+}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/service/SearchUtil.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/service/SearchUtil.java
index 87a5653fb..2c3ac2211 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/service/SearchUtil.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/service/SearchUtil.java
@@ -46,10 +46,13 @@ import 
org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati
 import 
org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
 import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
-import org.apache.fineract.infrastructure.core.service.database.DatabaseType;
+import 
org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
 import org.apache.fineract.infrastructure.core.service.database.JdbcJavaType;
+import org.apache.fineract.infrastructure.core.service.database.SqlOperator;
 import 
org.apache.fineract.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
 import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
+import org.apache.fineract.portfolio.search.data.ColumnFilterData;
+import org.apache.fineract.portfolio.search.data.FilterData;
 import org.springframework.jdbc.support.rowset.SqlRowSet;
 
 public final class SearchUtil {
@@ -112,6 +115,7 @@ public final class SearchUtil {
         }
     }
 
+    @NotNull
     public static List<String> validateToJdbcColumns(List<String> columns, 
Map<String, ResultsetColumnHeaderData> columnHeaders,
             List<ApiParameterError> errors, boolean allowEmpty) {
         List<String> result = new ArrayList<>();
@@ -131,7 +135,6 @@ public final class SearchUtil {
             errors.add(parameterErrorWithValue("error.msg.column.empty", 
"Column filter is empty", API_PARAM_COLUMN, null));
         }
         if (column != null) {
-            SQLInjectionValidator.validateDynamicQuery(column);
             if (!columnHeaders.containsKey(column)) {
                 column = camelToSnake(column);
                 if (!columnHeaders.containsKey(column)) {
@@ -143,8 +146,64 @@ public final class SearchUtil {
         return column;
     }
 
+    public static boolean buildQueryCondition(List<ColumnFilterData> 
columnFilters, @NotNull StringBuilder where,
+            @NotNull List<Object> params, String alias, Map<String, 
ResultsetColumnHeaderData> columnHeaders, boolean embedded,
+            boolean strict, @NotNull DatabaseSpecificSQLGenerator 
sqlGenerator) {
+        if (columnFilters == null) {
+            return false;
+        }
+        boolean added = false;
+        int isize = columnFilters.size();
+        for (int i = 0; i < isize; i++) {
+            boolean addedFilter = buildFilterCondition(columnFilters.get(i), 
where, params, alias, columnHeaders, embedded, strict,
+                    sqlGenerator);
+            if (addedFilter && i < isize - 1) {
+                where.append(" AND ");
+            }
+            added |= addedFilter;
+        }
+        return added;
+    }
+
+    public static boolean buildFilterCondition(ColumnFilterData columnFilter, 
@NotNull StringBuilder where, @NotNull List<Object> params,
+            String alias, Map<String, ResultsetColumnHeaderData> 
columnHeaders, boolean embedded, boolean strict,
+            @NotNull DatabaseSpecificSQLGenerator sqlGenerator) {
+        String columnName = columnFilter.getColumn();
+        List<FilterData> filters = columnFilter.getFilters();
+        int size = filters.size();
+        for (int i = 0; i < size; i++) {
+            if (!embedded && where.isEmpty()) {
+                where.append(" WHERE ");
+            }
+            FilterData filter = filters.get(i);
+            SqlOperator operator = filter.getOperator();
+            List<String> values = filter.getValues();
+            List<Object> objectValues = values == null ? null
+                    : values.stream().map(e -> 
parseAndValidateJdbcColumnValue(columnName, e, columnHeaders, strict, 
sqlGenerator))
+                            .toList();
+
+            operator.validateValues(values);
+            if (operator.isPlaceholderSupported()) {
+                where.append(operator.formatPlaceholder(sqlGenerator, 
columnName, alias));
+                if (objectValues != null) {
+                    if (operator.isListType()) {
+                        params.add(objectValues);
+                    } else {
+                        params.addAll(objectValues);
+                    }
+                }
+            } else {
+                where.append(operator.formatSql(sqlGenerator, 
columnHeaders.get(columnName).getColumnType(), columnName, alias, values));
+            }
+            if (i < size - 1) {
+                where.append(" AND ");
+            }
+        }
+        return size > 0;
+    }
+
     public static Object parseAndValidateJdbcColumnValue(String column, String 
columnValue,
-            Map<String, ResultsetColumnHeaderData> columnHeaders, DatabaseType 
dialect) {
+            Map<String, ResultsetColumnHeaderData> columnHeaders, boolean 
strict, @NotNull DatabaseSpecificSQLGenerator sqlGenerator) {
         List<ApiParameterError> errors = new ArrayList<>();
         column = validateToJdbcColumn(column, columnHeaders, errors, false);
         if (!errors.isEmpty()) {
@@ -152,12 +211,12 @@ public final class SearchUtil {
         }
         ResultsetColumnHeaderData columnHeader = columnHeaders.get(column);
         String dateFormat = columnHeader.getColumnType().isDateTimeType() ? 
DEFAULT_DATETIME_FORMAT : DEFAULT_DATE_FORMAT;
-        return columnHeader.getColumnType().toJdbcValue(dialect,
-                parseAndValidateColumnValue(columnHeader, columnValue, 
dateFormat, ENGLISH, dialect), false);
+        return 
columnHeader.getColumnType().toJdbcValue(sqlGenerator.getDialect(),
+                parseAndValidateColumnValue(columnHeader, columnValue, 
dateFormat, ENGLISH, strict, sqlGenerator), false);
     }
 
     public static Object parseAndValidateColumnValue(final 
ResultsetColumnHeaderData columnHeader, final String pValue,
-            final String dateFormat, final Locale locale, DatabaseType 
dialect) {
+            final String dateFormat, final Locale locale, boolean strict, 
@NotNull DatabaseSpecificSQLGenerator sqlGenerator) {
         String columnValue = pValue;
         JdbcJavaType colType = columnHeader.getColumnType();
         if (!colType.isStringType() || !columnHeader.isMandatory()) {
@@ -173,7 +232,9 @@ public final class SearchUtil {
         if (StringUtils.isEmpty(columnValue)) {
             return columnValue;
         }
-        SQLInjectionValidator.validateDynamicQuery(columnValue);
+        if (strict) {
+            SQLInjectionValidator.validateDynamicQuery(columnValue);
+        }
 
         if (columnHeader.hasColumnValues()) {
             if (columnHeader.isCodeValueDisplayType()) {
@@ -193,7 +254,7 @@ public final class SearchUtil {
                 return codeLookup;
             } else {
                 throw new 
PlatformDataIntegrityException("error.msg.invalid.columnType.", "Code: " + 
columnHeader.getColumnName()
-                        + " - Invalid Type " + colType.getJdbcName(dialect) + 
" (neither varchar nor int)");
+                        + " - Invalid Type " + 
colType.getJdbcName(sqlGenerator.getDialect()) + " (neither varchar nor int)");
             }
         }
 
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImplTest.java
 
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImplTest.java
index caa5a9f9f..f38920ce8 100644
--- 
a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImplTest.java
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImplTest.java
@@ -37,7 +37,6 @@ import 
org.apache.fineract.infrastructure.core.service.database.DatabaseType;
 import 
org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver;
 import 
org.apache.fineract.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
 import 
org.apache.fineract.infrastructure.dataqueries.exception.DatatableNotFoundException;
-import org.apache.fineract.infrastructure.security.utils.SQLInjectionException;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -75,7 +74,7 @@ public class ReadWriteNonCoreDataServiceImplTest {
     @Test
     public void testSqlInjectionCaughtQueryDataTable() {
         mockDatatableValidation();
-        assertThrows(SQLInjectionException.class, () -> {
+        assertThrows(PlatformApiDataValidationException.class, () -> {
             underTest.queryDataTable("table", "cf1", "vf1", "' or 1=1");
         });
     }
@@ -83,7 +82,7 @@ public class ReadWriteNonCoreDataServiceImplTest {
     @Test
     public void testSqlInjectionCaughtQueryDataTable2() {
         mockDatatableValidation();
-        assertThrows(SQLInjectionException.class, () -> {
+        assertThrows(PlatformApiDataValidationException.class, () -> {
             underTest.queryDataTable("table", "cf1", "vf1", "1; DROP TABLE 
m_loan; SELECT");
         });
     }
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionDatatableIntegrationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionDatatableIntegrationTest.java
index 52ca3180d..bec3c9a75 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionDatatableIntegrationTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionDatatableIntegrationTest.java
@@ -56,10 +56,8 @@ public class 
SavingsAccountTransactionDatatableIntegrationTest {
 
     private static final String SAVINGS_TRANSACTION_APP_TABLE_NAME = 
EntityTables.SAVINGS_TRANSACTION.getName();
     public static final String ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL";
-    public static final String DEFAULT_DATE_FORMAT = "dd MMM yyyy";
     final String startDate = "01 Jun 2023";
     final String firstDepositDate = "05 Jun 2023";
-    final String secondDepositDate = "09 Jun 2023";
     private RequestSpecification requestSpec;
     private ResponseSpecification responseSpec;
     private DatatableHelper datatableHelper;
@@ -136,7 +134,7 @@ public class 
SavingsAccountTransactionDatatableIntegrationTest {
         assertNotNull(columnHeaderData);
 
         // two columns with 1 primary key and 2 audit columns created
-        assertEquals(columnHeaderData.size(), 6);
+        assertEquals(6, columnHeaderData.size());
 
         // deleting the datatable
         String deletedDataTableName = 
this.datatableHelper.deleteDatatable(datatableName);
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionsSearchIntegrationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionsSearchIntegrationTest.java
index c89440375..4be682d15 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionsSearchIntegrationTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionsSearchIntegrationTest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.fineract.integrationtests;
 
+import static 
org.apache.fineract.infrastructure.core.service.DateUtils.parseLocalDate;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
@@ -29,18 +30,18 @@ import io.restassured.specification.RequestSpecification;
 import io.restassured.specification.ResponseSpecification;
 import java.math.BigDecimal;
 import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
+import java.time.ZoneId;
 import java.util.HashMap;
 import java.util.List;
-import org.apache.fineract.client.models.Filters;
+import java.util.Locale;
+import java.util.Map;
+import java.util.stream.Collectors;
 import org.apache.fineract.client.models.GetSavingsAccountTransactionsPageItem;
-import org.apache.fineract.client.models.PagedRequestSavingsTransactionSearch;
-import org.apache.fineract.client.models.RangeFilterBigDecimal;
-import org.apache.fineract.client.models.RangeFilterLocalDate;
 import 
org.apache.fineract.client.models.SavingsAccountTransactionsSearchResponse;
-import org.apache.fineract.client.models.SavingsTransactionSearch;
-import org.apache.fineract.client.models.SortOrder;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.core.service.MathUtil;
+import org.apache.fineract.integrationtests.common.BusinessDateHelper;
 import org.apache.fineract.integrationtests.common.ClientHelper;
 import org.apache.fineract.integrationtests.common.CommonConstants;
 import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
@@ -48,16 +49,21 @@ import org.apache.fineract.integrationtests.common.Utils;
 import 
org.apache.fineract.integrationtests.common.savings.SavingsAccountHelper;
 import 
org.apache.fineract.integrationtests.common.savings.SavingsProductHelper;
 import 
org.apache.fineract.integrationtests.common.savings.SavingsStatusChecker;
+import org.apache.fineract.portfolio.savings.SavingsAccountTransactionType;
+import org.apache.fineract.portfolio.search.data.TransactionSearchRequest;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
 
 @SuppressWarnings({ "rawtypes" })
 public class SavingsAccountTransactionsSearchIntegrationTest {
 
     public static final String ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL";
     public static final String DEFAULT_DATE_FORMAT = "dd MMM yyyy";
+    public static final Locale DEFAULT_LOCALE = Locale.ENGLISH;
     final String startDate = "01 May 2023";
     final String firstDepositDate = "05 May 2023";
     final String secondDepositDate = "09 May 2023";
@@ -78,191 +84,229 @@ public class 
SavingsAccountTransactionsSearchIntegrationTest {
         this.requestSpec = new 
RequestSpecBuilder().setContentType(ContentType.JSON).build();
         this.requestSpec.header("Authorization", "Basic " + 
Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
         this.responseSpec = new 
ResponseSpecBuilder().expectStatusCode(200).build();
-        this.responseSpecForValidationError = new 
ResponseSpecBuilder().expectStatusCode(400).build();
         this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, 
this.responseSpec);
+        this.responseSpecForValidationError = new 
ResponseSpecBuilder().expectStatusCode(400).build();
         this.savingsAccountHelperValidationError = new 
SavingsAccountHelper(this.requestSpec, this.responseSpecForValidationError);
         this.savingsProductHelper = new SavingsProductHelper();
     }
 
     @Test
-    public void testSavingsTransactionsSearchWithAmountFilterLteGte() throws 
JsonProcessingException {
+    public void testSavingsTransactionsSearchAmountFrom() throws 
JsonProcessingException {
         final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, startDate);
         Assertions.assertNotNull(clientID);
-
         final Integer savingsId = createSavingsAccountDailyPosting(clientID, 
startDate);
 
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "100", 
startDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "300", 
startDate, CommonConstants.RESPONSE_RESOURCE_ID);
 
-        Filters filters = new Filters();
-        
filters.addTransactionAmountItem(buildTransactionAmountRange(RangeFilterBigDecimal.OperatorEnum.GTE,
 BigDecimal.valueOf(100)));
-        
filters.addTransactionAmountItem(buildTransactionAmountRange(RangeFilterBigDecimal.OperatorEnum.LTE,
 BigDecimal.valueOf(200)));
-        PagedRequestSavingsTransactionSearch searchRequest = 
buildTransactionsSearchReqeust(filters, null, null, null);
-        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchTransactions(savingsId,
-                searchRequest);
+        TransactionSearchRequest searchParameters = new 
TransactionSearchRequest().fromAmount(BigDecimal.valueOf(100));
+        Map<String, Object> queryParams = 
buildTransactionsSearchQuery(searchParameters, null, null);
+        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchSavingsTransactions(savingsId,
+                queryParams);
+
         Assertions.assertNotNull(transactionsResponse);
-        assertEquals(1, transactionsResponse.getTotalFilteredRecords());
-        Assertions.assertNotNull(transactionsResponse.getPageItems());
-        List<GetSavingsAccountTransactionsPageItem> pageItemsList = 
List.copyOf(transactionsResponse.getPageItems());
-        BigDecimal expectedAmount = BigDecimal.valueOf(100);
-        assertEquals(0, 
expectedAmount.compareTo(pageItemsList.get(0).getAmount()));
+        assertEquals(2, transactionsResponse.getTotal());
+        Assertions.assertNotNull(transactionsResponse.getContent());
+        List<GetSavingsAccountTransactionsPageItem> pageItemsList = 
List.copyOf(transactionsResponse.getContent());
+        assertEquals(2, pageItemsList.size());
+        assertTrue(MathUtil.isEqualTo(BigDecimal.valueOf(100), 
pageItemsList.get(1).getAmount()));
     }
 
     @Test
-    public void testSavingsTransactionsSearchWithAmountFilterLtGt() throws 
JsonProcessingException {
+    public void testSavingsTransactionsSearchAmountFromTo() throws 
JsonProcessingException {
         final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, startDate);
         Assertions.assertNotNull(clientID);
-
         final Integer savingsId = createSavingsAccountDailyPosting(clientID, 
startDate);
 
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "100", 
startDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "300", 
startDate, CommonConstants.RESPONSE_RESOURCE_ID);
 
-        Filters filters = new Filters();
-        
filters.addTransactionAmountItem(buildTransactionAmountRange(RangeFilterBigDecimal.OperatorEnum.GT,
 BigDecimal.valueOf(100)));
-        
filters.addTransactionAmountItem(buildTransactionAmountRange(RangeFilterBigDecimal.OperatorEnum.LT,
 BigDecimal.valueOf(400)));
-        PagedRequestSavingsTransactionSearch searchRequest = 
buildTransactionsSearchReqeust(filters, null, null, null);
-        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchTransactions(savingsId,
-                searchRequest);
+        TransactionSearchRequest searchParameters = new 
TransactionSearchRequest().fromAmount(BigDecimal.valueOf(100))
+                .toAmount(BigDecimal.valueOf(200));
+        Map<String, Object> queryParams = 
buildTransactionsSearchQuery(searchParameters, null, null);
+        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchSavingsTransactions(savingsId,
+                queryParams);
+
         Assertions.assertNotNull(transactionsResponse);
-        assertEquals(1, transactionsResponse.getTotalFilteredRecords());
-        Assertions.assertNotNull(transactionsResponse.getPageItems());
-        List<GetSavingsAccountTransactionsPageItem> pageItemsList = 
List.copyOf(transactionsResponse.getPageItems());
-        BigDecimal expectedAmount = BigDecimal.valueOf(300);
-        assertEquals(0, 
expectedAmount.compareTo(pageItemsList.get(0).getAmount()));
+        assertEquals(1, transactionsResponse.getTotal());
+        Assertions.assertNotNull(transactionsResponse.getContent());
+        List<GetSavingsAccountTransactionsPageItem> pageItemsList = 
List.copyOf(transactionsResponse.getContent());
+        assertEquals(1, pageItemsList.size());
+        assertTrue(MathUtil.isEqualTo(BigDecimal.valueOf(100), 
pageItemsList.get(0).getAmount()));
     }
 
     @Test
-    public void testSavingsTransactionsSearchWithDateFilterLteGte() throws 
JsonProcessingException {
+    public void testSavingsTransactionsSearchDateFromTo() throws 
JsonProcessingException {
         final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, startDate);
         Assertions.assertNotNull(clientID);
-
         final Integer savingsId = createSavingsAccountDailyPosting(clientID, 
startDate);
 
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "100", 
firstDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "300", 
secondDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, 
"100", withdrawDate, CommonConstants.RESPONSE_RESOURCE_ID);
 
-        Filters filters = new Filters();
-        
filters.addTransactionDateItem(buildTransactionDateRange(RangeFilterLocalDate.OperatorEnum.GTE,
 LocalDate.of(2023, 05, 06)));
-        
filters.addTransactionDateItem(buildTransactionDateRange(RangeFilterLocalDate.OperatorEnum.LTE,
 LocalDate.of(2023, 05, 10)));
-        PagedRequestSavingsTransactionSearch searchRequest = 
buildTransactionsSearchReqeust(filters, null, null, null);
-        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchTransactions(savingsId,
-                searchRequest);
+        TransactionSearchRequest searchParameters = new 
TransactionSearchRequest()
+                .fromDate(firstDepositDate, DEFAULT_DATE_FORMAT, 
DEFAULT_LOCALE).toDate(withdrawDate, DEFAULT_DATE_FORMAT, DEFAULT_LOCALE);
+        Map<String, Object> queryParams = 
buildTransactionsSearchQuery(searchParameters, DEFAULT_DATE_FORMAT, 
DEFAULT_LOCALE);
+        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchSavingsTransactions(savingsId,
+                queryParams);
+
         Assertions.assertNotNull(transactionsResponse);
-        assertEquals(2, transactionsResponse.getTotalFilteredRecords());
-        Assertions.assertNotNull(transactionsResponse.getPageItems());
-        assertEquals(2, transactionsResponse.getPageItems().size());
-        List<GetSavingsAccountTransactionsPageItem> pageItemsList = 
List.copyOf(transactionsResponse.getPageItems());
-        assertEquals(0, parseDate(withdrawDate, 
DEFAULT_DATE_FORMAT).compareTo(pageItemsList.get(0).getDate()));
-        assertEquals(0, parseDate(secondDepositDate, 
DEFAULT_DATE_FORMAT).compareTo(pageItemsList.get(1).getDate()));
+        assertEquals(3, transactionsResponse.getTotal());
+        Assertions.assertNotNull(transactionsResponse.getContent());
+        List<GetSavingsAccountTransactionsPageItem> pageItemsList = 
List.copyOf(transactionsResponse.getContent());
+        assertEquals(3, pageItemsList.size());
+        assertEquals(parseLocalDate(withdrawDate, DEFAULT_DATE_FORMAT), 
pageItemsList.get(0).getDate());
+        assertEquals(parseLocalDate(secondDepositDate, DEFAULT_DATE_FORMAT), 
pageItemsList.get(1).getDate());
     }
 
     @Test
-    public void 
testSavingsTransactionsSearchWithTransactionTypeDepositAndDefaultSort() {
+    public void testSavingsTransactionsSearchSubmittedDateFromTo() throws 
JsonProcessingException {
+        LocalDate businessDate = LocalDate.now(ZoneId.systemDefault());
         final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, startDate);
         Assertions.assertNotNull(clientID);
+        final Integer savingsId = createSavingsAccountDailyPosting(clientID, 
startDate);
+
+        try {
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, true);
+            BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, 
BusinessDateType.BUSINESS_DATE, businessDate);
+
+            this.savingsAccountHelper.depositToSavingsAccount(savingsId, 
"100", firstDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
+            this.savingsAccountHelper.depositToSavingsAccount(savingsId, 
"300", secondDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
+            this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, 
"100", withdrawDate, CommonConstants.RESPONSE_RESOURCE_ID);
+        } finally {
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, false);
+        }
+        String submittedDate = DateUtils.format(businessDate, 
DEFAULT_DATE_FORMAT, DEFAULT_LOCALE);
+        TransactionSearchRequest searchParameters = new 
TransactionSearchRequest()
+                .fromSubmittedDate(submittedDate, DEFAULT_DATE_FORMAT, 
DEFAULT_LOCALE)
+                .toSubmittedDate(submittedDate, DEFAULT_DATE_FORMAT, 
DEFAULT_LOCALE);
+        Map<String, Object> queryParams = 
buildTransactionsSearchQuery(searchParameters, DEFAULT_DATE_FORMAT, 
DEFAULT_LOCALE);
+        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchSavingsTransactions(savingsId,
+                queryParams);
 
+        Assertions.assertNotNull(transactionsResponse);
+        assertEquals(3, transactionsResponse.getTotal());
+        Assertions.assertNotNull(transactionsResponse.getContent());
+        List<GetSavingsAccountTransactionsPageItem> pageItemsList = 
List.copyOf(transactionsResponse.getContent());
+        assertEquals(3, pageItemsList.size());
+        assertEquals(businessDate, pageItemsList.get(0).getSubmittedOnDate());
+        assertEquals(businessDate, pageItemsList.get(1).getSubmittedOnDate());
+        assertEquals(businessDate, pageItemsList.get(2).getSubmittedOnDate());
+    }
+
+    @Test
+    public void 
testSavingsTransactionsSearchTransactionTypeDepositAndDefaultSort() {
+        final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, startDate);
+        Assertions.assertNotNull(clientID);
         final Integer savingsId = createSavingsAccountDailyPosting(clientID, 
startDate);
 
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "100", 
firstDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "300", 
secondDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, 
"100", withdrawDate, CommonConstants.RESPONSE_RESOURCE_ID);
 
-        Filters filters = new Filters();
-        
filters.setTransactionType(List.of(Filters.TransactionTypeEnum.DEPOSIT));
-        PagedRequestSavingsTransactionSearch searchRequest = 
buildTransactionsSearchReqeust(filters, null, null, null);
-        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchTransactions(savingsId,
-                searchRequest);
+        int typeD = SavingsAccountTransactionType.DEPOSIT.getId();
+        TransactionSearchRequest searchParameters = new 
TransactionSearchRequest().types(String.valueOf(typeD));
+        Map<String, Object> queryParams = 
buildTransactionsSearchQuery(searchParameters, DEFAULT_DATE_FORMAT, 
DEFAULT_LOCALE);
+        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchSavingsTransactions(savingsId,
+                queryParams);
+
         Assertions.assertNotNull(transactionsResponse);
-        assertEquals(2, transactionsResponse.getTotalFilteredRecords());
-        Assertions.assertNotNull(transactionsResponse.getPageItems());
-        assertEquals(2, transactionsResponse.getPageItems().size());
-        List<GetSavingsAccountTransactionsPageItem> pageItemsList = 
List.copyOf(transactionsResponse.getPageItems());
-        
assertTrue(Filters.TransactionTypeEnum.DEPOSIT.getValue().equalsIgnoreCase(pageItemsList.get(0).getTransactionType().getValue()));
-        assertEquals(0, 
BigDecimal.valueOf(300).compareTo(pageItemsList.get(0).getAmount()));
-        assertEquals(0, parseDate(secondDepositDate, 
DEFAULT_DATE_FORMAT).compareTo(pageItemsList.get(0).getDate()));
-        
assertTrue(Filters.TransactionTypeEnum.DEPOSIT.getValue().equalsIgnoreCase(pageItemsList.get(1).getTransactionType().getValue()));
-        assertEquals(0, 
BigDecimal.valueOf(100).compareTo(pageItemsList.get(1).getAmount()));
-        assertEquals(0, parseDate(firstDepositDate, 
DEFAULT_DATE_FORMAT).compareTo(pageItemsList.get(1).getDate()));
+        assertEquals(2, transactionsResponse.getTotal());
+        Assertions.assertNotNull(transactionsResponse.getContent());
+        List<GetSavingsAccountTransactionsPageItem> pageItemsList = 
List.copyOf(transactionsResponse.getContent());
+        assertEquals(2, pageItemsList.size());
+        GetSavingsAccountTransactionsPageItem first = pageItemsList.get(0);
+        assertEquals(Long.valueOf(typeD), first.getTransactionType().getId());
+        assertTrue(MathUtil.isEqualTo(BigDecimal.valueOf(300), 
first.getAmount()));
+        assertEquals(parseLocalDate(secondDepositDate, DEFAULT_DATE_FORMAT), 
first.getDate());
+        GetSavingsAccountTransactionsPageItem second = pageItemsList.get(1);
+        assertEquals(Long.valueOf(typeD), second.getTransactionType().getId());
+        assertTrue(MathUtil.isEqualTo(BigDecimal.valueOf(100), 
second.getAmount()));
+        assertEquals(parseLocalDate(firstDepositDate, DEFAULT_DATE_FORMAT), 
second.getDate());
     }
 
     @Test
-    public void 
testSavingsTransactionsSearchWithTransactionTypeWithdrawAndDeposit() throws 
JsonProcessingException {
+    public void 
testSavingsTransactionsSearchTransactionTypesWithdrawAndDeposit() throws 
JsonProcessingException {
         final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, startDate);
         Assertions.assertNotNull(clientID);
-
         final Integer savingsId = createSavingsAccountDailyPosting(clientID, 
startDate);
 
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "100", 
firstDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "300", 
secondDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, 
"100", withdrawDate, CommonConstants.RESPONSE_RESOURCE_ID);
 
-        Filters filters = new Filters();
-        
filters.setTransactionType(List.of(Filters.TransactionTypeEnum.DEPOSIT, 
Filters.TransactionTypeEnum.WITHDRAWAL));
-        PagedRequestSavingsTransactionSearch searchRequest = 
buildTransactionsSearchReqeust(filters, null, null, null);
-        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchTransactions(savingsId,
-                searchRequest);
+        int typeD = SavingsAccountTransactionType.DEPOSIT.getId();
+        int typeW = SavingsAccountTransactionType.WITHDRAWAL.getId();
+        TransactionSearchRequest searchParameters = new 
TransactionSearchRequest().types(String.valueOf(typeD) + ',' + typeW);
+        Map<String, Object> queryParams = 
buildTransactionsSearchQuery(searchParameters, DEFAULT_DATE_FORMAT, 
DEFAULT_LOCALE);
+        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchSavingsTransactions(savingsId,
+                queryParams);
+
         Assertions.assertNotNull(transactionsResponse);
-        assertEquals(3, transactionsResponse.getTotalFilteredRecords());
-        Assertions.assertNotNull(transactionsResponse.getPageItems());
-        assertEquals(3, transactionsResponse.getPageItems().size());
-        List<GetSavingsAccountTransactionsPageItem> pageItemsList = 
List.copyOf(transactionsResponse.getPageItems());
-        assertTrue(
-                
Filters.TransactionTypeEnum.WITHDRAWAL.getValue().equalsIgnoreCase(pageItemsList.get(0).getTransactionType().getValue()));
-        assertEquals(0, 
BigDecimal.valueOf(100).compareTo(pageItemsList.get(0).getAmount()));
-        
assertTrue(Filters.TransactionTypeEnum.DEPOSIT.getValue().equalsIgnoreCase(pageItemsList.get(1).getTransactionType().getValue()));
-        assertEquals(0, 
BigDecimal.valueOf(300).compareTo(pageItemsList.get(1).getAmount()));
-        
assertTrue(Filters.TransactionTypeEnum.DEPOSIT.getValue().equalsIgnoreCase(pageItemsList.get(2).getTransactionType().getValue()));
-        assertEquals(0, 
BigDecimal.valueOf(100).compareTo(pageItemsList.get(2).getAmount()));
+        assertEquals(3, transactionsResponse.getTotal());
+        Assertions.assertNotNull(transactionsResponse.getContent());
+        List<GetSavingsAccountTransactionsPageItem> pageItemsList = 
List.copyOf(transactionsResponse.getContent());
+        assertEquals(3, pageItemsList.size());
+        assertEquals(Long.valueOf(typeW), 
pageItemsList.get(0).getTransactionType().getId());
+        assertTrue(MathUtil.isEqualTo(BigDecimal.valueOf(100), 
pageItemsList.get(0).getAmount()));
+        assertEquals(Long.valueOf(typeD), 
pageItemsList.get(1).getTransactionType().getId());
+        assertTrue(MathUtil.isEqualTo(BigDecimal.valueOf(300), 
pageItemsList.get(1).getAmount()));
+        assertEquals(Long.valueOf(typeD), 
pageItemsList.get(2).getTransactionType().getId());
+        assertTrue(MathUtil.isEqualTo(BigDecimal.valueOf(100), 
pageItemsList.get(2).getAmount()));
     }
 
     @Test
-    public void testSavingsTransactionsSearchWithPaginationAndNoFilter() {
+    public void testSavingsTransactionsSearchPaginationAndNoFilter() {
         final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, startDate);
         Assertions.assertNotNull(clientID);
         final Integer savingsId = createSavingsAccountDailyPosting(clientID, 
startDate);
+
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "100", 
firstDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "300", 
secondDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, 
"100", withdrawDate, CommonConstants.RESPONSE_RESOURCE_ID);
-        Filters filters = new Filters();
-        int page = 0;
-        int size = 2;
-        PagedRequestSavingsTransactionSearch searchRequest = 
buildTransactionsSearchReqeust(filters, page, size, null);
-        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchTransactions(savingsId,
-                searchRequest);
+
+        TransactionSearchRequest searchParameters = new 
TransactionSearchRequest().pageable(0, 2, null, null);
+        Map<String, Object> queryParams = 
buildTransactionsSearchQuery(searchParameters, null, null);
+        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchSavingsTransactions(savingsId,
+                queryParams);
+
         Assertions.assertNotNull(transactionsResponse);
-        assertEquals(3, transactionsResponse.getTotalFilteredRecords());
-        Assertions.assertNotNull(transactionsResponse.getPageItems());
-        assertEquals(2, transactionsResponse.getPageItems().size());
+        assertEquals(3, transactionsResponse.getTotal());
+        Assertions.assertNotNull(transactionsResponse.getContent());
+        assertEquals(2, transactionsResponse.getContent().size());
     }
 
     @Test
-    public void 
testSavingsTransactionsSearchWithTransactionTypeDepositAndSortByAmountAsc() {
+    public void 
testSavingsTransactionsSearchTransactionTypeDepositAndSortByAmountAsc() {
         final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, startDate);
         Assertions.assertNotNull(clientID);
         final Integer savingsId = createSavingsAccountDailyPosting(clientID, 
startDate);
+
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "100", 
firstDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "300", 
secondDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, 
"200", withdrawDate, CommonConstants.RESPONSE_RESOURCE_ID);
-        Filters filters = new Filters();
-        
filters.setTransactionType(List.of(Filters.TransactionTypeEnum.DEPOSIT));
-        SortOrder sortOrder = new SortOrder();
-        sortOrder.setProperty("amount");
-        sortOrder.setDirection(SortOrder.DirectionEnum.ASC);
-        List<SortOrder> sortOrders = List.of(sortOrder);
-        PagedRequestSavingsTransactionSearch searchRequest = 
buildTransactionsSearchReqeust(filters, null, null, sortOrders);
-        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchTransactions(savingsId,
-                searchRequest);
+
+        int typeD = SavingsAccountTransactionType.DEPOSIT.getId();
+        TransactionSearchRequest searchParameters = new 
TransactionSearchRequest().types(String.valueOf(typeD)).pageable(null, null,
+                "amount", Sort.Direction.ASC);
+        Map<String, Object> queryParams = 
buildTransactionsSearchQuery(searchParameters, DEFAULT_DATE_FORMAT, 
DEFAULT_LOCALE);
+        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchSavingsTransactions(savingsId,
+                queryParams);
+
         Assertions.assertNotNull(transactionsResponse);
-        assertEquals(2, transactionsResponse.getTotalFilteredRecords());
-        Assertions.assertNotNull(transactionsResponse.getPageItems());
-        assertEquals(2, transactionsResponse.getPageItems().size());
-        List<GetSavingsAccountTransactionsPageItem> pageItemsList = 
List.copyOf(transactionsResponse.getPageItems());
-        
assertTrue(Filters.TransactionTypeEnum.DEPOSIT.getValue().equalsIgnoreCase(pageItemsList.get(0).getTransactionType().getValue()));
-        assertEquals(0, 
BigDecimal.valueOf(100).compareTo(pageItemsList.get(0).getAmount()));
-        
assertTrue(Filters.TransactionTypeEnum.DEPOSIT.getValue().equalsIgnoreCase(pageItemsList.get(1).getTransactionType().getValue()));
-        assertEquals(0, 
BigDecimal.valueOf(300).compareTo(pageItemsList.get(1).getAmount()));
+        assertEquals(2, transactionsResponse.getTotal());
+        Assertions.assertNotNull(transactionsResponse.getContent());
+        List<GetSavingsAccountTransactionsPageItem> pageItemsList = 
List.copyOf(transactionsResponse.getContent());
+        assertEquals(2, pageItemsList.size());
+        GetSavingsAccountTransactionsPageItem first = pageItemsList.get(0);
+        assertEquals(Long.valueOf(typeD), first.getTransactionType().getId());
+        assertTrue(MathUtil.isEqualTo(BigDecimal.valueOf(100), 
first.getAmount()));
+        assertEquals(parseLocalDate(firstDepositDate, DEFAULT_DATE_FORMAT), 
first.getDate());
+        GetSavingsAccountTransactionsPageItem second = pageItemsList.get(1);
+        assertEquals(Long.valueOf(typeD), second.getTransactionType().getId());
+        assertTrue(MathUtil.isEqualTo(BigDecimal.valueOf(300), 
second.getAmount()));
+        assertEquals(parseLocalDate(secondDepositDate, DEFAULT_DATE_FORMAT), 
second.getDate());
     }
 
     @Test
@@ -270,69 +314,56 @@ public class 
SavingsAccountTransactionsSearchIntegrationTest {
         final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, startDate);
         Assertions.assertNotNull(clientID);
         final Integer savingsId = createSavingsAccountDailyPosting(clientID, 
startDate);
+
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "100", 
firstDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "300", 
secondDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, 
"50", withdrawDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "400", 
thirdDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "200", 
fourthDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
-
         this.savingsAccountHelper.postInterestForSavings(savingsId);
-        Filters filters = new Filters();
-        
filters.addTransactionAmountItem(buildTransactionAmountRange(RangeFilterBigDecimal.OperatorEnum.GTE,
 BigDecimal.valueOf(100)));
-        
filters.addTransactionAmountItem(buildTransactionAmountRange(RangeFilterBigDecimal.OperatorEnum.LT,
 BigDecimal.valueOf(500)));
-        
filters.addTransactionDateItem(buildTransactionDateRange(RangeFilterLocalDate.OperatorEnum.GT,
 LocalDate.of(2023, 05, 06)));
-        
filters.addTransactionDateItem(buildTransactionDateRange(RangeFilterLocalDate.OperatorEnum.LTE,
 LocalDate.of(2023, 06, 01)));
-        
filters.setTransactionType(List.of(Filters.TransactionTypeEnum.DEPOSIT));
-        SortOrder sortOrder = new SortOrder();
-        sortOrder.setProperty("amount");
-        sortOrder.setDirection(SortOrder.DirectionEnum.DESC);
-        List<SortOrder> sortOrders = List.of(sortOrder);
-        int page = 0;
-        int size = 2;
-        PagedRequestSavingsTransactionSearch searchRequest = 
buildTransactionsSearchReqeust(filters, page, size, sortOrders);
-        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchTransactions(savingsId,
-                searchRequest);
-        Assertions.assertNotNull(transactionsResponse);
-        assertEquals(3, transactionsResponse.getTotalFilteredRecords());
-        Assertions.assertNotNull(transactionsResponse.getPageItems());
-        assertEquals(2, transactionsResponse.getPageItems().size());
-        List<GetSavingsAccountTransactionsPageItem> pageItemsList = 
List.copyOf(transactionsResponse.getPageItems());
-        
assertTrue(Filters.TransactionTypeEnum.DEPOSIT.getValue().equalsIgnoreCase(pageItemsList.get(0).getTransactionType().getValue()));
-        assertEquals(0, 
BigDecimal.valueOf(400).compareTo(pageItemsList.get(0).getAmount()));
-        assertEquals(0, parseDate(thirdDepositDate, 
DEFAULT_DATE_FORMAT).compareTo(pageItemsList.get(0).getDate()));
-        
assertTrue(Filters.TransactionTypeEnum.DEPOSIT.getValue().equalsIgnoreCase(pageItemsList.get(1).getTransactionType().getValue()));
-        assertEquals(0, 
BigDecimal.valueOf(300).compareTo(pageItemsList.get(1).getAmount()));
-        assertEquals(0, parseDate(secondDepositDate, 
DEFAULT_DATE_FORMAT).compareTo(pageItemsList.get(1).getDate()));
 
+        int typeD = SavingsAccountTransactionType.DEPOSIT.getId();
+        TransactionSearchRequest searchParameters = new 
TransactionSearchRequest().fromAmount(BigDecimal.valueOf(100))
+                .toAmount(BigDecimal.valueOf(500)).fromDate("2023-05-06", 
DateUtils.DEFAULT_DATE_FORMAT, DEFAULT_LOCALE)
+                .toDate("2023-06-01", DateUtils.DEFAULT_DATE_FORMAT, 
DEFAULT_LOCALE).types(String.valueOf(typeD))
+                .pageable(0, 2, "amount", Sort.Direction.DESC);
+        Map<String, Object> queryParams = 
buildTransactionsSearchQuery(searchParameters, DateUtils.DEFAULT_DATE_FORMAT, 
DEFAULT_LOCALE);
+        SavingsAccountTransactionsSearchResponse transactionsResponse = 
this.savingsAccountHelper.searchSavingsTransactions(savingsId,
+                queryParams);
+
+        Assertions.assertNotNull(transactionsResponse);
+        assertEquals(3, transactionsResponse.getTotal());
+        Assertions.assertNotNull(transactionsResponse.getContent());
+        List<GetSavingsAccountTransactionsPageItem> pageItemsList = 
List.copyOf(transactionsResponse.getContent());
+        assertEquals(2, pageItemsList.size());
+        GetSavingsAccountTransactionsPageItem first = pageItemsList.get(0);
+        assertEquals(Long.valueOf(typeD), first.getTransactionType().getId());
+        assertTrue(MathUtil.isEqualTo(BigDecimal.valueOf(400), 
first.getAmount()));
+        assertEquals(parseLocalDate(thirdDepositDate, DEFAULT_DATE_FORMAT), 
first.getDate());
+        GetSavingsAccountTransactionsPageItem second = pageItemsList.get(1);
+        assertEquals(Long.valueOf(typeD), second.getTransactionType().getId());
+        assertTrue(MathUtil.isEqualTo(BigDecimal.valueOf(300), 
second.getAmount()));
+        assertEquals(parseLocalDate(secondDepositDate, DEFAULT_DATE_FORMAT), 
second.getDate());
     }
 
     @Test
-    public void testSavingsTransactionsSearchFilterRangeValidationError() {
+    public void testSavingsTransactionsSearchDateValidationError() {
         final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, startDate);
         Assertions.assertNotNull(clientID);
         final Integer savingsId = createSavingsAccountDailyPosting(clientID, 
startDate);
+
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "100", 
firstDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "300", 
secondDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, 
"50", withdrawDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "400", 
thirdDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "200", 
fourthDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
 
-        Filters filters = new Filters();
-        
filters.addTransactionAmountItem(buildTransactionAmountRange(RangeFilterBigDecimal.OperatorEnum.GTE,
 BigDecimal.valueOf(100)));
-        
filters.addTransactionAmountItem(buildTransactionAmountRange(RangeFilterBigDecimal.OperatorEnum.LT,
 BigDecimal.valueOf(500)));
-        
filters.addTransactionAmountItem(buildTransactionAmountRange(RangeFilterBigDecimal.OperatorEnum.LT,
 BigDecimal.valueOf(1000)));
-        
filters.addTransactionDateItem(buildTransactionDateRange(RangeFilterLocalDate.OperatorEnum.GT,
 LocalDate.of(2023, 05, 6)));
-        
filters.addTransactionDateItem(buildTransactionDateRange(RangeFilterLocalDate.OperatorEnum.LTE,
 LocalDate.of(2023, 06, 1)));
-        
filters.addTransactionDateItem(buildTransactionDateRange(RangeFilterLocalDate.OperatorEnum.LTE,
 LocalDate.of(2023, 06, 8)));
-        
filters.setTransactionType(List.of(Filters.TransactionTypeEnum.DEPOSIT));
-        SortOrder sortOrder = new SortOrder();
-        sortOrder.setProperty("amount");
-        sortOrder.setDirection(SortOrder.DirectionEnum.DESC);
-        List<SortOrder> sortOrders = List.of(sortOrder);
-        int page = 0;
-        int size = 2;
-        PagedRequestSavingsTransactionSearch searchRequest = 
buildTransactionsSearchReqeust(filters, page, size, sortOrders);
-        this.savingsAccountHelperValidationError.searchTransactions(savingsId, 
searchRequest);
+        int typeD = SavingsAccountTransactionType.DEPOSIT.getId();
+        TransactionSearchRequest searchParameters = new 
TransactionSearchRequest().fromAmount(BigDecimal.valueOf(100))
+                .toAmount(BigDecimal.valueOf(500));
+        Map<String, Object> queryParams = 
buildTransactionsSearchQuery(searchParameters, null, null);
+        queryParams.put("fromDate", "05 May 2023"); // wrong date format
+        
this.savingsAccountHelperValidationError.searchSavingsTransactions(savingsId, 
queryParams);
     }
 
     @Test
@@ -346,11 +377,11 @@ public class 
SavingsAccountTransactionsSearchIntegrationTest {
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "400", 
thirdDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
         this.savingsAccountHelper.depositToSavingsAccount(savingsId, "200", 
fourthDepositDate, CommonConstants.RESPONSE_RESOURCE_ID);
 
-        Filters filters = new Filters();
-        
filters.addTransactionAmountItem(buildTransactionAmountRange(RangeFilterBigDecimal.OperatorEnum.GTE,
 BigDecimal.valueOf(-100)));
-        
filters.setTransactionType(List.of(Filters.TransactionTypeEnum.DEPOSIT));
-        PagedRequestSavingsTransactionSearch searchRequest = 
buildTransactionsSearchReqeust(filters, null, null, null);
-        this.savingsAccountHelperValidationError.searchTransactions(savingsId, 
searchRequest);
+        TransactionSearchRequest searchParameters = new 
TransactionSearchRequest();
+        Map<String, Object> queryParams = 
buildTransactionsSearchQuery(searchParameters, null, null);
+        queryParams.put("fromAmount", "test"); // not number
+        responseSpecForValidationError.statusCode(404);
+        
this.savingsAccountHelperValidationError.searchSavingsTransactions(savingsId, 
queryParams);
     }
 
     private Integer createSavingsAccountDailyPosting(final Integer clientID, 
final String startDate) {
@@ -372,36 +403,53 @@ public class 
SavingsAccountTransactionsSearchIntegrationTest {
         return SavingsProductHelper.createSavingsProduct(savingsProductJSON, 
requestSpec, responseSpec);
     }
 
-    private PagedRequestSavingsTransactionSearch 
buildTransactionsSearchReqeust(Filters filters, Integer page, Integer size,
-            List<SortOrder> sorts) {
-        final Integer DEFAULT_PAGE_SIZE = 50;
-        SavingsTransactionSearch savingsTransactionSearch = new 
SavingsTransactionSearch();
-        savingsTransactionSearch.setFilters(filters);
-        PagedRequestSavingsTransactionSearch pagedRequest = new 
PagedRequestSavingsTransactionSearch();
-        pagedRequest.setRequest(savingsTransactionSearch);
-        pagedRequest.setSorts(sorts != null ? sorts : new ArrayList<>());
-        pagedRequest.setPage(page != null ? page : 0);
-        pagedRequest.setSize(size != null ? size : DEFAULT_PAGE_SIZE);
-        return pagedRequest;
-    }
-
-    private RangeFilterBigDecimal 
buildTransactionAmountRange(RangeFilterBigDecimal.OperatorEnum operator, 
BigDecimal value) {
-        RangeFilterBigDecimal transactionAmountFilter = new 
RangeFilterBigDecimal();
-        transactionAmountFilter.setOperator(operator);
-        transactionAmountFilter.setValue(value);
-        return transactionAmountFilter;
-    }
-
-    private RangeFilterLocalDate 
buildTransactionDateRange(RangeFilterLocalDate.OperatorEnum operator, LocalDate 
value) {
-        RangeFilterLocalDate transactionDateFilter = new 
RangeFilterLocalDate();
-        transactionDateFilter.setOperator(operator);
-        transactionDateFilter.setValue(value);
-        return transactionDateFilter;
-    }
-
-    public static LocalDate parseDate(String dateStr, String pattern) {
-        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
-        return LocalDate.parse(dateStr, formatter);
+    private Map<String, Object> 
buildTransactionsSearchQuery(TransactionSearchRequest searchParams, String 
dateFormat, Locale locale) {
+        HashMap<String, Object> params = new HashMap<>();
+        if (searchParams.getFromDate() != null) {
+            params.put("fromDate", 
DateUtils.format(searchParams.getFromDate(), dateFormat, locale));
+        }
+        if (searchParams.getToDate() != null) {
+            params.put("toDate", DateUtils.format(searchParams.getToDate(), 
dateFormat, locale));
+        }
+        if (searchParams.getFromSubmittedDate() != null) {
+            params.put("fromSubmittedDate", 
DateUtils.format(searchParams.getFromSubmittedDate(), dateFormat, locale));
+        }
+        if (searchParams.getToSubmittedDate() != null) {
+            params.put("toSubmittedDate", 
DateUtils.format(searchParams.getToSubmittedDate(), dateFormat, locale));
+        }
+        if (searchParams.getFromAmount() != null) {
+            params.put("fromAmount", searchParams.getFromAmount());
+        }
+        if (searchParams.getToAmount() != null) {
+            params.put("toAmount", searchParams.getToAmount());
+        }
+        if (searchParams.getTypes() != null) {
+            params.put("types", String.join(",", searchParams.getTypes()));
+        }
+        if (searchParams.getCredit() != null) {
+            params.put("credit", searchParams.getCredit());
+        }
+        if (searchParams.getDebit() != null) {
+            params.put("debit", searchParams.getDebit());
+        }
+        PageRequest pageable = searchParams.getPageable();
+        if (pageable != null) {
+            params.put("offset", pageable.getPageNumber());
+            params.put("limit", pageable.getPageSize());
+            Sort sort = pageable.getSort();
+            if (sort.isSorted()) {
+                List<Sort.Order> orders = sort.toList();
+                params.put("sortOrder", orders.get(0).getDirection());
+                params.put("orderBy", 
orders.stream().map(Sort.Order::getProperty).collect(Collectors.joining(",")));
+            }
+        }
+        if (dateFormat != null) {
+            params.put("dateFormat", dateFormat);
+        }
+        if (locale != null) {
+            params.put("locale", locale.toString());
+        }
+        return params;
     }
 
     // Reset configuration fields
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java
index 7f6cc2d0f..48d0ccb6d 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java
@@ -18,6 +18,9 @@
  */
 package org.apache.fineract.integrationtests.common.savings;
 
+import static org.apache.fineract.integrationtests.common.Utils.DEFAULT_TENANT;
+import static 
org.apache.fineract.integrationtests.common.Utils.TENANT_PARAM_NAME;
+
 import com.google.common.reflect.TypeToken;
 import com.google.gson.Gson;
 import io.restassured.specification.RequestSpecification;
@@ -36,9 +39,9 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import org.apache.fineract.client.models.PagedRequestSavingsTransactionSearch;
 import 
org.apache.fineract.client.models.SavingsAccountTransactionsSearchResponse;
 import org.apache.fineract.client.util.JSON;
+import org.apache.fineract.integrationtests.client.IntegrationTest;
 import org.apache.fineract.integrationtests.common.CommonConstants;
 import org.apache.fineract.integrationtests.common.Utils;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
@@ -48,7 +51,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings({ "rawtypes" })
-public class SavingsAccountHelper {
+public class SavingsAccountHelper extends IntegrationTest {
 
     private final RequestSpecification requestSpec;
     private final ResponseSpecification responseSpec;
@@ -650,12 +653,11 @@ public class SavingsAccountHelper {
         return Utils.performServerGet(requestSpec, responseSpec, URL, "");
     }
 
-    public SavingsAccountTransactionsSearchResponse searchTransactions(Integer 
savingsId,
-            PagedRequestSavingsTransactionSearch searchReqeust) {
-        final String SAVINGS_TRANSACTIONS_SEARCH_URL = SAVINGS_ACCOUNT_URL + 
"/" + savingsId + "/transactions/search" + "?"
-                + Utils.TENANT_IDENTIFIER;
-        String jsonBodyToSend = GSON.toJson(searchReqeust);
-        String response = Utils.performServerPost(this.requestSpec, 
this.responseSpec, SAVINGS_TRANSACTIONS_SEARCH_URL, jsonBodyToSend);
+    public SavingsAccountTransactionsSearchResponse 
searchSavingsTransactions(Integer savingsId, Map<String, Object> queryParams) {
+        final String url = SAVINGS_ACCOUNT_URL + "/" + savingsId + 
"/transactions/search";
+        queryParams.put(TENANT_PARAM_NAME, DEFAULT_TENANT);
+        requestSpec.queryParams(queryParams);
+        String response = Utils.performServerGet(this.requestSpec, 
this.responseSpec, url);
         return GSON.fromJson(response, 
SavingsAccountTransactionsSearchResponse.class);
     }
 


Reply via email to