fix for performance issues

This commit is contained in:
pramod
2016-08-26 19:05:30 +05:30
parent ff58f74d79
commit ca1adedd40
14 changed files with 267 additions and 61 deletions
@@ -19,6 +19,7 @@
package org.apache.fineract.infrastructure.configuration.domain; package org.apache.fineract.infrastructure.configuration.domain;
import java.util.Date; import java.util.Date;
import org.apache.fineract.infrastructure.cache.domain.CacheType; import org.apache.fineract.infrastructure.cache.domain.CacheType;
public interface ConfigurationDomainService { public interface ConfigurationDomainService {
@@ -82,5 +83,7 @@ public interface ConfigurationDomainService {
boolean isDailyTPTLimitEnabled(); boolean isDailyTPTLimitEnabled();
Long getDailyTPTLimit(); Long getDailyTPTLimit();
void removeGlobalConfigurationPropertyDataFromCache(String propertyName);
} }
@@ -19,11 +19,15 @@
package org.apache.fineract.infrastructure.configuration.domain; package org.apache.fineract.infrastructure.configuration.domain;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.cache.domain.CacheType; import org.apache.fineract.infrastructure.cache.domain.CacheType;
import org.apache.fineract.infrastructure.cache.domain.PlatformCache; import org.apache.fineract.infrastructure.cache.domain.PlatformCache;
import org.apache.fineract.infrastructure.cache.domain.PlatformCacheRepository; import org.apache.fineract.infrastructure.cache.domain.PlatformCacheRepository;
import org.apache.fineract.infrastructure.configuration.data.GlobalConfigurationPropertyData;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.useradministration.domain.Permission; import org.apache.fineract.useradministration.domain.Permission;
import org.apache.fineract.useradministration.domain.PermissionRepository; import org.apache.fineract.useradministration.domain.PermissionRepository;
import org.apache.fineract.useradministration.exception.PermissionNotFoundException; import org.apache.fineract.useradministration.exception.PermissionNotFoundException;
@@ -37,6 +41,7 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
private final PermissionRepository permissionRepository; private final PermissionRepository permissionRepository;
private final GlobalConfigurationRepositoryWrapper globalConfigurationRepository; private final GlobalConfigurationRepositoryWrapper globalConfigurationRepository;
private final PlatformCacheRepository cacheTypeRepository; private final PlatformCacheRepository cacheTypeRepository;
private static Map<String, GlobalConfigurationPropertyData> configurations = new HashMap<>();
@Autowired @Autowired
public ConfigurationDomainServiceJpa(final PermissionRepository permissionRepository, public ConfigurationDomainServiceJpa(final PermissionRepository permissionRepository,
@@ -54,22 +59,20 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
if (thisTask == null) { throw new PermissionNotFoundException(taskPermissionCode); } if (thisTask == null) { throw new PermissionNotFoundException(taskPermissionCode); }
final String makerCheckerConfigurationProperty = "maker-checker"; final String makerCheckerConfigurationProperty = "maker-checker";
final GlobalConfigurationProperty property = this.globalConfigurationRepository final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(makerCheckerConfigurationProperty);
.findOneByNameWithNotFoundDetection(makerCheckerConfigurationProperty);
return thisTask.hasMakerCheckerEnabled() && property.isEnabled(); return thisTask.hasMakerCheckerEnabled() && property.isEnabled();
} }
@Override @Override
public boolean isAmazonS3Enabled() { public boolean isAmazonS3Enabled() {
return this.globalConfigurationRepository.findOneByNameWithNotFoundDetection("amazon-S3").isEnabled(); return getGlobalConfigurationPropertyData("amazon-S3").isEnabled();
} }
@Override @Override
public boolean isRescheduleFutureRepaymentsEnabled() { public boolean isRescheduleFutureRepaymentsEnabled() {
final String rescheduleRepaymentsConfigurationProperty = "reschedule-future-repayments"; final String rescheduleRepaymentsConfigurationProperty = "reschedule-future-repayments";
final GlobalConfigurationProperty property = this.globalConfigurationRepository final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(rescheduleRepaymentsConfigurationProperty);
.findOneByNameWithNotFoundDetection(rescheduleRepaymentsConfigurationProperty);
return property.isEnabled(); return property.isEnabled();
} }
@@ -82,30 +85,28 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
@Override @Override
public boolean isRescheduleRepaymentsOnHolidaysEnabled() { public boolean isRescheduleRepaymentsOnHolidaysEnabled() {
final String holidaysConfigurationProperty = "reschedule-repayments-on-holidays"; final String holidaysConfigurationProperty = "reschedule-repayments-on-holidays";
final GlobalConfigurationProperty property = this.globalConfigurationRepository final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(holidaysConfigurationProperty);
.findOneByNameWithNotFoundDetection(holidaysConfigurationProperty);
return property.isEnabled(); return property.isEnabled();
} }
@Override @Override
public boolean allowTransactionsOnHolidayEnabled() { public boolean allowTransactionsOnHolidayEnabled() {
final String allowTransactionsOnHolidayProperty = "allow-transactions-on-holiday"; final String allowTransactionsOnHolidayProperty = "allow-transactions-on-holiday";
final GlobalConfigurationProperty property = this.globalConfigurationRepository final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(allowTransactionsOnHolidayProperty);
.findOneByNameWithNotFoundDetection(allowTransactionsOnHolidayProperty);
return property.isEnabled(); return property.isEnabled();
} }
@Override @Override
public boolean allowTransactionsOnNonWorkingDayEnabled() { public boolean allowTransactionsOnNonWorkingDayEnabled() {
final String propertyName = "allow-transactions-on-non_workingday"; final String propertyName = "allow-transactions-on-non_workingday";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.isEnabled(); return property.isEnabled();
} }
@Override @Override
public boolean isConstraintApproachEnabledForDatatables() { public boolean isConstraintApproachEnabledForDatatables() {
final String propertyName = "constraint_approach_for_datatables"; final String propertyName = "constraint_approach_for_datatables";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.isEnabled(); return property.isEnabled();
} }
@@ -125,49 +126,49 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
@Override @Override
public Long retrievePenaltyWaitPeriod() { public Long retrievePenaltyWaitPeriod() {
final String propertyName = "penalty-wait-period"; final String propertyName = "penalty-wait-period";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.getValue(); return property.getValue();
} }
@Override @Override
public Long retrieveGraceOnPenaltyPostingPeriod() { public Long retrieveGraceOnPenaltyPostingPeriod() {
final String propertyName = "grace-on-penalty-posting"; final String propertyName = "grace-on-penalty-posting";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.getValue(); return property.getValue();
} }
@Override @Override
public boolean isPasswordForcedResetEnable() { public boolean isPasswordForcedResetEnable() {
final String propertyName = "force-password-reset-days"; final String propertyName = "force-password-reset-days";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.isEnabled(); return property.isEnabled();
} }
@Override @Override
public Long retrievePasswordLiveTime() { public Long retrievePasswordLiveTime() {
final String propertyName = "force-password-reset-days"; final String propertyName = "force-password-reset-days";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.getValue(); return property.getValue();
} }
@Override @Override
public Long retrieveOpeningBalancesContraAccount() { public Long retrieveOpeningBalancesContraAccount() {
final String propertyName = "office-opening-balances-contra-account"; final String propertyName = "office-opening-balances-contra-account";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.getValue(); return property.getValue();
} }
@Override @Override
public boolean isSavingsInterestPostingAtCurrentPeriodEnd() { public boolean isSavingsInterestPostingAtCurrentPeriodEnd() {
final String propertyName = "savings-interest-posting-current-period-end"; final String propertyName = "savings-interest-posting-current-period-end";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.isEnabled(); return property.isEnabled();
} }
@Override @Override
public Integer retrieveFinancialYearBeginningMonth() { public Integer retrieveFinancialYearBeginningMonth() {
final String propertyName = "financial-year-beginning-month"; final String propertyName = "financial-year-beginning-month";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
if (property.isEnabled()) return property.getValue().intValue(); if (property.isEnabled()) return property.getValue().intValue();
return 1; return 1;
} }
@@ -175,7 +176,7 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
@Override @Override
public Integer retrieveMinAllowedClientsInGroup() { public Integer retrieveMinAllowedClientsInGroup() {
final String propertyName = "min-clients-in-group"; final String propertyName = "min-clients-in-group";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
if (property.isEnabled()) { return property.getValue().intValue(); } if (property.isEnabled()) { return property.getValue().intValue(); }
return null; return null;
} }
@@ -183,7 +184,7 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
@Override @Override
public Integer retrieveMaxAllowedClientsInGroup() { public Integer retrieveMaxAllowedClientsInGroup() {
final String propertyName = "max-clients-in-group"; final String propertyName = "max-clients-in-group";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
if (property.isEnabled()) { return property.getValue().intValue(); } if (property.isEnabled()) { return property.getValue().intValue(); }
return null; return null;
} }
@@ -191,7 +192,7 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
@Override @Override
public boolean isMeetingMandatoryForJLGLoans() { public boolean isMeetingMandatoryForJLGLoans() {
final String propertyName = "meetings-mandatory-for-jlg-loans"; final String propertyName = "meetings-mandatory-for-jlg-loans";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.isEnabled(); return property.isEnabled();
} }
@@ -199,7 +200,7 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
public int getRoundingMode() { public int getRoundingMode() {
final String propertyName = "rounding-mode"; final String propertyName = "rounding-mode";
int defaultValue = 6; // 6 Stands for HALF-EVEN int defaultValue = 6; // 6 Stands for HALF-EVEN
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
if (property.isEnabled()) { if (property.isEnabled()) {
int value = property.getValue().intValue(); int value = property.getValue().intValue();
if (value < 0 || value > 6) { if (value < 0 || value > 6) {
@@ -213,40 +214,40 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
@Override @Override
public boolean isBackdatePenaltiesEnabled() { public boolean isBackdatePenaltiesEnabled() {
final String propertyName = "backdate-penalties-enabled"; final String propertyName = "backdate-penalties-enabled";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.isEnabled(); return property.isEnabled();
} }
@Override @Override
public boolean isOrganisationstartDateEnabled() { public boolean isOrganisationstartDateEnabled() {
final String propertyName = "organisation-start-date"; final String propertyName = "organisation-start-date";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.isEnabled(); return property.isEnabled();
} }
@Override @Override
public Date retrieveOrganisationStartDate() { public Date retrieveOrganisationStartDate() {
final String propertyName = "organisation-start-date"; final String propertyName = "organisation-start-date";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.getDateValue(); return property.getDateValue();
} }
@Override @Override
public boolean isPaymnetypeApplicableforDisbursementCharge() { public boolean isPaymnetypeApplicableforDisbursementCharge() {
final String propertyName = "paymenttype-applicable-for-disbursement-charges"; final String propertyName = "paymenttype-applicable-for-disbursement-charges";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.isEnabled(); return property.isEnabled();
} }
@Override @Override
public boolean isSkippingMeetingOnFirstDayOfMonthEnabled() { public boolean isSkippingMeetingOnFirstDayOfMonthEnabled() {
return this.globalConfigurationRepository.findOneByNameWithNotFoundDetection("skip-repayment-on-first-day-of-month").isEnabled(); return getGlobalConfigurationPropertyData("skip-repayment-on-first-day-of-month").isEnabled();
} }
@Override @Override
public Long retreivePeroidInNumberOfDaysForSkipMeetingDate() { public Long retreivePeroidInNumberOfDaysForSkipMeetingDate() {
final String propertyName = "skip-repayment-on-first-day-of-month"; final String propertyName = "skip-repayment-on-first-day-of-month";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.getValue(); return property.getValue();
} }
@@ -254,30 +255,45 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
@Override @Override
public boolean isInterestChargedFromDateSameAsDisbursementDate() { public boolean isInterestChargedFromDateSameAsDisbursementDate() {
final String propertyName = "interest-charged-from-date-same-as-disbursal-date"; final String propertyName = "interest-charged-from-date-same-as-disbursal-date";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.isEnabled(); return property.isEnabled();
} }
@Override @Override
public boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled() { public boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled() {
final String propertyName = "change-emi-if-repaymentdate-same-as-disbursementdate"; final String propertyName = "change-emi-if-repaymentdate-same-as-disbursementdate";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.isEnabled(); return property.isEnabled();
} }
@Override @Override
public boolean isDailyTPTLimitEnabled() { public boolean isDailyTPTLimitEnabled() {
final String propertyName = "daily-tpt-limit"; final String propertyName = "daily-tpt-limit";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.isEnabled(); return property.isEnabled();
} }
@Override @Override
public Long getDailyTPTLimit() { public Long getDailyTPTLimit() {
final String propertyName = "daily-tpt-limit"; final String propertyName = "daily-tpt-limit";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
return property.getValue(); return property.getValue();
} }
@Override
public void removeGlobalConfigurationPropertyDataFromCache(final String propertyName) {
String identifier = ThreadLocalContextUtil.getTenant().getTenantIdentifier();
String key = identifier + "_" + propertyName;
configurations.remove(key);
}
private GlobalConfigurationPropertyData getGlobalConfigurationPropertyData(final String propertyName) {
String identifier = ThreadLocalContextUtil.getTenant().getTenantIdentifier();
String key = identifier + "_" + propertyName;
if (!configurations.containsKey(key)) {
GlobalConfigurationProperty configuration = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName);
configurations.put(key, configuration.toData());
}
return configurations.get(key);
}
} }
@@ -26,6 +26,7 @@ import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.fineract.infrastructure.configuration.data.GlobalConfigurationPropertyData;
import org.apache.fineract.infrastructure.configuration.exception.GlobalConfigurationPropertyCannotBeModfied; import org.apache.fineract.infrastructure.configuration.exception.GlobalConfigurationPropertyCannotBeModfied;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.security.exception.ForcePasswordResetException; import org.apache.fineract.infrastructure.security.exception.ForcePasswordResetException;
@@ -84,11 +85,6 @@ public class GlobalConfigurationProperty extends AbstractPersistable<Long> {
return this.dateValue; return this.dateValue;
} }
public boolean updateTo(final boolean value) {
final boolean updated = this.enabled != value;
this.enabled = value;
return updated;
}
public Map<String, Object> update(final JsonCommand command) { public Map<String, Object> update(final JsonCommand command) {
@@ -131,5 +127,14 @@ public class GlobalConfigurationProperty extends AbstractPersistable<Long> {
public static GlobalConfigurationProperty newSurveyConfiguration(final String name) { public static GlobalConfigurationProperty newSurveyConfiguration(final String name) {
return new GlobalConfigurationProperty(name, false, null, null, null, false); return new GlobalConfigurationProperty(name, false, null, null, null, false);
} }
public GlobalConfigurationPropertyData toData() {
return new GlobalConfigurationPropertyData(getName(), isEnabled(), getValue(), getDateValue(), this.getId(), this.description,
this.isTrapDoor);
}
public String getName() {
return this.name;
}
} }
@@ -21,6 +21,7 @@ package org.apache.fineract.infrastructure.configuration.service;
import java.util.Map; import java.util.Map;
import org.apache.fineract.infrastructure.configuration.data.GlobalConfigurationDataValidator; import org.apache.fineract.infrastructure.configuration.data.GlobalConfigurationDataValidator;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.configuration.domain.GlobalConfigurationProperty; import org.apache.fineract.infrastructure.configuration.domain.GlobalConfigurationProperty;
import org.apache.fineract.infrastructure.configuration.domain.GlobalConfigurationRepositoryWrapper; import org.apache.fineract.infrastructure.configuration.domain.GlobalConfigurationRepositoryWrapper;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
@@ -43,13 +44,16 @@ public class GlobalConfigurationWritePlatformServiceJpaRepositoryImpl implements
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final GlobalConfigurationRepositoryWrapper repository; private final GlobalConfigurationRepositoryWrapper repository;
private final GlobalConfigurationDataValidator globalConfigurationDataValidator; private final GlobalConfigurationDataValidator globalConfigurationDataValidator;
private final ConfigurationDomainService configurationDomainService;
@Autowired @Autowired
public GlobalConfigurationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, public GlobalConfigurationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
final GlobalConfigurationRepositoryWrapper codeRepository, final GlobalConfigurationDataValidator dataValidator) { final GlobalConfigurationRepositoryWrapper codeRepository, final GlobalConfigurationDataValidator dataValidator,
final ConfigurationDomainService configurationDomainService) {
this.context = context; this.context = context;
this.repository = codeRepository; this.repository = codeRepository;
this.globalConfigurationDataValidator = dataValidator; this.globalConfigurationDataValidator = dataValidator;
this.configurationDomainService = configurationDomainService;
} }
@@ -67,6 +71,7 @@ public class GlobalConfigurationWritePlatformServiceJpaRepositoryImpl implements
final Map<String, Object> changes = configItemForUpdate.update(command); final Map<String, Object> changes = configItemForUpdate.update(command);
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
this.configurationDomainService.removeGlobalConfigurationPropertyDataFromCache(configItemForUpdate.getName());
this.repository.save(configItemForUpdate); this.repository.save(configItemForUpdate);
} }
@@ -35,6 +35,6 @@ public interface FloatingRatesReadPlatformService {
FloatingRateData retrieveBaseLendingRate(); FloatingRateData retrieveBaseLendingRate();
List<InterestRatePeriodData> retrieveInterestRatePeriods(Long floatingRateId); List<InterestRatePeriodData> retrieveInterestRatePeriods(Long productId);
} }
@@ -87,13 +87,13 @@ public class FloatingRatesReadPlatformServiceImpl implements
@Override @Override
public List<InterestRatePeriodData> retrieveInterestRatePeriods( public List<InterestRatePeriodData> retrieveInterestRatePeriods(
final Long floatingRateId) { final Long productId) {
try { try {
FloatingInterestRatePeriodRowMapper mapper = new FloatingInterestRatePeriodRowMapper(); FloatingInterestRatePeriodRowMapper mapper = new FloatingInterestRatePeriodRowMapper();
return this.jdbcTemplate.query(mapper.schema(), mapper, return this.jdbcTemplate.query(mapper.schema(), mapper,
new Object[] { floatingRateId }); new Object[] { productId });
} catch (final EmptyResultDataAccessException e) { } catch (final EmptyResultDataAccessException e) {
throw new FloatingRateNotFoundException(floatingRateId); throw new FloatingRateNotFoundException("error.msg.floatingrate.not.found.for.product");
} }
} }
@@ -242,7 +242,9 @@ public class FloatingRatesReadPlatformServiceImpl implements
.append(" linkedrateperiods.is_differential_to_base_lending_rate as linkedrateperiods_is_differential_to_base_lending_rate, ") .append(" linkedrateperiods.is_differential_to_base_lending_rate as linkedrateperiods_is_differential_to_base_lending_rate, ")
.append(" baserate.from_date as baserate_from_date, ") .append(" baserate.from_date as baserate_from_date, ")
.append(" baserate.interest_rate as baserate_interest_rate ") .append(" baserate.interest_rate as baserate_interest_rate ")
.append("from m_floating_rates as linkedrate ") .append(" from m_product_loan as lp ")
.append(" join m_product_loan_floating_rates as plfr on lp.id = plfr.loan_product_id ")
.append(" join m_floating_rates as linkedrate on linkedrate.id = plfr.floating_rates_id ")
.append("left join m_floating_rates_periods as linkedrateperiods on (linkedrate.id = linkedrateperiods.floating_rates_id and linkedrateperiods.is_active = 1) ") .append("left join m_floating_rates_periods as linkedrateperiods on (linkedrate.id = linkedrateperiods.floating_rates_id and linkedrateperiods.is_active = 1) ")
.append("left join ( ") .append("left join ( ")
.append(" select blr.name, ") .append(" select blr.name, ")
@@ -266,7 +268,7 @@ public class FloatingRatesReadPlatformServiceImpl implements
.append(" where blr.is_base_lending_rate = 1 and blr.is_active = 1 ") .append(" where blr.is_base_lending_rate = 1 and blr.is_active = 1 ")
.append(" ) as b ") .append(" ) as b ")
.append(" where b.from_date <= linkedrateperiods.from_date)) ") .append(" where b.from_date <= linkedrateperiods.from_date)) ")
.append("and linkedrate.id = ? ") .append("and lp.id = ? ")
.append("order by linkedratePeriods_from_date desc "); .append("order by linkedratePeriods_from_date desc ");
@Override @Override
@@ -393,7 +393,7 @@ public class LoansApiResource {
loanBasicDetails = LoanAccountData.withLoanCalendarData(loanBasicDetails, calendarData); loanBasicDetails = LoanAccountData.withLoanCalendarData(loanBasicDetails, calendarData);
} }
Collection<InterestRatePeriodData> interestRatesPeriods = this.loanReadPlatformService.retrieveLoanInterestRatePeriodData(loanId); Collection<InterestRatePeriodData> interestRatesPeriods = this.loanReadPlatformService.retrieveLoanInterestRatePeriodData(loanBasicDetails);
Collection<LoanTransactionData> loanRepayments = null; Collection<LoanTransactionData> loanRepayments = null;
LoanScheduleData repaymentSchedule = null; LoanScheduleData repaymentSchedule = null;
@@ -1600,4 +1600,22 @@ public class LoanAccountData {
return LoanAccountData.collateralTemplate(loanCollateralOptions); return LoanAccountData.collateralTemplate(loanCollateralOptions);
} }
public boolean isLoanProductLinkedToFloatingRate() {
return this.isLoanProductLinkedToFloatingRate;
}
public LocalDate getDisbursementDate(){
return this.timeline.getDisbursementDate();
}
public boolean isFloatingInterestRate() {
return this.isFloatingInterestRate;
}
public BigDecimal getInterestRateDifferential() {
return this.interestRateDifferential;
}
} }
@@ -148,4 +148,12 @@ public class LoanApplicationTimelineData {
return new RepaymentScheduleRelatedLoanData(this.expectedDisbursementDate, this.actualDisbursementDate, currency, principal, return new RepaymentScheduleRelatedLoanData(this.expectedDisbursementDate, this.actualDisbursementDate, currency, principal,
inArrearsTolerance, totalFeeChargesAtDisbursement); inArrearsTolerance, totalFeeChargesAtDisbursement);
} }
public LocalDate getDisbursementDate(){
LocalDate disbursementDate = this.expectedDisbursementDate;
if(this.actualDisbursementDate != null){
disbursementDate = this.actualDisbursementDate;
}
return disbursementDate;
}
} }
@@ -125,7 +125,7 @@ public interface LoanReadPlatformService {
LoanTransactionData retrieveRefundByCashTemplate(Long loanId); LoanTransactionData retrieveRefundByCashTemplate(Long loanId);
Collection<InterestRatePeriodData> retrieveLoanInterestRatePeriodData(Long loanId); Collection<InterestRatePeriodData> retrieveLoanInterestRatePeriodData(LoanAccountData loan);
Collection<Long> retrieveLoanIdsWithPendingIncomePostingTransactions(); Collection<Long> retrieveLoanIdsWithPendingIncomePostingTransactions();
@@ -62,7 +62,6 @@ import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformServic
import org.apache.fineract.portfolio.charge.data.ChargeData; import org.apache.fineract.portfolio.charge.data.ChargeData;
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType; import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
import org.apache.fineract.portfolio.client.api.ClientApiConstants;
import org.apache.fineract.portfolio.client.data.ClientData; import org.apache.fineract.portfolio.client.data.ClientData;
import org.apache.fineract.portfolio.client.domain.ClientEnumerations; import org.apache.fineract.portfolio.client.domain.ClientEnumerations;
import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; import org.apache.fineract.portfolio.client.service.ClientReadPlatformService;
@@ -2065,22 +2064,19 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
} }
@Override @Override
public Collection<InterestRatePeriodData> retrieveLoanInterestRatePeriodData(Long loanId) { public Collection<InterestRatePeriodData> retrieveLoanInterestRatePeriodData(LoanAccountData loanData) {
this.context.authenticatedUser(); this.context.authenticatedUser();
final Loan loan = this.loanRepository.findOne(loanId); if (loanData.isLoanProductLinkedToFloatingRate()) {
if (loan == null) { throw new LoanNotFoundException(loanId); }
if (loan.loanProduct().isLinkedToFloatingInterestRate()) {
final Collection<InterestRatePeriodData> intRatePeriodData = new ArrayList<>(); final Collection<InterestRatePeriodData> intRatePeriodData = new ArrayList<>();
final Collection<InterestRatePeriodData> intRates = this.floatingRatesReadPlatformService.retrieveInterestRatePeriods(loan final Collection<InterestRatePeriodData> intRates = this.floatingRatesReadPlatformService.retrieveInterestRatePeriods(loanData
.loanProduct().getFloatingRates().getFloatingRate().getId()); .loanProductId());
for (final InterestRatePeriodData rate : intRates) { for (final InterestRatePeriodData rate : intRates) {
if (rate.getFromDate().compareTo(loan.getDisbursementDate().toDate()) > 0 && loan.getIsFloatingInterestRate()) { if (rate.getFromDate().compareTo(loanData.getDisbursementDate().toDate()) > 0 && loanData.isFloatingInterestRate()) {
updateInterestRatePeriodData(rate, loan); updateInterestRatePeriodData(rate, loanData);
intRatePeriodData.add(rate); intRatePeriodData.add(rate);
} else if (rate.getFromDate().compareTo(loan.getDisbursementDate().toDate()) <= 0) { } else if (rate.getFromDate().compareTo(loanData.getDisbursementDate().toDate()) <= 0) {
updateInterestRatePeriodData(rate, loan); updateInterestRatePeriodData(rate, loanData);
intRatePeriodData.add(rate); intRatePeriodData.add(rate);
break; break;
} }
@@ -2091,8 +2087,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
return null; return null;
} }
private void updateInterestRatePeriodData(InterestRatePeriodData rate, Loan loan) { private void updateInterestRatePeriodData(InterestRatePeriodData rate, LoanAccountData loan) {
rate.setLoanProductDifferentialInterestRate(loan.loanProduct().getFloatingRates().getInterestRateDifferential()); LoanProductData loanProductData = loanProductReadPlatformService.retrieveLoanProductFloatingDetails(loan.loanProductId());
rate.setLoanProductDifferentialInterestRate(loanProductData.getInterestRateDifferential());
rate.setLoanDifferentialInterestRate(loan.getInterestRateDifferential()); rate.setLoanDifferentialInterestRate(loan.getInterestRateDifferential());
BigDecimal effectiveInterestRate = BigDecimal.ZERO; BigDecimal effectiveInterestRate = BigDecimal.ZERO;
@@ -468,6 +468,99 @@ public class LoanProductData {
syncExpectedWithDisbursementDate, canUseForTopup); syncExpectedWithDisbursementDate, canUseForTopup);
} }
public static LoanProductData loanProductWithFloatingRates(final Long id, final String name,
final boolean isLinkedToFloatingInterestRates, final Integer floatingRateId, final String floatingRateName,
final BigDecimal interestRateDifferential, final BigDecimal minDifferentialLendingRate,
final BigDecimal defaultDifferentialLendingRate, final BigDecimal maxDifferentialLendingRate,
final boolean isFloatingInterestRateCalculationAllowed) {
final String shortName = null;
final String description = null;
final CurrencyData currency = CurrencyData.blank();
final BigDecimal principal = null;
final BigDecimal minPrincipal = null;
final BigDecimal maxPrincipal = null;
final BigDecimal tolerance = null;
final Integer numberOfRepayments = null;
final Integer minNumberOfRepayments = null;
final Integer maxNumberOfRepayments = null;
final Integer repaymentEvery = null;
final BigDecimal interestRatePerPeriod = null;
final BigDecimal minInterestRatePerPeriod = null;
final BigDecimal maxInterestRatePerPeriod = null;
final BigDecimal annualInterestRate = null;
final boolean isVariableInstallmentsAllowed = false;
final Integer minimumGap = null;
final Integer maximumGap = null;
final EnumOptionData repaymentFrequencyType = LoanEnumerations.repaymentFrequencyType(PeriodFrequencyType.MONTHS);
final EnumOptionData interestRateFrequencyType = LoanEnumerations.interestRateFrequencyType(PeriodFrequencyType.MONTHS);
final EnumOptionData amortizationType = LoanEnumerations.amortizationType(AmortizationMethod.EQUAL_INSTALLMENTS);
final EnumOptionData interestType = LoanEnumerations.interestType(InterestMethod.DECLINING_BALANCE);
final EnumOptionData interestCalculationPeriodType = LoanEnumerations
.interestCalculationPeriodType(InterestCalculationPeriodMethod.SAME_AS_REPAYMENT_PERIOD);
final Boolean allowPartialPeriodInterestCalcualtion = null;
final Long fundId = null;
final String fundName = null;
final Long transactionProcessingStrategyId = null;
final String transactionProcessingStrategyName = null;
final Integer graceOnPrincipalPayment = null;
final Integer recurringMoratoriumOnPrincipalPeriods = null;
final Integer graceOnInterestPayment = null;
final Integer graceOnInterestCharged = null;
final Integer graceOnArrearsAgeing = null;
final Integer overdueDaysForNPA = null;
final Collection<ChargeData> charges = null;
final Collection<LoanProductBorrowerCycleVariationData> principalVariationsForBorrowerCycle = new ArrayList<>(1);
final Collection<LoanProductBorrowerCycleVariationData> interestRateVariationsForBorrowerCycle = new ArrayList<>(1);
final Collection<LoanProductBorrowerCycleVariationData> numberOfRepaymentVariationsForBorrowerCycle = new ArrayList<>(1);
final EnumOptionData accountingType = AccountingEnumerations.accountingRuleType(AccountingRuleType.NONE);
final boolean includeInBorrowerCycle = false;
final boolean useBorrowerCycle = false;
final LocalDate startDate = null;
final LocalDate closeDate = null;
final String status = null;
final String externalId = null;
final Boolean multiDisburseLoan = null;
final Integer maxTrancheCount = null;
final BigDecimal outstandingLoanBalance = null;
final EnumOptionData daysInMonthType = CommonEnumerations.daysInMonthType(DaysInMonthType.ACTUAL);
final EnumOptionData daysInYearType = CommonEnumerations.daysInYearType(DaysInYearType.ACTUAL);
final boolean isInterestRecalculationEnabled = false;
final LoanProductInterestRecalculationData interestRecalculationData = LoanProductInterestRecalculationData
.sensibleDefaultsForNewLoanProductCreation();
final Integer minimumDaysBetweenDisbursalAndFirstRepayment = null;
final Boolean holdGuaranteeFunds = false;
final LoanProductGuaranteeData productGuaranteeData = null;
final BigDecimal principalThresholdForLastInstallment = null;
final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion = false;
final boolean canDefineInstallmentAmount = false;
final Integer installmentAmountInMultiplesOf = null;
final LoanProductConfigurableAttributes loanProductConfigurableAttributes = null;
final boolean syncExpectedWithDisbursementDate = false;
final boolean canUseForTopup = false;
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType,
amortizationType, interestType, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, fundId, fundName,
transactionProcessingStrategyId, transactionProcessingStrategyName, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment,
graceOnInterestCharged, charges, accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status,
externalId, principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle,
numberOfRepaymentVariationsForBorrowerCycle, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData,
principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount,
installmentAmountInMultiplesOf, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId,
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
syncExpectedWithDisbursementDate, canUseForTopup);
}
public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings, public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings,
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings, final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings,
@@ -1100,4 +1193,8 @@ public class LoanProductData {
public boolean canUseForTopup() { public boolean canUseForTopup() {
return this.canUseForTopup; return this.canUseForTopup;
} }
public BigDecimal getInterestRateDifferential() {
return this.interestRateDifferential;
}
} }
@@ -46,4 +46,6 @@ public interface LoanProductReadPlatformService {
Collection<LoanProductData> retrieveAllowedProductsForMix(Long productId); Collection<LoanProductData> retrieveAllowedProductsForMix(Long productId);
Collection<LoanProductBorrowerCycleVariationData> retrieveLoanProductBorrowerCycleVariations(Long loanProductId); Collection<LoanProductBorrowerCycleVariationData> retrieveLoanProductBorrowerCycleVariations(Long loanProductId);
LoanProductData retrieveLoanProductFloatingDetails(Long loanProductId);
} }
@@ -617,5 +617,58 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
return this.jdbcTemplate.query(sql, rm, new Object[] { productId, productId }); return this.jdbcTemplate.query(sql, rm, new Object[] { productId, productId });
} }
@Override
public LoanProductData retrieveLoanProductFloatingDetails(final Long loanProductId) {
try {
final LoanProductFloatingRateMapper rm = new LoanProductFloatingRateMapper();
final String sql = "select " + rm.schema() + " where lp.id = ?";
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { loanProductId });
} catch (final EmptyResultDataAccessException e) {
throw new LoanProductNotFoundException(loanProductId);
}
}
private static final class LoanProductFloatingRateMapper implements RowMapper<LoanProductData> {
public LoanProductFloatingRateMapper() {}
public String schema() {
return "lp.id as id, lp.name as name,"
+ "lp.is_linked_to_floating_interest_rates as isLinkedToFloatingInterestRates, "
+ "lfr.floating_rates_id as floatingRateId, " + "fr.name as floatingRateName, "
+ "lfr.interest_rate_differential as interestRateDifferential, "
+ "lfr.min_differential_lending_rate as minDifferentialLendingRate, "
+ "lfr.default_differential_lending_rate as defaultDifferentialLendingRate, "
+ "lfr.max_differential_lending_rate as maxDifferentialLendingRate, "
+ "lfr.is_floating_interest_rate_calculation_allowed as isFloatingInterestRateCalculationAllowed "
+ " from m_product_loan lp " + " left join m_product_loan_floating_rates as lfr on lfr.loan_product_id = lp.id "
+ " left join m_floating_rates as fr on lfr.floating_rates_id = fr.id ";
}
@Override
public LoanProductData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = JdbcSupport.getLong(rs, "id");
final String name = rs.getString("name");
final boolean isLinkedToFloatingInterestRates = rs.getBoolean("isLinkedToFloatingInterestRates");
final Integer floatingRateId = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "floatingRateId");
final String floatingRateName = rs.getString("floatingRateName");
final BigDecimal interestRateDifferential = rs.getBigDecimal("interestRateDifferential");
final BigDecimal minDifferentialLendingRate = rs.getBigDecimal("minDifferentialLendingRate");
final BigDecimal defaultDifferentialLendingRate = rs.getBigDecimal("defaultDifferentialLendingRate");
final BigDecimal maxDifferentialLendingRate = rs.getBigDecimal("maxDifferentialLendingRate");
final boolean isFloatingInterestRateCalculationAllowed = rs.getBoolean("isFloatingInterestRateCalculationAllowed");
return LoanProductData.loanProductWithFloatingRates(id, name, isLinkedToFloatingInterestRates, floatingRateId,
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed);
}
}
} }