FINERACT-984-6: PostgreSQL support

This commit is contained in:
Arnold Galovics
2022-02-22 18:03:09 +01:00
committed by Aleksandar Vidakovic
parent 34729186d7
commit 8389106a58
92 changed files with 3505 additions and 655 deletions
+107
View File
@@ -0,0 +1,107 @@
# 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.
#
# NB: Travis CI (dist: bionic) supports up to v3.7
# (unless we'd install a more recent version in .travis.yml)
version: '3.7'
services:
# Backend service
fineractpostgresql:
image: postgres:13.4
volumes:
- ./fineract-db/docker/postgresql:/docker-entrypoint-initdb.d/:Z,ro
restart: always
environment:
POSTGRES_USER: root
POSTGRES_PASSWORD: skdcnwauicn2ucnaecasdsajdnizucawencascdca
FINERACT_DB_USER: postgres
FINERACT_DB_PASS: skdcnwauicn2ucnaecasdsajdnizucawencascdca
FINERACT_TENANTS_DB_NAME: fineract_tenants
FINERACT_TENANT_DEFAULT_DB_NAME: fineract_default
healthcheck:
test: [ "CMD", "pg_isready", "-q", "-d", "postgres", "-U", "root" ]
timeout: 10s
retries: 10
ports:
- "5432:5432"
fineract-server:
image: fineract:latest
volumes:
- ./fineract-provider/build/data:/data
healthcheck:
test: ["CMD", 'sh', '-c', 'echo -e "Checking for the availability of Fineract server deployment"; while ! nc -z "fineract-server" 8443; do sleep 1; printf "-"; done; echo -e " >> Fineract server has started";' ]
timeout: 10s
retries: 10
ports:
- 8443:8443
depends_on:
fineractpostgresql:
condition: service_healthy
environment:
# TODO: env vars prefixed with "fineract_tenants_*" will be removed with one of the next releases
#- fineract_tenants_driver=org.postgresql.Driver
#- fineract_tenants_url=jdbc:postgresql://fineractpostgresql:5432/fineract_tenants
#- fineract_tenants_uid=postgres
#- fineract_tenants_pwd=skdcnwauicn2ucnaecasdsajdnizucawencascdca
# NOTE: node aware scheduler
- FINERACT_NODE_ID=1
# NOTE: env vars prefixed "FINERACT_HIKARI_*" are used to configure the database connection pool
- FINERACT_HIKARI_DRIVER_SOURCE_CLASS_NAME=org.postgresql.Driver
- FINERACT_HIKARI_JDBC_URL=jdbc:postgresql://fineractpostgresql:5432/fineract_tenants
- FINERACT_HIKARI_USERNAME=postgres
- FINERACT_HIKARI_PASSWORD=skdcnwauicn2ucnaecasdsajdnizucawencascdca
# ... following variables are optional; "application.properties" contains reasonable defaults (same as here)
- FINERACT_HIKARI_MINIMUM_IDLE=3
- FINERACT_HIKARI_MAXIMUM_POOL_SIZE=10
- FINERACT_HIKARI_IDLE_TIMEOUT=60000
- FINERACT_HIKARI_CONNECTION_TIMEOUT=20000
- FINERACT_HIKARI_TEST_QUERY=SELECT 1
- FINERACT_HIKARI_AUTO_COMMIT=true
- FINERACT_HIKARI_DS_PROPERTIES_CACHE_PREP_STMTS=true
- FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SIZE=250
- FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SQL_LIMIT=2048
- FINERACT_HIKARI_DS_PROPERTIES_USE_SERVER_PREP_STMTS=true
- FINERACT_HIKARI_DS_PROPERTIES_USE_LOCAL_SESSION_STATE=true
- FINERACT_HIKARI_DS_PROPERTIES_REWRITE_BATCHED_STATEMENTS=true
- FINERACT_HIKARI_DS_PROPERTIES_CACHE_RESULT_SET_METADATA=true
- FINERACT_HIKARI_DS_PROPERTIES_CACHE_SERVER_CONFIGURATION=true
- FINERACT_HIKARI_DS_PROPERTIES_ELIDE_SET_AUTO_COMMITS=true
- FINERACT_HIKARI_DS_PROPERTIES_MAINTAIN_TIME_STATS=false
- FINERACT_HIKARI_DS_PROPERTIES_LOG_SLOW_QUERIES=true
- FINERACT_HIKARI_DS_PROPERTIES_DUMP_QUERIES_IN_EXCEPTION=true
# NOTE: env vars prefixed "FINERACT_DEFAULT_TENANTDB_*" are used to create the default tenant database
- FINERACT_DEFAULT_TENANTDB_HOSTNAME=fineractpostgresql
- FINERACT_DEFAULT_TENANTDB_PORT=5432
- FINERACT_DEFAULT_TENANTDB_UID=postgres
- FINERACT_DEFAULT_TENANTDB_PWD=skdcnwauicn2ucnaecasdsajdnizucawencascdca
- FINERACT_DEFAULT_TENANTDB_CONN_PARAMS=
- FINERACT_DEFAULT_TENANTDB_TIMEZONE=Asia/Kolkata
- FINERACT_DEFAULT_TENANTDB_IDENTIFIER=default
- FINERACT_DEFAULT_TENANTDB_NAME=fineract_default
- FINERACT_DEFAULT_TENANTDB_DESCRIPTION=Default Demo Tenant
# Frontend service
community-app:
image: openmf/community-app:latest
container_name: mifos-ui
restart: always
ports:
- 9090:80
depends_on:
fineract-server:
condition: service_healthy
+1 -1
View File
@@ -57,7 +57,7 @@ services:
# NOTE: node aware scheduler
- FINERACT_NODE_ID=1
# NOTE: env vars prefixed "FINERACT_HIKARI_*" are used to configure the database connection pool
- FINERACT_HIKARI_DRIVER_CLASS_NAME=org.mariadb.jdbc.Driver
- FINERACT_HIKARI_DRIVER_SOURCE_CLASS_NAME=org.mariadb.jdbc.Driver
- FINERACT_HIKARI_JDBC_URL=jdbc:mariadb://fineractmysql:3306/fineract_tenants
- FINERACT_HIKARI_USERNAME=root
- FINERACT_HIKARI_PASSWORD=skdcnwauicn2ucnaecasdsajdnizucawencascdca
+29
View File
@@ -0,0 +1,29 @@
#!/bin/bash
#
# 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.
#
set -e
export PGPASSWORD=$POSTGRES_PASSWORD;
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
CREATE USER $FINERACT_DB_USER WITH PASSWORD '$FINERACT_DB_PASS';
CREATE DATABASE $FINERACT_TENANTS_DB_NAME;
CREATE DATABASE $FINERACT_TENANT_DEFAULT_DB_NAME;
GRANT ALL PRIVILEGES ON DATABASE $FINERACT_TENANTS_DB_NAME TO $FINERACT_DB_USER;
GRANT ALL PRIVILEGES ON DATABASE $FINERACT_TENANT_DEFAULT_DB_NAME TO $FINERACT_DB_USER;
EOSQL
+3
View File
@@ -200,6 +200,7 @@ configurations {
}
dependencies {
driver 'org.mariadb.jdbc:mariadb-java-client:2.7.4'
driver 'org.postgresql:postgresql:42.1.4'
}
URLClassLoader loader = GroovyObject.class.classLoader
@@ -237,6 +238,7 @@ bootRun {
dependencies {
implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.4'
implementation 'org.postgresql:postgresql:42.1.4'
}
classpath += files("build/generated/swagger-ui")
@@ -316,6 +318,7 @@ jib {
dependencies {
implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.4'
implementation 'org.postgresql:postgresql:42.1.4'
}
extraDirectories {
@@ -49,6 +49,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.organisation.office.data.OfficeData;
@@ -77,18 +78,22 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
private final ColumnValidator columnValidator;
private final FinancialActivityAccountRepositoryWrapper financialActivityAccountRepositoryWrapper;
private final PaginationHelper<JournalEntryData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
private final DatabaseSpecificSQLGenerator sqlGenerator;
@Autowired
public JournalEntryReadPlatformServiceImpl(final RoutingDataSource dataSource,
final GLAccountReadPlatformService glAccountReadPlatformService, final ColumnValidator columnValidator,
final OfficeReadPlatformService officeReadPlatformService,
final FinancialActivityAccountRepositoryWrapper financialActivityAccountRepositoryWrapper) {
final FinancialActivityAccountRepositoryWrapper financialActivityAccountRepositoryWrapper,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.glAccountReadPlatformService = glAccountReadPlatformService;
this.officeReadPlatformService = officeReadPlatformService;
this.financialActivityAccountRepositoryWrapper = financialActivityAccountRepositoryWrapper;
this.columnValidator = columnValidator;
this.paginationHelper = paginationHelper;
this.sqlGenerator = sqlGenerator;
}
private static final class GLJournalEntryMapper implements RowMapper<JournalEntryData> {
@@ -250,7 +255,7 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
GLJournalEntryMapper rm = new GLJournalEntryMapper(associationParametersData);
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(rm.schema());
final Object[] objectArray = new Object[15];
@@ -304,28 +309,19 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
String fromDateString = null;
String toDateString = null;
if (fromDate != null && toDate != null) {
sqlBuilder.append(whereClose + " journalEntry.entry_date between ? and ? ");
whereClose = " and ";
fromDateString = df.format(fromDate);
toDateString = df.format(toDate);
objectArray[arrayPos] = fromDateString;
arrayPos = arrayPos + 1;
objectArray[arrayPos] = toDateString;
arrayPos = arrayPos + 1;
sqlBuilder.append(whereClose + " journalEntry.entry_date between '" + fromDateString + "' and '" + toDateString + "' ");
whereClose = " and ";
} else if (fromDate != null) {
sqlBuilder.append(whereClose + " journalEntry.entry_date >= ? ");
fromDateString = df.format(fromDate);
objectArray[arrayPos] = fromDateString;
arrayPos = arrayPos + 1;
sqlBuilder.append(whereClose + " journalEntry.entry_date >= '" + fromDateString + "' ");
whereClose = " and ";
} else if (toDate != null) {
sqlBuilder.append(whereClose + " journalEntry.entry_date <= ? ");
toDateString = df.format(toDate);
objectArray[arrayPos] = toDateString;
arrayPos = arrayPos + 1;
sqlBuilder.append(whereClose + " journalEntry.entry_date <= '" + toDateString + "' ");
whereClose = " and ";
}
@@ -368,15 +364,16 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
}
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
final Object[] finalObjectArray = Arrays.copyOf(objectArray, arrayPos);
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), finalObjectArray, rm);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), finalObjectArray, rm);
}
@Override
@@ -530,9 +527,8 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
final GLJournalEntryMapper rm = new GLJournalEntryMapper(associationParametersData);
final String sql = "select " + rm.schema()
+ " where journalEntry.transaction_id = ? and journalEntry.entity_id = ? and journalEntry.entity_type_enum = ?";
final String sqlCountRows = "SELECT FOUND_ROWS()";
Object[] data = { transactionId, entityId, entityType };
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sql, data, rm);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sql, data, rm);
} catch (final EmptyResultDataAccessException e) {
throw new JournalEntriesNotFoundException(entityId, e);
}
@@ -39,6 +39,7 @@ import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.jobs.annotation.CronTarget;
import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
@@ -62,41 +63,19 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry
private final JournalEntryDataValidator dataValidator;
private final FromJsonHelper fromApiJsonHelper;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final GLJournalEntryMapper entryMapper = new GLJournalEntryMapper();
// if a limit is not added to the running balance select statements below
// and the resultset is more than 400,000,
// the script will eat up all of the server memory
private final String selectRunningBalanceSqlLimit = "limit 0, 10000";
private final String officeRunningBalanceSql = "select je.office_running_balance as runningBalance,je.account_id as accountId from acc_gl_journal_entry je "
+ "inner join (select max(id) as id from acc_gl_journal_entry where office_id=? and entry_date < ? group by account_id,entry_date) je2 "
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where office_id=? and entry_date < ? group by account_id) je3 "
+ "where je2.id = je.id and je.entry_date = je3.date group by je.id order by je.entry_date DESC "
+ selectRunningBalanceSqlLimit;
private final String organizationRunningBalanceSql = "select je.organization_running_balance as runningBalance,je.account_id as accountId from acc_gl_journal_entry je "
+ "inner join (select max(id) as id from acc_gl_journal_entry where entry_date < ? group by account_id,entry_date) je2 "
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where entry_date < ? group by account_id) je3 "
+ "where je2.id = je.id and je.entry_date = je3.date group by je.id order by je.entry_date DESC "
+ selectRunningBalanceSqlLimit;
private final String officesRunningBalanceSql = "select je.office_running_balance as runningBalance,je.account_id as accountId,je.office_id as officeId "
+ "from acc_gl_journal_entry je "
+ "inner join (select max(id) as id from acc_gl_journal_entry where entry_date < ? group by office_id,account_id,entry_date) je2 "
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where entry_date < ? group by office_id,account_id) je3 "
+ "where je2.id = je.id and je.entry_date = je3.date group by je.id order by je.entry_date DESC "
+ selectRunningBalanceSqlLimit;
@Autowired
public JournalEntryRunningBalanceUpdateServiceImpl(final RoutingDataSource dataSource,
final OfficeRepositoryWrapper officeRepositoryWrapper, final JournalEntryDataValidator dataValidator,
final FromJsonHelper fromApiJsonHelper) {
final FromJsonHelper fromApiJsonHelper, DatabaseSpecificSQLGenerator sqlGenerator) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.officeRepositoryWrapper = officeRepositoryWrapper;
this.dataValidator = dataValidator;
this.fromApiJsonHelper = fromApiJsonHelper;
this.sqlGenerator = sqlGenerator;
}
@Override
@@ -140,7 +119,12 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry
Map<Long, BigDecimal> runningBalanceMap = new HashMap<>(5);
Map<Long, Map<Long, BigDecimal>> officesRunningBalance = new HashMap<>();
List<Map<String, Object>> list = jdbcTemplate.queryForList(organizationRunningBalanceSql, entityDate, entityDate);
List<Map<String, Object>> list = jdbcTemplate.queryForList(
"select je.organization_running_balance as runningBalance,je.account_id as accountId from acc_gl_journal_entry je "
+ "inner join (select max(id) as id from acc_gl_journal_entry where entry_date < ? group by account_id,entry_date) je2 ON je2.id = je.id "
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where entry_date < ? group by account_id) je3 ON je.entry_date = je3.date "
+ "group by je.id order by je.entry_date DESC " + sqlGenerator.limit(10000, 0),
entityDate, entityDate);
for (Map<String, Object> entries : list) {
Long accountId = Long.parseLong(entries.get("accountId").toString()); // Drizzle
// is
@@ -157,7 +141,12 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry
}
}
List<Map<String, Object>> officesRunningBalanceList = jdbcTemplate.queryForList(officesRunningBalanceSql, entityDate, entityDate);
List<Map<String, Object>> officesRunningBalanceList = jdbcTemplate
.queryForList("select je.office_running_balance as runningBalance,je.account_id as accountId,je.office_id as officeId "
+ "from acc_gl_journal_entry je "
+ "inner join (select max(id) as id from acc_gl_journal_entry where entry_date < ? group by office_id,account_id,entry_date) je2 ON je2.id = je.id "
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where entry_date < ? group by office_id,account_id) je3 ON je.entry_date = je3.date "
+ "group by je.id order by je.entry_date DESC " + sqlGenerator.limit(10000, 0), entityDate, entityDate);
for (Map<String, Object> entries : officesRunningBalanceList) {
Long accountId = Long.parseLong(entries.get("accountId").toString());
Long officeId = Long.parseLong(entries.get("officeId").toString());
@@ -212,7 +201,12 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry
private void updateRunningBalance(Long officeId, Date entityDate) {
Map<Long, BigDecimal> runningBalanceMap = new HashMap<>(5);
List<Map<String, Object>> list = jdbcTemplate.queryForList(officeRunningBalanceSql, officeId, entityDate, officeId, entityDate);
List<Map<String, Object>> list = jdbcTemplate.queryForList(
"select je.office_running_balance as runningBalance,je.account_id as accountId from acc_gl_journal_entry je "
+ "inner join (select max(id) as id from acc_gl_journal_entry where office_id=? and entry_date < ? group by account_id,entry_date) je2 ON je2.id = je.id "
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where office_id=? and entry_date < ? group by account_id) je3 ON je.entry_date = je3.date "
+ "group by je.id order by je.entry_date DESC " + sqlGenerator.limit(10000, 0),
officeId, entityDate, officeId, entityDate);
for (Map<String, Object> entries : list) {
Long accountId = (Long) entries.get("accountId");
if (!runningBalanceMap.containsKey(accountId)) {
@@ -32,6 +32,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -46,18 +47,23 @@ public class ProvisioningEntriesReadPlatformServiceImpl implements ProvisioningE
private static final Logger LOG = LoggerFactory.getLogger(ProvisioningEntriesReadPlatformServiceImpl.class);
private final JdbcTemplate jdbcTemplate;
private final PaginationHelper<LoanProductProvisioningEntryData> loanProductProvisioningEntryDataPaginationHelper = new PaginationHelper<>();
private final PaginationHelper<ProvisioningEntryData> provisioningEntryDataPaginationHelper = new PaginationHelper<>();
private final PaginationHelper loanProductProvisioningEntryDataPaginationHelper;
private final PaginationHelper provisioningEntryDataPaginationHelper;
private final DatabaseSpecificSQLGenerator sqlGenerator;
@Autowired
public ProvisioningEntriesReadPlatformServiceImpl(final RoutingDataSource dataSource) {
public ProvisioningEntriesReadPlatformServiceImpl(final RoutingDataSource dataSource, DatabaseSpecificSQLGenerator sqlGenerator,
PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.loanProductProvisioningEntryDataPaginationHelper = paginationHelper;
this.provisioningEntryDataPaginationHelper = paginationHelper;
this.sqlGenerator = sqlGenerator;
}
@Override
public Collection<LoanProductProvisioningEntryData> retrieveLoanProductsProvisioningData(Date date) {
String formattedDate = new SimpleDateFormat("yyyy-MM-dd").format(date);
LoanProductProvisioningEntryMapper mapper = new LoanProductProvisioningEntryMapper();
LoanProductProvisioningEntryMapper mapper = new LoanProductProvisioningEntryMapper(sqlGenerator);
final String sql = mapper.schema();
return this.jdbcTemplate.query(sql, mapper, new Object[] { formattedDate, formattedDate, formattedDate });
}
@@ -66,17 +72,17 @@ public class ProvisioningEntriesReadPlatformServiceImpl implements ProvisioningE
private final StringBuilder sqlQuery;
private LoanProductProvisioningEntryMapper() {
private LoanProductProvisioningEntryMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
sqlQuery = new StringBuilder().append(
"select (CASE WHEN loan.loan_type_enum=1 THEN mclient.office_id ELSE mgroup.office_id END) as office_id, loan.loan_type_enum, pcd.criteria_id as criteriaid, loan.product_id,loan.currency_code,")
.append("GREATEST(datediff(?")
.append(",sch.duedate),0) as numberofdaysoverdue,sch.duedate, pcd.category_id, pcd.provision_percentage,")
.append("GREATEST(" + sqlGenerator.dateDiff("?", "sch.duedate")
+ ", 0) as numberofdaysoverdue,sch.duedate, pcd.category_id, pcd.provision_percentage,")
.append("loan.total_outstanding_derived as outstandingbalance, pcd.liability_account, pcd.expense_account from m_loan_repayment_schedule sch")
.append(" LEFT JOIN m_loan loan on sch.loan_id = loan.id")
.append(" JOIN m_loanproduct_provisioning_mapping lpm on lpm.product_id = loan.product_id")
.append(" JOIN m_provisioning_criteria_definition pcd on pcd.criteria_id = lpm.criteria_id and ")
.append("(pcd.min_age <= GREATEST(datediff(?,sch.duedate),0) and GREATEST(datediff(?")
.append(",sch.duedate),0) <= pcd.max_age) and pcd.criteria_id is not null ")
.append("(pcd.min_age <= GREATEST(" + sqlGenerator.dateDiff("?", "sch.duedate") + ",0) and GREATEST("
+ sqlGenerator.dateDiff("?", "sch.duedate") + ",0) <= pcd.max_age) and pcd.criteria_id is not null ")
.append("LEFT JOIN m_client mclient ON mclient.id = loan.client_id ")
.append("LEFT JOIN m_group mgroup ON mgroup.id = loan.group_id ")
.append("where loan.loan_status_id=300 and sch.duedate = ")
@@ -221,7 +227,7 @@ public class ProvisioningEntriesReadPlatformServiceImpl implements ProvisioningE
public Page<ProvisioningEntryData> retrieveAllProvisioningEntries(Integer offset, Integer limit) {
ProvisioningEntryDataMapper mapper = new ProvisioningEntryDataMapper();
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(mapper.getSchema());
sqlBuilder.append(" order by entry.created_date");
if (limit != null) {
@@ -231,10 +237,9 @@ public class ProvisioningEntriesReadPlatformServiceImpl implements ProvisioningE
sqlBuilder.append(" offset ").append(offset);
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
Object[] whereClauseItemsitems = new Object[] {};
return this.provisioningEntryDataPaginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(),
whereClauseItemsitems, mapper);
return this.provisioningEntryDataPaginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), whereClauseItemsitems,
mapper);
}
@Override
@@ -308,7 +313,7 @@ public class ProvisioningEntriesReadPlatformServiceImpl implements ProvisioningE
public Page<LoanProductProvisioningEntryData> retrieveProvisioningEntries(SearchParameters searchParams) {
LoanProductProvisioningEntryRowMapper mapper = new LoanProductProvisioningEntryRowMapper();
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(mapper.getSchema());
String whereClose = " where ";
List<Object> items = new ArrayList<>();
@@ -344,8 +349,7 @@ public class ProvisioningEntriesReadPlatformServiceImpl implements ProvisioningE
}
}
Object[] whereClauseItemsitems = items.toArray();
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.loanProductProvisioningEntryDataPaginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(),
return this.loanProductProvisioningEntryDataPaginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(),
whereClauseItemsitems, mapper);
}
@@ -55,7 +55,7 @@ public final class AdHoc extends AbstractAuditableCustom {
@Column(name = "report_run_every")
private Long reportRunEvery;
@Column(name = "IsActive", nullable = false)
@Column(name = "is_active", nullable = false)
private boolean isActive = false;
private AdHoc() {}
@@ -26,6 +26,7 @@ import org.apache.fineract.adhocquery.data.AdHocData;
import org.apache.fineract.adhocquery.exception.AdHocNotFoundException;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -36,12 +37,14 @@ import org.springframework.stereotype.Service;
public class AdHocReadPlatformServiceImpl implements AdHocReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final AdHocMapper adHocRowMapper;
@Autowired
public AdHocReadPlatformServiceImpl(final RoutingDataSource dataSource) {
public AdHocReadPlatformServiceImpl(final RoutingDataSource dataSource, DatabaseSpecificSQLGenerator sqlGenerator) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.adHocRowMapper = new AdHocMapper();
this.sqlGenerator = sqlGenerator;
this.adHocRowMapper = new AdHocMapper(sqlGenerator);
}
@Override
@@ -53,7 +56,8 @@ public class AdHocReadPlatformServiceImpl implements AdHocReadPlatformService {
@Override
public Collection<AdHocData> retrieveAllActiveAdHocQuery() {
final String sql = "select " + this.adHocRowMapper.schema() + " where r.IsActive = true order by r.id";
final String sql = "select " + this.adHocRowMapper.schema() + " where r." + sqlGenerator.escape("is_active")
+ " = true order by r.id";
return this.jdbcTemplate.query(sql, this.adHocRowMapper);
}
@@ -72,6 +76,12 @@ public class AdHocReadPlatformServiceImpl implements AdHocReadPlatformService {
protected static final class AdHocMapper implements RowMapper<AdHocData> {
private final DatabaseSpecificSQLGenerator sqlGenerator;
public AdHocMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
this.sqlGenerator = sqlGenerator;
}
@Override
public AdHocData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
@@ -96,7 +106,7 @@ public class AdHocReadPlatformServiceImpl implements AdHocReadPlatformService {
}
public String schema() {
return " r.id as id, r.name as name, r.query as query, r.table_name as tableName,r.table_fields as tableField ,r.IsActive as isActive ,r.email as email ,"
return " r.id as id, r.name as name, r.query as query, r.table_name as tableName,r.table_fields as tableField ,r.is_active as isActive ,r.email as email ,"
+ " r.report_run_frequency_code, r.report_run_every, r.last_run, "
+ " r.created_date as createdDate, r.createdby_id as createdById,cb.username as createdBy,r.lastmodifiedby_id as updatedById ,r.lastmodified_date as updatedOn "
+ " from m_adhoc r left join m_appuser cb on cb.id=r.createdby_id left join m_appuser mb on mb.id=r.lastmodifiedby_id";
@@ -43,6 +43,7 @@ import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.infrastructure.security.utils.SQLBuilder;
@@ -87,7 +88,8 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
private final ClientReadPlatformService clientReadPlatformService;
private final LoanProductReadPlatformService loanProductReadPlatformService;
private final StaffReadPlatformService staffReadPlatformService;
private final PaginationHelper<AuditData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final PaginationParametersDataValidator paginationParametersDataValidator;
private final SavingsProductReadPlatformService savingsProductReadPlatformService;
private final DepositProductReadPlatformService depositProductReadPlatformService;
@@ -100,7 +102,8 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
final LoanProductReadPlatformService loanProductReadPlatformService, final StaffReadPlatformService staffReadPlatformService,
final PaginationParametersDataValidator paginationParametersDataValidator,
final SavingsProductReadPlatformService savingsProductReadPlatformService,
final DepositProductReadPlatformService depositProductReadPlatformService, final ColumnValidator columnValidator) {
final DepositProductReadPlatformService depositProductReadPlatformService, final ColumnValidator columnValidator,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.fromApiJsonHelper = fromApiJsonHelper;
@@ -113,6 +116,8 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
this.savingsProductReadPlatformService = savingsProductReadPlatformService;
this.depositProductReadPlatformService = depositProductReadPlatformService;
this.columnValidator = columnValidator;
this.paginationHelper = paginationHelper;
this.sqlGenerator = sqlGenerator;
}
private static final class AuditMapper implements RowMapper<AuditData> {
@@ -199,7 +204,7 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
final AuditMapper rm = new AuditMapper();
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(rm.schema(includeJson, hierarchy));
sqlBuilder.append(' ').append(extraCriteria.getSQLTemplate());
if (parameters.isOrderByRequested()) {
@@ -216,8 +221,7 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
LOG.info("sql: {}", sqlBuilder);
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), extraCriteria.getArguments(), rm);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), extraCriteria.getArguments(), rm);
}
@Override
@@ -60,7 +60,7 @@ public class EmailCampaign extends AbstractPersistableCustom {
private Integer campaignType;
@ManyToOne
@JoinColumn(name = "businessRule_id", nullable = false)
@JoinColumn(name = "business_rule_id", nullable = false)
private Report businessRuleId;
@Column(name = "param_value")
@@ -72,7 +72,7 @@ public class EmailCampaignReadPlatformServiceImpl implements EmailCampaignReadPl
sql.append("ec.id as id, ");
sql.append("ec.campaign_name as campaignName, ");
sql.append("ec.campaign_type as campaignType, ");
sql.append("ec.businessRule_id as businessRuleId, ");
sql.append("ec.business_rule_id as businessRuleId, ");
sql.append("ec.email_subject as emailSubject, ");
sql.append("ec.email_message as emailMessage, ");
sql.append("ec.email_attachment_file_format as emailAttachmentFileFormat, ");
@@ -36,6 +36,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -46,12 +47,16 @@ import org.springframework.stereotype.Service;
public class EmailReadPlatformServiceImpl implements EmailReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final EmailMapper emailRowMapper = new EmailMapper();
private final PaginationHelper<EmailData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
@Autowired
public EmailReadPlatformServiceImpl(final RoutingDataSource dataSource) {
public EmailReadPlatformServiceImpl(final RoutingDataSource dataSource, DatabaseSpecificSQLGenerator sqlGenerator,
PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.sqlGenerator = sqlGenerator;
this.paginationHelper = paginationHelper;
}
private static final class EmailMapper implements RowMapper<EmailData> {
@@ -129,7 +134,7 @@ public class EmailReadPlatformServiceImpl implements EmailReadPlatformService {
@Override
public Collection<EmailData> retrieveAllPending(final SearchParameters searchParameters) {
final String sqlPlusLimit = (searchParameters.getLimit() > 0) ? " limit 0, " + searchParameters.getLimit() : "";
final String sqlPlusLimit = (searchParameters.getLimit() > 0) ? " " + sqlGenerator.limit(searchParameters.getLimit()) : "";
final String sql = "select " + this.emailRowMapper.schema() + " where emo.status_enum =? " + sqlPlusLimit;
return this.jdbcTemplate.query(sql, this.emailRowMapper, EmailMessageStatusType.PENDING.getValue());
@@ -137,7 +142,7 @@ public class EmailReadPlatformServiceImpl implements EmailReadPlatformService {
@Override
public Collection<EmailData> retrieveAllSent(final SearchParameters searchParameters) {
final String sqlPlusLimit = (searchParameters.getLimit() > 0) ? " limit 0, " + searchParameters.getLimit() : "";
final String sqlPlusLimit = (searchParameters.getLimit() > 0) ? " " + sqlGenerator.limit(searchParameters.getLimit()) : "";
final String sql = "select " + this.emailRowMapper.schema() + " where emo.status_enum = ?" + sqlPlusLimit;
return this.jdbcTemplate.query(sql, this.emailRowMapper, EmailMessageStatusType.SENT.getValue());
@@ -145,7 +150,7 @@ public class EmailReadPlatformServiceImpl implements EmailReadPlatformService {
@Override
public List<Long> retrieveExternalIdsOfAllSent(final Integer limit) {
final String sqlPlusLimit = (limit > 0) ? " limit 0, " + limit : "";
final String sqlPlusLimit = (limit > 0) ? " " + sqlGenerator.limit(limit) : "";
final String sql = "select external_id from " + this.emailRowMapper.tableName() + " where status_enum =? " + sqlPlusLimit;
return this.jdbcTemplate.queryForList(sql, Long.class, EmailMessageStatusType.SENT.getValue());
@@ -153,7 +158,7 @@ public class EmailReadPlatformServiceImpl implements EmailReadPlatformService {
@Override
public Collection<EmailData> retrieveAllDelivered(final Integer limit) {
final String sqlPlusLimit = (limit > 0) ? " limit 0, " + limit : "";
final String sqlPlusLimit = (limit > 0) ? " " + sqlGenerator.limit(limit) : "";
final String sql = "select " + this.emailRowMapper.schema() + " where emo.status_enum = ?" + sqlPlusLimit;
return this.jdbcTemplate.query(sql, this.emailRowMapper, EmailMessageStatusType.DELIVERED.getValue());
@@ -161,7 +166,7 @@ public class EmailReadPlatformServiceImpl implements EmailReadPlatformService {
@Override
public Collection<EmailData> retrieveAllFailed(final SearchParameters searchParameters) {
final String sqlPlusLimit = (searchParameters.getLimit() > 0) ? " limit 0, " + searchParameters.getLimit() : "";
final String sqlPlusLimit = (searchParameters.getLimit() > 0) ? " " + sqlGenerator.limit(searchParameters.getLimit()) : "";
final String sql = "select " + this.emailRowMapper.schema() + " where emo.status_enum = ?" + sqlPlusLimit;
return this.jdbcTemplate.query(sql, this.emailRowMapper, EmailMessageStatusType.FAILED.getValue());
@@ -170,7 +175,7 @@ public class EmailReadPlatformServiceImpl implements EmailReadPlatformService {
@Override
public Page<EmailData> retrieveEmailByStatus(final Integer limit, final Integer status, final Date dateFrom, final Date dateTo) {
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(this.emailRowMapper.schema());
if (status != null) {
sqlBuilder.append(" where emo.status_enum= ? ");
@@ -183,12 +188,11 @@ public class EmailReadPlatformServiceImpl implements EmailReadPlatformService {
toDateString = df.format(dateTo);
sqlBuilder.append(" and emo.submittedon_date >= ? and emo.submittedon_date <= ? ");
}
final String sqlPlusLimit = (limit > 0) ? " limit 0, " + limit : "";
final String sqlPlusLimit = (limit > 0) ? " " + sqlGenerator.limit(limit) : "";
if (!sqlPlusLimit.isEmpty()) {
sqlBuilder.append(sqlPlusLimit);
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(),
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(),
new Object[] { status, fromDateString, toDateString }, this.emailRowMapper);
}
}
@@ -42,6 +42,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.portfolio.calendar.service.CalendarDropdownReadPlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
@@ -56,20 +57,24 @@ public class SmsCampaignReadPlatformServiceImpl implements SmsCampaignReadPlatfo
private final BusinessRuleMapper businessRuleMapper;
private final JdbcTemplate jdbcTemplate;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final SmsCampaignDropdownReadPlatformService smsCampaignDropdownReadPlatformService;
private final SmsCampaignMapper smsCampaignMapper;
private final CalendarDropdownReadPlatformService calendarDropdownReadPlatformService;
private final PaginationHelper<SmsCampaignData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
@Autowired
public SmsCampaignReadPlatformServiceImpl(final RoutingDataSource dataSource,
SmsCampaignDropdownReadPlatformService smsCampaignDropdownReadPlatformService,
final CalendarDropdownReadPlatformService calendarDropdownReadPlatformService) {
final CalendarDropdownReadPlatformService calendarDropdownReadPlatformService, DatabaseSpecificSQLGenerator sqlGenerator,
PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
businessRuleMapper = new BusinessRuleMapper();
this.sqlGenerator = sqlGenerator;
this.businessRuleMapper = new BusinessRuleMapper(sqlGenerator);
this.smsCampaignDropdownReadPlatformService = smsCampaignDropdownReadPlatformService;
smsCampaignMapper = new SmsCampaignMapper();
this.smsCampaignMapper = new SmsCampaignMapper();
this.calendarDropdownReadPlatformService = calendarDropdownReadPlatformService;
this.paginationHelper = paginationHelper;
}
@Override
@@ -87,17 +92,18 @@ public class SmsCampaignReadPlatformServiceImpl implements SmsCampaignReadPlatfo
public Page<SmsCampaignData> retrieveAll(final SearchParameters searchParameters) {
final Integer visible = 1;
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(this.smsCampaignMapper.schema() + " where sc.is_visible = ? ");
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(jdbcTemplate, sqlCountRows, sqlBuilder.toString(), new Object[] { visible },
this.smsCampaignMapper);
return this.paginationHelper.fetchPage(jdbcTemplate, sqlBuilder.toString(), new Object[] { visible }, this.smsCampaignMapper);
}
@Override
@@ -133,7 +139,7 @@ public class SmsCampaignReadPlatformServiceImpl implements SmsCampaignReadPlatfo
final String schema;
private BusinessRuleMapper() {
private BusinessRuleMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
final StringBuilder sql = new StringBuilder(300);
sql.append("sr.id as id, ");
sql.append("sr.report_name as reportName, ");
@@ -141,7 +147,7 @@ public class SmsCampaignReadPlatformServiceImpl implements SmsCampaignReadPlatfo
sql.append("sr.report_subtype as reportSubType, ");
sql.append("sr.description as description, ");
sql.append("sp.parameter_variable as params, ");
sql.append("sp.parameter_FormatType as paramType, ");
sql.append("sp." + sqlGenerator.escape("parameter_FormatType") + " as paramType, ");
sql.append("sp.parameter_label as paramLabel, ");
sql.append("sp.parameter_name as paramName ");
sql.append("from stretchy_report sr ");
@@ -22,6 +22,7 @@ package org.apache.fineract.infrastructure.core.config;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.apache.fineract.infrastructure.core.domain.AuditorAwareImpl;
import org.apache.fineract.infrastructure.openjpa.OpenJpaTransactionManager;
import org.apache.fineract.infrastructure.openjpa.OpenJpaVendorAdapter;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
@@ -58,8 +59,8 @@ public class PersistenceConfig {
}
@Bean
public JpaTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager jtm = new JpaTransactionManager();
public OpenJpaTransactionManager transactionManager(EntityManagerFactory emf) {
OpenJpaTransactionManager jtm = new OpenJpaTransactionManager();
jtm.setEntityManagerFactory(emf);
return jtm;
}
@@ -20,26 +20,46 @@ package org.apache.fineract.infrastructure.core.service;
import java.util.List;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;
public class PaginationHelper<E> {
@Component
public class PaginationHelper {
public Page<E> fetchPage(final JdbcTemplate jt, final String sqlCountRows, final String sqlFetchRows, final Object[] args,
final RowMapper<E> rowMapper) {
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final DatabaseTypeResolver databaseTypeResolver;
@Autowired
public PaginationHelper(DatabaseSpecificSQLGenerator sqlGenerator, DatabaseTypeResolver databaseTypeResolver) {
this.sqlGenerator = sqlGenerator;
this.databaseTypeResolver = databaseTypeResolver;
}
public <E> Page<E> fetchPage(final JdbcTemplate jt, final String sqlFetchRows, final Object[] args, final RowMapper<E> rowMapper) {
final List<E> items = jt.query(sqlFetchRows, rowMapper, args);
// determine how many rows are available
final int totalFilteredRecords = jt.queryForObject(sqlCountRows, Integer.class);
String sqlCountRows = sqlGenerator.countLastExecutedQueryResult(sqlFetchRows);
final int totalFilteredRecords;
if (databaseTypeResolver.isMySQL()) {
totalFilteredRecords = jt.queryForObject(sqlCountRows, Integer.class);
} else {
totalFilteredRecords = jt.queryForObject(sqlCountRows, Integer.class, args);
}
return new Page<>(items, totalFilteredRecords);
}
public Page<Long> fetchPage(JdbcTemplate jdbcTemplate, String sql, String sqlCountRows, Class<Long> type) {
public <E> Page<Long> fetchPage(JdbcTemplate jdbcTemplate, String sql, Class<Long> type) {
final List<Long> items = jdbcTemplate.queryForList(sql, type);
// determine how many rows are available
String sqlCountRows = sqlGenerator.countLastExecutedQueryResult(sql);
Integer totalFilteredRecords = jdbcTemplate.queryForObject(sqlCountRows, Integer.class);
return new Page<>(items, ObjectUtils.defaultIfNull(totalFilteredRecords, 0));
@@ -24,6 +24,7 @@ import java.sql.SQLException;
import java.util.Collection;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.stereotype.Component;
@Component
@@ -40,7 +41,7 @@ public class DatabaseIndependentQueryService implements DatabaseQueryService {
try {
DatabaseQueryService result = null;
if (isNotEmpty(queryServices)) {
result = queryServices.stream().filter(qs -> qs.isSupported(dataSource)).findAny().orElse(null);
result = queryServices.stream().filter(DatabaseQueryService::isSupported).findAny().orElse(null);
}
if (result == null) {
throw new IllegalStateException("DataSource not supported: " + dataSource.getConnection().getMetaData().getURL());
@@ -52,7 +53,7 @@ public class DatabaseIndependentQueryService implements DatabaseQueryService {
}
@Override
public boolean isSupported(DataSource dataSource) {
public boolean isSupported() {
return true;
}
@@ -60,4 +61,9 @@ public class DatabaseIndependentQueryService implements DatabaseQueryService {
public boolean isTablePresent(DataSource dataSource, String tableName) {
return choose(dataSource).isTablePresent(dataSource, tableName);
}
@Override
public SqlRowSet getTableColumns(DataSource dataSource, String tableName) {
return choose(dataSource).getTableColumns(dataSource, tableName);
}
}
@@ -19,10 +19,14 @@
package org.apache.fineract.infrastructure.core.service.database;
import javax.sql.DataSource;
import org.springframework.jdbc.support.rowset.SqlRowSet;
public interface DatabaseQueryService {
boolean isSupported(DataSource dataSource);
boolean isSupported();
boolean isTablePresent(DataSource dataSource, String tableName);
// TODO: This needs to be improved to have a custom POJO return type instead of the raw SqlRowSet
SqlRowSet getTableColumns(DataSource dataSource, String tableName);
}
@@ -0,0 +1,150 @@
/**
* 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.service.database;
import static java.lang.String.format;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class DatabaseSpecificSQLGenerator {
private final DatabaseTypeResolver databaseTypeResolver;
@Autowired
public DatabaseSpecificSQLGenerator(DatabaseTypeResolver databaseTypeResolver) {
this.databaseTypeResolver = databaseTypeResolver;
}
public String escape(String arg) {
if (databaseTypeResolver.isMySQL()) {
return format("`%s`", arg);
} else if (databaseTypeResolver.isPostgreSQL()) {
return format("\"%s\"", arg);
}
return arg;
}
public String groupConcat(String arg) {
if (databaseTypeResolver.isMySQL()) {
return format("GROUP_CONCAT(%s)", arg);
} else if (databaseTypeResolver.isPostgreSQL()) {
// STRING_AGG only works with strings
return format("STRING_AGG(%s::varchar, ',')", arg);
} else {
throw new IllegalStateException("Database type is not supported for group concat " + databaseTypeResolver.databaseType());
}
}
public String limit(int count) {
return limit(count, 0);
}
public String limit(int count, int offset) {
if (databaseTypeResolver.isMySQL()) {
return format("LIMIT %s,%s", offset, count);
} else if (databaseTypeResolver.isPostgreSQL()) {
return format("LIMIT %s OFFSET %s", count, offset);
} else {
throw new IllegalStateException("Database type is not supported for limit " + databaseTypeResolver.databaseType());
}
}
public String calcFoundRows() {
if (databaseTypeResolver.isMySQL()) {
return "SQL_CALC_FOUND_ROWS";
} else {
return "";
}
}
public String countLastExecutedQueryResult(String sql) {
if (databaseTypeResolver.isMySQL()) {
return "SELECT FOUND_ROWS()";
} else {
return countQueryResult(sql);
}
}
public String countQueryResult(String sql) {
return format("SELECT COUNT(*) FROM (%s) AS temp", sql);
}
public String currentDate() {
if (databaseTypeResolver.isMySQL()) {
return "CURDATE()";
} else if (databaseTypeResolver.isPostgreSQL()) {
return "CURRENT_DATE";
} else {
throw new IllegalStateException("Database type is not supported for current date " + databaseTypeResolver.databaseType());
}
}
public String subDate(String date, String multiplier, String unit) {
if (databaseTypeResolver.isMySQL()) {
return format("DATE_SUB(%s, INTERVAL %s %s)", date, multiplier, unit);
} else if (databaseTypeResolver.isPostgreSQL()) {
return format("(%s::TIMESTAMP - %s * INTERVAL '1 %s')", date, multiplier, unit);
} else {
throw new IllegalStateException("Database type is not supported for subtracting date " + databaseTypeResolver.databaseType());
}
}
public String dateDiff(String date1, String date2) {
if (databaseTypeResolver.isMySQL()) {
return format("DATEDIFF(%s, %s)", date1, date2);
} else if (databaseTypeResolver.isPostgreSQL()) {
return format("EXTRACT(DAY FROM (%s::TIMESTAMP - %s::TIMESTAMP))", date1, date2);
} else {
throw new IllegalStateException("Database type is not supported for date diff " + databaseTypeResolver.databaseType());
}
}
public String lastInsertId() {
if (databaseTypeResolver.isMySQL()) {
return "LAST_INSERT_ID()";
} else if (databaseTypeResolver.isPostgreSQL()) {
return "LASTVAL()";
} else {
throw new IllegalStateException("Database type is not supported for last insert id " + databaseTypeResolver.databaseType());
}
}
public String castChar(String sql) {
if (databaseTypeResolver.isMySQL()) {
return format("CAST(%s AS CHAR)", sql);
} else if (databaseTypeResolver.isPostgreSQL()) {
return format("%s::CHAR", sql);
} else {
throw new IllegalStateException(
"Database type is not supported for casting to character " + databaseTypeResolver.databaseType());
}
}
public String currentSchema() {
if (databaseTypeResolver.isMySQL()) {
return "SCHEMA()";
} else if (databaseTypeResolver.isPostgreSQL()) {
return "CURRENT_SCHEMA()";
} else {
throw new IllegalStateException("Database type is not supported for current schema " + databaseTypeResolver.databaseType());
}
}
}
@@ -19,5 +19,5 @@
package org.apache.fineract.infrastructure.core.service.database;
public enum DatabaseType {
MYSQL
MYSQL, POSTGRESQL
}
@@ -18,53 +18,49 @@
*/
package org.apache.fineract.infrastructure.core.service.database;
import static org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection.toProtocol;
import com.zaxxer.hikari.HikariConfig;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.sql.DataSource;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import java.util.concurrent.atomic.AtomicReference;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class DatabaseTypeResolver {
public class DatabaseTypeResolver implements InitializingBean {
private final Map<String, DatabaseType> protocolMapping = Map.of("jdbc:mariadb", DatabaseType.MYSQL, "jdbc:mysql", DatabaseType.MYSQL);
private final Map<String, DatabaseType> driverMapping = Map.of("org.mariadb.jdbc.Driver", DatabaseType.MYSQL, "com.mysql.jdbc.Driver",
DatabaseType.MYSQL, "org.postgresql.Driver", DatabaseType.POSTGRESQL);
private final Map<DataSource, DatabaseType> dataSourceCache = new ConcurrentHashMap<>();
private final RoutingDataSource routingDataSource;
private final AtomicReference<DatabaseType> currentDatabaseType = new AtomicReference<>();
private final HikariConfig hikariConfig;
@Autowired
public DatabaseTypeResolver(RoutingDataSource routingDataSource) {
this.routingDataSource = routingDataSource;
public DatabaseTypeResolver(HikariConfig hikariConfig) {
this.hikariConfig = hikariConfig;
}
public boolean isMySQL() {
return isMySQL(routingDataSource);
@Override
public void afterPropertiesSet() throws Exception {
currentDatabaseType.set(determineDatabaseType(hikariConfig.getDriverClassName()));
}
public boolean isMySQL(DataSource dataSource) {
return DatabaseType.MYSQL.equals(databaseType(dataSource));
private DatabaseType determineDatabaseType(String driverClassName) {
DatabaseType databaseType = driverMapping.get(driverClassName);
if (databaseType == null) {
throw new IllegalArgumentException("The driver's class is not supported " + driverClassName);
}
return databaseType;
}
public DatabaseType databaseType() {
return databaseType(routingDataSource);
return currentDatabaseType.get();
}
public DatabaseType databaseType(DataSource dataSource) {
DataSource unwrappedDataSource = dataSource;
if (dataSource instanceof RoutingDataSource) {
unwrappedDataSource = ((RoutingDataSource) dataSource).determineTargetDataSource();
}
return dataSourceCache.computeIfAbsent(unwrappedDataSource, (ds) -> {
String protocol = toProtocol(ds);
DatabaseType databaseType = protocolMapping.get(protocol);
if (databaseType == null) {
throw new IllegalArgumentException("The DataSource is not supported");
}
return databaseType;
});
public boolean isPostgreSQL() {
return DatabaseType.POSTGRESQL.equals(currentDatabaseType.get());
}
public boolean isMySQL() {
return DatabaseType.MYSQL.equals(currentDatabaseType.get());
}
}
@@ -19,10 +19,9 @@
package org.apache.fineract.infrastructure.core.service.database;
import static java.lang.String.format;
import static org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection.toProtocol;
import java.util.Set;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.stereotype.Component;
@@ -30,12 +29,16 @@ import org.springframework.stereotype.Component;
@Component
public class MySQLQueryService implements DatabaseQueryService {
private final Set<String> supportedProtocols = Set.of("jdbc:mariadb", "jdbc:mysql");
private final DatabaseTypeResolver databaseTypeResolver;
@Autowired
public MySQLQueryService(DatabaseTypeResolver databaseTypeResolver) {
this.databaseTypeResolver = databaseTypeResolver;
}
@Override
public boolean isSupported(DataSource dataSource) {
String protocol = toProtocol(dataSource);
return supportedProtocols.contains(protocol.toLowerCase());
public boolean isSupported() {
return databaseTypeResolver.isMySQL();
}
@Override
@@ -44,4 +47,17 @@ public class MySQLQueryService implements DatabaseQueryService {
SqlRowSet rs = jdbcTemplate.queryForRowSet(format("SHOW TABLES LIKE '%s'", tableName));
return rs.next();
}
@Override
public SqlRowSet getTableColumns(DataSource dataSource, String tableName) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String sql = "SELECT c.COLUMN_NAME, c.IS_NULLABLE, c.DATA_TYPE, c.CHARACTER_MAXIMUM_LENGTH, c.COLUMN_KEY FROM INFORMATION_SCHEMA.COLUMNS c WHERE TABLE_SCHEMA = schema() AND TABLE_NAME = '"
+ tableName + "' ORDER BY ORDINAL_POSITION";
final SqlRowSet columnDefinitions = jdbcTemplate.queryForRowSet(sql);
if (columnDefinitions.next()) {
return columnDefinitions;
} else {
throw new IllegalArgumentException("Table " + tableName + " is not found");
}
}
}
@@ -0,0 +1,65 @@
/**
* 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.service.database;
import static java.lang.String.format;
import java.util.Objects;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.stereotype.Component;
@Component
public class PostgreSQLQueryService implements DatabaseQueryService {
private final DatabaseTypeResolver databaseTypeResolver;
@Autowired
public PostgreSQLQueryService(DatabaseTypeResolver databaseTypeResolver) {
this.databaseTypeResolver = databaseTypeResolver;
}
@Override
public boolean isSupported() {
return databaseTypeResolver.isPostgreSQL();
}
@Override
public boolean isTablePresent(DataSource dataSource, String tableName) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
Integer result = jdbcTemplate.queryForObject(format("SELECT COUNT(table_name) " + "FROM information_schema.tables "
+ "WHERE table_schema = 'public' " + "AND table_name = '%s';", tableName), Integer.class);
return Objects.equals(result, 1);
}
@Override
public SqlRowSet getTableColumns(DataSource dataSource, String tableName) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String sql = "SELECT attname AS COLUMN_NAME, not attnotnull AS IS_NULLABLE, atttypid::regtype AS DATATYPE, attlen AS CHARACTER_MAXIMUM_LENGTH, attnum = 1 AS COLUMN_KEY FROM pg_attribute WHERE attrelid = '\""
+ tableName + "\"'::regclass AND attnum > 0 AND NOT attisdropped ORDER BY attnum";
final SqlRowSet columnDefinitions = jdbcTemplate.queryForRowSet(sql);
if (columnDefinitions.next()) {
return columnDefinitions;
} else {
throw new IllegalArgumentException("Table " + tableName + " is not found");
}
}
}
@@ -19,7 +19,6 @@
package org.apache.fineract.infrastructure.core.service.migration;
import java.util.Map;
import javax.sql.DataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseType;
import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver;
import org.springframework.beans.factory.annotation.Autowired;
@@ -28,7 +27,7 @@ import org.springframework.stereotype.Component;
@Component
public class DatabaseAwareMigrationContextProvider {
private final Map<DatabaseType, String> contextMapping = Map.of(DatabaseType.MYSQL, "mysql");
private final Map<DatabaseType, String> contextMapping = Map.of(DatabaseType.MYSQL, "mysql", DatabaseType.POSTGRESQL, "postgresql");
private final DatabaseTypeResolver databaseTypeResolver;
@@ -37,8 +36,8 @@ public class DatabaseAwareMigrationContextProvider {
this.databaseTypeResolver = databaseTypeResolver;
}
public String provide(DataSource dataSource) {
DatabaseType databaseType = databaseTypeResolver.databaseType(dataSource);
public String provide() {
DatabaseType databaseType = databaseTypeResolver.databaseType();
String context = contextMapping.get(databaseType);
if (context == null) {
throw new IllegalStateException("Database is not supported");
@@ -43,7 +43,7 @@ public class ExtendedSpringLiquibaseFactory {
}
public ExtendedSpringLiquibase create(DataSource dataSource, String... contexts) {
String databaseContext = databaseAwareMigrationContextProvider.provide(dataSource);
String databaseContext = databaseAwareMigrationContextProvider.provide();
return new ExtendedSpringLiquibaseBuilder(liquibaseProperties).withDataSource(dataSource).withResourceLoader(resourceLoader)
.withContexts(contexts).withContexts(environment.getActiveProfiles()).withContext(databaseContext).build();
}
@@ -44,7 +44,7 @@ public class CreditReportReadPlatformServiceImpl implements CreditReportReadPlat
private static final class CreditReportDataMapper implements RowMapper<CreditReportData> {
public String schema() {
return " c.id as id, c.creditBureauId as creditBureauId , c.nationalId as nationalId from m_creditreport c ";
return " c.id as id, c.credit_bureau_id as creditBureauId , c.national_id as nationalId from m_creditreport c ";
}
@Override
@@ -19,6 +19,7 @@
package org.apache.fineract.infrastructure.creditbureau.domain;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
@@ -34,6 +35,7 @@ public class CreditBureau extends AbstractPersistableCustom {
private String country;
@Column(name = "implementation_key")
private String implementationKey;
public CreditBureau(String name, String product, String country, String implementationKey,
@@ -33,15 +33,16 @@ import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
@Table(name = "m_creditbureau_loanproduct_mapping")
public class CreditBureauLoanProductMapping extends AbstractPersistableCustom {
@Column(name = "is_CreditCheck_Mandatory")
@Column(name = "is_credit_check_mandatory")
private boolean isCreditCheckMandatory;
@Column(name = "skip_CreditCheck_in_Failure")
@Column(name = "skip_credit_check_in_failure")
private boolean skipCreditCheckInFailure;
@Column(name = "stale_Period")
@Column(name = "stale_period")
private int stalePeriod;
@Column(name = "is_active")
private boolean isActive;
@ManyToOne
@@ -43,16 +43,16 @@ public class CreditBureauToken extends AbstractPersistableCustom {
@Column(name = "token")
private String accessToken;
@Column(name = "tokenType")
@Column(name = "token_type")
private String tokenType;
@Column(name = "expiresIn")
@Column(name = "expires_in")
private String expiresIn;
@Column(name = "issued")
private String issued;
@Column(name = "expiryDate")
@Column(name = "expiry_date")
private Date expires;
public static CreditBureauToken fromJson(final JsonCommand command) {
@@ -29,14 +29,14 @@ import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Table(name = "m_creditreport")
public final class CreditReport extends AbstractPersistableCustom {
@Column(name = "creditBureauId")
@Column(name = "credit_bureau_id")
private Long creditBureauId;
@Column(name = "nationalId")
@Column(name = "national_id")
private String nationalId;
@Basic(fetch = FetchType.LAZY)
@Column(name = "creditReports")
@Column(name = "credit_reports")
private byte[] creditReports;
private CreditReport() {}
@@ -21,6 +21,7 @@ package org.apache.fineract.infrastructure.creditbureau.domain;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
@@ -37,6 +38,7 @@ public class OrganisationCreditBureau extends AbstractPersistableCustom {
@OneToOne
private CreditBureau creditbureau;
@Column(name = "is_active")
private boolean isActive;
@OneToMany(mappedBy = "organisation_creditbureau", cascade = CascadeType.ALL)
@@ -48,7 +48,7 @@ public class CreditBureauLoanProductMappingReadPlatformServiceImpl implements Cr
return "cblp.id as mappingId, cblp.organisation_creditbureau_id as orgcbId,"
+ "orgcb.alias as alias,concat( cb.product,' - ' ,cb.name,' - ',cb.country) as creditbureau,"
+ "cblp.loan_product_id as lpId,lp.name as loan_product_name,cblp.is_creditcheck_mandatory as crCheck,cblp.skip_creditcheck_in_failure as skipcheck,"
+ "cblp.stale_period as staleperiod,cblp.isActive as isActive from"
+ "cblp.stale_period as staleperiod,cblp.is_active as isActive from"
+ " m_creditbureau_loanproduct_mapping cblp, m_organisation_creditbureau orgcb,m_product_loan lp,m_creditbureau cb"
+ " where cblp.organisation_creditbureau_id=orgcb.id and cblp.loan_product_id=lp.id and orgcb.creditbureau_id=cb.id";
}
@@ -45,7 +45,7 @@ public class CreditBureauReadPlatformServiceImpl implements CreditBureauReadPlat
public String schema() {
return "cb.id as creditBureauID,cb.name as creditBureauName,cb.product as creditBureauProduct,"
+ "cb.country as country,concat(cb.product,' - ',cb.name,' - ',cb.country) as cbSummary,cb.implementationKey as implementationKey from m_creditbureau cb";
+ "cb.country as country,concat(cb.product,' - ',cb.name,' - ',cb.country) as cbSummary,cb.implementation_key as implementationKey from m_creditbureau cb";
}
@Override
@@ -46,7 +46,7 @@ public class OrganisationCreditBureauReadPlatformServiceImpl implements Organisa
public String schema() {
return "ocb.id as orgCbId,ocb.alias as orgCbAlias,cb.name as creditbureauName,cb.product as creditbureauProduct,cb.country as creditbureauCountry,"
+ "concat(cb.product,' - ',cb.name,' - ',cb.country) as CreditBureauSummary,"
+ "ocb.creditbureau_id as cbid,ocb.isActive as isActive"
+ "ocb.creditbureau_id as cbid,ocb.is_active as isActive"
+ " from m_organisation_creditbureau ocb,m_creditbureau cb where ocb.creditbureau_id=cb.id";
}
@@ -166,7 +166,8 @@ public final class ResultsetColumnHeaderData implements Serializable {
}
private boolean isDateTime() {
return "datetime".equalsIgnoreCase(this.columnType);
return "datetime".equalsIgnoreCase(this.columnType) || "timestamp without time zone".equalsIgnoreCase(this.columnType)
|| "timestamptz".equalsIgnoreCase(this.columnType) || "timestamp with time zone".equalsIgnoreCase(this.columnType);
}
public boolean isString() {
@@ -174,7 +175,7 @@ public final class ResultsetColumnHeaderData implements Serializable {
}
private boolean isChar() {
return "char".equalsIgnoreCase(this.columnType);
return "char".equalsIgnoreCase(this.columnType) || "CHARACTER VARYING".equalsIgnoreCase(this.columnType);
}
private boolean isVarchar() {
@@ -190,7 +191,7 @@ public final class ResultsetColumnHeaderData implements Serializable {
}
private boolean isInteger() {
return "integer".equalsIgnoreCase(this.columnType);
return "integer".equalsIgnoreCase(this.columnType) || "int4".equalsIgnoreCase(this.columnType);
}
private boolean isSmallInt() {
@@ -206,7 +207,7 @@ public final class ResultsetColumnHeaderData implements Serializable {
}
private boolean isBigInt() {
return "bigint".equalsIgnoreCase(this.columnType);
return "bigint".equalsIgnoreCase(this.columnType) || "int8".equalsIgnoreCase(this.columnType);
}
private boolean isLong() {
@@ -30,6 +30,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.dataqueries.data.DatatableCheckStatusData;
import org.apache.fineract.infrastructure.dataqueries.data.DatatableChecksData;
import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
@@ -52,35 +53,39 @@ import org.springframework.stereotype.Service;
public class EntityDatatableChecksReadPlatformServiceImpl implements EntityDatatableChecksReadService {
private final JdbcTemplate jdbcTemplate;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final RegisterDataTableMapper registerDataTableMapper;
private final EntityDataTableChecksMapper entityDataTableChecksMapper;
private final EntityDatatableChecksRepository entityDatatableChecksRepository;
private final ReadWriteNonCoreDataService readWriteNonCoreDataService;
private final LoanProductReadPlatformService loanProductReadPlatformService;
private final SavingsProductReadPlatformService savingsProductReadPlatformService;
private final PaginationHelper<EntityDataTableChecksData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
@Autowired
public EntityDatatableChecksReadPlatformServiceImpl(final RoutingDataSource dataSource,
final LoanProductReadPlatformService loanProductReadPlatformService,
final SavingsProductReadPlatformService savingsProductReadPlatformService,
final EntityDatatableChecksRepository entityDatatableChecksRepository,
final ReadWriteNonCoreDataService readWriteNonCoreDataService) {
final ReadWriteNonCoreDataService readWriteNonCoreDataService, DatabaseSpecificSQLGenerator sqlGenerator,
PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.sqlGenerator = sqlGenerator;
this.registerDataTableMapper = new RegisterDataTableMapper();
this.entityDataTableChecksMapper = new EntityDataTableChecksMapper();
this.loanProductReadPlatformService = loanProductReadPlatformService;
this.savingsProductReadPlatformService = savingsProductReadPlatformService;
this.entityDatatableChecksRepository = entityDatatableChecksRepository;
this.readWriteNonCoreDataService = readWriteNonCoreDataService;
this.paginationHelper = paginationHelper;
}
@Override
public Page<EntityDataTableChecksData> retrieveAll(SearchParameters searchParameters, final Long status, final String entity,
final Long productId) {
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(this.entityDataTableChecksMapper.schema());
if (status != null || entity != null || productId != null) {
@@ -101,15 +106,16 @@ public class EntityDatatableChecksReadPlatformServiceImpl implements EntityDatat
sqlBuilder.append(" and t.product_id = ? ");
paramList.add(productId);
}
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(jdbcTemplate, sqlCountRows, sqlBuilder.toString(), paramList.toArray(),
entityDataTableChecksMapper);
return this.paginationHelper.fetchPage(jdbcTemplate, sqlBuilder.toString(), paramList.toArray(), entityDataTableChecksMapper);
}
@@ -26,6 +26,9 @@ import java.util.List;
import javax.sql.DataSource;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseIndependentQueryService;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver;
import org.apache.fineract.infrastructure.dataqueries.data.GenericResultsetData;
import org.apache.fineract.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
import org.apache.fineract.infrastructure.dataqueries.data.ResultsetColumnValueData;
@@ -45,11 +48,18 @@ public class GenericDataServiceImpl implements GenericDataService {
private final JdbcTemplate jdbcTemplate;
private final DataSource dataSource;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final DatabaseTypeResolver databaseTypeResolver;
private final DatabaseIndependentQueryService databaseIndependentQueryService;
private static final Logger LOG = LoggerFactory.getLogger(GenericDataServiceImpl.class);
@Autowired
public GenericDataServiceImpl(final RoutingDataSource dataSource) {
public GenericDataServiceImpl(final RoutingDataSource dataSource, DatabaseSpecificSQLGenerator sqlGenerator,
DatabaseTypeResolver databaseTypeResolver, DatabaseIndependentQueryService databaseIndependentQueryService) {
this.dataSource = dataSource;
this.sqlGenerator = sqlGenerator;
this.databaseTypeResolver = databaseTypeResolver;
this.databaseIndependentQueryService = databaseIndependentQueryService;
this.jdbcTemplate = new JdbcTemplate(this.dataSource);
}
@@ -205,14 +215,14 @@ public class GenericDataServiceImpl implements GenericDataService {
columnDefinitions.beforeFirst();
while (columnDefinitions.next()) {
final String columnName = columnDefinitions.getString("COLUMN_NAME");
final String isNullable = columnDefinitions.getString("IS_NULLABLE");
final String isPrimaryKey = columnDefinitions.getString("COLUMN_KEY");
final String columnType = columnDefinitions.getString("DATA_TYPE");
final Long columnLength = columnDefinitions.getLong("CHARACTER_MAXIMUM_LENGTH");
final String columnName = columnDefinitions.getString(1);
final String isNullable = columnDefinitions.getString(2);
final String isPrimaryKey = columnDefinitions.getString(5);
final String columnType = columnDefinitions.getString(3);
final Long columnLength = columnDefinitions.getLong(4);
final boolean columnNullable = "YES".equalsIgnoreCase(isNullable);
final boolean columnIsPrimaryKey = "PRI".equalsIgnoreCase(isPrimaryKey);
final boolean columnNullable = "YES".equalsIgnoreCase(isNullable) || "TRUE".equalsIgnoreCase(isNullable);
final boolean columnIsPrimaryKey = "PRI".equalsIgnoreCase(isPrimaryKey) || "TRUE".equalsIgnoreCase(isPrimaryKey);
List<ResultsetColumnValueData> columnValues = new ArrayList<>();
String codeName = null;
@@ -295,18 +305,13 @@ public class GenericDataServiceImpl implements GenericDataService {
return columnValues;
}
@SuppressWarnings("AvoidHidingCauseException")
private SqlRowSet getDatatableMetaData(final String datatable) {
final String sql = "select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, COLUMN_KEY"
+ " from INFORMATION_SCHEMA.COLUMNS " + " where TABLE_SCHEMA = schema() and TABLE_NAME = '" + datatable
+ "'order by ORDINAL_POSITION";
final SqlRowSet columnDefinitions = this.jdbcTemplate.queryForRowSet(sql);
if (columnDefinitions.next()) {
return columnDefinitions;
try {
return databaseIndependentQueryService.getTableColumns(dataSource, datatable);
} catch (IllegalArgumentException e) {
throw new DatatableNotFoundException(datatable);
}
throw new DatatableNotFoundException(datatable);
}
private SqlRowSet getDatatableCodeData(final String datatable, final String columnName) {
@@ -56,6 +56,8 @@ import org.apache.fineract.infrastructure.core.serialization.DatatableCommandFro
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver;
import org.apache.fineract.infrastructure.dataqueries.api.DataTableApiConstant;
import org.apache.fineract.infrastructure.dataqueries.data.DataTableValidator;
import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
@@ -92,15 +94,22 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
private static final String CODE_VALUES_TABLE = "m_code_value";
private static final Logger LOG = LoggerFactory.getLogger(ReadWriteNonCoreDataServiceImpl.class);
// TODO: Extract these types out of here
private static final ImmutableMap<String, String> apiTypeToMySQL = ImmutableMap.<String, String>builder().put("string", "VARCHAR")
.put("number", "INT").put("boolean", "BIT").put("decimal", "DECIMAL").put("date", "DATE").put("datetime", "DATETIME")
.put("text", "TEXT").put("dropdown", "INT").build();
private static final ImmutableMap<String, String> apiTypeToPostgreSQL = ImmutableMap.<String, String>builder().put("string", "VARCHAR")
.put("number", "INT").put("boolean", "BIT").put("decimal", "DECIMAL").put("date", "DATE").put("datetime", "TIMESTAMP")
.put("text", "TEXT").put("dropdown", "INT").build();
private static final List<String> stringDataTypes = Arrays.asList("char", "varchar", "blob", "text", "tinyblob", "tinytext",
"mediumblob", "mediumtext", "longblob", "longtext");
private final JdbcTemplate jdbcTemplate;
private final DataSource dataSource;
private final DatabaseTypeResolver databaseTypeResolver;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final PlatformSecurityContext context;
private final FromJsonHelper fromJsonHelper;
private final JsonParserHelper helper;
@@ -120,8 +129,10 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
final FromJsonHelper fromJsonHelper, final GenericDataService genericDataService,
final DatatableCommandFromApiJsonDeserializer fromApiJsonDeserializer, final CodeReadPlatformService codeReadPlatformService,
final ConfigurationDomainService configurationDomainService, final DataTableValidator dataTableValidator,
final ColumnValidator columnValidator) {
final ColumnValidator columnValidator, DatabaseTypeResolver databaseTypeResolver, DatabaseSpecificSQLGenerator sqlGenerator) {
this.dataSource = dataSource;
this.databaseTypeResolver = databaseTypeResolver;
this.sqlGenerator = sqlGenerator;
this.jdbcTemplate = new JdbcTemplate(this.dataSource);
this.context = context;
this.fromJsonHelper = fromJsonHelper;
@@ -487,8 +498,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
}
private void assertDataTableExists(final String datatableName) {
final String sql = "select (CASE WHEN exists (select 1 from information_schema.tables where table_schema = schema()"
+ " and table_name = ?) THEN 'true' ELSE 'false' END)";
final String sql = "select (CASE WHEN exists (select 1 from information_schema.tables where table_schema = "
+ sqlGenerator.currentSchema() + " and table_name = ?) THEN 'true' ELSE 'false' END)";
final String dataTableExistsString = this.jdbcTemplate.queryForObject(sql, String.class, new Object[] { datatableName });
final boolean dataTableExists = Boolean.valueOf(dataTableExistsString);
if (!dataTableExists) {
@@ -532,15 +543,24 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (StringUtils.isNotBlank(code)) {
if (isConstraintApproach) {
codeMappings.put(dataTableNameAlias + "_" + name, this.codeReadPlatformService.retriveCode(code).getCodeId());
constrainBuilder.append(", CONSTRAINT `fk_").append(dataTableNameAlias).append("_").append(name).append("` ")
.append("FOREIGN KEY (`" + name + "`) ").append("REFERENCES `").append(CODE_VALUES_TABLE).append("` (`id`)");
String fkName = "fk_" + dataTableNameAlias + "_" + name;
constrainBuilder.append(", CONSTRAINT ").append(sqlGenerator.escape(fkName)).append(" ")
.append("FOREIGN KEY (" + sqlGenerator.escape(name) + ") ").append("REFERENCES ")
.append(sqlGenerator.escape(CODE_VALUES_TABLE)).append(" (id)");
} else {
name = datatableColumnNameToCodeValueName(name, code);
}
}
final String mysqlType = apiTypeToMySQL.get(type);
sqlBuilder = sqlBuilder.append("`" + name + "` " + mysqlType);
final String dataType;
if (databaseTypeResolver.isMySQL()) {
dataType = apiTypeToMySQL.get(type);
} else if (databaseTypeResolver.isPostgreSQL()) {
dataType = apiTypeToPostgreSQL.get(type);
} else {
throw new IllegalStateException("Current database is not supported");
}
sqlBuilder = sqlBuilder.append(sqlGenerator.escape(name) + " " + dataType);
if (type != null) {
if (type.equalsIgnoreCase("String")) {
@@ -599,12 +619,13 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
StringBuilder sqlBuilder = new StringBuilder();
final StringBuilder constrainBuilder = new StringBuilder();
final Map<String, Long> codeMappings = new HashMap<>();
sqlBuilder = sqlBuilder.append("CREATE TABLE `" + datatableName + "` (");
sqlBuilder = sqlBuilder.append("CREATE TABLE " + sqlGenerator.escape(datatableName) + " (");
if (multiRow) {
sqlBuilder = sqlBuilder.append("`id` BIGINT NOT NULL AUTO_INCREMENT, ").append("`" + fkColumnName + "` BIGINT NOT NULL, ");
sqlBuilder = sqlBuilder.append("id BIGINT NOT NULL AUTO_INCREMENT, ")
.append(sqlGenerator.escape(fkColumnName) + " BIGINT NOT NULL, ");
} else {
sqlBuilder = sqlBuilder.append("`" + fkColumnName + "` BIGINT NOT NULL, ");
sqlBuilder = sqlBuilder.append(sqlGenerator.escape(fkColumnName) + " BIGINT NOT NULL, ");
}
for (final JsonElement column : columns) {
@@ -615,19 +636,26 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
// Remove trailing comma and space
sqlBuilder = sqlBuilder.delete(sqlBuilder.length() - 2, sqlBuilder.length());
String fullFkName = "fk_" + fkName;
if (multiRow) {
sqlBuilder = sqlBuilder.append(", PRIMARY KEY (`id`)")
.append(", KEY `fk_" + apptableName.substring(2) + "_id` (`" + fkColumnName + "`)")
.append(", CONSTRAINT `fk_" + fkName + "` ").append("FOREIGN KEY (`" + fkColumnName + "`) ")
.append("REFERENCES `" + actualAppTableName + "` (`id`)");
sqlBuilder = sqlBuilder.append(", PRIMARY KEY (id)")
.append(", KEY " + sqlGenerator.escape("fk_" + apptableName.substring(2) + "_id") + " ("
+ sqlGenerator.escape(fkColumnName) + ")")
.append(", CONSTRAINT " + sqlGenerator.escape(fullFkName) + " ")
.append("FOREIGN KEY (" + sqlGenerator.escape(fkColumnName) + ") ")
.append("REFERENCES " + sqlGenerator.escape(actualAppTableName) + " (id)");
} else {
sqlBuilder = sqlBuilder.append(", PRIMARY KEY (`" + fkColumnName + "`)").append(", CONSTRAINT `fk_" + fkName + "` ")
.append("FOREIGN KEY (`" + fkColumnName + "`) ").append("REFERENCES `" + actualAppTableName + "` (`id`)");
sqlBuilder = sqlBuilder.append(", PRIMARY KEY (" + sqlGenerator.escape(fkColumnName) + ")")
.append(", CONSTRAINT " + sqlGenerator.escape(fullFkName) + " ")
.append("FOREIGN KEY (" + sqlGenerator.escape(fkColumnName) + ") ")
.append("REFERENCES " + sqlGenerator.escape(actualAppTableName) + " (id)");
}
sqlBuilder.append(constrainBuilder);
sqlBuilder = sqlBuilder.append(") ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;");
sqlBuilder.append(")");
if (databaseTypeResolver.isMySQL()) {
sqlBuilder.append(" ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;");
}
this.jdbcTemplate.execute(sqlBuilder.toString());
registerDatatable(datatableName, apptableName, entitySubType);
@@ -686,32 +714,33 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (StringUtils.isBlank(newName)) {
newName = name;
}
String fkName = "fk_" + dataTableNameAlias + "_" + name;
String newFkName = "fk_" + dataTableNameAlias + "_" + newName;
if (!StringUtils.equalsIgnoreCase(code, newCode) || !StringUtils.equalsIgnoreCase(name, newName)) {
if (StringUtils.equalsIgnoreCase(code, newCode)) {
final int codeId = getCodeIdForColumn(dataTableNameAlias, name);
if (codeId > 0) {
removeMappings.add(dataTableNameAlias + "_" + name);
constrainBuilder.append(", DROP FOREIGN KEY `fk_").append(dataTableNameAlias).append("_").append(name).append("` ");
constrainBuilder.append(", DROP FOREIGN KEY ").append(sqlGenerator.escape(fkName)).append(" ");
codeMappings.put(dataTableNameAlias + "_" + newName, (long) codeId);
constrainBuilder.append(",ADD CONSTRAINT `fk_").append(dataTableNameAlias).append("_").append(newName).append("` ")
.append("FOREIGN KEY (`" + newName + "`) ").append("REFERENCES `").append(CODE_VALUES_TABLE)
.append("` (`id`)");
constrainBuilder.append(",ADD CONSTRAINT ").append(sqlGenerator.escape(newFkName)).append(" ")
.append("FOREIGN KEY (" + sqlGenerator.escape(newName) + ") ").append("REFERENCES ")
.append(sqlGenerator.escape(CODE_VALUES_TABLE)).append(" (id)");
}
} else {
if (code != null) {
removeMappings.add(dataTableNameAlias + "_" + name);
if (newCode == null || !StringUtils.equalsIgnoreCase(name, newName)) {
constrainBuilder.append(", DROP FOREIGN KEY `fk_").append(dataTableNameAlias).append("_").append(name)
.append("` ");
constrainBuilder.append(", DROP FOREIGN KEY ").append(sqlGenerator.escape(fkName)).append(" ");
}
}
if (newCode != null) {
codeMappings.put(dataTableNameAlias + "_" + newName, this.codeReadPlatformService.retriveCode(newCode).getCodeId());
if (code == null || !StringUtils.equalsIgnoreCase(name, newName)) {
constrainBuilder.append(",ADD CONSTRAINT `fk_").append(dataTableNameAlias).append("_").append(newName)
.append("` ").append("FOREIGN KEY (`" + newName + "`) ").append("REFERENCES `")
.append(CODE_VALUES_TABLE).append("` (`id`)");
constrainBuilder.append(",ADD CONSTRAINT ").append(sqlGenerator.escape(newFkName)).append(" ")
.append("FOREIGN KEY (" + sqlGenerator.escape(newName) + ") ").append("REFERENCES ")
.append(sqlGenerator.escape(CODE_VALUES_TABLE)).append(" (id)");
}
}
}
@@ -735,7 +764,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
length = mapColumnNameDefinition.get(name).getColumnLength().intValue();
}
sqlBuilder = sqlBuilder.append(", CHANGE `" + name + "` `" + newName + "` " + type);
sqlBuilder = sqlBuilder.append(", CHANGE " + sqlGenerator.escape(name) + " " + sqlGenerator.escape(newName) + " " + type);
if (length != null && length > 0) {
if (type.toLowerCase().equals("decimal")) {
sqlBuilder.append("(19,6)");
@@ -751,7 +780,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
}
if (after != null) {
sqlBuilder = sqlBuilder.append(" AFTER `" + after + "`");
sqlBuilder = sqlBuilder.append(" AFTER " + sqlGenerator.escape(after));
}
}
@@ -781,16 +810,25 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (StringUtils.isNotBlank(code)) {
if (isConstraintApproach) {
String fkName = "fk_" + dataTableNameAlias + "_" + name;
codeMappings.put(dataTableNameAlias + "_" + name, this.codeReadPlatformService.retriveCode(code).getCodeId());
constrainBuilder.append(",ADD CONSTRAINT `fk_").append(dataTableNameAlias).append("_").append(name).append("` ")
.append("FOREIGN KEY (`" + name + "`) ").append("REFERENCES `").append(CODE_VALUES_TABLE).append("` (`id`)");
constrainBuilder.append(",ADD CONSTRAINT ").append(sqlGenerator.escape(fkName)).append(" ")
.append("FOREIGN KEY (" + sqlGenerator.escape(name) + ") ").append("REFERENCES ")
.append(sqlGenerator.escape(CODE_VALUES_TABLE)).append(" (id)");
} else {
name = datatableColumnNameToCodeValueName(name, code);
}
}
final String mysqlType = apiTypeToMySQL.get(type);
sqlBuilder = sqlBuilder.append(", ADD `" + name + "` " + mysqlType);
final String dataType;
if (databaseTypeResolver.isMySQL()) {
dataType = apiTypeToMySQL.get(type);
} else if (databaseTypeResolver.isPostgreSQL()) {
dataType = apiTypeToPostgreSQL.get(type);
} else {
throw new IllegalStateException("Current database is not supported");
}
sqlBuilder = sqlBuilder.append(", ADD " + sqlGenerator.escape(name) + " " + dataType);
if (type != null) {
if (type.equalsIgnoreCase("String") && length != null) {
@@ -809,7 +847,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
}
if (after != null) {
sqlBuilder = sqlBuilder.append(" AFTER `" + after + "`");
sqlBuilder = sqlBuilder.append(" AFTER " + sqlGenerator.escape(after));
}
}
@@ -817,7 +855,6 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
final StringBuilder constrainBuilder, final List<String> codeMappings) {
final String datatableAlias = datatableName.toLowerCase().replaceAll("\\s", "_");
final String name = column.has("name") ? column.get("name").getAsString() : null;
// sqlBuilder = sqlBuilder.append(", DROP COLUMN `" + name + "`");
final StringBuilder findFKSql = new StringBuilder();
findFKSql.append("SELECT count(*)").append("FROM information_schema.TABLE_CONSTRAINTS i")
.append(" WHERE i.CONSTRAINT_TYPE = 'FOREIGN KEY'").append(" AND i.TABLE_SCHEMA = DATABASE()")
@@ -825,8 +862,9 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
.append("_").append(name).append("' ");
final int count = this.jdbcTemplate.queryForObject(findFKSql.toString(), Integer.class);
if (count > 0) {
String fkName = "fk_" + datatableAlias + "_" + name;
codeMappings.add(datatableAlias + "_" + name);
constrainBuilder.append(", DROP FOREIGN KEY `fk_").append(datatableAlias).append("_").append(name).append("` ");
constrainBuilder.append(", DROP FOREIGN KEY ").append(sqlGenerator.escape(fkName)).append(" ");
}
}
@@ -875,7 +913,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (StringUtils.isNotEmpty(type)) {
if (mandatory && stringDataTypes.contains(type.toLowerCase())) {
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("UPDATE `" + datatableName + "` SET `" + name + "` = '' WHERE `" + name + "` IS NULL");
sqlBuilder.append("UPDATE " + sqlGenerator.escape(datatableName) + " SET " + sqlGenerator.escape(name) + " = '' WHERE "
+ sqlGenerator.escape(name) + " IS NULL");
this.jdbcTemplate.update(sqlBuilder.toString());
}
@@ -908,7 +947,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
final boolean isConstraintApproach = this.configurationDomainService.isConstraintApproachEnabledForDatatables();
if (!StringUtils.isBlank(entitySubType)) {
String updateLegalFormSQL = "update `x_registered_table` SET `entity_subtype`='" + entitySubType
String updateLegalFormSQL = "update x_registered_table SET entity_subtype='" + entitySubType
+ "' WHERE registered_table_name = '" + datatableName + "'";
this.jdbcTemplate.execute(updateLegalFormSQL);
}
@@ -925,19 +964,28 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
final String newConstraintName = datatableName.toLowerCase().replaceAll("\\s", "_") + "_" + newFKName;
StringBuilder sqlBuilder = new StringBuilder();
String fullOldFk = "fk_" + oldFKName;
String fullOldConstraint = "fk_" + oldConstraintName;
String fullNewFk = "fk_" + newFKName;
String fullNewConstraint = "fk_" + newConstraintName;
if (mapColumnNameDefinition.containsKey("id")) {
sqlBuilder = sqlBuilder.append("ALTER TABLE `" + datatableName + "` ").append("DROP KEY `fk_" + oldFKName + "`,")
.append("DROP FOREIGN KEY `fk_" + oldConstraintName + "`,")
.append("CHANGE COLUMN `" + oldFKName + "` `" + newFKName + "` BIGINT NOT NULL,")
.append("ADD KEY `fk_" + newFKName + "` (`" + newFKName + "`),")
.append("ADD CONSTRAINT `fk_" + newConstraintName + "` ").append("FOREIGN KEY (`" + newFKName + "`) ")
.append("REFERENCES `" + actualAppTableName + "` (`id`)");
sqlBuilder = sqlBuilder.append("ALTER TABLE " + sqlGenerator.escape(datatableName) + " ")
.append("DROP KEY " + sqlGenerator.escape(fullOldFk) + ",")
.append("DROP FOREIGN KEY " + sqlGenerator.escape(fullOldConstraint) + ",")
.append("CHANGE COLUMN " + sqlGenerator.escape(oldFKName) + " " + sqlGenerator.escape(newFKName)
+ " BIGINT NOT NULL,")
.append("ADD KEY " + sqlGenerator.escape(fullNewFk) + " (" + sqlGenerator.escape(newFKName) + "),")
.append("ADD CONSTRAINT " + sqlGenerator.escape(fullNewConstraint) + " ")
.append("FOREIGN KEY (" + sqlGenerator.escape(newFKName) + ") ")
.append("REFERENCES " + sqlGenerator.escape(actualAppTableName) + " (id)");
} else {
sqlBuilder = sqlBuilder.append("ALTER TABLE `" + datatableName + "` ")
.append("DROP FOREIGN KEY `fk_" + oldConstraintName + "`,")
.append("CHANGE COLUMN `" + oldFKName + "` `" + newFKName + "` BIGINT NOT NULL,")
.append("ADD CONSTRAINT `fk_" + newConstraintName + "` ").append("FOREIGN KEY (`" + newFKName + "`) ")
.append("REFERENCES `" + actualAppTableName + "` (`id`)");
sqlBuilder = sqlBuilder.append("ALTER TABLE " + sqlGenerator.escape(datatableName) + " ")
.append("DROP FOREIGN KEY " + sqlGenerator.escape(fullOldConstraint) + ",")
.append("CHANGE COLUMN " + sqlGenerator.escape(oldFKName) + " " + sqlGenerator.escape(newFKName)
+ " BIGINT NOT NULL,")
.append("ADD CONSTRAINT " + sqlGenerator.escape(fullNewConstraint) + " ")
.append("FOREIGN KEY (" + sqlGenerator.escape(newFKName) + ") ")
.append("REFERENCES " + sqlGenerator.escape(actualAppTableName) + " (id)");
}
this.jdbcTemplate.execute(sqlBuilder.toString());
@@ -956,14 +1004,14 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
throw new GeneralPlatformDomainRuleException("error.msg.non.empty.datatable.column.cannot.be.deleted",
"Non-empty datatable columns can not be deleted.");
}
StringBuilder sqlBuilder = new StringBuilder("ALTER TABLE `" + datatableName + "`");
StringBuilder sqlBuilder = new StringBuilder("ALTER TABLE " + sqlGenerator.escape(datatableName));
final StringBuilder constrainBuilder = new StringBuilder();
final List<String> codeMappings = new ArrayList<>();
for (final JsonElement column : dropColumns) {
parseDatatableColumnForDrop(column.getAsJsonObject(), sqlBuilder, datatableName, constrainBuilder, codeMappings);
}
// Remove the first comma, right after ALTER TABLE `datatable`
// Remove the first comma, right after ALTER TABLE datatable
final int indexOfFirstComma = sqlBuilder.indexOf(",");
if (indexOfFirstComma != -1) {
sqlBuilder = sqlBuilder.deleteCharAt(indexOfFirstComma);
@@ -974,7 +1022,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
}
if (addColumns != null) {
StringBuilder sqlBuilder = new StringBuilder("ALTER TABLE `" + datatableName + "`");
StringBuilder sqlBuilder = new StringBuilder("ALTER TABLE " + sqlGenerator.escape(datatableName));
final StringBuilder constrainBuilder = new StringBuilder();
final Map<String, Long> codeMappings = new HashMap<>();
for (final JsonElement column : addColumns) {
@@ -987,7 +1035,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
constrainBuilder, codeMappings, isConstraintApproach);
}
// Remove the first comma, right after ALTER TABLE `datatable`
// Remove the first comma, right after ALTER TABLE datatable
final int indexOfFirstComma = sqlBuilder.indexOf(",");
if (indexOfFirstComma != -1) {
sqlBuilder = sqlBuilder.deleteCharAt(indexOfFirstComma);
@@ -998,7 +1046,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
}
if (changeColumns != null) {
StringBuilder sqlBuilder = new StringBuilder("ALTER TABLE `" + datatableName + "`");
StringBuilder sqlBuilder = new StringBuilder("ALTER TABLE " + sqlGenerator.escape(datatableName));
final StringBuilder constrainBuilder = new StringBuilder();
final Map<String, Long> codeMappings = new HashMap<>();
final List<String> removeMappings = new ArrayList<>();
@@ -1010,7 +1058,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
constrainBuilder, codeMappings, removeMappings, isConstraintApproach);
}
// Remove the first comma, right after ALTER TABLE `datatable`
// Remove the first comma, right after ALTER TABLE datatable
final int indexOfFirstComma = sqlBuilder.indexOf(",");
if (indexOfFirstComma != -1) {
sqlBuilder = sqlBuilder.deleteCharAt(indexOfFirstComma);
@@ -1090,7 +1138,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
} else {
sqlArray = new String[1];
}
final String sql = "DROP TABLE `" + datatableName + "`";
final String sql = "DROP TABLE " + sqlGenerator.escape(datatableName);
sqlArray[0] = sql;
this.jdbcTemplate.batchUpdate(sqlArray);
} catch (final JpaSystemException | DataIntegrityViolationException e) {
@@ -1114,7 +1162,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
}
private int getRowCount(final String datatableName) {
final String sql = "select count(*) from `" + datatableName + "`";
final String sql = "select count(*) from " + sqlGenerator.escape(datatableName);
return this.jdbcTemplate.queryForObject(sql, Integer.class);
}
@@ -1240,9 +1288,9 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (id == null) {
String whereClause = getFKField(appTable) + " = " + appTableId;
SQLInjectionValidator.validateSQLInput(whereClause);
sql = sql + "select * from `" + dataTableName + "` where " + whereClause;
sql = sql + "select * from " + sqlGenerator.escape(dataTableName) + " where " + whereClause;
} else {
sql = sql + "select * from `" + dataTableName + "` where id = " + id;
sql = sql + "select * from " + sqlGenerator.escape(dataTableName) + " where id = " + id;
}
if (StringUtils.isNotBlank(order)) {
@@ -1267,9 +1315,9 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (id == null) {
String whereClause = getFKField(appTable) + " = " + appTableId;
SQLInjectionValidator.validateSQLInput(whereClause);
sql = sql + "select * from `" + dataTableName + "` where " + whereClause;
sql = sql + "select * from " + sqlGenerator.escape(dataTableName) + " where " + whereClause;
} else {
sql = sql + "select * from `" + dataTableName + "` where id = " + id;
sql = sql + "select * from " + sqlGenerator.escape(dataTableName) + " where id = " + id;
}
final List<ResultsetRowData> result = fillDatatableResultSetDataRows(sql);
@@ -1328,22 +1376,22 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
* means it relates to an m_client that is in a group (still an m_client account)
*/
if (appTable.equalsIgnoreCase("m_loan")) {
scopedSQL = "select distinctrow x.* from ("
scopedSQL = "select distinct x.* from ("
+ " (select o.id as officeId, l.group_id as groupId, l.client_id as clientId, null as savingsId, l.id as loanId, null as entityId from m_loan l "
+ " join m_client c on c.id = l.client_id " + " join m_office o on o.id = c.office_id and o.hierarchy like '"
+ currentUser.getOffice().getHierarchy() + "%'" + " where l.id = " + appTableId + ")" + " union all "
+ " (select o.id as officeId, l.group_id as groupId, l.client_id as clientId, null as savingsId, l.id as loanId, null as entityId from m_loan l "
+ " join m_group g on g.id = l.group_id " + " join m_office o on o.id = g.office_id and o.hierarchy like '"
+ currentUser.getOffice().getHierarchy() + "%'" + " where l.id = " + appTableId + ")" + " ) x";
+ currentUser.getOffice().getHierarchy() + "%'" + " where l.id = " + appTableId + ")" + " ) as x";
}
if (appTable.equalsIgnoreCase("m_savings_account")) {
scopedSQL = "select distinctrow x.* from ("
scopedSQL = "select distinct x.* from ("
+ " (select o.id as officeId, s.group_id as groupId, s.client_id as clientId, s.id as savingsId, null as loanId, null as entityId from m_savings_account s "
+ " join m_client c on c.id = s.client_id " + " join m_office o on o.id = c.office_id and o.hierarchy like '"
+ currentUser.getOffice().getHierarchy() + "%'" + " where s.id = " + appTableId + ")" + " union all "
+ " (select o.id as officeId, s.group_id as groupId, s.client_id as clientId, s.id as savingsId, null as loanId, null as entityId from m_savings_account s "
+ " join m_group g on g.id = s.group_id " + " join m_office o on o.id = g.office_id and o.hierarchy like '"
+ currentUser.getOffice().getHierarchy() + "%'" + " where s.id = " + appTableId + ")" + " ) x";
+ currentUser.getOffice().getHierarchy() + "%'" + " where s.id = " + appTableId + ")" + " ) as x";
}
if (appTable.equalsIgnoreCase("m_client")) {
scopedSQL = "select o.id as officeId, null as groupId, c.id as clientId, null as savingsId, null as loanId, null as entityId from m_client c "
@@ -1484,14 +1532,14 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
}
}
columnName = "`" + key + "`";
columnName = sqlGenerator.escape(key);
insertColumns += ", " + columnName;
selectColumns += "," + pValueWrite + " as " + columnName;
}
}
addSql = "insert into `" + datatable + "` (`" + fkName + "` " + insertColumns + ")" + " select " + appTableId + " as id"
+ selectColumns;
addSql = "insert into " + sqlGenerator.escape(datatable) + " (" + sqlGenerator.escape(fkName) + " " + insertColumns + ")"
+ " select " + appTableId + " as id" + selectColumns;
LOG.info("{}", addSql);
@@ -1532,16 +1580,16 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
scoresId += pValueWrite + " ,";
}
columnName = "`" + key + "`";
columnName = sqlGenerator.escape(key);
insertColumns += ", " + columnName;
selectColumns += "," + pValueWrite + " as " + columnName;
}
scoresId = scoresId.replaceAll(" ,$", "");
String vaddSql = "insert into `" + datatable + "` (`" + fkName + "` " + insertColumns + ", `score` )" + " select " + appTableId
+ " as id" + selectColumns + " , ( SELECT SUM( code_score ) FROM m_code_value WHERE m_code_value.id IN (" + scoresId
+ " ) ) as score";
String vaddSql = "insert into " + sqlGenerator.escape(datatable) + " (" + sqlGenerator.escape(fkName) + " " + insertColumns
+ ", score )" + " select " + appTableId + " as id" + selectColumns
+ " , ( SELECT SUM( code_score ) FROM m_code_value WHERE m_code_value.id IN (" + scoresId + " ) ) as score";
LOG.info("{}", vaddSql);
@@ -1566,7 +1614,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
String pValueWrite = "";
final String singleQuote = "'";
boolean firstColumn = true;
String sql = "update `" + datatable + "` ";
String sql = "update " + sqlGenerator.escape(datatable) + " ";
for (final ResultsetColumnHeaderData pColumnHeader : columnHeaders) {
final String key = pColumnHeader.getColumnName();
if (changedColumns.containsKey(key)) {
@@ -1588,7 +1636,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
+ singleQuote;
}
}
sql += "`" + key + "` = " + pValueWrite;
sql += sqlGenerator.escape(key) + " = " + pValueWrite;
}
}
@@ -1783,7 +1831,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
}
paramValue = tmpBoolean.toString();
} else if (columnHeader.isString()) {
if (paramValue.length() > columnHeader.getColumnLength()) {
if (columnHeader.getColumnLength() > 0 && paramValue.length() > columnHeader.getColumnLength()) {
final ApiParameterError error = ApiParameterError.parameterError(
"validation.msg.datatable.entry.column.exceeds.maxlength",
"The column `" + columnHeader.getColumnName() + "` exceeds its defined max-length ",
@@ -1801,13 +1849,13 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
private String getDeleteEntriesSql(final String datatable, final String FKField, final Long appTableId) {
return "delete from `" + datatable + "` where `" + FKField + "` = " + appTableId;
return "delete from " + sqlGenerator.escape(datatable) + " where " + sqlGenerator.escape(FKField) + " = " + appTableId;
}
private String getDeleteEntrySql(final String datatable, final Long datatableId) {
return "delete from `" + datatable + "` where `id` = " + datatableId;
return "delete from " + sqlGenerator.escape(datatable) + " where id = " + datatableId;
}
@@ -1841,17 +1889,17 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
@Override
public Long countDatatableEntries(final String datatableName, final Long appTableId, String foreignKeyColumn) {
final String sqlString = "SELECT COUNT(`" + foreignKeyColumn + "`) FROM `" + datatableName + "` WHERE `" + foreignKeyColumn + "`="
+ appTableId;
final String sqlString = "SELECT COUNT(" + sqlGenerator.escape(foreignKeyColumn) + ") FROM " + sqlGenerator.escape(datatableName)
+ " WHERE " + sqlGenerator.escape(foreignKeyColumn) + "=" + appTableId;
final Long count = this.jdbcTemplate.queryForObject(sqlString, Long.class);
return count;
}
public boolean isDatatableAttachedToEntityDatatableCheck(final String datatableName) {
StringBuilder builder = new StringBuilder();
builder.append(" SELECT COUNT(edc.`x_registered_table_name`) FROM `x_registered_table` xrt ");
builder.append(" JOIN m_entity_datatable_check edc ON edc.`x_registered_table_name` = xrt.`registered_table_name`");
builder.append(" WHERE edc.`x_registered_table_name` = '" + datatableName + "'");
builder.append(" SELECT COUNT(edc.x_registered_table_name) FROM x_registered_table xrt ");
builder.append(" JOIN m_entity_datatable_check edc ON edc.x_registered_table_name = xrt.registered_table_name");
builder.append(" WHERE edc.x_registered_table_name = '" + datatableName + "'");
final Long count = this.jdbcTemplate.queryForObject(builder.toString(), Long.class);
return count > 0 ? true : false;
}
@@ -26,6 +26,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.jobs.data.JobDetailData;
import org.apache.fineract.infrastructure.jobs.data.JobDetailHistoryData;
import org.apache.fineract.infrastructure.jobs.exception.JobNotFoundException;
@@ -36,24 +37,30 @@ import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional(readOnly = true)
public class SchedulerJobRunnerReadServiceImpl implements SchedulerJobRunnerReadService {
private final JdbcTemplate jdbcTemplate;
private final ColumnValidator columnValidator;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final PaginationHelper<JobDetailHistoryData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
@Autowired
public SchedulerJobRunnerReadServiceImpl(final RoutingDataSource dataSource, final ColumnValidator columnValidator) {
public SchedulerJobRunnerReadServiceImpl(final RoutingDataSource dataSource, final ColumnValidator columnValidator,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.columnValidator = columnValidator;
this.sqlGenerator = sqlGenerator;
this.paginationHelper = paginationHelper;
}
@Override
public List<JobDetailData> findAllJobDeatils() {
final JobDetailMapper detailMapper = new JobDetailMapper();
final JobDetailMapper detailMapper = new JobDetailMapper(sqlGenerator);
final String sql = detailMapper.schema();
final List<JobDetailData> JobDeatils = this.jdbcTemplate.query(sql, detailMapper, new Object[] {});
return JobDeatils;
@@ -63,7 +70,7 @@ public class SchedulerJobRunnerReadServiceImpl implements SchedulerJobRunnerRead
@Override
public JobDetailData retrieveOne(final Long jobId) {
try {
final JobDetailMapper detailMapper = new JobDetailMapper();
final JobDetailMapper detailMapper = new JobDetailMapper(sqlGenerator);
final String sql = detailMapper.schema() + " where job.id=?";
return this.jdbcTemplate.queryForObject(sql, detailMapper, new Object[] { jobId });
} catch (final EmptyResultDataAccessException e) {
@@ -76,9 +83,9 @@ public class SchedulerJobRunnerReadServiceImpl implements SchedulerJobRunnerRead
if (!isJobExist(jobId)) {
throw new JobNotFoundException(String.valueOf(jobId));
}
final JobHistoryMapper jobHistoryMapper = new JobHistoryMapper();
final JobHistoryMapper jobHistoryMapper = new JobHistoryMapper(sqlGenerator);
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(jobHistoryMapper.schema());
sqlBuilder.append(" where job.id=?");
if (searchParameters.isOrderByRequested()) {
@@ -91,15 +98,15 @@ public class SchedulerJobRunnerReadServiceImpl implements SchedulerJobRunnerRead
}
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), new Object[] { jobId },
jobHistoryMapper);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), new Object[] { jobId }, jobHistoryMapper);
}
@Override
@@ -131,10 +138,16 @@ public class SchedulerJobRunnerReadServiceImpl implements SchedulerJobRunnerRead
private static final class JobDetailMapper implements RowMapper<JobDetailData> {
private final StringBuilder sqlBuilder = new StringBuilder("select").append(
" job.id,job.display_name as displayName,job.next_run_time as nextRunTime,job.initializing_errorlog as initializingError,job.cron_expression as cronExpression,job.is_active as active,job.currently_running as currentlyRunning,")
.append(" runHistory.version,runHistory.start_time as lastRunStartTime,runHistory.end_time as lastRunEndTime,runHistory.`status`,runHistory.error_message as jobRunErrorMessage,runHistory.trigger_type as triggerType,runHistory.error_log as jobRunErrorLog ")
.append(" from job job left join job_run_history runHistory ON job.id=runHistory.job_id and job.previous_run_start_time=runHistory.start_time ");
private final StringBuilder sqlBuilder;
JobDetailMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
sqlBuilder = new StringBuilder("select").append(
" job.id,job.display_name as displayName,job.next_run_time as nextRunTime,job.initializing_errorlog as initializingError,job.cron_expression as cronExpression,job.is_active as active,job.currently_running as currentlyRunning,")
.append(" runHistory.version,runHistory.start_time as lastRunStartTime,runHistory.end_time as lastRunEndTime,runHistory."
+ sqlGenerator.escape("status")
+ ",runHistory.error_message as jobRunErrorMessage,runHistory.trigger_type as triggerType,runHistory.error_log as jobRunErrorLog ")
.append(" from job job left join job_run_history runHistory ON job.id=runHistory.job_id and job.previous_run_start_time=runHistory.start_time ");
}
public String schema() {
return this.sqlBuilder.toString();
@@ -172,9 +185,15 @@ public class SchedulerJobRunnerReadServiceImpl implements SchedulerJobRunnerRead
private static final class JobHistoryMapper implements RowMapper<JobDetailHistoryData> {
private final StringBuilder sqlBuilder = new StringBuilder(200).append(
" runHistory.version,runHistory.start_time as runStartTime,runHistory.end_time as runEndTime,runHistory.`status`,runHistory.error_message as jobRunErrorMessage,runHistory.trigger_type as triggerType,runHistory.error_log as jobRunErrorLog ")
.append(" from job job join job_run_history runHistory ON job.id=runHistory.job_id");
private final StringBuilder sqlBuilder;
JobHistoryMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
sqlBuilder = new StringBuilder(200)
.append(" runHistory.version,runHistory.start_time as runStartTime,runHistory.end_time as runEndTime,runHistory."
+ sqlGenerator.escape("status")
+ ",runHistory.error_message as jobRunErrorMessage,runHistory.trigger_type as triggerType,runHistory.error_log as jobRunErrorLog ")
.append(" from job job join job_run_history runHistory ON job.id=runHistory.job_id");
}
public String schema() {
return this.sqlBuilder.toString();
@@ -0,0 +1,42 @@
/**
* 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.openjpa;
import javax.persistence.EntityManager;
import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport;
import org.springframework.orm.jpa.EntityManagerHolder;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
import org.springframework.transaction.support.TransactionSynchronizationManager;
public class OpenJpaTransactionManager extends JpaTransactionManager {
@Override
protected void doCommit(DefaultTransactionStatus status) {
JdbcTransactionObjectSupport txObject = (JdbcTransactionObjectSupport) status.getTransaction();
if (txObject.isReadOnly()) {
EntityManagerHolder holder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(obtainEntityManagerFactory());
if (holder != null) {
EntityManager entityManager = holder.getEntityManager();
entityManager.clear();
}
}
super.doCommit(status);
}
}
@@ -31,6 +31,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.dataqueries.data.ReportData;
import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobData;
import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobEmailAttachmentFileFormat;
@@ -49,11 +50,16 @@ public class ReportMailingJobReadPlatformServiceImpl implements ReportMailingJob
private final JdbcTemplate jdbcTemplate;
private final ColumnValidator columnValidator;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final PaginationHelper paginationHelper;
@Autowired
public ReportMailingJobReadPlatformServiceImpl(final RoutingDataSource dataSource, final ColumnValidator columnValidator) {
public ReportMailingJobReadPlatformServiceImpl(final RoutingDataSource dataSource, final ColumnValidator columnValidator,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.columnValidator = columnValidator;
this.sqlGenerator = sqlGenerator;
this.paginationHelper = paginationHelper;
}
@Override
@@ -61,9 +67,8 @@ public class ReportMailingJobReadPlatformServiceImpl implements ReportMailingJob
final StringBuilder sqlStringBuilder = new StringBuilder(200);
final List<Object> queryParameters = new ArrayList<>();
final ReportMailingJobMapper mapper = new ReportMailingJobMapper();
final PaginationHelper<ReportMailingJobData> paginationHelper = new PaginationHelper<>();
sqlStringBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlStringBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlStringBuilder.append(mapper.reportMailingJobSchema());
sqlStringBuilder.append(" where rmj.is_deleted = false");
@@ -79,15 +84,15 @@ public class ReportMailingJobReadPlatformServiceImpl implements ReportMailingJob
}
if (searchParameters.isLimited()) {
sqlStringBuilder.append(" limit ").append(searchParameters.getLimit());
sqlStringBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlStringBuilder.append(" offset ").append(searchParameters.getOffset());
sqlStringBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlStringBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
return paginationHelper.fetchPage(this.jdbcTemplate, "SELECT FOUND_ROWS()", sqlStringBuilder.toString(), queryParameters.toArray(),
mapper);
return paginationHelper.fetchPage(this.jdbcTemplate, sqlStringBuilder.toString(), queryParameters.toArray(), mapper);
}
@Override
@@ -28,6 +28,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobRunHistoryData;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.springframework.beans.factory.annotation.Autowired;
@@ -39,15 +40,19 @@ import org.springframework.stereotype.Service;
public class ReportMailingJobRunHistoryReadPlatformServiceImpl implements ReportMailingJobRunHistoryReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final ReportMailingJobRunHistoryMapper reportMailingJobRunHistoryMapper;
private final ColumnValidator columnValidator;
private final PaginationHelper<ReportMailingJobRunHistoryData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
@Autowired
public ReportMailingJobRunHistoryReadPlatformServiceImpl(final RoutingDataSource dataSource, final ColumnValidator columnValidator) {
public ReportMailingJobRunHistoryReadPlatformServiceImpl(final RoutingDataSource dataSource, final ColumnValidator columnValidator,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.sqlGenerator = sqlGenerator;
this.reportMailingJobRunHistoryMapper = new ReportMailingJobRunHistoryMapper();
this.columnValidator = columnValidator;
this.paginationHelper = paginationHelper;
}
@Override
@@ -56,7 +61,7 @@ public class ReportMailingJobRunHistoryReadPlatformServiceImpl implements Report
final StringBuilder sqlStringBuilder = new StringBuilder(200);
final List<Object> queryParameters = new ArrayList<>();
sqlStringBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlStringBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlStringBuilder.append(this.reportMailingJobRunHistoryMapper.reportMailingJobRunHistorySchema());
if (reportMailingJobId != null) {
@@ -74,15 +79,16 @@ public class ReportMailingJobRunHistoryReadPlatformServiceImpl implements Report
}
if (searchParameters.isLimited()) {
sqlStringBuilder.append(" limit ").append(searchParameters.getLimit());
sqlStringBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlStringBuilder.append(" offset ").append(searchParameters.getOffset());
sqlStringBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlStringBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
return this.paginationHelper.fetchPage(this.jdbcTemplate, "SELECT FOUND_ROWS()", sqlStringBuilder.toString(),
queryParameters.toArray(), this.reportMailingJobRunHistoryMapper);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlStringBuilder.toString(), queryParameters.toArray(),
this.reportMailingJobRunHistoryMapper);
}
private static final class ReportMailingJobRunHistoryMapper implements RowMapper<ReportMailingJobRunHistoryData> {
@@ -32,6 +32,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.infrastructure.sms.data.SmsData;
import org.apache.fineract.infrastructure.sms.domain.SmsMessageEnumerations;
@@ -47,15 +48,19 @@ import org.springframework.stereotype.Service;
public class SmsReadPlatformServiceImpl implements SmsReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final SmsMapper smsRowMapper;
private final PaginationHelper<SmsData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
private final ColumnValidator columnValidator;
@Autowired
public SmsReadPlatformServiceImpl(final RoutingDataSource dataSource, final ColumnValidator columnValidator) {
public SmsReadPlatformServiceImpl(final RoutingDataSource dataSource, final ColumnValidator columnValidator,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.sqlGenerator = sqlGenerator;
this.smsRowMapper = new SmsMapper();
this.columnValidator = columnValidator;
this.paginationHelper = paginationHelper;
}
private static final class SmsMapper implements RowMapper<SmsData> {
@@ -130,7 +135,7 @@ public class SmsReadPlatformServiceImpl implements SmsReadPlatformService {
@Override
public Collection<SmsData> retrieveAllPending(final Long campaignId, final Integer limit) {
final String sqlPlusLimit = limit > 0 ? " limit 0, " + limit : "";
final String sqlPlusLimit = limit > 0 ? " " + sqlGenerator.limit(limit) : "";
String sql = "select " + this.smsRowMapper.schema() + " where smo.status_enum = " + SmsMessageStatusType.PENDING.getValue();
if (campaignId != null) {
sql += " and smo.campaign_id = " + campaignId;
@@ -143,7 +148,7 @@ public class SmsReadPlatformServiceImpl implements SmsReadPlatformService {
@Override
public Collection<SmsData> retrieveAllSent(final Integer limit) {
final String sqlPlusLimit = limit > 0 ? " limit 0, " + limit : "";
final String sqlPlusLimit = limit > 0 ? " " + sqlGenerator.limit(limit) : "";
final String sql = "select " + this.smsRowMapper.schema() + " where smo.status_enum IN ("
+ SmsMessageStatusType.WAITING_FOR_DELIVERY_REPORT.getValue() + "," + SmsMessageStatusType.SENT.getValue() + ")"
+ sqlPlusLimit;
@@ -153,7 +158,7 @@ public class SmsReadPlatformServiceImpl implements SmsReadPlatformService {
@Override
public List<Long> retrieveExternalIdsOfAllSent(final Integer limit) {
final String sqlPlusLimit = limit > 0 ? " limit 0, " + limit : "";
final String sqlPlusLimit = limit > 0 ? " " + sqlGenerator.limit(limit) : "";
final String sql = "select external_id from " + this.smsRowMapper.tableName() + " where status_enum = "
+ SmsMessageStatusType.SENT.getValue() + sqlPlusLimit;
@@ -162,18 +167,17 @@ public class SmsReadPlatformServiceImpl implements SmsReadPlatformService {
@Override
public Page<Long> retrieveAllWaitingForDeliveryReport(final Integer limit) {
final String sqlPlusLimit = limit > 0 ? " limit 0, " + limit : "";
final String sqlPlusLimit = limit > 0 ? " " + sqlGenerator.limit(limit) : "";
final String sql = "select id from " + this.smsRowMapper.tableName() + " where status_enum = "
+ SmsMessageStatusType.WAITING_FOR_DELIVERY_REPORT.getValue() + sqlPlusLimit;
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(jdbcTemplate, sql, sqlCountRows, Long.class);
return this.paginationHelper.fetchPage(jdbcTemplate, sql, Long.class);
// (this.jdbcTemplate, sqlCountRows, new Object [] {}, Long.class);
// this.jdbcTemplate.queryForList(sql, Long.class);
}
@Override
public List<Long> retrieveAllPending(final Integer limit) {
final String sqlPlusLimit = limit > 0 ? " limit 0, " + limit : "";
final String sqlPlusLimit = limit > 0 ? " " + sqlGenerator.limit(limit) : "";
final String sql = "select external_id from " + this.smsRowMapper.tableName() + " where status_enum = "
+ SmsMessageStatusType.PENDING.getValue() + sqlPlusLimit;
@@ -182,7 +186,7 @@ public class SmsReadPlatformServiceImpl implements SmsReadPlatformService {
@Override
public Collection<SmsData> retrieveAllDelivered(final Integer limit) {
final String sqlPlusLimit = limit > 0 ? " limit 0, " + limit : "";
final String sqlPlusLimit = limit > 0 ? " " + sqlGenerator.limit(limit) : "";
final String sql = "select " + this.smsRowMapper.schema() + " where smo.status_enum = " + SmsMessageStatusType.DELIVERED.getValue()
+ sqlPlusLimit;
@@ -191,7 +195,7 @@ public class SmsReadPlatformServiceImpl implements SmsReadPlatformService {
@Override
public Collection<SmsData> retrieveAllFailed(final Integer limit) {
final String sqlPlusLimit = limit > 0 ? " limit 0, " + limit : "";
final String sqlPlusLimit = limit > 0 ? " " + sqlGenerator.limit(limit) : "";
final String sql = "select " + this.smsRowMapper.schema() + " where smo.status_enum = " + SmsMessageStatusType.FAILED.getValue()
+ sqlPlusLimit;
@@ -204,7 +208,7 @@ public class SmsReadPlatformServiceImpl implements SmsReadPlatformService {
final StringBuilder sqlBuilder = new StringBuilder(200);
final Object[] objectArray = new Object[10];
int arrayPos = 0;
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(this.smsRowMapper.schema());
if (status != null) {
sqlBuilder.append(" where smo.campaign_id = ? and smo.status_enum= ? ");
@@ -239,14 +243,15 @@ public class SmsReadPlatformServiceImpl implements SmsReadPlatformService {
}
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
final Object[] finalObjectArray = Arrays.copyOf(objectArray, arrayPos);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), finalObjectArray, this.smsRowMapper);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), finalObjectArray, this.smsRowMapper);
}
}
@@ -50,6 +50,7 @@ import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityEx
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.interoperation.data.InteropAccountData;
import org.apache.fineract.interoperation.data.InteropIdentifierAccountResponseData;
@@ -141,6 +142,7 @@ public class InteropServiceImpl implements InteropService {
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final DefaultToApiJsonSerializer<LoanAccountData> toApiJsonSerializer;
private final DatabaseSpecificSQLGenerator sqlGenerator;
@Autowired
public InteropServiceImpl(PlatformSecurityContext securityContext, InteropDataValidator interopDataValidator,
@@ -150,7 +152,7 @@ public class InteropServiceImpl implements InteropService {
SavingsHelper savingsHelper, SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper,
SavingsAccountDomainService savingsAccountService, final RoutingDataSource dataSource,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
final DefaultToApiJsonSerializer<LoanAccountData> toApiJsonSerializer) {
final DefaultToApiJsonSerializer<LoanAccountData> toApiJsonSerializer, DatabaseSpecificSQLGenerator sqlGenerator) {
this.securityContext = securityContext;
this.dataValidator = interopDataValidator;
this.savingsAccountRepository = savingsAccountRepository;
@@ -166,13 +168,20 @@ public class InteropServiceImpl implements InteropService {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.toApiJsonSerializer = toApiJsonSerializer;
this.sqlGenerator = sqlGenerator;
}
private static final class KycMapper implements RowMapper<InteropKycData> {
private final DatabaseSpecificSQLGenerator sqlGenerator;
KycMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
this.sqlGenerator = sqlGenerator;
}
public String schema() {
return " country.code_value as nationality, c.date_of_birth as dateOfBirth, c.mobile_no as contactPhone, gender.code_value as gender, c.email_address as email, "
+ "kyc.code_value as idType, ci.document_key as idNo, ci.`description` as description, "
+ "kyc.code_value as idType, ci.document_key as idNo, ci." + sqlGenerator.escape("description") + " as description, "
+ "country.code_value as country, a.`address_line_1`, a.`address_line_2`, "
+ "a.city, state.code_value as stateProvince, a.postal_code as postalCode, c.firstname as firstName, c.middlename as middleName,"
+ "c.lastname as lastName, c.display_name as displayName" + " from " + "m_client c "
@@ -512,7 +521,7 @@ public class InteropServiceImpl implements InteropService {
Long client_id = savingsAccount.getClient().getId();
try {
final InteropServiceImpl.KycMapper rm = new InteropServiceImpl.KycMapper();
final InteropServiceImpl.KycMapper rm = new InteropServiceImpl.KycMapper(sqlGenerator);
final String sql = "select " + rm.schema() + " where c.id = ?";
final InteropKycData accountKyc = this.jdbcTemplate.queryForObject(sql, rm, new Object[] { client_id });
@@ -27,6 +27,7 @@ import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.notification.cache.CacheNotificationResponseHeader;
@@ -43,17 +44,20 @@ public class NotificationReadPlatformServiceImpl implements NotificationReadPlat
private final JdbcTemplate jdbcTemplate;
private final PlatformSecurityContext context;
private final ColumnValidator columnValidator;
private final PaginationHelper<NotificationData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final NotificationDataRow notificationDataRow = new NotificationDataRow();
private final NotificationMapperRow notificationMapperRow = new NotificationMapperRow();
private HashMap<Long, HashMap<Long, CacheNotificationResponseHeader>> tenantNotificationResponseHeaderCache = new HashMap<>();
@Autowired
public NotificationReadPlatformServiceImpl(final RoutingDataSource dataSource, final PlatformSecurityContext context,
final ColumnValidator columnValidator) {
final ColumnValidator columnValidator, DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.context = context;
this.columnValidator = columnValidator;
this.paginationHelper = paginationHelper;
this.sqlGenerator = sqlGenerator;
}
@Override
@@ -114,8 +118,9 @@ public class NotificationReadPlatformServiceImpl implements NotificationReadPlat
@Override
public Page<NotificationData> getAllUnreadNotifications(final SearchParameters searchParameters) {
final Long appUserId = context.authenticatedUser().getId();
String sql = "SELECT SQL_CALC_FOUND_ROWS ng.id as id, nm.user_id as userId, ng.object_type as objectType, "
+ "ng.object_identifier as objectId, ng.actor as actor, ng.action action, ng.notification_content "
String sql = "SELECT " + sqlGenerator.calcFoundRows() + " ng.id as id, nm.user_id as userId, ng.object_type as objectType, "
+ "ng.object_identifier as objectId, ng.actor as actor, ng." + sqlGenerator.escape("action")
+ " as action, ng.notification_content "
+ "as content, ng.is_system_generated as isSystemGenerated, nm.created_at as createdAt "
+ "FROM notification_mapper nm INNER JOIN notification_generator ng ON nm.notification_id = ng.id "
+ "WHERE nm.user_id = ? AND nm.is_read = false order by nm.created_at desc";
@@ -126,8 +131,9 @@ public class NotificationReadPlatformServiceImpl implements NotificationReadPlat
@Override
public Page<NotificationData> getAllNotifications(SearchParameters searchParameters) {
final Long appUserId = context.authenticatedUser().getId();
String sql = "SELECT SQL_CALC_FOUND_ROWS ng.id as id, nm.user_id as userId, ng.object_type as objectType, "
+ "ng.object_identifier as objectId, ng.actor as actor, ng.action action, ng.notification_content "
String sql = "SELECT " + sqlGenerator.calcFoundRows() + " ng.id as id, nm.user_id as userId, ng.object_type as objectType, "
+ "ng.object_identifier as objectId, ng.actor as actor, ng." + sqlGenerator.escape("action")
+ " as action, ng.notification_content "
+ "as content, ng.is_system_generated as isSystemGenerated, nm.created_at as createdAt "
+ "FROM notification_mapper nm INNER JOIN notification_generator ng ON nm.notification_id = ng.id "
+ "WHERE nm.user_id = ? order by nm.created_at desc";
@@ -149,15 +155,16 @@ public class NotificationReadPlatformServiceImpl implements NotificationReadPlat
}
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
Object[] params = new Object[] { appUserId };
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), params, this.notificationDataRow);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), params, this.notificationDataRow);
}
private static final class NotificationMapperRow implements RowMapper<NotificationMapperData> {
@@ -35,9 +35,11 @@ import org.apache.fineract.useradministration.domain.RoleRepository;
import org.apache.fineract.useradministration.exception.RoleNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
@Service
@Transactional
public class TopicDomainServiceImpl implements TopicDomainService {
private final RoleRepository roleRepository;
@@ -28,6 +28,7 @@ import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
@@ -47,6 +48,7 @@ import org.springframework.stereotype.Service;
public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final PlatformSecurityContext context;
private final CurrencyReadPlatformService currencyReadPlatformService;
private final ColumnValidator columnValidator;
@@ -55,11 +57,12 @@ public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService
@Autowired
public OfficeReadPlatformServiceImpl(final PlatformSecurityContext context,
final CurrencyReadPlatformService currencyReadPlatformService, final RoutingDataSource dataSource,
final ColumnValidator columnValidator) {
final ColumnValidator columnValidator, DatabaseSpecificSQLGenerator sqlGenerator) {
this.context = context;
this.currencyReadPlatformService = currencyReadPlatformService;
this.columnValidator = columnValidator;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.sqlGenerator = sqlGenerator;
}
private static final class OfficeMapper implements RowMapper<OfficeData> {
@@ -105,13 +108,20 @@ public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService
private static final class OfficeTransactionMapper implements RowMapper<OfficeTransactionData> {
private final DatabaseSpecificSQLGenerator sqlGenerator;
OfficeTransactionMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
this.sqlGenerator = sqlGenerator;
}
public String schema() {
return " ot.id as id, ot.transaction_date as transactionDate, ot.from_office_id as fromOfficeId, fromoff.name as fromOfficeName, "
+ " ot.to_office_id as toOfficeId, tooff.name as toOfficeName, ot.transaction_amount as transactionAmount, ot.description as description, "
+ " ot.currency_code as currencyCode, rc.decimal_places as currencyDigits, rc.currency_multiplesof as inMultiplesOf, "
+ " rc.name as currencyName, rc.internationalized_name_code as currencyNameCode, rc.display_symbol as currencyDisplaySymbol "
+ " from m_office_transaction ot " + " left join m_office fromoff on fromoff.id = ot.from_office_id "
+ " left join m_office tooff on tooff.id = ot.to_office_id " + " join m_currency rc on rc.`code` = ot.currency_code";
+ " left join m_office tooff on tooff.id = ot.to_office_id " + " join m_currency rc on rc."
+ sqlGenerator.escape("code") + " = ot.currency_code";
}
@Override
@@ -244,7 +254,7 @@ public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService
final String hierarchy = currentUser.getOffice().getHierarchy();
final String hierarchySearchString = hierarchy + "%";
final OfficeTransactionMapper rm = new OfficeTransactionMapper();
final OfficeTransactionMapper rm = new OfficeTransactionMapper(sqlGenerator);
final String sql = "select " + rm.schema()
+ " where (fromoff.hierarchy like ? or tooff.hierarchy like ?) order by ot.transaction_date, ot.id";
@@ -33,6 +33,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
@@ -70,19 +71,23 @@ public class TellerManagementReadPlatformServiceImpl implements TellerManagement
private final OfficeReadPlatformService officeReadPlatformService;
private final StaffReadPlatformService staffReadPlatformService;
private final CurrencyReadPlatformService currencyReadPlatformService;
private final PaginationHelper<CashierTransactionData> paginationHelper = new PaginationHelper<>();
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final PaginationHelper paginationHelper;
private final ColumnValidator columnValidator;
@Autowired
public TellerManagementReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
final OfficeReadPlatformService officeReadPlatformService, StaffReadPlatformService staffReadPlatformService,
final CurrencyReadPlatformService currencyReadPlatformService, final ColumnValidator columnValidator) {
final CurrencyReadPlatformService currencyReadPlatformService, final ColumnValidator columnValidator,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.officeReadPlatformService = officeReadPlatformService;
this.staffReadPlatformService = staffReadPlatformService;
this.currencyReadPlatformService = currencyReadPlatformService;
this.columnValidator = columnValidator;
this.sqlGenerator = sqlGenerator;
this.paginationHelper = paginationHelper;
}
private static final class TellerMapper implements RowMapper<TellerData> {
@@ -545,12 +550,13 @@ public class TellerManagementReadPlatformServiceImpl implements TellerManagement
+ " and (cli_txn.payment_detail_id IS NULL OR payType.is_cash_payment = true) ) " + " order by created_date ";
if (searchParameters.isLimited()) {
sql = sql + " limit " + searchParameters.getLimit();
sql += " ";
if (searchParameters.isOffset()) {
sql = sql + " offset " + searchParameters.getOffset();
sql += sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset());
} else {
sql += sqlGenerator.limit(searchParameters.getLimit());
}
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
// return this.jdbcTemplate.query(sql, ctm, new Object[] { cashierId,
// currencyCode, hierarchySearchString, cashierId, currencyCode,
// hierarchySearchString, cashierId, currencyCode,
@@ -558,7 +564,7 @@ public class TellerManagementReadPlatformServiceImpl implements TellerManagement
// });
Object[] params = new Object[] { cashierId, currencyCode, hierarchySearchString, cashierId, currencyCode, hierarchySearchString,
cashierId, currencyCode, hierarchySearchString, cashierId, currencyCode, hierarchySearchString };
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sql, params, ctm);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sql, params, ctm);
}
private static final class CashierMapper implements RowMapper<CashierData> {
@@ -35,6 +35,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.organisation.office.data.OfficeData;
@@ -62,25 +63,28 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
private final OfficeReadPlatformService officeReadPlatformService;
private final PortfolioAccountReadPlatformService portfolioAccountReadPlatformService;
private final ColumnValidator columnValidator;
private final DatabaseSpecificSQLGenerator sqlGenerator;
// mapper
private final AccountTransfersMapper accountTransfersMapper;
// pagination
private final PaginationHelper<AccountTransferData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@Autowired
public AccountTransfersReadPlatformServiceImpl(final RoutingDataSource dataSource,
final ClientReadPlatformService clientReadPlatformService, final OfficeReadPlatformService officeReadPlatformService,
final PortfolioAccountReadPlatformService portfolioAccountReadPlatformService, final ColumnValidator columnValidator) {
final PortfolioAccountReadPlatformService portfolioAccountReadPlatformService, final ColumnValidator columnValidator,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.clientReadPlatformService = clientReadPlatformService;
this.officeReadPlatformService = officeReadPlatformService;
this.portfolioAccountReadPlatformService = portfolioAccountReadPlatformService;
this.columnValidator = columnValidator;
this.sqlGenerator = sqlGenerator;
this.accountTransfersMapper = new AccountTransfersMapper();
this.paginationHelper = paginationHelper;
}
@Override
@@ -215,7 +219,7 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
public Page<AccountTransferData> retrieveAll(final SearchParameters searchParameters, final Long accountDetailId) {
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(this.accountTransfersMapper.schema());
Object[] finalObjectArray = {};
if (accountDetailId != null) {
@@ -239,9 +243,7 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
}
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), finalObjectArray,
this.accountTransfersMapper);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), finalObjectArray, this.accountTransfersMapper);
}
@Override
@@ -411,7 +413,7 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
public Page<AccountTransferData> retrieveByStandingInstruction(final Long id, final SearchParameters searchParameters) {
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(this.accountTransfersMapper.schema()).append(
" join m_account_transfer_standing_instructions atsi on atsi.account_transfer_details_id = att.account_transfer_details_id ");
sqlBuilder.append(" where atsi.id = ?");
@@ -427,17 +429,17 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
}
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
}
final Object[] finalObjectArray = { id };
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), finalObjectArray,
this.accountTransfersMapper);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), finalObjectArray, this.accountTransfersMapper);
}
@Override
@@ -26,6 +26,7 @@ import java.util.Collection;
import java.util.List;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.account.PortfolioAccountType;
import org.apache.fineract.portfolio.account.data.PortfolioAccountDTO;
@@ -48,11 +49,11 @@ public class PortfolioAccountReadPlatformServiceImpl implements PortfolioAccount
private final PortfolioLoanAccountRefundByTransferMapper accountRefundByTransferMapper;
@Autowired
public PortfolioAccountReadPlatformServiceImpl(final RoutingDataSource dataSource) {
public PortfolioAccountReadPlatformServiceImpl(final RoutingDataSource dataSource, DatabaseSpecificSQLGenerator sqlGenerator) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.savingsAccountMapper = new PortfolioSavingsAccountMapper();
this.loanAccountMapper = new PortfolioLoanAccountMapper();
this.accountRefundByTransferMapper = new PortfolioLoanAccountRefundByTransferMapper();
this.accountRefundByTransferMapper = new PortfolioLoanAccountRefundByTransferMapper(sqlGenerator);
}
@Override
@@ -295,7 +296,7 @@ public class PortfolioAccountReadPlatformServiceImpl implements PortfolioAccount
private final String schemaSql;
PortfolioLoanAccountRefundByTransferMapper() {
PortfolioLoanAccountRefundByTransferMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
final StringBuilder amountQueryString = new StringBuilder(400);
amountQueryString.append("(select (SUM(COALESCE(mr.principal_completed_derived, 0)) +");
@@ -304,7 +305,7 @@ public class PortfolioAccountReadPlatformServiceImpl implements PortfolioAccount
amountQueryString.append(" SUM(COALESCE(mr.penalty_charges_completed_derived, 0))) as total_in_advance_derived");
amountQueryString.append(" from m_loan ml INNER JOIN m_loan_repayment_schedule mr on mr.loan_id = ml.id");
amountQueryString.append(" where ml.id=? and ml.loan_status_id = 300");
amountQueryString.append(" and mr.duedate >= CURDATE() group by ml.id having");
amountQueryString.append(" and mr.duedate >= " + sqlGenerator.currentDate() + " group by ml.id having");
amountQueryString.append(" (SUM(COALESCE(mr.principal_completed_derived, 0)) + ");
amountQueryString.append(" SUM(COALESCE(mr.interest_completed_derived, 0)) + ");
amountQueryString.append("SUM(COALESCE(mr.fee_charges_completed_derived, 0)) + ");
@@ -34,6 +34,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.organisation.office.data.OfficeData;
import org.apache.fineract.portfolio.account.PortfolioAccountType;
@@ -50,26 +51,30 @@ import org.springframework.stereotype.Service;
public class StandingInstructionHistoryReadPlatformServiceImpl implements StandingInstructionHistoryReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final ColumnValidator columnValidator;
// mapper
private final StandingInstructionHistoryMapper standingInstructionHistoryMapper;
// pagination
private final PaginationHelper<StandingInstructionHistoryData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
@Autowired
public StandingInstructionHistoryReadPlatformServiceImpl(final RoutingDataSource dataSource, final ColumnValidator columnValidator) {
public StandingInstructionHistoryReadPlatformServiceImpl(final RoutingDataSource dataSource, final ColumnValidator columnValidator,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.sqlGenerator = sqlGenerator;
this.standingInstructionHistoryMapper = new StandingInstructionHistoryMapper();
this.columnValidator = columnValidator;
this.paginationHelper = paginationHelper;
}
@Override
public Page<StandingInstructionHistoryData> retrieveAll(StandingInstructionDTO standingInstructionDTO) {
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(this.standingInstructionHistoryMapper.schema());
if (standingInstructionDTO.transferType() != null || standingInstructionDTO.clientId() != null
|| standingInstructionDTO.clientName() != null
@@ -149,15 +154,16 @@ public class StandingInstructionHistoryReadPlatformServiceImpl implements Standi
}
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
final Object[] finalObjectArray = paramObj.toArray();
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), finalObjectArray,
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), finalObjectArray,
this.standingInstructionHistoryMapper);
}
@@ -41,6 +41,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.organisation.office.data.OfficeData;
import org.apache.fineract.organisation.office.service.OfficeReadPlatformService;
@@ -76,25 +77,29 @@ public class StandingInstructionReadPlatformServiceImpl implements StandingInstr
private final OfficeReadPlatformService officeReadPlatformService;
private final PortfolioAccountReadPlatformService portfolioAccountReadPlatformService;
private final DropdownReadPlatformService dropdownReadPlatformService;
private final DatabaseSpecificSQLGenerator sqlGenerator;
// mapper
private final StandingInstructionMapper standingInstructionMapper;
// pagination
private final PaginationHelper<StandingInstructionData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
@Autowired
public StandingInstructionReadPlatformServiceImpl(final RoutingDataSource dataSource,
final ClientReadPlatformService clientReadPlatformService, final OfficeReadPlatformService officeReadPlatformService,
final PortfolioAccountReadPlatformService portfolioAccountReadPlatformService,
final DropdownReadPlatformService dropdownReadPlatformService, final ColumnValidator columnValidator) {
final DropdownReadPlatformService dropdownReadPlatformService, final ColumnValidator columnValidator,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.clientReadPlatformService = clientReadPlatformService;
this.officeReadPlatformService = officeReadPlatformService;
this.portfolioAccountReadPlatformService = portfolioAccountReadPlatformService;
this.dropdownReadPlatformService = dropdownReadPlatformService;
this.sqlGenerator = sqlGenerator;
this.standingInstructionMapper = new StandingInstructionMapper();
this.columnValidator = columnValidator;
this.paginationHelper = paginationHelper;
}
@Override
@@ -257,7 +262,7 @@ public class StandingInstructionReadPlatformServiceImpl implements StandingInstr
public Page<StandingInstructionData> retrieveAll(final StandingInstructionDTO standingInstructionDTO) {
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(this.standingInstructionMapper.schema());
if (standingInstructionDTO.transferType() != null || standingInstructionDTO.clientId() != null
|| standingInstructionDTO.clientName() != null) {
@@ -315,16 +320,16 @@ public class StandingInstructionReadPlatformServiceImpl implements StandingInstr
}
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
final Object[] finalObjectArray = paramObj.toArray();
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), finalObjectArray,
this.standingInstructionMapper);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), finalObjectArray, this.standingInstructionMapper);
}
@Override
@@ -332,9 +337,10 @@ public class StandingInstructionReadPlatformServiceImpl implements StandingInstr
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select ");
sqlBuilder.append(this.standingInstructionMapper.schema());
sqlBuilder.append(
" where atsi.status=? and CURRENT_DATE() >= atsi.valid_from and (atsi.valid_till IS NULL or CURRENT_DATE() < atsi.valid_till) ")
.append(" and (atsi.last_run_date <> CURRENT_DATE() or atsi.last_run_date IS NULL)")
sqlBuilder
.append(" where atsi.status=? and " + sqlGenerator.currentDate() + " >= atsi.valid_from and (atsi.valid_till IS NULL or "
+ sqlGenerator.currentDate() + " < atsi.valid_till) ")
.append(" and (atsi.last_run_date <> " + sqlGenerator.currentDate() + " or atsi.last_run_date IS NULL)")
.append(" ORDER BY atsi.priority DESC");
return this.jdbcTemplate.query(sqlBuilder.toString(), this.standingInstructionMapper, status);
}
@@ -354,7 +360,8 @@ public class StandingInstructionReadPlatformServiceImpl implements StandingInstr
@Override
public StandingInstructionDuesData retriveLoanDuesData(final Long loanId) {
final StandingInstructionLoanDuesMapper rm = new StandingInstructionLoanDuesMapper();
final String sql = "select " + rm.schema() + " where ml.id= ? and ls.duedate <= CURRENT_DATE() and ls.completed_derived <> 1";
final String sql = "select " + rm.schema() + " where ml.id= ? and ls.duedate <= " + sqlGenerator.currentDate()
+ " and ls.completed_derived <> 1";
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { loanId });
}
@@ -40,6 +40,7 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.jobs.annotation.CronTarget;
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
import org.apache.fineract.infrastructure.jobs.service.JobName;
@@ -85,6 +86,7 @@ public class StandingInstructionWritePlatformServiceImpl implements StandingInst
private final StandingInstructionReadPlatformService standingInstructionReadPlatformService;
private final AccountTransfersWritePlatformService accountTransfersWritePlatformService;
private final JdbcTemplate jdbcTemplate;
private final DatabaseSpecificSQLGenerator sqlGenerator;
@Autowired
public StandingInstructionWritePlatformServiceImpl(final StandingInstructionDataValidator standingInstructionDataValidator,
@@ -92,7 +94,8 @@ public class StandingInstructionWritePlatformServiceImpl implements StandingInst
final AccountTransferDetailRepository accountTransferDetailRepository,
final StandingInstructionRepository standingInstructionRepository,
final StandingInstructionReadPlatformService standingInstructionReadPlatformService,
final AccountTransfersWritePlatformService accountTransfersWritePlatformService, final RoutingDataSource dataSource) {
final AccountTransfersWritePlatformService accountTransfersWritePlatformService, final RoutingDataSource dataSource,
DatabaseSpecificSQLGenerator sqlGenerator) {
this.standingInstructionDataValidator = standingInstructionDataValidator;
this.standingInstructionAssembler = standingInstructionAssembler;
this.accountTransferDetailRepository = accountTransferDetailRepository;
@@ -100,6 +103,7 @@ public class StandingInstructionWritePlatformServiceImpl implements StandingInst
this.standingInstructionReadPlatformService = standingInstructionReadPlatformService;
this.accountTransfersWritePlatformService = accountTransfersWritePlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.sqlGenerator = sqlGenerator;
}
@Transactional
@@ -261,7 +265,8 @@ public class StandingInstructionWritePlatformServiceImpl implements StandingInst
boolean transferCompleted = true;
StringBuilder errorLog = new StringBuilder();
StringBuilder updateQuery = new StringBuilder(
"INSERT INTO m_account_transfer_standing_instructions_history (standing_instruction_id, `status`, amount,execution_time, error_log) VALUES (");
"INSERT INTO m_account_transfer_standing_instructions_history (standing_instruction_id, " + sqlGenerator.escape("status")
+ ", amount,execution_time, error_log) VALUES (");
try {
this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
} catch (final PlatformApiDataValidationException e) {
@@ -41,10 +41,10 @@ public class ClientFamilyMembers extends AbstractPersistableCustom {
@Column(name = "firstname")
private String firstName;
@Column(name = "middleName")
@Column(name = "middlename")
private String middleName;
@Column(name = "lastName")
@Column(name = "lastname")
private String lastName;
@Column(name = "qualification")
@@ -29,6 +29,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.charge.data.ChargeData;
@@ -45,16 +46,20 @@ import org.springframework.stereotype.Service;
@Service
public class ClientChargeReadPlatformServiceImpl implements ClientChargeReadPlatformService {
private final PaginationHelper<ClientChargeData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
private final JdbcTemplate jdbcTemplate;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final PlatformSecurityContext context;
private final ClientChargeMapper clientChargeMapper;
@Autowired
public ClientChargeReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource) {
public ClientChargeReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.sqlGenerator = sqlGenerator;
this.clientChargeMapper = new ClientChargeMapper();
this.paginationHelper = paginationHelper;
}
public static final class ClientChargeMapper implements RowMapper<ClientChargeData> {
@@ -135,7 +140,7 @@ public class ClientChargeReadPlatformServiceImpl implements ClientChargeReadPlat
SearchParameters searchParameters) {
final ClientChargeMapper rm = new ClientChargeMapper();
final StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ").append(rm.schema()).append(" where cc.client_id=? ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ").append(rm.schema()).append(" where cc.client_id=? ");
// filter for active charges
if (status.equalsIgnoreCase(ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ACTIVE)) {
@@ -156,14 +161,15 @@ public class ClientChargeReadPlatformServiceImpl implements ClientChargeReadPlat
// apply limit and offsets
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), new Object[] { clientId },
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), new Object[] { clientId },
this.clientChargeMapper);
}
@@ -43,6 +43,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
@@ -88,7 +89,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
private final CodeValueReadPlatformService codeValueReadPlatformService;
private final SavingsProductReadPlatformService savingsProductReadPlatformService;
// data mappers
private final PaginationHelper<ClientData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final ClientMapper clientMapper = new ClientMapper();
private final ClientLookupMapper lookupMapper = new ClientLookupMapper();
private final ClientMembersOfGroupMapper membersOfGroupMapper = new ClientMembersOfGroupMapper();
@@ -110,7 +112,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final ClientFamilyMembersReadPlatformService clientFamilyMembersReadPlatformService,
final ConfigurationReadPlatformService configurationReadPlatformService,
final EntityDatatableChecksReadService entityDatatableChecksReadService, final ColumnValidator columnValidator,
final ClientCollateralManagementRepositoryWrapper clientCollateralManagementRepositoryWrapper) {
final ClientCollateralManagementRepositoryWrapper clientCollateralManagementRepositoryWrapper,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.context = context;
this.officeReadPlatformService = officeReadPlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource);
@@ -123,6 +126,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
this.entityDatatableChecksReadService = entityDatatableChecksReadService;
this.columnValidator = columnValidator;
this.clientCollateralManagementRepositoryWrapper = clientCollateralManagementRepositoryWrapper;
this.paginationHelper = paginationHelper;
this.sqlGenerator = sqlGenerator;
}
@Override
@@ -208,7 +213,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
// }
List<Object> paramList = new ArrayList<>(Arrays.asList(underHierarchySearchString, underHierarchySearchString));
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(this.clientMapper.schema());
sqlBuilder.append(" where (o.hierarchy like ? or transferToOffice.hierarchy like ?) ");
@@ -235,15 +240,15 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
}
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), paramList.toArray(),
this.clientMapper);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), paramList.toArray(), this.clientMapper);
}
private String buildSqlStringFromClientCriteria(String schemaSql, final SearchParameters searchParameters, List<Object> paramList) {
@@ -275,8 +280,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
}
if (displayName != null) {
// extraCriteria += " and concat(ifnull(c.firstname, ''),
// if(c.firstname > '',' ', '') , ifnull(c.lastname, '')) like "
// extraCriteria += " and concatcoalesce(c.firstname, ''),
// if(c.firstname > '',' ', '') , coalesce(c.lastname, '')) like "
paramList.add("%" + displayName + "%");
extraCriteria += " and c.display_name like ? ";
}
@@ -29,6 +29,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.client.data.ClientTransactionData;
import org.apache.fineract.portfolio.client.domain.ClientEnumerations;
@@ -46,14 +47,17 @@ import org.springframework.stereotype.Service;
public class ClientTransactionReadPlatformServiceImpl implements ClientTransactionReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final ClientTransactionMapper clientTransactionMapper;
private final PaginationHelper<ClientTransactionData> paginationHelper;
private final PaginationHelper paginationHelper;
@Autowired
public ClientTransactionReadPlatformServiceImpl(final RoutingDataSource dataSource) {
public ClientTransactionReadPlatformServiceImpl(final RoutingDataSource dataSource, DatabaseSpecificSQLGenerator sqlGenerator,
PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.sqlGenerator = sqlGenerator;
this.clientTransactionMapper = new ClientTransactionMapper();
this.paginationHelper = new PaginationHelper<>();
this.paginationHelper = paginationHelper;
}
private static final class ClientTransactionMapper implements RowMapper<ClientTransactionData> {
@@ -137,21 +141,23 @@ public class ClientTransactionReadPlatformServiceImpl implements ClientTransacti
public Page<ClientTransactionData> retrieveAllTransactions(Long clientId, SearchParameters searchParameters) {
Object[] parameters = new Object[1];
final StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ").append(this.clientTransactionMapper.schema()).append(" where c.id = ? ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ").append(this.clientTransactionMapper.schema())
.append(" where c.id = ? ");
parameters[0] = clientId;
final String sqlCountRows = "SELECT FOUND_ROWS()";
sqlBuilder.append(" order by tr.transaction_date DESC, tr.created_date DESC, tr.id DESC ");
// apply limit and offsets
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), parameters,
this.clientTransactionMapper);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), parameters, this.clientTransactionMapper);
}
@Override
@@ -42,6 +42,7 @@ import org.apache.fineract.infrastructure.core.api.JsonQuery;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.calendar.domain.Calendar;
@@ -90,12 +91,13 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
private final CollectionSheetGenerateCommandFromApiJsonDeserializer collectionSheetGenerateCommandFromApiJsonDeserializer;
private final CalendarRepositoryWrapper calendarRepositoryWrapper;
private final AttendanceDropdownReadPlatformService attendanceDropdownReadPlatformService;
private final MandatorySavingsCollectionsheetExtractor mandatorySavingsExtractor = new MandatorySavingsCollectionsheetExtractor();
private final MandatorySavingsCollectionsheetExtractor mandatorySavingsExtractor;
private final CodeValueReadPlatformService codeValueReadPlatformService;
private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
private final CalendarReadPlatformService calendarReadPlatformService;
private final ConfigurationDomainService configurationDomainService;
private final CalendarInstanceRepository calendarInstanceRepository;
private final DatabaseSpecificSQLGenerator sqlGenerator;
@Autowired
public CollectionSheetReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
@@ -106,7 +108,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
final CodeValueReadPlatformService codeValueReadPlatformService,
final PaymentTypeReadPlatformService paymentTypeReadPlatformService,
final CalendarReadPlatformService calendarReadPlatformService, final ConfigurationDomainService configurationDomainService,
final CalendarInstanceRepository calendarInstanceRepository) {
final CalendarInstanceRepository calendarInstanceRepository, DatabaseSpecificSQLGenerator sqlGenerator) {
this.context = context;
this.centerReadPlatformService = centerReadPlatformService;
this.namedParameterjdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
@@ -119,6 +121,8 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
this.calendarReadPlatformService = calendarReadPlatformService;
this.configurationDomainService = configurationDomainService;
this.calendarInstanceRepository = calendarInstanceRepository;
this.sqlGenerator = sqlGenerator;
mandatorySavingsExtractor = new MandatorySavingsCollectionsheetExtractor(sqlGenerator);
}
/*
@@ -215,6 +219,12 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
private static final class JLGCollectionSheetFaltDataMapper implements RowMapper<JLGCollectionSheetFlatData> {
private final DatabaseSpecificSQLGenerator sqlGenerator;
JLGCollectionSheetFaltDataMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
this.sqlGenerator = sqlGenerator;
}
public String collectionSheetSchema(final boolean isCenterCollection) {
StringBuilder sql = new StringBuilder(400);
sql.append("SELECT loandata.*, sum(lc.amount_outstanding_derived) as chargesDue from ")
@@ -223,7 +233,9 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
.append("gl.level_name As levelName, ").append("cl.id As clientId, ").append("ln.id As loanId, ")
.append("ln.account_no As accountId, ").append("ln.loan_status_id As accountStatusId, ")
.append("pl.short_name As productShortName, ").append("ln.product_id As productId, ")
.append("ln.currency_code as currencyCode, ln.currency_digits as currencyDigits, ln.currency_multiplesof as inMultiplesOf, rc.`name` as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, ")
.append("ln.currency_code as currencyCode, ln.currency_digits as currencyDigits, ln.currency_multiplesof as inMultiplesOf, rc."
+ sqlGenerator.escape("name")
+ " as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, ")
.append("(CASE WHEN ln.loan_status_id = 200 THEN ln.principal_amount ELSE null END) As disbursementAmount, ")
.append("sum(COALESCE((CASE WHEN ln.loan_status_id = 300 THEN ls.principal_amount ELSE 0.0 END), 0.0) - COALESCE((CASE WHEN ln.loan_status_id = 300 THEN ls.principal_completed_derived ELSE 0.0 END), 0.0)) As principalDue, ")
.append("ln.principal_repaid_derived As principalPaid, ")
@@ -237,7 +249,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
.append("JOIN m_group_client gc ON gc.group_id = gp.id ").append("JOIN m_client cl ON cl.id = gc.client_id ")
.append("LEFT JOIN m_loan ln ON cl.id = ln.client_id and ln.group_id=gp.id AND ln.group_id is not null AND ( ln.loan_status_id = 300 ) ")
.append("LEFT JOIN m_product_loan pl ON pl.id = ln.product_id ")
.append("LEFT JOIN m_currency rc on rc.`code` = ln.currency_code ")
.append("LEFT JOIN m_currency rc on rc." + sqlGenerator.escape("code") + " = ln.currency_code ")
.append("LEFT JOIN m_loan_repayment_schedule ls ON ls.loan_id = ln.id AND ls.completed_derived = 0 AND ls.duedate <= :dueDate ")
.append("left join m_calendar_instance ci on gp.parent_id = ci.entity_id and ci.entity_type_enum =:entityTypeId ")
.append("left join m_meeting mt on ci.id = mt.calendar_instance_id and mt.meeting_date =:dueDate ")
@@ -354,7 +366,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
final String hierarchy = currentUser.getOffice().getHierarchy();
final String officeHierarchy = hierarchy + "%";
final JLGCollectionSheetFaltDataMapper mapper = new JLGCollectionSheetFaltDataMapper();
final JLGCollectionSheetFaltDataMapper mapper = new JLGCollectionSheetFaltDataMapper(sqlGenerator);
final SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("dueDate", transactionDateStr)
.addValue("groupId", group.getId()).addValue("officeHierarchy", officeHierarchy)
@@ -457,7 +469,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
final String dueDateStr = df.format(Date.from(transactionDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
final JLGCollectionSheetFaltDataMapper mapper = new JLGCollectionSheetFaltDataMapper();
final JLGCollectionSheetFaltDataMapper mapper = new JLGCollectionSheetFaltDataMapper(sqlGenerator);
StringBuilder sql = new StringBuilder(mapper.collectionSheetSchema(true));
@@ -487,6 +499,11 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
private static final class MandatorySavingsCollectionsheetExtractor implements ResultSetExtractor<Collection<JLGGroupData>> {
private final GroupSavingsDataMapper groupSavingsDataMapper = new GroupSavingsDataMapper();
private final DatabaseSpecificSQLGenerator sqlGenerator;
MandatorySavingsCollectionsheetExtractor(DatabaseSpecificSQLGenerator sqlGenerator) {
this.sqlGenerator = sqlGenerator;
}
public String collectionSheetSchema(final boolean isCenterCollection) {
@@ -497,7 +514,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
.append("sa.account_no As accountId, ").append("sa.status_enum As accountStatusId, ")
.append("sp.short_name As productShortName, ").append("sp.id As productId, ")
.append("sa.currency_code as currencyCode, ").append("sa.currency_digits as currencyDigits, ")
.append("sa.currency_multiplesof as inMultiplesOf, ").append("rc.`name` as currencyName, ")
.append("sa.currency_multiplesof as inMultiplesOf, ").append("rc." + sqlGenerator.escape("name") + " as currencyName, ")
.append("rc.display_symbol as currencyDisplaySymbol, ")
.append("(CASE WHEN sa.deposit_type_enum=100 THEN 'Saving Deposit' ELSE (CASE WHEN sa.deposit_type_enum=300 THEN 'Recurring Deposit' ELSE 'Current Deposit' END) END) as depositAccountType, ")
.append("rc.internationalized_name_code as currencyNameCode, ")
@@ -511,7 +528,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
.append("JOIN m_savings_product sp ON sa.product_id=sp.id ")
.append("LEFT JOIN m_deposit_account_recurring_detail dard ON sa.id = dard.savings_account_id AND dard.is_mandatory = true AND dard.is_calendar_inherited = true ")
.append("LEFT JOIN m_mandatory_savings_schedule mss ON mss.savings_account_id=sa.id AND mss.duedate <= :dueDate ")
.append("LEFT JOIN m_currency rc on rc.`code` = sa.currency_code ");
.append("LEFT JOIN m_currency rc on rc." + sqlGenerator.escape("code") + " = sa.currency_code ");
if (isCenterCollection) {
sql.append("WHERE gp.parent_id = :centerId ");
@@ -680,7 +697,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
final boolean checkForStaffId = staffId != null;
final IndividualCollectionSheetFaltDataMapper mapper = new IndividualCollectionSheetFaltDataMapper(checkForOfficeId,
checkForStaffId);
checkForStaffId, sqlGenerator);
final SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("dueDate", transactionDateStr)
.addValue("officeHierarchy", officeHierarchy);
@@ -696,7 +713,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
.query(mapper.sqlSchema(), namedParameters, mapper);
IndividualMandatorySavingsCollectionsheetExtractor mandatorySavingsExtractor = new IndividualMandatorySavingsCollectionsheetExtractor(
checkForOfficeId, checkForStaffId);
checkForOfficeId, checkForStaffId, sqlGenerator);
// mandatory savings data for collection sheet
Collection<IndividualClientData> clientData = this.namedParameterjdbcTemplate
.query(mandatorySavingsExtractor.collectionSheetSchema(), namedParameters, mandatorySavingsExtractor);
@@ -714,15 +731,16 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
private final String sql;
IndividualCollectionSheetFaltDataMapper(final boolean checkForOfficeId, final boolean checkforStaffId) {
IndividualCollectionSheetFaltDataMapper(final boolean checkForOfficeId, final boolean checkforStaffId,
DatabaseSpecificSQLGenerator sqlGenerator) {
StringBuilder sb = new StringBuilder();
sb.append("SELECT loandata.*, sum(lc.amount_outstanding_derived) as chargesDue ");
sb.append("from (SELECT cl.display_name As clientName, ");
sb.append("cl.id As clientId, ln.id As loanId, ln.account_no As accountId, ln.loan_status_id As accountStatusId,");
sb.append(" pl.short_name As productShortName, ln.product_id As productId, ");
sb.append("ln.currency_code as currencyCode, ln.currency_digits as currencyDigits, ln.currency_multiplesof as inMultiplesOf, ");
sb.append(
"rc.`name` as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, ");
sb.append("rc." + sqlGenerator.escape("name")
+ " as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, ");
sb.append("(CASE WHEN ln.loan_status_id = 200 THEN ln.principal_amount ELSE null END) As disbursementAmount, ");
sb.append(
"sum(COALESCE((CASE WHEN ln.loan_status_id = 300 THEN ls.principal_amount ELSE 0.0 END), 0.0) - COALESCE((CASE WHEN ln.loan_status_id = 300 THEN ls.principal_completed_derived ELSE 0.0 END), 0.0)) As principalDue, ");
@@ -737,7 +755,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
sb.append("JOIN m_client cl ON cl.id = ln.client_id ");
sb.append("LEFT JOIN m_office of ON of.id = cl.office_id AND of.hierarchy like :officeHierarchy ");
sb.append("LEFT JOIN m_product_loan pl ON pl.id = ln.product_id ");
sb.append("LEFT JOIN m_currency rc on rc.`code` = ln.currency_code ");
sb.append("LEFT JOIN m_currency rc on rc." + sqlGenerator.escape("code") + " = ln.currency_code ");
sb.append("JOIN m_loan_repayment_schedule ls ON ls.loan_id = ln.id AND ls.completed_derived = 0 AND ls.duedate <= :dueDate ");
sb.append("where ");
if (checkForOfficeId) {
@@ -804,7 +822,8 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
private final String sql;
IndividualMandatorySavingsCollectionsheetExtractor(final boolean checkForOfficeId, final boolean checkforStaffId) {
IndividualMandatorySavingsCollectionsheetExtractor(final boolean checkForOfficeId, final boolean checkforStaffId,
DatabaseSpecificSQLGenerator sqlGenerator) {
final StringBuilder sb = new StringBuilder(400);
sb.append(
@@ -812,8 +831,8 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
sb.append("sa.id As savingsId, sa.account_no As accountId, sa.status_enum As accountStatusId, ");
sb.append("sp.short_name As productShortName, sp.id As productId, ");
sb.append("sa.currency_code as currencyCode, sa.currency_digits as currencyDigits, sa.currency_multiplesof as inMultiplesOf, ");
sb.append(
"rc.`name` as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, ");
sb.append("rc." + sqlGenerator.escape("name")
+ " as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, ");
sb.append("SUM(COALESCE(mss.deposit_amount,0) - coalesce(mss.deposit_amount_completed_derived,0)) as dueAmount ");
sb.append("FROM m_savings_account sa ");
sb.append("JOIN m_client cl ON cl.id = sa.client_id ");
@@ -823,7 +842,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
sb.append(
"LEFT JOIN m_mandatory_savings_schedule mss ON mss.savings_account_id=sa.id AND mss.completed_derived = 0 AND mss.duedate <= :dueDate ");
sb.append("LEFT JOIN m_office of ON of.id = cl.office_id AND of.hierarchy like :officeHierarchy ");
sb.append("LEFT JOIN m_currency rc on rc.`code` = sa.currency_code ");
sb.append("LEFT JOIN m_currency rc on rc." + sqlGenerator.escape("code") + " = sa.currency_code ");
sb.append("WHERE sa.status_enum=300 and sa.group_id is null and sa.deposit_type_enum in (100,300,400) ");
sb.append("and (cl.status_enum = 300 or (cl.status_enum = 600 and cl.closedon_date >= :dueDate)) ");
if (checkForOfficeId) {
@@ -46,6 +46,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.infrastructure.security.utils.SQLBuilder;
@@ -94,7 +95,8 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
private final CenterDataMapper centerMapper = new CenterDataMapper();
private final GroupDataMapper groupDataMapper = new GroupDataMapper();
private final PaginationHelper<CenterData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final PaginationParametersDataValidator paginationParametersDataValidator;
private static final Set<String> SUPPORTED_ORDER_BY_VALUES = new HashSet<>(Arrays.asList("id", "name", "officeId", "officeName"));
@@ -104,7 +106,7 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
final StaffReadPlatformService staffReadPlatformService, final CodeValueReadPlatformService codeValueReadPlatformService,
final PaginationParametersDataValidator paginationParametersDataValidator,
final ConfigurationDomainService configurationDomainService, final CalendarReadPlatformService calendarReadPlatformService,
final ColumnValidator columnValidator) {
final ColumnValidator columnValidator, DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.context = context;
this.clientReadPlatformService = clientReadPlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource);
@@ -115,6 +117,8 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
this.configurationDomainService = configurationDomainService;
this.calendarReadPlatformService = calendarReadPlatformService;
this.columnValidator = columnValidator;
this.paginationHelper = paginationHelper;
this.sqlGenerator = sqlGenerator;
}
// 'g.' preffix because of ERROR 1052 (23000): Column 'column_name' in where
@@ -336,7 +340,7 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
final String hierarchySearchString = hierarchy + "%";
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(this.centerMapper.schema());
final SQLBuilder extraCriteria = getCenterExtraCriteria(this.centerMapper.schema(), searchParameters);
extraCriteria.addNonNullCriteria("o.hierarchy like ", hierarchySearchString);
@@ -349,15 +353,15 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
}
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), extraCriteria.getArguments(),
this.centerMapper);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), extraCriteria.getArguments(), this.centerMapper);
}
@Override
@@ -383,9 +387,11 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
}
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
}
@@ -35,6 +35,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.infrastructure.security.utils.SQLBuilder;
@@ -67,7 +68,8 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
private final CodeValueReadPlatformService codeValueReadPlatformService;
private final AllGroupTypesDataMapper allGroupTypesDataMapper = new AllGroupTypesDataMapper();
private final PaginationHelper<GroupGeneralData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final PaginationParametersDataValidator paginationParametersDataValidator;
private final ColumnValidator columnValidator;
@@ -77,7 +79,8 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
public GroupReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
final CenterReadPlatformService centerReadPlatformService, final OfficeReadPlatformService officeReadPlatformService,
final StaffReadPlatformService staffReadPlatformService, final CodeValueReadPlatformService codeValueReadPlatformService,
final PaginationParametersDataValidator paginationParametersDataValidator, final ColumnValidator columnValidator) {
final PaginationParametersDataValidator paginationParametersDataValidator, final ColumnValidator columnValidator,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.centerReadPlatformService = centerReadPlatformService;
@@ -86,6 +89,8 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
this.codeValueReadPlatformService = codeValueReadPlatformService;
this.paginationParametersDataValidator = paginationParametersDataValidator;
this.columnValidator = columnValidator;
this.paginationHelper = paginationHelper;
this.sqlGenerator = sqlGenerator;
}
@Override
@@ -144,7 +149,7 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
final String hierarchySearchString = hierarchy + "%";
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(this.allGroupTypesDataMapper.schema());
final SQLBuilder extraCriteria = getGroupExtraCriteria(this.allGroupTypesDataMapper.schema(), searchParameters);
@@ -163,8 +168,7 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
}
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), extraCriteria.getArguments(),
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), extraCriteria.getArguments(),
this.allGroupTypesDataMapper);
}
@@ -30,6 +30,7 @@ import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformSer
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.client.api.ClientApiConstants;
@@ -54,21 +55,24 @@ public class InterestRateChartReadPlatformServiceImpl implements InterestRateCha
private final PlatformSecurityContext context;
private final JdbcTemplate jdbcTemplate;
private final InterestRateChartMapper chartRowMapper = new InterestRateChartMapper();
private final InterestRateChartExtractor chartExtractor = new InterestRateChartExtractor();
private final InterestRateChartExtractor chartExtractor;
private final InterestRateChartDropdownReadPlatformService chartDropdownReadPlatformService;
private final InterestIncentiveDropdownReadPlatformService interestIncentiveDropdownReadPlatformService;
private final CodeValueReadPlatformService codeValueReadPlatformService;
private final DatabaseSpecificSQLGenerator sqlGenerator;
@Autowired
public InterestRateChartReadPlatformServiceImpl(PlatformSecurityContext context, final RoutingDataSource dataSource,
InterestRateChartDropdownReadPlatformService chartDropdownReadPlatformService,
final InterestIncentiveDropdownReadPlatformService interestIncentiveDropdownReadPlatformService,
final CodeValueReadPlatformService codeValueReadPlatformService) {
final CodeValueReadPlatformService codeValueReadPlatformService, DatabaseSpecificSQLGenerator sqlGenerator) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.chartDropdownReadPlatformService = chartDropdownReadPlatformService;
this.interestIncentiveDropdownReadPlatformService = interestIncentiveDropdownReadPlatformService;
this.codeValueReadPlatformService = codeValueReadPlatformService;
this.sqlGenerator = sqlGenerator;
chartExtractor = new InterestRateChartExtractor(this.sqlGenerator);
}
@Override
@@ -180,7 +184,7 @@ public class InterestRateChartReadPlatformServiceImpl implements InterestRateCha
private static final class InterestRateChartExtractor implements ResultSetExtractor<Collection<InterestRateChartData>> {
InterestRateChartMapper chartMapper = new InterestRateChartMapper();
InterestRateChartSlabExtractor chartSlabsMapper = new InterestRateChartSlabExtractor();
InterestRateChartSlabExtractor chartSlabsMapper;
private final String schemaSql;
@@ -188,7 +192,8 @@ public class InterestRateChartReadPlatformServiceImpl implements InterestRateCha
return this.schemaSql;
}
private InterestRateChartExtractor() {
private InterestRateChartExtractor(DatabaseSpecificSQLGenerator sqlGenerator) {
chartSlabsMapper = new InterestRateChartSlabExtractor(sqlGenerator);
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("irc.id as ircId, irc.name as ircName, irc.description as ircDescription,")
@@ -206,7 +211,7 @@ public class InterestRateChartReadPlatformServiceImpl implements InterestRateCha
.append("from ")
.append("m_interest_rate_chart irc left join m_interest_rate_slab ircd on irc.id=ircd.interest_rate_chart_id ")
.append(" left join m_interest_incentives iri on iri.interest_rate_slab_id = ircd.id ")
.append(" left join m_code_value code on code.id = iri.attribute_value ")
.append(" left join m_code_value code on " + sqlGenerator.castChar("code.id") + " = iri.attribute_value ")
.append("left join m_currency curr on ircd.currency_code= curr.code ")
.append("left join m_deposit_product_interest_rate_chart dpirc on irc.id=dpirc.interest_rate_chart_id ")
.append("left join m_savings_product sp on sp.id=dpirc.deposit_product_id ");
@@ -289,7 +294,7 @@ public class InterestRateChartReadPlatformServiceImpl implements InterestRateCha
return this.schemaSql;
}
private InterestRateChartSlabsMapper() {
private InterestRateChartSlabsMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("ircd.id as ircdId, ircd.description as ircdDescription, ircd.period_type_enum ircdPeriodTypeId, ").append(
@@ -302,7 +307,7 @@ public class InterestRateChartReadPlatformServiceImpl implements InterestRateCha
.append(" iri.incentive_type as incentiveType, iri.amount as amount, ").append("code.code_value as attributeValueDesc ")
.append("from ").append("m_interest_rate_slab ircd ")
.append(" left join m_interest_incentives iri on iri.interest_rate_slab_id = ircd.id ")
.append(" left join m_code_value code on code.id = iri.attribute_value ")
.append(" left join m_code_value code on " + sqlGenerator.castChar("code.id") + " = iri.attribute_value ")
.append("left join m_currency curr on ircd.currency_code= curr.code ");
this.schemaSql = sqlBuilder.toString();
}
@@ -347,7 +352,7 @@ public class InterestRateChartReadPlatformServiceImpl implements InterestRateCha
private static final class InterestRateChartSlabExtractor implements ResultSetExtractor<InterestRateChartSlabData> {
InterestRateChartSlabsMapper chartSlabsMapper = new InterestRateChartSlabsMapper();
InterestRateChartSlabsMapper chartSlabsMapper;
InterestIncentiveMapper incentiveMapper = new InterestIncentiveMapper();
private final String schemaSql;
@@ -357,7 +362,8 @@ public class InterestRateChartReadPlatformServiceImpl implements InterestRateCha
return this.schemaSql;
}
private InterestRateChartSlabExtractor() {
private InterestRateChartSlabExtractor(DatabaseSpecificSQLGenerator sqlGenerator) {
chartSlabsMapper = new InterestRateChartSlabsMapper(sqlGenerator);
this.schemaSql = chartSlabsMapper.schema();
}
@@ -29,6 +29,7 @@ import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformSer
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.client.api.ClientApiConstants;
@@ -49,21 +50,24 @@ public class InterestRateChartSlabReadPlatformServiceImpl implements InterestRat
private final PlatformSecurityContext context;
private final JdbcTemplate jdbcTemplate;
private final InterestRateChartSlabExtractor chartSlabExtractor = new InterestRateChartSlabExtractor();
private final InterestRateChartSlabExtractor chartSlabExtractor;
private final InterestRateChartDropdownReadPlatformService chartDropdownReadPlatformService;
private final InterestIncentiveDropdownReadPlatformService interestIncentiveDropdownReadPlatformService;
private final CodeValueReadPlatformService codeValueReadPlatformService;
private final DatabaseSpecificSQLGenerator sqlGenerator;
@Autowired
public InterestRateChartSlabReadPlatformServiceImpl(PlatformSecurityContext context, final RoutingDataSource dataSource,
InterestRateChartDropdownReadPlatformService chartDropdownReadPlatformService,
final InterestIncentiveDropdownReadPlatformService interestIncentiveDropdownReadPlatformService,
final CodeValueReadPlatformService codeValueReadPlatformService) {
final CodeValueReadPlatformService codeValueReadPlatformService, DatabaseSpecificSQLGenerator sqlGenerator) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.chartDropdownReadPlatformService = chartDropdownReadPlatformService;
this.interestIncentiveDropdownReadPlatformService = interestIncentiveDropdownReadPlatformService;
this.codeValueReadPlatformService = codeValueReadPlatformService;
this.sqlGenerator = sqlGenerator;
chartSlabExtractor = new InterestRateChartSlabExtractor(sqlGenerator);
}
@Override
@@ -131,7 +135,7 @@ public class InterestRateChartSlabReadPlatformServiceImpl implements InterestRat
return this.schemaSql;
}
private InterestRateChartSlabsMapper() {
private InterestRateChartSlabsMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("ircd.id as ircdId, ircd.description as ircdDescription, ircd.period_type_enum ircdPeriodTypeId, ").append(
@@ -144,7 +148,7 @@ public class InterestRateChartSlabReadPlatformServiceImpl implements InterestRat
.append(" iri.incentive_type as incentiveType, iri.amount as amount, ").append("code.code_value as attributeValueDesc ")
.append("from ").append("m_interest_rate_slab ircd ")
.append(" left join m_interest_incentives iri on iri.interest_rate_slab_id = ircd.id ")
.append(" left join m_code_value code on code.id = iri.attribute_value ")
.append(" left join m_code_value code on " + sqlGenerator.castChar("code.id") + " = iri.attribute_value ")
.append("left join m_currency curr on ircd.currency_code= curr.code ");
this.schemaSql = sqlBuilder.toString();
}
@@ -186,7 +190,7 @@ public class InterestRateChartSlabReadPlatformServiceImpl implements InterestRat
private static final class InterestRateChartSlabExtractor implements ResultSetExtractor<Collection<InterestRateChartSlabData>> {
InterestRateChartSlabsMapper chartSlabsMapper = new InterestRateChartSlabsMapper();
InterestRateChartSlabsMapper chartSlabsMapper;
InterestIncentiveMapper incentiveMapper = new InterestIncentiveMapper();
private final String schemaSql;
@@ -195,7 +199,8 @@ public class InterestRateChartSlabReadPlatformServiceImpl implements InterestRat
return this.schemaSql;
}
private InterestRateChartSlabExtractor() {
private InterestRateChartSlabExtractor(DatabaseSpecificSQLGenerator sqlGenerator) {
chartSlabsMapper = new InterestRateChartSlabsMapper(sqlGenerator);
this.schemaSql = chartSlabsMapper.schema();
}
@@ -182,7 +182,7 @@ public class Loan extends AbstractPersistableCustom {
@Column(name = "loan_type_enum", nullable = false)
private Integer loanType;
@ManyToOne(fetch = FetchType.EAGER)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product_id", nullable = false)
private LoanProduct loanProduct;
@@ -323,7 +323,7 @@ public class Loan extends AbstractPersistableCustom {
private Set<LoanOfficerAssignmentHistory> loanOfficerHistory;
@OrderBy(value = "installmentNumber")
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true, fetch = FetchType.EAGER)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true, fetch = FetchType.LAZY)
private List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = new ArrayList<>();
@OrderBy(value = "dateOf, id")
@@ -362,7 +362,7 @@ public class Loan extends AbstractPersistableCustom {
@OrderBy(value = "expectedDisbursementDate, id")
private List<LoanDisbursementDetails> disbursementDetails = new ArrayList<>();
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true, fetch = FetchType.EAGER)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true, fetch = FetchType.LAZY)
private List<PostDatedChecks> postDatedChecks = new ArrayList<>();
@OrderBy(value = "termApplicableFrom, id")
@@ -372,7 +372,7 @@ public class Loan extends AbstractPersistableCustom {
@Column(name = "total_recovered_derived", scale = 6, precision = 19)
private BigDecimal totalRecovered;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "loan", optional = true, orphanRemoval = true, fetch = FetchType.EAGER)
@OneToOne(cascade = CascadeType.ALL, mappedBy = "loan", optional = true, orphanRemoval = true, fetch = FetchType.LAZY)
private LoanInterestRecalculationDetails loanInterestRecalculationDetails;
@Column(name = "is_npa", nullable = false)
@@ -408,7 +408,7 @@ public class Loan extends AbstractPersistableCustom {
@Column(name = "is_topup", nullable = false)
private boolean isTopup = false;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "loan", optional = true, orphanRemoval = true, fetch = FetchType.EAGER)
@OneToOne(cascade = CascadeType.ALL, mappedBy = "loan", optional = true, orphanRemoval = true, fetch = FetchType.LAZY)
private LoanTopupDetails loanTopupDetails;
@OneToMany(fetch = FetchType.LAZY)
@@ -57,8 +57,10 @@ import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundEx
import org.apache.fineract.portfolio.loanproduct.serialization.LoanProductDataValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleCalculationPlatformService {
private final CalculateLoanScheduleQueryFromApiJsonHelper fromApiJsonDeserializer;
@@ -205,6 +207,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
}
@Override
@Transactional(readOnly = true)
public LoanScheduleData generateLoanScheduleForVariableInstallmentRequest(Long loanId, final String json) {
final Loan loan = this.loanAssembler.assembleFrom(loanId);
this.loanScheduleAssembler.assempleVariableScheduleFrom(loan, json);
@@ -43,8 +43,10 @@ import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional(readOnly = true)
public class LoanScheduleHistoryReadPlatformServiceImpl implements LoanScheduleHistoryReadPlatformService {
private final JdbcTemplate jdbcTemplate;
@@ -32,8 +32,10 @@ import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanResch
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class LoanScheduleHistoryWritePlatformServiceImpl implements LoanScheduleHistoryWritePlatformService {
private final LoanScheduleHistoryReadPlatformService loanScheduleHistoryReadPlatformService;
@@ -37,8 +37,10 @@ import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class LoanScheduleWritePlatformServiceImpl implements LoanScheduleWritePlatformService {
private final LoanAccountDomainService loanAccountDomainService;
@@ -34,6 +34,7 @@ import javax.sql.DataSource;
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
@@ -63,6 +64,7 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
private final LoanChargeReadPlatformService loanChargeReadPlatformService;
private final JdbcTemplate jdbcTemplate;
private final DataSource dataSource;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
private final AppUserRepositoryWrapper userRepository;
private final LoanRepositoryWrapper loanRepositoryWrapper;
@@ -72,9 +74,11 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
public LoanAccrualWritePlatformServiceImpl(final RoutingDataSource dataSource, final LoanReadPlatformService loanReadPlatformService,
final JournalEntryWritePlatformService journalEntryWritePlatformService,
final LoanChargeReadPlatformService loanChargeReadPlatformService, final AppUserRepositoryWrapper userRepository,
final LoanRepositoryWrapper loanRepositoryWrapper, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository) {
final LoanRepositoryWrapper loanRepositoryWrapper, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
DatabaseSpecificSQLGenerator sqlGenerator) {
this.loanReadPlatformService = loanReadPlatformService;
this.dataSource = dataSource;
this.sqlGenerator = sqlGenerator;
this.jdbcTemplate = new JdbcTemplate(this.dataSource);
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
this.loanChargeReadPlatformService = loanChargeReadPlatformService;
@@ -274,7 +278,7 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
LoanTransactionType.ACCRUAL.getValue(), Date.from(accruedTill.atStartOfDay(ZoneId.systemDefault()).toInstant()), amount,
interestportion, feeportion, penaltyportion, DateUtils.getDateOfTenant());
@SuppressWarnings("deprecation")
final Long transactonId = this.jdbcTemplate.queryForObject("SELECT LAST_INSERT_ID()", Long.class);
final Long transactonId = this.jdbcTemplate.queryForObject("SELECT " + sqlGenerator.lastInsertId(), Long.class);
Map<LoanChargeData, BigDecimal> applicableCharges = scheduleAccrualData.getApplicableCharges();
String chargespaidSql = "INSERT INTO m_loan_charge_paid_by (loan_transaction_id, loan_charge_id, amount,installment_number) VALUES (?,?,?,?)";
@@ -32,6 +32,7 @@ import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.jobs.annotation.CronTarget;
import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BusinessEntity;
@@ -58,14 +59,16 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService, Bus
private static final Logger LOG = LoggerFactory.getLogger(LoanArrearsAgingServiceImpl.class);
private final BusinessEventNotifierService businessEventNotifierService;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private final JdbcTemplate jdbcTemplate;
@Autowired
public LoanArrearsAgingServiceImpl(final RoutingDataSource dataSource,
final BusinessEventNotifierService businessEventNotifierService) {
public LoanArrearsAgingServiceImpl(final RoutingDataSource dataSource, final BusinessEventNotifierService businessEventNotifierService,
DatabaseSpecificSQLGenerator sqlGenerator) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.businessEventNotifierService = businessEventNotifierService;
this.sqlGenerator = sqlGenerator;
}
@PostConstruct
@@ -114,7 +117,8 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService, Bus
updateSqlBuilder.append(" left join m_product_loan_recalculation_details prd on prd.product_id = ml.product_id ");
updateSqlBuilder.append(" WHERE ml.loan_status_id = 300 "); // active
updateSqlBuilder.append(" and mr.completed_derived is false ");
updateSqlBuilder.append(" and mr.duedate < SUBDATE(CURDATE(),INTERVAL COALESCE(ml.grace_on_arrears_ageing, 0) day) ");
updateSqlBuilder.append(" and mr.duedate < ")
.append(sqlGenerator.subDate(sqlGenerator.currentDate(), "COALESCE(ml.grace_on_arrears_ageing, 0)", "day")).append(" ");
updateSqlBuilder.append(" and (prd.arrears_based_on_original_schedule = false or prd.arrears_based_on_original_schedule is null) ");
updateSqlBuilder.append(" GROUP BY ml.id");
@@ -134,7 +138,7 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService, Bus
int count = this.jdbcTemplate.queryForObject("select count(mla.loan_id) from m_loan_arrears_aging mla where mla.loan_id =?",
Integer.class, loan.getId());
List<String> updateStatement = new ArrayList<>();
OriginalScheduleExtractor originalScheduleExtractor = new OriginalScheduleExtractor(loan.getId().toString());
OriginalScheduleExtractor originalScheduleExtractor = new OriginalScheduleExtractor(loan.getId().toString(), sqlGenerator);
Map<Long, List<LoanSchedulePeriodData>> scheduleDate = this.jdbcTemplate.query(originalScheduleExtractor.schema,
originalScheduleExtractor);
if (scheduleDate.size() > 0) {
@@ -204,13 +208,14 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService, Bus
loanIdentifier.append("INNER JOIN m_loan_repayment_schedule mr on mr.loan_id = ml.id ");
loanIdentifier.append(
"inner join m_product_loan_recalculation_details prd on prd.product_id = ml.product_id and prd.arrears_based_on_original_schedule = true ");
loanIdentifier.append(
"WHERE ml.loan_status_id = 300 and mr.completed_derived is false and mr.duedate < SUBDATE(CURDATE(),INTERVAL COALESCE(ml.grace_on_arrears_ageing, 0) day) group by ml.id");
loanIdentifier.append("WHERE ml.loan_status_id = 300 and mr.completed_derived is false and mr.duedate < ")
.append(sqlGenerator.subDate(sqlGenerator.currentDate(), "COALESCE(ml.grace_on_arrears_ageing, 0)", "day"))
.append(" group by ml.id");
List<Long> loanIds = this.jdbcTemplate.queryForList(loanIdentifier.toString(), Long.class);
if (!loanIds.isEmpty()) {
String loanIdsAsString = loanIds.toString();
loanIdsAsString = loanIdsAsString.substring(1, loanIdsAsString.length() - 1);
OriginalScheduleExtractor originalScheduleExtractor = new OriginalScheduleExtractor(loanIdsAsString);
OriginalScheduleExtractor originalScheduleExtractor = new OriginalScheduleExtractor(loanIdsAsString, sqlGenerator);
Map<Long, List<LoanSchedulePeriodData>> scheduleDate = this.jdbcTemplate.query(originalScheduleExtractor.schema,
originalScheduleExtractor);
@@ -419,13 +424,14 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService, Bus
private final String schema;
OriginalScheduleExtractor(final String loanIdsAsString) {
OriginalScheduleExtractor(final String loanIdsAsString, DatabaseSpecificSQLGenerator sqlGenerator) {
final StringBuilder scheduleDetail = new StringBuilder();
scheduleDetail.append("select ml.id as loanId, mr.duedate as dueDate, mr.principal_amount as principalAmount, ");
scheduleDetail.append(
"mr.interest_amount as interestAmount, mr.fee_charges_amount as feeAmount, mr.penalty_charges_amount as penaltyAmount ");
scheduleDetail.append("from m_loan ml INNER JOIN m_loan_repayment_schedule_history mr on mr.loan_id = ml.id ");
scheduleDetail.append("where mr.duedate < SUBDATE(CURDATE(),INTERVAL COALESCE(ml.grace_on_arrears_ageing, 0) day) and ");
scheduleDetail.append("where mr.duedate < "
+ sqlGenerator.subDate(sqlGenerator.currentDate(), "COALESCE(ml.grace_on_arrears_ageing, 0)", "day") + " and ");
scheduleDetail.append("ml.id IN(").append(loanIdsAsString).append(") and mr.version = (");
scheduleDetail.append("select max(lrs.version) from m_loan_repayment_schedule_history lrs where mr.loan_id = lrs.loan_id");
scheduleDetail.append(") order by ml.id,mr.duedate");
@@ -47,6 +47,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
@@ -129,9 +130,11 @@ import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@Service
@Transactional(readOnly = true)
public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
private final JdbcTemplate jdbcTemplate;
@@ -147,8 +150,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
private final CodeValueReadPlatformService codeValueReadPlatformService;
private final CalendarReadPlatformService calendarReadPlatformService;
private final StaffReadPlatformService staffReadPlatformService;
private final PaginationHelper<LoanAccountData> paginationHelper = new PaginationHelper<>();
private final LoanMapper loaanLoanMapper = new LoanMapper();
private final PaginationHelper paginationHelper;
private final LoanMapper loaanLoanMapper;
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
@@ -158,6 +161,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
private final ConfigurationDomainService configurationDomainService;
private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
private final ColumnValidator columnValidator;
private final DatabaseSpecificSQLGenerator sqlGenerator;
@Autowired
public LoanReadPlatformServiceImpl(final PlatformSecurityContext context,
@@ -172,7 +176,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final FloatingRatesReadPlatformService floatingRatesReadPlatformService, final LoanUtilService loanUtilService,
final ConfigurationDomainService configurationDomainService,
final AccountDetailsReadPlatformService accountDetailsReadPlatformService, final LoanRepositoryWrapper loanRepositoryWrapper,
final ColumnValidator columnValidator) {
final ColumnValidator columnValidator, DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.context = context;
this.loanRepositoryWrapper = loanRepositoryWrapper;
this.applicationCurrencyRepository = applicationCurrencyRepository;
@@ -194,6 +198,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
this.configurationDomainService = configurationDomainService;
this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
this.columnValidator = columnValidator;
this.loaanLoanMapper = new LoanMapper(sqlGenerator);
this.sqlGenerator = sqlGenerator;
this.paginationHelper = paginationHelper;
}
@Override
@@ -204,7 +211,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final String hierarchy = currentUser.getOffice().getHierarchy();
final String hierarchySearchString = hierarchy + "%";
final LoanMapper rm = new LoanMapper();
final LoanMapper rm = new LoanMapper(sqlGenerator);
final StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("select ");
@@ -225,7 +232,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
// final AppUser currentUser = this.context.authenticatedUser();
this.context.authenticatedUser();
final LoanMapper rm = new LoanMapper();
final LoanMapper rm = new LoanMapper(sqlGenerator);
String sql = "select " + rm.loanSchema() + " where l.account_no=?";
@@ -238,7 +245,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
// final AppUser currentUser = this.context.authenticatedUser();
this.context.authenticatedUser();
final LoanMapper rm = new LoanMapper();
final LoanMapper rm = new LoanMapper(sqlGenerator);
String sql = "select " + rm.loanSchema()
+ " left join glim_parent_child_mapping as glim on glim.glim_child_account_id=l.account_no "
@@ -271,7 +278,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
try {
this.context.authenticatedUser();
final LoanTransactionsMapper rm = new LoanTransactionsMapper();
final LoanTransactionsMapper rm = new LoanTransactionsMapper(sqlGenerator);
// retrieve all loan transactions that are not invalid and have not
// been 'contra'ed by another transaction
@@ -296,7 +303,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final String hierarchySearchString = hierarchy + "%";
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(this.loaanLoanMapper.loanSchema());
// TODO - for time being this will data scope list of loans returned to
@@ -351,17 +358,17 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
}
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
}
final Object[] objectArray = extraCriterias.toArray();
final Object[] finalObjectArray = Arrays.copyOf(objectArray, arrayPos);
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), finalObjectArray,
this.loaanLoanMapper);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), finalObjectArray, this.loaanLoanMapper);
}
@Override
@@ -432,7 +439,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
this.context.authenticatedUser();
RepaymentTransactionTemplateMapper mapper = new RepaymentTransactionTemplateMapper();
RepaymentTransactionTemplateMapper mapper = new RepaymentTransactionTemplateMapper(sqlGenerator);
String sql = "select " + mapper.schema();
LoanTransactionData loanTransactionData = this.jdbcTemplate.queryForObject(sql, mapper,
new Object[] { LoanTransactionType.REPAYMENT.getValue(), loanId, loanId });
@@ -574,7 +581,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
public LoanTransactionData retrieveLoanTransaction(final Long loanId, final Long transactionId) {
this.context.authenticatedUser();
try {
final LoanTransactionsMapper rm = new LoanTransactionsMapper();
final LoanTransactionsMapper rm = new LoanTransactionsMapper(sqlGenerator);
final String sql = "select " + rm.loanPaymentsSchema() + " where l.id = ? and tr.id = ? ";
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { loanId, transactionId });
} catch (final EmptyResultDataAccessException e) {
@@ -584,6 +591,12 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
private static final class LoanMapper implements RowMapper<LoanAccountData> {
private final DatabaseSpecificSQLGenerator sqlGenerator;
LoanMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
this.sqlGenerator = sqlGenerator;
}
public String loanSchema() {
return "l.id as id, l.account_no as accountNo, l.external_id as externalId, l.fund_id as fundId, f.name as fundName,"
+ " l.loan_type_enum as loanType, l.loanpurpose_cv_id as loanPurposeId, cv.code_value as loanPurposeName,"
@@ -614,7 +627,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
+ " l.allow_partial_period_interest_calcualtion as allowPartialPeriodInterestCalcualtion,"
+ " l.loan_status_id as lifeCycleStatusId, l.loan_transaction_strategy_id as transactionStrategyId, "
+ " lps.name as transactionStrategyName, "
+ " l.currency_code as currencyCode, l.currency_digits as currencyDigits, l.currency_multiplesof as inMultiplesOf, rc.`name` as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, "
+ " l.currency_code as currencyCode, l.currency_digits as currencyDigits, l.currency_multiplesof as inMultiplesOf, rc."
+ sqlGenerator.escape("name")
+ " as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, "
+ " l.loan_officer_id as loanOfficerId, s.display_name as loanOfficerName, "
+ " l.principal_disbursed_derived as principalDisbursed," + " l.principal_repaid_derived as principalPaid,"
+ " l.principal_writtenoff_derived as principalWrittenOff,"
@@ -664,8 +679,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
+ " l.total_recovered_derived as totalRecovered" + ", topuploan.account_no as closureLoanAccountNo, "
+ " topup.topup_amount as topupAmount " + " from m_loan l" //
+ " join m_product_loan lp on lp.id = l.product_id" //
+ " left join m_loan_recalculation_details lir on lir.loan_id = l.id "
+ " join m_currency rc on rc.`code` = l.currency_code" //
+ " left join m_loan_recalculation_details lir on lir.loan_id = l.id " + " join m_currency rc on rc."
+ sqlGenerator.escape("code") + " = l.currency_code" //
+ " left join m_client c on c.id = l.client_id" //
+ " left join m_group g on g.id = l.group_id" //
+ " left join m_loan_arrears_aging la on la.loan_id = l.id" //
@@ -1286,17 +1301,24 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
private static final class LoanTransactionsMapper implements RowMapper<LoanTransactionData> {
private final DatabaseSpecificSQLGenerator sqlGenerator;
LoanTransactionsMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
this.sqlGenerator = sqlGenerator;
}
public String loanPaymentsSchema() {
return " tr.id as id, tr.transaction_type_enum as transactionType, tr.transaction_date as `date`, tr.amount as total, "
+ " tr.principal_portion_derived as principal, tr.interest_portion_derived as interest, "
return " tr.id as id, tr.transaction_type_enum as transactionType, tr.transaction_date as " + sqlGenerator.escape("date")
+ ", tr.amount as total, " + " tr.principal_portion_derived as principal, tr.interest_portion_derived as interest, "
+ " tr.fee_charges_portion_derived as fees, tr.penalty_charges_portion_derived as penalties, "
+ " tr.overpayment_portion_derived as overpayment, tr.outstanding_loan_balance_derived as outstandingLoanBalance, "
+ " tr.unrecognized_income_portion as unrecognizedIncome," + " tr.submitted_on_date as submittedOnDate, "
+ " tr.manually_adjusted_or_reversed as manuallyReversed, "
+ " 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, l.net_disbursal_amount as netDisbursalAmount,"
+ " l.currency_code as currencyCode, l.currency_digits as currencyDigits, l.currency_multiplesof as inMultiplesOf, rc.`name` as currencyName, "
+ " l.currency_code as currencyCode, l.currency_digits as currencyDigits, l.currency_multiplesof as inMultiplesOf, rc."
+ sqlGenerator.escape("name") + " as currencyName, "
+ " rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, "
+ " pt.value as paymentTypeName, tr.external_id as externalId, tr.office_id as officeId, office.name as officeName, "
+ " fromtran.id as fromTransferId, fromtran.is_reversed as fromTransferReversed,"
@@ -1305,7 +1327,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
+ " totran.id as toTransferId, totran.is_reversed as toTransferReversed,"
+ " totran.transaction_date as toTransferDate, totran.amount as toTransferAmount,"
+ " totran.description as toTransferDescription " + " from m_loan l join m_loan_transaction tr on tr.loan_id = l.id"
+ " join m_currency rc on rc.`code` = l.currency_code "
+ " join m_currency rc on rc." + sqlGenerator.escape("code") + " = l.currency_code "
+ " 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_office office on office.id=tr.office_id"
+ " left join m_account_transfer_transaction fromtran on fromtran.from_loan_transaction_id = tr.id "
@@ -1529,7 +1551,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final MusoniOverdueLoanScheduleMapper rm = new MusoniOverdueLoanScheduleMapper();
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("select ").append(rm.schema()).append(" where DATE_SUB(CURDATE(),INTERVAL ? DAY) > ls.duedate ")
sqlBuilder.append("select ").append(rm.schema())
.append(" where " + sqlGenerator.subDate(sqlGenerator.currentDate(), "?", "day") + " > ls.duedate ")
.append(" and ls.completed_derived <> true and mc.charge_applies_to_enum =1 ")
.append(" and ls.recalculated_interest_component <> true ")
.append(" and mc.charge_time_enum = 9 and ml.loan_status_id = 300 ");
@@ -1539,7 +1562,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
}
// Only apply for duedate = yesterday (so that we don't apply
// penalties on the duedate itself)
sqlBuilder.append(" and ls.duedate >= DATE_SUB(CURDATE(),INTERVAL (? + 1) DAY)");
sqlBuilder.append(" and ls.duedate >= " + sqlGenerator.subDate(sqlGenerator.currentDate(), "(? + 1)", "day"));
return this.jdbcTemplate.query(sqlBuilder.toString(), rm, new Object[] { penaltyWaitPeriod, penaltyWaitPeriod });
}
@@ -1560,7 +1583,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
@Override
public Collection<DisbursementData> retrieveLoanDisbursementDetails(final Long loanId) {
final LoanDisbursementDetailMapper rm = new LoanDisbursementDetailMapper();
final LoanDisbursementDetailMapper rm = new LoanDisbursementDetailMapper(sqlGenerator);
final String sql = "select " + rm.schema()
+ " where dd.loan_id=? group by dd.id, lc.amount_waived_derived order by dd.expected_disburse_date";
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
@@ -1568,8 +1591,15 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
private static final class LoanDisbursementDetailMapper implements RowMapper<DisbursementData> {
private final DatabaseSpecificSQLGenerator sqlGenerator;
LoanDisbursementDetailMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
this.sqlGenerator = sqlGenerator;
}
public String schema() {
return "dd.id as id,dd.expected_disburse_date as expectedDisbursementdate, dd.disbursedon_date as actualDisbursementdate,dd.principal as principal,dd.net_disbursal_amount as netDisbursalAmount,sum(lc.amount) chargeAmount, lc.amount_waived_derived waivedAmount,group_concat(lc.id) loanChargeId "
return "dd.id as id,dd.expected_disburse_date as expectedDisbursementdate, dd.disbursedon_date as actualDisbursementdate,dd.principal as principal,dd.net_disbursal_amount as netDisbursalAmount,sum(lc.amount) chargeAmount, lc.amount_waived_derived waivedAmount, "
+ sqlGenerator.groupConcat("lc.id") + " loanChargeId "
+ "from m_loan l inner join m_loan_disbursement_detail dd on dd.loan_id = l.id left join m_loan_tranche_disbursement_charge tdc on tdc.disbursement_detail_id=dd.id "
+ "left join m_loan_charge lc on lc.id=tdc.loan_charge_id and lc.is_active=true";
}
@@ -1596,7 +1626,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
@Override
public DisbursementData retrieveLoanDisbursementDetail(Long loanId, Long disbursementId) {
final LoanDisbursementDetailMapper rm = new LoanDisbursementDetailMapper();
final LoanDisbursementDetailMapper rm = new LoanDisbursementDetailMapper(sqlGenerator);
final String sql = "select " + rm.schema() + " where dd.loan_id=? and dd.id=? group by dd.id, lc.amount_waived_derived";
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { loanId, disbursementId });
}
@@ -1642,7 +1672,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
.append(" and (((ls.fee_charges_amount <> COALESCE(ls.accrual_fee_charges_derived, 0))")
.append(" or ( ls.penalty_charges_amount <> COALESCE(ls.accrual_penalty_charges_derived, 0))")
.append(" or ( ls.interest_amount <> COALESCE(ls.accrual_interest_derived, 0)))")
.append(" and loan.loan_status_id=:active and mpl.accounting_type=:type and loan.is_npa=false and ls.duedate <= CURDATE()) ");
.append(" and loan.loan_status_id=:active and mpl.accounting_type=:type and loan.is_npa=false and ls.duedate <= "
+ sqlGenerator.currentDate() + ") ");
if (organisationStartDate != null) {
sqlBuilder.append(" and ls.duedate > :organisationstartdate ");
}
@@ -1662,27 +1693,26 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
LoanSchedulePeriodicAccrualMapper mapper = new LoanSchedulePeriodicAccrualMapper();
Date organisationStartDate = this.configurationDomainService.retrieveOrganisationStartDate();
String formattedTillDate = formatter.format(tillDate);
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("select ").append(mapper.schema()).append(
" where (recaldet.is_compounding_to_be_posted_as_transaction is null or recaldet.is_compounding_to_be_posted_as_transaction = false) ")
.append(" and (((ls.fee_charges_amount <> COALESCE(ls.accrual_fee_charges_derived, 0))")
.append(" or (ls.penalty_charges_amount <> COALESCE(ls.accrual_penalty_charges_derived, 0))")
.append(" or (ls.interest_amount <> COALESCE(ls.accrual_interest_derived, 0)))")
.append(" and loan.loan_status_id=:active and mpl.accounting_type=:type and (loan.closedon_date <= :tilldate"
+ " or loan.closedon_date is null)")
.append(" and loan.is_npa=false and (ls.duedate <= :tilldate or (ls.duedate > :tilldate"
+ " and ls.fromdate < :tilldate))) ");
.append(" and loan.loan_status_id=:active and mpl.accounting_type=:type and (loan.closedon_date <= '" + formattedTillDate
+ "' or loan.closedon_date is null)")
.append(" and loan.is_npa=false and (ls.duedate <= '" + formattedTillDate + "' or (ls.duedate > '" + formattedTillDate
+ "' and ls.fromdate < '" + formattedTillDate + "'))) ");
if (organisationStartDate != null) {
sqlBuilder.append(" and ls.duedate > :organisationstartdate ");
String formattedOrganizationStartDate = formatter
.format(LocalDate.ofInstant(organisationStartDate.toInstant(), DateUtils.getDateTimeZoneOfTenant()));
sqlBuilder.append(" and ls.duedate > '" + formattedOrganizationStartDate + "' ");
}
sqlBuilder.append(" order by loan.id,ls.duedate ");
Map<String, Object> paramMap = new HashMap<>(4);
paramMap.put("active", LoanStatus.ACTIVE.getValue());
paramMap.put("type", AccountingRuleType.ACCRUAL_PERIODIC.getValue());
paramMap.put("tilldate", formatter.format(tillDate));
paramMap.put("organisationstartdate",
(organisationStartDate == null) ? formatter.format(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()))
: formatter.format(LocalDate.ofInstant(organisationStartDate.toInstant(), DateUtils.getDateTimeZoneOfTenant())));
return this.namedParameterJdbcTemplate.query(sqlBuilder.toString(), paramMap, mapper);
}
@@ -1879,6 +1909,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
@Override
public List<Long> fetchLoansForInterestRecalculation(Integer pageSize, Long maxLoanIdInList, String officeHierarchy) {
String currentdate = formatter.format(DateUtils.getLocalDateOfTenant());
// will look only for yesterday modified rates
String yesterday = formatter.format(DateUtils.getLocalDateOfTenant().minusDays(1));
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("SELECT ml.id FROM m_loan ml ");
sqlBuilder.append(" left join m_client mc on mc.id = ml.client_id ");
@@ -1893,19 +1926,20 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
sqlBuilder.append(" left join m_loan_reschedule_request lrr on lrr.loan_id = ml.id");
// this is to identify the applicable rates when base rate is changed
sqlBuilder.append(" left join m_floating_rates bfr on bfr.is_base_lending_rate = true");
sqlBuilder.append(" left join m_floating_rates_periods bfrp on bfr.id = bfrp.floating_rates_id and bfrp.created_date >= ?");
sqlBuilder.append(" left join m_floating_rates_periods bfrp on bfr.id = bfrp.floating_rates_id and bfrp.created_date >= '"
+ yesterday + "'");
sqlBuilder.append(" WHERE ml.loan_status_id = ? ");
sqlBuilder.append(" and ml.is_npa = false ");
sqlBuilder.append(" and ((");
sqlBuilder.append("ml.interest_recalculation_enabled = true ");
sqlBuilder.append(" and (ml.interest_recalcualated_on is null or ml.interest_recalcualated_on <> ?)");
sqlBuilder.append(" and (ml.interest_recalcualated_on is null or ml.interest_recalcualated_on <> '" + currentdate + "')");
sqlBuilder.append(" and ((");
sqlBuilder.append(" mr.completed_derived is false ");
sqlBuilder.append(" and mr.duedate < ? )");
sqlBuilder.append(" or dd.expected_disburse_date < ? )) ");
sqlBuilder.append(" and mr.duedate < '" + currentdate + "' )");
sqlBuilder.append(" or dd.expected_disburse_date < '" + currentdate + "' )) ");
sqlBuilder.append(" or (");
sqlBuilder.append(" fr.is_active = true and frp.is_active = true");
sqlBuilder.append(" and (frp.created_date >= ? or ");
sqlBuilder.append(" and (frp.created_date >= '" + yesterday + "' or ");
sqlBuilder
.append("(bfrp.id is not null and frp.is_differential_to_base_lending_rate = true and frp.from_date >= bfrp.from_date)) ");
sqlBuilder.append("and lrr.loan_id is null");
@@ -1914,12 +1948,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
sqlBuilder.append(" group by ml.id ");
sqlBuilder.append(" limit ? ");
try {
String currentdate = formatter.format(DateUtils.getLocalDateOfTenant());
// will look only for yesterday modified rates
String yesterday = formatter.format(DateUtils.getLocalDateOfTenant().minusDays(1));
return Collections.synchronizedList(this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class,
new Object[] { yesterday, LoanStatus.ACTIVE.getValue(), currentdate, currentdate, currentdate, yesterday,
maxLoanIdInList, officeHierarchy, pageSize }));
new Object[] { LoanStatus.ACTIVE.getValue(), maxLoanIdInList, officeHierarchy, pageSize }));
} catch (final EmptyResultDataAccessException e) {
return null;
}
@@ -1929,7 +1959,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
public Collection<LoanTransactionData> retrieveWaiverLoanTransactions(final Long loanId) {
try {
final LoanTransactionDerivedComponentMapper rm = new LoanTransactionDerivedComponentMapper();
final LoanTransactionDerivedComponentMapper rm = new LoanTransactionDerivedComponentMapper(sqlGenerator);
final String sql = "select " + rm.schema()
+ " where tr.loan_id = ? and tr.transaction_type_enum = ? and tr.is_reversed=false order by tr.transaction_date ASC,id ";
@@ -1947,10 +1977,16 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
private static final class LoanTransactionDerivedComponentMapper implements RowMapper<LoanTransactionData> {
private final DatabaseSpecificSQLGenerator sqlGenerator;
LoanTransactionDerivedComponentMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
this.sqlGenerator = sqlGenerator;
}
public String schema() {
return " tr.id as id, tr.transaction_type_enum as transactionType, tr.transaction_date as `date`, tr.amount as total, "
+ " tr.principal_portion_derived as principal, tr.interest_portion_derived as interest, "
return " tr.id as id, tr.transaction_type_enum as transactionType, tr.transaction_date as " + sqlGenerator.escape("date")
+ ", tr.amount as total, " + " tr.principal_portion_derived as principal, tr.interest_portion_derived as interest, "
+ " tr.fee_charges_portion_derived as fees, tr.penalty_charges_portion_derived as penalties, "
+ " tr.overpayment_portion_derived as overpayment, tr.outstanding_loan_balance_derived as outstandingLoanBalance, "
+ " tr.unrecognized_income_portion as unrecognizedIncome " + " from m_loan_transaction tr ";
@@ -2076,7 +2112,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
+ " + SUM(COALESCE(mr.interest_completed_derived, 0)) " + " + SUM(COALESCE(mr.fee_charges_completed_derived, 0)) "
+ " + SUM(COALESCE(mr.penalty_charges_completed_derived, 0))) as total_in_advance_derived "
+ " from m_loan ml INNER JOIN m_loan_repayment_schedule mr on mr.loan_id = ml.id "
+ " where ml.id=? and mr.duedate >= CURDATE() group by ml.id having "
+ " where ml.id=? and mr.duedate >= " + sqlGenerator.currentDate() + " group by ml.id having "
+ " (SUM(COALESCE(mr.principal_completed_derived, 0)) " + " + SUM(COALESCE(mr.interest_completed_derived, 0)) "
+ " + SUM(COALESCE(mr.fee_charges_completed_derived, 0)) "
+ "+ SUM(COALESCE(mr.penalty_charges_completed_derived, 0))) > 0";
@@ -2158,6 +2194,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
@Override
public Collection<Long> retrieveLoanIdsWithPendingIncomePostingTransactions() {
String currentdate = formatter.format(DateUtils.getLocalDateOfTenant());
StringBuilder sqlBuilder = new StringBuilder().append(" select distinct loan.id ").append(" from m_loan as loan ").append(
" inner join m_loan_recalculation_details as recdet on (recdet.loan_id = loan.id and recdet.is_compounding_to_be_posted_as_transaction is not null and recdet.is_compounding_to_be_posted_as_transaction = true) ")
.append(" inner join m_loan_repayment_schedule as repsch on repsch.loan_id = loan.id ")
@@ -2165,10 +2202,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
.append(" left join m_loan_transaction as trans on (trans.is_reversed <> true and trans.transaction_type_enum = 19 and trans.loan_id = loan.id and trans.transaction_date = adddet.effective_date) ")
.append(" where loan.loan_status_id = 300 ").append(" and loan.is_npa = false ")
.append(" and adddet.effective_date is not null ").append(" and trans.transaction_date is null ")
.append(" and adddet.effective_date < ? ");
.append(" and adddet.effective_date < '" + currentdate + "' ");
try {
String currentdate = formatter.format(DateUtils.getLocalDateOfTenant());
return this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class, new Object[] { currentdate });
return this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class);
} catch (final EmptyResultDataAccessException e) {
return null;
}
@@ -2222,8 +2258,13 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
private static final class RepaymentTransactionTemplateMapper implements RowMapper<LoanTransactionData> {
private final DatabaseSpecificSQLGenerator sqlGenerator;
private CurrencyMapper currencyMapper = new CurrencyMapper();
RepaymentTransactionTemplateMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
this.sqlGenerator = sqlGenerator;
}
public String schema() {
StringBuilder sqlBuilder = new StringBuilder();
@@ -2238,12 +2279,13 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
sqlBuilder.append(
"ls.penalty_charges_amount - coalesce(ls.penalty_charges_completed_derived,0) - coalesce(ls.penalty_charges_writtenoff_derived,0) - coalesce(ls.penalty_charges_waived_derived,0) as penaltyDue, ");
sqlBuilder.append(
"l.currency_code as currencyCode, l.currency_digits as currencyDigits, l.currency_multiplesof as inMultiplesOf, l.net_disbursal_amount as netDisbursalAmount, rc.`name` as currencyName, ");
"l.currency_code as currencyCode, l.currency_digits as currencyDigits, l.currency_multiplesof as inMultiplesOf, l.net_disbursal_amount as netDisbursalAmount, rc."
+ sqlGenerator.escape("name") + " as currencyName, ");
sqlBuilder.append("rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode ");
sqlBuilder.append("FROM m_loan l ");
sqlBuilder.append(
"LEFT JOIN m_loan_transaction tr ON tr.loan_id = l.id AND tr.transaction_type_enum = ? and tr.is_reversed = false ");
sqlBuilder.append("join m_currency rc on rc.`code` = l.currency_code ");
sqlBuilder.append("join m_currency rc on rc." + sqlGenerator.escape("code") + " = l.currency_code ");
sqlBuilder.append("JOIN m_loan_repayment_schedule ls ON ls.loan_id = l.id AND ls.completed_derived = 0 ");
sqlBuilder.append("join( ");
sqlBuilder.append("(select min(ls.duedate) datedue,ls.loan_id from m_loan_repayment_schedule ls ");
@@ -29,6 +29,7 @@ import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityType;
import org.apache.fineract.infrastructure.entityaccess.service.FineractEntityAccessUtil;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
@@ -58,17 +59,20 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
private final JdbcTemplate jdbcTemplate;
private final ChargeReadPlatformService chargeReadPlatformService;
private final RateReadService rateReadService;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final FineractEntityAccessUtil fineractEntityAccessUtil;
@Autowired
public LoanProductReadPlatformServiceImpl(final PlatformSecurityContext context,
final ChargeReadPlatformService chargeReadPlatformService, final RoutingDataSource dataSource,
final FineractEntityAccessUtil fineractEntityAccessUtil, final RateReadService rateReadService) {
final FineractEntityAccessUtil fineractEntityAccessUtil, final RateReadService rateReadService,
DatabaseSpecificSQLGenerator sqlGenerator) {
this.context = context;
this.chargeReadPlatformService = chargeReadPlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.fineractEntityAccessUtil = fineractEntityAccessUtil;
this.rateReadService = rateReadService;
this.sqlGenerator = sqlGenerator;
}
@Override
@@ -121,7 +125,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
this.context.authenticatedUser();
final LoanProductLookupMapper rm = new LoanProductLookupMapper();
final LoanProductLookupMapper rm = new LoanProductLookupMapper(sqlGenerator);
String sql = "select " + rm.schema();
@@ -143,7 +147,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
public Collection<LoanProductData> retrieveAllLoanProductsForLookup(final boolean activeOnly) {
this.context.authenticatedUser();
final LoanProductLookupMapper rm = new LoanProductLookupMapper();
final LoanProductLookupMapper rm = new LoanProductLookupMapper(sqlGenerator);
String sql = "select ";
if (activeOnly) {
@@ -479,12 +483,18 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
private static final class LoanProductLookupMapper implements RowMapper<LoanProductData> {
private final DatabaseSpecificSQLGenerator sqlGenerator;
LoanProductLookupMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
this.sqlGenerator = sqlGenerator;
}
public String schema() {
return "lp.id as id, lp.name as name, lp.allow_multiple_disbursals as multiDisburseLoan from m_product_loan lp";
}
public String activeOnlySchema() {
return schema() + " where (close_date is null or close_date >= CURDATE())";
return schema() + " where (close_date is null or close_date >= " + sqlGenerator.currentDate() + ")";
}
public String productMixSchema() {
@@ -563,7 +573,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
this.context.authenticatedUser();
final LoanProductLookupMapper rm = new LoanProductLookupMapper();
final LoanProductLookupMapper rm = new LoanProductLookupMapper(sqlGenerator);
String sql = "Select " + rm.productMixSchema();
@@ -583,7 +593,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
this.context.authenticatedUser();
final LoanProductLookupMapper rm = new LoanProductLookupMapper();
final LoanProductLookupMapper rm = new LoanProductLookupMapper(sqlGenerator);
String sql = "Select " + rm.restrictedProductsSchema() + " where pm.product_id=? ";
// Check if branch specific products are enabled. If yes, fetch only
@@ -612,7 +622,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
this.context.authenticatedUser();
final LoanProductLookupMapper rm = new LoanProductLookupMapper();
final LoanProductLookupMapper rm = new LoanProductLookupMapper(sqlGenerator);
String sql = "Select " + rm.schema() + " where ";
@@ -32,8 +32,10 @@ import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDat
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.exception.PostDatedCheckNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional(readOnly = true)
public class RepaymentWithPostDatedChecksReadPlatformServiceImpl implements RepaymentWithPostDatedChecksReadPlatformService {
private final PostDatedChecksRepository postDatedChecksRepository;
@@ -31,6 +31,7 @@ import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformSer
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.client.api.ClientApiConstants;
@@ -59,21 +60,24 @@ public class DepositAccountInterestRateChartReadPlatformServiceImpl implements D
private final PlatformSecurityContext context;
private final JdbcTemplate jdbcTemplate;
private final DepositAccountInterestRateChartMapper chartRowMapper = new DepositAccountInterestRateChartMapper();
private final DepositAccountInterestRateChartExtractor chartExtractor = new DepositAccountInterestRateChartExtractor();
private final DepositAccountInterestRateChartExtractor chartExtractor;
private final InterestRateChartDropdownReadPlatformService chartDropdownReadPlatformService;
private final InterestIncentiveDropdownReadPlatformService interestIncentiveDropdownReadPlatformService;
private final CodeValueReadPlatformService codeValueReadPlatformService;
private final DatabaseSpecificSQLGenerator sqlGenerator;
@Autowired
public DepositAccountInterestRateChartReadPlatformServiceImpl(PlatformSecurityContext context, final RoutingDataSource dataSource,
InterestRateChartDropdownReadPlatformService chartDropdownReadPlatformService,
final InterestIncentiveDropdownReadPlatformService interestIncentiveDropdownReadPlatformService,
final CodeValueReadPlatformService codeValueReadPlatformService) {
final CodeValueReadPlatformService codeValueReadPlatformService, DatabaseSpecificSQLGenerator sqlGenerator) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.chartDropdownReadPlatformService = chartDropdownReadPlatformService;
this.interestIncentiveDropdownReadPlatformService = interestIncentiveDropdownReadPlatformService;
this.codeValueReadPlatformService = codeValueReadPlatformService;
this.sqlGenerator = sqlGenerator;
chartExtractor = new DepositAccountInterestRateChartExtractor(sqlGenerator);
}
@Override
@@ -194,7 +198,7 @@ public class DepositAccountInterestRateChartReadPlatformServiceImpl implements D
return this.schemaSql;
}
private DepositAccountInterestRateChartExtractor() {
private DepositAccountInterestRateChartExtractor(DatabaseSpecificSQLGenerator sqlGenerator) {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("irc.id as ircId, irc.name as ircName, irc.description as ircDescription,")
@@ -212,7 +216,7 @@ public class DepositAccountInterestRateChartReadPlatformServiceImpl implements D
.append("from ")
.append("m_savings_account_interest_rate_chart irc left join m_savings_account_interest_rate_slab ircd on irc.id=ircd.savings_account_interest_rate_chart_id ")
.append(" left join m_savings_interest_incentives iri on iri.deposit_account_interest_rate_slab_id =ircd.id ")
.append(" left join m_code_value code on code.id = iri.attribute_value ")
.append(" left join m_code_value code on " + sqlGenerator.castChar("code.id") + " = iri.attribute_value ")
.append("left join m_currency curr on ircd.currency_code= curr.code ")
.append("left join m_savings_account sa on irc.savings_account_id=sa.id ");
@@ -30,6 +30,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.portfolio.savings.data.DepositAccountOnHoldTransactionData;
import org.springframework.beans.factory.annotation.Autowired;
@@ -41,16 +42,19 @@ import org.springframework.stereotype.Service;
public class DepositAccountOnHoldTransactionReadPlatformServiceImpl implements DepositAccountOnHoldTransactionReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final ColumnValidator columnValidator;
private final PaginationHelper<DepositAccountOnHoldTransactionData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
private final DepositAccountOnHoldTransactionsMapper mapper;
@Autowired
public DepositAccountOnHoldTransactionReadPlatformServiceImpl(final RoutingDataSource dataSource,
final ColumnValidator columnValidator) {
public DepositAccountOnHoldTransactionReadPlatformServiceImpl(final RoutingDataSource dataSource, final ColumnValidator columnValidator,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
mapper = new DepositAccountOnHoldTransactionsMapper();
this.sqlGenerator = sqlGenerator;
this.mapper = new DepositAccountOnHoldTransactionsMapper();
this.columnValidator = columnValidator;
this.paginationHelper = paginationHelper;
}
@Override
@@ -58,7 +62,7 @@ public class DepositAccountOnHoldTransactionReadPlatformServiceImpl implements D
SearchParameters searchParameters) {
final StringBuilder sqlBuilder = new StringBuilder(200);
List<Long> paramObj = new ArrayList<>(2);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(this.mapper.schema());
sqlBuilder.append(" where tr.savings_account_id = ? ");
@@ -79,15 +83,16 @@ public class DepositAccountOnHoldTransactionReadPlatformServiceImpl implements D
}
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
final Object[] finalObjectArray = paramObj.toArray();
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), finalObjectArray, this.mapper);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), finalObjectArray, this.mapper);
}
@@ -37,6 +37,7 @@ import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.organisation.staff.data.StaffData;
@@ -107,7 +108,8 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
private final DepositAccountLookupMapper depositAccountLookupsRowMapper = new DepositAccountLookupMapper();
private final DepositAccountForMaturityMapper depositAccountForMaturityRowMapper = new DepositAccountForMaturityMapper();
private final PaginationParametersDataValidator paginationParametersDataValidator;
private final PaginationHelper<DepositAccountData> paginationHelper = new PaginationHelper<>();
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final PaginationHelper paginationHelper;
private final SavingsAccountTransactionsMapper transactionsMapper;
private final ClientReadPlatformService clientReadPlatformService;
private final GroupReadPlatformService groupReadPlatformService;
@@ -137,11 +139,13 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
final InterestRateChartReadPlatformService productChartReadPlatformService,
final SavingsAccountReadPlatformService savingsAccountReadPlatformService,
final DropdownReadPlatformService dropdownReadPlatformService, final CalendarReadPlatformService calendarReadPlatformService,
PaymentTypeReadPlatformService paymentTypeReadPlatformService) {
PaymentTypeReadPlatformService paymentTypeReadPlatformService, DatabaseSpecificSQLGenerator sqlGenerator,
PaginationHelper paginationHelper) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.accountChartReadPlatformService = chartReadPlatformService;
this.paginationParametersDataValidator = paginationParametersDataValidator;
this.sqlGenerator = sqlGenerator;
this.transactionsMapper = new SavingsAccountTransactionsMapper();
this.clientReadPlatformService = clientReadPlatformService;
this.groupReadPlatformService = groupReadPlatformService;
@@ -156,6 +160,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
this.dropdownReadPlatformService = dropdownReadPlatformService;
this.calendarReadPlatformService = calendarReadPlatformService;
this.paymentTypeReadPlatformService = paymentTypeReadPlatformService;
this.paginationHelper = paginationHelper;
}
@Override
@@ -191,15 +196,13 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
}
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(depositAccountMapper.schema());
sqlBuilder.append(" where sa.deposit_type_enum = ? ");
sqlBuilder.append(paginationParameters.paginationSql());
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(),
new Object[] { depositAccountType.getValue() }, depositAccountMapper);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), new Object[] { depositAccountType.getValue() },
depositAccountMapper);
}
@Override
@@ -222,11 +225,9 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
sqlBuilder.append(this.depositAccountForMaturityRowMapper.schema());
sqlBuilder.append(" WHERE da.deposit_type_enum in (?, ?) and da.status_enum = ?");
LocalDate today = DateUtils.getLocalDateOfTenant();
return this.jdbcTemplate.query(sqlBuilder.toString(), this.depositAccountForMaturityRowMapper,
new Object[] { formatter.format(today), DepositAccountType.FIXED_DEPOSIT.getValue(),
DepositAccountType.RECURRING_DEPOSIT.getValue(), SavingsAccountStatusType.ACTIVE.getValue() });
new Object[] { DepositAccountType.FIXED_DEPOSIT.getValue(), DepositAccountType.RECURRING_DEPOSIT.getValue(),
SavingsAccountStatusType.ACTIVE.getValue() });
}
@Override
@@ -519,6 +520,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
@Override
public Collection<Map<String, Object>> retriveDataForRDScheduleCreation() {
String today = formatter.format(DateUtils.getLocalDateOfTenant());
final StringBuilder sb = new StringBuilder(300);
sb.append(" select rd.savings_account_id savingsId, rd.mandatory_recommended_deposit_amount as amount,");
sb.append(" mc.recurrence as recurrence ,");
@@ -529,13 +531,13 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
sb.append(" inner join m_deposit_account_recurring_detail rd on rd.savings_account_id = dat.savings_account_id ");
sb.append(" inner join m_calendar_instance mci on mci.entity_type_enum = ? and mci.entity_id = dat.savings_account_id ");
sb.append(" inner join m_calendar mc on mc.id = mci.calendar_id and mc.calendar_type_enum = ?");
sb.append(" inner join m_mandatory_savings_schedule ms on ms.savings_account_id = dat.savings_account_id and ms.duedate > ?");
sb.append(" inner join m_mandatory_savings_schedule ms on ms.savings_account_id = dat.savings_account_id and ms.duedate > '" + today
+ "'");
sb.append(" where dat.deposit_period is null");
sb.append(" group by ms.savings_account_id, rd.mandatory_recommended_deposit_amount, mc.recurrence, rd.savings_account_id");
return this.jdbcTemplate.queryForList(sb.toString(), SavingsAccountStatusType.ACTIVE.getValue(),
CalendarEntityType.SAVINGS.getValue(), CalendarType.COLLECTION.getValue(),
formatter.format(DateUtils.getLocalDateOfTenant()));
CalendarEntityType.SAVINGS.getValue(), CalendarType.COLLECTION.getValue());
}
private abstract static class DepositAccountMapper implements RowMapper<DepositAccountData> {
@@ -1383,22 +1385,20 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
private static final class DepositAccountForMaturityMapper implements RowMapper<DepositAccountData> {
private final String schemaSql;
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
DepositAccountForMaturityMapper() {
public String schema() {
LocalDate today = DateUtils.getLocalDateOfTenant();
String formattedToday = formatter.format(today);
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("da.id as id, ");
sqlBuilder.append("da.account_no as accountNumber, ");
sqlBuilder.append("da.deposit_type_enum as depositTypeId ");
sqlBuilder.append("FROM m_savings_account da ");
sqlBuilder.append("inner join m_deposit_account_term_and_preclosure dat on dat.savings_account_id = da.id ");
sqlBuilder.append("and dat.maturity_date is not null and dat.maturity_date <= ? ");
sqlBuilder.append("and dat.maturity_date is not null and dat.maturity_date <= '" + formattedToday + "' ");
this.schemaSql = sqlBuilder.toString();
}
public String schema() {
return this.schemaSql;
return sqlBuilder.toString();
}
@Override
@@ -40,6 +40,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
@@ -101,6 +102,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
private final SavingsProductReadPlatformService savingsProductReadPlatformService;
private final StaffReadPlatformService staffReadPlatformService;
private final SavingsDropdownReadPlatformService dropdownReadPlatformService;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final ChargeReadPlatformService chargeReadPlatformService;
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@@ -113,7 +115,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
// private final SavingsAccountAnnualFeeMapper annualFeeMapper;
// pagination
private final PaginationHelper<SavingsAccountData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
private final EntityDatatableChecksReadService entityDatatableChecksReadService;
private final ColumnValidator columnValidator;
@@ -126,7 +128,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
final StaffReadPlatformService staffReadPlatformService, final SavingsDropdownReadPlatformService dropdownReadPlatformService,
final ChargeReadPlatformService chargeReadPlatformService,
final EntityDatatableChecksReadService entityDatatableChecksReadService, final ColumnValidator columnValidator,
final SavingsAccountAssembler savingAccountAssembler) {
final SavingsAccountAssembler savingAccountAssembler, PaginationHelper paginationHelper,
DatabaseSpecificSQLGenerator sqlGenerator) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.clientReadPlatformService = clientReadPlatformService;
@@ -134,6 +137,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
this.savingsProductReadPlatformService = savingProductReadPlatformService;
this.staffReadPlatformService = staffReadPlatformService;
this.dropdownReadPlatformService = dropdownReadPlatformService;
this.sqlGenerator = sqlGenerator;
this.transactionTemplateMapper = new SavingsAccountTransactionTemplateMapper();
this.transactionsMapper = new SavingsAccountTransactionsMapper();
this.savingsAccountTransactionsForBatchMapper = new SavingsAccountTransactionsForBatchMapper();
@@ -142,6 +146,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
this.chargeReadPlatformService = chargeReadPlatformService;
this.entityDatatableChecksReadService = entityDatatableChecksReadService;
this.columnValidator = columnValidator;
this.paginationHelper = paginationHelper;
this.savingAccountMapperForInterestPosting = new SavingAccountMapperForInterestPosting();
this.savingAccountAssembler = savingAccountAssembler;
}
@@ -184,7 +189,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
final String hierarchySearchString = hierarchy + "%";
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(this.savingAccountMapper.schema());
sqlBuilder.append(" join m_office o on o.id = c.office_id");
@@ -222,16 +227,16 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
}
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
}
final Object[] finalObjectArray = Arrays.copyOf(objectArray, arrayPos);
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), finalObjectArray,
this.savingAccountMapper);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), finalObjectArray, this.savingAccountMapper);
}
@Override
@@ -271,7 +276,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
+ "where (CASE WHEN sa.interest_posted_till_date is not null THEN tr.transaction_date >= sa.interest_posted_till_date ELSE tr.transaction_date >= sa.activatedon_date END) ";
}
sql = sql + "and apm.product_type=2 and sa.interest_posted_till_date<" + java.sql.Date.valueOf(currentDate);
sql = sql + "and apm.product_type=2 and sa.interest_posted_till_date < '" + java.sql.Date.valueOf(currentDate) + "'";
sql = sql + " order by sa.id, tr.transaction_date, tr.created_date, tr.id";
List<SavingsAccountData> savingsAccountDataList = this.jdbcTemplate.query(sql, this.savingAccountMapperForInterestPosting,
@@ -1650,20 +1655,21 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
@Override
public List<Long> retrieveSavingsIdsPendingInactive(LocalDate tenantLocalDate) {
String formattedTenantLocalDate = formatter.format(tenantLocalDate);
List<Long> ret = null;
StringBuilder sql = new StringBuilder("select sa.id ");
sql.append(" from m_savings_account as sa ");
sql.append(" inner join m_savings_product as sp on (sa.product_id = sp.id and sp.is_dormancy_tracking_active = 1) ");
sql.append(" inner join m_savings_product as sp on (sa.product_id = sp.id and sp.is_dormancy_tracking_active = true) ");
sql.append(" where sa.status_enum = 300 ");
sql.append(" and sa.sub_status_enum = 0 ");
sql.append(" and DATEDIFF(?,(select COALESCE(max(sat.transaction_date), sa.activatedon_date) ");
sql.append(" from m_savings_account_transaction as sat ");
sql.append(" where sat.is_reversed = false ");
sql.append(" and sat.transaction_type_enum in (1,2) ");
sql.append(" and sat.savings_account_id = sa.id)) >= sp.days_to_inactive ");
String compareDate = "(select COALESCE(max(sat.transaction_date), sa.activatedon_date) "
+ "from m_savings_account_transaction as sat where sat.is_reversed = false"
+ " and sat.transaction_type_enum in (1,2) and sat.savings_account_id = sa.id)";
sql.append(" and ").append(sqlGenerator.dateDiff("'" + formattedTenantLocalDate + "'", compareDate))
.append(" >= sp.days_to_inactive ");
try {
ret = this.jdbcTemplate.queryForList(sql.toString(), Long.class, new Object[] { formatter.format(tenantLocalDate) });
ret = this.jdbcTemplate.queryForList(sql.toString(), Long.class);
} catch (EmptyResultDataAccessException e) {
// ignore empty result scenario
} catch (DataAccessException e) {
@@ -1675,20 +1681,20 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
@Override
public List<Long> retrieveSavingsIdsPendingDormant(LocalDate tenantLocalDate) {
String currentDate = formatter.format(tenantLocalDate);
List<Long> ret = null;
StringBuilder sql = new StringBuilder("select sa.id ");
sql.append(" from m_savings_account as sa ");
sql.append(" inner join m_savings_product as sp on (sa.product_id = sp.id and sp.is_dormancy_tracking_active = 1) ");
sql.append(" inner join m_savings_product as sp on (sa.product_id = sp.id and sp.is_dormancy_tracking_active = true) ");
sql.append(" where sa.status_enum = 300 ");
sql.append(" and sa.sub_status_enum = 100 ");
sql.append(" and DATEDIFF(?,(select COALESCE(max(sat.transaction_date),sa.activatedon_date) ");
sql.append(" from m_savings_account_transaction as sat ");
sql.append(" where sat.is_reversed = false ");
sql.append(" and sat.transaction_type_enum in (1,2) ");
sql.append(" and sat.savings_account_id = sa.id)) >= sp.days_to_dormancy ");
sql.append(" and " + sqlGenerator.dateDiff("'" + currentDate + "'",
"(select COALESCE(max(sat.transaction_date),sa.activatedon_date) from m_savings_account_transaction as sat where sat.is_reversed = false and sat.transaction_type_enum in (1,2) and sat.savings_account_id = sa.id)")
+ " ");
sql.append(" >= sp.days_to_dormancy ");
try {
ret = this.jdbcTemplate.queryForList(sql.toString(), Long.class, new Object[] { formatter.format(tenantLocalDate) });
ret = this.jdbcTemplate.queryForList(sql.toString(), Long.class);
} catch (EmptyResultDataAccessException e) {
// ignore empty result scenario
} catch (DataAccessException e) {
@@ -1706,11 +1712,10 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
sql.append(" inner join m_savings_product as sp on (sa.product_id = sp.id and sp.is_dormancy_tracking_active = true) ");
sql.append(" where sa.status_enum = 300 ");
sql.append(" and sa.sub_status_enum = 200 ");
sql.append(" and DATEDIFF(?,(select COALESCE(max(sat.transaction_date),sa.activatedon_date) ");
sql.append(" from m_savings_account_transaction as sat ");
sql.append(" where sat.is_reversed = false ");
sql.append(" and sat.transaction_type_enum in (1,2) ");
sql.append(" and sat.savings_account_id = sa.id)) >= sp.days_to_escheat ");
sql.append(" and " + sqlGenerator.dateDiff("?",
"(select COALESCE(max(sat.transaction_date),sa.activatedon_date) from m_savings_account_transaction as sat where sat.is_reversed = false and sat.transaction_type_enum in (1,2) and sat.savings_account_id = sa.id)")
+ " ");
sql.append(" >= sp.days_to_escheat ");
try {
ret = this.jdbcTemplate.queryForList(sql.toString(), Long.class, new Object[] { formatter.format(tenantLocalDate) });
@@ -108,6 +108,10 @@ public class SavingsSchedularInterestPoster implements Callable<Void> {
this.tenant = tenant;
}
public void setConfigurationDomainService(ConfigurationDomainService configurationDomainService) {
this.configurationDomainService = configurationDomainService;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@@ -183,6 +183,7 @@ public class SavingsSchedularServiceImpl implements SavingsSchedularService {
poster.setJdbcTemplate(jdbcTemplate);
poster.setBackdatedTxnsAllowedTill(backdatedTxnsAllowedTill);
poster.setTransactionTemplate(transactionTemplate);
poster.setConfigurationDomainService(configurationDomainService);
posters.add(poster);
@@ -30,6 +30,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountData;
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountDividendData;
@@ -45,12 +46,16 @@ public class ShareAccountDividendReadPlatformServiceImpl implements ShareAccount
private final JdbcTemplate jdbcTemplate;
private final ColumnValidator columnValidator;
private final PaginationHelper<ShareAccountDividendData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
private final DatabaseSpecificSQLGenerator sqlGenerator;
@Autowired
public ShareAccountDividendReadPlatformServiceImpl(final RoutingDataSource dataSource, final ColumnValidator columnValidator) {
public ShareAccountDividendReadPlatformServiceImpl(final RoutingDataSource dataSource, final ColumnValidator columnValidator,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.columnValidator = columnValidator;
this.paginationHelper = paginationHelper;
this.sqlGenerator = sqlGenerator;
}
@Override
@@ -71,7 +76,7 @@ public class ShareAccountDividendReadPlatformServiceImpl implements ShareAccount
public Page<ShareAccountDividendData> retriveAll(final Long payoutDetailId, final SearchParameters searchParameters) {
ShareAccountDividendMapper shareAccountDividendMapper = new ShareAccountDividendMapper();
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(shareAccountDividendMapper.schema());
sqlBuilder.append(" where sadd.dividend_pay_out_id = ? ");
List<Object> params = new ArrayList<>(2);
@@ -92,16 +97,16 @@ public class ShareAccountDividendReadPlatformServiceImpl implements ShareAccount
}
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
Object[] paramsObj = params.toArray();
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), paramsObj,
shareAccountDividendMapper);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), paramsObj, shareAccountDividendMapper);
}
private static final class ShareAccountDividendMapper implements RowMapper<ShareAccountDividendData> {
@@ -36,6 +36,7 @@ import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.accountdetails.data.ShareAccountSummaryData;
import org.apache.fineract.portfolio.accounts.constants.AccountsApiConstants;
@@ -82,7 +83,8 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
private final PurchasedSharesReadPlatformService purchasedSharesReadPlatformService;
private final JdbcTemplate jdbcTemplate;
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private final PaginationHelper<AccountData> shareAccountDataPaginationHelper = new PaginationHelper<>();
private final PaginationHelper shareAccountDataPaginationHelper;
private final DatabaseSpecificSQLGenerator sqlGenerator;
@Autowired
public ShareAccountReadPlatformServiceImpl(final RoutingDataSource dataSource, final ApplicationContext applicationContext,
@@ -91,7 +93,8 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
final SavingsAccountReadPlatformService savingsAccountReadPlatformService,
final ClientReadPlatformService clientReadPlatformService,
final ShareAccountChargeReadPlatformService shareAccountChargeReadPlatformService,
final PurchasedSharesReadPlatformService purchasedSharesReadPlatformService) {
final PurchasedSharesReadPlatformService purchasedSharesReadPlatformService, DatabaseSpecificSQLGenerator sqlGenerator,
PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.applicationContext = applicationContext;
this.chargeReadPlatformService = chargeReadPlatformService;
@@ -100,7 +103,8 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
this.clientReadPlatformService = clientReadPlatformService;
this.shareAccountChargeReadPlatformService = shareAccountChargeReadPlatformService;
this.purchasedSharesReadPlatformService = purchasedSharesReadPlatformService;
this.shareAccountDataPaginationHelper = paginationHelper;
this.sqlGenerator = sqlGenerator;
}
@Override
@@ -190,7 +194,7 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
final Collection<ShareAccountTransactionData> purchasedShares = null;
ShareAccountMapper mapper = new ShareAccountMapper(charges, purchasedShares);
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(mapper.schema());
sqlBuilder.append(" where sa.status_enum = ? ");
if (limit != null) {
@@ -200,10 +204,8 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
sqlBuilder.append(" offset ").append(offSet);
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
Object[] whereClauseItemsitems = new Object[] { ShareAccountStatusType.ACTIVE.getValue() };
return this.shareAccountDataPaginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(),
whereClauseItemsitems, mapper);
return this.shareAccountDataPaginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), whereClauseItemsitems, mapper);
}
@Override
@@ -223,10 +225,10 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
params.add(id);
params.add(ShareAccountStatusType.ACTIVE.getValue());
if (fetchInActiveAccounts) {
String formattedStartDate = formatter.format(startDate);
sb.append(" and (sa.status_enum = ? or (sa.status_enum = ? ");
sb.append(" and sa.closed_date > ?)) ");
sb.append(" and sa.closed_date > '" + formattedStartDate + "')) ");
params.add(ShareAccountStatusType.CLOSED.getValue());
params.add(formatter.format(startDate));
} else {
sb.append(" and sa.status_enum = ? ");
}
@@ -31,6 +31,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountDividendData;
import org.apache.fineract.portfolio.shareaccounts.service.SharesEnumerations;
@@ -46,12 +47,16 @@ public class ShareProductDividendReadPlatformServiceImpl implements ShareProduct
private final JdbcTemplate jdbcTemplate;
private final ColumnValidator columnValidator;
private final PaginationHelper<ShareProductDividendPayOutData> paginationHelper = new PaginationHelper<>();
private final PaginationHelper paginationHelper;
private final DatabaseSpecificSQLGenerator sqlGenerator;
@Autowired
public ShareProductDividendReadPlatformServiceImpl(final RoutingDataSource dataSource, final ColumnValidator columnValidator) {
public ShareProductDividendReadPlatformServiceImpl(final RoutingDataSource dataSource, final ColumnValidator columnValidator,
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.columnValidator = columnValidator;
this.paginationHelper = paginationHelper;
this.sqlGenerator = sqlGenerator;
}
@Override
@@ -59,7 +64,7 @@ public class ShareProductDividendReadPlatformServiceImpl implements ShareProduct
final SearchParameters searchParameters) {
ShareProductDividendMapper shareProductDividendMapper = new ShareProductDividendMapper();
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(shareProductDividendMapper.schema());
sqlBuilder.append(" where sp.id = ? ");
List<Object> params = new ArrayList<>(2);
@@ -79,16 +84,16 @@ public class ShareProductDividendReadPlatformServiceImpl implements ShareProduct
}
if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
sqlBuilder.append(" ");
if (searchParameters.isOffset()) {
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
} else {
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
}
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
Object[] paramsObj = params.toArray();
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), paramsObj,
shareProductDividendMapper);
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), paramsObj, shareProductDividendMapper);
}
private static final class ShareProductDividendMapper implements RowMapper<ShareProductDividendPayOutData> {
@@ -37,6 +37,7 @@ import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformService;
import org.apache.fineract.portfolio.charge.data.ChargeData;
@@ -62,20 +63,24 @@ public class ShareProductReadPlatformServiceImpl implements ProductReadPlatformS
private final ShareProductDropdownReadPlatformService shareProductDropdownReadPlatformService;
private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService;
private final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService;
private final PaginationHelper<ProductData> shareProductDataPaginationHelper = new PaginationHelper<>();
private final PaginationHelper shareProductDataPaginationHelper;
private final DatabaseSpecificSQLGenerator sqlGenerator;
@Autowired
public ShareProductReadPlatformServiceImpl(final RoutingDataSource dataSource,
final CurrencyReadPlatformService currencyReadPlatformService, final ChargeReadPlatformService chargeReadPlatformService,
final ShareProductDropdownReadPlatformService shareProductDropdownReadPlatformService,
final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService,
final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService) {
final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService, DatabaseSpecificSQLGenerator sqlGenerator,
PaginationHelper paginationHelper) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.currencyReadPlatformService = currencyReadPlatformService;
this.chargeReadPlatformService = chargeReadPlatformService;
this.shareProductDropdownReadPlatformService = shareProductDropdownReadPlatformService;
this.accountingDropdownReadPlatformService = accountingDropdownReadPlatformService;
this.accountMappingReadPlatformService = accountMappingReadPlatformService;
this.shareProductDataPaginationHelper = paginationHelper;
this.sqlGenerator = sqlGenerator;
}
@Override
@@ -84,7 +89,7 @@ public class ShareProductReadPlatformServiceImpl implements ProductReadPlatformS
final Collection<ChargeData> charges = null;
ShareProductRowMapper mapper = new ShareProductRowMapper(shareMarketCollection, charges);
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
sqlBuilder.append(mapper.schema());
if (limit != null) {
sqlBuilder.append(" limit ").append(limit);
@@ -93,10 +98,8 @@ public class ShareProductReadPlatformServiceImpl implements ProductReadPlatformS
sqlBuilder.append(" offset ").append(offSet);
}
final String sqlCountRows = "SELECT FOUND_ROWS()";
Object[] whereClauseItemsitems = new Object[] {};
return this.shareProductDataPaginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(),
whereClauseItemsitems, mapper);
return this.shareProductDataPaginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), whereClauseItemsitems, mapper);
}
@Override
@@ -38,6 +38,7 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.RoutingDataSourceServiceFactory;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver;
import org.apache.fineract.infrastructure.jobs.annotation.CronTarget;
import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
@@ -83,6 +84,7 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
private final JobRegisterService jobRegisterService;
private final ScheduledJobDetailRepository scheduledJobDetailsRepository;
private final FineractProperties fineractProperties;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final DatabaseTypeResolver databaseTypeResolver;
@Autowired
@@ -95,7 +97,7 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
final ShareAccountSchedularService shareAccountSchedularService,
final TrialBalanceRepositoryWrapper trialBalanceRepositoryWrapper, @Lazy final JobRegisterService jobRegisterService,
final ScheduledJobDetailRepository scheduledJobDetailsRepository, final FineractProperties fineractProperties,
DatabaseTypeResolver databaseTypeResolver) {
DatabaseSpecificSQLGenerator sqlGenerator, DatabaseTypeResolver databaseTypeResolver) {
this.dataSourceServiceFactory = dataSourceServiceFactory;
this.savingsAccountWritePlatformService = savingsAccountWritePlatformService;
this.savingsAccountChargeReadPlatformService = savingsAccountChargeReadPlatformService;
@@ -107,6 +109,7 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
this.jobRegisterService = jobRegisterService;
this.scheduledJobDetailsRepository = scheduledJobDetailsRepository;
this.fineractProperties = fineractProperties;
this.sqlGenerator = sqlGenerator;
this.databaseTypeResolver = databaseTypeResolver;
}
@@ -219,7 +222,7 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
updateSqlBuilder.append(" FROM m_loan ml ");
updateSqlBuilder.append(" INNER JOIN m_loan_repayment_schedule mr on mr.loan_id = ml.id ");
updateSqlBuilder.append(" WHERE ml.loan_status_id = 300 ");
updateSqlBuilder.append(" and mr.duedate >= CURDATE() ");
updateSqlBuilder.append(" and mr.duedate >= " + sqlGenerator.currentDate() + " ");
updateSqlBuilder.append(" GROUP BY ml.id");
updateSqlBuilder
.append(" HAVING (SUM(coalesce(mr.principal_completed_derived, 0)) + SUM(coalesce(mr.interest_completed_derived, 0)) +");
@@ -313,7 +316,8 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
fromPart = " (select loan.id " + " FROM m_loan_arrears_aging laa" + " INNER JOIN m_loan loan on laa.loan_id = loan.id "
+ " INNER JOIN m_product_loan mpl on mpl.id = loan.product_id AND mpl.overdue_days_for_npa is not null "
+ "WHERE loan.loan_status_id = 300 and " + "laa.overdue_since_date_derived < "
+ "SUBDATE(CURDATE(),INTERVAL COALESCE(mpl.overdue_days_for_npa, 0) day)" + " group by loan.id) as sl ";
+ sqlGenerator.subDate(sqlGenerator.currentDate(), "COALESCE(mpl.overdue_days_for_npa, 0)", "day")
+ " group by loan.id) as sl ";
wherePart = " where ml.id=sl.id ";
updateSqlBuilder.append("UPDATE m_loan as ml ");
if (databaseTypeResolver.isMySQL()) {
@@ -23,6 +23,7 @@ import java.sql.SQLException;
import java.util.Collection;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.useradministration.data.PasswordValidationPolicyData;
import org.apache.fineract.useradministration.exception.PasswordValidationPolicyNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -35,12 +36,14 @@ import org.springframework.stereotype.Service;
public class PasswordValidationPolicyReadPlatformServiceImpl implements PasswordValidationPolicyReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final PasswordValidationPolicyMapper passwordValidationPolicyMapper;
@Autowired
public PasswordValidationPolicyReadPlatformServiceImpl(final RoutingDataSource dataSource) {
public PasswordValidationPolicyReadPlatformServiceImpl(final RoutingDataSource dataSource, DatabaseSpecificSQLGenerator sqlGenerator) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.passwordValidationPolicyMapper = new PasswordValidationPolicyMapper();
this.sqlGenerator = sqlGenerator;
this.passwordValidationPolicyMapper = new PasswordValidationPolicyMapper(sqlGenerator);
}
@Override
@@ -62,6 +65,12 @@ public class PasswordValidationPolicyReadPlatformServiceImpl implements Password
protected static final class PasswordValidationPolicyMapper implements RowMapper<PasswordValidationPolicyData> {
private final DatabaseSpecificSQLGenerator sqlGenerator;
public PasswordValidationPolicyMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
this.sqlGenerator = sqlGenerator;
}
@Override
public PasswordValidationPolicyData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
@@ -74,8 +83,8 @@ public class PasswordValidationPolicyReadPlatformServiceImpl implements Password
}
public String schema() {
return " pvp.id as id, pvp.active as active, pvp.description as description, pvp.`key` as `key`"
+ " from m_password_validation_policy pvp";
return " pvp.id as id, pvp.active as active, pvp.description as description, pvp." + sqlGenerator.escape("key") + " as "
+ sqlGenerator.escape("key") + "" + " from m_password_validation_policy pvp";
}
}
@@ -22,6 +22,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.useradministration.data.PermissionData;
import org.slf4j.Logger;
@@ -37,12 +38,15 @@ public class PermissionReadPlatformServiceImpl implements PermissionReadPlatform
private static final Logger LOG = LoggerFactory.getLogger(PermissionReadPlatformServiceImpl.class);
private final JdbcTemplate jdbcTemplate;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final PlatformSecurityContext context;
@Autowired
public PermissionReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource) {
public PermissionReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
DatabaseSpecificSQLGenerator sqlGenerator) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.sqlGenerator = sqlGenerator;
}
@Override
@@ -50,7 +54,7 @@ public class PermissionReadPlatformServiceImpl implements PermissionReadPlatform
this.context.authenticatedUser();
final PermissionUsageDataMapper mapper = new PermissionUsageDataMapper();
final PermissionUsageDataMapper mapper = new PermissionUsageDataMapper(sqlGenerator);
final String sql = mapper.permissionSchema();
LOG.info("retrieveAllPermissions: {}", sql);
return this.jdbcTemplate.query(sql, mapper, new Object[] {});
@@ -61,7 +65,7 @@ public class PermissionReadPlatformServiceImpl implements PermissionReadPlatform
this.context.authenticatedUser();
final PermissionUsageDataMapper mapper = new PermissionUsageDataMapper();
final PermissionUsageDataMapper mapper = new PermissionUsageDataMapper(sqlGenerator);
final String sql = mapper.makerCheckerablePermissionSchema();
LOG.info("retrieveAllMakerCheckerablePermissions: {}", sql);
@@ -71,7 +75,7 @@ public class PermissionReadPlatformServiceImpl implements PermissionReadPlatform
@Override
public Collection<PermissionData> retrieveAllRolePermissions(final Long roleId) {
final PermissionUsageDataMapper mapper = new PermissionUsageDataMapper();
final PermissionUsageDataMapper mapper = new PermissionUsageDataMapper(sqlGenerator);
final String sql = mapper.rolePermissionSchema();
LOG.info("retrieveAllRolePermissions: {}", sql);
@@ -80,6 +84,12 @@ public class PermissionReadPlatformServiceImpl implements PermissionReadPlatform
private static final class PermissionUsageDataMapper implements RowMapper<PermissionData> {
private final DatabaseSpecificSQLGenerator sqlGenerator;
PermissionUsageDataMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
this.sqlGenerator = sqlGenerator;
}
@Override
public PermissionData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
@@ -106,7 +116,8 @@ public class PermissionReadPlatformServiceImpl implements PermissionReadPlatform
*/
return "select p.grouping, p.code, p.entity_name as entityName, p.action_name as actionName, p.can_maker_checker as selected"
+ " from m_permission p " + " where `grouping` != 'special' and code not like 'READ_%' and code not like '%\\_CHECKER'"
+ " from m_permission p " + " where " + sqlGenerator.escape("grouping")
+ " != 'special' and code not like 'READ_%' and code not like '%\\_CHECKER'"
+ " order by p.grouping, coalesce(entity_name, ''), p.code";
}
@@ -23,6 +23,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<property name="current_date" value="CURDATE()" context="mysql"/>
<property name="current_date" value="CURRENT_DATE" context="postgresql"/>
<property name="current_datetime" value="NOW()"/>
<include file="tenant-store/initial-switch-changelog-tenant-store.xml" relativeToChangelogFile="true" context="tenant_store_db AND initial_switch"/>
<include file="tenant-store/changelog-tenant-store.xml" relativeToChangelogFile="true" context="tenant_store_db AND !initial_switch"/>
@@ -22,6 +22,5 @@
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<!-- An example how to include upcoming changes -->
<!-- <include file="parts/0003_upcoming_change.xml" relativeToChangelogFile="true"/> -->
<include file="parts/0003_reset_postgresql_sequences.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<changeSet author="fineract" id="1-postgresql" context="postgresql">
<sql>
SELECT SETVAL('tenant_server_connections_id_seq', COALESCE(MAX(id), 0)+1, false ) FROM tenant_server_connections;
SELECT SETVAL('tenants_id_seq', COALESCE(MAX(id), 0)+1, false ) FROM tenants;
SELECT SETVAL('timezones_id_seq', COALESCE(MAX(id), 0)+1, false ) FROM timezones;
</sql>
</changeSet>
</databaseChangeLog>
@@ -22,6 +22,6 @@
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<!-- An example how to include upcoming changes -->
<!-- <include file="parts/0003_upcoming_change.xml" relativeToChangelogFile="true"/> -->
<include file="parts/0003_postgresql_specific_initial_data.xml" relativeToChangelogFile="true"/>
<include file="parts/0004_camelcase_column_renaming.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
File diff suppressed because one or more lines are too long
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<changeSet author="fineract" id="1" objectQuotingStrategy="QUOTE_ALL_OBJECTS">
<renameColumn tableName="m_adhoc" oldColumnName="IsActive" newColumnName="is_active" columnDataType="BOOLEAN"/>
<renameColumn tableName="m_creditbureau" oldColumnName="implementationKey" newColumnName="implementation_key" columnDataType="VARCHAR(100)"/>
<renameColumn tableName="m_creditbureau_loanproduct_mapping" oldColumnName="isActive" newColumnName="is_active" columnDataType="BOOLEAN"/>
<renameColumn tableName="m_creditbureau_token" oldColumnName="tokenType" newColumnName="token_type" columnDataType="VARCHAR(128)"/>
<renameColumn tableName="m_creditbureau_token" oldColumnName="expiresIn" newColumnName="expires_in" columnDataType="VARCHAR(128)"/>
<renameColumn tableName="m_creditbureau_token" oldColumnName="expiryDate" newColumnName="expiry_date" columnDataType="DATE"/>
<renameColumn tableName="m_creditreport" oldColumnName="creditBureauId" newColumnName="credit_bureau_id" columnDataType="BIGINT"/>
<renameColumn tableName="m_creditreport" oldColumnName="nationalId" newColumnName="national_id" columnDataType="VARCHAR(128)"/>
<renameColumn tableName="m_creditreport" oldColumnName="creditReports" newColumnName="credit_reports" columnDataType="BLOB"/>
<renameColumn tableName="m_organisation_creditbureau" oldColumnName="isActive" newColumnName="is_active" columnDataType="BOOLEAN"/>
<renameColumn tableName="scheduled_email_campaign" oldColumnName="businessRule_id" newColumnName="business_rule_id" columnDataType="INT"/>
</changeSet>
</databaseChangeLog>
@@ -19,7 +19,9 @@
package org.apache.fineract.infrastructure.configuration.spring;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.zaxxer.hikari.HikariConfig;
import javax.sql.DataSource;
import org.apache.fineract.infrastructure.core.boot.AbstractApplicationConfiguration;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
@@ -42,6 +44,13 @@ import org.springframework.security.crypto.password.PasswordEncoder;
@EnableConfigurationProperties({ FineractProperties.class })
public class TestsWithoutDatabaseAndNoJobsConfiguration extends AbstractApplicationConfiguration {
@Bean
public HikariConfig hikariConfig() {
HikariConfig mock = mock(HikariConfig.class);
when(mock.getDriverClassName()).thenReturn("org.mariadb.jdbc.Driver");
return mock;
}
@Bean
public TenantDataSourceFactory tenantDataSourceFactory() {
return new TenantDataSourceFactory(null) {